Skip to content

feat(agents): a Crew seat may run without a saved agent - #183

Merged
bryantderosier merged 4 commits into
crews/08-crews-design-recordsfrom
crews/09-custom-seats
Sep 21, 2026
Merged

bryantderosier merged 4 commits into
crews/08-crews-design-recordsfrom
crews/09-custom-seats

Conversation

@bryantderosier

@bryantderosier bryantderosier commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

A Crew could only seat agents with a saved definition, so a dynamic Crew that did not fit a mold anyone had saved could not be composed. Jackson raised this on #152 and I agreed.

A seat may now name no saved agent. The Captain proposes it with agent unset, or I pick Custom agent, the first choice in the roster card's agent list, and give the seat a name and instructions. A custom seat runs on the Captain's own provider, model, and runtime mode, since it has no policy of its own and the human approved it; it carries no persona assignment and no handoff obligation, and the gate shows it as "Custom agent · Runs as the Captain". The gate notice and the seat briefs say agent=custom for it.

Migration 15 rebuilds j5_agent_crew_member with a nullable agent_id; the contracts, the MCP schemas, and the Fleet roster follow. Tests cover the launcher (Captain's route and mode, no assignment, no obligation), the gate (a custom seat skips the library check), and the card (a custom seat needs instructions).

Stacked on #152. Design record: docs/j5/worklog/2026-09-16-crew-command-decoupling.md, "the second round".

Evidence

The proposed roster carries a Critic seat and a custom seat (writer, "Runs as the Captain"). Choosing Custom seat for a new seat asks for its name and instructions; the label reads "Custom seat" because #185 sits on top of this branch on my dev server.

Custom seat in the roster card

🤖 Generated with Claude Code

Closes #209.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 effective changed lines (test files excluded in mixed PRs). labels Sep 17, 2026
@bryantderosier
bryantderosier added this pull request to stack #153 September 17, 2026 12:29
@bryantderosier bryantderosier self-assigned this Sep 17, 2026

@Jacksondr5 Jacksondr5 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Custom seats are the right addition and the shape is sound: reservation identity works for them, no agent_id non-null assumptions survive in the reads or cards, migration 015 preserves rows and constraints (the second reviewer probed it in-memory), the seat brief carries instructions verbatim with no obligation block, and no upstream file is touched.

Requesting changes on two things.

  1. The gate promises an access level the seat does not get (inline on CrewLaunchService.ts). This is not a ceiling question; the gate is the human's approval and crews.md AC3 says it shows each seat's access before the person approves.
  2. A Captain-proposed custom seat may carry no instructions. crewSeatShapeProblem in crewLimits.ts treats instructions as optional, validateSeats skips a null agent, and the MCP and HTTP schemas make instructions optional, so propose_crew with {seat: "writer", reason: "drafts notes"} files cleanly and the card shows a seat with nothing but the brief and no edit affordance. The card's own add path requires instructions, and crewLimits.ts says the rule is checked at every door. Require instructions for a null-agent seat in crewSeatShapeProblem, once.

Comments:

  • Migration 015 has no test that a populated member row survives the rebuild and that a null agent_id then inserts. AGENTS.md: backend behavior changes ship with focused tests for that behavior.
  • A custom seat skips the provider-availability check that saved seats get in resolveSeats, so a vanished Captain provider records the Crew and fails asynchronously. Rare; a one-line check keeps "whole or not at all".
  • agent=custom in notices collides with a persona literally named custom, which the id schema allows. Reserve the id or write the sentinel as an empty value.
  • crews.md's definition paragraph still says every seat is persona-backed with a handoff obligation.

Reviewed by Claude Fable 5.1 in Claude Code, with an independent pass by GPT-6-Astra in Codex.

Comment thread apps/server/src/j5/a2a/CrewLaunchService.ts Outdated
@bryantderosier

Copy link
Copy Markdown
Collaborator Author

627213cfc takes your first option: a custom seat's mode comes from the Captain's resolved persona runtime, and the gate says exactly what is inherited (model and access, not a sandbox) since only a persona assignment can carry one. A custom seat without instructions is refused at the shared shape check. The migration test, the provider check, the custom sentinel, and the crews.md paragraph are tracked in #187.

@Jacksondr5 Jacksondr5 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A custom seat's mode now comes from the Captain's resolved persona runtime (workspace-write to auto-accept-edits, read-only to approval-required), the gate says what is inherited and the docs say the sandbox is not, and a custom seat without instructions is refused at the shared shape check with a test for each. Approving.

Two nits for #187 alongside the ones already there: the shape check accepts whitespace-only instructions (trim before testing emptiness), and "model and access" on the card reads a touch cleaner as "model and access mode" since access is exactly what is not fully carried.

Reviewed by Claude Fable 5.1 in Claude Code, with an independent pass by GPT-6-Astra in Codex.

@bryantderosier

Copy link
Copy Markdown
Collaborator Author

Migration follow-up is in 571cb0b9c. Migration 017 checks whether agent_id is still NOT NULL and only then runs the member-table rebuild. This repairs a database that applied lower-stack migration 016 while 015 was absent, without renumbering applied history or resetting crew tables. Tests cover that upgrade, an existing custom-seat database, retained populated rows, nullable inserts, and repeated migration runs.

@bryantderosier

Copy link
Copy Markdown
Collaborator Author

Follow-ups are pushed in f03c6763a. Custom seats validate the current provider/model before any Crew record or thread is created; whitespace-only instructions are rejected; the gate promises the Captain’s access mode. Empty persona values distinguish custom seats from a saved persona named custom. Existing populated-database upgrade coverage remains intact, including migration 017; no reset is required. Focused tests and server/web typechecks pass.

@bryantderosier
bryantderosier force-pushed the crews/09-custom-seats branch 2 times, most recently from c9ba701 to 5b16f8b Compare September 21, 2026 11:56
bryantderosier and others added 4 commits September 21, 2026 11:07
Jackson wants dynamic Crews that do not fit a saved mold. A seat may now name no agent: the Captain proposes it with agent unset, or the person picks Custom agent (the first choice on the roster card) and gives it a name and instructions. A custom seat runs on the Captain's own provider, model, and runtime mode, since it has no policy of its own and the human approved it; it has no handoff obligation and no persona assignment. Migration 15 makes the member row's agent id nullable.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nd must carry instructions

The seat copied the Captain's stored runtime mode, which for a persona
Captain is whatever the person picked at launch rather than the policy
it actually runs under, so a read-only Captain's custom seat started
full-access while the gate said it runs as the Captain. The mode now
comes from the Captain's resolved persona runtime, and the gate, tools,
and docs say what is inherited: provider, model, and access mode, not a
sandbox. A custom seat proposed without instructions is refused at the
shape check every door shares, matching the card's own rule.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bryantderosier
bryantderosier merged commit 56bc2a4 into j5/main Sep 21, 2026
20 checks passed
@bryantderosier
bryantderosier deleted the crews/09-custom-seats branch September 21, 2026 15:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 effective changed lines (test files excluded in mixed PRs). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A Crew seat may run without a saved agent

2 participants