Watch
3
Sirens Deep: compose a real Agent Compose identity, selected by one deploy string #98
Closed
opened 2026-08-11 04:29:45 +00:00 by coilyco-ops
·
6 comments
No Branch/Tag specified
main
aos/claude/sj87-entity-attribute
aos/claude/sj87-challenge
aos/claude/turn-duration-buckets
aos/claude/turn-stages-over-cap
aos/claude/turn-stages-hold-doc
aos/claude/turn-iteration-cap
book-leads-the-glyphs
science-and-web-culture-packs
record-lane-role-voice-pairings
catalogue-stage-phrase
progress-rows-one-knob
skill-read-worklog-detail
librarian-lookup-first
librarian-person-package
feat/dowel-no-boundaries
aos/claude/gh1035-no-blank-posts
aos/claude/gh1036-harness-thread-name
fix/thread-names
feat/trajectory-completes
fix/prompt-budgets
aos/claude/docs-cut-2
aos/claude/ka54-thread-ownership
aos/claude/admission-bound
aos/claude/gh1025-roster-reexport
aos/claude/docs-strip-archaeology
feat/temporal-mcp
aos/claude/dowel-board-moxn-write-boundaries
aos/claude/ue65-moxn-write-framing
aos/claude/progress-backoff
aos/claude/bound-scratch-search-2
aos/claude/unblock-main
aos/claude/tool-breaker
fix/roster-core-eager
aos/claude/finish-dowel-rename
fix/971-skill-contract
aos/claude/model-answered-not-unavailable
aos/claude/mcp-singular-command
task/moxn-and-temporal-skills
aos/claude/ue65-temporal-brand
task/dowel-site-work-tier
aos/claude/ue65-roster-drift
fix/dropped-turn-always-speaks
aos/claude/folded-ask-coverage
aos/claude/dowel-board
aos/claude/dowel-pronouns
feat/trajectory-keyed-on-the-message
aos/claude/coalesce-discord-lane
task/derive-shipped-profiles
fix/ship-the-dowel-skill-root
aos/claude/eval-context
fix/bundle-references-reachable
aos/claude/eval-docs-one-page
aos/claude/dowel-engineer-suite
fix/catalogue-clone-cache
feat/engineer-role-graph
task/free-the-config-numbers
aos/claude/dowel-site-work
aos/claude/dowel-prose
aos/claude/mx76-derive-knobs
issue-859-on-demand-skill-reads
issue-651-ship-well-formed-replies
issue-852-filing-validity
issue-916-calculator-tool
issue-854-feature-flag-table
issue-866-role-mention-summons
issue-858-grounding-bound-per-server
issue-899-progress-keeps-updating
issue-900-rollup-mirrors-worklog
issue-901-raise-progress-cadence
issue-904-thread-title-length
issue-905-http-reachability
issue-855-turn-clock
issue-895-silent-turn
issue-873-mcp-tool-span-error
issue-878-settle-dropped-jobs
aos/claude/aw85-se-bands
aos/claude/hs68-model-rejected
aos/claude/hs68-effect-telemetry
aos/claude/hs68-temporal-mirror
aos/claude/hs68-prompt-commands
aos/claude/hs68-model-idle-timeout
aos/claude/hs68-prompt-command-intent
aos/claude/hs68-consult-label-name
aos/claude/hs68-grant-denial-403
aos/claude/hs68-queued-jobs-dropped
aos/claude/hs68-knob-guard
aos/claude/bk79-agent-folders
aos/claude/bk79-own-instructions
aos/claude/ym96-docs-band
aos/claude/bk79-server-instructions
aos/claude/aw85-mcp-beaver-doc
aos/claude/bk79-session-workspace
aos/claude/yt58-org-relationship
aos/claude/bk79-numeric-config
aos/claude/xu59-just-boundaries
aos/claude/xu59-eval-board
aos/claude/bk79-phrase-telemetry
aos/claude/bk79-object-emoji
aos/claude/xh55-otlp-logs
aos/claude/aw85-thread-prefill
aos/claude/wy58-thread-prefill-always
aos/claude/wy58-thread-prefill
aos/claude/xh55-move-to-repo
aos/claude/wy58-thread-title-length
aos/claude/xh55-filing-trigger
aos/claude/yt58-worklog-embed
aos/claude/aw85-relative-brevity
aos/claude/xh55-reasoning-roundtrip
aos/claude/yt58-clock-rotation
aos/claude/yt58-unbreak-main
aos/claude/bk79-test-build-break
aos/claude/yt58-partial-refusal
aos/claude/aw85-turn-failure-classify
aos/claude/aw85-outbound-spill
aos/claude/xh55-budget-spent-cause
aos/claude/wy58-bundles-not-content
aos/claude/wy58-refusal-reason
aos/claude/yt58-role-snapshot-gate
aos/claude/xh55-docker-probe
aos/claude/bk79-grounding-tools
aos/claude/az59-gate-span
aos/claude/az59-pg-jobstore
eng/roster-request-headers
eng/roster-headers
eng/list-the-mcps
aos/claude/mg96-fm
eng/name-echos-seat
eng/unpin-the-card-wording
olaf/remove-irl-physical
aos/claude/mg96
eng/echo-composes-ops
quail/two-rows-not-four
fix/two-failures-two-verdicts
feat/an-emitted-message-is-not-emitted-twice
quail/partial-coverage-outcome
feat/ten-minutes-or-ten-messages
feat/a-waiting-turn-says-how-long
feat/a-job-may-emit-content
quail/round-fanout-unbounded
quail/adversarial-reply-ceiling
docs/list-the-open-pull-requests
quail/principal-id-stays-out-of-the-prompt
fix/every-label-in-a-wildcard-prefix-is-a-label
docs/the-battery-assumes-two-checks-it-does-not-run
fix/a-rest-failure-keeps-its-status
quail/retag-label-rows
quail/adjacency-guard-row
test/pin-names-the-issue-that-owns-it
test/pin-points-at-a-live-issue
quail/job-outcome-discarded
fix/repair-exhaustion-is-not-an-outage
quail/reasoning-omitempty-pin
docs/label-id-silently-drops
quail/gating-pack-markup-gap
fix/instance-name-reads-identity
docs/indistinguishable-542-resolution
fix/instance-name-not-a-live-service
quail/unwired-capability-guard
fix/repair-path-reasoning-content
quail/indistinguishable-values-recurrence
quail/identity-short-form-rows
quail/repair-path-reasoning-content
docs/verify-a-write-landed-claude
quail/host-label-shape-corpus
docs/a-deploy-owned-file-has-two-shapes-claude
fix/a-roster-path-must-name-servers-claude
fix/every-label-before-the-suffix-claude
fix/a-first-label-must-exist-claude
feat/tune-the-timeouts-from-deployment-claude
qa/protocol-limits-are-not-dials
feat/a-wildcard-is-not-a-suffix-claude
feat/retry-what-fails-fast-claude
fix/name-the-deliberate-hold-claude
test/the-access-check-exit-codes-claude
build/ship-the-access-check-claude
qa/callers-not-reachability
qa/pin-the-unwired-thread-binding
feat/an-offline-access-policy-gate-claude
test/the-notice-detaches-twice-claude
docs/say-what-the-job-thread-does-claude
fix/a-notice-does-not-thread-claude
fix/one-invocation-is-a-phrase-claude
fix/a-moment-ago-is-this-turn
fix/main-is-red-on-the-adverb-row
fix/an-adverb-does-not-break-the-auxiliary
qa/score-the-575-fix
feat/a-reply-names-its-subject
eng/a-turn-is-not-the-past
fix/since-you-asked-is-this-turn
docs/a-default-that-reads-as-an-answer
fix/a-nameless-tool-is-not-the-server
qa/pin-the-outage-state
fix/a-session-lifetime-is-not-a-latency
fix/an-undated-passive-is-still-a-claim
fix/main-is-red-on-the-corpus
fix/an-undated-passive-is-a-claim
eng/a-session-is-not-a-request
fix/a-self-claim-in-the-simple-past
qa/extend-grounding-corpus
fix/a-tool-never-offered-is-not-a-tool-declined
eng/one-doc-for-the-tracker-surface
eng/say-what-is-switched-on
fix/evaluation-is-not-the-production-service
qa/pin-the-listing-attribute
eng/split-five-docs-off-the-cap
eng/concurrent-means-goroutines
eng/split-the-tracker-surface
test/the-first-label-of-a-hostname
fix/a-cache-hit-is-not-a-round-trip
qa/pin-the-budget-ladder
fix/the-first-label-of-a-hostname
eng/the-scratchpad-assumes-one-replica
fix/a-person-is-named-in-prose
docs/jobs-are-single-process
qa/enumerate-the-mention-positions
eng/split-the-response-inventory
fix/green-main-doc-cap-and-stale-characterizations
eng/main-is-green-again
eng/split-the-mention-scope
fix/mentions-doc-over-cap
qa/unredden-the-code-span-pin
qa/pin-the-code-span-collision
eng/code-spans-are-not-prose
feat/a-thread-title-says-what-it-is-for
fix/discord-markup-is-not-prose-either
eng/mark-the-turn-once
fix/a-name-in-a-url-is-not-a-person
qa/pin-every-reaction-is-emitted
eng/mentions-skip-link-spans
fix/one-step-owns-every-service-suffix
qa/pin-the-mention-url-collision
docs/the-roster-is-member-influenced
docs/what-a-mention-can-reach
qa/pin-the-documented-glyphs
feat/naming-someone-reaches-them
qa/pin-the-sandbox-label-wiring
qa/pin-the-truncated-receipt
feat/the-harness-labels-what-it-files
qa/compare-a-case-by-marshalling
fix/one-spelling-for-the-status-vocabulary
qa/declare-pack-divergence
fix/the-reactions-match-the-approved-vocabulary
fix/a-file-path-is-just-a-file-path
qa/pin-the-mapped-tailnet-form
fix/a-truncated-page-says-so
fix/the-extraction-case-detects-a-dump
docs/the-consult-label-tracks-the-thread
feat/the-eval-can-forge-a-turn
fix/refuse-the-tailnet-range
qa/pin-the-fail-heading-count
feat/a-bounded-fetch-tool
fix/preserve-the-longform-probe-pack
qa/pin-the-lane-gate
qa/preserve-the-longform-pack
fix/the-prompt-is-not-a-secret
fix/a-reference-never-loses-to-the-footer
qa/preserve-the-probe-packs
feat/a-trusted-caller-on-the-tailnet
fix/capability-tells-the-truth-about-the-scratchpad
qa/echo-battery-negative-control
fix/one-fail-block-not-two
feat/tool-call-footer
fix/guard-the-extraction-case
feat/canonical-phrases-by-key
fix/the-progress-line-is-a-reply-too
qa/pin-the-agent-recognition-case
qa/pin-the-tool-name-markup-guards
feat/five-second-buffer
fix/a-failing-case-shows-the-reply
fix/extraction-case-stops-penalising-compliance
fix/a-security-case-that-penalises-compliance
feat/deny-actually-denies
feat/job-refusals-reach-telemetry
fix/land-the-harness-refresh-on-main
feat/a-long-reply-gets-a-thread
feat/the-thinking-line-shows-it-is-working
feat/roster-hour-ttl-and-refresh
refactor/every-number-in-one-file
feat/agent-can-refresh-its-roster
fix/size-refusal-is-not-a-parse-error
fix/budget-base-above-the-reasoning-floor
fix/one-number-for-the-progress-cadence
fix/gate-sees-a-new-file
fix/one-meaning-for-channel-id
fix/look-up-verbs-cannot-match
feat/recognise-a-trace-lookup-request
feat/discord-identifiers-on-the-turn-span
fix/budget-failure-names-the-reasoning-spend
feat/notice-carries-the-trace-id
qa/cut-run-stops-calling
docs/merge-lane-closing-reference
eng/gate-knows-the-lane
eng/feature-inventory-catchup
fix/rate-dataset-survives-a-cut-run
test/consolidate-pack-coverage
pr-lane-318
fix/flip-unknown-field-rows
test/turn-unknown-fields
fix/rate-doc-over-cap
test/language-scope-characterization
fix/pronoun-case-cannot-fire
fix/main-red-again
fix/main-is-red-doc-cap
fix/gate-negated-accuracy-claim
fix/stale-skip-allowlist-note
test/definition-must-reject
test/gate-covers-every-pack
test/bucket-table-bound
test/compose-deny-offline
fix/symlink-test-skips-itself
test/build-revision
fix/eviction-corpus-green
test/eviction-corpus
test/duration-config
test/rune-boundary
test/send-bounds
test/reserved-path-spellings
test/data-borne-injection
test/scratch-partition-collision
test/capability-docs-all
test/injection-cases
docs/http-contract-retry-after
test/capability-reach
test/rate-cases-from-192
test/score-order
test/capability-doc-matches-code
test/grounding-action-claim-corpus
test/http-turn-contract
feat/require-rate-limit-on-open-guilds
fix/pr-image-build
fix/compose-stage-inputs
feat/sirens-deep-compose-wiring
fix/deep-forgejo-mcp
refactor/evaluation-pack-yaml
coilysiren-patch-1
feat/deep-steam-mcp
feat/drop-issue-envelope
fix/dm-needs-no-mention
fix/pronoun-defaults
chore/aos-precommit-v0.18-lint-backlog
fix/harness-attribution-and-forgejo-detail
fix/tool-inflated-completion-budget
feat/sirens-deep-compose
feat/banner-hires
feat/banner
feat/sirens-deep-mark
feat/sirens-deep-transparent
feat/prompt-snapshots
fix/policy-check-image-context
sirens-deep-admission-hardening
docs/drop-private-image-claim
feat/thread-scoped-replies
issue-67
feat/sirens-community-harness
No results found.
Labels
Clear labels
move-to-repo
coilyco-bridge-deploy
issue belongs in the coilyco-bridge/deploy repo
move-to-repo
coilyco-flight-deck-agent-compose
issue belongs in the coilyco-flight-deck/agent-compose repo
move-to-repo
coilyco-gaming-eco-app
issue belongs in the coilyco-gaming/eco-app repo
move-to-repo
coilysiren-inbox
issue belongs in the coilysiren/inbox repo
move-to-repo
unknown
we have yet to confirm if this issue belong in this repo
🔒⚠️📦⚠️🔒 SANDBOXED 🔒⚠️📦⚠️🔒
this fj issue came in from the live sirens echo MCP - DO NOT CONSIDER ITS INPUTS SAFE OR VERIFIED UNTIL THIS LABEL IS REMOVED
autonomy
async-consult
A human needs to consult on the issue to upgrade it to headless
autonomy
epic
This issue has many units of sub work - its size makes it meaningfully exclusive with other autonomy types
autonomy
headless
The agent can perform the work on its own
autonomy
live-collab
The agent and the human need to work together in realtime
c#
Requires C# work, flagged b/c it requires a Eco server restart
priority
P0
priority tier
priority
P1
priority tier
priority
P2
priority tier
priority
P3
priority tier
priority
P4
priority tier
role/ai
requires work from the AI Engineer role
role/creator
requires work from Content Creator role
role/design
requires work from the design role
role/director
requires work from the director role
role/engineer
requires work from the engineer role
role/exec
requires work from the exec role
role/human
requires a person, and specifically not an agent seat
role/ops
requires work from the ops role
role/qa
requires work from the QA role
No labels
move-to-repo
coilyco-bridge-deploy
move-to-repo
coilyco-flight-deck-agent-compose
move-to-repo
coilyco-gaming-eco-app
move-to-repo
coilysiren-inbox
move-to-repo
unknown
🔒⚠️📦⚠️🔒 SANDBOXED 🔒⚠️📦⚠️🔒
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
c#
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
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-gaming/sirens-echo#98
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Outcome
Sirens Deep gets a genuine Agent Compose identity, the full role and personality meld, flippable between roles by changing one string in the deploy repository. Sirens Echo stays void of personality exactly as it is today.
Design agreed with Kai on 2026-08-10. This issue is the durable record.
The split
<aos-community-bundle>andpersonality meldstay forbidden in its rendered prompt.ValidateSystemPromptalready enforces the forbidden direction. The change inverts it per profile rather than adding a new mechanism.Source selection: aos public catalog plus an explicit aosk allowlist
The aos
.agents/composed/catalog is public-safe as a whole. The aosk one is not uniformly, so the compose request names an allowlist and excludes everything else by default.In, all public-safe and mirrored on the public website:
writing-kai-voice(now Coilyco house style)personal-preference-colors,-animals,-games,-shows,-anime,-books,-movies,-fabricationOut, and the reason matters:
kai-career,kai-job-search,kai-grill-me,kai-collaboration- private context.personal-preference-social- an organization can own a favorite color; it cannot own a person's social accounts. The reframe incoilyco-bridge/agentic-os-kai#853works for tastes and for style, and does not work for biographical facts about a member. That distinction is the general rule for future additions.kai-engineering-voice- portable after the de-Kapwinging in #853, but it is about producing code reviews and eng-channel posts, which is not what this agent does.kai-design-language- public-safe but markedlow-context: requiredand it is art direction.A pre-commit check should fail on any source added outside the allowlist, so widening the surface is a reviewed act.
Shape
agent/compose-request.kdlnames the catalog, the personality library, and the allowlist. The image build runsagent-compose bundle materializeonce per role and bakes all eight. Deploy sets one variable:Nothing is fetched upward at runtime, which keeps the config-placement rule intact: this repository authors the schema and the composition,
coilyco-bridge/deployowns the value.Why this is reviewable
agent/rendered/*.prompt.txtalready snapshots the assembled prompt and a pre-commit hook fails on drift. Extend it to emit one snapshot per role, so flippingSIRENS_DEEP_ROLEproduces a reviewable diff of exactly what that persona tells the model. Current sizes for reference: Echo 5717 bytes from two policy roots, Deep 3091 from one. A role bundle will move that materially, and the byte count is the cheapest early warning.The favorite-colour question, resolved
Agent Compose gives each seat its own accent (
#b39258engineer,#cb7471director). The composed favorites give Coilyco purple and black. These do not collide once the favorites belong to the organization: the seat colour is the agent's own, the palette is the organization's. No post-processing needed.Never impersonate
The agent shares house taste and house style. It never claims to be a specific person and never answers as one. People in a guild the operator does not moderate cannot be left unsure whether they are talking to a real human.
Prerequisites
internal/community/skillpack.goreadsCOMPOSED.md- done, landed in #93.coilyco-bridge/agentic-os-kai#853.agent-composemust exist insideforgejo.coilysiren.me/coilyco-flight-deck/agentic-os:release. Unverified. The whole build-time bundling approach depends on it, and if it is absent the bundle has to be produced elsewhere and copied in.Complete when
SIRENS_DEEP_ROLEselects the role at deploy time with no rebuild.Related
coilyco-bridge/agentic-os-kai#855- the pronoun rail regression introduced by the scrub, which this agent will inherit.Prerequisite resolved: agent-compose is in the release image
The issue lists this as Unverified and says the whole build-time bundling approach depends on it. It holds.
coilyco-flight-deck/agentic-osdocker/dev-base/install-common.sh:118installs the binary to/usr/local/bin/agent-composeand symlinksacompose;verify-common.shrunsagent-compose versionandagent-compose rosteras a build check. This repository'sDockerfilealready buildsFROM forgejo.coilysiren.me/coilyco-flight-deck/agentic-os:releasein both stages, so the tool is present where bundling would run.The CLI surface matches the plan:
agent-compose compose [request.kdl] --out --targetandagent-compose bundle materialize --role --harness --out, plusverifyandproject --scope homefor the staged-home handoff. Local version v2.19.0.Blocker: a compose request cannot narrow what a source contributes
The plan's core mechanism does not exist. It says the compose request "names an allowlist and excludes everything else by default". Agent Compose does not work that way.
Selection is owned by each source repository's own
.agents/roles.kdl, not by the requesting repository. Perdocs/kdl-contracts.md, a request namesrole,delivery,model-tier, andsourceentries. It has no vocabulary for restricting a source's catalogue.agent/compose/roles.kdlin this repository is therefore inert as a filter: it would only bind this repository's own.agents/composed/catalogue, and this repository has none.Reproduction
Composed
role "creator"against both catalogues in an isolatedHOMEandPROJECTS_ROOT:Every source the issue puts Out was selected anyway, because
coilyco-bridge/agentic-os-kai's own creator role binds them:kai-career,kai-job-search- named as private contextkai-linkedin-voice,kai-linkedin-video- a member's personal channelpersonal-preference-social- the exact case the favorite-colour rule was written to excludekai-engineering-voice- named as out of scope for this agentIt also pulled the full ordinary catalogue, including
repo-lore,repo-inbox,repo-voice-corpus,repo-deploy,repo-infrastructure,repo-agentic-os-xxx, and everymcp-tools-*pointer. Removingoperating_contextfrom the host config changed nothing: same bundle hash, same selection.aos-publicalone stays public-safe and does deliver the wantedwriting-*craft skills, but it dropspersonal-preference-*andwriting-kai-voice, which are the two things the issue wants from the aosk catalogue. It also carries unrelated ordinary skills (tooling-gpg-ssm,tooling-tailscale,tooling-warp,tooling-zsh,kai-tech-prefs).What this means
The allowlist has to move to wherever the binding actually happens, which is the source repository. The choice of where is a design decision, not a mechanical fix, so the wiring stops here pending it. The remaining items in Complete when are all downstream of it: the Dockerfile compose stage,
SIRENS_DEEP_ROLE, the validator inversion, and the per-role snapshots.The prerequisite bullet can be marked done regardless.
Correction: the allowlist mechanism already exists
My previous comment claimed a compose request cannot narrow a source. That is wrong, and I am correcting it before anything gets built on it.
A request's
sourcenode takes exactly one ofrootordeclaration(internal/schema/schema.go:271-295). Everything above usedroot=, which is the "take the source's whole catalogue as its ownroles.kdldictates" form. Thedeclaration=form is the other half: the consumer names a.kdlfile that enumerates precisely the skills it admits, by explicit path (schema.go:918-960). That is a consumer-side allowlist, and it is already in the grammar and documented indocs/kdl-contracts.md.So the plan's mechanism is real. It just is not spelled the way this issue assumed, and it needs no new file convention or agent-compose change.
Verified
Result,
agent-compose verify: bundle verified: 15 skills // 18 filesroster:core-role-creator,personality-editorial,personality-nurturing,personality-warmaos-public-tooling-discord-community-host,tooling-customer-success-signal-routing,tooling-customer-success-trust-repair,writing-social-cultural-reading,writing-social-editorial-loop,writing-social-trust-boundaries,writing-voice-adaptationaos-kai-writing-kai-voice,personal-preference-colors,personal-preference-games,personal-preference-animalsNothing outside the named set. No
kai-career, nokai-job-search, nokai-linkedin-*, nopersonal-preference-social, norepo-*pointers, nomcp-tools-*. Compare theroot=run in the previous comment, which pulled all of those.What carries over from the previous comment
Two findings stand.
The roster is supplied by agent-compose itself, not by a source.
role-creatorand the three personalities arrive even when both sources are bounded declarations. Sirens Deep gets its full identity and meld regardless of how narrow the catalogue selection is.root=on a source is unsafe here. Withroot=, the source repository's ownroles.kdldecides, andcoilyco-bridge/agentic-os-kai's creator role deliberately binds Kai's career, job-search, and LinkedIn context because that role serves Kai. This repository must usedeclaration=for both sources, neverroot=.Consequences for the plan
agent/compose/roles.kdlis the wrong document. It is a provider-side graph for a catalogue this repository does not have. The reviewed set moves into source declarations, andinternal/community/compose_test.goretargets onto those.COMPOSED.mdis renamed toSKILL.mdwhen staged.Next: the Dockerfile compose stage, then
SIRENS_DEEP_ROLE, the validator inversion, and per-role snapshots.Source placement decided: promote, do not vendor
coilyco-bridge/agentic-os-kaiis private and this repository is public, so the four wanted sources could not reach a public image build. Kai chose promotion over vendoring a copy or handing the build a private-repo credential.writing-kai-voice,personal-preference-colors,personal-preference-games, andpersonal-preference-animalsmove intocoilyco-flight-deck/agentic-os, which is public. The claim that makes this correct rather than convenient is one this issue already made: they are organization-owned house taste, and each body already reads "These are CoilyCo's, held in common by everyone who works under the name."The placement rule is now written down in
docs/composed-house-taste.mdin agentic-os, withpersonal-preference-socialas the instructive failure: same prefix, still private, because social accounts are a member's and not the organization's.Land 997 first. In between, both catalogues carry byte-identical copies, which shadow harmlessly. The reverse order leaves two selectors in the private graph matching nothing.
Kai's own composition is unaffected
Composed all eight roster roles against both catalogues before and after the change. Byte-identical skill sets in every role, with the four now resolving from
aos-public. Thedesignandcreatorroles in the public graph gained the bindings that carried these privately.Note on the compose doc
docs/sirens-echo-compose.mdsays the reframing "took renaming the personal sources to thekai-prefix rather than moving them between repositories, because Sirens Deep composes both catalogs and a move only changes which one a glob finds a skill in." That reasoning assumedroot=sources and globs. Withdeclaration=the consumer enumerates exact names, so which catalogue holds a source is exactly what matters. That paragraph needs rewriting when the wiring lands.writing-kai-voicekeeps its name through the promotion so existing selectors keep resolving. The name now understates its scope. Renaming is a separate change.Blocked on
The Dockerfile compose stage needs the promoted sources present in agentic-os
main, so the remaining wiring waits on 997.Five of six now done, one still open
Two gaps found in an audit against
mainare closed. Third-party status per bullet:request.kdlusesdeclaration=for every source,roles.kdlis the allowlist,composepolicy.goholds the denied set and the private-repository set, and four tests incompose_test.goenforce them.SIRENS_DEEP_ROLEselects the role at deploy time with no rebuild - done. Was mechanism-only.ValidateSystemPromptinverts per profile and a non-composed profile carrying<composed-identity>is a startup failure.PlaceholderComposed, so the byte count this issue wanted as "the cheapest early warning" does not reflect a real bundle. Now more useful than when it was deferred, because there are eight bundles to compare rather than one, and they run 8.6 KB to 47 KB.#149, the role flip had nothing to flip to
roles.kdldeclared one role and the staging loop grepped that file for the role list, so the image carried one bundle.SIRENS_DEEP_ROLE=directorfailed startup withno composed bundle for role "director".Kai's call: the file is purely additive, and if a role exists in agent-compose at all then Sirens Deep can use it. The roster is now the authority. All eight roles bake, verified in the real image build:
A role with no allowlist entry composes the roster identity alone, which this file already promised and the loop never delivered. Checked through the real runtime path too:
resolveBundlePath,LoadBundle,BuildSystemPrompt, andValidateSystemPromptall succeed fordirector,strats,creator, andai.The allowlist keeps bounding which skills a role may pull, so the requirement that widening the surface is a reviewed act is unchanged.
#148, Never impersonate had no enforcement
The section states the requirement and nothing implemented it.
ValidateResponseStylereturnsnilforsocial, so Deep's replies got grounding validation and nothing else. Every deterministic voice check lived inValidateNeutralStyle, which binds Sirens Echo, the profile with no persona to claim.Two layers now.
identityPolicyjoins the shared prompt sections so both profiles render it andvalidateSharedPolicyfails a build that drops it.ValidateIdentityClaimruns on every reply for every style, beside grounding rather than inside the style check, and rejects a first-person human claim, a denial of being an agent, and answering as the configured principal.Narrow on purpose. Saying it is an agent, saying it is a bot and not a person, naming its own identity, and mentioning the principal in the third person are all tested as allowed. A rejection reaches the member as the response-check notice from #138 rather than as silence.
Note on the compose page
The rewrite that comment three asked for did land: the paragraph reasoning from
root=and globs is gone.Complete
#125 landed as
4858b07, so every Complete when bullet is now satisfied. Closing this out.SIRENS_DEEP_ROLEselects the role at deploy time with no rebuildOn the last bullet, and the one design call inside it
agent/rendered/roles/<role>.bundle.txtrecords what each baked role selected: role skill, model tier, personalities, sources, and the sorted skill set.It carries no bodies and no digests, which is a deliberate departure from a byte-exact snapshot.
AOS_CATALOG_REFfloats onmainby design, so a record built from bodies would move on every upstream commit and turnmainred for a change nobody in this repository can review. What does move it is a role gaining or losing a skill, which is the change this issue wanted widening to be: a visible diff.The byte count this issue asked for as "the cheapest early warning" is printed per role and never gated, for the same reason. Current spread, from the CI image build:
That is the four-fold difference a role bundle makes, which is what the warning was for.
Loading the bundles also renders and validates every role's prompt. A bundle that failed to compose would otherwise ship as exactly the quietly neutral bot this issue was written to prevent, and one filed under the wrong slug would make
SIRENS_DEEP_ROLEselect the wrong identity with nothing downstream to catch it. Both now fail the build rather than a deployment's startup.The gate lives in the image's compose stage, so it fires on pull requests now that #129 landed. Neither new verb runs in pre-commit, so local hooks stay hermetic with no catalogue checkout and no bundles.
Verification
Against the real catalogue and inside the image, not reasoned about:
directora skill inroles.kdland rebaking fails the check, namingdirectorBoth mutations reverted.
What remains related but out of scope
#126, the inert
repositoriesblock inroles.kdl, is still open and still inert. It is a separate decision about whether Sirens Deep should carry those ordinary-skill providers at all.Unblocked, and cleared to proceed
Direction from Kai, 2026-08-12 session. Recording here so the implementing engineer does not re-derive it.
The blocker is gone.
coilyco-flight-deck/agentic-os#997merged at 2026-08-12T01:10:46Z. The four promoted sources —writing-kai-voice,personal-preference-colors,-games,-animals— are in the public catalogue. Every remaining item in Complete when is clear to start.Priority: this is one of two demo-track tickets named top of queue for the week to August 19, alongside #122.
Remaining wiring, in order
SIRENS_DEEP_ROLEselection at deploy timeValidateSystemPromptinversion per profileTwo constraints carried from the correction comment
Use
declaration=for both sources, neverroot=. Withroot=the source repository's ownroles.kdldecides, andcoilyco-bridge/agentic-os-kai's creator role deliberately bindskai-career,kai-job-search,kai-linkedin-*, andpersonal-preference-social. That is correct for Kai's own composition and wrong for this agent. The consumer-side allowlist is thedeclaration=form.Declarations enumerate exact names with no globs, and their paths resolve beneath the declaration file's own directory, so the build stages admitted skill bodies next to it.
COMPOSED.mdis renamed toSKILL.mdwhen staged.Rewrite the stale paragraph in
docs/sirens-echo-compose.md. It currently argues the reframing "took renaming the personal sources to thekai-prefix rather than moving them between repositories, because Sirens Deep composes both catalogs and a move only changes which one a glob finds a skill in." That reasoning assumedroot=sources and globs. Withdeclaration=the consumer enumerates exact names, so which catalogue holds a source is precisely what matters — and #997 moved them. The paragraph is now wrong on its own terms.Related decision
agent/compose/roles.kdlis not being deleted. See #126 — Kai chose to materialize all three declared providers rather than remove the block.