diff --git a/.claude-plugin/skill-assets.sha256 b/.claude-plugin/skill-assets.sha256
index cbd00041..2f565d53 100644
--- a/.claude-plugin/skill-assets.sha256
+++ b/.claude-plugin/skill-assets.sha256
@@ -2,5 +2,5 @@
94bfa06317a8fe6a6a7e204bb70c5abdc9e4bbc34d79dd6f8447a30140bc8b85 .claude-plugin/plugin.json
055655db84af07561d002f0c69744313d8413c39f3e873f941f0fa0b1e76dc66 skills/engraphis-memory/references/CONVENTIONS.md
62019760766ff472a76a0f81437898f39e3c1fe2631732b7b7733e50c1ad837f skills/engraphis-memory/references/SCOPING.md
-4ce83a2768680ec84488a767fc3bd6cd62688d785010a0abd1d4b3edbf14d03a skills/engraphis-memory/references/TOOLS.md
-605181000a20a808e570b00cd2e852561f21234f041db03ade73f533b0e8bdaf skills/engraphis-memory/SKILL.md
+96c8e9b9cee1b3cb43c4bef9e48c57ed92af707f7f7a5d28d73b1ac247d2f0c6 skills/engraphis-memory/references/TOOLS.md
+0f98098df695b9a00dc78402911124ebf09a4a058f6c8bec2c6234ec61fac13a skills/engraphis-memory/SKILL.md
diff --git a/.dockerignore b/.dockerignore
index 7848fc73..8616b6df 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -63,3 +63,6 @@ playwright-report
*.log
*.whl
*.tar.gz
+# Test suites and evaluation harnesses — not needed in production images.
+tests/
+eval/
diff --git a/.env.example b/.env.example
index 8ace22b2..d009335b 100644
--- a/.env.example
+++ b/.env.example
@@ -321,9 +321,6 @@ ENGRAPHIS_LLM_MODEL=gpt-4o-mini
# rerankers when ENGRAPHIS_REQUIRE_IMMUTABLE_MODELS=1.
# ENGRAPHIS_RERANK_REVISION=
-# Workspace allow-list: comma-separated names. Empty = all allowed.
-# ENGRAPHIS_WORKSPACES=acme,personal
-
# Cloud Sync relay: endpoint and optional token for self-hosted relay.
# ENGRAPHIS_RELAY_URL=https://relay.example.com
# ENGRAPHIS_SYNC_TOKEN=
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f4407534..d18fc4ac 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -12,6 +12,7 @@ jobs:
test:
name: test + lint (full offline stack)
runs-on: ubuntu-latest
+ timeout-minutes: 45
strategy:
fail-fast: false
matrix:
@@ -51,6 +52,7 @@ jobs:
typecheck:
name: core + backends typecheck (Python 3.11)
runs-on: ubuntu-latest
+ timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
@@ -68,6 +70,7 @@ jobs:
encryption:
name: encryption driver gate (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
+ timeout-minutes: 15
strategy:
fail-fast: false
matrix:
@@ -94,6 +97,7 @@ jobs:
core-py39:
name: core floor (numpy-only, Python 3.9)
runs-on: ubuntu-latest
+ timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
@@ -161,6 +165,7 @@ jobs:
coverage:
name: coverage gate (Python 3.11)
runs-on: ubuntu-latest
+ timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
@@ -178,6 +183,7 @@ jobs:
hygiene:
name: repo hygiene gate (no stray DBs/logs)
runs-on: ubuntu-latest
+ timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Reject stray runtime artifacts at repo root
@@ -192,6 +198,7 @@ jobs:
pi-extension:
name: Pi extension (${{ matrix.os }}, Python ${{ matrix.python-version }}, Node ${{ matrix.node-version }})
runs-on: ${{ matrix.os }}
+ timeout-minutes: 20
strategy:
fail-fast: false
matrix:
@@ -229,6 +236,7 @@ jobs:
browser-accessibility:
name: browser accessibility smoke
runs-on: ubuntu-latest
+ timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
@@ -254,6 +262,7 @@ jobs:
# pyproject.toml, or this workflow). No third-party actions — plain git diff.
name: docker smoke — path gate
runs-on: ubuntu-latest
+ timeout-minutes: 5
outputs:
run: ${{ steps.decide.outputs.run }}
steps:
@@ -274,6 +283,7 @@ jobs:
docker-smoke:
name: docker build + health smoke
runs-on: ubuntu-latest
+ timeout-minutes: 20
needs: docker-gate
if: needs.docker-gate.outputs.run == 'true'
steps:
@@ -312,7 +322,8 @@ jobs:
trap cleanup EXIT
python -m pip install --disable-pip-version-check --no-cache-dir pip-audit==2.10.1
docker create --name "$container" engraphis:ci >/dev/null
- docker cp "$container":/usr/local/lib/python3.11/site-packages/. "$audit_dir"
+ site_packages=$(docker run --rm engraphis:ci python3 -c "import sysconfig; print(sysconfig.get_path('purelib'))")
+ docker cp "$container:$site_packages/." "$audit_dir"
python -m pip_audit --path "$audit_dir"
- name: Run container (offline deterministic embedder — no model downloads)
run: |
@@ -343,6 +354,7 @@ jobs:
build:
name: build + install wheel
runs-on: ubuntu-latest
+ timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0f9acac3..1da7d229 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -19,6 +19,7 @@ jobs:
build:
name: Build distributions
runs-on: ubuntu-latest
+ timeout-minutes: 30
if: >-
github.event_name == 'push' ||
inputs.release_tag == ''
@@ -151,6 +152,7 @@ jobs:
reproducibility-build:
name: Independent distribution builder ${{ matrix.builder }}
runs-on: ubuntu-latest
+ timeout-minutes: 30
container: python:3.11-slim@sha256:90744cff8f32887f075c47d747a173ff333e9e98801667af93c357fa9f5e28ff
if: >-
github.event_name == 'push' ||
@@ -188,6 +190,7 @@ jobs:
name: Compare independent distribution builders
needs: [build, reproducibility-build]
runs-on: ubuntu-latest
+ timeout-minutes: 10
if: >-
github.event_name == 'push' ||
inputs.release_tag == ''
@@ -279,6 +282,7 @@ jobs:
python-matrix:
name: Python ${{ matrix.python-version }} release gate
runs-on: ubuntu-latest
+ timeout-minutes: 30
strategy:
fail-fast: false
matrix:
@@ -320,6 +324,7 @@ jobs:
github.event_name == 'push' ||
inputs.release_tag == ''
runs-on: ubuntu-latest
+ timeout-minutes: 30
steps:
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
@@ -372,6 +377,7 @@ jobs:
installed-artifact-platform-smoke:
name: Installed wheel smoke (${{ matrix.os }})
needs: build
+ timeout-minutes: 20
runs-on: ${{ matrix.os }}
if: >-
github.event_name == 'push' ||
@@ -423,6 +429,7 @@ jobs:
encryption:
name: Encryption driver release gate (Python ${{ matrix.python-version }})
+ timeout-minutes: 15
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -447,6 +454,7 @@ jobs:
browser-accessibility:
name: Browser accessibility release gate
+ timeout-minutes: 20
runs-on: ubuntu-latest
if: >-
github.event_name == 'push' ||
@@ -472,6 +480,7 @@ jobs:
pi-extension:
name: Pi extension release gate
+ timeout-minutes: 20
runs-on: ubuntu-latest
if: >-
github.event_name == 'push' ||
@@ -503,6 +512,7 @@ jobs:
docker-smoke:
name: Production image release gate
runs-on: ubuntu-latest
+ timeout-minutes: 20
if: >-
github.event_name == 'push' ||
inputs.release_tag == ''
@@ -609,7 +619,8 @@ jobs:
trap cleanup EXIT
python -m pip install --disable-pip-version-check --no-cache-dir pip-audit==2.10.1
docker create --name "$container" engraphis:release >/dev/null
- docker cp "$container":/usr/local/lib/python3.11/site-packages/. "$audit_dir"
+ site_packages=$(docker run --rm engraphis:release python3 -c "import sysconfig; print(sysconfig.get_path('purelib'))")
+ docker cp "$container:$site_packages/." "$audit_dir"
python -m pip_audit --path "$audit_dir"
- name: Run customer-mode readiness smoke
shell: bash
@@ -618,6 +629,7 @@ jobs:
-e ENGRAPHIS_EMBED_MODEL= \
-e ENGRAPHIS_LOOP_INTERVAL=0 \
-e ENGRAPHIS_HOST=0.0.0.0 \
+ -e ENGRAPHIS_SERVICE_MODE=customer \
engraphis:release
for i in $(seq 1 60); do
if curl -fsS http://127.0.0.1:8700/api/ready; then
@@ -642,6 +654,7 @@ jobs:
github.event_name == 'push' ||
inputs.release_tag == ''
runs-on: ubuntu-latest
+ timeout-minutes: 15
permissions:
contents: read
env:
@@ -675,6 +688,7 @@ jobs:
needs: [build, reproducibility-check, python-matrix, artifact-core-py39, installed-artifact-platform-smoke, encryption, browser-accessibility, pi-extension, docker-smoke, code-security]
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
+ timeout-minutes: 10
permissions:
contents: read
@@ -752,6 +766,7 @@ jobs:
# semver tag, whose value was matched to pyproject.toml in the build job above.
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
+ timeout-minutes: 10
permissions:
id-token: write
contents: read
@@ -798,6 +813,7 @@ jobs:
needs: publish
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
+ timeout-minutes: 10
permissions:
contents: write
@@ -843,6 +859,7 @@ jobs:
github.ref == 'refs/heads/main' &&
inputs.release_tag != ''
runs-on: ubuntu-latest
+ timeout-minutes: 10
permissions:
actions: read
contents: write
diff --git a/.gitignore b/.gitignore
index 1d45ea37..9f8de4aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,11 @@ __pycache__/
*.db-shm
*.db-journal
*.db.*.bak
+*.sqlite
+*.sqlite3
+*.sqlite-wal
+*.sqlite-shm
+*.sqlite-journal
# Webhook fulfillment runtime state — dedup DB + the undelivered-key fallback,
# which can contain live license keys. Must never be committed.
@@ -28,6 +33,9 @@ build/
/engraphis-[0-9]*/
.pytest_cache/
/.pytest-*-tmp/
+# Focused UI/API test runs use named repository-local base directories.
+/.pytest-tmp-ui-*/
+/.codex-pytest-tmp/
.ruff_cache/
.coverage
node_modules/
diff --git a/AGENTS.md b/AGENTS.md
index 163a5231..5ed35ab5 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -244,6 +244,26 @@ These are pure, unit-tested functions — change them only with a corresponding
re-verify with `wc -l`/`grep` before trusting a test run against it; clearing `__pycache__`
alone does not fix this (the staleness is in the source, not in cached bytecode).
+### PR delivery protocol for automated maintenance
+
+When an agent is maintaining an open pull request, the matching PR branch or an isolated
+worktree is the delivery boundary:
+
+1. Implement every attributable, safe, scoped review or CI fix in that matching branch or
+ worktree. After tests and lint pass, inspect `git status` and the complete diff, then commit
+ and push every clean, attributable fix and PR worktree file with an ordinary non-force push.
+ A verified fix must not be left only in a local checkout.
+2. Keep unrelated user edits, ambiguous files, credentials, generated databases, logs, and
+ secrets out of the PR. Preserve ambiguous work in its original checkout or a separate
+ worktree and report the exact separation needed; never mix it into an otherwise clean PR.
+3. After each push, recheck the remote CI/workflow results, logs, and current review threads.
+ Continue with safe, attributable iterations until the PR is merge-ready, and report exact
+ files, commits, tests, remaining review items, and blockers.
+4. Never force-push, merge, deploy, publish, delete branches/files, change credentials, rerun
+ workflows, post GitHub comments, resolve review threads, or send external messages without
+ explicit approval. Merge remains prohibited unless the user explicitly approves it, even
+ when checks are green.
+
---
## 7. Source-of-truth docs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8549389..b6f57d7f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,12 +5,189 @@ All notable changes to Engraphis are documented here. Format loosely follows
## [Unreleased]
+### Changed
+
+- Direct black-hole children now receive compact, deterministic orbital lanes near the black
+ hole instead of inheriting the farthest authored radius. Each lane keeps phase and painted
+ clearance, while community-child planets remain in their local moving frame; oversized Galaxy
+ scenes seed the same lanes before their kinematic clock starts.
+- Complete Galaxy packing now uses a 4% painted-envelope clearance instead of a blanket 15%
+ radial allowance, keeping solar-system carriers materially denser around the black-hole
+ interior while preserving non-overlap.
+- Explicit `orbits` links from the black hole now promote community anchors and their declared
+ stellar children into the central orbital carrier group, so the Orbital speed control moves
+ the connected nodes in both live and oversized Galaxy paths.
+- Every Galaxy body now receives both motion frames: its top-level system carrier orbits the
+ black hole, while the body follows its immediate star/planet carrier with cached local phase;
+ legacy community metadata and nested moons use the same hierarchy without phase rewinds.
+- Complete graph capacity is doubled to 40,000 entity nodes and 200,000 raw relationships,
+ with matching evidence, connector, payload, and full-loader ceilings; live-render safety
+ thresholds remain unchanged so oversized scenes stay on the static/kinematic path.
+
+- Galaxy admission now uses a tighter default carrier gap and calibrated orbital slack, keeping
+ more complete solar systems in the black-hole interior without sacrificing painted clearance.
+
+- Galaxy mode now exposes normalized controls for gravitational constant, compact black-hole
+ mass, independent local-solar gravity, space friction, edge-spring stiffness, and orbit
+ pause/play. The fixed-step Velocity Verlet field superposes black-hole carrier motion with
+ softened dominant-star orbits, adds bounded near-horizon frame dragging, differential tidal
+ stretching, and carrier-only orbital decay, preserves Hooke tethers and short-range
+ repulsion, and captures sub-escape drag releases into their authored star system while high
+ velocity releases escape. A bounded canvas layer renders the central gravity well, lens halo,
+ short trails, and up to 24 shallow local-star wells without adding simulation bodies.
+- The dashboard Galaxy graph now caches its outer safety radius at 2× the initial painted
+ extent; escaped nodes are confined to that fixed envelope instead of expanding it.
+- The Galaxy gravity slider now spans `0..400` while retaining the release-stable default
+ black-hole field of `240` and local field of `120`. Independent community stars run on a 2.5×
+ orbital clock and retain the calibrated default stellar well when Gravity is zero. An explicit
+ black hole now retains a smaller `24`-setting floor at the loose endpoint, so neither solar
+ systems nor their planets silently stop while the displayed control remains at zero.
+- The Galaxy default orbital separation is now `60`, a 25% increase from `48`. Link and contact
+ projections remain contractive and correction-capped so dense layouts cannot overshoot or
+ ping-pong. Same-system contacts project along each declared stellar orbit so they preserve
+ radius and relative velocity while the dominant star remains fixed in the local system frame.
+- Galaxy's `Orbital speed` control now scales local stellar rotation and whole-system rotation
+ around the central galaxy anchor in both live and oversized kinematic layouts. Its faster
+ endpoint also gives planets a modest 6% larger local orbital radius while the midpoint remains
+ unchanged; saved views continue using `repel`.
+- Direct black-hole graph connections now classify their non-anchor nodes as black-hole
+ satellites, including legacy payloads without `system_anchor_id`, so those nodes rotate with
+ the same Orbital speed phase.
+- Carrier orbit support now adopts a node's post-contact phase before advancing it, preventing
+ collision or boundary corrections from snapping nodes back to a stale lane angle and producing
+ visible jitter.
+- Oversized Galaxy fallback layouts now use the complete gravity range instead of saturating near
+ the lower end of the slider.
+- Complete Galaxy overview scenes remain expanded and physically live through 1,000 nodes and
+ 2,000 relations; larger Galaxy scenes and non-Galaxy full views retain the deterministic
+ fallback.
+- Historical graph views now keep at least one ghost relation's endpoints together under
+ undersized node caps, and ghost evidence drilldowns resolve invalidated supporting memories
+ instead of a colliding live canonical alias.
+
+### Fixed
+
+- Galaxy layout now packs each complete solar-system envelope before orbital seeding and keeps
+ those envelopes separated with rigid carrier translations during live motion. Compact server
+ targets can no longer stack large systems near the black hole, while local planet positions,
+ velocities, event-horizon clearance, and the finite outer boundary remain intact.
+- Galaxy hierarchy authority is now label-independent: an authored `anchor_role="global"`
+ selects the central mass regardless of its display name or evidence mass, while unannotated
+ compatibility scenes fall back deterministically through mass, rank, degree, and stable ID.
+- The central black-hole adornment now advances a visible spin phase with the Galaxy physics
+ clock, so an otherwise satellite-free core no longer appears frozen while remaining the fixed
+ origin for the surrounding galaxy.
+- Near-horizon curvature is now measured from each system's dominant-star carrier through a
+ bounded black-hole-scale band. A wide solar system can no longer be misclassified as already
+ inside the gravity well and have its ordinary galactic angular momentum drained.
+- Galaxy systems revealed after the initial render, restored with zeroed velocity, or shown as
+ singletons now receive their own black-hole-frame tangential admission instead of being marked
+ seeded while stationary. Oversized Complete views use a bounded node-only hierarchical orbit
+ clock, and visible historical ghosts move as massless test particles without entering gravity,
+ contacts, or momentum.
+- Galaxy members that appear before their eventual star, arrive through a later reveal, change
+ parent systems, or return with a zeroed local phase now receive one star-relative circular seed
+ without recoiling the dominant node. Existing healthy stellar orbits remain untouched.
+- Dominant community stars now remain inertial at the centre of their moving solar-system frame.
+ Local gravity, stellar contact, dense separation, seeding, speed limiting, and the oversized
+ kinematic fallback move planets around that star instead of wobbling the star with its planets.
+- Galaxy Reheat now wakes the persistent fixed-step clock without injecting bonus physics slices,
+ and cross-system separation is bounded so it cannot kick entire solar systems into a visible
+ fast-forward, ping-pong, or speed-cap pulse.
+- Ledger graph reloads now retire and cache-bust a renderer that fetched successfully but failed
+ to register, instead of replaying the same broken asset response.
+- Existing Galaxy preferences migrate only the retired `48` orbital-separation default to `60`;
+ deliberate custom values, including Gravity `0`, remain unchanged.
+
## [1.6] - 2026-08-08
-Minor release advancing the v2 engine through schema 16 with deterministic sync state, trusted
+Minor release advancing the v2 engine through schema 16 with deterministic sync state, trusted
local document and Obsidian import, tighter trust boundaries, synchronized agent guidance, and
stronger release and evaluation evidence.
+### Changed
+
+- The Ledger knowledge graph now defaults to evidence-mass Galaxy gravity. The `galaxy-v6`
+ scene contract retains the magnitude of degree, PageRank, support, and repository evidence;
+ one mass value determines both visibly distinct star radius and gravitational pull. Deterministic
+ mass-ranked cores and orbital bands form local solar systems. The highest-evidence node becomes
+ the central black hole, rendered at least twice the ordinary evidence radius so its event horizon
+ remains visible at minimum Node size. Deterministic logarithmic arms seed a non-uniform disk, and
+ a fixed-step leapfrog clock advances eccentric, differential system orbits through an
+ evidence-derived core-plus-halo potential. Gravity now treats the dominant evidence node as
+ the explicit black-hole source: its field is `240` at the default slider and `864` at maximum,
+ while local solar-system, bridge, and drag gravity receives exactly half (`120` and `432`). The
+ smooth response remains true-zero and monotonic, and the rest of the core community contributes
+ through the softened halo rather than silently inflating the black-hole node's mass. External
+ solar systems also exert a weaker softened mutual field on one another: nearby evidence-heavy
+ systems perturb each other without requiring a relation edge, while the black hole remains the
+ dominant galaxy-wide potential.
+ The controlled centre pull is also doubled, retaining an immediate radial response rather than
+ hiding the stronger field behind a slower projector. Galaxy dynamics no
+ longer depend on D3 alpha decay, render cadence, or
+ force-directed settling. Galactic and local-system motion now uses a `0.021328125` fixed timestep,
+ another 30% slower than the preceding `0.03046875` cadence, while direct pointer movement remains responsive.
+ Every live seed coordinate and local orbit begins another 20% inward, putting
+ system centers at 40% of the original Galaxy radius. While live, the black-hole frame follows a
+ controlled inward spiral: Gravity 0 holds the loose seeded radius, and default/maximum convergence
+ now advances the same inward trajectory at 70% of its immediately preceding speed. Gravity slider input also
+ applies an immediate, reversible system-center response without changing local geometry or velocity:
+ its full range spans 40% radius contraction, and default-to-maximum visibly contracts about 31%
+ synchronously while maximum gravity retains its 3.6x field;
+ outward attempts still receive a 110% radial counter-projection and can never increase their
+ radius. Link distance now drives same-system evidence springs with twice the prior response and
+ a squared scale curve. Its default is now `8`, giving connected nodes a 0.25x rest length, 75%
+ tighter than the preceding default, while the full range still spans 1/16x tight orbits through
+ 25x loose orbits without allowing
+ cross-system relations to collapse the galaxy. A bounded mass-weighted positional relation
+ constraint makes Link distance respond immediately while preserving each solar system's centre
+ of mass. Orbital separation now owns an explicit same-system safety envelope instead of relying
+ on an imperceptible softening side effect: both its positional response and cushion scale are
+ doubled, spanning zero added space through 30 world units while preserving evidence-mass centre
+ of mass and removing closing energy. Dense projections retain the requested
+ compact radius and report unavoidable projected overlap instead of silently expanding the disk.
+ Near the core, the direct close-encounter term is 25% lower and its weight moves into the smooth
+ halo, reducing ejection without weakening the total evidence-mass field. Legacy layouts and
+ `/api/graph` remain available.
+
+### Fixed
+
+- Replace the packed-disk Galaxy regression with persistent softened-Newtonian dynamics. Galaxy
+ phase space is isolated from Compact and other legacy layouts, angular momentum is preserved
+ across layout changes, and large stars are visibly distinct. A smooth evidence-mass field keeps
+ each solar system bound while direct star-to-star gravity supplies smaller organic perturbations;
+ evidence bridges remain visible provenance without injecting non-central orbital energy or
+ relation springs compressing the scene into a graph blob. Dragging now leaves the fixed-step
+ Galaxy clock live without alpha changes, global reheats, reseeding, or detaching any global force.
+ The pointer owns exactly one moving mass source while every live body follows its softened
+ inverse-square gravity, whether linked or unlinked; distance and evidence mass determine the
+ response, and explicit relations only strengthen it. A bounded once-per-physics-slice projection
+ makes nearby unlinked bodies visibly follow without teleporting, freezing the rest of the graph,
+ or depending on pointer-event frequency. Pointer events update only the source position and
+ field membership--the gravitational response is sampled by the 30 Hz physics clock. The selected
+ Link orbit supplies a safe periapsis,
+ tangential momentum is retained, and release adds no wake or impulse. Freeze remains the sole
+ explicit motion gate. The explicit **Reheat layout** action now gives Galaxy a finite custom-
+ solver relaxation burst (30 extra steps, or 12 for large live scenes) instead of merely ensuring
+ its already-running clock exists; repeated clicks coalesce, current orbital phase is preserved,
+ and no D3 alpha, random kick, or orbital reseed is introduced.
+- Eliminate false Galaxy "reheating" caused by two local solvers fighting each other every tick.
+ Link distance and Orbital separation now share the same lower-bound target, the redundant live
+ velocity spring no longer injects energy alongside the positional constraint, and close-range
+ separation dissipates closing radial motion. Correction-distance diagnostics expose whether a
+ system is genuinely settling without changing its orbital phase or waking D3.
+- Stabilize dense solar systems and high-degree hubs without weakening their gravity. Link and
+ Orbital-separation constraints now sample one immutable phase and apply one simultaneous,
+ mass-balanced update per node instead of stacking an update for every incident edge. Aggregate
+ position and contact-velocity caps prevent a hub slingshot, while a system-relative speed fuse
+ damps only anomalous member motion and preserves each free system's center-of-mass orbit.
+- Show unlinked entities in new Ledger and Classic graph views by default so isolated evidence is
+ not silently omitted. The toolbar still switches to a linked-only view, and persisted user or
+ saved-view preferences remain authoritative.
+- Keep large Galaxy scenes interactive by replacing quadratic entity-visibility scans with
+ set-wise privacy pruning, driving evidence lookups from the requested relation IDs, and making
+ Ledger retries cancel and supersede stale scene requests safely.
+
### Added
- A dependency-free, source-neutral local document importer for Markdown, plain text,
@@ -33,7 +210,7 @@ stronger release and evaluation evidence.
- Fail closed on new `user`-scope memory writes until records carry an immutable owner identity;
preserve historical reads and the existing promotion rejection instead of presenting
workspace-bound rows as private personal memory.
-- Parse bounded dotenv-style configuration without an optional runtime dependency, and load it only from the owner-private
+- Parse bounded dotenv-style configuration without an optional runtime dependency, and load it only from the owner-private
`~/.engraphis/config.env` or an absolute owner-private file selected by
`ENGRAPHIS_ENV_FILE`; arbitrary working-directory `.env` files are not a trust boundary.
- Clarify Cloud Sync credential-origin binding, secret-manager-only unattended credentials,
@@ -225,7 +402,7 @@ tombstones remain global.
### Upgrade notes
-- `engraphis-mcp` now exposes nine Smart tools instead of 33 direct tools. Clients that depend on
+- `engraphis-mcp` now exposes nine Smart tools instead of 34 direct tools. Clients that depend on
the former names should switch their server command to `engraphis-mcp-classic`; HTTP clients can
use `engraphis-mcp-http --classic`.
- Existing v2 databases migrate automatically to schema 9 on first open; the change is additive
@@ -237,7 +414,7 @@ tombstones remain global.
- Smart MCP is now the zero-configuration `engraphis-mcp` default. It exposes nine compact tools:
sessions, prompt-ready recall, durable memory, discovery, validated read/action execution, and
- governed record read/update plus conflict review. `engraphis-mcp-classic` preserves the former 33
+ governed record read/update plus conflict review. `engraphis-mcp-classic` preserves the former 34
direct tool names and legacy alias response shapes for pinned integrations.
- The first-party `@engraphis/pi` package under `integrations/pi` exposes that Smart MCP surface
as native Pi tools, verifies the Engraphis 1.4.x handshake, and ships with independent npm
@@ -1302,4 +1479,4 @@ and safe hosted deployment.
---
-**Security reporting:** Email **security@engraphis.dev** for vulnerability disclosure.
+**Security reporting:** Email **security@engraphis.dev** for vulnerability disclosure.
diff --git a/README.md b/README.md
index b7b63d25..016f268a 100644
--- a/README.md
+++ b/README.md
@@ -14,9 +14,11 @@
Knowledge Graph · run engraphis-dashboard to see it live
-
-
----
+
+
+**Grounded, not guessed.** Memory with receipts. Local by default. [Explore the proof gallery](https://github.com/Coding-Dev-Tools/engraphis/tree/main/docs/advertising) or [read the campaign guide](https://github.com/Coding-Dev-Tools/engraphis/blob/main/docs/advertising/campaign.md).
+
+---
> **Open-core boundary:** this repository contains the free local engine, dashboard, MCP server,
> and customer-side clients. Hosted sync, analytics, automation, and team services run on the
@@ -37,11 +39,12 @@ context Engraphis actually emitted, keeps token counters and release versions se
labels adaptive history reductions separately from packing savings. Receipts without estimator
metadata remain historical/unclassified. This measures estimated prompt-context reduction; it
does not measure provider billing. The `/context-savings` API and
-`engraphis_context_savings` MCP tool accept optional `from_ts`, `to_ts`, and `release_version`
-filters.
+`engraphis_context_savings` MCP tool aggregate the complete history across all visible workspaces
+by default, or accept an explicit workspace plus optional `from_ts`, `to_ts`, and
+`release_version` filters.
-
+ Less repeated history means more room for the task, tools, and useful evidence.
@@ -154,7 +157,7 @@ selection, set `ENGRAPHIS_UPDATE_EXTRAS` to a comma-separated list (for example
`server,mcp`), or set it to `none` for the base package only.
> **Upgrading to 1.4:** `engraphis-mcp` now exposes the nine-tool Smart gateway. Integrations that
-> require the former 33 direct tool names should run `engraphis-mcp-classic`. The SQLite schema
+> require the former 34 direct tool names should run `engraphis-mcp-classic`. The SQLite schema
> in the 1.4.0 release was version 9. Existing v7-to-v8 databases already contain `confidence`
> and `pinned_at`/`unpinned_at`; v9 adds the `memory_tombstones` repository-scope column/table
> and performs a one-time entity-canonicalization repair, then migrates automatically on first
@@ -566,7 +569,7 @@ when you are ready to evaluate the service boundary and billing options.
| Memory engine + Smart MCP (Classic 34-tool compatibility) | ✓ | ✓ | ✓ |
| Version-chain diffs, offline knowledge graph | ✓ | ✓ | ✓ |
| Manual local consolidation (dry-run by default) | ✓ | ✓ | ✓ |
-| Local workspace export (JSON: memories, sessions, audit) | ✓ | ✓ | ✓ |
+| Local workspace export (portable v2 JSON: memories, source manifests, graph/code evidence, sessions, audit, and receipts) | ✓ | ✓ | ✓ |
| Hosted Cloud Sync | | ✓ | ✓ |
| Hosted Analytics | | ✓ | ✓ |
| Hosted Auto Consolidation + retention policy | | ✓ | ✓ |
@@ -693,14 +696,13 @@ file. It never searches the working directory for `.env`, and explicit process v
| Env Var | Default | Description |
|---------|---------|-------------|
| `ENGRAPHIS_ENV_FILE` | `~/.engraphis/config.env` | Optional trusted config leaf selected before trusted values load. Its bounded dependency-free parser performs no interpolation. An explicit value must be an absolute path to an owner-private regular file; arbitrary working-directory `.env` files are ignored. |
-| `ENGRAPHIS_DB_PATH` | Source: `/engraphis.db`; installed: platform user-data directory | SQLite database file. Installed defaults are `%LOCALAPPDATA%\engraphis\engraphis.db` (Windows), `~/Library/Application Support/engraphis/engraphis.db` (macOS), and `$XDG_DATA_HOME/engraphis/engraphis.db` or `~/.local/share/engraphis/engraphis.db` (Linux). The environment variable overrides every default. |
+| `ENGRAPHIS_DB_PATH` | Source: `/engraphis.db`; installed: platform user-data directory | SQLite database file. Installed defaults are `%LOCALAPPDATA%\engraphis\engraphis.db` (Windows), `~/Library/Application Support/engraphis/engraphis.db` (macOS), and `$XDG_DATA_HOME/engraphis/engraphis.db` or `~/.local/share/engraphis/engraphis.db` (Linux). The environment variable overrides every default; a relative value is resolved from the trusted `~/.engraphis/config.env` directory so launch CWD cannot select a different workspace database. |
| `ENGRAPHIS_HOST` | `127.0.0.1` | Server bind address |
| `ENGRAPHIS_PORT` | `8700` | Dashboard port |
| `ENGRAPHIS_SERVICE_MODE` | `customer` | The public package supports only `customer`; hosted vendor, relay, compute, and worker roles are not distributed here |
| `ENGRAPHIS_API_TOKEN` | Not set | Optional bearer credential for this single-user local customer node; never reuse a hosted credential |
| `ENGRAPHIS_CORS_ORIGINS` | loopback on `ENGRAPHIS_PORT` | Comma-separated REST CORS allow-list; defaults to `127.0.0.1` and `localhost` on the configured port |
-| `ENGRAPHIS_WORKSPACES` | Not set | Optional comma-separated server-side workspace allow-list |
-| `ENGRAPHIS_INDEX_ROOTS` | Working, home, and temporary directories | Optional path-separator-delimited absolute-path allow-list that replaces the default roots accepted by local code indexing |
+| `ENGRAPHIS_INDEX_ROOTS` | Working, home, and temporary directories | Optional path-separator-delimited absolute-path allow-list that replaces the default roots accepted by local code indexing |
| `ENGRAPHIS_HTTP_INDEX_ROOT` | First `ENGRAPHIS_INDEX_ROOTS` entry, or current directory | Single root for dashboard and REST `POST /api/code/index`; submitted paths resolve beneath it. An explicit root (or fallback entry) must be absolute; an explicit HTTP root is included in the engine-approved set. MCP and CLI indexing continue to use `ENGRAPHIS_INDEX_ROOTS`. |
| `ENGRAPHIS_DB_KEY` | Not set | Encrypt the database at rest (SQLCipher). Or use `ENGRAPHIS_DB_KEY_FILE` |
| `ENGRAPHIS_EMBED_MODEL` | `sentence-transformers/all-MiniLM-L6-v2` | sentence-transformers model |
diff --git a/SECURITY.md b/SECURITY.md
index 91c80424..76e989f1 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -67,8 +67,9 @@ DOMPurify at all render sites. Verified against payloads with `onerror` handlers
### 3. Scope isolation
- Every read takes a `SearchFilter`; tools only return memories within requested `workspace`/`repo`
- Every write targeting a memory by ID re-validates scope membership
-- **Hard workspace binding** (`ENGRAPHIS_WORKSPACES`): comma-separated allow-list makes
- workspace a hard boundary; requests outside the list are refused before touching the store
+- Workspace creation is not controlled by a process-wide allow-list; each operation still
+ carries its explicit workspace/repo/session scope and authenticated personal workspaces
+ enforce their owner boundary
### 4. Secrets & data at rest
- `.env`, `*.db`, `*.db-wal`, `*.db-shm` are git-ignored and must never be logged. Gitignore is
diff --git a/docs/MCP_TOOLS.md b/docs/MCP_TOOLS.md
index cec272b9..8526a0af 100644
--- a/docs/MCP_TOOLS.md
+++ b/docs/MCP_TOOLS.md
@@ -98,7 +98,7 @@ the [memory write trust model](WRITE_REVIEW.md) and [recall recovery guide](RECA
| Code | `engraphis_export_code_graph` | Exports graph JSON, Markdown, and HTML. |
| Code | `engraphis_link_symbol` | Manually links a code symbol to a memory (idempotent). |
| Audit | `engraphis_receipts` | Lists content-free hashed operation receipts. |
-| Audit | `engraphis_context_savings` | Reports receipt-backed estimated context tokens saved, eligible/excluded deliveries, basis, confidence, and token-counter identity; optional `from_ts`, `to_ts`, and `release_version` filters are supported. This is estimated prompt-context reduction, not provider billing. |
+| Audit | `engraphis_context_savings` | Reports receipt-backed estimated context tokens saved across all visible workspaces by default, or one workspace when supplied; optional `from_ts`, `to_ts`, and `release_version` filters are supported. This is estimated prompt-context reduction, not provider billing. |
| Audit | `engraphis_verify_receipts` | Verifies the receipt chain, local tail anchor, and an optional saved head/count. |
| Audit | `engraphis_export_receipts` | Exports a shareable receipt-only audit bundle. |
| Governance | `engraphis_retire` | Retires a memory by closing its validity window. It does not delete history. |
@@ -111,12 +111,14 @@ the [memory write trust model](WRITE_REVIEW.md) and [recall recovery guide](RECA
| Operations | `engraphis_stats` | Returns memory counts for health checks. |
| Operations | `engraphis_check_update` | Refreshes the release cache and reports whether a newer version is available. |
-All four recall tools (`engraphis_recall`, `engraphis_recall_context`,
+The classic recall, grounded, and answer tools (`engraphis_recall`,
`engraphis_recall_grounded`, and the `engraphis_answer` alias) accept `planning="off"|"auto"`,
optional `mtype_limits` such as `{"working": 1, "semantic": 3}`, and optional
-`max_response_tokens` from `1` through `1000000`. `response_mode="full"` returns the classic
+`max_response_tokens` from `2` through `1000000`. `response_mode="full"` returns the classic
response; `"compact"` removes packed context and citation/memory bodies from the end while
-preserving source/citation references. Responses include a stable `context_revision`. Planner
+preserving source/citation references. `engraphis_recall_context` is always compact and does
+not accept `response_mode`; it shares the same `max_response_tokens` floor. Responses include
+a stable `context_revision`. Planner
details, per-query rankings, type-limit drops, and fallback reasons are returned only when
`diagnostics=true`. Type limits are post-rank maxima and can intentionally return fewer than `k`;
they do not raise a memory type's relevance. Every planned query remains inside the caller's scope,
diff --git a/docs/advertising/campaign.md b/docs/advertising/campaign.md
new file mode 100644
index 00000000..9c0015d1
--- /dev/null
+++ b/docs/advertising/campaign.md
@@ -0,0 +1,186 @@
+# Engraphis proof-first campaign
+
+Engraphis should be marketed as a memory system that can show its work.
+
+> Grounded, not guessed. Memory with receipts. Local by default.
+
+This guide turns existing demos, benchmark artifacts, and product surfaces into a repeatable campaign. It does not introduce new product claims.
+
+## Message architecture
+
+### The flagship promise
+
+**Engraphis carries project knowledge forward without treating old information as current truth.**
+
+Use this promise when the audience needs the whole story: local storage, scoped recall, temporal validity, provenance, and context packing.
+
+### Four proof stories
+
+| Story | Hook | Existing proof | Primary action |
+| --- | --- | --- | --- |
+| Local | No account. No API key. Still remembers. | Dashboard quickstart and local-first README copy | Install free |
+| Grounded | No support, no answer. | Grounded recall and evidence-backed behavior fixture | Inspect grounded recall |
+| Temporal | Facts change. History stays visible. | Continuity demo, invalidation, supersession, and timeline | Watch the continuity demo |
+| Efficient | Fewer tokens, better evidence. | Registered `offline-chunking` and `offline-performance` fixtures | Read the benchmark |
+
+Keep one story per asset. Do not combine every feature into one graphic.
+
+## Four-week distribution sequence
+
+### Week 1: Local memory
+
+Lead with the relief of not starting from zero and the control of keeping memory on the machine.
+
+- Short screen clip: open the local dashboard and show the graph, provenance, and receipts.
+- Static post: “Your agent’s memory can stay on your machine.”
+- Setup post: `pip install "engraphis[mcp]"`, `engraphis-init`, and the Smart MCP command.
+- README placement: link the proof gallery directly below the existing knowledge graph image.
+
+### Week 2: Grounded recall
+
+Lead with a cited answer and an explicit abstain. The contrast is more memorable than another generic retrieval diagram.
+
+- Carousel: “Cited answer” beside “No support, no answer.”
+- Short clip: ask one supported question, then one off-topic question.
+- Technical post: explain why the grounded gate uses absolute support instead of the normalized recall score.
+- CTA: “Try grounded recall.”
+
+### Week 3: Temporal memory
+
+Lead with one changing repository decision. Show the old fact, the new fact, and the reason the old record remains queryable.
+
+- Timeline graphic: old validity window closes, new fact becomes current.
+- Continuity reel: use the existing 56-second demo artifact.
+- Blog post: “Engraphis does not just remember. It remembers what changed.”
+- CTA: “Inspect the why and timeline.”
+
+### Week 4: Context economy
+
+Lead with the smallest useful evidence, not a vague claim about speed or cost.
+
+- Stat card: `740.3 -> 214.3` tokens with Recall@5 `1.000` in the registered fixture.
+- Evidence card: `162.2 -> 42.4` tokens to the smallest evidence-holding memory.
+- Technical post: clarify that the compact payload proxy is separate from chunking and must not be added to it.
+- CTA: “Read the benchmark definitions.”
+
+## Reusable post hooks
+
+1. Stop replaying the whole chat.
+2. Memory with receipts.
+3. No support, no answer.
+4. Facts change. History stays visible.
+5. Some answers live in the graph, not the note.
+6. Your agent does not need more history. It needs the right evidence.
+7. Local memory should not require a trust fall.
+8. Find the symbol. Explain the decision.
+9. Nine Smart MCP tools first. Discover advanced actions only when needed.
+10. Bring your memory stack. Publish one immutable run.
+
+## Public benchmark challenge
+
+### Campaign idea
+
+Invite memory-tool builders to run a fixed, public-safe fixture and publish the artifact digest, command, configuration, and result summary.
+
+### Public copy
+
+> Bring your memory stack. Publish one immutable run.
+>
+> Use the locked fixture, keep the comparison boundary explicit, and share the result without raw questions, answers, prompts, or private records.
+
+### Launch requirements
+
+- Anchor every published number to an evidence ID in `BENCHMARKS.md`.
+- Use the public runbook in `docs/PUBLIC_BENCHMARK_RUNBOOK.md` as the execution contract.
+- Publish the whole-input and source-file digests required by the runbook.
+- Keep raw questions, answers, prompts, context, and per-record content fingerprints out of public artifacts.
+- Present the challenge as a reproducibility standard, not as a self-selected victory lap.
+
+### Embed-ready result format
+
+```text
+Memory benchmark
+Stack:
+Fixture:
+Command:
+Artifact digest:
+Result summary:
+Limitations:
+```
+
+## Remixable diagram set
+
+Create five self-contained HTML or SVG artifacts. Each should have one headline, one visual claim, one source link, and one CTA.
+
+1. **Memory flow:** source material -> scoped memory -> hybrid recall -> task-ready evidence.
+2. **Supersession chain:** old fact -> invalidation -> current fact -> why and timeline.
+3. **Benchmark flow:** locked fixture -> exact command -> digest -> public result.
+4. **Scope hierarchy:** workspace -> repo -> session -> memory.
+5. **MCP integration:** install -> initialize -> connect -> recall and remember.
+
+Use the gallery in `docs/advertising/index.html` as the visual reference. Keep the page free of external font, image, and JavaScript dependencies. Existing evidence files remain the canonical source views:
+
+- `docs/images/context-efficiency.svg`
+- `docs/images/evidence-backed-agent-examples.svg`
+- `docs/images/knowledge-graph.png`
+- `demo/engraphis_screen_demo.html`
+
+The linked `diagram-design` project is a useful reference for self-contained HTML/SVG, brand tokens, gallery navigation, and exportable variants: .
+
+## Setup recipes
+
+### Smart MCP
+
+```bash
+pip install "engraphis[mcp]"
+engraphis-init
+codex mcp add engraphis -- engraphis-mcp
+```
+
+### Dashboard
+
+```bash
+pip install "engraphis[server]"
+engraphis-dashboard
+```
+
+### Offline Python library
+
+```python
+from engraphis.service import MemoryService
+
+memory = MemoryService.create("engraphis.db")
+```
+
+Keep hosted sync and Pro trial messaging below the free local path. The local engine is the first conversion step. Hosted services are a separate trust and pricing decision.
+
+## Measurement plan
+
+Track these events without changing existing button labels or URL structure:
+
+| Event | Meaning |
+| --- | --- |
+| `advertising_gallery_open` | A visitor opened the proof gallery |
+| `advertising_demo_open` | A visitor opened the continuity demo |
+| `advertising_install_click` | A visitor selected the free install path |
+| `advertising_mcp_click` | A visitor selected the MCP path |
+| `advertising_graph_click` | A visitor opened the graph quickstart |
+| `advertising_trial_click` | A visitor selected an existing Pro or Team trial CTA |
+| `advertising_benchmark_click` | A visitor opened the public benchmark material |
+
+Run two headline comparisons:
+
+- “Grounded, not guessed.” versus “Memory that knows where it came from.”
+- “Install free” versus “Connect MCP.”
+
+Judge the result by demo opens, install completion, MCP setup completion, graph export usage, and trial clicks. Do not call an experiment successful without a defined denominator and time window.
+
+## Claim guardrails
+
+- Keep `740.3 -> 214.3`, `162.2 -> 42.4`, and `23,810 -> 10,202` as separate measurements with their existing definitions.
+- These measurements must not be added together.
+- Do not describe deterministic fixtures as official LoCoMo or LongMemEval leaderboard results.
+- Do not turn a synthetic fallback screen into customer evidence.
+- Do not claim provider billing, universal latency, or customer productivity from the current offline fixtures.
+- Keep code `query`, memory-backed `explain`, graph `path`, and graph `impact` as distinct actions.
+- Preserve the local versus hosted boundary in every pricing and privacy asset.
diff --git a/docs/advertising/index.html b/docs/advertising/index.html
new file mode 100644
index 00000000..7320d750
--- /dev/null
+++ b/docs/advertising/index.html
@@ -0,0 +1,473 @@
+
+
+
+
+
+
+ Engraphis | Grounded, not guessed
+
+
+
+
Use a living fact, not a feature list, to show what makes Engraphis different from a chat replay or a flat note store.
+
+
+
+
+
A correction closes the old validity window. It does not erase the record.
+
+
+
Facts change. History stays useful.
+
Show one subject moving from an earlier decision to a current one. The audience sees the old fact, the new fact, and the evidence chain that explains the transition.
Week 1: LocalNo account. No API key. Still remembers.
+
Week 2: GroundedCited answer or explicit abstain.
+
Week 3: TemporalFacts change. History stays visible.
+
Week 4: EfficientFewer tokens, better evidence.
+
+
+
+
+
+
+
Keep the proof honest.
+
Trust is part of the product story. These boundaries keep the gallery useful to technical readers.
+
+
+ What the numbers mean
+
The 740.3 to 214.3 comparison is retrieved memory content in a deterministic fixture. It is not provider billing, latency, or a universal customer outcome.
+
+
+ What the demo means
+
The continuity demo is generated from a real in-memory MemoryService run. Any sample fallback is labeled and must not be presented as customer evidence.
+
+
+ What the graph means
+
Symbol and file search, memory-backed explanation, path, impact, and export are distinct actions. The gallery keeps those terms separate.