Skip to content

feat(agents): implement the predefined agent archetype catalog - #39

Open
rodrigottv wants to merge 5 commits into
renatoasse:masterfrom
rodrigottv:feat/agent-archetype-catalog
Open

feat(agents): implement the predefined agent archetype catalog#39
rodrigottv wants to merge 5 commits into
renatoasse:masterfrom
rodrigottv:feat/agent-archetype-catalog

Conversation

@rodrigottv

Copy link
Copy Markdown

Context

The agents/ registry has been scaffolded since the initial commit but the directory was never created. src/agents.js and src/agents-cli.js are fully implemented, "agents/" is in package.json files[], and 'agents' is in PROTECTED_PATHS — yet opensquad agents has always listed an empty catalog.

I traced the whole history (159 commits, all branches): no path under agents/ ever existed, so nothing was removed. docs/plans/2026-03-01-fix-init-distribution-plan.md specified installAllAgents() in Step 3, but only its documentation task (Check H in opensquad-dev) was ever executed. The checklist has been asking for a function that was never written.

This PR implements the feature end to end.

Design decisions

Two constraints shaped this, and I'd especially like your read on them:

1. Archetypes ship without a persona name. design.prompt.md requires every agent to have a two-word alliterative name with a squad-unique initial letter. A static catalog with fixed names ("Ângela Ângulo") cannot satisfy that when composed arbitrarily. So archetypes carry only a functional name (Researcher), and the Architect assigns the persona name during specialization — the naming rule stays intact.

2. Archetypes do not duplicate best-practices/. That directory already holds the deep domain knowledge (350+ lines per discipline) and design.prompt.md Phase A already reads it. Duplicating it into the catalog would repeat the mistake the canonical-sources refactor removed. The archetype holds the agent shape (~110 lines: persona stance, principles, process, decision criteria, anti-patterns, quality criteria); the best-practices file holds the knowledge. Each archetype's bestPractices: field links the two, and the Architect reads both.

What changed

Catalog — 8 archetypes, one per "Discipline" entry in best-practices/_catalog.yaml, so the mapping isn't arbitrary: researcher, strategist, copywriter, technical-writer, image-designer, data-analyst, reviewer, publisher. Plus a generated _catalog.yaml index, following the same read-the-index-first pattern as best-practices.

Flow — one direction only:

agents/{id}/AGENT.md          (repo: archetype, reusable skeleton)
  → init/update               installs agents/{id}.agent.md into the project
    → design.prompt.md Phase E  reads the index, picks a match, SPECIALIZES it
      → build.prompt.md         writes squads/{code}/agents/{id}.agent.md

An archetype is an input to Design, never an output of Build. Each carries a ## Specialization Contract telling the Architect what to fill in. Gate 1 now rejects any generated agent still carrying the ARCHETYPE banner or a Specialization Contract — that's what catches a verbatim copy instead of a real specialization.

Wiringinit installs the full catalog; update backfills only archetypes missing from the target, since agents is in PROTECTED_PATHS and user customizations must survive. _catalog.yaml is generated, so update refreshes it in place.

Graceful degradation — Phase E step 5: if agents/_catalog.yaml is absent (older install, or the user deleted it), the Architect designs every agent from scratch as before. A missing catalog never fails a build.

Tests

npm test: 126 → 140, all passing. npm run lint clean.

Six existing tests asserted the empty-registry state and had to be inverted:

  • 4 no-ops guarded by if (available.length === 0) return; with the comment "No bundled agents in dev environment — skip"
  • 2 asserting init/update leave no agents/ directory (init does not create agents dir when no bundled agents exist, update succeeds when no bundled agents exist)

New coverage: catalog↔directory exact correspondence (a directory missing from the index is invisible to the Architect; an index entry with no directory points at a nonexistent file), frontmatter parseability including pt-BR/es, id validity against validateAgentId(), the init install, and the update backfill preserving a customized agent.

Also included

  • fix(cli): both agents and skills printed a /tree/main/ browse URL, but the default branch is master — those links 404'd. Harmless while agents/ didn't exist; it now points at real content.
  • chore: package-lock.json declared 0.1.11 while package.json is at 0.1.15.
  • docs: rewrote CLAUDE.md (the root copy was a stale duplicate of the end-user template, not developer guidance) and the opensquad-dev checklist, whose Checks A/B/C/H described a templates/ mirror and an installAllAgents() that no longer match the code. The Golden Rule and the IDE-contamination check were already correct and are unchanged — and I verified my own prompt edits against Check J: no IDE-specific logic in shared files.

One thing I did not touch

.gitignore line 11 ignores tests/, but the 7 test files are tracked — so they work, yet a new test file needs git add -f or it silently never reaches CI. I hit this while committing. It looked out of scope for this PR, but it's worth a separate fix.

🤖 Generated with Claude Code

rodrigottv and others added 4 commits July 27, 2026 08:21
The lockfile still declared 0.1.11 while package.json is at 0.1.15, and
carried stale `peer: true` markers on two dev dependencies. Regenerated by
npm install; no dependency versions changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both `opensquad agents` and `opensquad skills` printed a /tree/main/ URL,
but the repository's default branch is master, so the links 404'd. This was
harmless while agents/ did not exist; it now points at real content.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The agents/ registry was scaffolded in the initial commit — src/agents.js,
src/agents-cli.js, "agents/" in package.json files[], and 'agents' in
PROTECTED_PATHS — but the directory itself was never created, so the catalog
was always empty. docs/plans/2026-03-01-fix-init-distribution-plan.md
specified installAllAgents(); only its documentation task was ever executed.

This implements the feature end to end.

Catalog: 8 archetypes, one per "Discipline" entry in the best-practices
catalog, plus a generated _catalog.yaml index so the Architect can discover
them without reading every AGENT.md.

Archetypes are foundations, not finished agents. They ship without a persona
name — only a functional one ("Researcher") — so the squad-unique two-word
naming rule in design.prompt.md stays satisfiable when composing a squad.
Each carries a Specialization Contract stating what the Architect must fill
in. Deep domain knowledge stays in _opensquad/core/best-practices/; the
archetype holds the agent shape, not a second copy of the knowledge.

Flow, one direction only:

  agents/{id}/AGENT.md
    -> init/update      installs agents/{id}.agent.md into the project
      -> design.prompt.md Phase E   reads the index and specializes a match
        -> build.prompt.md          writes squads/{code}/agents/{id}.agent.md

An archetype is an input to Design, never an output of Build. Build's Gate 1
now rejects any generated agent still carrying the ARCHETYPE banner or a
Specialization Contract, which is what catches a verbatim copy.

Wiring: init installs the full catalog; update backfills only archetypes
missing from the target, since 'agents' is in PROTECTED_PATHS and user
customizations must survive. _catalog.yaml is generated, so update refreshes
it in place.

Tests: six existing tests asserted the empty-registry state — four no-ops
guarded by `if (available.length === 0) return;` and two asserting that
init/update leave no agents/ directory. All six now exercise the real
catalog, alongside new coverage for catalog/directory correspondence, the
init install, and the update backfill preserving customized agents.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CLAUDE.md at the repo root was a copy of the end-user template shipped to
consumer projects (templates/ide-templates/claude-code/CLAUDE.md), left over
from the repo dogfooding itself. It is not in package.json files[], so
nothing distributes or tests it. Replaced with guidance for developing the
package: the installer/runtime split, the four copy mechanisms and their
differing init-vs-update semantics, the multi-IDE golden rule, squad
anatomy, the dashboard state.json contract, and the archetype flow.

opensquad-dev predated the canonical-sources refactor and described a
templates/_opensquad/core mirror, a templates/skills mirror, and an
installAllAgents() that had never been implemented. Checks A and B now
verify those mirrors stay absent rather than present; C, D, E, and H were
rewritten against the real code; H, I, and K were added for the version
file, localization, and the runner/dashboard state contract. The Golden Rule
and the IDE-contamination check were already correct and are unchanged.

Both files now note that docs/plans/ are historical records rather than
current specs, since the 2026-03-01 plan was only partially executed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t files

The archetype-containment checks were listed under Gate 1's "For EACH
.agent.md file" loop, so they only ever scanned squads/{code}/agents/.
Leakage is not confined there: squad.yaml, step files and pipeline/data/
are just as likely to carry a stray archetype reference, and the scoped
check reports a clean pass while the leak sits in squad.yaml.

Found by building a real squad from the catalog and then auditing it. The
generated squad.yaml carried an `archetype_note:` provenance field on each
agent; the agent files themselves were clean, so Gate 1 passed. Verified by
re-injecting the same field: the new gate reports
squads/{code}/squad.yaml:45, the old check reports nothing.

Promotes the two leak checks out of Gate 1 into a squad-wide Gate 1c and
adds provenance fields to what it rejects, since a self-contained squad
should record which archetype it came from nowhere but the conversation.
The persona-name check stays in Gate 1, where it is genuinely per-agent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@rodrigottv

Copy link
Copy Markdown
Author

Update: Gate 1c — archetype containment now scans the whole squad

Pushed d53e6e3, which fixes a gap I found by actually building a squad from the catalog rather than only running the unit tests.

The gap. The archetype-containment checks were sitting inside Gate 1's "For EACH .agent.md file" loop, so they only scanned squads/{code}/agents/. Leakage isn't confined there — squad.yaml, step files and pipeline/data/ can carry a stray reference just as easily, and the scoped check happily reports a clean pass while the leak sits in squad.yaml.

How it surfaced. I built a 3-agent LinkedIn-post squad from the catalog and audited the result. The generated squad.yaml had an archetype_note: provenance field on each agent. The agent files were clean, so Gate 1 passed. Verified by re-injecting the same field afterwards:

Gate 1c (whole squad):  squads/linkedin-post/squad.yaml:45: archetype_note: "..."
Gate 1  (agents/ only): nothing

The fix. Promotes the two leak checks out of Gate 1 into a squad-wide Gate 1c, and adds provenance fields to what it rejects — a self-contained squad should record which archetype it came from nowhere except the conversation with the user. The persona-name check stays in Gate 1, where it is genuinely per-agent.

What the build exercise validated

Beyond the gap, the archetype flow held up:

Check Result
Archetype banner / Specialization Contract leaked none
Archetype functional name leaked into personas none — Bruno Busca, Paula Palavra, Rita Rigor
Two-word names, unique initials B / P / R
Gate 1 structural minimums (9 criteria × 3 agents) all clear, 202–230 lines vs. 100 required
Referential integrity (party CSV → agents, pipeline → steps) 100%

Two design decisions from the PR description proved load-bearing in practice:

  • The whenToUse discrimination works. A LinkedIn post correctly resolved to copywriter (short-form persuasive) rather than technical-writer (long-form explanatory) — the distinction most likely to go wrong.
  • strategist excluded itself. Its Specialization Contract says "Omit this agent entirely when the pipeline goes straight from research to writing", which is exactly what happened. The YAGNI instruction inside the archetype prevented a useless agent.

Caveat on this evidence

I wrote the Phase E instructions, so I'm a biased evaluator — following them is easier for me than for a fresh session. What this genuinely validates is structural: paths resolve, referenced files exist, Gate 1 is satisfiable, and the instructions don't contradict each other. It does not establish that an independent session reaches the same archetype choices. A clean-session run would be worth doing before merge.

The exercise also skipped onboarding (no company.md) and live Phase B research, so the agents' Output Examples are realistic but illustrative rather than research-derived.

npm test still 140/140, lint clean, no IDE-specific logic introduced into the shared prompt.

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.

1 participant