Move the external agentic-qe-fleet entry from v3.15.10 (e5814a2f) to
v3.15.11 (221d6de15c73bb385961e4e649d8fcc1f5dc2dea). The plugin folder
changed only its version and its MCP pin (agentic-qe@3.15.11). Updates
the README links, the external-plugins test fixture and ADR-484.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* 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>
* feat(marketplace): list Agentic QE (agentic-qe-fleet) as an external, pinned plugin
The ruflo marketplace now lists agentic-qe-fleet by a git-subdir source pinned
to agentic-qe v3.15.0 (1363bc7d), so `/plugin install agentic-qe-fleet@ruflo`
installs the plugin from its own repository: 11 QE agents, 9 skills, 9 commands,
the agentic-qe MCP server pinned to 3.15.0, and the aqe-mod guard.
Tooling that assumed every entry is a local ./plugins folder now handles an
external one:
- validate-marketplace.yml checks an external entry (git-subdir, https url,
path without .., full sha, description) instead of failing on it
- smoke-all-plugins checks out each external entry at its sha and runs its own
scripts/smoke.sh (--skip-external to omit); the workflow also runs when
marketplace.json changes
- ruflo-console 0.40.9: plugin-map line (Dev Tools), the coverage test requires
a line for every external entry, and the Plugin Catalog reads an external
plugin from its install path in installed_plugins.json (EXT badge)
- README and plugins/README rows; ADR-484 records the decision and evidence
* docs(adr-484): record what Claude Code before 2.1.69 does with the external entry, and main's existing floor
* fix(ci): fence the external-plugin smoke: github-only sources, realpath containment, scrubbed env and cwd, read-only token
Review findings 1 and 2 on #3950:
- scripts/external-plugins.mjs: sources must be https://github.com/<owner>/<repo>(.git);
the plugin folder, its manifest and smoke.sh must stay inside the checkout after realpath;
the external smoke.sh runs with only PATH, LANG, TERM and CI kept (no GITHUB_TOKEN,
ACTIONS_*, *_TOKEN, *_KEY, *SECRET*), a temporary HOME, and its checkout (in a temp
folder outside the workspace) as cwd; git fetch runs with the same env
- validate-marketplace.yml applies the same github-only allowlist and path rule
- all-plugins-smoke.yml: permissions contents: read, persist-credentials: false,
runs tests/external-plugins.test.mjs
- tests/external-plugins.test.mjs: non-github host and lookalikes refused by both
validators, symlink escapes refused, child env has no GITHUB_TOKEN and cwd is outside
the workspace
* ci(all-plugins-smoke): raise the smoke-all timeout from 10 to 15 minutes
Review finding 4 on #3950: green runs on main take 9m40-9m50s, so the job sat on the
10-minute cap and was cancelled at 10m16s on this PR.
* test(console): an external plugin's description, version, source line and docs are stripped of escapes and bidi controls
Review finding 3 on #3950: the catalog reader already passes every external manifest
string through plain() (ESC/CSI/OSC sequences, C0/C1 controls, U+202A-202E and
U+2066-2069 removed); this test holds it to that.
* ci(test-ratchet): tests/external-plugins.test.mjs runs under node --test, not the root vitest
all-plugins-smoke.yml runs it with node --test; vitest reported "No test suite found".
* feat(marketplace): move the agentic-qe-fleet pin to v3.15.1 (4f0f8412)
agentic-qe v3.15.1 changes only the aqe-mod guard (#920: hardened, still tighten-only,
same engine API and events as 3.15.0) and pins agentic-qe@3.15.1 in .mcp.json.
* docs(adr-484): install evidence re-run at the v3.15.1 pin
* feat(marketplace): move the agentic-qe-fleet pin to v3.15.2 (9db36edf)
agentic-qe v3.15.2: aqe-mod reports its real version, keeps guard totals and the last
refusal across sessions (additive totals/lastRefusal in status.json), and never reads or
writes its status file through a symlink (adds $.fs.read and $.fs.stat); guard judging
unchanged. .mcp.json pins agentic-qe@3.15.2. ADR-484 evidence re-run at this pin.
* fix(marketplace): plain-name paths for external plugins, pin-review note, one marketplace for agentic-qe-fleet
- both validators (scripts/external-plugins.mjs, validate-marketplace.yml) require the
plugin path to match ^[A-Za-z0-9._-]+(/[A-Za-z0-9._-]+)*$ with no . or .. segment:
%2e%2e, a\..\b, a//b and a trailing slash are refused; tests cover both validators
- ADR-484: every pin bump needs a review of the pinned scripts/smoke.sh
- READMEs: install agentic-qe-fleet from the agentic-qe or the ruflo marketplace, not both
* feat(marketplace): move the agentic-qe-fleet pin to v3.15.3 (d7e5ffa7)
The plugin at v3.15.3 differs from v3.15.2 only in its version and its MCP
pin (agentic-qe@3.15.3). ADR-484's evidence records the install re-run at
the new pin.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(plugins): pin agentic-qe to v3.15.4 (bec02b13)
The plugin at v3.15.4 differs from v3.15.3 only in its version and its MCP
pin (agentic-qe@3.15.4). ADR-484's evidence records the install re-run at
the new pin.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(plugins): pin agentic-qe to v3.15.5 (d65ede14)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(console): leave the console version bump to the maintainer at merge
The console version and CHANGELOG entry collided with every console release on
main (four rebases on 2026-10-12, each only plugins/ruflo-console/CHANGELOG.md).
plugin.json, hooks/version.ts, scripts/smoke.sh and CHANGELOG.md now match
main; ADR-484 and its index row say 'next console release'.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(plugins): pin agentic-qe to v3.15.6 (0fa34d24)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(plugins): pin agentic-qe to v3.15.7 (7f2d091d)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(plugins): pin agentic-qe to v3.15.8 (d9ce98f7)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(plugins): pin agentic-qe to v3.15.9 (d1c33d2b)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(plugins): pin agentic-qe to v3.15.10 (e5814a2f)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: rUv <ruv@ruv.net>
The standalone terminal UI now leads each page with the same title art and
pictures the console draws, as coloured cells (Raster in the terminal kit),
in the console's looks (Classic BBS default, Orbital, plain), moving at
--fps with only the changed rows redrawn.
- tui/ansi.ts: Raster; control/escape/invisible/wide code points become
spaces, malformed or oversized cells draw nothing
- looks: --look, t key; --boot; --fps, --no-anim, --no-pictures
- focus reporting pauses the animation clock; NO_COLOR, dumb terminals,
and widths under 44 fall back to the words
- guide: flags, looks, the t key; corrects the confirm-card sentence
- ADR-489: phase 4 recorded, parity table skeleton
- README/guide SVGs regenerated from real frames (leak-checked)
Co-Authored-By: RuFlo <ruv@ruv.net>
README gets a short optional pointer (npx ruflo tui, --plain) and one small animated SVG. docs/USERGUIDE.md gets a
Terminal UI (optional) section: requirements, commands, keys, exit codes, what each page shows, the AI page's ask-first
card and its Codex/OpenRouter rules, the honest limits and a pointer to the Orbital theme. Both SVGs are built from real
frames of ruflo-tui 3.56.7 in a throwaway sample project; scripts/render-tui-svg.mjs rebuilds them (CSS animation only,
no scripts or external references, prefers-reduced-motion shows the first frame).
Co-Authored-By: RuFlo <ruv@ruv.net>
Reduce vector replay from 29.6 MB to 3.84 MB through shared glyphs and per-cell animation. Retain 456 frames; verify SMIL timelines and img animation in Chrome.