xiaowei-system/skills/software-development/agent-cli-builder/SKILL.md

5.9 KiB

tags name description version author updated
software development
agent-cli-builder Building agent-native CLIs — wrap HTTP APIs or GUI apps into structured, stateful CLIs with REPL mode, JSON output, and SKILL.md for AI agent discoverability. Based on CLI-Anything methodology adapted for Hermes. 1.0 小唯 A06 2026-07-01

Agent CLI Builder

Build agent-native command-line interfaces for any software, service, or HTTP API. A CLI built this way lets AI agents (or humans) operate the software through deterministic commands instead of GUI clicks.

When to Use

  • An HTTP API exists but has no CLI (e.g., ZhiYi, KOCR, gaokao API)
  • A GUI app has a backend CLI but no structured agent interface (e.g., Blender, LibreOffice)
  • You want any AI agent to discover and use a tool via SKILL.md

Methodology (CLI-Anything 7-Phase SOP, Adapted)

Phase 1: API/Codebase Analysis

Identify the target:
  - HTTP API → catalog all endpoints, request/response shapes, auth
  - GUI app → find backend engine, native CLI, data model
  - Existing CLI → identify gaps for --json output, REPL mode

Map operations to command groups
Design state model (session, project, undo/redo)

Phase 2: CLI Architecture

Interaction model (pick at least 2):
  - Stateful REPL (default — `invoke_without_command=True`)
  - One-shot subcommands (for scripting)
  - Both ✓

Command groups matching logical domains:
  - Health/status
  - Core operations (search, navigate, create)
  - Stats/metrics
  - Configuration/settings

Output format:
  - Human-readable (tables, icons) for interactive use
  - `--json` flag for machine-readable (EVERY command)

Phase 3: Implementation

Standard project layout:

<project>/
├── setup.py                    ← PyPI installable (pip install -e .)
├── cli_anything/               ← PEP 420 namespace (NO __init__.py)
│   └── <service>/              ← Sub-package
│       ├── __init__.py
│       ├── __main__.py         ← python3 -m entry
│       ├── README.md
│       ├── <service>_cli.py    ← Click CLI (main entry point)
│       ├── core/
│       │   ├── __init__.py
│       │   └── client.py       ← API client wrapper
│       ├── utils/
│       │   ├── __init__.py
│       │   └── repl_skin.py    ← (optional) prompt_toolkit REPL
│       ├── skills/
│       │   └── SKILL.md        ← Agent-discoverable skill definition
│       └── tests/
│           ├── TEST.md
│           ├── __init__.py
│           └── test_core.py

Core patterns:

# client.py — API wrapper
class ServiceClient:
    def _get(self, path): ...
    def _post(self, path, data): ...
    def search(self, query, **kwargs): ...
    def health(self): ...

# <service>_cli.py — Click CLI
@click.group(invoke_without_command=True)
@click.option("--json", is_flag=True)
def cli(ctx, json_flag):
    """Description."""
    global _json_output; _json_output = json_flag
    if ctx.invoked_subcommand is None:
        ctx.invoke(repl)

# Every command MUST support --json + human-readable dual output
def output(data, message=""):
    if _json_output:
        click.echo(json.dumps(data, indent=2, ensure_ascii=False, default=str))
    else:
        if message: click.echo(message)
        # Format nicely for humans

Iron rules:

  • Use cli_anything as PEP 420 namespace package (no __init__.py)
  • invoke_without_command=True → REPL as default
  • Every command --json flag
  • CLI = Click + entry_points.console_scripts
  • API key via environment variable with sensible defaults

Phase 4: Test Plan (TEST.md)

Write BEFORE test code:

  1. Test inventory (files + estimated count)
  2. Client unit tests (each method)
  3. CLI subprocess tests (install, run, verify output)
  4. E2E tests (real API calls)

Phase 5: Test Implementation

# test_core.py
def test_health():
    c = Client()
    r = c.health()
    assert r.get("status") == "ok"

def test_search():
    c = Client()
    r = c.search("query")
    assert len(r.get("results", [])) > 0

Phase 6: SKILL.md Generation

Generate a skills/SKILL.md so AI agents can auto-discover the CLI:

---
name: cli-anything-<service>
description: One-line description of what the CLI does
---

Include: install command, all commands with options, JSON output examples, environment variables.

Phase 7: Install & Verify

cd <project> && pip install -e .
which cli-anything-<service>
cli-anything-<service> --help
cli-anything-<service> health
cli-anything-<service> search "test" --json
python3 tests/test_core.py

Verification Checklist

  • pip install -e . succeeds
  • CLI entry point registered (which cli-anything-<name>)
  • --help shows all command groups
  • health command returns 200
  • Core operations work
  • --json produces valid JSON
  • Default mode enters REPL
  • Tests pass (9+ tests)
  • SKILL.md exists in skills/
  • Environment vars documented in README

Examples

Project Service API Base Key Location
cli-anything-zhiyi ZhiYi MemoryWeave localhost:7821 zhiyi-dev-key-2026 ~/bin/cli-anything-zhiyi/

For detailed examples from a real implementation, see references/cli-anything-zhiyi.md.

Pitfalls

  • Namespace package: cli_anything/ directory must NOT have __init__.py. Each sub-package does.
  • Global state: Use module-level globals for _json_output and _client — they're per-CLI-instance and reset with each CLI call.
  • REPL vs one-shot: REPL as default via invoke_without_command=True. Make sure /quit works gracefully.
  • Auth: API keys in env vars with sensible defaults. Never hardcode in source.
  • Timeout: API calls need generous timeouts (10s for reads, 30s for search).