Repository navigation
v1.4.4
Release Notes v1.4.4
Released: 2026-10-06
This release finishes the team migration story: a project's graph now moves to a team server alongside its raw memories, retries stop at teammate edits instead of writing over them, and the whole migration can be undone. Supporting that are new revision-guarded entity write paths, typed publication staged inside native transactions, a stricter health probe, and fixes for two high-severity dependency advisories.
Highlights
✨ Move a project's whole graph to a team server
sibyl migrate to-team now runs a second pass over the graph (--graph, on by default; --no-graph to skip). Tasks, epics, milestones, decisions, procedures, notes, and their links are recreated on the team server in topological order through POST /entities/bulk and the new links endpoint. Derived rows (topics, passages, mention edges) are left out so the target re-derives them. Everything is written through the authenticated API as the caller, so no cluster or database access is needed. See the new docs/cli/migrate.md.
✨ Undo a team migration without touching anyone's work
sibyl migrate to-team --undo removes what the migration created and nobody has changed since, working from the migration ledger alone. Rows a teammate edited, rows something outside the migration links to, and rows the migration adopted rather than created are all kept. Deletes name the exact revision the migration last wrote, and the server re-checks it under lock. Pair with --dry-run to preview the outcome via GET /entities/{entity_id}/deletable.
🐛 Retries no longer overwrite teammates
When a migration retries after a lost response, writes land through EntityManager.create_direct_authorized(), which calls replace_authorized_entity() in the new sibyl_core.services.graph_write_authority module. If an entity identity already exists under a different owner or project, the write is refused ("Entity identity already exists under another owner or project"). The upsert itself is fenced on a snapshot fingerprint taken before the write: if the row changed in between, the transaction returns 'changed write authority' and the write is rejected rather than applied. Link writes carry expected_revision so topology additions fail closed on concurrent edits.
✨ Typed publication staged in native transactions
stage_native_typed_graph_publication() collects, validates, and stages a typed graph entity inside a caller-owned transaction and never commits it. The caller decides whether to commit or seal the handle with the new NativeTransaction.invalidate(). Source evidence is captured as PublicationSourceEvidence records (namespace, database, row and state hashes) on the returned StagedTypedGraphPublication, and concurrent writes to referenced sources are caught by witness checks before commit instead of after.
🔧 Health reports unhealthy when auth storage is unreadable
A running API could previously report healthy while unable to read auth storage. The readiness probe now performs a bounded auth-store read (SELECT id FROM users LIMIT 1) and returns 503 with dependency detail when it fails. No per-org namespaces are queried and no auth records reach the response body.
Team Migration
sibyl migrate to-teamgained--graph/--no-graph,--undo,--target-project,--share-private,--allow-personal-org, and--limit, alongside the existing--target-context,--project,--source-org, and--dry-run.- Graph creation is ordered by class so containers land before their contents: epics and milestones first, tasks second, everything else after. Links are declared once their targets exist.
- An epic or milestone a teammate already created under the same name is adopted rather than duplicated, and adopted rows are recorded so
--undonever removes them. - Each row keeps a stable idempotency key across retries (
migration-raw:<sha256>,migration-create:<sha256>,migration-links:<sha256>), so a replayed request returns the original receipt instead of writing twice. - Where an earlier outcome is genuinely unknown, callers can pass
replay_interrupted=falseto refuse blind re-execution; the server answers 409 and the ledger retains the request body for reconciliation. - New CLI test coverage in
apps/cli/tests/test_migrate_graph.pyand expandedtest_migrate_to_team.py.
API Changes
POST /entities/{entity_id}/links(new, inapps/api/src/sibyl/api/routes/entity_links.py): adds missing links to an existing entity without replacing its content. Requiresexpected_revision(≥1) and acceptsrelated_to,epic_id,parent_task_id,depends_on. Responds withEntityLinksResponsecarrying the newrevision,added_relationship_ids,existing_relationship_ids, andreplayed. Revision mismatches return 409.GET /entities/{entity_id}/deletable(new): dry-runs the checks a guarded unshared delete would run and reportsdeletableplus a reason, without deleting anything.DELETE /entities/{entity_id}: newexpected_revisionandif_unsharedquery params. Withif_unshared=true, the delete is refused with 409entity_sharedwhen a row outside the entity's own migration links to it. Derived rows and the project itself do not count as sharing.POST /entities: newprotect_ownershipandreplay_interruptedquery params.protect_ownership=truerequires an authenticatedsync=truerequest and returns 422 otherwise. The response now includesrevision. When anepicis supplied on a synchronous create, the epic's existence is now verified before the row is filed (if epic and is_syncinentity_mutations.py).PATCH /tasks/{task_id}: newreplay_interruptedquery param, an added epic-existence check on the update path, and anepic_startedkey in the response payload when a status change starts the parent epic.PATCH /entities/{entity_id}now recordsmodified_byfrom the authenticated user.
Graph Internals
- New
sibyl_core.services.graph_write_authorityexportsrow_author(),row_project(), andreplace_authorized_entity(). - New
sibyl_core.services.graph_link_writesandgraph_publication_fencemodules back the links endpoint and staged publication respectively. EntityManager.delete_many()deletes several entities and their edges in one transaction, using per-id equality predicates so each statement stays index-served rather than scanning the table.source_state_storegainedNativeSourceCut,load_native_source_cut(), andcheck_native_source_cuts()for engine-hashed physical evidence.bulk_identity_parts()was extracted inentity_serialization.py, and bulk-created entities now carrycreated_by.
Operations and Security
- The API runtime image now applies Debian security upgrades during build, clearing critical and high advisories in
perland its bundled modules that the pinneddebian:12-slimbase still shipped. sharplifted to 0.35.5 (GHSA-wq5f-xc86-pv6w) andsource-map-jsto 1.2.2 (GHSA-68fv-2mgg-jv7q), both high-severity advisories in packages shipped by the web app.pnpm audit --prodis clean again.- Dependency rollup:
uvicorn[standard]0.53.0,pyjwt[crypto]2.14.0,ty0.0.84, plus Biome, Playwright, Vitest, Mermaid, and TanStack Query updates.pydantic-ai-slimstays pinned under its<2.52cap because 2.52 changes structured-output and tool-choice behavior. - Docs theme now imports Mermaid through the bundler, so architecture diagrams render.
Reverted
- Abstained chain retirement (
fix(memory): retire abstained chains without changing evidence) was reverted. Routing native reflection ids through the capture-availability projection hid reflections published withreflect_memory(persist=True)from recall. Memory persistence behaves as it did in 1.4.3; the change will return once the default memory loop smoke test passes.
Upgrade Notes
- Check your health probe expectations.
/healthnow returns 503 when auth storage cannot be read. If a deployment was passing probes while auth storage was degraded, it will now be marked unready. Confirm auth storage connectivity before rolling out. - Rebuild or repull the API image to pick up the Debian security upgrades.
- Reinstall JS dependencies so the
sharpandsource-map-jsoverrides take effect; verify withpnpm audit --prod. - Existing clients need no changes:
replay_interrupteddefaults totrueandprotect_ownershipdefaults tofalse, preserving prior behavior. Opt in only where you need the stricter guarantees. - Running
sibyl migrate to-team --undorequires project maintainer access on the target server, since graph deletes are maintainer-gated. Preview with--dry-runfirst.
Install
Local server
curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --version 1.4.4Remote CLI
curl -fsSL https://raw.githubusercontent.com/hyperb1iss/sibyl/main/install.sh | sh -s -- --remote --version 1.4.4
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.4 --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.4Artifacts
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.