Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -168,5 +168,11 @@ ENGRAPHIS_LLM_API_KEY=sk-your-key-here
# Hosted entitlements may report a separate local-only write grace capped at 24 hours.
# It never extends the exact 3-day trial, subscription expiry, or any cloud access.

# Managed compute consent. Set to 1 to allow the open package to upload workspace
# snapshots to the Engraphis Cloud service for managed analytics, dreaming, and
# consolidation. Without this flag, managed compute is off and no cloud upload
# occurs. The cloud service is authoritative for all paid computation.
# ENGRAPHIS_MANAGED_COMPUTE_CONSENT=1

# Optional credential-redacted JSON logs for hosted customer deployments.
# ENGRAPHIS_JSON_LOGS=1
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ internal/
/demo/generated/
/demo/output/

# Local demo variants and large media assets are working files, not package inputs.
/demo/*_killer.html
/demo/*_social_demo.html
/demo/assets/

# FUSE mount artifacts: orphaned unlink-while-open handles from the Cowork
# mount layer, not real content. Safe to ignore; delete host-side once the
# holding process releases the handle (rm from the sandbox gets EPERM).
Expand Down
94 changes: 36 additions & 58 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,9 @@ All notable changes to Engraphis are documented here. Format loosely follows

## [Unreleased]

### Added

- A search-first Analytical Galaxy Graph Explorer backed by canonical, evidence-weighted
scenes; deterministic hierarchical system gravity; compact edge backbones and aggregate
bridges; exact-ID evidence/history inspection; strongest-evidence paths; synchronized
accessible tables; responsive list-first mobile behavior; saved/shareable scene state; and
local PNG, JSON, and CSV exports.
- Additive schema-v4 canonical identity and bi-temporal edge-support records, deterministic
`/api/graph/scene`, `/api/graph/suggest`, `/api/graph/entities/{canonical_id}`, and
`/api/graph/path` contracts with repository, memory-type, evidence-time, historical, and
weak-co-occurrence filtering, plus a persisted graph-index job with dry-run, progress,
cancellation, generation state, bounded error reporting, audit records, and tamper-evident
receipts.
- Galaxy Explorer: a new Simple view (the default) renders a clean glowing galactic core with
soft bloom, plus an Advanced view toggle that keeps the fully decorated explorer available.
Default galaxy rotation is now ~10x slower for readability, and a new Freeze control
pauses/resumes the live rotation.

### Changed
No unreleased changes.

- The legacy graph view now defaults to deterministic community islands, keeps sparse
influence bridges visually subordinate, and renders bounded direct A-MEM links even when
entity extraction is disabled. A reproducible repository-local screen-demo workflow exercises
session handoff, bi-temporal supersession, recall evidence, and history without external
services.
- The public distribution is now structurally customer-only. License issuance, billing,
fulfillment, Team identity, hosted relay, managed compute, worker execution, vendor
administration, and commercial operations tooling moved to a private service repository;
the Apache package retains local core functionality and customer-side protocols.
- Analytics, Cloud Sync service operation, Auto Dreaming, Auto Consolidation, automation
scheduling, and Team administration are now hosted-service capabilities. The public dashboard
keeps status, consent, and launch surfaces plus the free manual consolidation action; it no
longer ships local premium algorithms, schedulers, Team accounts, invitations, roles, or seats.
- The hosted no-card trial remains **exactly 3 active days** after email confirmation. A distinct
`workspace_write_grace` may preserve ordinary writes to an already provisioned local workspace
for at most 24 hours; it never extends the trial or any cloud/paid access.
- Documentation now states the legal boundary directly: Apache-2.0 rights in already published
releases and forks cannot be clawed back. Future proprietary value is protected through the
private hosted implementation and service authorization boundary.
- Recall graph seeding now matches all entity names with one boundary-aware compiled pattern
instead of rescanning every memory once per entity, and the streamable-HTTP launcher warms
the singleton service before accepting clients.

- The graph explorer uses its locally bundled ForceGraph + D3 renderer under the strict
same-origin CSP. The new scene APIs and synchronized accessible entity/relation tables are
additive to that shipped UI.
- Graph GET requests are strictly read-only. While an explicit mutating index job runs, graph
reads return a rebuilding conflict instead of mixing old and partially derived metrics.

## [1.0.1] - 2026-07-23
## [1.0.1] - 2026-07-24

Public 1.0.1 client reliability release.

Expand All @@ -64,12 +17,13 @@ Public 1.0.1 client reliability release.
dashboard host and retired Railway relay URL without changing customer-provided relay URLs.
- Default Pro and Team upgrade links now target the live authenticated account portal rather
than the retired Team dashboard host.
- Hosted endpoint validation now fails closed when DNS resolution cannot establish that a
configured destination is public, preventing unresolved hosts from bypassing the SSRF guard.
- Hosted endpoint validation now fails closed unless DNS establishes a globally routable
destination, and credential-bearing HTTPS connections pin the vetted address while preserving
original-host TLS verification to prevent DNS-rebinding SSRF.
- Hosted Automation and maintenance requests now use the selected workspace end to end rather
than silently falling back to the first workspace.
- The Automation tab has one proposal action, clear managed-upload disclosure, and automatic
entitlement-gated managed-compute availability while preserving snapshot redaction and limits.
- The Automation tab has one proposal action, clear managed-upload disclosure, and explicit
managed-compute consent in addition to entitlement checks, snapshot redaction, and limits.
- Commercial metadata now describes Pro as one owner account across that owner's local
installations, matching the hosted entitlement model; Team remains billed per named seat.
- API error responses and provider logs no longer expose arbitrary exception or configuration
Expand All @@ -78,16 +32,25 @@ Public 1.0.1 client reliability release.
backtracking. CodeQL now disables pull-request diff-informed analysis and CI fails on every
raw SARIF result, including pre-existing and source-suppressed results.
- The documented grounded-recall evaluation prints with the default Windows console encoding.
- Hosted Pro and Team links preserve the selected plan through account creation and Checkout.
- A total `401`/`402`/`403` Cloud Sync authorization loss restores the hosted recovery CTA,
while a successful empty or read-only workspace remains a partial result instead of being
misreported as a total denial.

## [1.0.0] - 2026-07-23

Public 1.0.0 open-core GA release.

### Added

- The Galaxy Knowledge Graph explorer with deterministic communities, entity/relation search,
temporal scenes, evidence and history inspection, accessible tables, and a locally bundled
ForceGraph + D3 renderer.
- The search-first Galaxy Knowledge Graph explorer with deterministic communities, canonical
evidence-weighted scenes, entity/relation search, temporal filtering, evidence and history
inspection, strongest-evidence paths, synchronized accessible tables, saved scene state,
local PNG/JSON/CSV export, Simple and Advanced views, and a locally bundled ForceGraph + D3 renderer
under the strict same-origin CSP.
- Additive schema-v4 canonical identity and bi-temporal edge-support records; deterministic
graph scene, suggestion, entity, and path APIs; and a persisted graph-index job with dry-run,
progress, cancellation, bounded errors, audit records, and tamper-evident receipts.
- A 29-tool MCP surface with explicit behavior annotations, operation receipts, exact session
retry semantics, portable plugin manifests, and checksummed skill assets.
- Customer-side hosted protocols for scoped Cloud Sync, rotating cloud sessions, Analytics,
Expand All @@ -102,6 +65,15 @@ Public 1.0.0 open-core GA release.
no environment variable turns the public package into a hosted Engraphis service.
- Session identity is exact across workspace, repo, authenticated user, agent, and goal; callers
can request a distinct run with `force_new=true` and observe retry reuse explicitly.
- The legacy graph view defaults to deterministic community islands, keeps sparse influence
bridges subordinate, and renders bounded A-MEM links when entity extraction is disabled. The
repository screen demo proves session handoff, bi-temporal supersession, recall evidence, and
history without an external service.
- The hosted no-card trial is exactly 3 active days after email confirmation. A separate
`workspace_write_grace` may preserve ordinary local writes for at most 24 hours but never
extends trial or paid cloud access.
- Apache-2.0 rights in published releases remain irrevocable; proprietary hosted value is
enforced by the private implementation and service authorization boundary.

### Fixed

Expand All @@ -117,15 +89,21 @@ Public 1.0.0 open-core GA release.
forgotten session-only graph evidence.
- Windows private-state validation uses safe file metadata checks without weakening symlink,
ownership, size, or atomic-publication protections.
- Recall graph seeding uses one boundary-aware compiled pattern instead of rescanning every
memory per entity, and the streamable HTTP launcher warms the singleton service before
accepting clients.
- Graph GET requests remain read-only and return a rebuilding conflict while an explicit
mutating index job is in progress.

### Security

- Removed hosted signer, vendor, billing, relay-storage, S3, worker, and Team administration
implementations from the public source and package artifacts.
- Bare memory IDs, shared-workspace controls, graph entities, statistics, snapshots, exports,
audit rows, and keyword fallbacks cannot cross authenticated session or workspace boundaries.
- Managed uploads are capped at 16 MiB and 100,000 rows, omit all session-scoped and
secret-class memories, and surface only fixed client-safe provider errors.
- Managed uploads require explicit customer consent, are capped at 16 MiB and 100,000 rows,
omit all session-scoped and secret-class memories, and surface only fixed client-safe
provider errors.
- Customer credentials remain owner-only, redirect-safe, serialized during rotation, and are
never substituted with an unproven local machine identifier.

Expand Down
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ a color palette and layout preset; or change the colors used for each type of no
| **Team Cloud** *(hosted Team)* | Open the hosted organization dashboard for invitations, roles, named seats, scoped credentials, and team audit history |
| **Settings** | Hosted-plan and Cloud Sync status, LLM provider setup/test, a live structured-extraction switch and activity viewer, appearance, and local engine/store info |

### Managed compute

The open package can upload bounded workspace snapshots to the Engraphis Cloud service
for managed analytics, dreaming, and consolidation. This is **off by default** and
requires explicit opt-in by setting `ENGRAPHIS_MANAGED_COMPUTE_CONSENT=1`. The cloud
service is authoritative for all paid computation; no local setting turns this package
into a compute worker or relay.

The dashboard is powered by the v2 engine — the same `MemoryService` that backs the MCP server
and the Python library. What you see in the UI is what your agents get.

Expand Down Expand Up @@ -608,8 +616,9 @@ background loop, cron wrapper, or worker.

Secret-class and session-scoped memories are excluded before a managed snapshot is serialized;
secret-class rows are rejected again by the hosted service. The encoded payload is capped at
16 MiB. Managed compute is enabled automatically for authorized customers. A managed proposal
does not silently rewrite the local database.
16 MiB. Managed compute remains off until the customer explicitly sets
`ENGRAPHIS_MANAGED_COMPUTE_CONSENT=1`; cloud entitlement is also required. A managed proposal
never silently rewrites the local database.

Manual consolidation can also use schema-validated LLM output through
`MemoryService.consolidate`, `POST /api/consolidate`, `engraphis_consolidate`, or
Expand Down Expand Up @@ -658,6 +667,7 @@ All via environment (or `.env`):
| `ENGRAPHIS_CLOUD_REFRESH_CREDENTIAL` | — | Bootstrap-only rotating hosted credential; after first use the owner-only cloud session replacement takes precedence |
| `ENGRAPHIS_CLOUD_TOKEN_SUBJECT` | `member` | Subject fixed during hosted bootstrap (`device` or `member`); set explicitly with an environment-only refresh credential |
| `ENGRAPHIS_CLOUD_ACCESS_TOKEN` | — | Optional short-lived access token for ephemeral jobs |
| `ENGRAPHIS_MANAGED_COMPUTE_CONSENT` | `0` | Explicitly set to `1` before uploading a bounded workspace snapshot for hosted Analytics or Automation |

See `.env.example` for the full customer-runtime and managed-service client options.

Expand Down
9 changes: 6 additions & 3 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,17 @@ them back as `expected_head` / `expected_count` when independent evidence is req
no paid-key parser, signer, issuer, local feature gate, or long-lived-key relay exchange.
- **Server authority:** every hosted and cost-bearing operation is authorized by the private
control plane; local plan labels and upgrade URLs are presentation metadata only.
- **Managed-compute boundaries:** Analytics, Auto Dreaming, and Auto Consolidation upload a
bounded snapshot for authorized customers. Secret-class memories are excluded before
- **Managed-compute consent:** Analytics, Auto Dreaming, and Auto Consolidation upload a
bounded snapshot only after explicit customer opt-in via
`ENGRAPHIS_MANAGED_COMPUTE_CONSENT=1`. Secret-class memories are excluded before
serialization and rejected again by the hosted service.
- **Trial and grace are separate:** an email-confirmed trial lasts exactly 3 active days. A
separately bounded, maximum-24-hour local workspace-write grace never extends the trial,
subscription, Cloud Sync, managed compute, Team access, seats, or credentials.
- **Remote URL validation:** hosted endpoints require HTTPS except explicit loopback use,
reject embedded credentials and redirects, and block private/reserved literal targets.
reject embedded credentials and redirects, require globally routable resolved addresses,
and pin credential-bearing TLS connections to a vetted address while verifying the
original hostname.
- **Bounded I/O:** credential-bearing JSON responses are read through strict byte limits;
malformed, oversized, or authoritative denial responses fail closed.
- **HTTP response headers:** every entrypoint sends `X-Content-Type-Options: nosniff`,
Expand Down
23 changes: 14 additions & 9 deletions demo/record_screen_demo.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ const repoRoot = resolve(demoDir, "..");
const generatedDir = join(demoDir, "generated");
const outputDir = join(demoDir, "output");
const payload = join(generatedDir, "screen_demo_payload.json");
const webm = join(outputDir, "engraphis-memory-demo.webm");
const mp4 = join(outputDir, "engraphis-memory-demo.mp4");
const html = "engraphis_screen_demo.html";
const baseName = "engraphis-memory-demo";
const width = 1920;
const height = 1080;
const durationMs = 56_500;
const webm = join(outputDir, `${baseName}.webm`);
const mp4 = join(outputDir, `${baseName}.mp4`);
const port = 8790;
const demoAssets = new Map([
["/", join(demoDir, "engraphis_screen_demo.html")],
["/engraphis_screen_demo.html", join(demoDir, "engraphis_screen_demo.html")],
["/", join(demoDir, html)],
[`/${html}`, join(demoDir, html)],
["/generated/screen_demo_payload.json", payload],
]);

Expand Down Expand Up @@ -49,15 +54,15 @@ await new Promise((resolveServer) => server.listen(port, "127.0.0.1", resolveSer

const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
recordVideo: { dir: outputDir, size: { width: 1920, height: 1080 } },
viewport: { width, height },
recordVideo: { dir: outputDir, size: { width, height } },
deviceScaleFactor: 1,
});
const page = await context.newPage();
await page.goto(`http://127.0.0.1:${port}/engraphis_screen_demo.html?autoplay=1`, { waitUntil: "networkidle" });
await page.goto(`http://127.0.0.1:${port}/${html}?autoplay=1`, { waitUntil: "networkidle" });
// Keep the capture clock independent from requestAnimationFrame throttling in
// headless environments; the page itself still stops its progress bar at 56s.
await page.waitForTimeout(56_500);
// headless environments and leave a small tail after the page's 56-second animation.
await page.waitForTimeout(durationMs);
await context.close();
await browser.close();
server.close();
Expand Down
5 changes: 5 additions & 0 deletions deploy/railway-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
"ENGRAPHIS_CLOUD_COMPUTE_URL": {
"value": "https://compute.engraphis.com",
"required": false
},
"ENGRAPHIS_MANAGED_COMPUTE_CONSENT": {
"value": "0",
"prompt": "Change to 1 only after reviewing the managed snapshot upload boundary.",
"required": false
}
}
}
4 changes: 2 additions & 2 deletions docs/RAILWAY_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ issuer, relay, managed compute, Auto Dreaming, Auto Consolidation, or Team ident
- No vendor signer, billing, mail, Team-admin, relay-storage, or worker secrets.

Hosted customer endpoint variables may be exposed as optional inputs, but a refresh credential
must be injected as a secret or mounted owner-only state file. Managed compute is enabled for
authorized customers automatically.
must be injected as a secret or mounted owner-only state file. Managed compute requires
explicit opt-in via `ENGRAPHIS_MANAGED_COMPUTE_CONSENT=1`.

## Publish gate

Expand Down
5 changes: 4 additions & 1 deletion docs/SYNC.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ python -m scripts.sync \

The dashboard's **Sync now** action invokes the same customer protocol. The public package does
not run a local auto-sync loop or ship a cron/Task Scheduler wrapper. Hosted automation belongs
to the private service.
to the private service. If the relay denies every attempted shared workspace because the session
is expired, revoked, or no longer entitled, the dashboard returns to the hosted Pro/Team recovery
CTA instead of reporting a successful empty sync. A successful empty or read-only workspace keeps
the result partial so another workspace's denial is not misreported as a total authorization loss.

### Local folder transport

Expand Down
10 changes: 6 additions & 4 deletions engraphis/backends/sync_relay.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from typing import Iterable, List, Optional, Tuple
from urllib.parse import quote, urlsplit, urlunsplit

from engraphis.hosted_client import build_pinned_https_opener
from engraphis.private_state import UnsafeStateFile, atomic_private_text, read_private_text

MAX_RELAY_BUNDLE_BYTES = 64 * 1024 * 1024
Expand Down Expand Up @@ -70,7 +71,7 @@ def redirect_request(self, req, fp, code, msg, headers, newurl):


def _urlopen_no_redirect(req, *, timeout: float):
return urllib.request.build_opener(_NoRedirectHandler()).open(req, timeout=timeout)
return build_pinned_https_opener(_NoRedirectHandler()).open(req, timeout=timeout)


def _validated_sync_token(value: str) -> str:
Expand Down Expand Up @@ -286,12 +287,13 @@ def _validated_base_url(value: str) -> str:
ip_obj = ipaddress.ip_address(ip)
except ValueError:
continue # sockaddr wasn't a parseable IP; skip
if (ip_obj.is_private or ip_obj.is_reserved or ip_obj.is_link_local
or ip_obj.is_multicast or ip_obj.is_unspecified):
if not ip_obj.is_global:
raise ValueError(
"relay URL must not target private/reserved IP ranges")
except (_socket.gaierror, OSError):
pass # DNS resolution failure; let the actual request fail later
raise ValueError(
"relay URL host could not be resolved to a public address"
) from None
return urlunsplit((scheme, parts.netloc, parts.path.rstrip("/"), "", ""))


Expand Down
Loading
Loading