Skip to content

Releases: stevepridemore/graph-memory

v0.3.0 — curl-pipeable installers + pre-built GHCR image

11 May 03:05
f285354

Choose a tag to compare

First release that ships without requiring users to clone the repo or build from source. The new install paths are documented in the README.

Highlights

  • Primary device install (machine running the containers):

    curl -fsSL https://raw.githubusercontent.com/stevepridemore/graph-memory/v0.3.0/scripts/install-primary.sh | bash -s v0.3.0

    PowerShell mirror at scripts/install-primary.ps1.

  • Secondary device install (anything pointing at the primary over Cloudflare Tunnel):

    curl -fsSL https://raw.githubusercontent.com/stevepridemore/graph-memory/v0.3.0/scripts/install-secondary.sh | bash -s v0.3.0 <tunnel-host>

    PowerShell mirror at scripts/install-secondary.ps1.

  • Developer install unchanged: clone + docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d.

What's in the box

  • Pre-built MCP image at ghcr.io/stevepridemore/graph-memory-mcp:v0.3.0 (also tagged :latest). Multi-stage build means no host-side npm install needed.
  • 12 graph-memory slash commands vendored under skills/ and installed to ~/.claude/skills/ by the installer.
  • Container entrypoint auto-seeds the prompts directory and generates a self-signed TLS cert on first run.
  • New .github/workflows/release.yml publishes the GHCR image on every v* tag.
  • scripts/sync-dream-skill.py now does platform-aware path substitution (--os auto|windows|unix).

Bug fixes

  • Slash commands ingest, ingest-audio, and graph-dream were referencing ~/.claude/graph-memory/ for the ingest queue, but the actual data dir is ~/graph-memory/. Fixed.
  • MCP server now generates a self-signed cert on first run instead of crashing with ENOENT: server.crt.

Tested

  • Tier 1 local: install dry-run on a WSL clone + multi-stage docker build + docker compose up against the locally-tagged image. Both containers healthy, /health returns 200 over HTTPS.
  • Tier 2 live: anonymous docker pull from GHCR + installer running against the published branch artifacts. Same green result.

🤖 Generated with Claude Code

v0.2.1 — STRIDE threat model fully closed (16/16)

09 May 21:23

Choose a tag to compare

Closes the remaining three STRIDE findings deferred at the v0.2.0 OAuth hardening pass. Internal threat model is now fully resolved (16 of 16 findings).

Included PRs

  • #23OAUTH_ALLOWED_EMAILS allowlist (closes S-2). Optional second-layer guard on top of Cloudflare Access at /oauth/authorize. Supports exact emails and *@domain wildcards. Re-validated on grant_type=refresh_token so removing an email invalidates refresh tokens within seconds.
  • #24readBody size caps (closes D-3). 64 KB on OAuth routes, 4 MB on /mcp. Two-layer defense (fast reject via Content-Length, streaming reject via byte counter). Hardcoded named constants.
  • #25 — Drop confidential-client support (closes I-1). Removes a misadvertised path: the server had been generating and storing plaintext client_secrets but never verifying them. Discovery metadata now advertises ["none"] only; /oauth/register rejects confidential auth methods. Future-enhancements note added to docs/REMOTE.md covering the deferred server-to-server / client_credentials case.

Compatibility

All real clients (claude.ai web, Claude Desktop, Claude Code) use PKCE + token_endpoint_auth_method: "none", which became mandatory in #18. No on-disk migration required. Production deployed at 182204a and smoke-tested on the wire.

v0.2.0 — OAuth 2.1 security hardening

09 May 06:02

Choose a tag to compare

v0.2.0 — OAuth 2.1 security hardening pass

Closes 12 of 16 findings from an end-to-end STRIDE threat model of the
public deployment at https://your-host.example/mcp.

  • POST /oauth/revoke (RFC 7009) — token revocation with persistent
    deny-list at $GRAPH_MEMORY_HOME/oauth/revoked.json (auto-prunes
    naturally-expired entries). revocation_endpoint advertised in
    authorization-server metadata.

  • Every issued access/refresh token now carries a unique jti claim for
    individual revocation lookup.

  • redirect_uri hostname allowlist on POST /oauth/register
    (claude.ai, *.claude.ai, claude.com, *.claude.com, localhost,
    127.0.0.1 by default; suffix-match-safe wildcard). Configurable via
    the new OAUTH_REDIRECT_URI_HOSTS env var.

  • Registration cap via OAUTH_MAX_CLIENTS (default 100; 429 once full).

  • clients.json now written with mode 0o600.

  • Structured OAuth event logging to
    $GRAPH_MEMORY_HOME/logs/oauth-events.jsonl: register / register_fail /
    authorize_ok / authorize_fail / token_issue / token_refresh /
    token_consume_fail / token_pkce_fail / token_refresh_fail /
    client_deregistered / revoke_ok / revoke_noop / bearer_verify_fail.
    Each event carries client_id, email, jti, redirect_uri_host, reason,
    and source_ip as applicable. Best-effort; never throws from the
    request path.

  • Refresh-token TTL: 90 days → 30 days. Existing tokens keep their
    original expiry; new tokens issued after deploy use the shorter TTL.

  • PKCE-S256 is now required for any client registered with
    token_endpoint_auth_method: "none" (i.e. public clients including the
    claude.ai connector). code_challenge_method=plain is rejected.
    Discovery metadata advertises ["S256"] only. Existing claude.ai
    connectors already send S256 — no flow change.

  • Refresh-grant rejects tokens whose client_id is no longer in
    clients.json (closes E-4).

  • 401 response bodies for bearer-verify failures now use a constant
    string; verbose jose reasons live in oauth-events.jsonl (closes I-3).

  • BearerVerifyError extends TenantAuthError, carrying .reason
    separately from the public .message.

  • revokeToken signature: Promise →
    Promise<{ revoked: boolean; jti?: string }>.

  • New module src/shared/oauth-events.ts (logger, OAuthEvent interface,
    pickClientIp helper).

  • config.ts now honors GRAPH_MEMORY_HOME env var (was hardcoded to
    homedir()/graph-memory).

  • docker-compose pins GRAPH_MEMORY_HOME=/root/graph-memory in the
    container's environment block to override the host-side value
    injected via env_file.

ID Severity Status
S-1 HIGH closed
T-1 LOW closed
D-1 MED closed
E-1 HIGH closed
E-2 MED closed
E-3 HIGH (chain) closed (subsumed by S-1 fix)
E-4 LOW closed
R-1 MED closed
I-3 LOW closed
S-3, T-2, I-2, D-2 informational no action needed
S-2 MED open (deferred)
I-1 LOW open (deferred — code path currently unused)
D-3 LOW–MED open (verification step)

47 OAuth unit tests + 12 OAuth-event-log tests + 46 Neo4j integration
tests + 2 PKCE tests = 100/100 passing against a throwaway Neo4j
side-car. CI runs against a fresh service container per build.

npm audit: 5 vulnerabilities (1 high, 4 moderate) → 0. All in
transitive deps fixable by patch/minor bumps; none reachable from
runtime paths we exercise.

2026-05-09.

v0.1.1 — Decay correctness + test coverage

08 May 03:11

Choose a tag to compare

⚠️ Operational note before upgrading

graph_decay was previously dropping the months component of a normalized duration, so any backdating beyond ~28 days only applied a fraction of expected decay. After this release, decay matches the documented per-type half-lives (Preferences ~693d, Events ~99d, etc.).

First run on an existing graph may show large catch-up decay. Recommended:

graph_export { label: "pre-v0.1.1-decay-fix" }   # back up first
graph_decay  { dry_run: true }                   # preview the impact
graph_decay  {}                                  # apply when ready

What's new

  • Fixed decay-formula bug (#13, commit 45edc8d) — duration.between().days returned only the days component of a normalized year/month/day duration. Switched to duration.inDays().days which forces an all-days representation.
  • 15 new integration tests covering decay math, bi-temporal queries, contradiction edge cases (#13)
  • Test suite is data-safe by construction (#12) — per-tenant isolation plus a startup guard that refuses to run against graphs holding non-test data. Catches the footgun where the test defaults match the production docker-compose Neo4j.
  • graph_merge tests added; stale test signatures repaired (#10)
  • CI runs typecheck + integration suite against a Neo4j 5.20 service container on every PR (#9, #10, #11)

New internal APIs

Not user-facing MCP tools — useful for ops/maintenance scripts:

  • Neo4jClient.clearTenant(tenantId) / countNodesOutsideTenantPrefix(prefix)
  • Neo4jClient.setNodeLastSeen(tenantId, id, daysAgo) / setEdgeLastConfirmed(...)
  • Neo4jClient.setEdgeInvalidAt(tenantId, fromId, toId, relation, isoString) — closes a documented-but-unimplemented gap; supersession was in the schema but had no public API before this.

Other

  • README badge cache-busted (#14)
  • GitHub Actions bumped to v5 (Node 24 internals) (#11)

Full changelog: v0.1.0...v0.1.1

v0.1.0

07 May 18:58

Choose a tag to compare

What's Changed

New Contributors

Full Changelog: https://github.com/stevepridemore/graph-memory/commits/v0.1.0