Skip to content

Pipeline Design 2

Seth Ford edited this page Feb 8, 2026 · 3 revisions

The ADR is ready. Here's the complete Architecture Decision Record:


Design: Add --json flag to shipwright status for machine-readable output

Context

The shipwright status command (scripts/cct-status.sh, ~170 lines) currently produces a human-readable dashboard with ANSI colors and Unicode box-drawing characters. It collects three categories of data:

  1. Tmux windows — finds Claude-related tmux windows, their pane counts, and active/idle status
  2. Team configs — reads ~/.claude/teams/*.json for member counts and names
  3. Task lists — iterates ~/.claude/tasks/, counts statuses, calculates progress percentages

There is no machine-readable output option. Other commands already implement --json flags (cct-cost.sh lines 253-389, cct-daemon.sh lines 2876-3095), establishing a clear pattern. The project enforces Bash 3.2 compatibility — no associative arrays, readarray, or ${var,,}.

Decision

Follow the established --json pattern from cct-cost.sh and cct-daemon.sh:

  1. Argument parsing: Add json_output=false boolean and a while [[ $# -gt 0 ]] / case loop at top of main()
  2. Data collection: Refactor the three collection sections to store results in shell variables. Build JSON arrays incrementally using jq per entry
  3. Output routing: After collection, check if [[ "$json_output" == "true" ]] — assemble final JSON with jq -n using --argjson for arrays and --arg for scalars, then return 0
  4. JSON construction: Use jq --arg / --argjson exclusively (never string interpolation). Accumulate array elements, combine with jq -s '.'

JSON Schema

{
  "timestamp": "2026-02-08T20:58:32Z",
  "version": "0.15.0",
  "tmux_windows": [
    { "session": "main", "window": "claude-myteam", "panes": 4, "active": true, "status": "active" }
  ],
  "teams": [
    { "name": "myteam", "members_count": 3, "members": ["lead", "builder", "tester"] }
  ],
  "task_lists": [
    { "team": "myteam", "total": 10, "completed": 7, "in_progress": 2, "pending": 1, "completion_pct": 70 }
  ],
  "summary": {
    "total_windows": 2, "total_teams": 1, "total_tasks": 10, "overall_completion_pct": 70
  }
}

Data Flow

main("--json")
  → parse_args() sets json_output=true
  → collect_tmux_windows() → $windows_json
  → collect_team_configs() → $teams_json
  → collect_task_lists() → $tasks_json
  → if json_output: jq -n assembles final object → stdout → return 0
  → else: existing dashboard rendering (unchanged)

Error Handling

  • No tmux running: tmux_windows = empty array []
  • No ~/.claude/teams/: teams = empty array []
  • No ~/.claude/tasks/: task_lists = empty array []
  • No jq installed: error "jq is required for --json output" → exit 1
  • All JSON to stdout; all errors to stderr (pipe-safe)

Alternatives Considered

  1. Structured text (key=value) — Pros: No jq dependency, simpler / Cons: Can't represent nested data (members list, task breakdowns), no codebase precedent, fragile for consumers
  2. Separate status-json subcommand — Pros: Clean separation / Cons: Code duplication, inconsistent with cost --json and daemon metrics --json patterns, more surface area
  3. YAML output — Pros: Human-readable / Cons: No yq guarantee, no precedent, quoting edge cases in bash

Implementation Plan

  • Files to modify:
    • scripts/cct-status.sh — Add --json flag parsing, refactor data collection into variables, add JSON output branch with jq -n
  • Files to create:
    • scripts/cct-status-test.sh — Tests following cct-daemon-test.sh patterns (valid JSON, key presence, empty-state, human output unchanged)
  • package.json — Add status test to npm test runner
  • Dependencies: jq (already used by cost, daemon, pipeline scripts)
  • Risk areas:
    • Bash 3.2: no associative arrays — use string concat or jq -s '.'
    • Existing code mixes computation with display (progress bars built inline) — refactoring must not break human output
    • pipefail + grep -c returning 0 matches → use || true guard per project conventions

Validation Criteria

  • shipwright status --json produces valid JSON (passes jq empty)
  • shipwright status --json | jq '.tmux_windows' returns an array
  • shipwright status --json | jq '.teams' returns an array
  • shipwright status --json | jq '.task_lists' returns an array
  • shipwright status --json | jq '.summary' returns an object with totals
  • shipwright status --json contains no ANSI escape codes
  • shipwright status (without --json) produces identical output to before
  • Empty state: JSON has empty arrays, not null or error
  • Missing jq + --json: clear error to stderr, exit 1
  • npm test passes including new status tests
  • All JSON values use correct types (numbers for counts/percentages, not strings)

Clone this wiki locally