feat(compose): give Sirens Deep a composed identity #124

Merged
coilysiren merged 8 commits from feat/sirens-deep-compose-wiring into main 2026-08-12 01:54:12 +00:00
Member

Wires #98 end to end.

Depends on

Merge coilyco-flight-deck/agentic-os#997 first. The declaration names four sources that only exist in the public catalogue after that lands, so the compose stage fails until then. Unit tests, vet, prompt-check, policy-check, and pre-commit are green now.

The allowlist moved

agent/compose/roles.kdl was the wrong document: a provider-side graph binding a .agents/composed/ catalogue this repository does not have. It filtered nothing.

The allowlist is now agent/compose/aos-public.kdl, a source declaration naming 13 exact skills. Only declaration= is permitted for a request source. With root= the source repository's own roles.kdl decides, and agentic-os-kai's creator role deliberately binds Kai's career, job-search, and LinkedIn context because that role serves Kai. A test fails any root= source.

Verified by composing both ways: root= pulled kai-career, kai-job-search, kai-linkedin-*, personal-preference-social, repo-lore, repo-inbox, and every mcp-tools-*. declaration= pulled exactly the named set, agent-compose verify: 15 skills // 18 files.

Build

scripts/stage-compose-sources.sh stages each admitted COMPOSED.md as SKILL.md beneath the declaration, since a declaration's paths resolve relative to its own directory. It composes one bundle per role and verifies each. The Dockerfile runs it in a new stage against a pinned AOS_CATALOG_REF clone, because the release image ships agent-compose but not the catalogue.

ward exec compose-bundles does the same locally from an AOS_CATALOG checkout.

Runtime

composed: true in the definition makes a bundle mandatory. SIRENS_DEEP_ROLE picks which baked bundle loads, so a role flip is a deploy change rather than a rebuild. A missing bundle stops the process rather than answering neutrally, which is what the issue asked for.

Validator inversion, with a correction

The issue asks that <aos-community-bundle> and personality meld become required for Deep. <aos-community-bundle> appears in no current bundle, so requiring it would have failed every startup. The anchors are strings a real bundle contains: <composed-identity>, Agent-compose assigned the, ## Personality meld, **Role skill //. The neutral profile must carry none of them, and both directions are tested.

Not done

Per-role prompt snapshots. The tracked snapshot renders a placeholder bundle so prompt-check stays hermetic in pre-commit without a catalogue checkout. Real per-role snapshots need the build to commit them; filed separately.

Verification

go test ./..., go vet ./..., prompt-check, policy-check, pre-commit run --all-files all pass.

Wires https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/98 end to end. ## Depends on **Merge https://forgejo.coilysiren.me/coilyco-flight-deck/agentic-os/pulls/997 first.** The declaration names four sources that only exist in the public catalogue after that lands, so the compose stage fails until then. Unit tests, vet, prompt-check, policy-check, and pre-commit are green now. ## The allowlist moved `agent/compose/roles.kdl` was the wrong document: a provider-side graph binding a `.agents/composed/` catalogue this repository does not have. It filtered nothing. The allowlist is now `agent/compose/aos-public.kdl`, a source declaration naming 13 exact skills. Only `declaration=` is permitted for a request source. With `root=` the source repository's own `roles.kdl` decides, and agentic-os-kai's creator role deliberately binds Kai's career, job-search, and LinkedIn context because that role serves Kai. A test fails any `root=` source. Verified by composing both ways: `root=` pulled `kai-career`, `kai-job-search`, `kai-linkedin-*`, `personal-preference-social`, `repo-lore`, `repo-inbox`, and every `mcp-tools-*`. `declaration=` pulled exactly the named set, `agent-compose verify`: 15 skills // 18 files. ## Build `scripts/stage-compose-sources.sh` stages each admitted `COMPOSED.md` as `SKILL.md` beneath the declaration, since a declaration's paths resolve relative to its own directory. It composes one bundle per role and verifies each. The Dockerfile runs it in a new stage against a pinned `AOS_CATALOG_REF` clone, because the release image ships `agent-compose` but not the catalogue. `ward exec compose-bundles` does the same locally from an `AOS_CATALOG` checkout. ## Runtime `composed: true` in the definition makes a bundle mandatory. `SIRENS_DEEP_ROLE` picks which baked bundle loads, so a role flip is a deploy change rather than a rebuild. A missing bundle stops the process rather than answering neutrally, which is what the issue asked for. ## Validator inversion, with a correction The issue asks that `<aos-community-bundle>` and `personality meld` become **required** for Deep. `<aos-community-bundle>` appears in no current bundle, so requiring it would have failed every startup. The anchors are strings a real bundle contains: `<composed-identity>`, `Agent-compose assigned the`, `## Personality meld`, `**Role skill //`. The neutral profile must carry none of them, and both directions are tested. ## Not done Per-role prompt snapshots. The tracked snapshot renders a placeholder bundle so `prompt-check` stays hermetic in pre-commit without a catalogue checkout. Real per-role snapshots need the build to commit them; filed separately. ## Verification `go test ./...`, `go vet ./...`, `prompt-check`, `policy-check`, `pre-commit run --all-files` all pass.
feat(compose): give Sirens Deep a composed identity
All checks were successful
ci / test (pull_request) Successful in 3m17s
ci / publish-echo-image (pull_request) Has been skipped
2ec82ace97
Replaces agent/compose/roles.kdl, which was the wrong document. It was a
provider-side graph binding a .agents/composed/ catalogue this repository
does not have, so it filtered nothing.

The allowlist is now a source declaration. A request source takes either
root= or declaration=, and only declaration= is permitted here: with
root= the source repository's own roles.kdl decides, and agentic-os-kai's
creator role deliberately binds Kai's career, job-search, and LinkedIn
context because that role serves Kai and not an agent that answers
strangers. Verified: the same compose with root= pulled all of those plus
every repo-* and mcp-tools-* pointer, and with declaration= pulled
exactly the 13 named sources.

Declarations name exact skills, never globs, so widening the surface is a
visible line in a diff.

Build: scripts/stage-compose-sources.sh stages each admitted COMPOSED.md
as SKILL.md beneath the declaration, composes one bundle per role, and
verifies each. The image runs it against a pinned AOS_CATALOG_REF clone,
because the release image ships agent-compose but not the catalogue.

Runtime: composed: true makes a bundle mandatory and SIRENS_DEEP_ROLE
picks which baked one loads, so a role flip needs no rebuild. A missing
bundle stops the process rather than answering neutrally.

ValidateSystemPrompt inverts per profile as issue 98 asked, but anchored
on strings a real bundle contains. The <aos-community-bundle> marker the
issue named appears in no current bundle, so requiring it would have
failed every startup.

Refs: #98
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
feat(compose): admit the whole preference family
All checks were successful
ci / test (pull_request) Successful in 1m10s
ci / publish-echo-image (pull_request) Has been skipped
7957775495
The declaration named three preference sources because I carried an
arbitrary set from a lab experiment instead of reading issue 98's list,
which names eight plus the router. All nine are admitted now, so the
family is not split for no stated reason.

personal-preference-social stays denied and stays private.

Also fixes the staging script, which was unusable as written. The compose
output path was built from OLDPWD after a cd and came out malformed, and
a scratch HOME with no agent-compose.yaml made every role converge a
whole home tree rather than materialize a bundle, which hung the run and
wrote a stray Library tree into the output. It now resolves the output
directory up front, writes a minimal config into the scratch home, and
removes the staged tree on exit so a local run leaves no Markdown that
documentation-layout rejects.

Verified against the real catalogue: seven role bundles compose and
verify in 0.33s, creator at 23 skills // 27 files, and LoadBundle reads
47264 bytes of composed identity from it.

Refs: #98
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
refactor(compose): keep the allowlist in agent-compose's own format
Some checks failed
ci / test (pull_request) Failing after 55s
ci / publish-echo-image (pull_request) Has been skipped
b510ef6833
The enumerated declaration was the wrong tracked artifact. It lost the
role graph's globs, made every entry carry a path= that is mechanically
derived from the name, and looked like a format unrelated to the rest of
agent-compose. The declaration form is real grammar, but it is the
overlay corner of it, meant for a source that ships explicit content
paths rather than for allowlisting an upstream catalogue.

agent/compose/roles.kdl comes back as the one tracked allowlist, globs
and all. cmd/sirens-echo-compose expands it against the pinned catalogue
and emits the declaration as build output, so nobody hand-writes a path
again. Four glob lines produce the same nineteen sources the enumeration
listed.

Globs stay safe because expansion enforces the invariant: a pattern that
reaches a denied source fails, a pattern that matches nothing fails, and
a global resolving to a private repository fails. The deny list moved to
composepolicy.go beside the expander, so the build and the suite share
one list instead of two copies.

Every role the graph declares bakes its own bundle, so per-role
allowlists work and the build no longer bakes seven roles from one set.

The second tracked file is forced by the grammar: agent-compose compose
takes a request, and a request source needs a separate declaration file.

The declared ordinary-skill providers are still inert, now tracked at
#126.

Verified against the real catalogue: creator bakes 23 skills // 27 files
in 4.5s.

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Update agent/compose/roles.kdl
Some checks failed
ci / test (pull_request) Failing after 1m9s
ci / publish-echo-image (pull_request) Has been skipped
9eb3bb526b
Three comment blocks in cmd/sirens-echo-compose and composepolicy.go ran
to three lines, which is what turned CI red.

I missed it because I ran pre-commit before git add. The hook walks
tracked files, so brand new ones are invisible to it and the local gate
came back clean on a tree the hook had never seen. Staging first is the
fix.

Also merges origin/main, which had moved three commits ahead with the MCP
resource work. The overlap is agent.go, config.go, config_test.go,
sirens-deep.yaml, and the config doc; all merged cleanly and the full
verb set passes on the result.

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
fix(compose): name the router personal-preferences, plural
All checks were successful
ci / test (pull_request) Successful in 55s
ci / publish-echo-image (pull_request) Has been skipped
31b9dcd095
The split into an explicit dashed glob plus the router is right: the old
personal-preference* star was quietly covering both, so admitting the
router looked like an accident of the pattern rather than a decision.

The router's skill name is plural, so "personal-preference" matched
nothing and expansion failed closed, which is the guard doing its job.
Same nineteen sources with the name corrected.

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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-gaming/sirens-echo!124
No description provided.