Skip to content

Add multi-agent harness support (Pi, Codex, Claude Code)#58

Merged
maxBRT merged 4 commits into
mainfrom
feature/add-harness-support
Jul 21, 2026
Merged

Add multi-agent harness support (Pi, Codex, Claude Code)#58
maxBRT merged 4 commits into
mainfrom
feature/add-harness-support

Conversation

@maxBRT

@maxBRT maxBRT commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

Makes agent: / --agent an Agent kind (cursor, pi, codex, claude) instead of a binary path, with Init prompting for a kind on TTY (non-TTY defaults to cursor), config validation that rejects legacy binary-style values, and an agent Port factory wired through the CLI. Adds headless adapters for Pi, Codex, and Claude Code so a Run can drive every Phase through one chosen kind via that kind's default PATH binary, with Ship-owned timeouts and curated observability into the same sink Cursor already uses.

Linked issues

RISK

  • Breaking config change (high likelihood for existing checkouts): checkouts with agent: agent or a binary path in .ship/config.yaml will fail at config parse until updated to a kind (agent: cursor). Operators who have not migrated will see a clear error with a migration hint, but Runs will not start until they edit the Shipfile.
  • Wrong or missing PATH binary (medium): if the chosen kind's default binary (agent, pi, codex, or claude) is missing or not authenticated, preflight fails before queue confirmation, or a Phase fails mid-Run and triggers Abort (undo commits for the failing Ticket). Affects anyone switching kinds without installing/auth'ing that CLI.
  • Harness flag / stream-format drift (medium for non-Cursor kinds): adapters depend on each CLI's current headless flags and JSON event shapes. Vendor CLI upgrades that rename flags or change success events can turn Phases into failures or Abort for that kind while Cursor continues to work.
  • Unattended permissions (inherent, intentional): Codex uses full approval/sandbox bypass and Claude uses skip-permissions for AFK Phases. A misconfigured or malicious Ticket prompt can cause broader local side effects under those kinds than a human-gated session would. Likelihood tracks how carefully Tickets are specified, not this PR's wiring.

QA — stress-test plan for a human

1. Happy path

From a clean git checkout of a real project (with gh authenticated and at least one open GitHub issue labeled ship):

  1. Build: go build -o /tmp/ship ./cmd/ship
  2. Init (TTY): cd /path/to/project && /tmp/ship init — confirm the prompt lists cursor, pi, codex, claude, type cursor, and verify .ship/config.yaml has agent: cursor.
  3. Cursor Run: with Cursor's agent on PATH and logged in, run /tmp/ship --max-iterations 1 — confirm queue picker, one Iteration (Implement then Review), Final Phase, and a PR opens.
  4. Pi: set agent: pi (or --agent pi), ensure pi is on PATH and authenticated, run a short Run (--max-iterations 1) and confirm Phases complete.
  5. Codex: same with agent: codex / codex on PATH.
  6. Claude: same with agent: claude / claude on PATH.
  7. Flag override: with Shipfile agent: cursor, run /tmp/ship --agent pi --help is not enough — run a dry config path by starting a Run with --agent pi and confirm preflight looks for pi (or completes if Pi is installed).

2. Edges / failure cases

  1. Legacy Shipfile: put agent: agent (or agent: /usr/local/bin/agent) in .ship/config.yaml and run /tmp/ship — expect parse failure mentioning agent: cursor.
  2. Unknown kind: agent: opencode or --agent opencode — expect unknown-kind error.
  3. Missing binary: agent: codex with codex removed from PATH — expect preflight failure before the Ticket picker stamps the queue.
  4. Init invalid kind on TTY: ship init in a dir without .ship/config.yaml, type nope — expect failure and no new Shipfile written.
  5. Non-TTY Init: ship init </dev/null (or equivalent non-TTY) — expect agent: cursor written with no prompt.
  6. Optional: force a Phase timeout with a tiny --timeout against a live Agent — confirm Abort restores the Ticket's commits and leaves ship on unfinished Tickets.

3. Out of scope

  • Tracker label creation / GitHub Ticket port internals beyond confirming the Run still claims and Done's Tickets as before.
  • Throbber / picker UI polish unrelated to Agent kind selection.
  • Live network fuzzing of every Agent vendor event type beyond one successful Phase per kind.
  • README / guide.html copy updates (still Cursor-centric in places); not required to validate the adapters.

maxBRT added 4 commits July 21, 2026 09:46
Repurpose Shipfile/flag agent from binary path to cursor|pi|codex|claude,
prompt for kind on TTY Init, and wire Runs through agent.New with PATH preflight.
Wire agent kind pi through the factory so Runs spawn ephemeral print/JSON Pi with project trust, Ship-enforced timeouts, and curated tool/token events from agent_end streams.
Wire agent kind codex through the factory so Runs spawn ephemeral exec/JSON Codex with full approval bypass, Ship-enforced timeouts, and curated tool/token events from turn.completed streams.
@maxBRT
maxBRT merged commit 73c00ae into main Jul 21, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant