Skip to main content
Always invoke as bunx smithers-orchestrator <command> (see Installation for why). Use --help on any command for the canonical option list.

Conventions

  • Persisted state lives in the nearest smithers.db (walk up from the working directory). Most read commands fail with a friendly message if no DB is found.
  • Boolean flags accept either bare form (--watch) or explicit --watch true|false.
  • --format json|yaml|md|jsonl, --filter-output <key.path>, --token-count, --token-limit N, --token-offset N, --schema, --llms, --mcp, --verbose, --help, --version are global.
  • Workflow resolution: up, graph, revert, replay, fork, retry-task, timetravel take a workflow file path. workflow run <name> resolves IDs from .smithers/workflows/<name>.tsx. workflow.tsx invoked directly behaves like up workflow.tsx.

Exit codes

0   success
1   execution failure
2   run cancelled / cancel succeeded
3   `up` ended in waiting-approval
4   invalid arguments / user-correctable input error
130 SIGINT
143 SIGTERM

Command catalog (TOON)

Commands listed by dotted name. Subcommands of workflow, cron, human, alerts, memory, openapi, agents, mcp, skills appear as parent.sub.
commands[56]:
  - name: init
    purpose: Install the local workflow pack into .smithers/
    flags[3]{name,short,type,default,desc}:
      force,,boolean,false,Overwrite existing scaffold files
      agents-only,,boolean,false,Only create .smithers/agents/
      install,,boolean,true,Run bun install inside .smithers/ after scaffolding
  - name: up
    purpose: Start or resume a workflow execution
    args[1]{name,type,required,desc}:
      workflow,string,true,Workflow file path
    flags[23]{name,short,type,default,desc}:
      detach,d,boolean,false,Background mode; print runId/pid/logFile and exit
      run-id,r,string,,Explicit run ID
      max-concurrency,c,number,4,Maximum parallel tasks
      root,,string,,Tool sandbox root (defaults to workflow's parent dir)
      log,,boolean,true,NDJSON event log output
      log-dir,,string,,NDJSON log directory
      allow-network,,boolean,false,Allow bash tool network access
      max-output-bytes,,number,,Max bytes per tool call return
      tool-timeout-ms,,number,,Max wall-clock per tool call
      hot,,boolean,false,Hot reload for .tsx workflows
      input,i,string,,Input JSON string
      resume,,boolean,false,Resume existing run
      force,,boolean,false,Resume even if run is marked running
      serve,,boolean,false,Start an HTTP server alongside the workflow
      port,,number,7331,HTTP server port when --serve
      host,,string,127.0.0.1,HTTP bind address when --serve
      auth-token,,string,,Bearer token for HTTP auth (or SMITHERS_API_KEY env)
      metrics,,boolean,true,Expose /metrics Prometheus endpoint when --serve
      supervise,,boolean,false,Run stale-run supervisor with --serve
      supervise-dry-run,,boolean,false,With --supervise; detect without resuming
      supervise-interval,,string,10s,Supervisor poll interval
      supervise-stale-threshold,,string,30s,Heartbeat staleness threshold
      supervise-max-concurrent,,number,3,Max runs resumed per poll
  - name: tui
    purpose: Interactive observability dashboard
  - name: ps
    purpose: List active, paused, and recent runs
    flags[5]{name,short,type,default,desc}:
      status,s,string,,"Filter: running|waiting-approval|waiting-event|waiting-timer|continued|finished|failed|cancelled"
      limit,l,number,20,Max rows
      all,a,boolean,false,Include all statuses
      watch,w,boolean,false,Refresh continuously
      interval,i,number,2,Watch refresh seconds
  - name: logs
    purpose: Tail lifecycle events for a run
    args[1]{name,type,required,desc}:
      runId,string,true,Run ID
    flags[4]{name,short,type,default,desc}:
      follow,f,boolean,true,Poll for new events while run is active
      follow-ancestry,,boolean,false,Include events from parent runs (root-to-current)
      since,,number,,Start from event sequence number
      tail,n,number,50,Last N events
  - name: events
    purpose: Query run event history with filters and grouping
    args[1]{name,type,required,desc}:
      runId,string,true,Run ID
    flags[8]{name,short,type,default,desc}:
      node,n,string,,Filter by node ID
      type,t,string,,"Category: agent|approval|frame|memory|node|openapi|output|revert|run|sandbox|scorer|snapshot|supervisor|timer|token|tool-call|workflow"
      since,s,string,,Window (5m, 2h)
      limit,l,number,1000,Max events (cap 100000)
      json,j,boolean,false,NDJSON output
      group-by,,string,,"node | attempt"
      watch,w,boolean,false,Append new events as they arrive
      interval,i,number,2,Watch poll seconds
  - name: chat
    purpose: Show agent transcripts (prompts, replies, stderr)
    args[1]{name,type,required,desc}:
      runId,string,false,Run ID (latest if omitted)
    flags[4]{name,short,type,default,desc}:
      all,a,boolean,false,Show every agent attempt
      follow,f,boolean,false,Watch for new output
      tail,n,number,,Last N chat blocks
      stderr,,boolean,true,Include agent stderr
  - name: chat.create
    purpose: Create and start a one-task auto-hijacked chat run
    flags[2]{name,short,type,default,desc}:
      agent,,string,,"claude-code|codex|gemini"
      cwd,,string,.,Working directory for the chat session
  - name: inspect
    purpose: Print structured run state, steps, approvals, loop info
    args[1]{name,type,required,desc}:
      runId,string,true,Run ID
    flags[2]{name,short,type,default,desc}:
      watch,w,boolean,false,Refresh continuously
      interval,i,number,2,Watch refresh seconds
  - name: node
    purpose: Enriched node details for debugging retries, tools, output
    args[1]{name,type,required,desc}:
      nodeId,string,true,Node ID
    flags[6]{name,short,type,default,desc}:
      run-id,r,string,,Run ID
      iteration,i,number,,Loop iteration (default latest)
      attempts,,boolean,false,Expand all attempts
      tools,,boolean,false,Expand tool input/output payloads
      watch,w,boolean,false,Refresh continuously
      interval,,number,2,Watch refresh seconds
  - name: why
    purpose: Explain why a run is currently blocked or paused
    args[1]{name,type,required,desc}:
      runId,string,true,Run ID
    flags[1]{name,short,type,default,desc}:
      json,,boolean,false,Structured JSON diagnosis
  - name: scores
    purpose: View scorer results for a run
    args[1]{name,type,required,desc}:
      runId,string,true,Run ID
    flags[1]{name,short,type,default,desc}:
      node,,string,,Filter to specific node ID
  - name: approve
    purpose: Record approval for a pending gate
    args[1]{name,type,required,desc}:
      runId,string,true,Run ID
    flags[4]{name,short,type,default,desc}:
      node,n,string,,Node ID (required if multiple gates pending)
      iteration,,number,0,Loop iteration
      note,,string,,Approval note
      by,,string,,Approver identifier
  - name: deny
    purpose: Deny a pending approval gate
    args[1]{name,type,required,desc}:
      runId,string,true,Run ID
    flags[4]{name,short,type,default,desc}:
      node,n,string,,Node ID
      iteration,,number,0,Loop iteration
      note,,string,,Denial note
      by,,string,,Denier identifier
  - name: signal
    purpose: Deliver a durable signal to a run waiting on WaitForEvent
    args[2]{name,type,required,desc}:
      runId,string,true,Run ID
      signalName,string,true,Signal name
    flags[3]{name,short,type,default,desc}:
      data,,string,{},Signal payload as JSON
      correlation,,string,,Correlation ID to match a specific waiter
      by,,string,,Sender identifier
  - name: supervise
    purpose: Watch for stale runs and auto-resume them
    flags[4]{name,short,type,default,desc}:
      dry-run,n,boolean,false,Detect without resuming
      interval,i,string,10s,Poll interval
      stale-threshold,t,string,30s,Heartbeat staleness threshold
      max-concurrent,c,number,3,Max runs resumed per poll
  - name: cancel
    purpose: Halt one active run; mark in-progress attempts as cancelled
    args[1]{name,type,required,desc}:
      runId,string,true,Run ID
  - name: down
    purpose: Cancel all active runs in nearest smithers.db
    flags[1]{name,short,type,default,desc}:
      force,,boolean,false,Cancel stale runs too
  - name: hijack
    purpose: Hand off the latest resumable agent session
    args[1]{name,type,required,desc}:
      runId,string,true,Run ID
    flags[3]{name,short,type,default,desc}:
      target,,string,,"Expected engine: claude-code|codex"
      timeout-ms,,number,30000,Wait time for live handoff
      launch,,boolean,true,Open session immediately
  - name: graph
    purpose: Render a workflow tree without executing
    args[1]{name,type,required,desc}:
      workflow,string,true,Workflow file path
    flags[2]{name,short,type,default,desc}:
      run-id,r,string,graph,Run ID for persisted input/outputs
      input,,string,,Input JSON (overrides persisted)
  - name: revert
    purpose: Restore workspace to a previous task attempt snapshot
    args[1]{name,type,required,desc}:
      workflow,string,true,Workflow file path
    flags[4]{name,short,type,default,desc}:
      run-id,r,string,,Run ID
      node-id,n,string,,Node ID
      attempt,,number,1,Attempt number
      iteration,,number,0,Loop iteration
  - name: retry-task
    purpose: Retry a specific task within a run
    args[1]{name,type,required,desc}:
      workflow,string,true,Workflow file path
    flags[5]{name,short,type,default,desc}:
      run-id,r,string,,Run ID
      node-id,n,string,,Task/node ID to retry
      iteration,,number,0,Loop iteration
      no-deps,,boolean,false,Only reset this node (skip dependents)
      force,,boolean,false,Allow retry even if run is still running
  - name: timetravel
    purpose: Atomic revert + node reset (filesystem via jj + DB)
    args[1]{name,type,required,desc}:
      workflow,string,true,Workflow file path
    flags[7]{name,short,type,default,desc}:
      run-id,r,string,,Run ID
      node-id,n,string,,Task/node ID
      iteration,,number,0,Loop iteration
      attempt,a,number,,Attempt number (default latest)
      no-vcs,,boolean,false,Skip filesystem revert (DB only)
      no-deps,,boolean,false,Only reset this node
      resume,,boolean,false,Resume after time travel
  - name: replay
    purpose: Fork from a checkpoint and resume execution
    args[1]{name,type,required,desc}:
      workflow,string,true,Workflow file path
    flags[6]{name,short,type,default,desc}:
      run-id,r,string,,Source run ID
      frame,f,number,,Frame number to fork from
      node,n,string,,Node ID to reset to pending
      input,i,string,,Input overrides as JSON
      label,l,string,,Branch label
      restore-vcs,,boolean,false,Restore jj revision to source frame
  - name: diff
    purpose: Compare two time-travel snapshots
    args[2]{name,type,required,desc}:
      a,string,true,Snapshot ref (run_id or run_id:frame_no)
      b,string,true,Snapshot ref
    flags[1]{name,short,type,default,desc}:
      json,,boolean,false,JSON output
  - name: fork
    purpose: Create a branched run from a snapshot
    args[1]{name,type,required,desc}:
      workflow,string,true,Workflow file path
    flags[6]{name,short,type,default,desc}:
      run-id,r,string,,Source run ID
      frame,f,number,,Frame number
      reset-node,n,string,,Node ID to reset
      input,i,string,,Input overrides
      label,l,string,,Branch label
      run,,boolean,false,Immediately start the forked run
  - name: timeline
    purpose: View execution timeline + forks
    args[1]{name,type,required,desc}:
      runId,string,true,Run ID
    flags[2]{name,short,type,default,desc}:
      tree,,boolean,false,Include all child forks recursively
      json,,boolean,false,JSON output
  - name: observability
    purpose: Start or stop the local Docker Compose observability stack
    flags[2]{name,short,type,default,desc}:
      detach,d,boolean,false,Background containers
      down,,boolean,false,Stop and remove stack
  - name: ask
    purpose: Query via the best available installed agent CLI
    args[1]{name,type,required,desc}:
      query,string,true,Question or prompt
    flags[6]{name,short,type,default,desc}:
      agent,,string,,"claude|codex|gemini|kimi|pi"
      tool-surface,,string,semantic,"MCP tool surface: semantic|raw"
      no-mcp,,boolean,false,Disable MCP bootstrap
      print-bootstrap,,boolean,false,Print bootstrap config instead of running
      dump-prompt,,boolean,false,Print full system prompt
      list-agents,,boolean,false,List available agents with status
  - name: agents.capabilities
    purpose: Print capability registry for all built-in CLI agents
  - name: agents.doctor
    purpose: Validate capability metadata for drift or contradictions
    flags[1]{name,short,type,default,desc}:
      json,,boolean,false,JSON report
  - name: human.inbox
    purpose: List all pending human requests across runs
    flags[1]{name,short,type,default,desc}:
      format,,string,,"json for structured output"
  - name: human.answer
    purpose: Submit a JSON response to a pending HumanTask request
    args[1]{name,type,required,desc}:
      requestId,string,true,Request ID
    flags[2]{name,short,type,default,desc}:
      value,,string,,Response as JSON (required)
      by,,string,,Operator identifier
  - name: human.cancel
    purpose: Cancel a pending human request
    args[1]{name,type,required,desc}:
      requestId,string,true,Request ID
    flags[1]{name,short,type,default,desc}:
      by,,string,,Operator identifier
  - name: alerts.list
    purpose: List active alerts from nearest smithers.db
  - name: alerts.ack
    purpose: Mark an alert as acknowledged
    args[1]{name,type,required,desc}:
      alertId,string,true,Alert ID
  - name: alerts.resolve
    purpose: Mark an alert as resolved
    args[1]{name,type,required,desc}:
      alertId,string,true,Alert ID
  - name: alerts.silence
    purpose: Silence an alert without resolving
    args[1]{name,type,required,desc}:
      alertId,string,true,Alert ID
  - name: memory.list
    purpose: List all stored facts in a namespace
    args[1]{name,type,required,desc}:
      namespace,string,true,"Namespace (e.g. workflow:my-flow, global:default)"
    flags[1]{name,short,type,default,desc}:
      workflow,w,string,,Path to .tsx workflow file (locates DB)
  - name: memory.recall
    purpose: Search stored facts by semantic similarity
    args[1]{name,type,required,desc}:
      query,string,true,Natural language query
    flags[3]{name,short,type,default,desc}:
      workflow,w,string,,Path to .tsx workflow file
      namespace,n,string,global:default,Namespace to search
      top-k,k,number,5,Number of results
  - name: openapi.list
    purpose: Parse an OpenAPI spec and print tool names + summaries
    args[1]{name,type,required,desc}:
      specPath,string,true,File path or URL to spec (JSON/YAML)
  - name: workflow.list
    purpose: List discovered workflows in .smithers/workflows/
  - name: workflow.run
    purpose: Run a discovered workflow by ID
    args[1]{name,type,required,desc}:
      name,string,true,Workflow ID
    flags[8]{name,short,type,default,desc}:
      prompt,p,string,,Shorthand for input.prompt
      input,,string,,Input JSON
      detach,d,boolean,,Background mode
      run-id,r,string,,Explicit run ID
      resume,,boolean,,Resume existing run
      serve,,boolean,,Start HTTP server alongside
      port,,number,,HTTP server port
      hot,,boolean,,Hot reload
  - name: workflow.path
    purpose: Resolve workflow ID to entry file path
    args[1]{name,type,required,desc}:
      name,string,true,Workflow ID
  - name: workflow.create
    purpose: Create a new workflow scaffold file
    args[1]{name,type,required,desc}:
      name,string,true,New ID (lowercase-kebab)
  - name: workflow.doctor
    purpose: Inspect workflow discovery health
    args[1]{name,type,required,desc}:
      name,string,false,Workflow ID (omit for all)
  - name: cron.start
    purpose: Start the background scheduler loop (polls every 15s)
  - name: cron.add
    purpose: Register a new workflow cron schedule
    args[2]{name,type,required,desc}:
      pattern,string,true,"Cron expression (e.g. 0 * * * *)"
      workflowPath,string,true,Path or ID of workflow
  - name: cron.list
    purpose: List all registered cron schedules
  - name: cron.rm
    purpose: Delete a cron schedule by ID
    args[1]{name,type,required,desc}:
      cronId,string,true,UUID of cron entry
  - name: completions
    purpose: Generate shell completion scripts
    args[1]{name,type,required,desc}:
      shell,string,true,"bash|zsh|fish|nushell"
  - name: mcp.add
    purpose: Register Smithers as an MCP server for an agent integration
    flags[3]{name,short,type,default,desc}:
      command,c,string,,Override the agent command
      no-global,,boolean,false,Project-local install
      agent,,string,,"Target: claude-code|cursor|..."
  - name: skills.add
    purpose: Sync skill files to agent integrations
    flags[2]{name,short,type,default,desc}:
      depth,,number,1,Grouping depth
      no-global,,boolean,false,Project-local install
  - name: skills.list
    purpose: List available skills

Operational notes

  • Detached mode (up --detach): redirects stdout/stderr to a log file; prints runId/pid/logFile and exits.
  • Serve mode (up --serve): starts the HTTP app and keeps the process alive until interrupted.
  • Progress reporting: writes events to stderr in the form [+MM:SS.mmm] <symbol> <summary>.
  • Signal handling: SIGINT/SIGTERM trigger a clean cancellation and SQLite close.
  • Supervisor guards: skips runs whose workflow file is missing, whose owner PID is alive, or which another supervisor already claimed.
  • Exit code 4 for human.answer: returned when the request is not found, not pending, or expired.