Skip to content

cli: one root error seam so every error path emits the agent-mode next_action line #1040

Open

Description

@pengfei-threemoonslab

Problem

CLAUDE.md:32, skills/agents-shipgate/SKILL.md:112 and AGENTS.md:403 promise a structured next_action JSON line on stderr in agent mode, without qualification. In practice 16 of 38 error paths emit it:

  • 15 CLI modules never call the emitter: fixture, skill, install_hooks, org, feedback, registry, self_check, _register_baseline, capability, authorization, evidence_packet, main, attest, mcp and trigger (for example cli/attest.py:122 typer.echo(...); raise typer.Exit(3));
  • Click usage and BadParameter errors never emit it: diff --base nope-ref --json exits 2 via typer.BadParameter (cli/diff.py:98) with no JSON line.

Raw str(ValidationError), with pydantic type codes, input values and errors.pydantic.dev URLs, becomes the user- and agent-facing message (cli/preflight.py:536 and other boundaries). The agents-shipgate-mcp console script dumps a traceback when the [mcp] extra is absent (mcp_server/server.py:362).

Evidence

  • #59 (medium) Agent-mode next_action JSON is promised for all errors but emitted on 16 of 38 error paths
    • Where: src/agents_shipgate/cli/attest.py:122
    • Evidence: attest.py:122 except InputParseError as exc: typer.echo(...); raise typer.Exit(3) from exc. diff --base nope-ref exits 2 via typer.BadParameter (diff.py:98) with no JSON line.
    • Observed: A Claude Code session (agent mode auto-enabled via CLAUDECODE=1) runs agents-shipgate agent handoff --from agents-shipgate-reports/verifier.json --json before verify has run. Stderr is the prose line Input parsing error: verifier.json not found: ..., exit 3, no JSON line. The agent's documented routing rule ('parse the JSON line, follow next_action') has nothing to parse; the same happens for attest, trigger --changed-files, capability export --config, baseline save -c, org bundle --from, feedback export --from, mcp audit --diff, skill lint <path>, fixture run <name>, install-hooks --target cursor.
    • Repro: cd $S/sra; AGENTS_SHIPGATE_AGENT_MODE=1 ./shipgate agent handoff --from /nonexistent.json --json; AGENTS_SHIPGATE_AGENT_MODE=1 ./shipgate trigger --changed-files /nonexistent.txt --json; AGENTS_SHIPGATE_AGENT_MODE=1 ./shipgate capability export --config /nonexistent.yaml --out /tmp/x.json # each: prose only, no JSON line
  • #82 (low) Raw pydantic validation dumps are surfaced as user-facing and agent-facing messages
    • Where: src/agents_shipgate/cli/preflight.py:536
    • Evidence: preflight.py:536 raise ConfigError(f'Invalid {source_label}: {exc}') from exc.
    • Observed: echo '{"planned_files":["x.py"]}' | agents-shipgate preflight --plan - --json in agent mode: message is Invalid Preflight plan: 1 validation error for PreflightPlanV1\nplanned_files\n Extra inputs are not permitted [type=extra_forbidden, input_value=['x.py'], input_type=list]\n For further information visit https://errors.pydantic.dev/2.13/v/extra_forbidden; next_action routes to verify --preview, which does not help with the plan shape.
    • Repro: cd $S/sra; echo '{"planned_files":["x.py"]}' | AGENTS_SHIPGATE_AGENT_MODE=1 ./shipgate preflight --workspace . --config shipgate.yaml --plan - --json
  • #94 (low) The agents-shipgate-mcp console script dumps a traceback when the [mcp] extra is absent
    • Where: src/agents_shipgate/mcp_server/server.py:362
    • Evidence: server.py:362 def main() -> None: serve_stdio().
    • Observed: A user adds agents-shipgate-mcp to their MCP client config after pipx install agents-shipgate. The client shows a crashed server with a traceback, and the suggested pip install does not reach the pipx venv.

Why it matters

  • Coding agents: the documented routing rule (parse the JSON line, follow next_action) has nothing to parse on more than half of the error paths.
  • Local CLI user: pydantic dumps and tracebacks instead of one actionable line.

Proposed fix

  • One exception and UsageError seam at the root group (a wrapper around typer.main.get_command(app), or overriding main()/Context.fail) that maps ConfigError, InputParseError, AgentsShipgateError, ValidationError and Click usage errors to the exit table, prints the prose line and calls emit_agent_mode_error_action. Delete per-command echo-and-exit pairs the seam covers.
  • One ValidationError formatter (location, reason, accepted keys) used at every boundary.
  • mcp_server/server.py main(): catch ConfigError, print one line with an install hint matching the install mode, exit 2.
  • If any path stays uncovered, qualify the promise in CLAUDE.md, AGENTS.md and SKILL.md (protected paths). CHANGELOG.

Protected paths: yes; this change touches protected paths and needs owner review before merge.

Acceptance criteria

  • A test walks every leaf command in the Click tree, triggers an invalid input in agent mode, and asserts exactly one parseable next_action JSON line on stderr and a documented exit code.
  • diff --base nope-ref --json in agent mode emits the JSON line.
  • No error message contains errors.pydantic.dev or type= codes (test over representative ValidationErrors).
  • agents-shipgate-mcp without the extra exits 2 with one line and no traceback.

Out of scope

Source

Engineering review 2026-10-12, findings #59, #82, #94 (the maintainer's private copy of the 2026-10-12 engineering review § Findings; verifier reproductions in its evidence companion, claims A47, A57, A56, A104).
Dimensions: cli-ux-agent-ergonomics, packaging-deps.
Implement after: #1022.
Related: #328 (ours-versus-theirs error classification).

Activity

  1. added
    bugSomething isn't working
    P1Picked up inside the current milestone window; keep about 15 open
    area:agent-modeAgent-mode contract: control envelope, next actions, command strings
    engineering-reviewFiled from the 2026-10-12 comprehensive engineering review
    on Oct 13, 2026
  2. added
    P2Queued; valuable but not blocking
    and removed
    P1Picked up inside the current milestone window; keep about 15 open
    on Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Queued; valuable but not blockingarea:agent-modeAgent-mode contract: control envelope, next actions, command stringsbugSomething isn't workingengineering-reviewFiled from the 2026-10-12 comprehensive engineering review

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions