sm-org-server 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. sm_org_server-0.1.0/.github/workflows/ci.yml +21 -0
  2. sm_org_server-0.1.0/.github/workflows/release.yml +48 -0
  3. sm_org_server-0.1.0/.gitignore +20 -0
  4. sm_org_server-0.1.0/.nanda/arp-conformance.json +24 -0
  5. sm_org_server-0.1.0/.nanda/conformance.json +25 -0
  6. sm_org_server-0.1.0/CHANGELOG.md +41 -0
  7. sm_org_server-0.1.0/GOVERNANCE.md +23 -0
  8. sm_org_server-0.1.0/LICENSE +21 -0
  9. sm_org_server-0.1.0/Makefile +20 -0
  10. sm_org_server-0.1.0/PKG-INFO +146 -0
  11. sm_org_server-0.1.0/PUBLISHING.md +48 -0
  12. sm_org_server-0.1.0/README.md +112 -0
  13. sm_org_server-0.1.0/WHITEPAPER.md +99 -0
  14. sm_org_server-0.1.0/docs/figures/arp-receipt-flow.svg +58 -0
  15. sm_org_server-0.1.0/docs/figures/receipts-surface.html +26 -0
  16. sm_org_server-0.1.0/docs/figures/render_receipts_surface.py +106 -0
  17. sm_org_server-0.1.0/pyproject.toml +81 -0
  18. sm_org_server-0.1.0/scripts/gen_arp_badge.py +87 -0
  19. sm_org_server-0.1.0/sm_server/__init__.py +7 -0
  20. sm_org_server-0.1.0/sm_server/app.py +512 -0
  21. sm_org_server-0.1.0/sm_server/merkle.py +125 -0
  22. sm_org_server-0.1.0/sm_server/signing.py +55 -0
  23. sm_org_server-0.1.0/sm_server/store/__init__.py +0 -0
  24. sm_org_server-0.1.0/sm_server/store/base.py +81 -0
  25. sm_org_server-0.1.0/sm_server/store/sqlite.py +182 -0
  26. sm_org_server-0.1.0/sm_server/trust.py +63 -0
  27. sm_org_server-0.1.0/tests/test_app.py +322 -0
  28. sm_org_server-0.1.0/tests/test_checkpoint.py +189 -0
  29. sm_org_server-0.1.0/tests/test_receipts.py +147 -0
  30. sm_org_server-0.1.0/tests/test_signing.py +49 -0
  31. sm_org_server-0.1.0/tests/test_store.py +64 -0
  32. sm_org_server-0.1.0/tests/test_trust.py +46 -0
  33. sm_org_server-0.1.0/uv.lock +930 -0
@@ -0,0 +1,21 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.11", "3.12"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: astral-sh/setup-uv@v5
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: ${{ matrix.python-version }}
20
+ # Same gate as `make ci-local`, so green locally == green in CI.
21
+ - run: make ci-local
@@ -0,0 +1,48 @@
1
+ # Publish sm-org-server to PyPI on a version tag, via PyPI Trusted Publishing (OIDC).
2
+ #
3
+ # No API token anywhere: PyPI is told (once, in its web UI) to trust THIS repo +
4
+ # THIS workflow file, and the `id-token: write` permission below lets the job
5
+ # mint a short-lived OIDC token PyPI accepts. See PUBLISHING.md for the one-time
6
+ # setup and the exact values to type into PyPI's "Add a publisher" form.
7
+ #
8
+ # Fires only when a tag like `v0.1.0` is pushed — never on normal commits.
9
+ name: release
10
+
11
+ on:
12
+ push:
13
+ tags:
14
+ - "v*"
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ publish:
21
+ name: Build + publish to PyPI
22
+ runs-on: ubuntu-latest
23
+ permissions:
24
+ # A job-level permissions block REPLACES the workflow-level one (it does not
25
+ # merge), so contents:read must be restated here or actions/checkout 404s on
26
+ # its own repo. Both lines are required.
27
+ contents: read # for actions/checkout
28
+ id-token: write # REQUIRED for Trusted Publishing — this is what replaces the token.
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+
32
+ - uses: actions/setup-python@v5
33
+ with:
34
+ python-version: "3.12"
35
+
36
+ - name: Build sdist + wheel
37
+ run: |
38
+ python -m pip install --upgrade build
39
+ python -m build
40
+
41
+ - name: Check the built distributions
42
+ run: |
43
+ python -m pip install --upgrade twine
44
+ python -m twine check dist/*
45
+
46
+ - name: Publish to PyPI
47
+ # No `with: password:` — the action uses the OIDC token automatically.
48
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,20 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ venv/
9
+
10
+ # Tooling caches
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .ruff_cache/
14
+ .coverage
15
+ htmlcov/
16
+ coverage/
17
+
18
+ # Agent tooling (never commit dev artifacts)
19
+ .claude/
20
+ .DS_Store
@@ -0,0 +1,24 @@
1
+ {
2
+ "payload": {
3
+ "schema_version": 1,
4
+ "runtime": "sm-chapter",
5
+ "protocol_versions": [
6
+ "0.1"
7
+ ],
8
+ "suite_digest": "sha256:d3610cf5bf09bef6dc49db731a8d93aaf3f553b0df8acf80790d152c8e9dc513",
9
+ "completed_at": "2026-06-05T02:22:37+00:00",
10
+ "exit_status": 0,
11
+ "passed": 22,
12
+ "failed": 0,
13
+ "skipped": 0,
14
+ "xfailed": 0,
15
+ "xpassed": 0,
16
+ "total_vectors": 22,
17
+ "extensions": {
18
+ "arp.conformance.profile": "receipts-0.1"
19
+ }
20
+ },
21
+ "signed_by": "did:key:z6MkwQGupwBpCHCboDXxjcFtjdoXpxeyZuVTduJtyQiXZkDN",
22
+ "signed_at": "2026-06-05T02:22:37+00:00",
23
+ "signature": "olY2Vk5bQY0pHURABL8ie4I+yhb3khmk70WS6ZKFNv8vNs6plgtGdKp865+h0ff7aJfuOudAr1YvEVD61mAtCg=="
24
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "payload": {
3
+ "schema_version": 1,
4
+ "runtime": "sm-chapter",
5
+ "protocol_versions": [
6
+ "0.3"
7
+ ],
8
+ "suite_digest": "sha256:dc16b6a2add91e96b86f569d979ca3b616e94bb17f27d5b35c4337a67587d669",
9
+ "completed_at": "2026-06-01T22:59:27.506265+00:00",
10
+ "exit_status": 0,
11
+ "passed": 61,
12
+ "failed": 0,
13
+ "skipped": 2,
14
+ "xfailed": 0,
15
+ "xpassed": 0,
16
+ "total_vectors": 63,
17
+ "extensions": {
18
+ "conformance.run.surface": "server",
19
+ "conformance.server.target": "http://localhost:8099"
20
+ }
21
+ },
22
+ "signed_by": "did:key:z6MkwQGupwBpCHCboDXxjcFtjdoXpxeyZuVTduJtyQiXZkDN",
23
+ "signed_at": "2026-06-01T22:59:27.506265+00:00",
24
+ "signature": "5coGdG+w9tW/zRulOyoMJidyt4422ZHGq32sfxWpftIoV4Sn2GUvPQ6GXUn1kIpej7oWrf0exBrzSk+leJwHBg=="
25
+ }
@@ -0,0 +1,41 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/), and the project adheres to
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Changed
10
+ - **Server rename (Tier 4, brand only — wire frozen).** The package, prose, public symbols, and config now use *server* vocabulary: `ChapterStore` → `ServerStore`, env vars `CHAPTER_*` → `SERVER_*` (legacy `CHAPTER_*` still read as aliases — no deployment breaks), app title `chapter-core` → `sm-org-server`. The **wire is unchanged**: `chapter_id`, the `ROTATE:{chapter_id}:…` canonical signing string, the `"chapter"`/`"chapters"` response keys, routes, and AgentFacts fields are all frozen by the protocol. Conformance stays green.
11
+
12
+ ### Added
13
+ - **ARP Issuer Log.** The server is now ARP-native — it keeps a verifiable log of [Agency Receipt Protocol](https://github.com/Sharathvc23/sm-arp) receipts via the `sm_arp` consumable library:
14
+ - `POST /api/receipts` — verify (structure → signature → authority → per-issuer hash chain §6.4) and persist a signed receipt; nothing written on failure.
15
+ - `GET /api/receipts/recent` (with `?principal=` filter) and `GET /api/receipts/{id}`.
16
+ - A live `receipts` A2UI surface over the log.
17
+ - Receipt persistence added to the `ServerStore` seam, so it follows the chosen backend (e.g. Postgres), not a side file.
18
+ - **Server self-emission.** Recording feedback also signs a server `attestation_issued` receipt endorsing the member (`issuer=server → counterparty=member`). The server holds its own ARP identity (stable via `SERVER_SEED`, ephemeral otherwise).
19
+ - **Signed ARP conformance badge** at `.nanda/arp-conformance.json`, served at `GET /.well-known/arp-conformance.json` and advertised in the well-known doc. Generated mechanically by `scripts/gen_arp_badge.py` against the live ingest surface (`SERVER_ARP_BADGE_PATH` overrides).
20
+ - **Signed Merkle checkpoint** (`aae-checkpoint/0.1`) over the whole Issuer Log. The per-issuer hash chain proves *forward* tamper-evidence within an issuer; the checkpoint adds the *reverse* seam across the whole log — membership you can verify offline:
21
+ - `GET /api/checkpoint` — an RFC 6962 Merkle root over every receipt (JCS-canonical leaf, including signature), signed by the server's ARP identity. Advertised in the well-known doc.
22
+ - `GET /api/checkpoint/proof/{receipt_id}` — the inclusion proof for one receipt, taken over the same `(issued_at, receipt_id)` ordering as the root so leaf indices line up. A holder verifies membership against the signed root with no further server trust.
23
+ - Pure RFC 6962 lib in `sm_server/merkle.py`, validated against independently-computed known answers; the checkpoint commits to the whole log (uncapped), never a silent prefix.
24
+
25
+ ## [0.1.0] — 2026-06-01
26
+
27
+ Initial public release.
28
+
29
+ ### Added
30
+ - Conformant server wire against a swappable `ServerStore` interface:
31
+ - `POST /api/members` — origin-gated registration with TOFU public key.
32
+ - `POST /api/members/rotate` — signed, nonce-protected key rotation.
33
+ - `POST /api/feedback` — signed-request verification (Ed25519, key-consistency, replay window) recording trust events.
34
+ - `GET /api/agents/{id}/trust` — trust dossier (score, tier, history).
35
+ - `GET /api/surfaces/{id}` — A2UI surface envelopes, public and auth-gated.
36
+ - `GET /api/federation` and `GET /api/federation/{peer}/members` — federation overview and peer member views.
37
+ - `GET /.well-known/nanda-agent.json` — peer discovery substrate.
38
+ - `SqliteStore` — zero-config, file-backed default backend with parameterized queries.
39
+ - Config-driven origin vocabulary (`SERVER_ORIGINS`, `SERVER_NONROTATABLE_ORIGINS`); no runtime-specific name in source.
40
+ - Trust ledger as the sum of canonical, server-set event deltas; tiers as thresholds.
41
+ - Signed conformance badge at `.nanda/conformance.json`.
@@ -0,0 +1,23 @@
1
+ # Governance
2
+
3
+ ## Scope
4
+
5
+ `sm-org-server` is the minimal conformant wire of a server: registration, key rotation, signed feedback, the trust ledger, surfaces, federation discovery, and the well-known substrate. It is deliberately *not* an agent runtime, a database, or a product. Storage backends, origin policy, and agent behaviour live above this line, in your code.
6
+
7
+ ## Versioning
8
+
9
+ - The package follows semantic versioning, independent of any protocol version.
10
+ - The **protocol wire** it implements — canonical signing strings, did:key derivation, trust-event deltas, the A2UI envelope shape — does not change within a major. A change to any of these is a major bump with a CHANGELOG entry and a regenerated conformance badge.
11
+ - Additive, namespaced, or configuration-only changes are minor or patch.
12
+
13
+ ## Conformance
14
+
15
+ A build is conformant *iff* a conformance suite passes against a running instance and the repository carries a green, signed `.nanda/conformance.json` pinned to that suite's vector digest. A passing badge is a precondition for any release tag. The signing key is a runtime key held outside CI; it is never committed.
16
+
17
+ ## Contributions
18
+
19
+ Issues and pull requests are welcome. A change that touches the wire must keep conformance green and update the badge. A change that touches storage or policy must keep the `ServerStore` Protocol stable or version it explicitly. All code keeps the gate green: `ruff`, `ruff format`, `mypy --strict`, and `pytest` at or above the coverage floor. Run the whole gate with one command before every push — `make ci-local` (uv-orchestrated; the same steps CI runs).
20
+
21
+ ## Attribution
22
+
23
+ Personal research contributions aligned with [Project NANDA](https://projectnanda.org) standards. Maintained by [stellarminds.ai](https://stellarminds.ai).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 stellarminds.ai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,20 @@
1
+ .PHONY: ci-local sync lint format typecheck test
2
+
3
+ # One command, run before every push. Mirrors CI exactly and hard-fails on the
4
+ # first red step. Same checks the GOVERNANCE gate names: ruff, mypy --strict, pytest.
5
+ ci-local: sync lint format typecheck test
6
+
7
+ sync:
8
+ uv sync --extra dev
9
+
10
+ lint:
11
+ uv run ruff check .
12
+
13
+ format:
14
+ uv run ruff format --check .
15
+
16
+ typecheck:
17
+ uv run mypy sm_server
18
+
19
+ test:
20
+ uv run pytest -v
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.4
2
+ Name: sm-org-server
3
+ Version: 0.1.0
4
+ Summary: Minimal, backend-agnostic, conformance-passing chapter server for federated AI agents.
5
+ Project-URL: Homepage, https://github.com/Sharathvc23/sm-org-server
6
+ Project-URL: Repository, https://github.com/Sharathvc23/sm-org-server
7
+ Project-URL: Changelog, https://github.com/Sharathvc23/sm-org-server/blob/main/CHANGELOG.md
8
+ Author: stellarminds.ai
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,chapter,conformance,did,federation,server
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Framework :: FastAPI
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Internet :: WWW/HTTP
19
+ Classifier: Topic :: Security :: Cryptography
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: base58>=2.1
22
+ Requires-Dist: cryptography>=42
23
+ Requires-Dist: fastapi>=0.110
24
+ Requires-Dist: jcs>=0.2
25
+ Requires-Dist: sm-arp>=0.2.1
26
+ Requires-Dist: uvicorn>=0.27
27
+ Provides-Extra: dev
28
+ Requires-Dist: httpx>=0.27; extra == 'dev'
29
+ Requires-Dist: mypy>=1.11; extra == 'dev'
30
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
31
+ Requires-Dist: pytest>=8.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.6; extra == 'dev'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # sm-org-server
36
+
37
+ **A minimal, backend-agnostic server for federated AI agents — small enough to read in one sitting, conformant enough to federate.**
38
+
39
+ A *server* is a home server for a community of AI agents: it registers them, gives each a verifiable identity, scores their trustworthiness, renders their shared surfaces, and federates with peer servers. `sm-org-server` is the smallest thing that does all of that correctly — the entire conformant wire is **~550 lines of Python against a swappable storage interface**, with no database lock-in, no LLM dependency, and no framework magic.
40
+
41
+ The intelligence, governance, and product features of a real server live *above* this line, as your own code. `sm-org-server` is the floor everyone shares.
42
+
43
+ ```
44
+ pip install sm-org-server
45
+ uvicorn sm_server.app:app
46
+ ```
47
+
48
+ That's a federating server with a SQLite backend, an Ed25519 identity, a trust ledger, and a clean HTTP surface — running on your laptop.
49
+
50
+ ## What you get
51
+
52
+ | Endpoint | Purpose |
53
+ |---|---|
54
+ | `POST /api/members` | Register an agent (origin-gated, TOFU public key) |
55
+ | `POST /api/members/rotate` | Rotate an agent's signing key (signed attestation, nonce-protected) |
56
+ | `POST /api/feedback` | Signed request → trust event (Ed25519, key-consistency, replay window) + a server-signed receipt |
57
+ | `GET /api/agents/{id}/trust` | Trust dossier: score, tier, history |
58
+ | `POST /api/receipts` | Ingest a signed ARP receipt into the Issuer Log (verify → hash-chain → persist) |
59
+ | `GET /api/receipts/recent` | Recent receipts (filter by `?principal=`) |
60
+ | `GET /api/receipts/{id}` | One receipt by id |
61
+ | `GET /api/surfaces/{id}` | A2UI surface envelope (the wire shape every renderer agrees on; `receipts` is a live one) |
62
+ | `GET /api/federation` | Federation overview + per-peer member views |
63
+ | `GET /.well-known/nanda-agent.json` | Discovery substrate for peers (did, facts_url, registries, conformance) |
64
+ | `GET /.well-known/conformance.json` | The signed wire conformance badge — public, no-auth, offline-verifiable |
65
+ | `GET /.well-known/arp-conformance.json` | The signed **ARP** receipt-suite badge |
66
+
67
+ ## Why it's this small
68
+
69
+ Most "agent platform" servers fuse three things that don't belong together: the **protocol wire** (what makes two servers interoperable), the **storage** (Postgres, Supabase, whatever), and the **agent brain** (the LLM, the policies, the product). Fuse them and the only way to be "compliant" is to adopt the whole stack.
70
+
71
+ `sm-org-server` separates them. It implements **only the wire**, against a `ServerStore` interface you can back with anything. Conformance is then *mechanical*: point a conformance suite at a running instance and it passes or it doesn't — no trust-me-it's-compatible.
72
+
73
+ ```
74
+ your product / policies / LLM ← you write this
75
+ ┌────────────────────────────────────┐
76
+ │ sm-org-server │ ← the conformant wire (this repo)
77
+ │ register · rotate · trust · feedback│
78
+ │ surfaces · federation · well-known │
79
+ └──────────────┬─────────────────────┘
80
+ │ ServerStore (Protocol)
81
+ SQLite (default) · Postgres · … ← swap freely
82
+ ```
83
+
84
+ ## Configuration
85
+
86
+ Everything is environment-driven; nothing runtime-specific is baked into the source.
87
+
88
+ | Variable | Default | Meaning |
89
+ |---|---|---|
90
+ | `SERVER_ID` | `sm-org-server` | This server's identifier (the wire `chapter_id`) |
91
+ | `SERVER_PUBLIC_URL` | `https://server.local` | Public base URL (for discovery substrate) |
92
+ | `SERVER_ORIGINS` | `sovereign` | Comma-separated admitted origin vocabulary |
93
+ | `SERVER_NONROTATABLE_ORIGINS` | *(none)* | Origins whose keys are managed and may not self-rotate |
94
+ | `SERVER_SEED`, `SERVER_BADGE_PATH`, `SERVER_ARP_BADGE_PATH` | *(see source)* | ARP seed and badge file locations |
95
+
96
+ > **Naming:** these env vars were `CHAPTER_*` before the server rename; the legacy names are still read as aliases, so existing deployments keep working. The *wire* field stays `chapter_id` (frozen by the protocol).
97
+
98
+ The origin vocabulary is **policy, not protocol**: a deployment declares which provenances it admits. The default is the neutral `sovereign` (self-custodied identity); a managed deployment can add its own install-time origins via config without changing a line of source.
99
+
100
+ ## Storage backends
101
+
102
+ The default `SqliteStore` is zero-config and file-backed. Any class satisfying the `ServerStore` Protocol (`sm_server/store/base.py`) is a drop-in — Postgres, Redis-backed, or an in-memory test double. Nothing above the interface knows what the backend is.
103
+
104
+ ## Receipts (ARP)
105
+
106
+ A server doesn't just track *that* agents are trusted — it keeps a verifiable record of *what they did*. `sm-org-server` is **ARP-native**: it maintains an **Issuer Log** of [Agency Receipt Protocol](https://github.com/Sharathvc23/sm-arp) receipts — Ed25519-signed, JCS-canonical, hash-chained per issuer (ARP §6.4).
107
+
108
+ ![ARP receipt flow](docs/figures/arp-receipt-flow.svg)
109
+
110
+ > The live `receipts` surface, rendered from a real `GET /api/surfaces/receipts` envelope: [docs/figures/receipts-surface.html](docs/figures/receipts-surface.html).
111
+
112
+ - **It ingests.** `POST /api/receipts` verifies a receipt (structure → signature → authority → hash chain) and persists it. A receipt is self-authenticating — its signature binds the issuer no matter who posts it — so the server trusts the envelope, not the transport. Verification fails → nothing is written.
113
+ - **It emits.** The server is a first-class issuer too: recording feedback also signs an `attestation_issued` receipt endorsing the member (`issuer=server → counterparty=member`) — the edge a reputation layer reads. Emission is the default, not an add-on.
114
+ - **It's swappable.** Receipts persist through the same `ServerStore` seam as members, so a Postgres-backed server keeps them in Postgres — not a side file.
115
+
116
+ The receipt envelope itself — build / sign / verify / canonical-bytes / chain — is the one canonical [`sm_arp`](https://github.com/Sharathvc23/sm-arp) library, shared with every other runtime, so the wire cannot drift. The live `GET /api/surfaces/receipts` A2UI surface renders the log.
117
+
118
+ ```python
119
+ from sm_arp import Identity, build_action, issue_receipt
120
+ me = Identity.generate()
121
+ r = issue_receipt(me, principal_did=me.did,
122
+ action=build_action(category="data_shared", human_summary="shared my calendar"))
123
+ # POST r to /api/receipts → {"accepted": true, "chain_link": "sha256:…"}
124
+ ```
125
+
126
+ ## Conformance
127
+
128
+ `sm-org-server` ships **two** signed badges — Ed25519-signed records of which suites it passed, each pinned to that suite's vector digest:
129
+
130
+ - `.nanda/conformance.json` — the **wire** suite, served at **`GET /.well-known/conformance.json`** (`SERVER_BADGE_PATH` overrides).
131
+ - `.nanda/arp-conformance.json` — the **ARP receipt** suite (a distinct corpus → a distinct badge), served at **`GET /.well-known/arp-conformance.json`** (`SERVER_ARP_BADGE_PATH` overrides). Generated *mechanically* by `scripts/gen_arp_badge.py`, which drives the live ingest surface with the canonical receipt vectors and counts what it actually accepts/rejects.
132
+
133
+ Both are public, unauthenticated, offline-verifiable, and advertised via pointers in the well-known doc; absent → the endpoint 404s. See the [conformance toolkit](https://github.com/Sharathvc23/sm-conformance) for how badges are produced and verified.
134
+
135
+ ## Development
136
+
137
+ ```
138
+ pip install -e '.[dev]'
139
+ ruff check sm_server tests
140
+ mypy sm_server
141
+ pytest # 65 tests, ≥80% coverage gate
142
+ ```
143
+
144
+ ## License
145
+
146
+ MIT © stellarminds.ai. See [LICENSE](LICENSE).
@@ -0,0 +1,48 @@
1
+ # Publishing sm-org-server to PyPI
2
+
3
+ `sm-org-server` publishes via **PyPI Trusted Publishing** — no API tokens. You tell PyPI
4
+ once that this repo's `release.yml` workflow may publish; after that, pushing a
5
+ version tag builds and uploads automatically.
6
+
7
+ > Do this only when `sm-org-server` is meant to be **public**.
8
+
9
+ ## One-time setup (≈5 minutes — this is the part only you can do)
10
+
11
+ 1. Create / sign in to a PyPI account → https://pypi.org/account/register/ (enable 2FA).
12
+ 2. Go to **https://pypi.org/manage/account/publishing/** → "Add a pending
13
+ publisher" (use *pending*, because the `sm-org-server` project doesn't exist on PyPI
14
+ yet — the first publish creates it).
15
+ 3. Fill the form with **exactly** these values:
16
+
17
+ | Field | Value |
18
+ |-------|-------|
19
+ | PyPI Project Name | `sm-org-server` |
20
+ | Owner | `Sharathvc23` |
21
+ | Repository name | `sm-org-server` |
22
+ | **Workflow name** | `release.yml` ← just the filename |
23
+ | Environment name | *(leave blank)* |
24
+
25
+ That's it. No secret is created or stored anywhere.
26
+
27
+ ## Releasing (every time, after setup)
28
+
29
+ ```bash
30
+ # bump version in pyproject.toml, commit, then:
31
+ git tag v0.1.0
32
+ git push origin v0.1.0
33
+ ```
34
+
35
+ The `release` workflow builds the sdist + wheel, runs `twine check`, and uploads
36
+ to PyPI over OIDC. Watch it under the repo's **Actions** tab. Within a minute,
37
+ `pip install sm-org-server` works for everyone.
38
+
39
+ ## Notes
40
+
41
+ - The tag (`v0.1.0`) and `version` in `pyproject.toml` must match.
42
+ - Dry run anytime, no upload: `python -m build && python -m twine check dist/*`.
43
+ - To test against TestPyPI first, add a pending publisher on
44
+ https://test.pypi.org and point the publish step at it with
45
+ `with: { repository-url: https://test.pypi.org/legacy/ }`.
46
+ - Hardening (optional): set `environment: pypi` on the job + a matching
47
+ Environment name in the PyPI publisher, then require reviewers on that GitHub
48
+ environment so a human approves each release.
@@ -0,0 +1,112 @@
1
+ # sm-org-server
2
+
3
+ **A minimal, backend-agnostic server for federated AI agents — small enough to read in one sitting, conformant enough to federate.**
4
+
5
+ A *server* is a home server for a community of AI agents: it registers them, gives each a verifiable identity, scores their trustworthiness, renders their shared surfaces, and federates with peer servers. `sm-org-server` is the smallest thing that does all of that correctly — the entire conformant wire is **~550 lines of Python against a swappable storage interface**, with no database lock-in, no LLM dependency, and no framework magic.
6
+
7
+ The intelligence, governance, and product features of a real server live *above* this line, as your own code. `sm-org-server` is the floor everyone shares.
8
+
9
+ ```
10
+ pip install sm-org-server
11
+ uvicorn sm_server.app:app
12
+ ```
13
+
14
+ That's a federating server with a SQLite backend, an Ed25519 identity, a trust ledger, and a clean HTTP surface — running on your laptop.
15
+
16
+ ## What you get
17
+
18
+ | Endpoint | Purpose |
19
+ |---|---|
20
+ | `POST /api/members` | Register an agent (origin-gated, TOFU public key) |
21
+ | `POST /api/members/rotate` | Rotate an agent's signing key (signed attestation, nonce-protected) |
22
+ | `POST /api/feedback` | Signed request → trust event (Ed25519, key-consistency, replay window) + a server-signed receipt |
23
+ | `GET /api/agents/{id}/trust` | Trust dossier: score, tier, history |
24
+ | `POST /api/receipts` | Ingest a signed ARP receipt into the Issuer Log (verify → hash-chain → persist) |
25
+ | `GET /api/receipts/recent` | Recent receipts (filter by `?principal=`) |
26
+ | `GET /api/receipts/{id}` | One receipt by id |
27
+ | `GET /api/surfaces/{id}` | A2UI surface envelope (the wire shape every renderer agrees on; `receipts` is a live one) |
28
+ | `GET /api/federation` | Federation overview + per-peer member views |
29
+ | `GET /.well-known/nanda-agent.json` | Discovery substrate for peers (did, facts_url, registries, conformance) |
30
+ | `GET /.well-known/conformance.json` | The signed wire conformance badge — public, no-auth, offline-verifiable |
31
+ | `GET /.well-known/arp-conformance.json` | The signed **ARP** receipt-suite badge |
32
+
33
+ ## Why it's this small
34
+
35
+ Most "agent platform" servers fuse three things that don't belong together: the **protocol wire** (what makes two servers interoperable), the **storage** (Postgres, Supabase, whatever), and the **agent brain** (the LLM, the policies, the product). Fuse them and the only way to be "compliant" is to adopt the whole stack.
36
+
37
+ `sm-org-server` separates them. It implements **only the wire**, against a `ServerStore` interface you can back with anything. Conformance is then *mechanical*: point a conformance suite at a running instance and it passes or it doesn't — no trust-me-it's-compatible.
38
+
39
+ ```
40
+ your product / policies / LLM ← you write this
41
+ ┌────────────────────────────────────┐
42
+ │ sm-org-server │ ← the conformant wire (this repo)
43
+ │ register · rotate · trust · feedback│
44
+ │ surfaces · federation · well-known │
45
+ └──────────────┬─────────────────────┘
46
+ │ ServerStore (Protocol)
47
+ SQLite (default) · Postgres · … ← swap freely
48
+ ```
49
+
50
+ ## Configuration
51
+
52
+ Everything is environment-driven; nothing runtime-specific is baked into the source.
53
+
54
+ | Variable | Default | Meaning |
55
+ |---|---|---|
56
+ | `SERVER_ID` | `sm-org-server` | This server's identifier (the wire `chapter_id`) |
57
+ | `SERVER_PUBLIC_URL` | `https://server.local` | Public base URL (for discovery substrate) |
58
+ | `SERVER_ORIGINS` | `sovereign` | Comma-separated admitted origin vocabulary |
59
+ | `SERVER_NONROTATABLE_ORIGINS` | *(none)* | Origins whose keys are managed and may not self-rotate |
60
+ | `SERVER_SEED`, `SERVER_BADGE_PATH`, `SERVER_ARP_BADGE_PATH` | *(see source)* | ARP seed and badge file locations |
61
+
62
+ > **Naming:** these env vars were `CHAPTER_*` before the server rename; the legacy names are still read as aliases, so existing deployments keep working. The *wire* field stays `chapter_id` (frozen by the protocol).
63
+
64
+ The origin vocabulary is **policy, not protocol**: a deployment declares which provenances it admits. The default is the neutral `sovereign` (self-custodied identity); a managed deployment can add its own install-time origins via config without changing a line of source.
65
+
66
+ ## Storage backends
67
+
68
+ The default `SqliteStore` is zero-config and file-backed. Any class satisfying the `ServerStore` Protocol (`sm_server/store/base.py`) is a drop-in — Postgres, Redis-backed, or an in-memory test double. Nothing above the interface knows what the backend is.
69
+
70
+ ## Receipts (ARP)
71
+
72
+ A server doesn't just track *that* agents are trusted — it keeps a verifiable record of *what they did*. `sm-org-server` is **ARP-native**: it maintains an **Issuer Log** of [Agency Receipt Protocol](https://github.com/Sharathvc23/sm-arp) receipts — Ed25519-signed, JCS-canonical, hash-chained per issuer (ARP §6.4).
73
+
74
+ ![ARP receipt flow](docs/figures/arp-receipt-flow.svg)
75
+
76
+ > The live `receipts` surface, rendered from a real `GET /api/surfaces/receipts` envelope: [docs/figures/receipts-surface.html](docs/figures/receipts-surface.html).
77
+
78
+ - **It ingests.** `POST /api/receipts` verifies a receipt (structure → signature → authority → hash chain) and persists it. A receipt is self-authenticating — its signature binds the issuer no matter who posts it — so the server trusts the envelope, not the transport. Verification fails → nothing is written.
79
+ - **It emits.** The server is a first-class issuer too: recording feedback also signs an `attestation_issued` receipt endorsing the member (`issuer=server → counterparty=member`) — the edge a reputation layer reads. Emission is the default, not an add-on.
80
+ - **It's swappable.** Receipts persist through the same `ServerStore` seam as members, so a Postgres-backed server keeps them in Postgres — not a side file.
81
+
82
+ The receipt envelope itself — build / sign / verify / canonical-bytes / chain — is the one canonical [`sm_arp`](https://github.com/Sharathvc23/sm-arp) library, shared with every other runtime, so the wire cannot drift. The live `GET /api/surfaces/receipts` A2UI surface renders the log.
83
+
84
+ ```python
85
+ from sm_arp import Identity, build_action, issue_receipt
86
+ me = Identity.generate()
87
+ r = issue_receipt(me, principal_did=me.did,
88
+ action=build_action(category="data_shared", human_summary="shared my calendar"))
89
+ # POST r to /api/receipts → {"accepted": true, "chain_link": "sha256:…"}
90
+ ```
91
+
92
+ ## Conformance
93
+
94
+ `sm-org-server` ships **two** signed badges — Ed25519-signed records of which suites it passed, each pinned to that suite's vector digest:
95
+
96
+ - `.nanda/conformance.json` — the **wire** suite, served at **`GET /.well-known/conformance.json`** (`SERVER_BADGE_PATH` overrides).
97
+ - `.nanda/arp-conformance.json` — the **ARP receipt** suite (a distinct corpus → a distinct badge), served at **`GET /.well-known/arp-conformance.json`** (`SERVER_ARP_BADGE_PATH` overrides). Generated *mechanically* by `scripts/gen_arp_badge.py`, which drives the live ingest surface with the canonical receipt vectors and counts what it actually accepts/rejects.
98
+
99
+ Both are public, unauthenticated, offline-verifiable, and advertised via pointers in the well-known doc; absent → the endpoint 404s. See the [conformance toolkit](https://github.com/Sharathvc23/sm-conformance) for how badges are produced and verified.
100
+
101
+ ## Development
102
+
103
+ ```
104
+ pip install -e '.[dev]'
105
+ ruff check sm_server tests
106
+ mypy sm_server
107
+ pytest # 65 tests, ≥80% coverage gate
108
+ ```
109
+
110
+ ## License
111
+
112
+ MIT © stellarminds.ai. See [LICENSE](LICENSE).