* fix(convert): two color names fall through to grey, and nothing checked
resolve_opencode_color() maps a name it does not recognise to #6B7280 and
says nothing about it. Four agents ask for a name it has never known:
engineering/engineering-minimal-change-engineer.md slate
specialized/operations-manager.md slate
gis/gis-technical-consultant.md navy
specialized/chief-financial-officer.md navy
All four render grey in the OpenCode integration, which reads as a
deliberate grey rather than a miss — and some agents do choose grey, so
there was nothing to notice.
`slate` and `navy` are now in the map. Values follow the CSS named color
where one exists (navy -> #000080, matching how teal already works) and
Tailwind's 500 shade otherwise (slate -> #64748B, matching gray).
Adding two names does not stop the next one, so two checks now cover it:
- lint-agents.sh rejects a color that is neither #RRGGBB nor a name the
converter knows, and prints the names it knows. The list is read out
of resolve_opencode_color() rather than copied, so it cannot drift
from the map that does the work. This runs on changed files in agent
PRs, which is where a new color arrives.
- test-convert-outputs.sh fails when an opencode output is #6B7280 and
the source did not ask for grey. Grey stays a legitimate choice; the
check is "grey only when the source said so".
CONTRIBUTING now says which color values actually work, since the template
just said `colorname or "#hexcode"`.
Verified: all 279 agents pass the new lint rule, and no opencode output
falls through to grey by accident.
* ci(lint): run the whole roster when the linter itself changes
The lint job scopes itself to the agent files a PR touched, which is right
for an agent PR and wrong for a rule change. A new rule lands without ever
having run against the other 278 agents — it either breaks a division
nobody edited or quietly does nothing, and either way CI is silent.
The colour check in the previous commit is the case in point: it changes
scripts/, so the lint workflow's path filter did not even fire, and the
rule would have merged without CI looking at a single agent.
Adds a lint-all job that runs the full-roster lint when scripts/
lint-agents.sh, convert.sh, or lib.sh is part of the diff, and says why it
is skipping when they are not. Those three paths are in the workflow's
trigger list now so the job can fire at all.
Aider loads a conventions file into context and keeps it there for the whole
session — that is what the file is for, and the docs say to load it with
--read so prompt caching can hold it. This integration concatenated every
agent body into it. At 279 agents that is 3,816,372 characters, roughly a
million tokens. No model takes that. Anyone who ran
./scripts/install.sh --tool aider
got a CONVENTIONS.md that either blows the context window on the first turn
or bills for a million tokens trying.
CONVENTIONS.md is now the roster index it was described as: one entry per
agent with the name, the description, the division, and the path to the
agent file. 96,823 characters, down from 3.8 million. The header explains
how to pull a single agent's full instructions into the session:
/read-only /path/to/agency-agents/engineering/engineering-frontend-developer.md
Naming an agent in a prompt still works the way it did — the description is
what the model needed for that, and it is still there.
test-convert-outputs.sh now holds the index to being an index: it fails if
CONVENTIONS.md grows past 250,000 characters, if it does not list exactly
one path per roster agent, or if any path it prints does not resolve. The
existing round-trip check on the accumulated file still covers the names and
descriptions.