Skip to main content

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-evidenceentry_hash content-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 contiguous seq; 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 as expected_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 = 40 while serving others through seq = 90 has 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 custodyissued_at is caller-asserted; key generation/rotation/revocation is out of scope. SPEC Appendix A reserves a feed/key-rotation payload 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 (POST a page) deliver the same object; verify_page checks 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

MIT


First published: 2026-07-30 | Last modified: 2026-08-02

Personal research contributions aligned with Project NANDA standards. Stellarminds.ai

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sm_feed-0.2.0.tar.gz (58.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sm_feed-0.2.0-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

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

Hashes for sm_feed-0.2.0.tar.gz
Algorithm Hash digest
SHA256 96b79602a946f00f3b7054b0e868cf068d04874f4579a8851d918877c480daf9
MD5 df50c2e36851ae87246a34d926038e37
BLAKE2b-256 3e0e3edc56bf57918713ecd2ba771a26efe7c43d55c648121caf52c4524d23df

See more details on using hashes here.

Provenance

The following attestation bundles were made for sm_feed-0.2.0.tar.gz:

Publisher: release.yml on Sharathvc23/sm-feed

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for sm_feed-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4d38ac3a15243737dffca51ac0e4cbd0b65f7171a0e1ebbd5d7de20f60baa133
MD5 83da3747dc319117761de86f6669d03f
BLAKE2b-256 f440462653d5f47b20879fd60ead94fe27eb8d006ac3a8344440aafb36dad62d

See more details on using hashes here.

Provenance

The following attestation bundles were made for sm_feed-0.2.0-py3-none-any.whl:

Publisher: release.yml on Sharathvc23/sm-feed

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page