Mutual recognition
A and B independently produce identities. Each verifies the other's entity statement and writes a signed recognition entry to its own peer cache.
Two independent murmurations can discover each other, establish
mutual recognition, run a full S3 proposal-forming cycle,
co-sign an engagement agreement — each side independently materializing a
byte-identical agreement file — exit cleanly, and now
read the exit lifecycle back: one flyway_status
shows which relationships and agreements are effectively closed, the co-signed file never rewritten.
With v0.2 the whole discover → recognize → deliver loop runs at a genuine distance —
over HTTPS and GitHub PRs, no shared filesystem. Cryptographic verification on both sides throughout.
The nine tools form the canonical surface of the protocol, and all nine are now wired —
discover, identity, recognition,
send, read, respond, propose,
and exit. Beyond the nine wire tools,
flyway materialize turns an accepted final-stage agreement proposal into the
co-signed agreements/<id>.yaml — a local act over records both sides already
hold, not a protocol signal.
| # | Tool | Purpose | Status | Demo |
|---|---|---|---|---|
| 01 | flyway_init | Initialize identity — DID + signed entity statement + Ed25519 keypair. | wired | Tier 1 |
| 02 | flyway_status | Report identity, peers, agreements, signature validity — and effective exit state: relationships / agreements closed by a verified exit (ADR-0013). | wired | Tier 8 |
| 03 | flyway_discover | Search a flyway directory for potential peers — pre-trust; you verify at recognition. Loads a local file or an https:// URL. |
wired | Tier 6 |
| 04 | flyway_recognize | Verify a peer's identity and write a signed recognition entry — locally or from its did:web URL. (Plus unrecognize.) |
wired | Tier 6 |
| 05 | flyway_tension | Flag a tension to a recognized peer (S3 Navigate via Tension). | wired | Tier 2 |
| 06 | flyway_propose | Send a directive, project, or engagement agreement; full S3 staging chain. | wired | Tier 4 |
| 07 | flyway_respond | Respond to a tension (acknowledge / dispute / dissolve / transfer) or a proposal (accept / object / exit). | wired | Tier 4 |
| 08 | flyway_check | Read incoming flyway signals; verify signatures and flag issues. | wired | Tier 2 |
| 09 | flyway_exit | Cleanly leave a peer relationship, project, or syndicate — signed, unilateral, always valid. | wired | smoke |
Each milestone lands one capability and one walkthrough that proves it. The top track is the surface era — a defined protocol, through identity and recognition, into a verified round-trip, a co-signed agreement, clean exit, and discovery (all nine tools). The bottom track is the v0.2 reach era — the same loop lifted off the shared filesystem: agreement provenance, then discover, recognize, and deliver over HTTPS and GitHub PRs.
A walkthrough is an end-to-end script run against the real CLI and MCP server, not a contrived test. Each tier proves a strictly larger surface than the last and produces signed artifacts inspectable after the run.
A and B independently produce identities. Each verifies the other's entity statement and writes a signed recognition entry to its own peer cache.
A signs a tension envelope; the local-fs transport delivers it into B's inbox; B's
flyway_check
independently verifies the signature against its cached copy of A's key.
B reads A's tension, verifies, and signs back — acknowledge / dispute / dissolve / transfer. A verifies and reads the response. Both sides hold complete signed records that reconcile without shared state.
A proposes a final-stage agreement; B co-signs by accepting. Each side independently
materializes a byte-identical
agreements/<id>.yaml
from records it already holds — matching SHA-256, no authoritative copy.
A tension runs the full driver → requirements → draft → refinement → final chain. B objects at the draft — the work is one-sided — and A's refinement integrates it: an expectation moves from one Source to the other, and that split lands in the co-signed agreement.
A peer is discovered from a remote HTTPS directory and recognized from its
did:web
URL — no shared filesystem. The remotely-fetched identity is still verified at recognition,
never trusted by transport.
A signal is delivered by opening a pull request against the peer's repo — fork-first, no write access to their tree; the recipient merges to accept. Completes the discover → recognize → deliver loop with no shared filesystem; PR-delivered bytes are byte-identical to local-fs.
An exited relationship and an agreement closed by a project exit both read as closed from a
single flyway_status
— the co-signed file never rewritten. A 4-agent review then hardened the inbox-exit trust
gate against replay before merge.
flyway skill install.
did:web:github.com:owner:repo → raw identity artifacts; verified at recognition.
projectId/syndicateId.
All nine tools have landed (through flyway_discover, S+7), and v0.2 has carried the
whole loop off the shared filesystem — v0.2a (HTTPS directory fetch + transport
seam), recognize-at-a-distance (ADR-0011), and v0.2b (github-pr
transport, ADR-0012) are all shipped. What remains is depth and one gated transport:
flyway_status reads the exit lifecycle back — a relationship or agreement closed
by a verified exit reports as effectively closed, the co-signed file never rewritten.
originTensionId propagates through the staging chain and is auto-stamped onto the
co-signed agreement under both signatures; a forged link is refused.
Nine open issues (12 closed, including #2 at S+8 and the season-wrap batch #16 / #17 / #20). All open items are depth or design questions — none security. Numbers link to GitHub.
Every line below names a property a reviewer can audit by reading a single function
in flyway-core. Adapters cannot weaken these — that's the whole point of
ADR-0009.
| Property | Enforced at | Verified at |
|---|---|---|
| Self-attestation | flywayInit |
flywayStatus, recognizePeer |
| Peer attestation | recognizePeer |
verifyRecognitionEntry, flywayStatus |
| Domain separation | signArtifactInline |
verifyInlineSignedArtifact |
| Canonicalization | canonicalize |
canonicalize (deterministic) |
| Tamper detection | every signer | every verifier |
| Cross-kind replay protection | buildSignedSignal |
verifySignedSignal |
| Antecedent verification (ADR-0009) | createTensionResponse (core) |
enforced at sign time |
| Co-signature byte-identity | signAgreement (detached) |
materializeAgreement (SHA-256 match) |
| Agreement provenance (#2) | createProposal (auto-stamp at final) |
carried under both co-signatures |
| SSRF guard (v0.2) | assertPublicHttpsUrl |
per-hop, before each network call |
| Pre-trust remote resolution | resolvePeerIdentity (pre-trust) |
recognizePeer (sig + key binding) |
| Path-traversal safety | peerCachePathSegments |
enforced at parse time |
| Recognition-window ordering | flywayCheck |
flywayCheck |
| Exit-honor gate (ADR-0013) | honorInboxExit / honorOutboxExit |
placement + recipient + verify, before an exit informs state |
| Atomic write | writeSignalFile (flag: 'wx') |
enforced at write time |
If you have half an hour to decide whether flyway is worth adopting, read these four artifacts in order.
Framing and tool surface. What flyway is.
Concrete sequence diagrams and contracts.
The single most informative artifact in the repo — consent through to a co-signed agreement.
Flavor of how invariants get captured.