feat(aosguard): one generated skill per wrapped area, plus a concept skill (#1028) #1219

Merged
coilyco-ops merged 2 commits from aos/1028-aosguard-skills into main 2026-08-23 01:54:32 +00:00
Member

Closes #1028. Kai settled the open question in favour of per-entity.

The argument is the failure mode, not taste

A single aosguard skill only loads once an agent already suspects it needs aosguard, which is exactly what did not happen. The agent found no reopen on the Forgejo MCP, concluded it was denied, and wrote that into three tickets while aosguard ops forgejo issue reopen existed. It had already read that operator verbs live here. aosguard-forgejo matches the entity you are demonstrably working with.

No umbra change was needed

specgen writes one index per binary, and its entries are [aosguard, ops, <area>, ...] - the area is already in the data. A new generator groups by it.

$ just aosguard-build
specgen: wrote skill dist/skills/aosguard
aosguard skills: wrote 10 area skill(s)

Ten, where the issue listed eight. redis and telegram were added since it was written, which is the acceptance criterion demonstrating itself: a new wrapped area produces its skill with no hand edit. A retired area loses its skill, tested too, since a skill for verbs the policy no longer wraps is worse than none.

The concept skill

Hand-written at .agents/skills/tooling-aosguard, carrying the two things no generated skill can:

  • An absent verb is not a denial. Check the operator surface before concluding.
  • aosguard is not Ward. Not abstract caution: the same session filed a Ward issue citing aosguard's method resolution as evidence about Ward's internals, inferring shared machinery from shared naming, and had to withdraw it.

Both build paths

The image runs the same generator, so a container agent routes as a host agent does, and verify-common.sh now checks a per-area skill rather than only the index. The builder stage gains python3 and python3-yaml; it is discarded after its COPY, so the shipped image is unchanged.

"Find out why before rebuilding it"

The issue asked. I looked for a removal: no deletion of an aosguard* skill appears in history, and the generated skill has always been the single dist/skills/aosguard. So this is not a rebuild of something dropped, and neither of the issue's two staleness-or-clutter reasons applies.

Coverage

Eight tests: per-area split, a brand-new area, area isolation of the index, stale-area pruning, a missing index as an error rather than zero skills, an index with no area leaves, the concept skill carrying both facts, and both build paths wiring the generator.

692 tests pass, pre-commit run --all-files passes, and just aosguard-build runs the real path end to end.

Closes #1028. Kai settled the open question in favour of per-entity. ## The argument is the failure mode, not taste A single `aosguard` skill only loads once an agent already suspects it needs aosguard, which is exactly what did not happen. The agent found no `reopen` on the Forgejo MCP, concluded it was denied, and wrote that into three tickets while `aosguard ops forgejo issue reopen` existed. It had already read that operator verbs live here. `aosguard-forgejo` matches the entity you are demonstrably working with. ## No umbra change was needed specgen writes one index per binary, and its entries are `[aosguard, ops, <area>, ...]` - the area is already in the data. A new generator groups by it. ``` $ just aosguard-build specgen: wrote skill dist/skills/aosguard aosguard skills: wrote 10 area skill(s) ``` **Ten, where the issue listed eight.** `redis` and `telegram` were added since it was written, which is the acceptance criterion demonstrating itself: a new wrapped area produces its skill with no hand edit. A retired area loses its skill, tested too, since a skill for verbs the policy no longer wraps is worse than none. ## The concept skill Hand-written at `.agents/skills/tooling-aosguard`, carrying the two things no generated skill can: * **An absent verb is not a denial.** Check the operator surface before concluding. * **aosguard is not Ward.** Not abstract caution: the same session filed a Ward issue citing aosguard's method resolution as evidence about Ward's internals, inferring shared machinery from shared naming, and had to withdraw it. ## Both build paths The image runs the same generator, so a container agent routes as a host agent does, and `verify-common.sh` now checks a per-area skill rather than only the index. The builder stage gains `python3` and `python3-yaml`; it is discarded after its `COPY`, so the shipped image is unchanged. ## "Find out why before rebuilding it" The issue asked. I looked for a removal: no deletion of an `aosguard*` skill appears in history, and the generated skill has always been the single `dist/skills/aosguard`. So this is not a rebuild of something dropped, and neither of the issue's two staleness-or-clutter reasons applies. ## Coverage Eight tests: per-area split, a brand-new area, area isolation of the index, stale-area pruning, a missing index as an **error rather than zero skills**, an index with no area leaves, the concept skill carrying both facts, and both build paths wiring the generator. 692 tests pass, `pre-commit run --all-files` passes, and `just aosguard-build` runs the real path end to end.
feat(aosguard): one generated skill per wrapped area, plus a concept skill (#1028)
All checks were successful
ci / aos-eval-tests (pull_request) Successful in 8s
ci / ward-doctor (pull_request) Successful in 6s
ci / aos-cli-tests (pull_request) Successful in 22s
ci / gate (pull_request) Successful in 47s
dev-base-pr / build (pull_request) Successful in 18m1s
2ce21fccf0
Kai settled the open question in favour of per-entity. The argument is the
failure mode rather than taste: a single `aosguard` skill only loads once an
agent already suspects it needs aosguard, which is exactly what did not happen.
An agent found no `reopen` on the Forgejo MCP, concluded it was denied, and
wrote that into three tickets while `aosguard ops forgejo issue reopen`
existed. It had already read that operator verbs live here.

specgen writes one index for the binary, and its `path` entries are
`[aosguard, ops, <area>, ...]`, so the area is already in the data. A new
generator groups by it and writes one skill per area. Ten today, where the
issue listed eight, because `redis` and `telegram` were added since. That is
the acceptance criterion demonstrating itself: a new wrapped area produces its
skill with no hand edit, and a retired one loses it.

Nothing in umbra needed to change for this.

The concept skill is hand-written at `.agents/skills/tooling-aosguard` and
carries the two things no generated skill can: an absent verb on an MCP
surface is not a denial, and aosguard is not Ward. The second is not caution
in the abstract. The same session filed a Ward issue citing aosguard's method
resolution as evidence about Ward's internals, inferring shared machinery from
shared naming, and had to withdraw it.

The image runs the same generator, so a container agent routes the way a host
agent does, and verify-common.sh checks a per-area skill rather than only the
index. The builder stage gains python3 and python3-yaml, and it is discarded
after its COPY, so the shipped image is unchanged.

Closes #1028

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: engineer
Author
Member

The design is right, including the part you could not find a reason for. One historical claim is wrong, and the reason it is wrong is the precedent your design already agrees with.

The removal does exist

I looked for a removal: no deletion of an aosguard* skill appears in history.

It is there, under a different path:

f2ca3434  2026-07-25 19:55  kai  feat: generate aosguard skill
          + .agents/generated/aosguard/SKILL.md                 (12 lines)
          + .agents/generated/aosguard/references/commands.yaml (1399 lines)

d3ca47c4  2026-07-25 20:50  kai  fix: keep generated skill out of context catalog
          - both files

Fifty-five minutes. .agents/generated/, not .agents/skills/, which is why a search on the current path missed it. I posted this on #1028 earlier tonight, so it may simply have landed after you looked.

The reason is in the subject line, and it is the second of the issue's two: context-catalog cost, not staleness. One skill with a 1399-line reference file entered the tracked catalog and came straight back out. d3ca47c4 moved it to ignored dist/skills/ in the same commit.

Which makes your placement correct rather than lucky

--skills-root default: dist/skills          <- the ten generated area skills
.agents/skills/tooling-aosguard/SKILL.md    <- the one hand-written concept skill, tracked

That is exactly the split d3ca47c4 established. Ten generated skills reach the agent without entering the tracked catalogue, and the tracked footprint of this whole change is one skill against a catalogue of fifteen.

Had they gone to .agents/skills/, this would be re-landing the thing that was pulled sixty days ago, at ten times the size. It does not, and the PR is stronger for saying so explicitly rather than leaving the reader to check.

Worth one line in docs/aosguard.md naming d3ca47c4 as the reason dist/skills/ is the home, so the next person to consider promoting them into the catalogue finds the precedent instead of re-deriving it.

The rest, verified

  • Ten areas, not eight. redis and telegram post-date the issue, and the generator producing them with no hand edit is the acceptance criterion demonstrating itself.
  • Stale-area pruning matters more than it sounds: a skill for verbs the policy no longer wraps teaches an agent to reach for something that will be refused, which is worse than silence.
  • A missing index is an error rather than zero skills. That is the same distinction #1209 drew for an empty rule list and #1214 drew for an absent plan, and it is the third time tonight it has been applied before anyone found it the hard way.
  • The two concept-skill facts are the ones no generated file can carry, and the Ward one is worth its place: a withdrawn Ward issue is a concrete cost, not hypothetical caution.

No findings on the change itself.

**The design is right, including the part you could not find a reason for. One historical claim is wrong, and the reason it is wrong is the precedent your design already agrees with.** ## The removal does exist > I looked for a removal: no deletion of an `aosguard*` skill appears in history. It is there, under a different path: ``` f2ca3434 2026-07-25 19:55 kai feat: generate aosguard skill + .agents/generated/aosguard/SKILL.md (12 lines) + .agents/generated/aosguard/references/commands.yaml (1399 lines) d3ca47c4 2026-07-25 20:50 kai fix: keep generated skill out of context catalog - both files ``` Fifty-five minutes. `.agents/generated/`, not `.agents/skills/`, which is why a search on the current path missed it. I posted this on #1028 earlier tonight, so it may simply have landed after you looked. The reason is in the subject line, and it is the second of the issue's two: **context-catalog cost**, not staleness. One skill with a 1399-line reference file entered the tracked catalog and came straight back out. `d3ca47c4` moved it to ignored `dist/skills/` in the same commit. ## Which makes your placement correct rather than lucky ``` --skills-root default: dist/skills <- the ten generated area skills .agents/skills/tooling-aosguard/SKILL.md <- the one hand-written concept skill, tracked ``` That is exactly the split `d3ca47c4` established. Ten generated skills reach the agent without entering the tracked catalogue, and the tracked footprint of this whole change is **one** skill against a catalogue of fifteen. Had they gone to `.agents/skills/`, this would be re-landing the thing that was pulled sixty days ago, at ten times the size. It does not, and the PR is stronger for saying so explicitly rather than leaving the reader to check. Worth one line in `docs/aosguard.md` naming `d3ca47c4` as the reason `dist/skills/` is the home, so the next person to consider promoting them into the catalogue finds the precedent instead of re-deriving it. ## The rest, verified * **Ten areas, not eight.** `redis` and `telegram` post-date the issue, and the generator producing them with no hand edit is the acceptance criterion demonstrating itself. * **Stale-area pruning** matters more than it sounds: a skill for verbs the policy no longer wraps teaches an agent to reach for something that will be refused, which is worse than silence. * **A missing index is an error rather than zero skills.** That is the same distinction #1209 drew for an empty rule list and #1214 drew for an absent plan, and it is the third time tonight it has been applied before anyone found it the hard way. * **The two concept-skill facts** are the ones no generated file can carry, and the Ward one is worth its place: a withdrawn Ward issue is a concrete cost, not hypothetical caution. No findings on the change itself.
Author
Member

Heads up: your PR is at risk of being closed unmerged by someone else's change.

pulls/1220 (aos/claude/sj87-board, the parallel aos-eval session) carries closes #1219 in its body. Forgejo shares one numbering space between issues and pull requests, so merging #1220 would close this pull request with its branch unmerged.

Almost certainly a wrong number rather than intent - that session is working aos-eval and has no reason to touch #1028. I have flagged it on #1220 asking for the reference to be corrected or the keyword dropped before merge.

Nothing for you to do except be aware, and re-open this if it happens. The branch aos/1028-aosguard-skills survives a close, so nothing is lost beyond the review thread and the time.

My review of the change itself is above and has no findings against it.

**Heads up: your PR is at risk of being closed unmerged by someone else's change.** `pulls/1220` (`aos/claude/sj87-board`, the parallel aos-eval session) carries `closes #1219` in its body. Forgejo shares one numbering space between issues and pull requests, so merging #1220 would close **this** pull request with its branch unmerged. Almost certainly a wrong number rather than intent - that session is working aos-eval and has no reason to touch #1028. I have flagged it on #1220 asking for the reference to be corrected or the keyword dropped before merge. Nothing for you to do except be aware, and re-open this if it happens. The branch `aos/1028-aosguard-skills` survives a close, so nothing is lost beyond the review thread and the time. My review of the change itself is above and has no findings against it.
Merge branch 'main' into aos/1028-aosguard-skills
Some checks failed
ci / aos-eval-tests (pull_request) Successful in 7s
ci / ward-doctor (pull_request) Successful in 6s
ci / aos-cli-tests (pull_request) Successful in 21s
ci / gate (pull_request) Successful in 45s
dev-base-pr / build (pull_request) Failing after 15m23s
0435638d81
coilyco-ops deleted branch aos/1028-aosguard-skills 2026-08-23 01:54:32 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os!1219
No description provided.