CB-625: extract fleet-agent-kit — write the role bodies once, generate for both backends #129

Open
opened 2026-08-22 21:35:27 +02:00 by ltms · 0 comments
Owner

Part of CB-621 (#125).

Why

The role definitions exist twice today, once per backend, and the two copies are kept by hand:

.claude/agents/{architect,dev,reviewer}.md
.opencode/agent/{architect,dev,reviewer}.md

Measured: all three bodies are byte-identical. Only the frontmatter differs, and only in two lines.

.claude/agents/architect.md      .opencode/agent/architect.md
---                              ---
name: architect                  description: ...
description: ...                 mode: primary
---                              ---

This is not a tidiness problem. It already caused an outage. In CB-618 the name: key was missing from all three .claude/agents/*.md files. Claude Code skips such a file in silence, so --agent architect failed with "not found" and every role spawn broke. A second hand-kept list that drifts from the first is the same defect family as CB-608 and CB-610.

Scope

New PUBLIC repo fleet/fleet-agent-kit:

roles/architect.md  roles/dev.md  roles/reviewer.md   <- body, written ONCE
skills/implementer/  skills/reviewer/  skills/setup/
build.sh  ->  dist/claude/    .claude/agents/*.md  + .claude-plugin/plugin.json
              dist/opencode/  .opencode/agent/*.md

The generator owns the frontmatter difference, so nobody can forget name: again.

The risk this ticket must not re-create

Workers read agent files from their worktree checkout of the project repo. If the generator lives in another repo, fleetd holds vendored generated copies. Vendored copies drift exactly like the hand-kept ones did. The drift just moves from inside one repo to between two, where it is harder to see.

So the kit is only acceptable as a separate repo if it ships both:

  1. versioned releases, so a consumer pins a version; and
  2. a drift check that the consumer's CI runs, which regenerates and fails if the committed output differs. Model it on the existing python check that keeps the CLAUDE.md block byte-identical with the wiki template.

If either is missing, keep the generator inside fleetd until a second consuming project actually exists.

Public-repo cleanup

  • plugin/.claude-plugin/plugin.json hardcodes homepage and repository as https://git.ltms.dev/lms/claude-bridge. Both go stale after CB-623.
  • The marketplace name changes from claude-bridge, so every installed plugin needs a reinstall. Say so in the release notes.
  • Keep .claude/skills/port-to-opencode/ out of the public kit. It is a primary-side skill and it references internal hosts.
  • Checked for leaks: the role bodies, plugin/README.md, plugin/.mcp.json and the setup skill carry no secrets and no internal host beyond 127.0.0.1:8765. Public is defensible.

Acceptance criteria

  • build.sh regenerates all six files, and the output is byte-identical to what is committed in fleetd.
  • The drift check fails when a generated file is edited by hand.
  • A live spawn of each of the three roles works on both backends, and each member answers with text from its own role body. Assert on the real spawn, not on the generated string.
Part of CB-621 (#125). ## Why The role definitions exist twice today, once per backend, and the two copies are kept by hand: ``` .claude/agents/{architect,dev,reviewer}.md .opencode/agent/{architect,dev,reviewer}.md ``` Measured: **all three bodies are byte-identical.** Only the frontmatter differs, and only in two lines. ``` .claude/agents/architect.md .opencode/agent/architect.md --- --- name: architect description: ... description: ... mode: primary --- --- ``` This is not a tidiness problem. It already caused an outage. In CB-618 the `name:` key was missing from all three `.claude/agents/*.md` files. Claude Code skips such a file **in silence**, so `--agent architect` failed with "not found" and every role spawn broke. A second hand-kept list that drifts from the first is the same defect family as CB-608 and CB-610. ## Scope New PUBLIC repo `fleet/fleet-agent-kit`: ``` roles/architect.md roles/dev.md roles/reviewer.md <- body, written ONCE skills/implementer/ skills/reviewer/ skills/setup/ build.sh -> dist/claude/ .claude/agents/*.md + .claude-plugin/plugin.json dist/opencode/ .opencode/agent/*.md ``` The generator owns the frontmatter difference, so nobody can forget `name:` again. ## The risk this ticket must not re-create Workers read agent files from their worktree checkout of the **project** repo. If the generator lives in another repo, `fleetd` holds vendored generated copies. Vendored copies drift exactly like the hand-kept ones did. The drift just moves from inside one repo to between two, where it is harder to see. So the kit is only acceptable as a separate repo if it ships **both**: 1. **versioned releases**, so a consumer pins a version; and 2. **a drift check that the consumer's CI runs**, which regenerates and fails if the committed output differs. Model it on the existing python check that keeps the `CLAUDE.md` block byte-identical with the wiki template. If either is missing, keep the generator inside `fleetd` until a second consuming project actually exists. ## Public-repo cleanup - `plugin/.claude-plugin/plugin.json` hardcodes `homepage` and `repository` as `https://git.ltms.dev/lms/claude-bridge`. Both go stale after CB-623. - The marketplace name changes from `claude-bridge`, so **every installed plugin needs a reinstall**. Say so in the release notes. - Keep `.claude/skills/port-to-opencode/` **out** of the public kit. It is a primary-side skill and it references internal hosts. - Checked for leaks: the role bodies, `plugin/README.md`, `plugin/.mcp.json` and the setup skill carry no secrets and no internal host beyond `127.0.0.1:8765`. Public is defensible. ## Acceptance criteria - `build.sh` regenerates all six files, and the output is byte-identical to what is committed in `fleetd`. - The drift check fails when a generated file is edited by hand. - A live spawn of each of the three roles works on **both** backends, and each member answers with text from its own role body. Assert on the real spawn, not on the generated string.
ltms added this to the 2.0 — one operation centre, many hosts milestone 2026-08-22 21:35:27 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: fleet/fleetd#129