Repository navigation
Release Notes 1.4.12
Released: 2026-11-03
This release makes write scope a project-level decision, adds captures that retire themselves on a deadline, and collapses the CLI to one verb per job. Alongside that, memory correction authority is now enforced uniformly across REST, MCP, and the promotion path, and scheduled backups stream instead of holding a whole namespace in memory.
🌟 Highlights
✨ Per-project default write scope
Projects now carry a default_memory_scope (private or project, default private). Captures without an explicit --scope follow the project default, so the CLI and MCP finally agree on where a write lands. Set it with sibyl project update <project> --default-scope project, through the new GET/PATCH /projects/{id}/settings routes, or from the Private/Shared toggle on the project page (project managers only). POST /memory/raw reports how scope was resolved in scope_resolution, and an explicit --scope still wins.
✨ Time-boxed captures that expire through the correction path
sibyl remember --expires 4h writes a raw capture with a deadline between 1 minute and 30 days. The expire_time_boxed_captures job runs every minute (Redis cron plus the in-process scheduler) and retires due captures through the normal correction path with reason expired, so lineage and disclosure behave as they do for any other retirement. Deadlines are server-owned under metadata.expires_at; callers cannot forge or extend them. POST /memory/raw accepts expires_in or expires_at, MCP remember accepts expires, and context packs mark raw notices with expires=. --expires refuses --key, --related-to, --task, and --wait-searchable.
🔥 One verb per job in the CLI
Reading memory is sibyl context. Writing memory is sibyl remember. search, recall, add, capture, note, and blame are gone, along with every hidden pre-1.2 alias (graph-search, graph-add, tasks, contexts, memory-*, pending-writes claim, task get). sibyl dev leaves the user binary: it wrapped docker compose for the repo devcontainer and shipped to everyone who could not use it. See Breaking Changes for the full mapping.
🐛 Correction authority enforced on every path
Changing someone else's project capture now requires a project maintainer grant, whether it arrives through the REST preview/apply pair, MCP correct_memory, a capture review-state PATCH, promotion invalidation, or review-drain archiving. Graph writes through POST /entities authorize their declared memory scope the same way the raw route already did, and API-key project binding is honored on project admin routes.
⚡️ Backups stream, restores land in bounded batches
The scheduled backup pages captures into a staging spool instead of materializing a namespace. On a 4k-entity namespace, peak memory drops from 2.9 GB (SurrealDB) and 2.5 GB (API) to 588 MB and 247 MB. Archive restores write at most 200 rows per transaction behind a server-side state digest, so a WebSocket keepalive timeout no longer strands a half-written namespace: interrupted restores leave whole units and a rerun finishes the job.
🔐 Memory scope and authorization
--scope organd--scope organizationare refused with a direct message: organization scope is not enabled yet, useprojectorteam.--propose-scope teamaccepts--propose-scope-key <team-uuid>so a proposal can name its target team. It is a hint; promotion still re-runs team membership policy.- Promotion resolves the caller's team membership for every entry point, and previews now receive the same API-key grants as apply, so a preview cannot promise what apply will refuse.
PATCH /projects/{id}/settingsrequires a memory space grant for project-bound API keys.- CLI
rememberrows bind to their raw capture only after projection proof, socorrectreaches them instead of stopping at an unlinked row.
🐛 Retrieval and recall fixes
- Project-narrowed node lanes admit project-less rows again (unscoped rows, the reader's private rows, legacy rows), which had been hidden from keys with a single project binding.
- A graph row's memory scope is read from its indexed column when the attribute stamp is missing, across node lanes, search, and related-entity lookups.
- Capture sidecars are filtered out of the author's private raw recall, so a remembered memory stops appearing twice.
- Remembered captures file under their verified project; foreign private rows are filtered in SQL, and a content migration backfills sidecar projects.
- Memory descriptions stay out of context-pack payloads for memory-shaped rows; BM25 terms still match without shipping the description.
🔧 CLI behavior
- Stored text prints verbatim. Values interpolated into terminal output (names, titles, descriptions) go through
rich.markup.escape, so a capture containing[bold]renders as written. - Read-only POSTs are never parked as pending writes: memory, reflection, and share previews, space-access preview, and
/synthesis/plan. - A write the server refuses on its first attempt with 404, 403, or 422 is dropped instead of nagging. 409 stays queued, since it can mean the write landed.
--content-filetrusts root-owned symlinks only at the filesystem root, which keeps the guard intact on macOS/tmpand/varlinks, and the error names the offending path.- Import draining is one helper (
source_imports.finish_import) shared byingestanddocument, with one error handler and one source-import receipt printer behind it. - The per-process circuit breaker and the queued-read class are deleted. The breaker protected nothing across short-lived CLI processes and only slowed queue replay.
🖥️ Web
- Long unbroken tokens in sidebar task names wrap inside their card, and the Focus query is clamped to three lines.
- The project page gains the Private/Shared default-scope toggle for project managers.
✅ Testing and CI
- The default memory loop smoke test moved to
apps/api/tests/test_default_memory_loop.pyso it runs on every PR instead of skipping on core shards that lack FastAPI. - E2E runs reuse the baseline seed session through
SIBYL_E2E_ACCESS_TOKEN, cutting the runner from four-plus logins per job to two.apps/e2e/tests/browser/test_login_budget.pyfails the run at five or more logins per client address, below the rate limiter's threshold. - Helm publication waits only on the chart package and the images it names, not on the Python, Homebrew, and AUR channels. An expired tap token no longer blocks chart users; release promotion still gates on all channels.
- New coverage for capture expiry, capture retirement authority, archive streaming and restore batching, project-admin API-key scope, project default scope, retrieval project-less rows and scope columns, markup escaping, and remember/correct binding.
📦 Dependencies
websocketsfloored at 17.4 inapps/cli. 17.4 is the release carrying the security fix forrecv()having no cap on fragments per message, which let a peer exhaust memory; every implementation was affected and the CVE is still pending, so image scanners cannot see it yet. The 17.0 breaking changes (removed pre-9.0 module aliases, keyword-only booleans onsend(),ping(),broadcast(), Latin-1 handshake headers) touch no call site here or in the SurrealDB SDK.google-genaimoves to 2.34, the first line that accepts websockets 17.pyasn1floored at 0.6.5 to clear four HIGH findings in the API image CVE scan.pydantic-ai-slimpinned to >=2.60,<2.61, bringingpydantic-graph2.60 andgenai-prices0.2.0.sibyl_core/ai/prices.pyis deleted: genai-prices now prices the models Sibyl supplemented (Haiku 5.5 long-prompt tiers, Sonnet 5.5 cache reads, GPT-6.1 Sol's 272K tier, Bedrock global and geography profiles), which was verified before merge.tests/ai/test_prices.pykeeps the dollar assertions, now made directly against genai-prices. The local Haiku 5.5 profile patch is removed for the same reason.tyfloored at 0.0.91 across the workspace, core, api, and cli, with no new diagnostics under error-on-warning.- Web runtime and dev groups move:
@tanstack/react-query5.104.5,@tanstack/react-virtual3.14.22,lucide-react1.65.0,motion14.9.0,next16.4.3, Biome 2.6.4, Storybook 10.6.5. - Tooling locks move to
ruff0.17.3,pytest9.2.0,playwright1.64.1, andastral-sh/setup-uvv10.3.3 in CI.
⚠️ Breaking changes
All of the following are CLI surface removals. Update scripts, agent skills, and shell aliases before upgrading.
| Removed | Use instead |
|---|---|
sibyl search "<query>" |
sibyl context "<query>" |
sibyl recall "<query>" |
sibyl context "<query>" |
sibyl add "<title>" "<content>" |
sibyl remember "<title>" "<content>" |
sibyl capture "<text>" |
sibyl remember "<title>" "<text>" (titles are no longer derived) |
sibyl note <task-id> "<text>" |
sibyl task note <task-id> "<text>" |
sibyl note "<text>" |
sibyl remember "<title>" "<text>" --kind note |
sibyl blame <id> |
sibyl correct <id> |
sibyl graph-search / sibyl graph-add |
sibyl context / sibyl remember |
sibyl tasks |
sibyl task list |
sibyl task get |
sibyl task show |
sibyl task create --sync |
sibyl task create (the flag did nothing) |
sibyl contexts ... |
sibyl config context ... |
sibyl memory-space|review|audit|inspect|import-status|promote|share |
sibyl admin memory <subcommand> |
sibyl pending-writes claim |
sibyl pending-writes adopt |
--kind gotcha |
--kind error_pattern |
--kind learning |
--kind note |
sibyl dev shell|up|down|status |
docker compose -f .devcontainer/docker-compose.yml exec|up|down, or open the devcontainer from your editor |
Other behavior changes worth checking:
--scope orgis rejected. Organization scope is not enabled; useprojectorteam.- MCP captures in unshared projects now land in
privaterather thanproject, unless the project's default says otherwise. - Read-like POSTs are no longer queued. Entries previously parked as read-like are dropped when the queue is read;
pending-writes discard --read-likeis gone with the class. - Correcting another author's project capture requires a maintainer grant. Contributor-level automation that edited other people's captures will now get a 403.
📝 Upgrade notes
- Run
sibyl migrate(or let the API migrate on boot) to apply auth migration 11 and content migration 57. Auth 11 definesprojects.default_memory_scopeas a string field defaulting toprivate, constrained toprivateorproject, and backfills existing rows. Content 57 defines theidx_raw_captures_expires_atindex over the server-ownedmetadata.expires_atkey; expiry deadlines live in the capture metadata bag, not as newraw_capturescolumns. A further content migration backfills projects onto capture sidecars. - Grep CI jobs, agent skills, hooks, and shell functions for the removed verbs and aliases in the table above. There is no deprecation shim this time.
- Decide each project's default write scope. Everything stays
privateuntil you set it:sibyl project update <project> --default-scope project. - If you pin
sibyl-devtransitively, make surewebsockets>=17.4resolves. Earlier 17.x releases still carry the unboundedrecv()fragment behavior. - Self-hosted API images should pick up
pyasn1>=0.6.5to keep the image scan clean. - If you run E2E suites in your own CI, pass the seeded session through
SIBYL_E2E_ACCESS_TOKENto stay under the login rate limit; seeapps/e2e/README.md.
Install
Local server
curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --version 1.4.12Remote CLI
curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --remote --version 1.4.12
sibyl init --remote https://sibyl.example.com
sibyl auth loginHomebrew
brew install hyperb1iss/tap/sibyl
sibyl upArch Linux (AUR)
paru -S sibyl
sibyl upHeadless server
curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --version 1.4.12 --no-openKubernetes (Helm)
helm repo add sibyl https://raw.githubusercontent.com/hyperb1iss/sibyl/gh-pages
helm repo update sibyl
helm upgrade --install sibyl sibyl/sibyl --version 1.4.12Artifacts
This release includes Python wheels and sdists, the generated
Homebrew formula, the generated AUR PKGBUILD, Helm charts, Docker
SBOMs, aggregate dual-registry cosign receipts, and a SHA256 checksum
manifest.