The company protocol
A Structure company is a git repository. Everything Structure knows about it is written into that repository as plain files and plain commits, in the conventions on this page. Nothing here needs Structure to read: a text editor shows the documents, and git log shows the decisions.
This is protocol 9.
The number is the document format the registry speaks (the same number a company names in schema: min-app:). It is bumped in the same commit that widens what a document may say, so a company that relies on something newer can say so, and an older build stops and says it cannot read the company instead of reading it wrong.
The rule that sorts every convention below: facts about the document go in the file, and facts about the change go in the commit. A document's type and standing live in its own frontmatter, where they travel with it. Who approved a change, which door it came through, what it did to a document's standing and which run made it live in the commit's trailers, where git log can answer without opening a diff.
Typed frontmatter and the types
A governed document is a markdown file whose first lines are a YAML block between two --- lines. The block says what the document is, and the check holds the document to what its type requires.
---
type: canon
standing: active
owner: human/miranda
updated: 2026-10-18
---
Every type shares these fields: type, standing (with the older status still read in its place), owner, updated as YYYY-MM-DD, and emit, which opts a document's body into the files agent tools read. Each type adds what it needs: a person carries actor: human/<handle>, and a document a process requires at its close carries owner, updated, run-id and process.
The path usually says the type, so most documents never have to; a type marked "declared by hand" below is only ever named in the frontmatter. The types this build knows:
| Type | What it is, and where it lives |
|---|---|
navigation | orientation: READMEs and the root harness files; never canon |
mission | what a department or product is for; departments/<name>/mission.md, products/<name>/mission.md |
person | a person on the roster; company/people/ |
roadmap | the ordered commitment for a scope; roadmap.md at the company, department, product or project root |
connector | a provider the company uses: who owns it, its cap, its key name; company/connectors/ |
mcp-server | an MCP server the company runs on: how it starts, the connector whose key it uses; company/tools/ |
canon | who we are and how we work; company/, and steering documents at department roots |
work | a deliverable moving through its function's lifecycle; departments/<name>/work/<stage>/ |
record | what a department did, kept for custody; departments/<name>/records/ |
routine | a standing order that runs on a trigger; departments/<name>/routines/, products/<name>/routines/ |
process | a repeatable operating standard; departments/<name>/processes/, products/<name>/processes/ |
cascade | a staged plan that walks departments; cascades/ |
role | an approach to compose work under; roles/ |
skill | a repeatable way of doing one kind of work; skills/<slug>/SKILL.md |
objective | a stated outcome with a horizon; objectives/ |
spec | what a project or product is building; projects/<name>/spec.md, products/<name>/spec.md |
guide | user-facing product documentation; docs/guide/ |
project | a project's own documents; projects/ |
checkpoint | saved work state another session can resume; memory/checkpoints/ |
signal | an observation kept for the record; memory/signals/ |
answer | a dated snapshot answering a one-off question; memory/answers/ |
change-review | a review of a shipped change after it landed; lives with its product, declared by hand |
content-package | one edition's copyable assets for posting; declared by hand |
publication-record | what was posted where, or why it was held; declared by hand |
release-report | what a release run did; memory/checkpoints/, declared by hand |
improvement-decision | what a run taught, classified; memory/checkpoints/, declared by hand |
batch-intake | typed residue handed to the next batch; memory/checkpoints/, declared by hand |
adr | an architecture decision record; products/<name>/docs/adr/ |
product-doc | a product's internal documents; products/<name>/ |
artifact | a storyboard, report, gallery or wireframe set, one package with its pages and assets; artifact.md at the package root |
The canon a company starts with is named by path: company/mission.md, company/values.md and company/positioning.md are expected, and company/vision.md and company/story.md are welcome.
A company's policy file is structure.yml at the root. It says who approves what (the gating: block, by path and by type) and, when the company needs a newer format, schema: min-app: <n>.
Standing
standing is about authority, never about work. It has four values:
draft: not yet. The document is written but does not speak for the company.active: yes. The document speaks for the company now.deprecated: no. It stays for history and no longer speaks.superseded: no, and another document speaks instead.
A person's document adds departed, which keeps the document (so history stays attributable to them) while they leave the roster's addressing.
On a work document and a checkpoint, status is a lifecycle stage (drafts, published, in-progress, done) and never a standing, so the two answer different questions and can sit side by side.
Approving a draft of a canon, mission, roadmap or process document rewrites one line, standing: draft to standing: active, and brings updated to the day, inside the signed commit.
The trailers
Trailers are the Key: value lines in the last paragraph of a commit message, the block git log --format='%(trailers)' prints. Structure writes these:
| Trailer | Written on | Says |
|---|---|---|
Approved-by: <actor> | every approval | who approved; a person's signature |
Actor: <actor> (via <door>) | every commit Structure writes | who made the change, and through which door |
Proposal-id: <id> | the merge of an approval request | which request this merge landed |
Approved-paths: <path> | the merge of an approval request | one line per gated path the approval covers; /none when it covered none |
Checks: <E> errors, <W> warnings | the merge, when a check ran | the check's verdict at the moment of approval |
Closes-work: <slug> | the merge that lands the last of a work | the work this approval finishes |
From-thread: <thread> | the merge of a request filed from a thread | where the request came from |
From-checkpoint: <path> | the merge, when the approver was shown a checkpoint | the handoff this landing picked up |
Work: <slug> | the first commit of an approval request filed from a work | the work the request belongs to |
Replaces: <path> <= <removed> | the first commit of an approval request | which new document stands in for which removed one |
Standing: <path> <from> -> <to> | an approval that moves a document's standing | the transition, one line per document |
Run: <invocation id> | the commits a process run writes | the run the change came from |
Compiled-by: structure (the runstructure app) | the hosted check's own compile commit | that the hosted check, not a person, wrote it |
An actor is human/<handle> or agent/<name>. A value is one line: a writer refuses a value with a line break rather than let it start a second trailer.
The approval of one draft, from any door, is one subject and one block. With the standing it moved, it reads:
approve: company/values.md
Approved-by: human/miranda
Actor: human/miranda (via structure approve)
Standing: company/values.md draft -> active
Landing an edit in the room signs land: <title>, and confirming that a document is still current signs bless: <path> still current, each with the same Approved-by: and Actor: lines. A bless never moves a standing; a land writes Standing: when the document it lands was a draft, because landing it approves it.
The merge that lands an approval request writes its lines in this order, each optional line only when it is true:
approve: Values stand, and Sofia leaves
Proposal-id: <id>
From-thread: <thread>
From-checkpoint: memory/checkpoints/<name>.md
Closes-work: values-pass
Approved-by: human/miranda
Approved-paths: company/people/sofia.md
Approved-paths: company/values.md
Checks: 0 errors, 0 warnings
Actor: human/miranda (via structure approve)
Standing: company/people/sofia.md active -> departed
Standing: company/values.md draft -> active
On the merge, Standing: is read off the two sides of the landing, in path order like Approved-paths:: one line for every document whose standing differs between main before the approval and the tree the approval lands. A document that arrives or is removed has no transition and gets no line, and neither does the founding commit that creates a company, whose documents arrive already approved. On the approval of one draft, the door writes the line because it knows the transition it made, which is always draft -> active.
Standing: and Run: ride after Actor:, and only when the commit knows them. A commit that knows neither is byte for byte the commit it was before they existed.
Only Approved-by:, together with the gate that checks Approved-paths: against what the landing changed, is authority. Every other trailer is a record: Standing: says what an approval did and never grants one, and an agent never writes Approved-by: itself. The older spelling Ratified-by: is still read as an approval in history written before the rename.
The commit structure compile --commit writes says what it regenerated and who ran it, and carries no Compiled-by::
compile: regenerate agent dialects (AGENTS.md, CLAUDE.md)
Actor: human/sofia (via structure compile)
The hosted check (the GitHub App installed on a company's repository) compiles on push and writes the same subject, with itself as the actor, the check's verdict, and Compiled-by: last, which is how it knows never to compile its own commit again:
compile: regenerate agent dialects (AGENTS.md)
Actor: app/runstructure (via check on push)
Checks: 0 errors, 1 warnings (structure/check run 42)
Compiled-by: structure (the runstructure app)
So git log answers the questions a company asks of its history without a diff:
git log -1 --format='%h %cI' --grep='^Standing: company/values.md draft -> active' # when values went active
git log --format='%h %(trailers:key=Run,valueonly)' -- company/ # which run made each change
git log --format='%h %(trailers:key=Approved-by,valueonly)' -- company/values.md # who approved each version
The branches
An approval request is a branch, overbot/proposals/<id>, cut from main with the change on it. Approving it merges it into main with the block above and retires the branch, so the merge's Proposal-id: is what still names the request afterwards.
These names, and the run refs below, still carry the product's earlier name. Renaming them is a migration that has not been ruled, so this page spells them exactly as git carries them. Moving a company to the new names lists which names moved and which did not.
passes: on a compiled document
A document compiled through a skill pass records each pass in its own frontmatter: which skill at which version, the day of the pass (never the day of a later compile), and which fields it rewrote.
passes:
- skill: "the-humanizer@<version>"
on: "2026-10-18"
note: "fields: one-liner, problem"
When a pack's compiled document carries passes: and no field was passed, it says passes: []. A pack names the skills its compiled documents pass through; the record of what actually ran is the document's own passes:, because the pass is a fact about the document.
The work record and its branch
A piece of work is a branch with a record. The branch is work/<handle>/<slug>, where the handle is the part of the owner after the /. The record is a typed document at .structure/work/<slug>.md, and its schema is strict: a field the schema does not name makes the record malformed.
---
type: work
title: Rewrite the onboarding page
owner: human/miranda
kind: task
state: open
base: "1a2b3c4d"
opened: 2026-10-18T09:00:00Z
harness: claude-code
---
kind is task or batch. state is open, put-aside or closed, and a closed record adds closed: as an ISO 8601 instant. base is the commit the branch was cut from, quoted so a sha of digits stays a string. A batch adds lanes:, each lane with an id, an optional branch and its own state. The structure work verbs commit the record with Actor: <actor> (via structure work <verb>), and Working on a company walks through them.
The marker line on compiled files
Every file structure compile writes carries one marker line that says it is generated, what to edit instead, which build wrote it, and a checksum of the file. Shortened here, where the middle sentence names the file that is yours to edit:
<!-- Generated by `structure compile` from this repo's canon. (what to edit instead) Written by build 2026-10-17. Checksum 1a2b3c4d5e6f7a8b (this file without this line). -->
The checksum is the first 16 hex characters of the SHA-256 of the file without its marker line, with CRLF read as LF. A file whose body no longer matches its checksum was edited by hand, which structure check reports. The build stamp and the checksum are never part of what makes two compiled files the same, so a new build is not a change. In a markdown file the line is an HTML comment; in a shell or YAML file it is a # comment; in a JSON file it is the "$structure" key's value. Agent dialects lists every file the compile writes.
Experimental: the run refs and the batch record
A process run is recorded outside the branches, under refs/overbot/process-runs/<digest>, where the digest is the SHA-256 hex of the run's invocation id. Each record is a commit whose tree holds record.json and the artifacts the run kept as artifact-0000, artifact-0001 and so on. The first commit's subject is start process run <id>, each later one's is record process run <id>, and both carry Run: <id>. The questions a run asked are kept beside it under refs/overbot/process-asks/<digest>. Both travel with the repository: Structure pushes them as git push origin <ref>:<ref> beside the branches.
A batch is a work of kind: batch, and its run is a process run like any other. Closing a batch checks that the record branch and both of its refs are on the remote before it deletes anything.
This part of the protocol is still moving: the batch verbs are experimental in the public build, and these shapes may change before they are public.
Any host
A company on any git host is a Structure company in full: every convention on this page lives in the repository, and nothing about the company is kept only somewhere else. When Structure hosts a company's repository, the index it derives from that repository is the private half, rebuilt from git and never the record.