(S)AGE — Sovereign Agent Governed Experience
!SAGE: governed memory for AI agents, with a lavender neural brain
Memory your agents can be held to.
SAGE is a governed memory and messaging layer for AI agents. Every memory is signed by an agent, admitted through a reviewable process, scoped by permissions you set, and kept with an audit trail you can inspect.
Connect your tools to the same local node so authorized agents can record experience and recall relevant context in later sessions. Inspect what they keep in CEREBRUM, SAGE's local dashboard.
Works with Claude Code, Codex, Cursor and other MCP-capable clients. Developers can integrate through the Python SDK or signed REST API. Recall depends on what is recorded, your configuration and the agent's use of its tools.
Download SAGE · Get started · Connect your AI · Developer quickstart
Why SAGE · Quick Start · For Developers · Architecture · Capabilities · Dashboard · Release history · Documentation
Why SAGE
Use SAGE when your agents return to ongoing work: a design decision worth keeping, an approach that failed, or a lesson the next session should use. RAG retrieves source material; SAGE uses retrieval too, with a governed record of agent experience around it.
- Trace the origin. Agent-signed writes attribute memories to their recorded author.
- Review admission. Memories pass through a validation lifecycle before they enter normal recall.
- Control access. Enrollment, domain permissions and classification determine which agents can use a memory.
- Keep memory useful. Inspect confidence and status, apply decay, or deprecate a memory while retaining its audit history.
Memory is local by default. Optional federation, connectors and remote model providers can send data to configured destinations. Enable the vault for memory-content encryption at rest; see the privacy details and Security FAQ.
Quick Start
Desktop: Download the latest release, open SAGE and complete setup in CEREBRUM. Choose your memory engine, connect an AI client and review agent access. Follow the connection guide for your tool or the full Getting Started walkthrough.
If SAGE is already running, check it before starting another server:
curl http://127.0.0.1:8080/health
A healthy node returns {"status":"healthy"}. After connecting an MCP client,
call sage_inception and follow its returned memory mode.
Build from source
From source (Go 1.26.10+):
git clone https://github.com/l33tdawg/sage.git && cd sage
go build -o sage-gui ./cmd/sage-gui/
./sage-gui setup # Pick your AI, get MCP config
./sage-gui serve # SAGE + Dashboard on :8080
Desktop packages: macOS DMG (signed & notarized) | Windows EXE | Linux tar.gz
Docker and containerized MCP setup
Docker
docker pull ghcr.io/l33tdawg/sage:latest
docker run -d --name sage \
-p 8080:8080 \
-v ~/.sage:/root/.sage \
ghcr.io/l33tdawg/sage:latest
Pin a specific version with ghcr.io/l33tdawg/sage:11.24.5.
The SAGE server stays in that container. To give a local MCP client a stdio bridge, start a second process inside the same running container:
docker exec -i \
-e SAGE_PROVIDER=claude-code \
-e SAGE_PROJECT=my-project \
-e SAGE_IDENTITY_PATH=/root/.sage/agents/claude-code-my-project/agent.key \
sage /usr/local/bin/sage-gui mcp
For the shipped Compose stack, use the service name rather than a generated container name:
docker compose -f docker-compose.sage-gui.yml exec -T \
-e SAGE_PROVIDER=claude-code \
-e SAGE_PROJECT=my-project \
-e SAGE_IDENTITY_PATH=/root/.sage/agents/claude-code-my-project/agent.key \
sage /usr/local/bin/sage-gui mcp
If an MCP client launches this through a wrapper, point its stdio configuration
at the wrapper's absolute path. Pass SAGE_PROVIDER, SAGE_PROJECT, and
SAGE_IDENTITY_PATH through docker exec -e/docker compose exec -e; setting
them only on the host-side Docker command does not place them in the container.
Keep the whole SAGE data root mounted at /root/.sage, including agent keys and
the ledger. Do not start a separate docker run ... mcp container: its
localhost:8080 is isolated from the running SAGE server.
HTTP MCP is also available at /v1/mcp/sse and /v1/mcp/streamable, but both
require a bearer token or OAuth. Bare http://localhost:8080 is the REST base,
not an unauthenticated MCP endpoint.
Upgrading an existing node
Upgrading from an older version?
**Upgrading an existing node — including the v10.x → v11 jump — is docs/UPGRADING.md.** In the desktop app, accept the update: SAGE verifies canonical upgrade compatibility, captures a full recovery snapshot, installs, and restarts automatically. Headless and quorum operators have separate technical procedures in the guide. Your chain advances in place; a personal node climbs the consensus fork ladder by itself. Read the guide before a multi-admin chain crosses app-v23 — that activation re-derives administrator authority.
If you installed SAGE before v5.0 and your AI isn't doing turn-by-turn memory updates, re-run the installer in your project directory:
cd /path/to/your/project
sage-gui mcp install
This installs Claude Code hooks that prompt the memory lifecycle (boot, turn, reflect) — even if your .mcp.json is already configured. Restart your Claude Code session after running this.
For Developers
Choose an integration for your workflow:
| Integration | Use it for | Start here | | --- | --- | --- | | MCP | Giving an existing AI client memory and coordination tools | Connection guide · MCP reference | | Python SDK | Building a memory-aware agent or application with sync/async clients | Developer quickstart · SDK reference | | Signed REST API | Integrating from another language over HTTP | REST reference |
The authoritative reference index covers exact API behavior, authentication, access controls and lifecycle rules. Start there when implementing an integration.
Python: read existing memories
Requires Python 3.10+, a running node and an enrolled agent. Set
SAGE_IDENTITY_PATH to that agent's existing key file and SAGE_DOMAIN to a
domain it can read.
python -m pip install sage-agent-sdk
import os
from sage_sdk import AgentIdentity, SageClient
identity = AgentIdentity.from_file(os.environ["SAGE_IDENTITY_PATH"])
domain = os.environ["SAGE_DOMAIN"]
with SageClient(
base_url="http://127.0.0.1:8080",
identity=identity,
trust_env=False,
) as client:
page = client.list_memories(
domain=domain, status="committed", limit=3,
)
for memory in page.memories:
print(memory.memory_id, memory.content)
Save as quickstart.py and run python quickstart.py. An empty list means no
committed memories are visible to this agent in that domain. Review enrollment
and domain permissions in CEREBRUM if access is denied.
To record experience, use propose() in a domain the agent can write to and set
classification explicitly. A submitted memory starts as proposed; normal
recall includes it after admission commits it. For semantic retrieval, use
hybrid() with query text and a matching embedding. See the
SDK examples and
memory admission guide.
Architecture
flowchart TB
A["AI agents · MCP / SDK / REST"] --> P["SAGE node · authenticated admission + live policy"]
H["CEREBRUM · local human control"] --> P
P --> M["Memory + local policy transactions<br/>CometBFT / ABCI"]
P --> W["Node-local coordination<br/>inbox / claims / replies"]
M --> B["BadgerDB<br/>authoritative chain state"]
B --> Q["Commit-time SQL projection<br/>content + vectors for authorized recall"]
P -. "explicit peer trust and sharing" .-> F["Separate SAGE chain<br/>bounded Read / receiver-controlled Copy"]
classDef entry fill:#eef2ff,stroke:#6366f1,color:#1e293b
classDef memory fill:#ecfdf5,stroke:#059669,color:#064e3b
classDef work fill:#fff7ed,stroke:#d97706,color:#7c2d12
class A,H,P entry
class M,B,Q memory
class W,F work
Agents are not validators. Personal mode runs one real CometBFT validator with a per-node memory auto-voter; it has no Byzantine redundancy. Registering more agents does not add consensus voters. A multi-validator deployment runs one shared chain; federation connects separate chains under explicit policy.
Storage has two roles. BadgerDB is authoritative for consensus state. SQLite (personal) or PostgreSQL + pgvector (cluster) projects memory content and vectors at Commit. Node-local message coordination is separate from the memory consensus path. Block inclusion is not the same as memory acceptance.
For the detailed trust boundaries, lifecycles, and deployment topology, see Architecture & Deployment.
Current Capabilities
| Capability | What it provides | |------------|------------------| | Governed memory | Persistent, attributed memories with consensus validation, semantic recall, confidence, and lifecycle controls | | Durable tasks | Exact-agent assigned backlog; open tasks do not decay; idempotent creation and workflow status | | Unified inbox | Local/federated requests, assignment notices, and a separate passive reply page | | Runtime handoff | Explicit session-and-revision-fenced takeover of claimed work within the same signed agent identity | | Access controls | Active enrollment, roles/profiles, ownership, Access Groups, compatible grants, and classification checks | | Controlled federation | Explicit agent exports and bounded Read/Copy policy, without granting local membership or Write | | Recovery and updates | In-place chain upgrades, recovery snapshots, and retained message claims across ordinary restarts |
How agents collaborate
flowchart TB
T["Task assigned to exact agent"] --> N["One-way assignment notice"]
N --> I["Unified inbox"]
R["Request addressed to exact agent"] --> I
I -->|"task notice"| V["Verify current assignment in backlog<br/>then update the task"]
I -->|"inbound request"| C["Claimed by one MCP runtime"]
C -->|"normal completion"| O["Idempotent reply"]
C -. "intentional same-agent takeover" .-> H["Handoff: expected session + revision"]
H --> O
O --> S["Original sender reads reply_items<br/>or pages retained replies"]
classDef input fill:#eef2ff,stroke:#6366f1,color:#1e293b
classDef task fill:#ecfdf5,stroke:#059669,color:#064e3b
classDef message fill:#fff7ed,stroke:#d97706,color:#7c2d12
class I input
class T,N,V task
class R,C,H,O,S message
Assignment, claim, and reply are different states. A task notice is not a request for a message result, and a reply is not a new assignment. Runtime handoff does not reassign a task to another agent. Wake notifications are payload-free hints, not delivery or claim evidence. Every agent request and result remains untrusted data, not authority to expand the user's instructions.
See the MCP task/inbox reference and message/reply lifecycle for exact fields, recovery, and authorization rules.
CEREBRUM Dashboard
!CEREBRUM MRI brain — memories mapped inside a 3D brain with focused related notes
http://127.0.0.1:8080/ui/ — a dashboard-native operator console centered on the 3D MRI memory brain, with chain health, agents, federation, semantic memory, recall tuning, vault recovery, tasks, imports, and updates around it. Every major workflow is available from the browser; the CLI stays there for automation and recovery.
| Control Board | Federation | Recall Engine | |:---:|:---:|:---:| | !CEREBRUM overview dashboard | !Federation join dashboard | !Recall engine settings | | Chain health, quorum, agents, federation, and embeddings | One trust-only JOIN that prepares Direct and Secure relay automatically, followed by independent Read/Copy choices on each SAGE | Smart-memory setup, managed reranker install, and recall-depth tuning |
The dashboard also includes governed agent enrollment, Access Groups, domain permissions, separate CEREBRUM Root credential handover, import/export, software updates, and encryption controls. Ordinary agent identity replacement uses re-enrollment; historical memory authorship is preserved.
Recent release notes (v11.24.5 and earlier)
What's New in v11.24.5
Task identity is now domain-aware. App-v23 tasks use their permanent idempotency identity—caller, exact signed domain, canonical [TASK] content, or an explicit occurrence key—instead of the global memory-content tombstone. The same task body can exist as a distinct task in another governed domain without being deprecated after consensus.
Deprecated tasks can no longer mutate. REST and the SQLite and PostgreSQL stores reject claim, completion, and status changes on deprecated task rows, so a full-ID update cannot report success against a task that has disappeared from the backlog.
No app-version or data migration. App-v29 remains active. Container: ghcr.io/l33tdawg/sage:11.24.5. SDK 11.24.5.
What's New in v11.24.4
macOS restarts now recover without Activity Monitor cleanup. The tray keeps sage-gui serve supervised, restarts unexpected exits with bounded backoff, detects a live child that stops answering health checks, and retains the unlocked passphrase for the replacement process. Daemon logs are appended so a failed restart keeps its evidence.
Shutdown no longer lets transport teardown strand an update. MCP HTTP and federation P2P close stages are bounded. A timeout is logged without rolling back an otherwise valid update or preventing the replacement process from starting.
CEREBRUM makes the restart wait visible. The updater now shows a live five-minute countdown and phase-specific status while SAGE finishes in-flight work, closes its listener, starts the replacement, and reconnects. The countdown keeps moving even while a request or health probe is waiting on the network.
No consensus change or chain migration. App-v29 remains active. Container: ghcr.io/l33tdawg/sage:11.24.4. SDK 11.24.4.
What's New in v11.24.3
AMID exposes the signer-fence recovery surface without requiring CEREBRUM. Operator-only GET /v1/dashboard/signer-fence/status, POST /v1/dashboard/signer-fence/lift, and POST /v1/dashboard/signer-fence/abandon routes now serve the cluster runtime. The exact configured governance operator must sign each request; caller-supplied proofs and evidence are rejected, request bodies are bounded, and the node rereads committed nonce, transaction, mempool, and peer state before every recovery decision.
AMID health now follows the external Comet engine. After the chain identity binds, AMID continually probes the configured CometBFT RPC /health, clears its Comet health bit on failure, and restores it after recovery. The compose validators use restart: unless-stopped, preserving deliberate operator stops while restarting unexpected exits.
Public SAGE-Noesis outcome receipts establish an evidence-only interop boundary. Receipt v1 is public-only, signed, off-consensus, and carries no REST or MCP route. It records reproducible control/treatment evidence without granting valuation, stake, governance, access, or memory authority to Noesis.
No consensus change or chain migration. App-v29 remains active. Container: ghcr.io/l33tdawg/sage:11.24.3. SDK 11.24.3.
What's New in v11.24.2
PostgreSQL stats now exclude deprecated memories from totals and per-domain counts, matching SQLite. Status counts and last activity retain their audit history.
CEREBRUM timelines now include in-range memories at fractional-second date boundaries. Whole-second and fractional bounds keep exact inclusive timestamp checks and canonical visibility checks.
No consensus change or chain migration. App-v29 remains active. Container: ghcr.io/l33tdawg/sage:11.24.2. SDK 11.24.2.
What's New in v11.24.1
App-v29 now activates automatically after its evidence gates pass. The auto-vote readiness ceiling moves from app-v28 to app-v29, so personal nodes converge on the architecture-independent PoE arithmetic already compiled in v11.24.0. The activation block keeps app-v28 behavior; deterministic EWMA, recency, corroboration, logarithm, exponential and final-weight calculations begin at H+1. Historical blocks continue to replay under their original app versions.
The app-v29 evidence spans the real failure surfaces. A four-validator ladder crosses app-v2 through app-v29 with byte-identical AppHash at H-1, H and H+1, then continues through the first post-activation PoE epoch. A separate quorum runs two validators and CometBFT processes on arm64 and two on amd64 against one chain. The real-process crash, partition, restart and state-sync gate targets exact app-v29 state.
The patch closes the release security gaps. Go 1.26.10 fixes GO-2026-6809 in crypto/x509; certifi 2026.10.19 removes the compromised emSign intermediate CA bundle from all benchmark environments; and the dependency group updates chi, klauspost/compress, go-winio, Playwright and pinned GitHub Actions.
No chain migration. Existing memories, identities, governance state and chain history are preserved. Container: ghcr.io/l33tdawg/sage:11.24.1. SDK 11.24.1.
What's New in v11.24.0
PoE weights now have an architecture-independent path. App-v29 compiles a new consensus form of the proof-of-experience arithmetic: EWMA state updates, recency, corroboration and final weights use explicitly rounded operations that produce the same float64 bits on arm64 and amd64. The gate remains dormant above the app-v28 auto-vote ceiling, so existing chains keep their current app version and historical blocks keep replaying under their original arithmetic until the mixed-architecture, replay, snapshot and state-sync evidence is complete. CI and release workflows now run exact golden vectors on native amd64 and arm64.
Org fleet enrollment Phase 1 lands. Organizations can issue 24-hour, single-use tokens bound to one exact node key and immutable policy scope. Redemption atomically stores the consume marker, replayable result and first signed policy in node-local SQLite; concurrent attempts cannot overwrite the winner, and a lost response can be replayed even after token expiry or revocation. Signed policy delivery adds monotonic revisions, rollback protection, persisted rotation history and overlap, a durable owner-visible equivocation alarm, and per-operation offline/expiry gates for enrollment and new peering. sage-gui org-token create|list|revoke exposes the operator flow.
No chain migration. App-v28 remains active and app-v29 remains compiled but dormant. Existing memories, identities, governance state and chain history are preserved. Container: ghcr.io/l33tdawg/sage:11.24.0. SDK 11.24.0.
What's New in v11.23.27
Find the exact MCP session before a handover. sage_sessions is a new read-only, self-only inventory of this agent's live MCP claimant sessions on the local node. It returns each exact session_id, transport kind, provider/project, whether it is the current session, liveness from the same OS advisory lock used by claimant identity acquisition, and the exact count of unfinished claims held by that session. Stale identity records are counted separately and are not presented as live sessions. The tool never claims, hands off, replies, or grants authority; session IDs remain coordination metadata, not authorization principals.
Access Group controls say what they do. CEREBRUM's Access Group editor now labels its close and delete actions accurately instead of putting Delete in the conventional close slot.
No chain migration. App-v28 remains active. The MCP catalog grows to 38 tools; clients with a cached catalog should re-list or reconnect. Container: ghcr.io/l33tdawg/sage:11.23.27. SDK 11.23.27.
What's New in v11.23.26
App-v28 activation now succeeds on legacy public corpora. The public-memory stage is built before the activation block's consensus transaction, so a record it could not encode aborted the activation on every replay and left the pending plan with no in-band downgrade. Records born before app-v25 whose canonical envelope lacks a domain, author, or author principal, carries a non-32-byte content hash, or carries a co-commit tombstone are now quarantined out of the committed public set instead of refusing the build. Records born under app-v25 or later still fail closed, and a recorded-but-empty or malformed field still refuses on every record. A record returns to the public set in the block that re-anchors its envelope.
Preflight now checks the corpus before the fork. sage-gui upgrade preflight runs the same read-only census as sage-gui upgrade public-memory-audit when a chain still has to cross app-v28, and refuses "clear to climb" when a record would block activation. The audit names every record, the exact failed checks, and whether the stage would quarantine or refuse it. --limit bounds the printed list; the counters still cover the whole corpus.
Quarantined records are visible, not silent. The audit reports them by memory id, and they stay outside the app-v28 public-memory tree until re-anchored. No chain migration is required; app-v28 remains active.
Container: ghcr.io/l33tdawg/sage:11.23.26. SDK 11.23.26.
What's New in v11.23.25
Unscoped recall works again on a mature node. An app-v23 node refuses a ranked recall whose candidate set exceeds its authorization scan budget rather than ranking an arbitrary prefix. On a node with a large corpus that made a domainless sage_recall fail permanently — the tool's default shape. Recall now falls back once to your governed home domain and reports the effective scope in domain, recall_scope and recall_scope_note, so an empty home-domain result is never read as proof the memory does not exist elsewhere. An explicitly scoped recall is never redirected.
Federated recall is bounded, and says why it is empty. /v1/federation/recall-plan now carries a server-side deadline with a per-peer budget, so one unreachable peer can no longer hold the request open until the caller gives up. An empty plan reports unavailable_reason — no_active_agreement, requested_chains_not_connected, peer_unreachable, domain_not_shared, planner_unavailable or federation_unavailable — instead of an empty error map that read as an authorization verdict. The reasons are aggregate by design and never name a peer.
Federated agents appear inside their Access Group. A federated agent linked to a local Access Group is now shown with the local members, with its authority stated. Federated write remains unavailable: it requires a consensus-bound federation ingress capability.
Product-specific bootstrap policy leaves core. A root-owned provisioning profile now drives init-fresh-personal-sage and check-private-config. SAGE core no longer carries any one product's home path, Unix account, or unit list. Products that shipped init-lantern-private must ship the profile and update their scripts before pinning this release.
App-v28 remains active and no chain migration is required.
Container: ghcr.io/l33tdawg/sage:11.23.25. SDK 11.23.25.
What's New in v11.23.24
Find agents across connected SAGEs in one call. sage_find_agent(name="...") searches this SAGE and caller-authorized contacts on connected SAGEs together by default. Exact name matches rank first in one bounded list. Local matches no longer hide remote matches, and same-named agents keep distinct exact addresses so you can choose the intended recipient.
Use scope="local" to search only this SAGE, or peer_chain to select one connected SAGE. If federated discovery cannot be verified, local matches remain available with an explicit incomplete flag. Cached contacts retain their caller-specific authorization checks, and each continuation still reads one bounded peer page.
MCP descriptions and message guidance now point to the combined lookup. After upgrading, re-list tools or reconnect clients with a cached catalog to load the new parameter and guidance. App-v28 remains active and no chain migration is required.
Container: ghcr.io/l33tdawg/sage:11.23.24. SDK 11.23.24.
What's New in v11.23.23
Close reviewed notices without replying. sage_message_close(message_id, reason) records an explicit “closed without reply” outcome for informational or withdrawn messages. Closing retains history and clears pending and unfinished inbox reminders across sessions and restarts. Exact-recipient pending messages need no claim; existing claims remain protected by their current session.
The close reason stays in recipient history and uses the content vault when enabled. Closures create no reply, read receipt, or sender reply activity. Inbound federated closure is local to the receiving SAGE. REST and both Python clients expose the same action, and startup nudges explain when to use it.
App-v28 remains active and no chain migration is required. Clients with a cached tool catalog re-list or reconnect to discover the new action.
Container: ghcr.io/l33tdawg/sage:11.23.23. SDK 11.23.23.
What's New in v11.23.22
Choose which agents a peer can find. Federation visibility uses the complete eligible roster instead of general registry entries that could make a partial selection fail. Search by name, provider, or ID, filter Visible/Hidden, and change an individual agent or only the agents matching your filters.
Review choices in one place. Compact rows, Save/Discard, and inline refresh controls keep visibility edits together. Filtered rows stay in place until saving, preserving keyboard focus. The peer's contacts have their own read-only view, while optional memory sharing and access settings are collapsed separately. Agents whose security policy blocks messages remain marked Not accepting.
Individual and filtered choices stay an exact selection, even when all current agents are selected. Show all agents explicitly includes future eligible agents. Visibility grants discovery only; memory access and message delivery keep their existing authorization checks.
App-v28 remains active and no chain migration is required.
Container: ghcr.io/l33tdawg/sage:11.23.22. SDK 11.23.22.
What's New in v11.23.21
Reliable inbox reply catch-up. The inbox now returns an explicit reply_watermark_candidate to save after processing the complete reply range. Its safety flags describe that inbox response and stay fixed while you page. For a truncated reply page, continue until sage_message_replies returns page_truncated=false, then use the candidate from the original inbox response as the next reply_since. An already complete inbox page needs no pager call. This replaces guidance that could send clients through the retained archive repeatedly.
Paging keeps its bounds. Each continuation supplies the next cursor with the same inclusive since and page limit. If the retained-reply pointer has no valid head, a returned reply page can still supply a candidate; a response with no valid candidate tells the client to omit reply_since on its next poll. Replies at the inclusive boundary remain deduplicated by message ID.
Clients carrying a tool catalog from before inbox v3 must re-list tools or reconnect to discover the existing sage_message_claim and sage_task_notice_ack actions. The server already advertises those tools and sends its tool-list change notification during runtime handoff.
App-v28 remains active and no chain migration is required.
Container: ghcr.io/l33tdawg/sage:11.23.21. SDK 11.23.21.
What's New in v11.23.20
Reading the inbox leaves work pending. sage_inbox now inspects messages and task notices without claiming messages, marking notices read, or creating a reply obligation. Agents accept one authorized message with sage_message_claim(message_id) and acknowledge one reviewed task notice with sage_task_notice_ack(notification_id). Message and task-notice pages advance independently, so a busy message inbox cannot hide task notices.
Agent integrations use the explicit acceptance contract. The old sage_messages_receive MCP tool is removed. Hooks, startup guidance, the Claude channel and the Python SDK use passive inspection; clients must explicitly claim a message before replying. Session ownership, signed federated receipts and recovery of existing claims remain enforced. Reconnect MCP clients after updating so they discover the 36-tool inventory.
Source builds and release builders move to Go 1.26.9, and both Go modules use golang.org/x/net v0.60.0 for the patched standard-library and HTTP/2 dependencies.
App-v28 remains active and no chain migration is required.
Container: ghcr.io/l33tdawg/sage:11.23.20. SDK 11.23.20.
What's New in v11.23.18
SQLite dependency maintenance. The SQLite driver moves to 1.60.1 with its matching libc dependency. This includes WAL shared-memory read-fault handling that returns an I/O error instead of crashing, plus faster argument binding for statements with many parameters. The embedded SQLite engine remains 3.53.4; Go tooling dependencies are also refreshed.
Reranker allocation checks. The reranker keeps its existing limit of 1,000 results. Its result slice now grows only within the capped selection loop, with no input-sized preallocation. Regression tests cover extreme limits, empty and oversized candidate pools, upstream failures and malformed scores.
The optional LoCoMo and LongMemEval benchmark environments now pin datasets==5.0.1, addressing GHSA-379c-qx7v-6h59 / CVE-2026-66007. Browser fixture tests use Playwright 1.63.0.
No consensus execution change, app-version change or chain migration; app-v28 stays active. The experimental, default-off local judge remains pinned to v16, with its runtime, thresholds and published qualification limits unchanged.
Container: ghcr.io/l33tdawg/sage:11.23.18. SDK 11.23.18.
What's New in v11.23.17
The optional local judge is now pinned to v16. On the disclosed frozen 40-item synthetic regression set, the attributed tank-warning example moves from rejection to operator review. All 18 genuine examples avoid rejection: 16 pass and two hold. All 22 negative examples still reject. These results were independently measured on Linux/arm64 with Ollama v0.31.1; they do not establish fresh-holdout accuracy or qualify production installation on every platform.
Select SAGE_LOCAL_JUDGE_MODEL=sage-memory-judge:v16 to use the new pin. The memory gate remains experimental and off by default; upgrading does not rewrite an explicit v15 setting. The download uses an immutable Hugging Face revision with separate SHA-256 pins for the downloaded GGUF and Ollama's registered blob. Thresholds, serving template and runtime are unchanged. See the memory-gate guide and v16 regression results. Thanks to @ihubanov for the update.
No consensus execution change, app-version change or chain migration; app-v28 stays active.
Container: ghcr.io/l33tdawg/sage:11.23.17. SDK 11.23.17.
What's New in v11.23.16
Task creation starts at 0.90 across MCP. When confidence is omitted, sage_remember(type="task") now matches sage_task; other memory types keep their 0.80 default. Corrections resolve the inherited memory type before choosing the default. Explicit scores, including 0 and 0.80, are preserved; malformed, non-finite and out-of-range scores are rejected. The tool schema describes the conditional defaults without inserting a fixed value that could override correction inheritance.
Submission receipts report the score that was signed. submitted_confidence appears on submitted sage_remember writes, including corrections and indeterminate outcomes, and on sage_task creation, replay and committed-but-unconfirmed receipts. It describes the request, not a later stored or query-time score. Skipped or rejected pre-validation and task-status updates do not report a submitted score.
Existing memory scores and task idempotency checks remain intact. There is no consensus execution change, app-version change or chain migration; app-v28 stays active and the qualified v15 local judge pin is unchanged.
Container: ghcr.io/l33tdawg/sage:11.23.16. SDK 11.23.16.
What's New in v11.23.15
MCP stdio bridges exit when their client process dies. Inherited pipes can keep a bridge's input open after its client has gone. SAGE now watches the original parent process, cancels its tools and subscriptions on confirmed parent exit, and bounds cleanup even when input or output is blocked. An idle client keeps its bridge.
Correction lineage resolves by content hash in CEREBRUM. The graph and related-memory view find the parent of a correction through bounded metadata lookups on SQLite and PostgreSQL. Legacy exact-ID pointers still work; ambiguous hashes and hidden parents do not expose a lineage edge or memory body.
A malformed reranker response preserves the original recall results. Missing, duplicate or invalid candidate indices and non-finite scores now discard the reranking response as a whole, keeping the existing reciprocal-rank-fusion ordering. The optional reranker remains off by default; its guidance now asks users to compare relevance and latency on their own queries.
Federation and message failures explain the next step. Local storage and target-resolution failures, plus failed requests to known peers, include bounded diagnostics and remedies. Route diagnostics report only attempted candidates and omit credentials, payloads and peer response bodies. Messaging controls also explain that blocking delivery does not hide an agent from discovery.
The release removes unused memory-transition helpers, expands bounded CI coverage, and documents reproducible retrieval benchmarks and the limits of the public research artifacts. No consensus execution change, app-version change or chain migration; app-v28 remains active. The local judge model stays pinned to the qualified v15 artifact.
Container: ghcr.io/l33tdawg/sage:11.23.15. SDK 11.23.15.
What's New in v11.23.14
MCP tool calls stay responsive while another tool waits on HTTP. Stdio now runs up to 16 tool requests concurrently and reads cancellation notifications immediately. A slow history read can no longer hold later independent tools or the tool registry behind it. Cancellation stops the matching request context; an indeterminate write still requires its normal reconciliation.
AMID restores unresolved signer fences before it starts serving. A private, node-local SQLite ledger preserves identity-only submission intents across process exits. Startup refuses an unreadable or malformed ledger, and a restored fence settles only on chain-proven fate. Disabling the REST validator key also removes the inherited key from ordinary signing paths. A proven fence finishes its durable cleanup before reopening the signer, so a fast next submission cannot lose its new recovery record to the prior cleanup.
Block sync rounds quorum-blocking power up correctly. A validator with power 1 out of 4 no longer leaves block sync early. Actual quorum-blocking power keeps its existing behavior.
An optional local judge checks lasting knowledge and its submitted evidence. Set SAGE_LOCAL_JUDGE_MODEL=sage-memory-judge:v15 to use SAGE's verified local model through its managed Ollama runtime. It remains experimental and off by default. Judge traffic is restricted to loopback, cloud aliases and mismatched model blobs are refused, and an unavailable judge holds proposals for operator review. Public seed-set qualification on SAGE's pinned runtime passed with external networking blocked; support precision was 97% with one accepted trap, and lasting precision was 100%. See the memory-gate guide and runtime qualification report for configuration and limits. Thanks to @ihubanov for the contribution.
No consensus execution change, app-version change or chain migration.
Container: ghcr.io/l33tdawg/sage:11.23.14. SDK 11.23.14.
What's New in v11.23.13
REST submissions keep their acknowledgment through the full write budget. A memory could commit after the server's response deadline had expired, leaving the caller with a connection error instead of the result. The deadline now accounts for embedding retries, the bounded nonce-lease wait and the consensus commit wait, with time for the response. The default is 285.75 seconds and the combined budget is capped at ten minutes; larger custom settings can still outlast that cap.
Vault recovery verifies the key before replacing vault.key. An invalid recovery key is refused before it can overwrite the existing vault key file.
This patch retains the memory gate shipped in v11.23.11. The unreleased evidence checks, managed local judge and model work are deferred. There is no consensus execution change, app-version change or chain migration. The cancelled v11.23.12 tag remains unchanged.
Container: ghcr.io/l33tdawg/sage:11.23.13. SDK 11.23.13.
What's New in v11.23.11
An optional memory-quality gate can hold uncertain memories for review. Set SAGE_HUNCH_URL to enable a background judge for proposed memories, with domain include/exempt settings controlling which memory text reaches the service. Built-in checks still run on every vote, and Settings → Memory gate lets the operator accept or reject held memories. The gate is off by default, supports SQLite stores, and does not change consensus or recall. See the memory-gate guide for configuration and limits. Thanks to @ihubanov for the contribution.
A provably stale memory vote can release its signer fence. When a vote's target has already committed, a stale-vote mempool filter can reject every retry before it reaches an indexed block result. SAGE now recognizes a narrow, versioned refusal for complete canonical memories submitted after app-v25 activation. The resolver binds that refusal to the exact signed vote and rechecks the transaction index before reporting its outcome. Ordinary CheckTx 13 errors and historical or incomplete targets keep the fence held.
CLI help is inert. Asking for serve --help, setup --help, or mcp --help returns usage before command dispatch, configuration, or instance locking, without creating home or project files.
Inbound federated messages wake their exact local recipient. Wake allocation commits atomically with message admission and transport deduplication. Duplicate or rolled-back deliveries cannot create extra wakes, and startup catches up existing unfinished inbound work.
No consensus execution change, transaction-type change, upgrade height, or chain reset. AMID operators must preserve unresolved transaction identity and signed bytes during maintenance: cmd/amid does not wire the durable-intent restore hooks used by sage-gui, so restarting it is not a fence-recovery proof.
Container: ghcr.io/l33tdawg/sage:11.23.11. SDK 11.23.11.
What's New in v11.23.10
A held signing key can no longer park the node's whole write path. A signer fence refuses every write from its key while it waits for proof of an earlier submission's fate, and that wait was bounded only by the caller's context — which the submit path passed as context.Background(), a context that never cancels and carries no deadline. The one goroutine holding the node's single signing lease sat there for as long as the fence stood — one observed node carried handlers parked 122–768 minutes — and every later writer for that key queued behind it on the same size-one lease, including the automatic reconciler whose job is to settle the fence and release it, so the hold could not clear itself. Reads stayed fast and denied writes still failed fast, which is why the incident reached the operator as writes time out, no error. WithNonceLease now derives a bounded wait (90 s) when the caller supplies no deadline, so a held fence fails retryable instead of parking, the lease is released, and the reconciler is no longer starved by the fence it exists to lift. A caller that supplies its own shorter deadline keeps it.
Background work the embedded web handler starts can no longer outlive the store it writes to. That handler started goroutines with no lifecycle owner, and unowned work that outlived its caller's store touched a closed database and panicked the process — first seen inside this repository's own suite, where one test's projection audit tore down another test's store. Unowned background work is counted now, and a caller that owns the stores drains it with WaitBackground before closing them.
Build and tooling. Local make builds pin to the host architecture instead of assuming amd64, and a Codex session started in a checkout inherits that checkout's Codex pin from .codex/config.toml — the counterpart of the existing .mcp.json Claude Code pin, so one workspace can carry both providers' pins. Dependency groups were refreshed.
No consensus change, no transaction-type change, no upgrade height, and no chain reset.
Container: ghcr.io/l33tdawg/sage:11.23.10. SDK 11.23.10.
What's New in v11.23.9
CEREBRUM now shows a held signing key. A signer fence refuses every write from its key and every coordinated restart while it waits for proof of an earlier submission's fate, and until this release the dashboard said nothing about it — the field report that produced the fence workstream read from the outside as reads are fine, writes time out, no error. System Status gains a row that appears only while a key is held: how many keys and how long, the node's own explanation of why the hold is deliberate, and one line per fence naming its resolution. reconciling means the identical bytes are still being re-submitted and it clears itself; waiting on proof means the signed bytes did not survive the process, so the chain or an operator has to settle it. Each line carries the nonce, how long the key has been held, the attempt count and the last recorded detail.
A hold that ends stays visible. The row above disappears with the fence, which left no way to tell it lifted while I was reading from it never happened. The last resolution is now kept and rendered — committed, rejected, spent, or resolved without a proof — so a fence that cleared itself is still on screen afterwards.
Two details that make the numbers trustworthy. The nonce crosses the wire as a string: SAGE nonces are nanosecond allocations that exceed JavaScript's safe integer range, and as a JSON number it reached the browser silently rounded, in the one place the operator compares it against the chain. And the panel never suggests restarting to clear a hold — a restart discards the fence and loses the transaction it protects, which is the failure the whole mechanism exists to prevent.
No consensus change, no transaction-type change, no upgrade height, and no chain reset.
Container: ghcr.io/l33tdawg/sage:11.23.9. SDK 11.23.9.
What's New in v11.23.8
A node stops manufacturing signer fences on an ordinary quit. Since the fence landed, every coordinated restart has drained signing before it committed, so its teardown could not sever a broadcast mid-flight. A plain signal or a serve error had no such drain: the HTTP force-close could catch a submission, raise an indeterminate outcome, write a durable fence record, and cost that payload at the next start — the fence can only lift on a proof, and a live one whose re-submission is refused by anything other than the nonce gate has no proof to reach. The ordinary exit now drains the same way the restart does: signing is quiesced, in-flight submissions get a bounded five-second window to finish, and only then do the listeners close. Signing is deliberately not resumed, because the process is leaving; an operator-ordered exit is never vetoed by the drain; and a submission that cannot finish in the window fails closed onto the durable record and the restored fence.
sage-gui fence abandon works on a node that keeps a peer. The credential-free operator exit added in 11.23.6 applies the same evidence gate as the daemon's abandon route, including its second acknowledgement for connected peers — a peer is a route the abandoned bytes could still take back into this node's mempool. The CLI had no way to carry that acknowledgement, so on a federated desktop node or a validator with a persistent peer it could only ever refuse and point at a field it had no way to set. --peer-redelivery-acknowledged now carries it, fence list names the requirement when peers are connected, and every unproven record states the restart step: a running daemon keeps holding the key until it restarts, and the durable record is what the next boot restores from.
No consensus change, no transaction-type change, no upgrade height, and no chain reset.
Container: ghcr.io/l33tdawg/sage:11.23.8. SDK 11.23.8.
What's New in v11.23.7
A node that has activated app-v28 can install its own updates again. The signed update flow takes a pre-upgrade recovery snapshot and proves it before it touches the installed app: the manifest carries the AppHash the running chain committed, and the proof restores the Badger backup and re-derives that digest from the restored bytes. Since app-v28 the committed AppHash is the public-memory composite commitment — the app-v13 digest of the state WITHOUT the public-memory index nodes, composed with the sparse index root — and the proof only knew the three earlier eras. Every app-v28 node therefore refused its own recovery snapshot, and the field report was exactly this shape: Failed to install signed app update: verify pre-upgrade snapshot: ... AppHash mismatch under every hash rule (legacy/app-v12/app-v13), with the update stuck on the snapshot step and no way forward from inside the app.
What now happens: the composite joins the candidate set, read through the same internal/store implementation the commit path uses instead of a second copy of the rule — the state-sync provider verification path already went stale exactly that way once, refusing every v28 provider while every pre-v28 chain stayed green. A pre-v28 state carries no public-memory commitment, so the composite is reported as not-applicable there and the three older candidates decide alone. The mismatch message now names the rules that were actually tried.
If you are reading this from an app-v28 node on 11.23.6 or earlier, read this part. The gate that just failed runs inside the binary you have installed, so that binary cannot install this release either — and the same gate vetoes a version-changing restart. Installing 11.23.7 once by hand is the path out: quit SAGE, drag SAGE.app from the DMG into /Applications, relaunch. Every update after that one works from inside the app again.
No consensus change, no transaction-type change, no upgrade height, and no chain reset.
Container: ghcr.io/l33tdawg/sage:11.23.7. SDK 11.23.7.
What's New in v11.23.6
A fence on a quiet chain settles itself, and the operator has a way in when it cannot. SAGE chains are idle by design: since app-v12 every node sets create_empty_blocks=false, so a block is minted exactly when a signed transaction enters the mempool and the chain sits still otherwis
... (README truncated for length)