Files
ruflo/v3/@claude-flow/cli/templates/grok/skills/agent-teams-grok/SKILL.md
T
Mathew BeaneandRuFlo 953d8d0018 feat: Grok Build host surface + host-agnostic team bus (ADR-402) (#3512)
* feat: Grok Build host surface + host-agnostic team bus (ADR-402)

Adds `ruflo init --grok` and nine team_* MCP tools. Together they let a
lead agent on Grok Build (or Codex, or Claude) run a named agent team
without Claude's SendMessage. The team state lives in the project under
.claude-flow/teams/.

Team bus (team_create, team_spawn, team_send, team_broadcast,
team_inbox, team_plan, team_status, team_on_stop, team_shutdown)
- One implementation: templates/grok/scripts/grok-team-bus.mjs (ops,
  CLI) plus grok-team-store.mjs (storage). The MCP tools import these
  files, the SubagentStop hook imports them, and init --grok copies
  them into a project as a CLI with no dependencies. The repo root has
  no second copy.
- Mail is scoped per team: teams/<team>/mailbox/<agent>/. team_inbox
  requires the team, and team_status counts only that team's mail.
- team.json updates take a cross-process lock (team.lock, an O_EXCL
  file holding an owner token) and are written through a temp file and
  a rename. A stale lock is broken by renaming it aside and checking
  the token, never by a blind delete, and release removes only the
  holder's own token. 30 concurrent spawns
  from separate processes register all 30.
- team_shutdown closes the team. After it, spawn, send, plan and
  on-stop refuse. team_spawn enforces maxAgents.
- A broadcast with no members is refused. priority is an integer from
  0 to 999, stored as a zero-padded filename prefix. Symlinked mailbox
  directories are refused. Concurrent drains claim each message by
  rename, so no message is delivered twice and no drain throws ENOENT.
- The spawn description is <role>:<agent>@<team>. The SubagentStop
  hook parses it to advance that team's plan. When the hook cannot
  record a team subagent, or the team is ambiguous, it writes the
  reason to stderr and exits 1.

init --grok
- Writes .grok/ (config, rules, four agent profiles, a skill, the
  SubagentStop hook), scripts/ and docs/grok/README.md in the project,
  and lists every path it wrote. --dry-run writes nothing.
- Pins the project MCP server to the running release (ruflo@<version>,
  which ships team_*) instead of @latest. From a source checkout it
  points at that checkout's bin/cli.js. Inserted values are escaped as
  TOML strings, so Windows paths are valid.
- Writes nothing outside the project unless --grok-statusline is
  passed. With the flag, it installs ~/.grok/ruflo/host-statusline.mjs
  and merges [ui.status_line] into ~/.grok/config.toml using
  @iarna/toml. The merge leaves an existing status row alone in any
  TOML form. It writes only when the re-parsed result keeps every
  other value, and otherwise prints the snippet to paste. The command
  is `node "<absolute path>"`, which needs no shell and runs no
  script from the repo.
- The status row expects only the agent-teams-grok skill.

Also classifies team_* in the capability brain (swarm-coordination)
and adds ADR-402.

Tests: __tests__/team-tools.test.ts, __tests__/grok-init.test.ts.

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(grok-host): address round-2 review of ADR-402 team bus (#3512)

N1 (blocking): root package.json "files" listed cli/dist but not
cli/templates, so npm pack (and npx claude-flow) shipped a build that
team_create / init --grok couldn't find grok-team-bus.mjs /
grok-team-store.mjs from. Added v3/@claude-flow/cli/templates/** and
verified with a real npm pack + tar extract (files present with the fix,
absent without it).

N2: breakStaleLock renamed a stale lock without re-checking it was still
the lock it first observed. A waiter that read a stale token could have
that exact lock broken by someone else and re-acquired fresh in between,
and the rename would steal that live lock out from under its holder,
opening a window for a fourth party to grab the vacated slot — two
holders at once. Now re-verifies token + mtime immediately before
renaming and backs off (no rename at all) if either changed. Added a
direct regression test (monkeypatched fs to force the exact interleaving)
plus a concurrent-CLI-process test with a pre-seeded stale lock.

N3: LOCK_WAIT_MS (10s) was shorter than LOCK_STALE_MS (30s), so any
acquire attempted in the ~20s gap between "waiter gives up" and "lock
considered stale" failed even with nothing actually stuck — and the
SubagentStop hook's own 5s command timeout couldn't survive either value.
Lowered stale/wait to 4s/4.5s (wait >= stale, both comfortably under the
hook's 5s budget with real critical sections being sub-millisecond JSON
r-m-w). Also replaced the synchronous Atomics.wait lock-wait loop with an
async setTimeout-based poll (sleepMsAsync), so an MCP server keeps serving
other requests while a caller waits for the lock; threaded async/await
through withTeamLock/createTeam/spawnMember/runCli/main and the
SubagentStop hook and team-tools.ts's dispatcher. sleepMs (sync) stays
only for writeJsonAtomic's bounded Windows rename retry.

Minor 1: --grok-statusline replaced a symlinked ~/.grok/config.toml with
a plain file, destroying the symlink. writeFileAtomic now resolves an
existing symlink and writes through it instead.

Minor 2: a TOML integer above 2^53 in the user's config parses to a
BigInt (@iarna/toml) and crashed JSON.stringify inside the status-line
merge, which ran as the LAST step of init — leaving project files already
written. Now validated up front, before any file is touched, naming the
offending key; init fails clean with nothing written instead of half-done.

Minor 3: host-statusline.mjs matched `trusted = true` / `[mcp_servers.x]`
via substring/regex, so a commented-out trusted=true read as trusted and
an `enabled = false` server still counted as loaded. Can't add a runtime
dependency on @iarna/toml here (this script ships as a zero-dependency
copy outside any node_modules tree — project scripts/ and
~/.grok/ruflo/host-statusline.mjs). Added a small comment-aware
table/key parser instead and used it for grok, and for codex's
mcp_servers check too (same bug class).

Minor 4: team_create --force reopened a team but left the old
incarnation's mailboxes on disk. Now clears mailbox/ when recreating.

Minor 5: priority accepted "1e2" and "0x10" (Number() coerces both).
Now requires a plain base-10 integer literal string.

Minor (stray changes): reverted an incidental .helpers-version bump and
a router.js mode change (644->755) picked up from a concurrent session's
helper auto-refresh — not part of this PR.

Verified: cli build + tsc --noEmit clean; grok-init.test.ts and
team-tools.test.ts (41 tests, including 8 new ones) and
guidance-brain.test.ts pass; full `npm test` for @claude-flow/cli is
green except 20 pre-existing failures across 16 files, all from
@claude-flow/memory / @claude-flow/mcp / @claude-flow/codex not being
built in this environment (none touch grok/team/statusline code).

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(grok-host): address round-3 review nits on the team lock and status line (#3512)

A lock whose holder pid is still alive is no longer broken after 4s, so a stalled writer does not lose an update. An existing [ui.status_line] no longer fails init when another value is a BigInt. Quoted trusted-folder keys may contain ].

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(grok-host): keep the TOML parser out of the MCP tool import path (#3512)

grokTemplatesRoot moves to init/grok-templates.ts, which has no
dependencies. The team_* tools import it from there, so loading the MCP
tool table no longer pulls in grok-generator and @iarna/toml. On current
main, analyze-json-output.test.ts runs the analyze command from a copied
source tree with only cli-core and security beside it, and failed 20 of
20 with "Cannot find package '@iarna/toml'" before this change.
grok-generator re-exports grokTemplatesRoot, so its callers are unchanged.

Co-Authored-By: RuFlo <ruv@ruv.net>

---------

Co-authored-by: RuFlo <ruv@ruv.net>
2026-10-20 05:42:06 -04:00

4.3 KiB

name, description
name description
agent-teams-grok Run Ruflo-style named Agent Teams on Grok Build using the host-agnostic team bus (scripts/grok-team-bus.mjs). Use when coordinating multi-agent pipelines, feature development with architect→coder→tester→reviewer, or replacing Claude SendMessage.

Agent Teams on Grok (ADR-402)

Claude SendMessage / TeammateTool are not available. Prefer Ruflo MCP team_* tools; CLI bus is the fallback.

Preferred: MCP tools

Tool Purpose
team_create Create team + topology
team_plan Ordered pipeline steps
team_spawn Register agent; returns spawn plan for spawn_subagent
team_send / team_broadcast Handoff messages
team_inbox Drain/peek mailbox
team_status / team_on_stop / team_shutdown Lifecycle

Discover: search_tool query team_create. Call via use_tool as ruflo__team_create etc.

Quick start (CLI fallback)

# 1. Create team
node scripts/grok-team-bus.mjs create --name feature-x --topology hierarchical

# 2. Register plan
node scripts/grok-team-bus.mjs plan --team feature-x \
  --steps '["architect","developer","tester","reviewer"]'

# 3. Register agents (prints spawnPlan JSON for spawn_subagent)
node scripts/grok-team-bus.mjs spawn --team feature-x --agent architect --role architect \
  --prompt "Design <feature>. Handoff to developer." --next developer
node scripts/grok-team-bus.mjs spawn --team feature-x --agent developer --role developer \
  --prompt "Implement from architect design." --next tester
node scripts/grok-team-bus.mjs spawn --team feature-x --agent tester --role tester \
  --prompt "Test implementation." --next reviewer
node scripts/grok-team-bus.mjs spawn --team feature-x --agent reviewer --role reviewer \
  --prompt "Review code and tests."

Lead (you) then

Checked against Grok Build 1.0.41. Pass only the live spawn arguments:

spawn_subagent({
  prompt: spawnPlan.prompt,
  description: spawnPlan.host.grok.spawn.description,
  background: spawnPlan.host.grok.spawn.background,
  isolation: spawnPlan.host.grok.spawn.isolation,
})
  1. Parse spawnPlan.host.grok.spawn (and prompt). Call spawn_subagent in one message for every agent (background: true).
  2. Leave host.grok.advisory on the plan. capability_mode and subagent_type are not spawn arguments on this Grok. The prompt carries the read-only or worktree constraint. isolation is the knob Grok enforces.
  3. .grok/agents/ruflo-* are session profiles (grok --agent-profile ruflo-coder or /agents). spawn_subagent does not select them. An omitted type is general-purpose.
  4. Children must not call spawn_subagent. Nesting depth is 1. The lead spawns the whole pipeline.
  5. Pass description unchanged (<role>:<agent>@<team>): the SubagentStop hook reads it to run on-stop for that team. Then spawn or resume the next step if needed.
  6. Synthesize results; shutdown the team. A shut-down team refuses spawn and send; team_create --force reopens the name.

Every call names its team: mail is per team, and several teams can run at once. team_spawn stops at the team's maxAgents.

If grok --version is newer than 1.0.41, re-read ~/.grok/docs/user-guide/16-subagents.md (Spawning Subagents) before forwarding extra keys. A key the schema dropped fails the spawn.

Defaults

Role Prompt constraint (advisory.capability_mode) isolation (passed through)
architect / reviewer read-only none
developer / tester full tools worktree

Messaging

node scripts/grok-team-bus.mjs send --team feature-x --to developer \
  --from architect --summary "design" --message "..."
node scripts/grok-team-bus.mjs inbox --team feature-x --agent developer
node scripts/grok-team-bus.mjs status --team feature-x

Also use Ruflo MCP when live

  • memory_search / memory_store with namespace team:feature-x
  • swarm_init for coordination records (then you still execute)

Anti-patterns

  • Waiting for swarm start to write code
  • Inventing SendMessage
  • Passing capability_mode or subagent_type into spawn_subagent (they are advisory on Grok Build 1.0.41)
  • Parallel coders on the same tree without worktrees
  • A child calling spawn_subagent (depth limit is 1)