Skip to content

Commit 0892f68

Browse files
feat: add licensing/analytics/auth Pro features to inspector (#6)
Adds a licensing layer, analytics module, and inspector auth, plus supporting scripts, docs (LAUNCH_PLAN, GO_TO_MARKET), config wiring and tests. 14 modified files + 10 new files.
1 parent cb4b41b commit 0892f68

24 files changed

Lines changed: 2468 additions & 61 deletions

.env.example

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,13 @@ ENGRAPHIS_LOOP_INTERVAL=60
5858
ENGRAPHIS_LOOP_TOP_K=20
5959
# Decay half-life in days (Ebbinghaus). Higher = memories persist longer.
6060
ENGRAPHIS_DECAY_HALFLIFE_DAYS=7
61+
62+
# ── License & Team mode (Pro) ───────────────────────────────────────────────
63+
# Engraphis core is free forever. A signed license key unlocks Pro features
64+
# (analytics dashboard, compliance export) and Team mode (multi-user Inspector).
65+
# Get a key at https://engraphis.dev/pro, then either set it here or paste it
66+
# in the Inspector's license dialog (persists to ~/.engraphis/license.key).
67+
# ENGRAPHIS_LICENSE_KEY=ENGR1.xxxxx.yyyyy
68+
# Team mode: per-user logins + roles (admin/member/viewer) on the Inspector.
69+
# Requires a Team license; first visit creates the admin account.
70+
# ENGRAPHIS_TEAM_MODE=1

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ build/
1616
.pytest_cache/
1717
.ruff_cache/
1818
models_cache/
19+
.secrets/

AGENTS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ python -m eval.external --dataset locomo10.json --format locomo --offline --limi
5252
# ── v2 Memory Inspector (product UI over MemoryService; same layer as the MCP server) ──
5353
python -m scripts.inspector # http://127.0.0.1:8710 (auth: ENGRAPHIS_API_TOKEN)
5454

55+
# ── Onboarding (writes .env with an absolute DB path; doctor mode verifies install) ──
56+
engraphis-init # or: python -m scripts.init
57+
engraphis-init --check
58+
59+
# ── Commercial layer (docs/LAUNCH_PLAN.md; gates live ONLY in inspector/app.py) ──
60+
python -m scripts.license_admin keygen # vendor keypair → .secrets/ (gitignored)
61+
python -m scripts.license_admin issue --email a@b.co --plan team --seats 5 --days 365
62+
ENGRAPHIS_LICENSE_KEY=ENGR1... # or ~/.engraphis/license.key; free tier = no key
63+
ENGRAPHIS_TEAM_MODE=1 # multi-user Inspector (needs a 'team' license)
64+
5565
# ── Sleep-time consolidation (schedulable local job; also an MCP tool) ────────
5666
python -m scripts.consolidate --db engraphis.db --workspace acme --dry-run
5767

CHANGELOG.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,49 @@
33
All notable changes to Engraphis are documented here. Format loosely follows
44
[Keep a Changelog](https://keepachangelog.com/); versions use SemVer.
55

6+
## [Unreleased] — commercial layer: license keys, Pro analytics/export, Team mode
7+
8+
### Added
9+
- **Offline signed license keys** (`engraphis/licensing.py`): Ed25519-signed
10+
`ENGR1.<payload>.<sig>` keys verified pure-stdlib (RFC 8032 implementation, tested against
11+
the RFC's own vectors) — no phone-home, no license server, no new dependency. Vendor CLI:
12+
`python -m scripts.license_admin keygen|issue|verify` (private key lives in gitignored
13+
`.secrets/`). Free tier is the absence of a key, never an error; a bad/expired key degrades
14+
to free with the reason surfaced in the UI.
15+
- **Pro: Analytics dashboard**`/api/analytics` + an Analytics tab in the Inspector:
16+
weekly growth, retention distribution, decay forecast (what the consolidation sweep will
17+
archive in 7/30 days), resolver action mix, most-connected entities. Data layer is a pure
18+
tested function (`engraphis/analytics.py`); charts are dependency-free inline SVG.
19+
- **Pro: Compliance export**`/api/export` + an export button in the Audit tab: full
20+
bi-temporal workspace dump (live + superseded memories, sessions, audit trail) as
21+
downloadable JSON (`MemoryService.export_workspace`).
22+
- **Team mode** (`ENGRAPHIS_TEAM_MODE=1` + a Team license): multi-user Inspector with
23+
PBKDF2 logins, hashed session cookies (HttpOnly, SameSite=Strict), first-run admin setup,
24+
seat limits from the signed key, and server-side roles — viewer (read) < member
25+
(+ governance) < admin (+ consolidate/users/license/export). Bearer token still works as a
26+
service account for scripts. Single-user setups are byte-for-byte unchanged.
27+
- **Upgrade UX without nagging**: plan badge + license dialog (paste-to-activate via
28+
`/api/license/activate`), locked-feature teasers rendered only where a locked feature was
29+
explicitly opened, and a guided first-run empty state with a copyable MCP config snippet.
30+
- Tests: 40+ new (RFC 8032 vectors, key tamper/expiry/seats, role matrix, login throttle,
31+
402 gating, analytics math) — all offline, `importorskip`-guarded like the rest.
32+
33+
- **Per-user audit attribution**: in team mode, pin/forget/correct audit rows record the
34+
signed-in user's email as the actor (service + engine already supported `actor`; the
35+
Inspector now passes it) — the Team tier's audit trail answers *who*, not just what.
36+
- **`engraphis-init`** — one command from `pip install` to a configured, agent-connected
37+
setup: writes `.env` with an **absolute** DB path (the silent default previously landed in
38+
the package directory — site-packages on pip installs), optional `--token`, prints exact
39+
Claude Code / Cursor / Cline / Zed MCP snippets with the DB path pinned via `env`, and
40+
`--check` is a doctor (install, extras, DB writability, license state).
41+
- Inspector polish: relative timestamps in the audit trail (exact time on hover), `/`
42+
focuses the active tab's search box, Dockerfile documents the Inspector port (8710).
43+
44+
### Docs
45+
- `docs/LAUNCH_PLAN.md` — monetization architecture, tier table, payments plan (merchant of
46+
record), UI/UX roadmap, launch checklist. `SECURITY.md` §6 documents the team-auth design.
47+
- README: corrected the MCP tool count (17), added `engraphis-init` to the quickstart.
48+
649
## [Unreleased] — v1 dashboard drill-down + polish pass
750

851
### Fixed

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ RUN useradd --create-home --uid 10001 engraphis && mkdir -p /data && chown -R en
2323
USER engraphis
2424
VOLUME ["/data"]
2525
EXPOSE 8700
26+
# Memory Inspector (product UI): run with `docker … engraphis-inspector` or a second service.
27+
EXPOSE 8710
2628

2729
HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
2830
CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8700/memory/health').status==200 else 1)"

README.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,38 @@ pip install -e ".[all]" # everything
6262
6363
---
6464

65+
## Free forever vs. Pro
66+
67+
The engine — recall, bi-temporal history, governance, code graph, MCP server, single-user
68+
Inspector — is free and Apache-2.0, permanently. A license key (verified **offline**; no
69+
phone-home, in keeping with local-first) unlocks the paid layer:
70+
71+
| | Free | Pro ($20/mo) | Team ($35/user/mo) |
72+
|---|---|---|---|
73+
| Memory engine + 17 MCP tools ||||
74+
| Memory Inspector (single-user) ||||
75+
| Analytics dashboard (growth, retention, decay forecast) | |||
76+
| Compliance export (full bi-temporal JSON dump) | |||
77+
| Multi-user Inspector: logins, roles, seat management | | ||
78+
| Priority support | |||
79+
80+
Paste your key into the Inspector's license dialog (the plan badge, top-left) or set
81+
`ENGRAPHIS_LICENSE_KEY`. Get a key at <https://engraphis.dev/pro>.
82+
83+
---
84+
6585
## Quickstart A — MCP server (the headline)
6686

6787
Plug Engraphis into any MCP-capable agent. With Claude Code:
6888

6989
```bash
7090
pip install -e ".[mcp]"
91+
engraphis-init # writes .env (DB location) + prints the exact snippets
7192
claude mcp add engraphis -- engraphis-mcp
7293
```
7394

95+
`engraphis-init --check` is the doctor: verifies the install, extras, and DB writability.
96+
7497
For Cursor / Cline / Zed / Windsurf, add to your MCP config:
7598

7699
```json
@@ -81,7 +104,7 @@ For Cursor / Cline / Zed / Windsurf, add to your MCP config:
81104
}
82105
```
83106

84-
Your agent now has 15 tools:
107+
Your agent now has 17 tools:
85108

86109
| Category | Tool | What it does |
87110
|---|---|---|
@@ -240,7 +263,7 @@ engraphis/
240263
│ ├── core/ # v2 engine — interfaces, store, recall, scoring, resolve, schema, ids
241264
│ ├── backends/ # pluggable embedder / vector index / reranker / codegraph (offline fallbacks)
242265
│ ├── service.py # validated MemoryService facade (no MCP dependency)
243-
│ ├── mcp_server.py # MCP server — 15 tools (write/read/governance/code/session)
266+
│ ├── mcp_server.py # MCP server — 17 tools (write/read/governance/code/session)
244267
│ ├── config.py # env-driven settings
245268
│ ├── app.py # REST server (FastAPI) + dashboard + auth middleware
246269
│ ├── routes/ stores/ engines/ llm/ # REST server surface

RELEASE_READINESS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,11 @@ MASTER_PLAN.md; full detail in `CHANGELOG.md`:
112112
3. **Encryption-at-rest** and **built-in rate limiting** (today: rely on disk encryption + a
113113
reverse proxy) — required for the regulated/Enterprise ICP.
114114
4. **Per-token tenant authorization** if you sell multi-tenant; today, isolate by instance.
115-
5. **An actual Pro-tier feature to sell.** The v1 dashboard had two real bugs fixed this pass
115+
5. **An actual Pro-tier feature to sell.** *(RESOLVED 2026-07-03 — see
116+
`docs/LAUNCH_PLAN.md` and `CHANGELOG.md`: offline signed license keys now gate three
117+
shipped features — Pro analytics dashboard, compliance export, and multi-user Team mode
118+
on the Inspector — with activation UX in the product. Remaining before charging: rotate
119+
the dev vendor keypair, set the real purchase URL, wire a merchant of record.)* The v1 dashboard had two real bugs fixed this pass
116120
(Knowledge Graph fragmentation, stored XSS) and is now correct, but "correct" isn't "worth
117121
$20/mo" — it's still a single-user local dashboard with no hosting, login, or team sync. See
118122
`docs/GO_TO_MARKET.md` §10 for the specific recommendation (hosted + multi-user version of

SECURITY.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,29 @@ repos you intend to index, the same way you'd scope any other local tool.
137137
regex indexer on any import or parse failure, rather than failing the write path. Pin
138138
versions and run `pip audit` in your environment.
139139

140+
## 6. Team mode & license keys (commercial layer)
141+
142+
Team mode (`ENGRAPHIS_TEAM_MODE=1` + a `team` license) replaces the single bearer token on
143+
the Inspector's `/api/*` with per-user sessions:
144+
145+
- **Passwords**: PBKDF2-HMAC-SHA256, 600k iterations, per-user salt, ≥10 chars; verification
146+
is constant-time (`hmac.compare_digest`) and unknown emails still burn one PBKDF2 (no
147+
user-enumeration timing oracle). Login failures share one generic message.
148+
- **Sessions**: 32-byte `secrets` tokens delivered as `HttpOnly; SameSite=Strict; Path=/`
149+
cookies and stored **hashed** (SHA-256) with a 12h TTL — a leaked users DB yields no usable
150+
cookies. Logout, user-disable, and demotion revoke server-side. CSRF posture: SameSite=Strict
151+
+ JSON-only bodies + loopback-only CORS; if you expose the Inspector beyond loopback, put
152+
TLS in front (the cookie does not set `Secure` on plain HTTP loopback).
153+
- **Roles** are enforced in the HTTP layer on every request (viewer < member < admin); the UI
154+
only hides what the server already refuses. The last active admin cannot be demoted or
155+
disabled. A valid bearer token acts as an admin service account so automation keeps working.
156+
- **Login throttle**: 5 failures / 15 min → 60 s lockout (in-process, matching the Inspector's
157+
single-process posture).
158+
- **License keys** are Ed25519-signed payloads verified offline against a pinned vendor public
159+
key (`engraphis/licensing.py`); nothing phones home. Keys carry no secrets — they are
160+
entitlements, and the private signing key must never live in the repo (gitignored
161+
`.secrets/`, rotate before selling: `python -m scripts.license_admin keygen`).
162+
140163
## Known limitations (not yet mitigated)
141164
- Rate limiting: an optional in-process per-IP limiter now ships (`ENGRAPHIS_RATE_LIMIT`,
142165
`ENGRAPHIS_RATE_WINDOW`), off by default; still front multi-process/distributed deployments

docs/GO_TO_MARKET.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ roadmap item, not a shipped, billable feature. What's actually true today:
119119

120120
- The **free core is genuinely strong**: hybrid recall, bi-temporal history (`why`/`timeline`),
121121
self-maintaining facts (deterministic conflict resolution), governance (forget/pin/correct,
122-
scope-checked), a code-symbol graph, and a 15-tool MCP server — all covered by 127 passing
122+
scope-checked), a code-symbol graph, and a 17-tool MCP server — all covered by 127 passing
123123
tests. That is a real, demonstrable advantage over "just a vector store," and it's free,
124124
matching Letta's "self-hosted = all features" positioning from §5.
125125
- The **v1 dashboard** (the closest thing to a "Memory Inspector UI" that exists) had two real

docs/LAUNCH_PLAN.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Engraphis — Launch Plan (v1.0 release + first paid tier)
2+
3+
_Date: 2026-07-03. Companion to `RELEASE_READINESS.md` (state audit) and
4+
`docs/GO_TO_MARKET.md` (pricing research). This document is the execution plan: what ships,
5+
in what order, and how the paid tier works technically and commercially._
6+
7+
## 1. Where we are
8+
9+
The free core is launch-ready (127 tests, offline gate green, 17 MCP tools, hardened write
10+
path). What was missing for revenue — and what this pass adds — is the commercial layer:
11+
there was no license mechanism, no paid feature, and no upgrade path in the product. See §3.
12+
13+
## 2. Monetization architecture (decided 2026-07-03)
14+
15+
**Model: open-core with offline signed license keys.** The core stays Apache-2.0 and fully
16+
functional. Pro features ship in this repo but activate only with a valid key. Keys are
17+
Ed25519-signed JSON payloads verified **offline** — no phone-home, no license server, which
18+
keeps the local-first promise intact (a memory engine that phones home would undercut the
19+
entire pitch).
20+
21+
- Key format: `ENGR1.<base64url payload>.<base64url signature>`; payload carries plan,
22+
features, seats, expiry. Verified against the vendor public key pinned in
23+
`engraphis/licensing.py`. Verification is pure stdlib (RFC 8032 Ed25519), so the
24+
numpy-only core guarantee holds.
25+
- Issue keys with `python -m scripts.license_admin issue --email … --plan team`. The signing
26+
key lives in `.secrets/` (gitignored). **Rotate the committed dev public key before selling
27+
a single license** (`license_admin keygen`), and keep the production private key in a
28+
password manager, never on a dev box.
29+
- Honesty note (Apache-2.0): a determined user can fork out the gate. That is the accepted
30+
trade of the Sidekiq-style model — you sell convenience, updates, and support to the honest
31+
majority. Do not escalate to obfuscation; it poisons trust and never works anyway.
32+
33+
### Tiers
34+
35+
| Tier | Price (target) | What's in it |
36+
|------|----------------|--------------|
37+
| Free | $0 forever | Whole engine: MCP server, recall/why/timeline, governance, code graph, single-user Inspector |
38+
| Pro | $20/mo or $200/yr | Analytics dashboard, compliance export (full bi-temporal JSON dump), priority support |
39+
| Team | $35/user/mo | Pro + multi-user Inspector: logins, roles (admin/member/viewer), seat-limited keys |
40+
41+
$20 anchors against Letta Pro ($20) and mem0 Starter ($19); see GO_TO_MARKET.md §10. Team
42+
pricing is per-seat because the seat count is in the signed key.
43+
44+
### Payments & fulfillment (not yet built — next step after this pass)
45+
46+
Use a merchant-of-record (Polar.sh or Lemon Squeezy — handles VAT/sales tax, ~5% fee) rather
47+
than raw Stripe at this stage. Flow: checkout → webhook → `license_admin issue` → key
48+
emailed. Automate with a ~50-line serverless function when volume justifies it; issue keys
49+
manually for the first customers (it's also a customer-discovery channel). Add the purchase
50+
URL in the Inspector's license dialog once live.
51+
52+
## 3. What ships in this pass (implemented)
53+
54+
1. **`engraphis/licensing.py`** — key parsing/verification, feature registry, cached
55+
`current_license()`; reads `ENGRAPHIS_LICENSE_KEY` or `~/.engraphis/license.key`.
56+
2. **`scripts/license_admin.py`** — vendor CLI: `keygen`, `issue`, `verify`.
57+
3. **Inspector license UX** — plan badge in the header, license dialog (activate key, see
58+
features), tasteful locked-tab teasers. Free tier is never nagged mid-workflow; upsell
59+
surfaces are opt-in clicks.
60+
4. **Pro: Analytics tab** — memory growth, retention distribution, decay forecast (which
61+
memories fall below the archive threshold in 7/30 days), resolver action mix, top
62+
entities. Server-side in `engraphis/analytics.py` (numpy/stdlib only), inline-SVG charts
63+
client-side (no chart library, consistent with the zero-dependency house style).
64+
5. **Pro: compliance export** — one-click full workspace dump (memories incl. superseded
65+
history, audit trail, sessions) as attachment-download JSON.
66+
6. **Team: multi-user Inspector**`ENGRAPHIS_TEAM_MODE=1` + a `team` key enables login
67+
(PBKDF2, HttpOnly session cookie), first-run admin setup, roles enforced server-side
68+
(viewer=read, member=+governance, admin=+consolidation/users/export), Team tab for user
69+
management. Without team mode nothing changes for existing single-user setups.
70+
7. **Tests** for all of the above, following the repo's `importorskip` CI-gate convention.
71+
72+
## 4. UI/UX improvements — beyond this pass
73+
74+
Ordered by effort-to-impact; the Inspector is already accessible (ARIA tabs, keyboard nav,
75+
dark/light) so this is polish, not rescue:
76+
77+
1. **First-run experience**: when no workspaces exist, show a guided empty state with the
78+
exact MCP config snippet to paste into Claude Code/Cursor (copy button), instead of a
79+
toast. Biggest funnel fix available — the current first screen is blank.
80+
2. **Onboarding command**: `engraphis init` that writes `.env`, picks a DB path, and prints
81+
the MCP snippet. Closes the "install → configured agent" gap in one step.
82+
3. Global search-as-you-type across tabs (debounced recall), keyboard palette (`/` to focus
83+
search), relative timestamps ("3d ago") with exact time on hover.
84+
4. Graph visualization of entity/link neighborhoods in the detail dialog (SVG, force layout
85+
is overkill — radial layout is fine at this scale). Candidate second Pro feature.
86+
5. Retire the v1 dashboard from the default install (`engraphis-server` keeps serving it for
87+
compat, but docs point at the Inspector only) — one product surface, one story.
88+
89+
## 5. Feature roadmap (next / later)
90+
91+
**Next (pre-1.0):** encryption-at-rest for the SQLite file (SQLCipher optional extra →
92+
`encryption` feature flag, regulated-ICP requirement per RELEASE_READINESS.md §"Before you
93+
charge" #3); consolidation policies (saved schedules with per-scope thresholds) as a Pro
94+
feature; publish LoCoMo/LongMemEval numbers (the eval adapter already exists).
95+
96+
**Later:** SSO/OIDC for Team (gate: first team customer asking); hosted Inspector (gate:
97+
recurring demand — it abandons local-first, so it must be pull, not push); scale backends
98+
(Qdrant/pgvector already behind interfaces); per-token tenant authorization for
99+
multi-tenant hosting.
100+
101+
## 6. Launch checklist (ordered)
102+
103+
1. ~~License mechanism + first three paid features~~ (this pass).
104+
2. Rotate vendor keypair; store private key offline. Set the real purchase URL in the
105+
Inspector dialog and `licensing.py`.
106+
3. Set up Polar/Lemon Squeezy product + webhook → key issuance.
107+
4. `git commit` (the tree at HEAD must be the audited one), tag `v0.2.0`, push, verify CI
108+
matrix (3.9/3.11), publish wheel to PyPI, smoke-test `pip install engraphis[all]` and the
109+
Docker image.
110+
5. Run LoCoMo benchmark, publish numbers in README (honest recall@k, per
111+
RELEASE_READINESS.md #1).
112+
6. Trademark search on "Engraphis" (#2 there) before spending on brand.
113+
7. Launch free tier loudly (Show HN, MCP directories, r/LocalLLaMA — the local-first angle
114+
is the hook), sell quietly (license dialog + pricing page). Revisit pricing after ten
115+
real conversations.
116+
117+
## 7. Risks
118+
119+
- **Someone forks out the gate** — accepted (see §2); mitigation is velocity and support,
120+
not DRM.
121+
- **Team mode expands the attack surface** — mitigated: PBKDF2-HMAC-SHA256 (600k iters),
122+
hashed session tokens, SameSite=Strict cookies, login backoff, server-side role checks on
123+
every route; see SECURITY.md §6. Still run `/security-review` on any change touching it.
124+
- **Paid features drift into the free core's value story** — the line is: *the engine
125+
remembers for free; seeing, proving, and sharing what it remembers is paid.* Analytics,
126+
export, and team are all on the right side of that line. Keep it that way.

0 commit comments

Comments
 (0)