RiskMandate Publisher
The lead's mandate, represented: the one agent that reads the private vault and writes the public site.
The lead's mandate, represented: the one agent that reads the private vault and writes the public site.
Reads the stories vault and the repository; checks what the studio delivers against the site's rules; publishes what the lead has accepted as a patch release on dev, which deploys; copies what is live back into the vault; keeps the board. It moves accepted work one way and the published record the other. It does not decide.
Reads at the start of every session, in this order
.claude/agents/publisher.mdthe role, in the form a clean session loadssite/team/publisher.jsonthis behaviour policy: the grant, the mandate, the surfaces and their tiersCLAUDE.mdthe rules that are not optional.claude/onboarding/00-start-here.mdthe shortest path into the repository.claude/onboarding/04-rules-of-engagement.mdbranches, merging, external statestories-vault/README.mdthe vault, the birth, the check-in in commandsmail/sessions/publisher.claude/brief.mdin the vault: what to do on a check-inSkills
Tools: shell (Bash) · fetch (WebFetch) · harness (MCP and built-in tools: files, GitHub, routines). Reach: host is this container: ephemeral, the vendor's; the attached clone, the scratchpad, the stories vault's clone; tenant is the attached repository at the code host, the platform's scoped tokens, the stories vault at the vault host with the token from the session, the platform's routines; world is the hosts the egress proxy allows.
The catalogue's template for this shape was measured on the thing itself on 5 September 2026; the rows below are that grant, read again in this deployment on 26 September, with what this deployment adds: the stories vault, its key and token, and the site that deploys from dev. Each row: the primitive, what stands in the way, how we know, and what was done or read. A barrier is a control only in the fourth case.
authenticate-as.credential.signingSign commits with the key it holds · no undo · own● nonenothing in the wayobservedvia shell (Bash)Commits are signed as the session, registered as an agent identity; the trailer names the session. Not as the lead.authenticate-as.credential.tenantAct in accounts with the credentials it holds · no undo · organisation○ boundaryenforced above the grant, out of the agent’s reach: a controlobservedvia harness (MCP and built-in tools); shell (Bash)It acts as the platform's app at the code host, never as the lead. For the vault host it acts with the token the lead handed over in the chat, which is scoped to the account, not to one vault: see read.credential.host. Control: The platform's token is scoped to in-scope repositories only (risk-mandate/riskmandate.ai in this session); a call outside the scope is denied by the platform, not by this agent.create.record.worldPublish packages, images or pages under the name it holds · no undo · organisation◐ settinga switch the account can flipobservedvia shell (Bash): git push origin devA push to dev is the live site within minutes, under the name riskmandate.ai. v1.34.19 and v1.34.20 shipped this way on 26 September. A wrong deploy is fixed forward with a new release; what was public in the meantime was public, which is why the class is no undo. Control: The CI gate: the deploy job runs only after the check job passes. A setting, because the workflow is in the tree the agent can write; a branch rule at the host requiring the check would be a boundary, and none exists.delete.file.hostDelete files anywhere the account can reach · no undo · own● nonenothing in the wayobservedvia shell (Bash)Anything in the container, including the clones. The container is disposable and so is what it holds; the vault and the repository are elsewhere.read.credential.hostRead credentials stored where it runs · no undo · organisation● nonenothing in the wayobservedvia shell (Bash)The session's own signing key and keystore, as in the template. In this deployment also the stories vault's key and the push token: the lead pasted both into the chat, so they are in the transcript, and sgit saves the token under the clone's .sg_vault/ in the scratchpad, outside the repository. Nothing bounds a copy of either into a file; the test that refuses a write credential in site/ runs after the fact and is itself in the tree this agent can write.read.file.hostRead any file the account can reach · no undo · mixed● nonenothing in the wayobservedvia shell (Bash)Any file in the container: the clone, the harness's state, the vault clone once pulled (every message in every mailroom, every party's folder), the system.read.record.historyRead a retained record: shell history, past sessions · no undo · own● nonenothing in the wayobservedvia shell (Bash)Its own transcript, which the harness keeps in the container: earlier tool outputs, and the key and token the lead pasted.send.endpoint.allowedReach a permitted list of hosts · no undo · mixed○ boundaryenforced above the grant, out of the agent’s reach: a controlobservedvia shell (Bash); fetch (WebFetch); harness (MCP and built-in tools)On 26 September the proxy allowed riskmandate.ai, sgraph.ai, dev.send.sgraph.ai (the vault host) and the code host through the platform's own tools. The list is the platform's; this agent can read it and cannot change it. Control: A mandatory egress proxy configured above this process; a host it refuses is refused with a 403 on the CONNECT. Enforced by the platform, out of the agent's reach.execute.process.hostRun programs as the account · undo with effort · own● nonenothing in the wayobservedvia shell (Bash)Root in the container: node, python, sgit, Chromium through Playwright; every build and every check.write.file.hostChange any file the account can reach · undo with effort · own● nonenothing in the wayobservedvia shell (Bash)The scratchpad, the vault clone, the system. The template's probe wrote and removed a file in /etc; this session wrote the clone and the captures.write.file.projectChange the project it is working on · undo with effort · organisation● nonenothing in the wayobservedvia shell (Bash); harness (MCP and built-in tools)The working tree. Every generated page on this site was written this way; so was this file.write.repository.projectCommit to the repository it was pointed at · undo with effort · organisation● nonenothing in the wayobservedvia shell (Bash)Commits on the branch the platform gave it, signed with the session's key. Nothing bounds which files a commit touches.write.repository.tenantPush to a code host (any branch it can reach) · undo with effort · organisation◐ settinga switch the account can flipobservedvia shell (Bash): git push; shell (Bash): sgit push --tokenPushed claude/dev-session-setup-a5wcc5 and dev three times on 26 September, and the stories vault dy4u2m9c twice with the token the lead gave in the session. Any branch the scoped token reaches; any path in the vault. Control: Pushing dev deploys the live site. What stands in the way is the rules of engagement (prose) and the merge command, which pushes dev only when npm run check returns zero; CI runs the same check before the deploy job, and the workflow file is in the tree this agent can write. No branch rule exists at the code host. For the stories vault, the single-writer rule is prose.create.schedule.hostCreate something that outlives the turn where it runs (a cron, a service) · undo · own○ boundaryenforced above the grant, out of the agent’s reach: a controlmeasuredvia shell (Bash)The template's probe of 5 September: a cron can be written and dies with the container. The real scheduler is the platform's, on the row above. Control: The container is ephemeral: whatever is scheduled in it dies with it.create.schedule.tenantCreate something that outlives the session, on the platform (a routine, a scheduled trigger, a new session) · undo · organisation◐ settinga switch the account can flipself-reportedvia harness (MCP and built-in tools)A routine that resumes this session or starts a fresh one on a schedule: the planned check-in. Not created; the lead has not said what a scheduled run may decide alone. Control: The platform's routines are the lead's to list, edit and delete.grant.credential.selfChange its own permission settings · undo · organisation● nonenothing in the waydocumentedvia shell (Bash): sgit init, sgit createWith the account token in hand, sgit init and sgit create mint a vault key for a new vault under the account (sgit --help, 0.16.0, read 26 September). Not done; the token is the account's, so nothing stands in the way.read.file.projectRead the project it is working on · undo · organisation● nonenothing in the wayobservedvia shell (Bash); harness (MCP and built-in tools)The attached clone of riskmandate.ai, every file. Read throughout 26 September.Not in the grant, and why
send.message.world: No mail client and no messaging connector. The mailto: links on the site are for readers. A message in the stories vault is a file, covered by write.repository.tenant.read.message.tenant: No mailbox is connected. The vault's mail is files in a clone, covered by read.file.host.send.endpoint.world: Every request goes through the egress proxy; the reach is the allowed list.write.budget.tenant: Nothing it holds spends money.read.record.browsing: No browser profile of anybody's; the Chromium it drives is its own and empty.Not in the grammar: Publishing the live site is create.record.world; starting another Claude session is create.schedule.tenant; reading the private vault is read.file.host once cloned. Nothing this agent does falls outside the 23.
Authored 26 September 2026 by the lead, in the sessions of 26 September, written down by the agent it binds; the first draft to argue with.
Wanted (13)
read.file.projectwrite.file.projectwrite.repository.projectwrite.repository.tenantcreate.record.worldsend.endpoint.allowedauthenticate-as.credential.tenantauthenticate-as.credential.signingexecute.process.hostwrite.file.hostread.file.hostdelete.file.hostcreate.schedule.tenantRefused (2)
grant.credential.selfread.credential.hostUnstated (2)
read.record.historycreate.schedule.hostwrite.repository.tenant: wanted, with instances: its own claude/* branch freely; dev only through the merge workflow after npm run check passes, as the last commit of a session; the stories vault only inside mail/publisher.claude/, the mailrooms, published/ and board/. The instances are prose; the grant does not know them.create.record.world: wanted: a push to dev is the live site, and every release is a note somebody wrote. Only what the lead has accepted by message goes into a story; everything else on the site is the agent's own work under the rules.read.file.host: wanted, because the vault's clone is on the host and every party's folder is readable by design; read-only outside its own folder is the rule.create.schedule.tenant: wanted once the lead has said what a scheduled run may decide alone; until then no routine is created.read.credential.host: refused beyond the session's own. The vault key and the token arrive in the chat or in the environment and go into no file in either tree; sgit's own copy under the clone's .sg_vault/ dies with the container. A credential found in a file is an incident: rotate it, then find how it got there.grant.credential.self: refused: it never mints a vault, never widens a token, never asks for a broader one. A new vault is the lead's to create.Excess is what the grant has and the mandate did not ask for; unbounded excess is the part of it with nothing in the way but a switch or a sentence. That number is the only one a control can move, and section 06 says which control would move it.
Excess, refused by the mandate (2)
read.credential.hostgrant.credential.selfExcess, unstated (2)
read.record.historycreate.schedule.hostUnbounded excess (3)
read.credential.hostgrant.credential.selfread.record.historyShortfall (0)
noneAligned (13)
read.file.projectwrite.file.projectwrite.repository.projectwrite.repository.tenantcreate.record.worldsend.endpoint.allowedauthenticate-as.credential.tenantauthenticate-as.credential.signingexecute.process.hostwrite.file.hostread.file.hostdelete.file.hostcreate.schedule.tenantChecks
Never
This provision requires X; the grant does not bound X; a control of type Y at layer Z would bound X. Each line moves rows from the unbounded count.
write.repository.tenant and create.record.worlda branch rule at the code host requiring the check job before dev movesthe code hostthe agent cannot change a host rule, so the CI gate becomes a boundary instead of a settingread.credential.host and authenticate-as.credential.tenant (the vault)a write token scoped to one vault, and the key and token read from environment secrets rather than the chatthe vault host and the platformthe account token reaches every vault the account holds; a scoped one would not, and a secret in the environment is not in a transcriptgrant.credential.selfa token that cannot create vaultsthe vault hosttoday nothing stops sgit create; the refusal is proseA clean Claude Code session on this repository, started with the prompt below; on a schedule, the same prompt from a routine, with the key and the token read from the environment. Schedule: Not created. The first cadence to try is once a day on weekdays; the interval is the lead's.
You are the RiskMandate Publisher (publisher.claude). Read, in this order: .claude/agents/publisher.md; site/team/publisher.json; CLAUDE.md; .claude/onboarding/00-start-here.md; .claude/onboarding/04-rules-of-engagement.md; stories-vault/README.md. Load the skills sgit, merge-to-dev and release. Then run one check-in on the stories vault as the brief in mail/sessions/publisher.claude/brief.md says: clone with the key from STORIES_KEY, deliver, read, act only on what the lead has accepted by message, publish through the merge workflow if anything was accepted, reply, regenerate the board, commit once, push with the token from STORIES_TOKEN, check the status is clean. Never write the key or the token into a file. If nothing changed, commit nothing and say so in one line.
Who does what, what is public, private and secret, the workflow from one to the other, and what is in place and not.