Metadata-Version: 2.4
Name: sm-feed
Version: 0.1.0
Summary: The Verifiable Agent Feed — a signed, hash-chained, cursor-based append-only feed a subscriber can prove is complete and untampered.
Project-URL: Homepage, https://github.com/Sharathvc23/sm-feed
Project-URL: Spec, https://github.com/Sharathvc23/sm-feed/blob/main/SPEC.md
Author-email: StellarMinds <hello@stellarminds.ai>
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agents,did,federation,feed,nanda,transparency-log,verifiable
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: sm-arp>=0.3.0
Provides-Extra: dev
Requires-Dist: coverage>=7.0; extra == 'dev'
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# 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_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.
- **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

- **Fork detection across subscribers** — a signed head proves "the issuer said
  this is head", not that every subscriber saw the same history. Witness
  co-signing / gossip (à la Certificate Transparency) is a later property; see
  [`SPEC.md`](./SPEC.md) §6.
- **Merkle inclusion proofs** — completeness is by walking the chain; an
  `O(log n)` proof for a single old entry is future work.
- **Push delivery, retry, and subscription registration** — the consumer's
  responsibility; this primitive fixes only the payload and its verification.
- **A trusted clock or key custody** — `issued_at` is caller-asserted; key
  generation/rotation/revocation is out of scope.

## 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.
- Opaque typed payload — the same wire format serves claims, events, or deltas.

## Installation

Not yet published to PyPI — install directly from the repository:

```bash
pip install git+https://github.com/Sharathvc23/sm-feed.git
```

## Quick start

```python
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.
page = log.page(cursor=None, generated_at="2026-01-01T02:00:00+00:00")

# Subscriber: verify authenticity + completeness, keep the new cursor anchor.
ok, reason, head = verify_page(page, expected_prev_hash=None)
assert ok, reason
# persist head["entry_hash"] as expected_prev_hash for the next pull
```

A runnable end-to-end example (publish → verify → detect a dropped entry) is in
[`examples/quick_start.py`](./examples/quick_start.py).

## Reference fixtures

The golden vectors under [`conformance/vectors/`](./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`](./SPEC.md) — normative wire shape and verification, working draft.
- [`WHITEPAPER.md`](./WHITEPAPER.md) — design rationale and axioms.
- [`THREATMODEL.md`](./THREATMODEL.md) — what it defends, and what it doesn't.

## Related packages

| Package | Role |
| --- | --- |
| [`sm-arp`](https://github.com/Sharathvc23/sm-arp) | Agency Receipt Protocol — the signed, hash-chained record primitive sm-feed reuses for crypto |
| [`sm-authority`](https://github.com/Sharathvc23/sm-authority) | Common Authority Evidence — establishes who controls a subject |
| [`sm-bridge`](https://github.com/Sharathvc23/sm-bridge) | AgentFacts / registry endpoints — a natural feed publisher and consumer |

## License

[MIT](./LICENSE)

---

*First published: 2026-07-30 | Last modified: 2026-07-30*

*Personal research contributions aligned with [Project NANDA](https://projectnanda.org) standards. [Stellarminds.ai](https://stellarminds.ai)*
