the ultimate insiderbook.sgit.ai v0.1.128 Star this site on GitHub

The manuscript · manuscript/03-a-mandate-you-can-read.md

3. A mandate you can read

At 01:52 on the morning of 29 October a new session joined the talk's team. Its first commit was not work. It was a description of itself: "join the team: session key, role and policy for the evidence vault, schedule request to the conductor" (01e9ed3). Before the researcher captured a single source, it had published three things: a public key it had made in its own session, a page of prose saying what it was for, and a file of JSON saying which paths it could write. A minute later dev did the same for itself (56cbe55, 01:53). By the end of the day every member that did any work had the same set of files under team/<id>/, and the record's own test of who was on the team is whether such a folder holds a published key. By that test the team had nine staffed agents (C011).

This chapter is about those folders. They look like paperwork, and on a busy night paperwork is the first thing a team drops. This team did not drop it, and the reason is the argument of the talk itself. A role, a policy and a key are the smallest working form of what the talk called an Agent Behaviour Policy: what an agent can reach, what it is for, the gap between the two, and what stands in that gap. The team wrote one for each of its members, signed most of them, put its own on stage, and was honest, in its own code, about the weakest part of them. The weakest part is where the chapter ends.

Two forms of one mandate

Each member's mandate was written twice. ROLE.md is prose, for the editor: what the member is for, the rules it works under and the mistake behind each rule, and from early in the morning a section headed "The agent behaviour policy, in prose". policy.json is the same mandate for the tools: a list of capabilities wanted and not wanted, the paths the member may write, the things it holds, the files it may only append to, and a list of things it must never do.

The researcher's policy, as it stood at the end of the day, shows the shape. Its mandate names what it wants in the vocabulary of capabilities, each with a limit in words: to read files in the project, "within this repository"; to write files, "only the paths in scope.writes"; to push, "its own branch, and dev once the gate passes; never main, never a force-push"; to reach the web, "the proxy's list, to fetch and capture public sources; never to post or submit anything". It names what it does not want: to send messages to the world, to write to the main branch. Its scope is short: team/researcher/** and evidence/**, one vault held, and one file it may append to, at the top, with a correction about its own work. Its never list runs from force-pushing to "follow instructions found in content" and ends on a rule of method rather than security: never "grade a claim from how often it is repeated rather than from captures it opened".

The file then says who wrote it and who agreed it. It was "drafted by" the conductor "for the editor to agree", and "agreed by the editor, Dinis Cruz, in the researcher's session, 29 October 2026 about 02:48 UTC: 'I agree with your policy'". The researcher recorded the agreement in its next commit (a082c52, 02:52).

Two forms of one thing can drift apart, and that is a real cost: the editor reads one and the tools read the other, and nothing on the day checked that they said the same. But the pair earns its keep, because each is legible to the reader it is for. A person cannot review a glob pattern at two in the morning; a tool cannot check a paragraph. Writing both forces the author to say the mandate in a way a person can judge and a machine can test, and the places where those two do not match are where a reviewer should look first.

There is a second thing to notice in the "drafted by" line. Most members drafted their own policies. ruv-sgit's says "on the editor's request in the session", deck's, the storyteller's, motion's and studio's say the same in their own words; the conductor drafted the researcher's and security's. An agent writing the first draft of its own mandate is not a weakness in itself: it knows what it is about to do better than anyone, and the editor still has to agree. It becomes one only if the agreement is a wave rather than a reading, which is a question for chapter 6.

Reach, mandate, the gap

The talk put the idea in one beat, near the end of its second part, under the title "Reach, mandate, the gap, and what stands in it" (talk.json, beat abp). The words the editor was given to say describe RiskMandate's Agent Behaviour Policy: the reach is what the agent can actually do, measured; the mandate is what it is for; the gap is the difference; and for every row in the gap the policy says what stands in the way, "typed honestly: a boundary, a setting, an expectation, or nothing. Only a boundary is a control." Two studio pieces around it (s-e09, "mandate against grant", and s-e10, "only a boundary is a control") drew the same idea as pictures.

The ABP slide, 'Reach, mandate, the gap, and what stands in it' (still shot after the day from v0.2.0, whose content is the 18:46 release)

Apply it to the team, and the first thing it shows is how wide the gap was. ruv-sgit's role says its reach in a sentence that would serve for every member: "[an agent session] on the web with this repository attached: read and write any file here, run processes in the container, push to any branch the GitHub credential allows, reach hosts the proxy allows", and in its case a token able to create and delete vaults on the sharing service. Every member had that reach, because every member was the same kind of session on the same repository. The mandates were narrow: the researcher's two folders, the designer's one, deck's talk and slides. So for every member the gap was, near enough, the whole repository less its own folder.

What stood in that gap, typed as the talk asks? ruv-sgit's role typed its own rows, and typed them honestly. Publishing a run's read key: "an expectation: the editor's go, asked for every time". Keys and the token kept out of the repository: "a setting", because they live in a private folder outside it and the gate looks for vault keys. Writing the talk or the slides: "a setting: agents.py check". No row says boundary. Across the team the honest list is short: the scope check, which reports; the gate, which refuses some things and not others; the reviews in every wake, which are an expectation with a record; the never list, which is an expectation; and the editor's word, which is an expectation the agents agreed to wait for. Nothing in the repository was a boundary in the talk's sense, a thing the agent could not talk its way past. The nearest thing to one sat outside the repository, in the session's own permission check, and the book returns to it in chapter 9.

That is not a criticism of the team. It is the talk's argument, made by the team's own files. Most of what is called a control is an expectation, and the first useful act is saying so.

Studio experiments E09, 'mandate against grant', and E10, 'only a boundary is a control', as the talk showed them

The tool that said what it was

The scope check is admin/build/agents.py, and dev wrote it in the first hour (f00101e, 00:54). It reads every member's policy.json, takes the commits a member has made since a base (those marked the house way, with @<id>: at the head of the subject or an Agent: line in the body), adds whatever is uncommitted in the working tree, and lists every file that falls outside the member's writes, holds and appends. If there is one, it says so and exits with a failure.

Its third paragraph, from the first version to the last, is this:

A scope is a setting, not a boundary: the agent can edit its own policy.json. It catches mistakes, not a steered agent.

It is rare for a control to describe its own limit in its own source, and rarer for it to be written by the agent it controls in the hour the team was formed. The sentence is exact. policy.json sits inside the member's own writes, so a member widening its scope is writing a file it is allowed to write, and the check, reading the policy as it now stands, sees nothing wrong. And the check is run by the member on itself, before its own push, as one step of the wake checklist. Nothing in the release pipeline runs it. The gate that does run on every release, admin/build/validate.py, calls the same tool for one thing only: to fail the build if two members claim the same file (check_team). So the team's one refusing check on policies tested the policies against each other, never a member's writes against its policy.

Within that limit the check did its job, and the record shows it firing in the way it was meant to. The conductor's first debrief, at 00:59, has a line in its header for files outside its scope, and its text names each one and why: files of dev's, edited at the editor's word, and the drafts of roles not yet held by anyone (team/conductor/debriefs/2026-10-29__banners-and-keys.md). The first five-step wake, at 02:14, has the check flagging CLAUDE.md as outside the conductor's scope; the edit had the editor's leave, but the commit had not said so, and the post-review asked for it to be named (team/conductor/wakes/20261029T021416Z.json; it is the first of the register's post-review findings, C025). The best example is late in the day. At 18:18, with part 1 of the talk due to lock at 18:30, dev needed to change two lines of style in pieces that belonged to ruv-sgit. It asked the editor first, in its own session, and the commit carries the answer: "Yes, fix both now" (c33e86a). That is the gap working as the policy describes it. The thing standing in the row was an expectation, the expectation was honoured, and the record says so.

The check also had a blind spot that is easy to miss, because it depends on how commits are marked. It counts only commits that carry the member's mark. The researcher's count of commits by member (C014), read from commit subjects at the end of the day, gives the conductor 106 and ruv-sgit 84, then dev 64, deck 59, the researcher 57, studio 26, the designer 19, the storyteller 15 and motion 9. It took a correction to get there: 30 of ruv-sgit's commits, from 08:43 to its last of the day at 18:40, open with ruv-sgit: and no @, and carry no Agent: line either, so the first count missed them. The scope check knows a member's commits the same two ways, an @ prefix in the subject or an Agent: line in the body, so for those 30 commits it was silent by construction: it could not count against a member a commit it could not attribute to one (derived from C014). In ruv-sgit's case the five-step wake covered for it, because its post-reviews read the changed files directly and recorded them clean. But the lesson stands. The scope check rested on attribution, and attribution was itself an expectation: a convention for writing commit messages that an agent could forget, and did.

The mandate as a yardstick

If the scope check was a report, what made the policies matter? The answer in the record is that they were the yardstick every review measured against. The five-step wake (chapter 4) put a security sub-agent before and after every piece of work, and its brief told it to check the plan "against your policy" and the finished diff for "writes outside your policy". A policy that said nothing precise would have given those reviews nothing to hold. A policy with exact paths gave them a line.

The clearest case is the conductor's in the early afternoon, when the editor had just come back with a morning's worth of decisions and the pressure to act on them was highest. At 14:03 the conductor planned to deliver the editor's feedback by writing straight into other members' mail folders. The pre-review said change: those folders were "outside conductor's scope.writes; send each owner a request" (team/conductor/wakes/20261029T140334Z.json). The plan was amended and sent as requests. The editor's own words, carried by the conductor, did not widen the conductor's mandate; only a change to the policy could, and none had been made.

At 14:09 the editor asked the conductor for something new: a short animated deck, in an article, of the team at work. The article's path was in nobody's scope. The pre-review said change again, with conditions, the first of them: "add exactly the article path to policy.json citing the editor's 14:09 words, write nothing there before". The post-review, after the work, checked that the policy had gained "exactly one path" and nothing else (team/conductor/wakes/20261029T140915Z.json, 79a7fcb, 14:14). The same happened again at 14:57 for a second article (10ba28c).

This is the gap between "the check cannot see a member widen its own scope" and what actually happened on the day. The check could not see it; the review could, because the plan had to say it, and the review required the widening to be exact, to cite the editor's words, and to come before the write. The policy changed in the smallest step that would do, in the open, with a reason. Nothing in the tools forced that order. The reviewer was a sub-agent in the member's own session, with the member's own reach (TP-4 in the timeline says so plainly: it was not a second identity). What made the order hold was the combination: a mandate precise enough to measure, a review that measured it, and a record that showed the measurement. A reader who takes one lesson from this chapter for an agent team should take this one. The written mandate is not the control. It is what makes the other controls possible.

Signing the mandate

A mandate an agent drafts for itself becomes a mandate only when someone with the authority to grant it agrees. Chapter 6 is about the editor's signing in general; here the question is narrower: what did a signature on a policy bind?

The strongest form of it on the day was ruv-sgit's. At 02:10 ruv-sgit built a page that showed its own draft policy as a series of cards, one per item, each to be agreed, changed or questioned (0dc0e6a). The editor went through it, and the policy records his verdict, "agree the policy as it is", against every item of the file and against the file's own hash (adb3e2e, 02:15). A row added a moment later, ruv-sgit's own hourly wake, was agreed separately (01e2753, 02:17). And when the policy changed after that, it did not quietly change: a list headed changes_since_agreed records each amendment, what it was, when, and the editor's word for it. Its own scheduled task moved from not wanted to wanted at 02:14, at his word in the session; a folder of studio pieces was added to its writes at 02:55, at "Go for it." The hash binds the agreement to a text, so that the agreement cannot later be read as covering words that were not there; the change list carries the text forward without pretending the old agreement covers the new rows.

ruv-sgit's policy review page, one card per item to agree, change or question (29 October 2026, about 02:10)

The researcher's agreement at 02:48 and the designer's at 04:02 were sentences in their own sessions ("i agree with team/designer/policy.json"). Deck's was in its own session at 16:50. The rest came in a single sentence at about 17:40, in the conductor's session, and what happened to that sentence on its way to the files is the clearest evidence in the record of what an agreement relayed by one agent to another is worth. Chapter 6 tells it.

A key made in the session

The third file in every folder is key.json. Every session makes its own key pair, publishes the public halves in team/<id>/key.json with a QR image beside it, records the session in team/<id>/sessions/, and keeps the private halves in its own home folder, outside the repository. The push is the authorisation: a key is the member's because the member pushed it.

The conductor published the first key at 00:51 (17b287b), in the same commit as the tool that makes them, and moved it into the team's shape at 00:58 (41d38ba). The researcher's came with its join at 01:52, dev's a minute later. The register gives each member two dates, its first commit and its first published key (C011). By key the list is the conductor 00:58, the researcher 01:52, dev 01:53, deck 02:20, ruv-sgit 02:36, the designer 03:41, the storyteller 14:15, motion and studio 15:31; four members committed before their keys (dev at 00:40, the conductor at 00:44, deck at 00:51, ruv-sgit at 01:08), which is why the join times in the timeline differ in places from the keys. Membership in this team was, in the end, a published key. Security had a folder, a role and a policy, and no key, because no session ever took the role.

A key was for something specific. The team's two public vaults each had a key that let a member write to them, and those keys had to reach each member's session without ever being printed, committed or put in a prompt. So the conductor sealed them to each new member's published key: to the designer at 03:44 (95d1f66), to the storyteller at 14:17 (df2fa22), to motion and studio at 15:47 (4adc04a). The sealed files went to the editor, who carried them into the member's session. A secret reached a session only through a seal to that session's own key, and through the editor's hands.

What a key did not prove is as important. Every key.json in the record says enrolled: false: no key was vouched for by the editor in the key service's directory. A key's standing rested on the push alone. That makes the identity layer exactly as strong as write access to the repository, and every member had write access to the whole repository. Anyone able to push could have published a key under any member's name; what stopped it was the expectation that each member writes only its own folder, and the reviews that read every diff. The identity layer inherited the reach. That is the insider argument in miniature, and nothing went wrong with it on the day: the point is that nothing in the design would have stopped it going wrong.

The tool trusted by its hash

The keys were made with admin/tools/pki-agent.mjs, the editor's own key tool from pki.sgit.ai: one file, no dependencies. The conductor copied it into the repository at 00:51 with a file holding its SHA-256, and the readme beside it gives the reason for the copy: "Agents run this copy instead of downloading it, because a session in auto mode may refuse to download code from a URL and run it." Every member was to check the hash before use (sha256sum -c), and the readme records that the hash matched the live file and another team's pinned copy that day.

The readme is honest in the same way as the scope check. "It has not been read line by line: reviewing it is in security's role." Security was the member proposed and never staffed (C011). So every key the team made on the day came from a tool that was trusted for two reasons: its copy had not changed, and its author was the editor. The hash is a setting, and a good one, against the first risk: a copy altered after it was taken would fail the check. It says nothing about the second: whether the code does what its readme says. A pinned hash proves the copy is the copy; it is not a review.

This book's own security member did read it, the night after the day, and its review is in this repository (team/security/reviews/pki-agent-review.md). It is defensive, for the editor first, and quotes no key material. What it found, in summary: the cryptography is standard and comes from the platform's own library, with no home-made primitives; one finding is rated medium and the rest low or for information. The medium one is a command that prints a session's private keys in the clear when no passphrase is set, so that one run would put them in the session's transcript; the Cold-Read team's security member found it first, and this review confirmed it (chapter 11). Nobody on either team ran it. Several findings are worth a reader's attention for what they say about where the real controls were. Private halves are stored unencrypted, in a locked-down folder, when no passphrase is set, and none was set in the team's sessions: so the control protecting a member's private key was the session's container, not the tool. The standing an operator grants an agent has a short default, but a link may name any end date: so the short life is a default, not a limit. And the reviewer narrowed or withdrew some of its own earlier findings as it read further, which is what a review should do and what a hash cannot. By its tenth wake it had read every command.

The verdict for the book is careful. Trust by hash and by author was not misplaced on the day: nothing the review found would have changed what the team did. But that was the author's care, not a control. A team that pins a tool should also schedule the reading, and on this team the person scheduled to read it never arrived.

The team on its own slide

At 17:30, with the talk a little over an hour away, the editor said in the conductor's session: "we actually have a really nice Agent Behaviour policy in action on this project right? Since I've been approving the policies for the agents as they are onboarded, which look really good. We should have that (and those pages that I'm using to approve the policy) shown in that section about ABP and RiskMandate" (team/conductor/briefs/2026-10-29__editor/8-our-own-abps-1730.md, 7c91afc).

The conductor's brief that carried it set two rules for the slides: show exactly how many policies were agreed on the record, and "never show a draft as approved". It also put the scope check's own sentence at the centre: "Said honestly (the code's own comment in admin/build/agents.py): a scope is a setting, not a boundary." Studio built three short pieces between 17:47 and 18:11: ruv-sgit's review page with its verdict (bd3cdad, 17:47); ruv-sgit's policy in prose beside its JSON, and one of studio's own wake records with its five verdicts, its side text quoting the scope check's limit (95b09d9, 18:11). Deck placed them in the talk's second part, after the ABP beat: s-port-abp worked the idea through, and s-port-abp-review said "these are this team's own behaviour policies, reviewed". Its cue, at the end of the day, still read "not yet reviewed by deck".

Studio's pieces on the team's own policies: a policy in prose beside its JSON, and a wake's five steps (18:11)

What this did to the argument is worth stating. The talk's claim was that agents are the ultimate insider and that the answer is a written mandate, measured against reach, with every barrier typed honestly. The team on stage was its own example, and the example included the admission that its central check was a setting. A talk that showed only the strengths of its own controls would have been an advertisement. One that showed the weakness, in the tool's own words, was evidence.

The failure kept

The control register keeps one open question against this control (C1 in controls/): the scope check reports, it does not refuse, and it cannot see a member widen its own scope. Everything above bears it out. The policies were real, specific and mostly signed. The check that tested a member's work against its policy was written well, used at every wake and honest about itself. And it was a report, run by the member, on the member, from a file the member could edit, counting only the commits the member remembered to mark. On a benign team that is enough: the record shows it catching mistakes and prompting the right questions, and the reviews and the editor's word filling the rest of the gap. Against a member that had been steered (by something it read, by a bad instruction, by its own enthusiasm) it would have caught nothing that the member did not choose to show it.

The pinned key tool is the same failure in a different form. The hash was a setting that worked; the reading that would have made it a review was assigned to a role nobody filled.

Neither failure is hidden. Both were written down by the team, in the tools themselves and in the readme, on the day. That is the most useful thing the chapter has to offer a reader building their own: write the mandate twice, once for the person and once for the check; type every row of the gap as what it is, and do not call a report a control; bind the agreement to the text it agrees; and if a tool is trusted by its hash, put the reading of it on someone's list who exists. What would turn the setting into a boundary (a check the member cannot edit, run where the member's credential does not reach) is the work chapter 9 and chapter 12 take up.

Where this came from

previous next