Technical Specification
swarm.at — Swarm-as-a-Service (SaaS) Information Settlement Protocol
Version 1.0.0 · Domain: swarm.at
1. Overview
swarm.at is a stateless Swarm-as-a-Service platform that acts as the deterministic clearing house for collaborative AI agents. It decouples Representation (the logic an agent performs) from Collaboration (the settlement on a shared task).
Agents produce probabilistic output. swarm.at turns that output into a deterministic, auditable record. The platform provides the institutional integrity layer that makes autonomous agents production-ready for enterprise use.
2. System Primitives
Statelessness: No agent maintains a session. Each interaction is a pure function: (Context + Task) = Proposal. Every call must include a Context_Slice and a Parent_Hash.
Determinism: Any operation that updates Shared State must be verified against the Institutional Logic schema.
Immutability: Once a task is settled, its record cannot be altered. Current_Hash must always link to Parent_Hash.
Institutional DNA: Rules (brand voice, budget limits, factual cutoffs) are stored in a schema external to the agents. Agents receive read-only slices.
Thrift: Minimize dependencies. Use Python 3.10+ standard libraries unless an external library reduces complexity by >50%.
3. Architecture
The system follows a Triage-Execute-Settle pattern across five layers.
3.1 Layer Overview
| Layer | Component | Responsibility | Implementation |
|---|---|---|---|
| Ingress | Context Injector | Prunes Shared State into a task-specific slice | Semantic search or keyword filtering |
| Execution | Dispatcher | Routes tasks by complexity to cheapest capable model | Python/FastAPI + Model Arbitrage |
| Execution | Executor | Stateless agent performing the work | Disposable API calls (Anthropic/OpenAI) |
| Verification | Shadow Auditor | Cross-model divergence checks to detect hallucinations | Secondary model comparison |
| Settlement | Settler | Commits verified work to the Ledger | Hash-chaining + flat-file append |
| Public | Verification Portal | UI for auditing transaction hashes | GitHub Pages |
3.2 Data Flow
User defines goal
-> Dispatcher evaluates complexity (0.0-1.0), selects model tier
-> Context Injector prunes Shared State into task-specific slice
-> Executor (stateless agent) receives slice + task, produces Proposal
-> Shadow Auditor runs secondary check (optional, for high-risk/random)
-> Settler verifies hash-chain + confidence + divergence
-> SETTLED (ledger append) | REJECTED (re-base) | ESCROWED (high divergence)
4. Data Model
4.1 Proposal Schema
The unit of work submitted by an agent for settlement.
{
"header": {
"task_id": "UUID",
"parent_hash": "SHA-256 (64 hex chars)",
"agent_metadata": {
"model": "string",
"version": "string"
}
},
"payload": {
"data_update": {},
"confidence_score": 0.0
},
"proof": "Optional trace of reasoning"
}
4.2 Ledger Entry Schema
Each settled transaction appended to the JSONL ledger.
{
"timestamp": 1234567890.123,
"task_id": "UUID",
"parent_hash": "SHA-256",
"payload": {},
"current_hash": "SHA-256"
}
4.3 Institutional Rules Schema
Configurable rules governing settlement behavior.
{
"min_confidence": 0.85,
"max_drift_allowed": 0.15
}
4.4 Ledger Format
- Format: Append-only
.jsonl(one JSON object per line) - Integrity: SHA-256 hash-chaining of all state transitions
- Security: Write-access restricted to the Settlement Engine; agents receive read-only slices
- Genesis: Empty ledger starts with parent hash
"0" * 64
5. Settlement Engine
The core logic governing the transition from execution to finality.
5.1 Settlement Statuses
| Status | Meaning |
|---|---|
| SETTLED | Proposal verified and committed to ledger |
| REJECTED | Failed verification (state drift, low confidence) |
| ESCROWED | High model divergence; held for manual review |
5.2 Verification Steps
The verify_and_settle() method executes these checks in order:
- Integrity Check:
proposal.parent_hash == ledger.latest_hash. Reject on mismatch ("State drift detected. Re-base required."). - Logic Check:
proposal.confidence_score >= institutional_rules.min_confidence. Reject if below threshold. - Shadow Audit (optional): If a shadow proposal exists, calculate divergence. Escrow if
divergence > max_drift_allowed. - Finality: Construct ledger entry, compute
current_hash = SHA-256(entry), append to ledger.
5.3 Hash Generation
SHA-256(json.dumps(content, sort_keys=True).encode())
Deterministic: sorted keys ensure consistent hashing regardless of insertion order.
6. Components
6.1 Dispatcher (Model Arbitrage)
Evaluates task complexity on a 0.0-1.0 scale and selects the lowest-cost API tier capable of the task.
| Tier | Complexity Range | Use Case |
|---|---|---|
| Thrifty | 0.0 - 0.3 | Simple lookups, formatting |
| Standard | 0.3 - 0.7 | Research, analysis |
| Premium | 0.7 - 1.0 | Complex reasoning, multi-step |
6.2 Context Injector (Semantic Pruning)
Extracts relevant institutional memory for a stateless agent. Takes the full Shared State and a set of query keywords, returns only the matching subset plus core_logic.
def get_context_slice(state, query_keywords):
return {k: v for k, v in state.items()
if k in query_keywords or k == "core_logic"}
Problem solved: Passing a 100k-token "brain" to every agent call is expensive. The Context Injector ensures agents run leaner, faster, and cheaper.
6.3 Shadow Auditor (Divergence Engine)
Runs a secondary, low-cost model check and compares outputs against the primary agent's proposal.
- Basic divergence: Binary (payloads match or don't)
- Extended divergence: Structural diff, optional NLP similarity scoring
- Threshold: Configurable via
max_drift_allowed(default 0.15) - Outcome: If models disagree beyond threshold, status is
ESCROWED(flagged before hitting ledger)
SDK interface: Provided as a decorator (@shadow_audit) that wraps agent functions.
6.4 Settler (Ledger Operations)
Manages the append-only JSONL ledger.
get_latest_hash()— Read last entry'scurrent_hashappend_entry(entry)— Write new entry to ledgerverify_chain()— Walk the full ledger and verify every hash link
7. API Specification
Framework: FastAPI
Base URL: https://api.swarm.at
Auth: Bearer token (Authorization: Bearer $SWARM_AT_KEY)
7.1 Endpoints
POST /v1/settle
Submit a proposal for settlement.
Request body: Proposal schema (section 4.1)
Response:
{"status": "SETTLED", "hash": "abc123..."}
// or
{"status": "REJECTED", "reason": "State drift detected. Re-base required."}
// or
{"status": "ESCROWED", "reason": "High model divergence."}
GET /v1/context?keywords=key1,key2
Get a context slice for a task.
Response: Pruned subset of Shared State.
GET /v1/status/{task_id}
Check settlement status of a specific task.
GET /v1/ledger/latest
Get the latest settled hash.
GET /v1/ledger/verify
Verify full ledger integrity (hash-chain unbroken).
GET /v1/whoami?agent_id=...
Agent self-check: returns trust level, allowed tools, promotion path. Requires auth.
POST /v1/agents/register
Register a new agent identity. Body: {"agent_id": "...", "role": "worker", "capabilities": []}. Requires auth.
Response:
{"agent_id": "my-agent", "role": "worker", "trust_level": "untrusted", ...}
GET /public/blueprints?tag=...&page=1&page_size=50
List available workflow blueprints. Public, no auth required. Supports tag filtering and pagination.
GET /public/blueprints/{blueprint_id}
Full blueprint detail including steps and fork count. Public, no auth required.
GET /llms.txt
LLM-readable protocol summary (text/plain). Follows the llms.txt v1.1.0 convention.
GET /robots.txt
Crawler guidance referencing /llms.txt.
GET /.well-known/agent-card.json
A2A agent-to-agent discovery card (JSON). Contains name, description, skills, and serviceUrl.
GET /.well-known/openapi.json
Enriched OpenAPI 3.1 spec with servers, tags, and examples.
POST /v1/blueprints/{blueprint_id}/fork
Fork blueprint into executable workflow. Requires auth.
Query params:
agent_id(string): Agent fork owner (default: "anonymous")
Response:
{
"workflow_id": "...",
"name": "...",
"step_count": 3,
"metadata": {...}
}
POST /v1/auth/token
Issue JWT token for agent. Public endpoint.
Request body:
{"agent_id": "...", "role": "worker"}
Response:
{"token": "eyJhb...", "agent_id": "...", "role": "worker"}
GET /v1/ledger/mode
Report ledger backend status. Public endpoint.
Response:
{"mode": "file", "backend": "JSONL", "path": "/tmp/ledger.jsonl"}
GET /public/receipts/{hash}
Look up a settlement receipt by its hash. Public, no auth required.
Response:
{
"status": "SETTLED",
"hash": "453eaa...178b287",
"task_id": "research-1",
"timestamp": 1770480398.05,
"parent_hash": "000000...000000"
}
Returns 404 if no entry matches. Use this to verify that a specific settlement exists and inspect its chain position.
GET /public/verify-trust?agent_id=X&min_trust=trusted
Check whether an agent meets a trust threshold. Public, no auth required.
Query params:
agent_id(required): Agent to checkmin_trust(required): Minimum trust level (untrusted,provisional,trusted,senior)
Response:
{
"agent_id": "my-agent",
"meets_requirement": true,
"trust_level": "trusted",
"reputation_score": 0.9412
}
Returns 404 for unknown agents, 400 for invalid trust levels.
GET /public/trust-summary
Aggregate count of agents at each trust level. Public, no auth required.
Response:
{
"total_agents": 5,
"by_trust_level": {"untrusted": 0, "provisional": 0, "trusted": 4, "senior": 1}
}
POST /v1/blueprints/publish
Publish a new blueprint to the catalog. Created as unvalidated. Requires auth.
Request body:
{
"name": "My Workflow",
"description": "Three-step analysis pipeline",
"tags": ["analysis"],
"steps": [{"step_id": "s1", "name": "Collect"}],
"agent_id": "publisher-agent"
}
Response:
{
"blueprint_id": "uuid",
"name": "My Workflow",
"author": "publisher-agent",
"step_count": 1,
"validated": false
}
8. MCP Settlement Server
An MCP (Model Context Protocol) server that acts as a gatekeeper for high-risk agent actions.
Server name: swarm-at-mcp
Installation: mcp add swarm-at --protocol-key [YOUR_KEY]
8.1 Tools Exposed
settle_action
Validates a proposed action against Institutional DNA before allowing execution. Used for high-risk operations (terminal commands, file writes, payments, deletions).
Input: Action description, context, parent_hash
Output: {"proceed": true/false, "reason": "...", "settlement_token": "..."}
guard_action
Settle before acting. Wraps settle_action with a guard semantic: call this before any destructive operation. If settlement is rejected, the action should not proceed.
Input: agent_id (string), action (string), data (JSON string, optional)
Output: Same as settle_action
check_settlement
Query ledger status for a given task or hash.
list_blueprints
List available workflow blueprints with optional tag filter.
Input: tag (optional string)
Output: JSON array of blueprints with blueprint_id, name, tags, step_count
get_blueprint
Get full blueprint details including steps and fork count.
Input: blueprint_id (string)
Output: Full blueprint JSON with steps array
fork_blueprint
Fork blueprint into executable workflow.
Input: blueprint_id (string), agent_id (string, optional)
Output: {"workflow_id": "...", "name": "...", "step_count": 3, "metadata": {...}}
verify_receipt
Look up a settlement receipt by its hash.
Input: hash (string, 64-character hex)
Output: {"found": true, "task_id": "...", "hash": "...", "timestamp": ..., "parent_hash": "..."}
check_trust
Check if an agent meets a minimum trust threshold.
Input: agent_id (string), min_trust (string: untrusted/provisional/trusted/senior)
Output: {"agent_id": "...", "meets_requirement": true, "trust_level": "trusted", "min_trust": "trusted"}
ledger_status
Get current chain state.
Input: (none)
Output: {"latest_hash": "...", "entry_count": 490, "chain_intact": true}
8.2 Safety Model
Before an agent runs a destructive command (e.g., rm -rf), it requests a Settlement Token from the MCP server. If the command violates Institutional DNA, the token is denied.
9. Python SDK
Drop-in library for agent builders.
9.1 Client API
from swarm_at import SwarmClient
client = SwarmClient(api_url="https://api.swarm.at", api_key="sk-...")
# Submit and settle a proposal
result = client.settle(proposal)
# Get pruned context for a task
context = client.context_slice(state, keywords=["topic_a", "topic_b"])
# Decorator for cross-model verification
@client.shadow_audit(shadow_model="haiku")
def research_task(context):
return agent.run(context)
9.2 Methods
| Method | Description |
|---|---|
settle(proposal) | Submit proposal, return settlement result |
guard_action(agent_id, action, data, confidence) | Settle before acting. Raises GuardError on rejection |
context_slice(state, keywords) | Get pruned context slice |
shadow_audit(shadow_model) | Decorator triggering cross-model verification |
list_blueprints(tag, page, page_size) | List blueprints with optional filtering |
get_blueprint(blueprint_id) | Get full blueprint detail with steps |
whoami(agent_id) | Agent self-check: trust level, permissions, promotion path |
register_agent(agent_id, role, capabilities) | Register a new agent identity |
fork_blueprint(blueprint_id, agent_id) | Fork blueprint into executable workflow |
create_token(agent_id, role) | Exchange credentials for JWT token |
9.3 One-Liner Public API
For the simplest integration, use the module-level settle() function:
from swarm_at import settle
result = settle(agent="my-agent", task="research", data={"findings": "..."})
Or use SettlementContext for stateful chaining:
from swarm_at import SettlementContext
ctx = SettlementContext()
r1 = ctx.settle(agent="agent-a", task="step-1")
r2 = ctx.settle(agent="agent-a", task="step-2") # auto-chains parent hash
Remote mode activates automatically when SWARM_API_URL is set.
10. Settlement Tiers
Graduated adoption tiers allow agents to start safely and grow into full settlement.
| Tier | SWARM_TIER | Behavior |
|---|---|---|
| SANDBOX | sandbox | Log-only. No ledger writes. Returns deterministic synthetic hashes. |
| STAGING | staging | Writes to ledger. Skips hash-chain enforcement. Enforces confidence. |
| PRODUCTION | production | Full verification: chain integrity + confidence + shadow audit. Default. |
export SWARM_TIER=sandbox
Each tier is governed by a TierPolicy with four flags: enforce_chain, enforce_confidence, write_ledger, log_only.
11. Framework Adapters
First-class adapters for the major agent frameworks. No framework imports required by the adapters -- they use getattr on duck-typed objects.
LangGraph
from swarm_at.adapters.langgraph import SwarmNodeWrapper
wrapper = SwarmNodeWrapper(agent="research-agent")
@wrapper.wrap
def research_node(state):
return {"findings": "..."}
AutoGen
from swarm_at.adapters.autogen import SwarmReplyCallback
callback = SwarmReplyCallback()
agent.register_reply([autogen.Agent], callback.on_reply)
Returns (False, None) -- pure observer, does not interfere with AutoGen's reply chain.
CrewAI
from swarm_at.adapters.crewai import SwarmTaskCallback
callback = SwarmTaskCallback()
crew = Crew(agents=[...], tasks=[...], task_callback=callback.on_task_complete)
OpenAI Assistants
from swarm_at.adapters.openai_assistants import SwarmRunHandler
handler = SwarmRunHandler(assistant_id="asst_abc123")
handler.settle_run(run, messages) # Run -> Molecule
handler.settle_step("tool_calls", step_data) # RunStep -> settlement
OpenAI Agents SDK
from swarm_at.adapters.openai_agents import SwarmAgentHook
hook = SwarmAgentHook(agent="my-agent")
hook.settle_run(result) # RunResult -> settlement
hook.settle_tool_call("search", input, output) # Tool call -> settlement
Strands (AWS)
from swarm_at.adapters.strands import SwarmStrandsCallback
callback = SwarmStrandsCallback()
callback.on_tool_complete("search", input, output)
callback.on_agent_complete("my-agent", result)
Haystack
from swarm_at.adapters.haystack import SwarmSettlementComponent
component = SwarmSettlementComponent()
result = component.run(data={"findings": "..."}, agent="pipeline-agent")
Install
pip install swarm-at-sdk[langgraph] # LangGraph adapter
pip install swarm-at-sdk[autogen] # AutoGen adapter
pip install swarm-at-sdk[crewai] # CrewAI adapter
pip install swarm-at-sdk[openai] # OpenAI Assistants adapter
pip install swarm-at-sdk[openai-agents] # OpenAI Agents SDK adapter
pip install swarm-at-sdk[strands] # Strands (AWS) adapter
pip install swarm-at-sdk[haystack] # Haystack adapter
pip install swarm-at-sdk[all] # All adapters + MCP
12. Protocol Schema Endpoint
Machine-readable endpoint for agent discovery:
GET /public/schema
Returns:
protocol: "swarm.at"version: "0.1.0"schemas: JSON schemas forProposal,SettlementResult,SettleRequestguarantees: determinism, idempotency, chain_integrity, trust_scoringtiers: policy details for sandbox/staging/production
No authentication required.
13. JWT Authentication
Token-based auth for stateless agent identification and role enforcement.
Concept
Complements API key auth. Agents exchange credentials for a signed JWT token via /v1/auth/token. Token contains agent identity, role, issued time, and expiration. Enables per-agent role-based access control (RBAC) without maintaining session state.
Token Format
Algorithm: HS256 (HMAC-SHA256)
Payload:
sub(string): agent_idrole(string): agent role (worker, orchestrator, etc.)iat(int): issued at (Unix timestamp)exp(int): expiration (Unix timestamp, default 1 hour)
Example decoded:
{
"sub": "my-agent",
"role": "worker",
"iat": 1234567890,
"exp": 1234571490
}
Dual Auth
The API supports both mechanisms:
- Bearer API key: Traditional static token (SWARM_API_KEYS env var)
- JWT: Dynamic token issued per request (SWARM_JWT_SECRET env var)
Request uses Authorization: Bearer <token>. Server validates first as API key, falls back to JWT decode.
Endpoints
POST /v1/auth/token (public)
Issue token. Body: {"agent_id": "my-agent", "role": "worker"}. Returns {"token": "eyJhb...", "agent_id": "my-agent", "role": "worker"}.
Returns 501 if SWARM_JWT_SECRET not configured.
Environment
| Variable | Default | Purpose |
|---|---|---|
SWARM_JWT_SECRET | (unset) | HS256 signing key; if unset, JWT auth disabled |
SWARM_JWT_EXPIRY | 3600 | Token lifetime (seconds) |
Error Cases
- 501: JWT auth not configured (SWARM_JWT_SECRET missing)
- 401: Malformed/missing authorization header
- 403: Invalid API key or JWT signature
14. OpenClaw Discovery Protocol
Makes swarm.at discoverable by LLMs, web crawlers, and agent-to-agent frameworks. All discovery endpoints are public (no auth required).
Discovery Endpoints
| Path | Content-Type | Purpose |
|---|---|---|
/llms.txt | text/plain | LLM-readable protocol summary (llms.txt v1.1.0) |
/robots.txt | text/plain | Crawler guidance, references /llms.txt |
/.well-known/agent-card.json | application/json | A2A agent-to-agent discovery card |
/.well-known/openapi.json | application/json | Enriched OpenAPI 3.1 spec |
/public/blueprints | application/json | Blueprint catalog (list, filter, paginate) |
/public/blueprints/{id} | application/json | Blueprint detail with steps |
/public/receipts/{hash} | application/json | Settlement receipt lookup by hash |
/public/verify-trust | application/json | Agent trust threshold check |
/public/trust-summary | application/json | Aggregate trust-level counts |
llms.txt Format
Plain text following the llms.txt v1.1.0 convention. Contains protocol name, one-line description, API base URL, core concepts, endpoint summaries, and integration examples. Generated deterministically by openclaw.generate_llms_txt().
A2A Agent Card
JSON document at /.well-known/agent-card.json following Google's Agent-to-Agent protocol. Contains:
name,description,urlskillsarray withid,name,description,tagsserviceUrlpointing to the API baseversionstring
Blueprint Catalog
Pre-validated workflow templates accessible without authentication. Each blueprint contains an ordered list of steps with dependencies, agent roles, and complexity scores. 31 pre-validated blueprints across 6 categories: Procurement & Supply Chain, Software Development, Finance & Compliance, Content & Knowledge, Customer Operations, and Specialty.
Environment Variables
| Variable | Default | Purpose |
|---|---|---|
SWARM_API_URL | https://api.swarm.at | API base URL used in generated discovery docs |
SWARM_SITE_URL | https://swarm.at | Site URL used in generated discovery docs |
15. Settlement Protocol (Agent-Facing)
The protocol loop that any participating agent must follow:
- Identify Parent Hash: Read the last settled hash from local state or ledger.
- Execute Task: Perform assigned work.
- Draft Proposal: Create JSON with
parent_hashanddata_update. - Invoke Settlement: Send proposal to
/v1/settle. - Update Local State: Only on
status: SETTLED, update local memory with new hash.
Safety rule: If response is REJECTED due to state mismatch, pull new state from ledger and re-perform work. Never overwrite local memory without a verified settlement hash.
16. Collective Consensus
When multiple agents (a swarm) work on one task, they don't just communicate; they Reconcile.
- First agent to find a valid solution "stakes" it on the ledger.
- Other agents in the swarm must "verify" or "contest" it.
- Finality is reached only when the consensus threshold is met.
17. Settlement Pulse
Periodic integrity check, replacing simple heartbeats with audit settlements.
- Frequency: Every 4 hours
- Action: Agent submits Work Summary + Hash to swarm.at ledger
- Purpose: Verify local agent memory hasn't drifted from institutional source of truth
18. Settlement Receipts
Every settled entry produces a rich receipt that third parties can verify independently.
Receipt Model
{
"status": "SETTLED",
"hash": "453eaa...178b287",
"task_id": "research-1",
"agent_id": "my-agent",
"timestamp": 1770480398.05,
"parent_hash": "000000...000000",
"trust_level": "trusted",
}
The SettlementReceipt model extends SettlementResult with provenance data: who settled, when, and where in the chain.
Engine Method
engine.settle_with_receipt(proposal, agent_id, trust_level) wraps verify_and_settle() and enriches the result with ledger data (timestamp, parent_hash) on success.
Public Lookup
GET /public/receipts/{hash} returns the receipt for any settled entry. No auth required. Returns 404 for unknown hashes.
Use case: Agent A settles an action and shares the hash with Agent B. Agent B calls /public/receipts/{hash} to independently verify the settlement happened before proceeding.
19. Trust Verification
Third parties can check an agent's trustworthiness without an API key.
Verify Trust
GET /public/verify-trust?agent_id=X&min_trust=trusted
Returns whether the agent meets the specified trust threshold. The response includes the agent's actual trust level and reputation score.
Use case: Before collaborating with an unknown agent, check its trust level. A supply chain agent can require min_trust=trusted before accepting orders from a counterparty.
Trust Summary
GET /public/trust-summary
Returns aggregate counts of agents at each trust level. Useful for monitoring the health of the agent ecosystem.
Trust Levels
| Level | Threshold | Capabilities |
|---|---|---|
| untrusted | New agent | Can execute tasks, cannot stake |
| provisional | 5+ settlements, Bayesian lower bound ≥ 0.60 | Can execute and stake |
| trusted | 20+ settlements, lower bound ≥ 0.82 | Full participation, can merge |
| senior | 100+ settlements, lower bound ≥ 0.92 | Can orchestrate workflows |
20. Guard Action Pattern
The recommended way to integrate settlement: settle before you act.
Concept
guard_action() combines proposal creation, settlement, and receipt into a single call. Call it before any destructive or irreversible operation. If settlement is rejected, the action doesn't happen.
SDK Usage
from swarm_at import SwarmClient
from swarm_at.sdk.client import GuardError
client = SwarmClient(api_url="https://api.swarm.at", api_key="sk-...")
try:
receipt = client.guard_action(
agent_id="my-agent",
action="delete-records",
data={"table": "users", "count": 150},
)
# receipt["hash"] is your cryptographic proof
perform_deletion(receipt["hash"])
except GuardError as e:
log(f"Action blocked: {e.reason}")
MCP Usage
The guard_action MCP tool provides the same semantics for agents using the Model Context Protocol:
// Agent calls guard_action before destructive operations
guard_action(agent_id="deploy-bot", action="deploy-service", data='{"env": "production"}')
How It Works
- Fetches the latest ledger hash
- Builds a
Proposalwith the action description as payload - Submits the proposal to
/v1/settle - On
SETTLED: returns receipt dict with hash, action, agent_id - On
REJECTED: raisesGuardErrorwith the reason
This makes settlement the path of least resistance. Instead of remembering to settle after every action, guard before every action.
21. Verification Guarantees
| Property | Definition |
|---|---|
| Chain Integrity | Every current_hash links to its parent_hash. Breakage detectable by walking the chain. |
| Determinism | Same input produces the same hash. Sorted keys, canonical JSON encoding. |
| Auditability | Full ledger is public. Any entry verifiable via /public/ledger/verify or git log. |
22. Hosting
- Frontend: GitHub Pages (documentation, dashboard)
- Backend: Railway (FastAPI, auto-deploys on push to
main) - Storage: Append-only JSONL ledger, git-backed
- Public Ledger: github.com/Mediaeater/swarm-at-ledger