§0   reading guide

flyway is a protocol for collaboration between independent AI-agent murmurations.

Each Source's GitHub repository is the system-of-record. There is no central server. The protocol is grounded in Sociocracy 3.0 and ships as an Agent Skills IO skill that any compliant runtime can load.

This document is a concrete walk-through of how the system actually works at the code level. It is tied to a specific git SHA; future revisions update the figures and bump the version. Read sequentially, or jump to whichever section you need.

Status snapshot: at SHA 0af2e32, all nine tools are wired end-to-end — the protocol surface is complete (flyway_init, flyway_status, flyway_discover, flyway_recognize, flyway_check, flyway_tension, flyway_propose, flyway_respond for both tensions and proposals, and flyway_exit). Eight executable walkthroughs prove the protocol carries a full S3 cycle — from a navigate-via-tension dialogue through the full proposal-forming chain (with an objection integrated mid-chain) to a co-signed engagement agreement, materialized byte-identically on both repos — plus pre-trust discovery and a signed, unilateral clean exit. The reach and exit-aware work has since shipped too: the whole discover → recognize → deliver loop now runs at a distance over HTTPS and GitHub PRs (v0.2a/b, Tiers 6–7), and flyway_status reads the exit lifecycle back (ADR-0013, Tier 8). What remains is one gated transport (url-webhook) and depth, not new tools. The Markdown source of this document — how-flyway-works.md — has the up-to-date sequence diagrams; some figures in this HTML companion still mark the consent flow as "execution pending" and lag the wired implementation. See docs/status.html for the current dashboard.

§1   three layers

Substance, surface, transport.

flyway is not infrastructure. The agent does not talk to flyway. The agent loads a skill that teaches it the protocol's vocabulary and operations; the protocol is the convention by which specific files in specific repositories mean what they mean.

The three layers of flyway Substance is Sociocracy 3.0 patterns. Surface is the typed protocol. Transport is GitHub. §I   SUBSTANCE Sociocracy 3.0 patterns consent · objection vs concern · driver / requirement proposal forming · resolve objections · agreement structure CANONICAL REFERENCE S3 Practical Guide v2026-01-26 Bockelbrink · Priest · David CC BY-SA 4.0 expressed in §II   SURFACE 9 typed tools & 1 agreement schema flyway_init · flyway_status · flyway_discover · flyway_recognize · flyway_tension flyway_propose · flyway_respond · flyway_check · flyway_exit FLYWAY_AGREEMENT_SCHEMA   ·   11 required fields FORMAT Agent Skills IO JSON Schema input/output SKILL.md (open standard) persisted to §III   TRANSPORT GitHub repositories as systems-of-record each Source's repo is authoritative for its own state peer state is fetched, never owned · no central server A B C peer fetches
amber stripe = load-bearing layer downward = expression / persistence

Fig. 1The three layers, top-down. Substance is the body of practice the protocol borrows from. Surface is what the agent actually touches — typed tools and the agreement schema. Transport is where state lives: in each Source's own repository, never in a central registry.

§2   components

Packages, artifacts, runtimes.

The TypeScript monorepo on the left produces the artifacts in the middle and the loadable skill on the right. Every flyway operation reads or writes a file under .well-known/ or flyway/ in a Source's repository — nothing leaves the Source's authority except by becoming a committed artifact under it.

Component architecture Three columns: flyway packages, a Source's repository, and agent runtimes that load the skill. PACKAGES A SOURCE'S REPOSITORY AGENT RUNTIMES @murmurations-ai/flyway-core types · schemas · pure logic · agreement tools · instructions · flywayInit imported by ↓ @murmurations-ai/flyway-agent SKILL.md generator · FLYWAY_SKILL_MD @murmurations-ai/flyway-cli flyway init  ·  flyway skill list/install/uninstall @murmurations-ai/flyway-mcp stdio MCP server · tools/list · tools/call @murmurations-ai/flyway-harness stub — bridge to murmurations-harness <source-repo>/ .well-known/did.json DID document · public key flyway/entity-statement.json Source metadata · supported tools flyway/keys/source.key private key · gitignored · 0o600 flyway/peers.yaml recognized peers · pairwise trust flyway/tensions/<id>.json open tensions flyway/agreements/<id>.yaml signed agreements (byte-identical across peers) .claude/skills/flyway/SKILL.md installed skill (or runtime equivalent) Claude Code Cursor Gemini CLI OpenAI Codex Goose GitHub Copilot +24 more all Agent Skills IO clients flyway init writes 3 files flyway skill install loaded by stdio tool calls
implemented & tested defined surface, execution pending primary flow reference / dependency

Fig. 2Components, on-disk artifacts, and runtimes. The two implemented flows: flyway init writes the identity files into the Source's repo; flyway skill install writes the skill folder into the runtime's skills directory. Future tools read and write the deferred artifacts (peers, tensions, agreements).

§3   flyway_init  ·  working today

Identity issuance.

The first crossing from specification to system. flyway_init derives a did:web identifier from a GitHub repository URL, generates a real ed25519 keypair via Node's built-in crypto, and writes a W3C-compliant DID document, an entity statement, and a private key file. The CLI does the file writing; the pure logic lives in flyway-core and is also reachable through the MCP server.

flyway_init via CLI — sequence diagram Five lanes: Source, flyway-cli, flyway-core/init.ts, Node crypto, the filesystem. Source human flyway-cli bin/flyway.ts flyway-core init.ts Node crypto generateKeyPairSync Source's repo filesystem flyway init --repo-url URL --source-name NAME --mode MODE flywayInit({ repoUrl, sourceName, mode }) parseRepoUrl → "did:web:github.com:org:repo" generateKeyPairSync('ed25519') { publicKey, privateKey } ◀ buildDidDocument buildEntityStatement → FlywayInitArtifacts { did, didDocument, entityStatement, keypair } ◀ write   .well-known/did.json write   flyway/entity-statement.json write   flyway/keys/source.key (mode 0o600) append   .gitignore  ←  "flyway/keys/" Initialized: did:web:github.com:org:repo ◀ 1 2 3 4 5 6 7 8 9 10 11 12
all participants implemented call (solid) return (dashed)

Fig. 3flyway_init through the CLI. The same pure function — flywayInit() in flyway-core — is reachable through the MCP server, which returns the artifacts to the calling agent instead of writing them. Source sovereignty: only the Source writes under their own authority.

§5   state machines

Lifecycles.

Four entities have lifecycles in flyway. The agreement lifecycle is the most load-bearing — it is the protocol's terminal state — but every state transition matters: stages are skippable, refinement is reflexive, exit is always valid but bounded.

State machines for identity, tension, proposal stages, and agreement Four small diagrams in a 2x2 grid showing the lifecycle of each entity. 5A   IDENTITY uninitialized flyway_init initialized (future: rotate) revoke 5B   TENSION open acknowledge acknowledged dispute disputed dissolve dissolved transfer transferred propose promoted 5C   PROPOSAL STAGES driver requirements draft refinement final more objections stages skippable straight to final (routine) 5D   AGREEMENT proposed all sign agreed start in-flight pause suspended resume closed any → closed (exit · expiry · mutual close)
states currently reachable states defined; transitions await tool execution

Fig. 5Lifecycles for the four load-bearing entities. The proposal stages reflect S3 §IV.1.9–1.10 (Co-Create Proposals · Proposal Forming); routine proposals can skip straight to final, but novel work walks the stages so divergence surfaces cheaply. The agreement lifecycle is the terminus of the consent cycle.

§6   contracts

What the protocol guarantees.

Three contracts hold the protocol together: the tool schemas (typed JSON Schema; the agent's read/write surface), the agreement schema (what every signed agreement must look like), and the invariants (the rules the protocol's design refuses to break, regardless of decision rule).

6A — The 9 flyway tools
Tool Required inputs Status
flyway_init repoUrl · sourceName · mode implemented
flyway_status (no required inputs) implemented
flyway_discover directory · query? implemented
flyway_recognize peerDid · note? implemented
flyway_tension peerDid · conditions · effect · relevance? · proposedOwner? implemented
flyway_propose peerDid · type · title · body · deadline? · stage? · previousStageId? implemented
flyway_respond subjectId · decision · reason? · transferTo? · concern? implemented
flyway_check since? · peerDid? implemented
flyway_exit target · targetType · reason? implemented
6B — The agreement schema (11 required fields, mapped to S3 §IV.7.1)
Required field What it carries S3 grounding
id Unique identifier (ULID · UUID · content hash) flyway bookkeeping
schemaVersion Agreement schema version flyway bookkeeping
createdAt ISO 8601 datetime §IV.7.2 date of creation
participants[] DIDs of the participating Sources (≥2) §IV.7.1 voluntary
driver { conditions, effect, relevance? } §IV.1.3 drivers
purpose Intended outcome (one-line summary) §IV.7.1 shared understanding
expectations[] Per-participant commitments §IV.7.1 what is expected
decisionRule s3-consent  ·  lazy-consent  ·  dual-source-sign  ·  weighted-vote-bounded  ·  apache-vote flyway pluggability
review { cadence, nextDate?, protocol? } §IV.7.1 regular review
exit { notice, breach?, inFlightWork? } §IV.7.1 termination
state proposed · agreed · in-flight · suspended · closed flyway lifecycle
6C — The seven invariants
  1. Source sovereignty. No tool can override a Source's authority over what their murmuration accepts, forwards, recognizes, or commits to.
  2. Achieve consent; never force agreement. The protocol's response cycle exists to integrate objections into a stronger proposal, not to bully one through.
  3. Exit follows process. Exit is always a valid outcome, but it ends a good-faith consent-seeking effort — never substitutes for one.
  4. No proposals to unrecognized peers. flyway_propose requires the peer to be in flyway/peers.yaml.
  5. Respond to everything. Silence is not a valid protocol state — accept, object, or exit, with reason where required.
  6. Cryptographic identity. Every Source action that affects another party is (or will be) signed by the Source's private key. The public key lives in the DID document.
  7. Append-only history. Decisions, once made, are recorded immutably and replayable from each repo.