Skip to content

APS CLI Developer Guide

This guide explains APS CLI internals, command structure, execution flow, and how to extend or debug the CLI.

APS CLI = reference implementation of the APS packaging + runtime spec.

Goal: make the CLI simple, hackable, Unix-style, and portable.


🧠 CLI Philosophy

Principle Description
Simple first Always start with minimal functionality
Predictable No magic — explicit inputs/outputs
Unix style JSON stdin → program → JSON stdout
Portable Works offline, local-first, OS-agnostic
Spec-driven CLI validates the APS standard

📦 CLI Code Overview

cli/
└── src/aps_cli/
├── app.py ← entrypoint + command handlers
├── manifest.py ← load + validate agent.yaml
├── cache.py ← local agent cache
├── utils.py
└── init.py

Entrypoint installed as aps binary.


🧬 CLI Architecture

flowchart TD
  U[User] --> CLI[aps command]
  CLI --> Parser[argparse]
  Parser --> Handler[cmd_* function]
  Handler --> Registry[HTTP client]
  Handler --> OS[File ops / tar / venv / PYTHONPATH]
  Handler --> AgentProc[Subprocess stdin/stdout]

Command Map

Command Purpose
aps run <path> Execute agent from folder or registry
aps build <src> Create .aps.tar.gz package
aps publish <file> Upload to registry
aps pull <id> Download + cache agent
aps validate <path> Validate manifest & layout
aps registry serve Start local registry

Future:

- aps login

- aps search <term>

- aps config

- aps sign / verify

Run Flow (local)

sequenceDiagram
  participant CLI
  participant Agent

  CLI->>CLI: load manifest
  CLI->>Agent: spawn python entrypoint
  CLI->>Agent: send stdin JSON
  Agent-->>CLI: stdout JSON
  CLI-->>User: print result

Key runtime logic in cmd_run_sync() + _wrap_request().

Run Flow (registry)

flowchart TD
  User --> CLI
  CLI --> Resolve{id starts with registry://?}
  Resolve -- no --> Local
  Resolve -- yes --> Meta[GET /v1/agents/id]
  Meta --> CacheCheck
  CacheCheck -- miss --> Pull
  Pull --> Cache
  Cache --> Local
  Local --> RunAgent

Helper function: _resolve_registry_path_if_needed()

Test Structure

- Unit-level tests under cli/tests/

- Fake registry calls via monkeypatch

- No external network calls allowed

Run:

pytest -q

Key Functions

File Function Purpose
app.py cmd_run_sync Run agent (local)
cmd_run_stream Streaming run mode
cmd_build Package agent
cmd_publish Upload tar.gz
cmd_pull Fetch to cache
_resolve_registry_path_if_needed Translate registry:// URIs
manifest.py load_manifest Validate agent.yaml
cache.py cached_agent_dir Return cache path

Subprocess Behavior

- Agents are run as external processes, not imported modules

- PYTHONPATH is auto-set to agent src/

- Both stdout and stderr captured

- Streaming mode reads line-by-line and detects final JSON

Adding a New Command

- Add argparse stanza in main()

- Write handler cmd_xxx(args)

- Unit test in cli/tests/test_xxx.py

- Update docs
def cmd_hello(args):
    print("hello world")

# inside parser block
s = subparsers.add_parser("hello")
s.set_defaults(func=cmd_hello)

Debugging Tips

Enable debug logs

export APS_DEBUG=1

Log process IO

Use print statements or sys.stderr.write() inside helpers.

Manual resolve test

python3 -c "import aps_cli.app as a;print(a._resolve_registry_path_if_needed('registry://dev.echo'))"

Roadmap Hooks

Placeholders in CLI for future:

- Signature validation

- Agent attestation

- Capability metadata

- Remote run orchestration

- Lifecycle hooks (prepare, cleanup)

- Config file ~/.aps/config

Done — You're Now Able to Modify the CLI

Next: see docs/testing.md for test conventions and CI rules.