Archon/docs/cli-developer-guide.md
Rasmus Widing 8e193f2c89
feat: workflow lifecycle visibility — Ralph events, CLI emitter, PRD discovery (#866)
* docs: add Ralph PRD for workflow lifecycle overhaul

* feat: Add Ralph story event types to WorkflowEventType

Implements US-001 from PRD.

Changes:
- packages/workflows/src/store.ts — append ralph_story_started and ralph_story_completed to WorkflowEventType union

* feat: Add workflow event emit CLI subcommand

Implements US-002 from PRD.

Changes:
- packages/workflows/src/store.ts — already has new event types (US-001)
- packages/cli/src/commands/workflow.ts — add workflowEventEmitCommand
- packages/cli/src/cli.ts — wire workflow event emit subcommand with --run-id, --type, --data flags

* fix: Fix PRD directory discovery duplication in Ralph DAG

Implements US-003 from PRD.

Changes:
- .archon/workflows/defaults/archon-ralph-dag.yaml — detect-input now outputs JSON with input_type and prd_dir fields; when condition updated to use field access; validate-prd discovery block replaced with $detect-input.output.prd_dir substitution

* feat: Emit Ralph story lifecycle events from implement loop

Implements US-004 from PRD.

Changes:
- .archon/workflows/defaults/archon-ralph-dag.yaml — add bun run cli workflow event emit calls after Phase 1.2 (story started) and Phase 5.1 (story completed) with || true for best-effort emission

* chore: Update PRD tracking — all stories complete

* fix: address review — event type validation, discovery fallback, docs

- Derive WorkflowEventType from WORKFLOW_EVENT_TYPES const array
  (enables runtime validation at CLI boundary, matches TRIGGER_RULES pattern)
- Add isValidEventType() guard in CLI — exit 1 on unknown --type
- Restore validate-prd discovery fallback for empty prd_dir after generation
- Clarify success message as best-effort in workflowEventEmitCommand
- Improve --data JSON warning to explain consequence (event emitted without data)
- Remove .archon/ralph/ artifacts (gitignored per-run PRD files)
- Add workflow event emit to CLAUDE.md, cli-user-guide, cli-developer-guide
2026-03-29 09:34:05 +03:00

23 KiB

Archon CLI Developer Guide

Technical reference for understanding CLI internals.

Package Structure

packages/cli/
├── src/
│   ├── cli.ts              # Entry point, argument parsing, routing
│   ├── commands/
│   │   ├── workflow.ts     # workflow list/run implementation
│   │   ├── isolation.ts    # isolation list/cleanup implementation
│   │   └── version.ts      # version command
│   └── adapters/
│       └── cli-adapter.ts  # IPlatformAdapter for stdout
└── package.json            # Defines "archon" binary

Entry Point Flow

┌─────────────────────────────────────────────────────────────────┐
│ archon <command> [subcommand] [options] [arguments]             │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ cli.ts:15-39  Load environment                                  │
│               .env (cwd) → ~/.archon/.env (fallback)            │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ cli.ts:115-135  Parse arguments                                 │
│                 --cwd, --branch, --no-worktree, --help          │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ cli.ts:154-170  Git repository check                            │
│                 Skip for version/help, validate and resolve to  │
│                 repo root for workflow/isolation commands       │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ cli.ts:172-246  Route to command handler                        │
│                 switch(command) → workflow | isolation | version│
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ cli.ts:244-252  Exit with code, always closeDatabase()          │
└─────────────────────────────────────────────────────────────────┘

Code: packages/cli/src/cli.ts:106-259

Git repository check:

  • Commands workflow, isolation, and complete require running from a git repository
  • Commands version, help, setup, and chat bypass this check
  • When in a subdirectory, automatically resolves to repository root
  • Exit code 1 if not in a git repository

workflow list Flow

┌──────────────────────────────────────────────────────────────────┐
│ archon workflow list [--json]                                    │
└──────────────────────────────┬───────────────────────────────────┘
                               │
                               ▼
┌──────────────────────────────────────────────────────────────────┐
│ workflow.ts  workflowListCommand(cwd, json?)                     │
└──────────────────────────────┬───────────────────────────────────┘
                               │
                               ▼
┌──────────────────────────────────────────────────────────────────┐
│ @archon/workflows/workflow-discovery                              │
│ discoverWorkflowsWithConfig(cwd, config)                          │
│ - Loads bundled defaults                                         │
│ - Searches .archon/workflows/ recursively                        │
│ - Merges (repo overrides defaults by name)                       │
└──────────────────────────────┬───────────────────────────────────┘
                               │
               ┌───────────────┴───────────────┐
               │ json=true                     │ json=false
               ▼                               ▼
┌──────────────────────────┐   ┌───────────────────────────────────┐
│ JSON output to stdout    │   │ Human-readable list to stdout     │
│ { workflows, errors }    │   │ name, description, type, options  │
└──────────────────────────┘   └───────────────────────────────────┘

Code: packages/cli/src/commands/workflow.ts


workflow run Flow

┌─────────────────────────────────────────────────────────────────┐
│ archon workflow run <name> [message] [--branch X] [--from X] [--no-worktree]│
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ workflow.ts:78-92  Discover & find workflow by name             │
│                    Error if not found (lists available)         │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ workflow.ts:99  Create CLIAdapter for stdout                    │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ workflow.ts:104-133  Database setup                             │
│ - Create conversation: cli-{timestamp}-{random}                 │
│ - Lookup codebase from directory (warn if fails)                │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
                    ┌─────────────┴─────────────┐
                    │                           │
             no --branch                   --branch
                    │                           │
                    ▼                           ▼
┌───────────────────────────┐   ┌───────────────────────────────────┐
│ Use cwd as-is             │   │ workflow.ts:152-168                │
│                           │   │ Auto-detect git repo               │
│                           │   │ Auto-register codebase if needed   │
└─────────────┬─────────────┘   └───────────────┬───────────────────┘
              │                                 │
              │                   ┌─────────────┴─────────────┐
              │                   │                           │
              │            --no-worktree               (default)
              │                   │                           │
              │                   ▼                           ▼
              │   ┌─────────────────────────┐ ┌─────────────────────────┐
              │   │ workflow.ts:171-175     │ │ workflow.ts:177-219     │
              │   │ git.checkout(cwd, branch)│ │ Check existing worktree │
              │   │                         │ │ If healthy → reuse      │
              │   │                         │ │ Else → provider.create()│
              │   │                         │ │ Track in DB             │
              │   └────────────┬────────────┘ └────────────┬────────────┘
              │                │                           │
              └────────────────┴─────────────┬─────────────┘
                                             │
                                             ▼
┌─────────────────────────────────────────────────────────────────┐
│ workflow.ts:235-243  executeWorkflow()                          │
│ - Pass adapter, conversation, workflow, cwd, message            │
│ - Stream AI responses to stdout                                 │
│ - Return success/failure                                        │
└─────────────────────────────────────────────────────────────────┘

Code: packages/cli/src/commands/workflow.ts:72-251

Worktree Provider: packages/core/src/isolation/providers/worktree-provider.ts


workflow event emit Flow

┌──────────────────────────────────────────────────────────────────┐
│ archon workflow event emit --run-id <uuid> --type <type> [...]   │
└──────────────────────────────┬───────────────────────────────────┘
                               │
                               ▼
┌──────────────────────────────────────────────────────────────────┐
│ cli.ts  Validate --run-id, --type (required)                     │
│         Validate --type against WORKFLOW_EVENT_TYPES              │
│         Parse --data as JSON (warn + skip if invalid)            │
└──────────────────────────────┬───────────────────────────────────┘
                               │
                               ▼
┌──────────────────────────────────────────────────────────────────┐
│ workflow.ts  workflowEventEmitCommand(runId, eventType, data?)   │
│              createWorkflowStore().createWorkflowEvent(...)       │
│              Non-throwing (fire-and-forget)                       │
└──────────────────────────────────────────────────────────────────┘

Code: packages/cli/src/cli.ts (case 'event'), packages/cli/src/commands/workflow.ts:workflowEventEmitCommand

Contract: Event persistence is best-effort. createWorkflowEvent catches all errors internally — the CLI prints a confirmation but cannot guarantee the event was stored.


isolation list Flow

┌─────────────────────────────────────────────────────────────────┐
│ archon isolation list                                           │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ isolation.ts:19-57  isolationListCommand()                      │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ @archon/core isolationDb.listAllActiveWithCodebase()            │
│ - Joins isolation_environments with codebases                   │
│ - Returns: path, branch, workflow_type, codebase_name,          │
│            platform, days_since_activity                        │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ isolation.ts:30-55  Group by codebase, print table              │
└─────────────────────────────────────────────────────────────────┘

Code: packages/cli/src/commands/isolation.ts:19-57


isolation cleanup Flow

┌─────────────────────────────────────────────────────────────────┐
│ archon isolation cleanup [days]                                 │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ isolation.ts:62-99  isolationCleanupCommand(daysStale)          │
│                     default: 7 days                             │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ @archon/core isolationDb.findStaleEnvironments(days)            │
│ - WHERE last_activity_at < now - days                           │
│ - Excludes telegram platform                                    │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│ For each stale environment:                                     │
│ 1. provider.destroy(path, options)                              │
│ 2. Update DB status → 'destroyed'                               │
│ 3. Log result                                                   │
└─────────────────────────────────────────────────────────────────┘

Code: packages/cli/src/commands/isolation.ts:62-99


CLI Adapter

Implements IPlatformAdapter for terminal output.

┌─────────────────────────────────────────────────────────────────┐
│ CLIAdapter                                                      │
├─────────────────────────────────────────────────────────────────┤
│ sendMessage(convId, msg) → Output to stdout                     │
│ getStreamingMode()       → 'batch'                              │
│ getPlatformType()        → 'cli'                                │
│ ensureThread()           → passthrough                          │
│ start() / stop()         → no-op                                │
└─────────────────────────────────────────────────────────────────┘

Code: packages/cli/src/adapters/cli-adapter.ts:13-47


Key Dependencies

Function Package Location Purpose
discoverWorkflowsWithConfig(cwd, config) @archon/workflows/workflow-discovery workflows/src/workflow-discovery.ts Find and parse workflow YAML
executeWorkflow(...) @archon/workflows/executor workflows/src/executor.ts Run workflow steps
getIsolationProvider() @archon/isolation isolation/src/factory.ts Get WorktreeProvider singleton
conversationDb.* @archon/core core/src/db/conversations.ts Conversation CRUD
codebaseDb.* @archon/core core/src/db/codebases.ts Codebase CRUD
isolationDb.* @archon/core core/src/db/isolation-environments.ts Worktree tracking
git.* @archon/git packages/git/src/ Git operations
closeDatabase() @archon/core core/src/db/connection.ts Clean shutdown

Conversation ID Format

CLI conversations use ID format: cli-{timestamp}-{random}

Example: cli-1705932847321-a7f3b2

Generated at: packages/cli/src/commands/workflow.ts:26


Worktree Reuse Logic

When --branch is provided:

  1. Lookup: isolationDb.findActiveByWorkflow(codebaseId, 'task', branchName)
  2. Health check: provider.healthCheck(path) on existing
  3. Reuse: If found and healthy (warns if --from was specified but not applied)
  4. Create: If not found or unhealthy — passes fromBranch to provider if specified via --from

Worktrees stored at: ~/.archon/worktrees/<repo>/<branch-slug>/

Code: packages/cli/src/commands/workflow.ts:177-219


Exit Codes

Code Meaning
0 Success
1 Error (logged to stderr, including not in git repo)

Database Connection

  • Connection opened on first database call
  • Always closed in finally block after command completes
  • Default: SQLite at ~/.archon/archon.db (zero setup, auto-initialized)
  • Optional: PostgreSQL when DATABASE_URL is set (for cloud/advanced deployments)

Code: packages/cli/src/cli.ts:229-241