feat(team-mode): align member and lead prompts with Claude Code free-code reference

Bring the team member addendum and the team-mode skill in line with the
Claude Code experimental Agent Teams reference (../free-code) on the
behavioral framing the LLM needs, while keeping every omo-specific
constraint (TeamRunId param, lead-only tool blocklist, eligibility
registry, sisyphus-junior routing) intact.

Member addendum (src/features/team-mode/member-guidance.ts) — adopt
free-code teammatePromptAddendum.ts wisdom that was missing:

- "User interacts primarily with the team lead" — members no longer try
  to address the user directly; they coordinate via task system + DMs.
- Stronger emphasis that plain assistant text is invisible to the team;
  team_send_message is mandatory, not optional.
- Broadcast (`to: "*"`) called out explicitly with "sparingly" guidance
  and the lead-only constraint.
- "Idle is normal" section: idle ≠ done, idle teammates can still
  receive messages, the lead must not treat idle as an error.
- "Communication rules" section forbidding structured JSON status
  messages and forbidding terminal tools as a peer-inspection backdoor;
  always reference teammates by NAME, not session ID.
- Auto-delivery framing: messages arrive as new turns, no manual inbox
  polling, no need to quote a teammate's message back to the lead.

Team-mode skill (src/features/builtin-skills/skills/team-mode.ts) —
adopt free-code TeamCreateTool/prompt.ts sections that were missing:

- Task ownership: any agent can set/change `owner` via team_task_update.
- Automatic message delivery: <peer_message ...> envelope flow.
- Teammate idle state: idle is the expected post-turn state; peer DM
  summaries surface in the lead's idle notification.
- Discovering team members: team_status + ~/.omo/teams/ config; refer by
  name, never raw session IDs.
- Task list coordination: claim by ID order (lowest first), check after
  every completion, escalate blocking deadlocks to the lead.
- Communication rules: same anti-patterns as the member addendum, scoped
  for the lead's awareness (no JSON status, no terminal peer-inspection,
  no delegate-task from inside members).

Test (create.test.ts) updated to track the renamed section header
("Lead-only tools you must NOT call") and to lock the new free-code
parity assertions ("user interacts primarily with the team lead",
"Idle is normal", "structured JSON status messages").

All other contract tests (team-mode skill keyword/section tests,
member parser, runtime tests) untouched and still passing.

Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode).
This commit is contained in:
YeonGyu-Kim
2026-04-30 16:40:27 +09:00
parent f6643e7e77
commit c90be7f9a6
3 changed files with 75 additions and 14 deletions
@@ -150,12 +150,15 @@ describe("createTeamRun", () => {
const firstPrompt = (launchMock.mock.calls as Array<[LaunchInput]>)[0]?.[0].prompt ?? ""
// then
expect(firstPrompt).toContain("Do not call lead-only lifecycle tools")
expect(firstPrompt).toContain("Lead-only tools you must NOT call")
expect(firstPrompt).not.toContain("3. Request shutdown via `team_shutdown_request`")
expect(firstPrompt).toContain("Include `summary` and `references`")
expect(firstPrompt).toContain("Move to `status: \"in_progress\"` when you start working")
expect(firstPrompt).toContain("delegate-task: Do not call this")
expect(firstPrompt).toContain("Do NOT call this from inside team members")
expect(firstPrompt).toContain("lead can decide whether to request shutdown")
expect(firstPrompt).toContain("user interacts primarily with the team lead")
expect(firstPrompt).toContain("Idle is normal")
expect(firstPrompt).toContain("structured JSON status messages")
})
test("rolls back launched members in reverse order when a later spawn fails", async () => {