The Verifiable Agent Feed — a signed, hash-chained, cursor-based append-only feed a subscriber can prove is complete and untampered.
Project description
sm-feed
The Verifiable Agent Feed — a signed, hash-chained, cursor-based append-only feed a subscriber can prove is complete and untampered.
An agent that publishes an ongoing stream — claims, lifecycle events, aggregate
signals — is served today by an RSS feed or a bespoke webhook. Both ask the
subscriber to trust the server for completeness: a feed can silently drop or
reorder an item and no one can tell. sm-feed closes that gap. Every entry is
Ed25519-signed and hash-chained, so a subscriber that walks a contiguous run
verifies authenticity, integrity, and completeness in one pass. It owns the
feed — the wire shape and its verification — and nothing else: the transport,
the storage, and the meaning of the payload are the consumer's. The payload is
opaque (any JSON object with a type), so one format carries any agent's stream.
What this package secures (v0.1)
- Authenticity — each entry is Ed25519-signed by the feed's issuer DID.
- Tamper-evidence —
entry_hashcontent-addresses the entry; any edit to any field breaks it and verification returns falsy (never raises on hostile input). - Completeness — entries are hash-chained (
prev_hash) with contiguousseq; a dropped or reordered entry breaks the chain from the subscriber's anchor. - Head attestation — a signed head (
{seq, entry_hash}) lets a subscriber pin "the feed as of here" and detect a later rewind. Rewind detection requires passing that pinned head back asexpected_head; the check is inert without it (SPEC §5 rule 6). - Adversarially tested. The conformance corpus includes a hostile vector per failure path: dropped entry, tampered payload, wrong anchor, forged head.
What this package does NOT (yet) do
- Actively surfacing forks across subscribers — equivocation detection from
two conflicting signed heads ships (
detect_equivocation, SPEC §7), but the gossip transport that brings a peer's head to you, and witness co-signing to catch a fork before two heads meet, are the consumer's / a later property. - Merkle inclusion proofs — a deliberate non-goal, not deferred: the chain is
strictly linear and completeness is proven by walking
prev_hash(SPEC §8). - Push delivery, retry, and subscription registration — the consumer's responsibility; this primitive fixes only the payload and its verification.
- Detecting a withheld or stale view — an issuer that freezes one subscriber
at
seq = 40while serving others throughseq = 90has not tampered, rewound, or forked, and nothing here catches it. Completeness is a claim about the run between two anchors, never about being current (THREATMODEL.md). - A trusted clock or key custody —
issued_atis caller-asserted; key generation/rotation/revocation is out of scope. SPEC Appendix A reserves afeed/key-rotationpayload convention, non-normatively.
Features
- One dependency (
sm-arp, for the shared Ed25519 / JCS / did:key crypto). - Pure, wall-clock-free core: the caller supplies timestamps.
- Pull (
GET …/feed?since=<cursor>) and push (POSTa page) deliver the same object;verify_pagechecks both. - Bounded pages — a publisher may serve a prefix of a long backlog with the head running ahead of it, so a transport has a conformant way to cap a response body (SPEC §4.1).
- Opaque typed payload — the same wire format serves claims, events, or deltas.
- Compaction — a late subscriber adopts a signed state checkpoint as genesis
and walks forward, instead of replaying from the start (
adopt_checkpoint). - Equivocation proofs — two conflicting signed heads yield a non-repudiable
proof that an issuer forked its feed (
detect_equivocation).
Installation
pip install sm-feed
The reference implementation is on PyPI; this repository is not yet public. The published sdist carries the specification, the threat model, and the conformance corpus, so a second implementation can be built from the package alone.
Quick start
from sm_arp import Identity
from sm_feed import FeedLog, verify_page
issuer = Identity.generate()
log = FeedLog(issuer)
log.append({"type": "example/claim", "title": "First"}, issued_at="2026-01-01T00:00:00+00:00")
log.append({"type": "example/claim", "title": "Second"}, issued_at="2026-01-01T01:00:00+00:00")
# Serve on pull (GET /feed?since=<cursor>) or POST on push — same object.
# limit= serves a bounded prefix of a long backlog (SPEC §4.1).
page = log.page(cursor=None, generated_at="2026-01-01T02:00:00+00:00")
# Subscriber: verify authenticity + completeness, keep the new cursor.
ok, reason, cursor = verify_page(page, expected_prev_hash=None, expected_head=None)
assert ok, reason
# Persist both, and pass them back on the next pull:
# cursor["entry_hash"] -> expected_prev_hash
# cursor["head"] -> expected_head (this is the rewind defence — pass it)
# cursor["complete_to_head"] is False while a bounded backlog is still draining.
A runnable end-to-end example (publish → verify → detect a dropped entry) is in
examples/quick_start.py.
Reference fixtures
The golden vectors under conformance/vectors/ are
regenerated by conformance/_vector_gen.py from a fixed, non-secret fixture seed
("11"×32 — regenerable, never a real key) and replayed by
tests/test_conformance_vectors.py. They are the language-agnostic corpus a
second implementation replays to prove interoperability.
Specification
-
SPEC.md— normative wire shape and verification, working draft. -
WHITEPAPER.md— design rationale and axioms. -
THREATMODEL.md— what it defends, and what it doesn't. Worked payload profiles (non-normative), each with a runnable example: -
capability-announcement— an agent announcing what it can do, and withdrawing it. The first-person case: issuer and subject are the same DID. (example) -
registry-changelog— a registry exposing its mutations. The same shape in the third person; a registry that subscribes to announcement feeds aggregates them into one of these. (example)
Related packages
| Package | Role |
|---|---|
sm-arp |
Agency Receipt Protocol — the signed, hash-chained record primitive sm-feed reuses for crypto |
sm-authority |
Common Authority Evidence — establishes who controls a subject |
sm-bridge |
AgentFacts / registry endpoints — a natural feed publisher and consumer |
License
First published: 2026-07-30 | Last modified: 2026-08-02
Personal research contributions aligned with Project NANDA standards. Stellarminds.ai
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sm_feed-0.2.0.tar.gz.
File metadata
- Download URL: sm_feed-0.2.0.tar.gz
- Upload date:
- Size: 58.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96b79602a946f00f3b7054b0e868cf068d04874f4579a8851d918877c480daf9
|
|
| MD5 |
df50c2e36851ae87246a34d926038e37
|
|
| BLAKE2b-256 |
3e0e3edc56bf57918713ecd2ba771a26efe7c43d55c648121caf52c4524d23df
|
Provenance
The following attestation bundles were made for sm_feed-0.2.0.tar.gz:
Publisher:
release.yml on Sharathvc23/sm-feed
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sm_feed-0.2.0.tar.gz -
Subject digest:
96b79602a946f00f3b7054b0e868cf068d04874f4579a8851d918877c480daf9 - Sigstore transparency entry: 2333116776
- Sigstore integration time:
-
Permalink:
Sharathvc23/sm-feed@bdfa51d57d6f1468068d6bcf63adbe6b31d1101c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Sharathvc23
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bdfa51d57d6f1468068d6bcf63adbe6b31d1101c -
Trigger Event:
push
-
Statement type:
File details
Details for the file sm_feed-0.2.0-py3-none-any.whl.
File metadata
- Download URL: sm_feed-0.2.0-py3-none-any.whl
- Upload date:
- Size: 19.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d38ac3a15243737dffca51ac0e4cbd0b65f7171a0e1ebbd5d7de20f60baa133
|
|
| MD5 |
83da3747dc319117761de86f6669d03f
|
|
| BLAKE2b-256 |
f440462653d5f47b20879fd60ead94fe27eb8d006ac3a8344440aafb36dad62d
|
Provenance
The following attestation bundles were made for sm_feed-0.2.0-py3-none-any.whl:
Publisher:
release.yml on Sharathvc23/sm-feed
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sm_feed-0.2.0-py3-none-any.whl -
Subject digest:
4d38ac3a15243737dffca51ac0e4cbd0b65f7171a0e1ebbd5d7de20f60baa133 - Sigstore transparency entry: 2333116798
- Sigstore integration time:
-
Permalink:
Sharathvc23/sm-feed@bdfa51d57d6f1468068d6bcf63adbe6b31d1101c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Sharathvc23
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bdfa51d57d6f1468068d6bcf63adbe6b31d1101c -
Trigger Event:
push
-
Statement type: