Skip to content

feat(spawn): auto-create team-of-one for globally registered teamless agents - #1174

Merged
namastex888 merged 1 commit into
devfrom
feat/team-of-one-auto-create
Apr 17, 2026
Merged

namastex888 merged 1 commit into
devfrom
feat/team-of-one-auto-create

Conversation

@namastex888

Copy link
Copy Markdown
Contributor

Summary

  • When a detached genie spawn can't resolve a team (no --team, no GENIE_TEAM, no parent session, no on-disk team already listing the agent), fall back to auto-creating a team-of-one named after the agent — only if that agent is registered in the global agent directory.
  • Unblocks the TUI flow where pressing Enter on an offline, teamless, globally registered agent (e.g. khal-os after ghost-team cleanup) was failing silently with "--team is required".
  • Unknown agents still fail closed; typos can't materialize bogus teams.

Trace that motivated this

From a read-only investigation:

  • Nav.tsx:707 spawns detached with --session <name> --new-window and strips GENIE_TEAM from env.
  • resolveTeamAndResume (agents.ts:1647-1652) used to exit 1 with --team is required when discoverTeamName() and findTeamsContainingAgent() both came back empty.
  • The detached child's stderr now routes to ~/.genie/logs/tui-spawn/<session>-<ts>.log (PR fix(spawn): fall back to on-disk team config when GENIE_TEAM unresolved #1170), but the TUI pane doesn't surface that to the user, so the failure looked like "TUI refuses to start the agent".

With this change: if the agent exists in the directory, spawn creates a team-of-one named after it. resolveNativeTeam → ensureNativeTeam materializes the config downstream exactly like any other team, so no new plumbing is introduced.

Changes

  • src/term-commands/agents.ts: +11 lines in resolveTeamAndResume — directory-gated auto-team-of-one branch between the on-disk scan and the final --team is required error.
  • src/lib/claude-native-teams.test.ts: +37 lines — regression tests for findTeamsContainingAgent (empty dir, no-match, single match, multiple ghost teams). Guards the scan the new branch sits on top of.

Test plan

  • bun test src/lib/claude-native-teams.test.ts — 37 pass, 0 fail (4 new)
  • bun run typecheck — clean
  • bun run lint — no new warnings (1 pre-existing complexity warning at agents.ts:1096 untouched)
  • bun run build — 4.6 MB bundle produced
  • Pre-push hook: full suite 2505 pass, 0 fail
  • Live verification on the Felipe server: after ghost-team cleanup, TUI Enter on offline khal-os starts it under team khal-os (planned as G-C of wish team-of-one-auto-create)

When a detached spawn hits resolveTeamAndResume with no team resolution
(no --team flag, no GENIE_TEAM, no parent session, no on-disk team
already listing the agent), fall back to auto-creating a team named
after the agent itself — *provided* the agent is registered in the
global agent directory. The team config is materialized downstream by
resolveNativeTeam → ensureNativeTeam; no new plumbing required.

Motivation: TUI Enter on an offline, teamless, globally registered
agent (e.g. `khal-os` after cleanup) now spawns it under a clean
`khal-os` team instead of failing silently with "--team is required",
which the detached spawn swallowed into a log file the user never saw.

Unknown agents still error out — the directory gate prevents typos
from silently materializing bogus teams.

Coverage:
- Added findTeamsContainingAgent tests (empty dir, no-match, single
  match by name, multiple matches) to guard the fallback scan that
  precedes the new branch.
@coderabbitai

coderabbitai Bot commented Apr 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a9a457c1-18bc-4b7a-ab59-90a0503705cb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/team-of-one-auto-create

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@namastex888
namastex888 merged commit 8ff2774 into dev Apr 17, 2026
6 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces unit tests for the findTeamsContainingAgent function and implements logic to automatically create a 'team-of-one' for globally registered agents when no team is specified. A review comment suggests simplifying the team resolution logic in src/term-commands/agents.ts by removing a redundant directory lookup and ensuring compatibility with custom roles.

Comment on lines +1651 to +1656
if (!team) {
const directoryEntry = await directory.get(effectiveRole);
if (directoryEntry) {
team = nativeTeams.sanitizeTeamName(effectiveRole);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The directory lookup here is redundant because handleWorkerSpawn already resolves the agent via resolveAgentForSpawn before calling this function. Furthermore, using effectiveRole for the lookup means that auto-creation will fail if the user provides a custom role via --role (as the alias won't be in the directory), even if the underlying agent is registered. Since handleWorkerSpawn only proceeds if the agent is found in the directory or built-ins, we can safely assume the agent is registered and simplify this block.

  if (!team) {
    team = nativeTeams.sanitizeTeamName(effectiveRole);
  }

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a03794d34e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1652 to +1654
const directoryEntry = await directory.get(effectiveRole);
if (directoryEntry) {
team = nativeTeams.sanitizeTeamName(effectiveRole);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restrict team-of-one fallback to non-builtin agents

This fallback uses directory.get(effectiveRole), which returns built-in agents as well as globally registered ones, so detached spawns with no team context now auto-assign teams for built-ins too. In practice, genie spawn <builtin> can silently create or reuse a same-named team even when no explicit team/session context exists, which is broader than the intended “global directory agent” gate and can route work into an unintended existing team with that name. Consider resolving with builtin metadata and only allowing this path for non-builtin entries.

Useful? React with 👍 / 👎.

namastex888 pushed a commit that referenced this pull request Apr 17, 2026
Follow-up to #1174 (auto-team-of-one). The isolatedSessionSpawn
heuristic in #1173 used `sessionOverride !== team` as a proxy for
"TUI per-agent spawn". That proxy breaks the moment
resolveTeamAndResume auto-creates a team-of-one named after the
agent — now session equals team, isolatedSessionSpawn goes false,
and resolveSpawnTeamWindow runs again, producing the same
3-window (bash + team-named + claude) cruft topology Felipe hit
before.

The fix: when the caller explicitly passes both --new-window and
--session, always skip team-window creation. The agent runs in
its own window in its own session — team windows exist to group
multi-member teams that share a session, and the TUI spawn path
doesn't want that coordination surface.
automagik-genie pushed a commit that referenced this pull request Apr 17, 2026
…mplification)

PR #1175 (merge f43db8d) simplified the isolatedSessionSpawn guard in
launchTmuxSpawn — removed the `sessionOverride !== team` redundancy
that was a stale proxy for TUI per-agent spawn. Auto-team-of-one
(PR #1174) now makes session and team equal for globally-registered
teamless agents, and the explicit `--session` flag should be honored
unconditionally. Accepted theirs verbatim.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@automagik-genie
automagik-genie deleted the feat/team-of-one-auto-create branch September 25, 2026 04:49
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.

2 participants