Skip to main content

FK YH — The VBI for AI Agents

An open protocol for agent discovery, coordination, observability, and independently verifiable attestations. Piggybacks on existing protocol fields (mDNS, HTTP headers, Prometheus). No new infrastructure.

FK YH is this protocol's name. The name is not expanded here — this specification claims no expansion for it.

VBI is the "vertical blanking interval" — the unused scanlines the BBC filled with Ceefax data in the 1970s. FK YH is the same trick for agents: the data rides in fields the protocols already have. SPEC.md §1.2 explains the analogy properly.

What FK YH is for. An agent publishes what it is doing in HTTP headers and on the local network. A third party — one who has never seen the agent and need not trust it — can check a signed statement about whether the work actually happened.

The answer is three-valued, and it is honest about its own uncertainty:

Outcome Meaning May the consumer act?
verified the evidence positively confirms the expected outcome under policy_id yes
failed the evidence contradicts the expected outcome no
inconclusive the evidence is missing, stale, inaccessible, or insufficient to reach a defensible conclusion no

Only verified is actionable. An authentic failed or inconclusive is still an authentic statement: authenticity and success are different facts, and the protocol reports them separately (ATTESTATION.md §5).

Where the project is (2026-10-22). The protocol and the attestation specification are v0.1. This repository is private while the protocol is being finalised. The LAM is private — staged for public release, and not published by this release. The suite collects 717 tests: 712 pass, 5 skip on macOS with the test extra installed. The last CI run on this branch was green in every job — seven job entries, because the Python package job runs the whole suite on both 3.11 and 3.12.

What this repository is not

Up front, because a trust protocol that overstates itself is worse than no protocol at all.

  • It does not prove that the underlying claim is true. A signature proves provenance and integrity — that this statement, from this key, has not been altered. Whether the world actually matches the statement needs reliable evidence, a sound method and explicit assumptions (ATTESTATION.md §9). A verifier that signs a false conclusion is indistinguishable, by design, from one that signs a true one.
  • It is not a status protocol. verified, failed and inconclusive are three distinct facts. "Authentic" and "successful" must never be collapsed into one another.
  • It is not implemented end to end. x402 payments (§6) are specified, not implemented, by decision — there is no x402 code here and nothing has been settled on chain. The 5-stage guarded executor is the reference implementation's, not the protocol's, and the Python half of it is not in this repository.
  • It does not make discovery trustworthy. mDNS advertisement is unauthenticated by design (SPEC.md §8.1). A deployment that needs authenticated discovery has to add it.
  • It has not been implemented by an outsider. The three consumers below are all by the same author. That proves the protocol interoperates across languages; it does not prove an outsider can implement it from the document alone. That test has not been run.

Why

The current generation of agents conflate saying success with being successful. They log "done" without independently checking the post-state. The attestation layer is the part of FK YH that addresses this: a verification result becomes a portable, signed statement that a third party — one who has never seen the agent or the verifier's code — can check for themselves.

The 5-stage guarded executor that produces those results belongs to the reference implementation, not to the protocol.

This repository

SPEC.md the protocol, 15 sections
ATTESTATION.md the attestation protocol, v0.1 (normative)
STATUS.md what is actually implemented, tested, partial, or absent
PLAN.md the build plan this repository was built to
CONTRIBUTING.md how to contribute, and how to run the suite
SECURITY.md how to report a security problem
pyproject.toml the package metadata: Python 3.11 or newer, cryptography as an optional extra (pip install -e '.[signing]')
fkyh/ the reference implementation — standard library only. Every module is listed under The fkyh package.
fkyh/signing.py optional signed gossip headers (§4.4) — cryptography stays optional
fkyh/keys.py the key store: keys on disk, revocation, rotation, trust configuration
fkyh/servicetype.py the RFC 6335 service-type naming rules, the derived types and the profile registry (§3.1)
tests/ the test suite, including a spec-conformance test
fixtures/attestations/ signed conformance fixtures + manifest
examples/fk-yh-node/ a runnable node: announce, answer, measure, prove
examples/independent-consumer/ a second consumer, in Python, written from the spec alone — by the same author as the implementation; see the disclosure below
examples/attestation-consumer-go/ a third consumer, in Go, written from the spec alone — also by the same author
examples/go-reference/ the Go executor implementation, and the cross-language oracle
examples/grafana/ the reference Grafana dashboard, with the provisioning that loads it
contracts/fkyh-registry/ an optional on-chain agent registry (Soroban) — §8.3. Verifies Ed25519 on chain, so a §4.4 signature can be checked against a registered key. Optional: no registry is required, and a node using none is conformant.
fixtures/x402/, fixtures/stellar/, fixtures/jcs/, fixtures/rfc/ the vendored oracles the pins are checked against, with SHA-256s in fixtures/ORACLES.json — the x402 and Stellar specifications, the RFC 8785 (JCS) reference test vectors, and the RFC texts themselves

The reference implementation, and one thing that will surprise you

The reference implementation — the LAM — is a separate repository, and it is private — staged for public release, and not published by this release: github.com/cyber-bollox/lam. There is no public URL for the LAM yet, and no document in this repository prints a clickable link that 404s: ask for access to the LAM and you will be given a URL that works. (This repository — FK YH — is private too; see Get started.)

The LAM adds a 5-stage guarded execution pipeline (Prepare → Authorize → Execute → Verify → Commit), per-action independent verifiers, layered memory, pattern discovery, and a self-evaluation harness. Those are properties of that implementation. The protocol does not specify them, so an implementer of FK YH is not required to build them.

The distinction matters: this repository is the specification, and a reference implementation of the parts that are specified. The executor surfaces are the LAM's, and the LAM is where the Python reference for the 5-stage guard lives.

⚠️ The browse commands in the specification return nothing against the reference implementation. SPEC.md §13.2 tells an operator to run dns-sd -B _fk-yh._tcp local to find agents on the network. Against the LAM those commands print nothing, and it is not your mistake:

  • the LAM advertises itself as _lamfax._tcp, not _fk-yh._tcp — it contains no occurrence of _fk-yh at all;
  • this repository's own reference node does advertise _fk-yh._tcp, so the browse command finds it while examples/hello-world.py or examples/fk-yh-node/run_demo.sh is running.

So: browse _fk-yh._tcp for FK YH agents, _lamfax._tcp for the LAM's own. The protocol's service type is _fk-yh._tcp (§3.1); the LAM had not adopted it when this was written.

Get started

Install the package:

# the library and the `fkyh` command
python3 -m pip install fkyh

# attestation signatures need `cryptography`, which is an optional
# extra on purpose: the library itself is standard-library only
python3 -m pip install 'fkyh[signing]'

The source repository (cyber-bollox/fk-yh) is private — the clone URL returns 404 for anyone who has not been invited, so ask for access to cyber-bollox/fk-yh if you want the tree, the audit reports, or the history.

You do not need the tree to use the package. pip install fkyh gives you the library and the fkyh command. The conformance corpus — the signed fixtures, the manifest, the oracles, and the suite that checks them — ships in the source distribution, so pip download --no-binary :all: fkyh gives you the corpus too.

Once you have the tree, everything below runs from the repository root with nothing else to install but two packages.

# Python 3.11 or newer — the floor pyproject.toml declares, and the
# version CI runs the suite on. 3.12 is the one most people have.
python3 --version

# the package, plus the test extra (which carries the optional
# prometheus_client and pyyaml the suite needs), plus the runner
python3 -m pip install -e '.[test]'
python3 -m pytest tests/ -q          # 717 tests collected, 712 pass, 5 skip

# the whole protocol, end to end
python3 examples/hello-world.py

# a second consumer, written from the specification alone
python3 examples/independent-consumer/run_conformance.py

Not installing anything? The package imports from the repository root as it stands — python3 -m pip install -e '.[test]' and run everything from this directory is enough.

What you should see:

  • pytest ends 712 passed, 5 skipped on macOS. Four of the skips are the live-mDNS tests: they need a real network and FKYH_AUDIT_LIVE=1, so they skip unless you ask for them. CI runs them — the macOS job has a step of its own with the variable set, because a pin that never runs cannot fail, and one of these four was found RED the first time it was actually executed (2026-10-22), still asserting the behaviour a fix had already removed. The fifth is the publication-truth pin, which stands down while this repository is private — the claim it polices ("this repository is private") would be true, and flagging it would be a lie. On Linux two more groups skip, because dns-sd is macOS-only. Nothing is hidden behind them, and the skip reasons are printed by the suite.
  • hello-world.py starts a node, advertises it on mDNS as _fk-yh._tcp.local, reads back its own headers and metrics, and then has a separate party validate its attestation — including a tampered copy, which is rejected with invalid_signature.
  • run_conformance.py ends 20/20 conformance checks passed — one per fixture in the manifest (18 of them), plus the two steps of the replay sequence.

The demo, and then the loop. examples/fk-yh-node/run_demo.sh starts a node and reads every surface it exposes. Its §8 line reads unavailable: HTTP Error 503, and that is correct: a node with no attestation supplied refuses to invent one, because it must not sign its own state. The demo says so itself, and points at the script that does exercise the path. For the whole loop — a separate program with its own key verifying the node and signing the result — run:

cd examples/fk-yh-node && ./run_independent_loop.sh

That prints verdict : ok / verified and trusted : True, and it is the demo worth reading: the node did not sign this, a separate party did.

Implement this: independent attestation consumer

The attestation specification is written to be implementable from the document alone. ATTESTATION.md is the normative text; fixtures/attestations/ is the conformance corpus.

With access to this repository, take two things and nothing else:

  • ATTESTATION.md — the specification
  • fixtures/attestations/ — the conformance fixture set

The point of the exercise is to build a consumer without reading the implementation, so take only those two things. The fixture set ships inside this repository, so it comes with the repository — there is no separate copy to fetch.

PROVE-IT.md is the full ask: what to build, what a report must contain, how to run each check, and what a pass means and what a failure means. A failure is as useful as a pass — it is a bug report against the specification, and it is wanted.

ls fixtures/attestations/

Read this before you start: the mode the corpus runs in

The corpus reaches every code §7.1 publishes (ATTESTATION.md §10.2): all 15, including revoked_verifier, unauthorised_policy, not_yet_valid, attempt_mismatch and the three evidence codes. A consumer that never emits revoked_verifier, never checks the attempt binding and never re-derives an evidence digest now fails the fixture set. The manifest is the authority: fixtures/attestations/manifest.json names the expected code for every fixture, and ATTESTATION.md §10.2 says the same thing in prose. To go from one error code to the fixture that exercises it, read fixtures/attestations/MANIFEST-COVERAGE.md.

It reaches them in a mode, and the mode is part of the contract. Give your consumer:

  • the published evidence directory, fixtures/attestations/evidence/ — so step 9 re-derives the digests instead of trusting the recorded ones. A consumer that cannot reach the evidence has nothing to refuse, and cannot reach evidence_missing, evidence_digest_mismatch or evidence_unreadable at all;
  • the task and the attempt the manifest records (task_id, attempt_id) — so steps 6 and 7 are checked;
  • a fresh replay store per fixture, and one shared within a sequence — §10.1 says why, and the published runners do it.

The published runner shows the whole shape:

python3 examples/independent-consumer/run_conformance.py

The fixtures, and what your consumer must return

Your consumer must produce the verdict recorded in manifest.json for every fixture:

Fixture Expected
valid-verified.json accepted, verified
valid-failed.json accepted, failed — accepted but not successful
valid-inconclusive.json accepted, inconclusive
evidence-no-digest.json accepted, inconclusive — the evidence record omits sha256
evidence-null-digest.json rejected — malformed — the evidence record carries "sha256": null
missing-signature.json rejected — missing_signature — the signature member is absent
tampered.json rejected — invalid_signature
unauthorized-verifier.json rejected — unknown_verifier
revoked-verifier.json rejected — revoked_verifier — signed by a key trust.json revokes
unauthorized-policy.json rejected — unauthorised_policy — signed by the trusted key, for a policy it may not attest under
expired.json rejected — expired
not-yet-valid.json rejected — not_yet_valid — issued_at is in the future
wrong-task.json rejected — task_mismatch
wrong-attempt.json rejected — attempt_mismatch — a valid attestation for another attempt
evidence-missing.json rejected — evidence_missing — the evidence file is not published
evidence-digest-mismatch.json rejected — evidence_digest_mismatch — the file's digest is not the recorded one
evidence-unreadable.json rejected — evidence_unreadable — the reference escapes the evidence root
unsupported-version.json rejected — unsupported_version

A rejection reports a code and no outcome; an acceptance reports ok and the attestation's own outcome. inconclusive is the verifier's statement, so a consumer never synthesises one for itself (ATTESTATION.md §5, §10.2).

Plus one sequence: present valid-verified.json twice to a consumer that keeps replay state. The second presentation must be rejected with replay. Replay is consumer state, not a property of the message — see ATTESTATION.md §8 and the sequences array in the manifest.

Plus one artifact: section-4-3-worked-example.json is the object ATTESTATION.md §4.3 publishes, so that the exact canonical bytes the specification prints are pinned against the code. It is not a verdict fixture, and the manifest lists it under artifacts.

The hard part is §4.1: the canonicalisation rule. Get it byte-identical and everything else follows. §4.1 now cites JCS (RFC 8785) and this repository implements it in fkyh/jcs.py, so the rule is a standard rather than a second copy of itself; the JCS reference test vectors are vendored under fixtures/jcs/ and the RFC texts under fixtures/rfc/, so the implementation is checked against the standard's own bytes.

Two details an implementer gets wrong easily:

  • the key id is derived, not chosen: key_id = "ed25519-" + hex(sha256(raw_public_key_bytes))[:16];
  • the trust configuration is a separate, signed-key material file (ATTESTATION.md §6), and a consumer MUST consult it before acting.

Three implementations, two languages, one author. The Go consumer is the one that matters: two Python implementations can share a misunderstanding and never find it, because they share a language, a JSON library and a set of habits. Go shares none of those.

All three were written by the same author, so this proves the protocol interoperates — it does not yet prove an outsider can implement it from the document alone. That test has not been run. See STATUS.md.

Implementation Language Score
fkyh/attestation.py Python 20/20
examples/independent-consumer/ Python 20/20
examples/attestation-consumer-go/ Go 20/20

The Go test suite pins the canonical payload as a hardcoded prefix — the bytes from {"alg":"ed25519", up to and including "verifier":{"key_id":". That is every field of the attestation except the key id's own value (the signature is not part of the canonical bytes at all). If the two languages ever disagree about key ordering, escaping or number formatting inside that prefix, it fails loudly rather than silently.

Running everything

python3 -m pip install -e '.[test]'

python3 -m pytest tests/ -q          # 717 tests collected, 712 pass, 5 skip
python3 examples/hello-world.py       # the protocol, end to end
cd examples/fk-yh-node && ./run_demo.sh
cd examples/fk-yh-node && ./run_independent_loop.sh   # the full attestation loop
python3 examples/independent-consumer/run_conformance.py

# the cross-language consumer
cd examples/attestation-consumer-go
go build -o /tmp/attestation-consumer .
/tmp/attestation-consumer --conformance ../../fixtures/attestations
go test ./...

The fkyh package

Module Spec What
fkyh/__init__.py — the package surface: PROTOCOL_VERSION and the state types
fkyh/state.py §4 agent and fleet state, and the response headers
fkyh/discovery.py §3 mDNS advertisement and browsing, TXT encoding
fkyh/servicetype.py §3.1 the service type, the RFC 6335 naming rules, the derived types, the profile registry
fkyh/metrics.py §5 Prometheus exposition, plus a parser for it
fkyh/gossip.py §7 the fleet scraper and the observer
fkyh/jcs.py ATTESTATION §4.1 JCS (RFC 8785) canonicalisation — the bytes that get signed
fkyh/signing.py §4.4 signed gossip headers — the canonical bytes, the signature header, the verdict vocabulary
fkyh/attestation.py ATTESTATION §7 the consumer side of the attestation protocol
fkyh/signer.py ATTESTATION the issuer side
fkyh/keys.py ATTESTATION §6, §4.4 the key store: keys on disk, revocation, rotation, trust configuration
fkyh/node.py — the HTTP service that serves all of it
fkyh/__main__.py — the command line: python3 -m fkyh keys create|show|revoke|rotate --keystore <dir>, and python3 -m fkyh verify --attestation <file> --trust <file>

Standard library only. cryptography is optional, and it is needed for two things: attestation signatures (fkyh/signer.py, fkyh/attestation.py) and signed gossip headers (§4.4 — fkyh/signing.py, fkyh/keys.py). A node that signs neither works without it. Nothing here imports the LAM — a test enforces it, because a protocol that is really specified by one implementation is not a protocol.

The fkyh package's own version and the protocol version are different things: fkyh.__version__ is the package version, and fkyh.state.PROTOCOL_VERSION is the protocol version — "0.1". The attestation envelope's schema_version is "0.1" as well (fkyh/attestation.py); a consumer MUST reject a version it does not understand rather than guess (ATTESTATION.md §11).

The spec-conformance test

tests/test_spec_conformance.py parses SPEC.md and ATTESTATION.md and asserts the code matches what they say: the header names, the metric names, the error-code vocabulary, the service type, the outcome set.

This is the test that keeps the protocol honest. It caught a real divergence — the two consumer implementations disagreed on eleven error codes, and the reference implementation did not match the spec's own list.

Status

v0.1 (draft). Sections 1–15 are written, and the attestation protocol v0.1 is specified with a published conformance fixture set.

The Python reference implementation of the 5-stage guarded executor lives in the LAM repository. The Go reference (examples/go-reference/) is the cross-language oracle for it. This repository cannot reach the LAM repository from CI, so what CI checks here is the oracle against the pinned contract in fixtures/executor/conformance.json — the same action set and the same expected stage, status and verifier outcome that the LAM's lam_conformance.py compares the two implementations against. Both sides are held to one document, and neither can drift from it silently.

x402 is specified but not implemented, by decision. See STATUS.md for the full honest picture, including the known limitations.

Contributing

Read CONTRIBUTING.md first. The short version: the suite is the gate — python3 -m pytest tests/ -q must be green — and a change to a specification document must be checked against the code, not merely written down. There are issue templates for a bug, a specification proposal and a conformance fixture. Security problems go to SECURITY.md, not to the public issue tracker.

Design partners

We are looking for teams building multi-agent systems, agent observability, or trust infrastructure who want to test independent verification against a real workflow. Open an issue describing your use case.

License

Apache License 2.0, © 2026 Jody Wicks. Chosen over MIT for the patent grant, which matters for a protocol others will build on. See LICENSE.

Metadata

Release files for fkyh 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fkyh 0.1.0
File Size Uploaded Provenance Actions
fkyh-0.1.0.tar.gz 652.9 kB Without provenance Details for fkyh-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for fkyh 0.1.0
File Interpreter ABI Platform Actions
fkyh-0.1.0-py3-none-any.whl Python 3 none any Details for fkyh-0.1.0-py3-none-any.whl

Total release size: 727.2 kB

Release files / fkyh-0.1.0.tar.gz

Download URL fkyh-0.1.0.tar.gz
Size 652.9 kB
Tags Source
SHA-256 checksum
How to use checksums
2719c5f5df684c7283e935a40d7f907d4bf6f44597775ac28065b132bcdd954b
BLAKE2b-256 checksum
How to use checksums
fff50c7a4a7a5684d897bcbfd5be88ace7430fbf5447949aaea1db0cb9f1fbbb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.4

Release files / fkyh-0.1.0-py3-none-any.whl

Download URL fkyh-0.1.0-py3-none-any.whl
Size 74.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5c6b14f3b6ae85321779377e0fefacdcb90d331efd282d85777c0ae15e30be06
BLAKE2b-256 checksum
How to use checksums
9366e629932c6312b129e2496eb87f1d36843d3b52541cdd815cd08ab2fbd566
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.4

Security for fkyh 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page