Skip to content

Releases: markmhendrickson/neotoma

v0.18.2

26 Jun 10:05
f38dd77

Choose a tag to compare

Install

npm install -g neotoma@0.18.2
npm https://www.npmjs.com/package/neotoma/v/0.18.2
Compare v0.18.1v0.18.2view diff

Two targeted bug fixes: entity resolution no longer accepts provenance labels as an entity's canonical name, and SOURCE_PRIORITY_IGNORED warnings now tell you exactly which fields are affected and why.

Highlights

  • Offline/auto-discovered entities no longer get named after a provenance label. Fields like source_name, data_source, and origin are now rejected as canonical name candidates alongside the existing source block — preventing unrelated entities from merging under a shared import label (e.g. every auto-resolved entity named "gmail import"). Fixed in src/services/entity_resolution.ts.
  • SOURCE_PRIORITY_IGNORED warnings are now self-diagnosing. The warning message now names each written field that ignores source_priority and states its effective merge strategy (e.g. 'title' uses last_write), so you know exactly which fields to target in reducer_config.merge_policies without re-reading the schema. Fixed in src/services/source_priority_warning.ts.

What changed for npm package users

Runtime / data layer

  • Entity resolution: source_name, data_source, and origin are now included in the provenance-label deny-list for canonical name derivation. If your store calls were producing entities with names like "gmail import" or "stale cache" after a background sync, this release corrects the root cause. No schema or client changes are required.
  • store_warnings[] shape for SOURCE_PRIORITY_IGNORED: the message field now includes a per-field breakdown ('field' uses strategy) and a policy note distinguishing between "no schema" and "schema present but no highest_priority entry". The code, observation_index, entity_type, and entity_id fields are unchanged.

Shipped artifacts

  • openapi.yaml — unchanged; no route or schema additions in this patch.
  • dist/ — updated for the two changed source files.

API surface & contracts

No OpenAPI changes. The store_warnings[] entry for SOURCE_PRIORITY_IGNORED carries a richer message string but the same structure. Callers that parse only the code field are unaffected.

Behavior changes

  • Entities that were previously auto-named after source_name, data_source, or origin field values will resolve differently going forward. If you have existing entities with provenance-label names, you may want to re-merge or split them — no automatic migration is applied.
  • The text of SOURCE_PRIORITY_IGNORED warnings changes. Callers that parse the message string for display or logging will see richer output.

Fixes

  • #1821fix(entity-resolution): reject source_name/data_source/origin as canonical_name. Provenance labels could become an entity's identity when no better name field was present, causing unrelated entities to merge under a shared import label.
  • #1822fix(store): enrich SOURCE_PRIORITY_IGNORED warning with field names and strategies. The warning previously identified the entity type and source priority but did not name which fields were ignoring it or why, forcing callers to cross-reference the schema to understand the fix.

Tests and validation

  • tests/services/entity_resolution.test.ts — 58 new assertions covering the three new provenance-label rejections and their interaction with the existing deny-list.
  • tests/unit/source_priority_ignored_warning.test.ts — 165 new unit assertions covering ignoredFieldStrategies and the enriched buildSourcePriorityIgnoredWarning message shape across no-schema, partial-schema, and highest_priority configurations.
  • tests/integration/store_source_priority_ignored_warning.test.ts — 9 new integration assertions validating the end-to-end warning emission path.
  • Security gates: G1 (security:classify-diff) sensitive=false, G2 (security:lint) 0 errors, G3 (security:manifest:check + test:security:auth-matrix) passed.

Security hardening

Not security-sensitive. npm run security:classify-diff -- --base v0.18.1 --head HEAD reported sensitive=false (5 changed files, all in entity-resolution logic and warning formatting — no middleware, auth, or route-registration paths).

Security review artifact: docs/releases/in_progress/v0.18.2/security_review.md — verdict: yes (no findings, no residual risks).

No security-sensitive surfaces touched.

Breaking changes

No breaking changes. No OpenAPI validation tightening, no request-shape changes, no field promotions or removals. Patch bump is correct per SemVer.


Commits (v0.18.1v0.18.2)

  • f38dd77 chore(release): bump version to v0.18.2 + supplement (#1836)
  • aee422e fix(store): enrich SOURCE_PRIORITY_IGNORED warning with field names and strategies (#1822) (#1835)
  • a0b6c68 fix(entity-resolution): reject source_name/data_source/origin as canonical_name (#1821) (#1834)

Full compare: v0.18.1...v0.18.2

v0.18.1

26 Jun 06:55
9a6e49d

Choose a tag to compare

v0.18.1 Release Supplement

Summary

Patch release that connects the two last-mile pipes on v0.18.0 by-reference source storage (#1775), so it is reachable over HTTP and through the natural "file + its entities" call shape. Both gaps were found by a developer-release evaluator who validated the engine end-to-end (zero-byte writes, SOURCE_UNAVAILABLE / SOURCE_REFERENCE_STALE drift cases) against a production DB.

Fixes

  • By-reference storage reachable over HTTP (#1826). source_storage was missing from openapi.yaml StoreRequest (which is additionalProperties: false), so the edge guard rejected POST /store with ERR_UNKNOWN_FIELD — the field only worked over the /mcp route. Added source_storage (enum: [inline, reference]) to the HTTP contract and regenerated openapi_types.ts.
  • No more silent inline fallback with entities[] + file (#1827). store({ entities, file_path, source_storage: "reference" }) silently stored inline and copied the bytes, because the hasEntities && hasUnstructured branches recursed into store() for the file leg without forwarding source_storage. It is now propagated, so the natural "file + its entities" call stores by reference as intended.

Behavior changes

  • Both surfaces (HTTP POST /store and the file+entities call shape) now honor source_storage: "reference" identically to the single-file MCP path. No other behavior change; inline remains the default.

Breaking changes

  • None.

Install: npm install neotoma@0.18.1 · npx neotoma@0.18.1
Compare: v0.18.0...v0.18.1

v0.18.0

25 Jun 20:39
475e642

Choose a tag to compare

v0.18.0 Release Supplement

Highlights

v0.18.0 closes the "my files and my edits are part of the loop" gap for local-first operators with two long-standing evaluator asks — by-reference source storage and disk-to-entity write-back — alongside the Bundles capability system (definition → runtime → activation → surfacing), richer sandbox showcase packs, and a set of cross-user read-leak security fixes.

What changed for npm package users

Sources / storage — by-reference (source_storage: "reference") (closes #1775)

  • store (and parse_file) accept source_storage: "inline" | "reference". With reference, Neotoma reads the file once to compute its content_hash + metadata and persists a sources row without copying the bytes — so a large or local file (e.g. a PDF on a space-constrained machine) becomes first-class in the graph without inflating the DB.
  • Retrieval resolves the path at read time; a moved/deleted file surfaces a structured SOURCE_UNAVAILABLE (never a misleading empty blob), and content drift surfaces SOURCE_REFERENCE_STALE. Content-addressing, dedup, and interpretation linkage are unchanged.
  • Default inline ⇒ zero behavior change for existing callers.

Mirror profiles — disk-to-entity write-back (neotoma mirror push) (closes #1776)

  • New neotoma mirror push <path|profile> round-trips operator edits of a mirrored markdown file back into Neotoma as correct()-ions, behind an opt-in per-profile allow_disk_writeback.
  • Editable fields only (generated/frontmatter regions are ignored); a 3-way diff against the last-synced base flags conflicts instead of overwriting; --check previews the exact corrections; edits are stamped observation_source: "human".

Bundles

  • A capability-bundle system landed end-to-end: definition lock (m1), runtime loader + enforcement + linter (m2), activation state store + CLI + manage_bundles MCP tool (m3), and /bundles surfacing — HTTP route + Inspector panel + scaffold tooling (m4).

Docs / onboarding

  • docs/foundation/what_to_store.md now leads with "you don't keep Neotoma clean — Neotoma keeps your state clean for you" and recasts the Tier 1/2/3 tables as a guide, not a gate.
  • New docs/vocabulary/plain_language.md — a plain-language primitives cheat-sheet (record/entity, observation, source, interpretation, relationship) with a "you say → Neotoma says" mapping.

Behavior changes

  • All additive / opt-in. source_storage defaults to inline; allow_disk_writeback defaults off; bundles enforce only when installed.

Security hardening

  • Scoped pre-existing cross-user read leaks in MCP handlers + aggregates (#1795).
  • Sandbox: degrade an unresolvable session bearer to anonymous instead of 401 (#1790); exempt internal seeding from the write rate limit (#1797).

Breaking changes

  • None. Every new surface is opt-in and backward-compatible.

Documentation

  • Neotoma issues #1775 / #1776 carry the full designs; both were driven by developer-release evaluator feedback.

v0.17.0

25 Jun 09:46
3f49ae2

Choose a tag to compare

Install

npm install -g neotoma@0.17.0
npm https://www.npmjs.com/package/neotoma/v/0.17.0
Compare v0.16.0v0.17.0view diff

v0.17.0 Release Supplement

v0.17.0 ships four agent-facing capabilities surfaced from a high-volume production integration — a single-call entity-identity resolver, machine-readable per-release capability delta, discard-by-default high-velocity intake with read-time sightings aggregation, and an embeddable (chrome-less) Inspector graph — alongside auth parity for AAuth-admitted MCP sessions, proxy session resilience, multi-user data isolation fixes, and a large expansion of the agentic eval harness. All new data surfaces are additive and backward-compatible.

Highlights

  • Resolve entity identity from any combination of signals in one call. identify_entity_by_signals accepts a bundle of name, email, company, domain, phone, and open-ended properties and returns a best-match entity with an identity score, resolution band (high/medium/low/unresolved), and top-N candidates — so an agent can auto-merge on high confidence, ask a human on medium, and create-new on low, without chaining three separate retrieve calls.
  • Know which tools an upgrade adds or removes before touching production. npm_check_update gains an opt-in include_capability_delta: true flag that returns new_tools and removed_tools arrays alongside a one-line capability_delta_recommendation, letting auto-upgrading agents enumerate newly available MCP tools in the same update-check call.
  • Keep high-velocity sources out of the graph without losing data. store accepts intake: { mode: "overflow" } to append raw payloads to a configurable JSONL sink (NEOTOMA_OVERFLOW_SINK) instead of creating entities; a new canonical_key + collapse_by mechanism deduplicates sightings at read time without merging or deleting stored rows.
  • Embed the Inspector graph anywhere via iframe. The new chrome-less /embed/graph?apiBase=<url>&node=<id> route renders the graph explorer with no sidebar or header, inherits CSS-variable skin tokens, and emits postMessage on node double-click so a host page can react — zero behavior change for the existing in-app /graph route.
  • AAuth-admitted agents can now use MCP tools directly. An agent with a valid agent_grant (AAuth-signed requests) can now authenticate an MCP session without a Bearer token, at exact parity with the REST direct-write endpoints. Capability scope ((op, entity_type) ceiling) is enforced per tool call, identical to the REST path.
  • Enforce allowed values, numeric bounds, and patterns at write time. register_schema now accepts per-field constraints (min/max, enum, pattern, banned) and a schema-level constraint_violation_policy ("reject" aborts the write; "warn" stores a non-blocking advisory). Schemas with no constraints are completely unaffected. (#1756)

What changed for npm package users

CLI (neotoma, neotoma request, …)

  • neotoma request gains a --aauth flag (#1748, #1752). Pass it to authenticate via AAuth request signature instead of a bearer token — the CLI sends no Authorization header so the per-agent JWK signature is the credential. Requires NEOTOMA_AAUTH_PRIVATE_JWK_PATH + NEOTOMA_AAUTH_SUB/NEOTOMA_AAUTH_KID. Useful for testing agent attribution from the CLI.
  • Per-agent AAuth JWK path override (NEOTOMA_AAUTH_PRIVATE_JWK_PATH) lets the CLI signer resolve the private JWK from an env-configured path rather than the global default (#1744). Useful when running multiple agent identities from the same machine.
  • neotoma digest import --from-ndjson is the consuming counterpart to the observer NDJSON feed (#1777). Reads an NDJSON file and imports entities into the local database.

Runtime / data layer

  • Proxy resilience: the stdio MCP proxy (src/proxy/mcp_stdio_proxy.ts) now recovers MCP sessions across backend restarts and non-sticky replica routing (#1750). A bounded re-initialize + retry loop (DEFAULT_MAX_ATTEMPTS=4, exponential backoff) replaces the single-shot 503 recovery; per-request timeouts (DEFAULT_REQUEST_TIMEOUT_MS=15s) fail fast into a retry instead of stalling. Configurable via NEOTOMA_MCP_PROXY_TIMEOUT_MS and NEOTOMA_MCP_PROXY_MAX_ATTEMPTS.
  • Multi-user data isolation fix: observation existence checks and snapshot computation queries in store are now scoped by user_id (#1753). Previously, a content-addressed observation from a different user with the same ID could silently suppress the current user's insert; snapshot computation could bleed cross-user observations into a snapshot. Both are fixed.
  • Prod server non-watch default: neotoma api start in production now defaults to non-watch mode (#1751), matching how most operators run the server and avoiding accidental file-watcher overhead on --env prod.
  • rc-autodeploy follow-ups: fix(ops) tidies the autodeploy flow after the v0.16.0 rc-autodeploy feature review (#1754).
  • SOURCE_PRIORITY_IGNORED store warning (#1774): when an observation carries a non-default source_priority but every field on the entity type uses a merge strategy that ignores it (last_write, merge_array, or most_specific without tie_breaker: source_priority), the priority value is now surfaced as a non-blocking advisory warning in the store response instead of being silently discarded.

Shipped artifacts

  • openapi.yaml is updated with a new POST /identify_entity_by_signals operation and updated store / npm_check_update schemas. See API surface section below.
  • src/shared/capability_manifest.json is a new generated artifact (built by scripts/generate-capability-manifest.ts). It is included in the npm package and is the source of truth for npm_check_update capability delta computation.

API surface & contracts

New endpoints

  • POST /identify_entity_by_signals (MCP: identify_entity_by_signals) — multi-signal entity resolver. Requires bearer auth; sandbox_allowed: none. Request body: { signals: { name?, email?, company?, domain?, phone?, additional_signals? }, entity_type?, top_n? }. Response: { best_match: { entity, identity_score, resolution_band, matched_signals } | null, candidates: [...] }.

Updated endpoints / tools

  • POST /store (MCP: store) — new optional intake field: { mode: "graph" | "overflow", reason? }. Default "graph" is unchanged. mode: "overflow" skips graph writes and appends to the JSONL sink; response shape changes to { overflowed: true, sink_path, line_offset }. New canonical_key and sighting_source_id fields on observation inputs are accepted and indexed. New SOURCE_PRIORITY_IGNORED advisory warning when source_priority is set but has no effect under the schema's merge strategies (#1774).
  • GET /entities (MCP: retrieve_entities) — new optional collapse_by: "canonical_key" parameter. When set, groups observations sharing a canonical_key at read time; response carries a sightings[] array on each synthesized result.
  • npm_check_update (MCP tool) — new optional include_capability_delta: boolean (default false). When true, response gains new_tools, removed_tools, capability_delta_recommendation, and (on degraded computation) capability_delta_note.
  • POST /register_schema (MCP: register_schema) — new optional per-field constraints object (min, max, enum, pattern, banned) and schema-level constraint_violation_policy ("reject" | "warn", default "reject"). Schema registration validates constraint fields at registration time. Schemas without constraints are unaffected (#1756).
  • GET /retrieve_entity_snapshot (MCP: retrieve_entity_snapshot) — new optional at_ingested parameter: ingestion-time cutoff ("what did we know by T"), excluding observations whose created_at is after the cutoff even if their observed_at predates it (#1777). Supplying both at and at_ingested ANDs the bounds.

OpenAPI security

/identify_entity_by_signals has security: [bearerAuth: []] and is present in scripts/security/protected_routes_manifest.json with requires_auth: true. The manifest has been regenerated and is in sync with openapi.yaml.

MCP initialize version fix

The serverInfo.version field in the MCP initialize response now reports the real server package version (e.g. 0.17.0) instead of the hardcoded "1.0.0" (#1689). Clients that inspect serverInfo.version for drift detection now get accurate data.

Behavior changes

  • AAuth MCP authentication parity: AAuth-admitted agents (active agent_grant, verified signature) can authenticate an MCP session without a Bearer token. The tool-call (op, entity_type) capability ceiling and governance-type guard apply identically to the REST path. Existing Bearer/OAuth callers are unaffected.
  • --strict merge gate expanded: store with --strict now permits merges via canonical_name, email, and stable internal/external ID fields (message_id, turn_key, thread_id, etc.), in addition to schema-declared canonical_name_fields. Heuristic fallbacks (name, title, fuzzy matches) are still refused. The updated error message explains all allowed paths (#1753).
  • Prod server watch mode: neotoma api start --env prod now defaults to non-watch mode.
  • Proxy retry semantics: MCP proxy sessions that previously fell permanently "unavailable" after a backend restart or replica routing event now recover transparently with bounded retries. The observable change is that tool calls succeed (with a short delay) across restarts rather than failing with a 503 or timeout.
  • Ingestion-time snapshot cutoff (at_ingested): retrieve_entity_snapshot gains an at_ingested parameter (ingestion-time cutoff: "what did we know by T", excluding observations whose `crea...
Read more

v0.16.0

18 Jun 16:28
b969383

Choose a tag to compare

Install

npm install -g neotoma@0.16.0
npm https://www.npmjs.com/package/neotoma/v/0.16.0
Compare v0.15.0v0.16.0view diff

v0.16.0 Release Supplement

Summary

v0.16.0 ships the first-party agent SDK + memory-protocol layer, inspector skinning for embedders, merge-relationship hardening, override-policy enforcement for agent_definition writes, and the remaining PR-salvage queue from the v0.16.0 consolidation pass.

  1. @neotoma/agent harness SDK (#318) — protocol-enforcing TypeScript SDK with withMemory / NeotomaMemory turn lifecycle (bounded retrieval → user-phase store → assistant-phase store), deterministic idempotency keys, and REFERS_TO / PART_OF edges by construction.
  2. Python NeotomaMemory layer (#322) — parity memory protocol for neotoma-client (with_memory, sync + async), Claude Code hook integration, and published SDK docs (docs/developer/sdk_python.md, site pages).
  3. Inspector skinning (#1585) — configurable palette via NEOTOMA_INSPECTOR_SKIN (bundled presets under inspector/public/skins/) or NEOTOMA_INSPECTOR_SKIN_CONFIG (arbitrary JSON path); server injects sanitized CSS variables before first paint.
  4. Merge relationship repoint (#1534 / #1507)mergeEntities repoints relationship_observations to the survivor, returns relationships_repointed in the OpenAPI merge response, and collapses duplicate edges by relationship_key (not metadata hash).
  5. override_validation service (#1634 / #398) — per-field write policies on agent_definition entities enforced at observation/correction write time via enforceOverridePolicy.
  6. Issues repo discovery (#1617) — M2 .well-known/neotoma.json resolver for cross-repo issue targeting.
  7. Peer-sync runbook (#1560) — cloud availability / Stop-hook peer documentation from salvage Wave 2.
  8. Site UI salvage (#396, #395) — remove MDX locale fallback banner; docs link in header nav + mobile FAB visibility fix.
  9. Inspector pinned dashboard panel — home page (/) shows a PinnedDashboardPanel grid when the API URL is configured; sidebar caps visible pins at 8 with a Show all (N) link back to home.

RC cycle fixes (post-rc.1)

The RC smoke-test loop produced two additional merges on top of the supplement scope above. Both are user-facing and worth calling out in the GitHub release notes.

Inspector pre-merge UI audit (#1674)

Operator-focused Inspector polish + design-system consistency pass landed before tagging:

  • Operator home, mobile shell, drawer — refreshed Inspector home for operators, mobile drawer + responsive polish across pages.
  • Design-system consistency — filters, selects, code blocks, recent feeds, and design surfaces migrated onto the canonical primitives. New reusable EmptyState, ApiNotConfiguredState, ListSurface, SegmentedControl, FiltersCard, MobileFilterPopover, ActiveFilterBadges, CopyableCodeBlock primitives wired across every index page.
  • Catch-all 404 route (inspector/src/pages/not_found.tsx) plus light/dark color audit (chart-1..5 tokens, success/warning utilities, dark-mode entity colors).
  • Backend /usage route + dashboard stats service (src/services/dashboard_stats.ts, src/services/timeline_query.ts) backing the dashboard with a real usage service.
  • Ops fixes/me path redaction, dev:full:prod token loading, chokidar-polling API watcher.

Windows spawn EINVAL regression fix (#1676 / #1677)

Field-reported regression: on Windows with modern Node.js (post CVE-2024-27980 patch — Node ≥ 18.20.2 / 20.12.2 / 21.7.2, all v22+), child_process.spawn('npm.cmd', ...) and other .cmd shims (npx.cmd, claude.cmd, tsx.cmd, neotoma.cmd) threw EINVAL unless shell: true was set. Most user-visible consequence: neotoma api start failed on Windows, so the local data API never came up and CLI writes were effectively blocked.

  • New helper src/shared/spawn_platform.ts (IS_WINDOWS, WIN_SHELL, shellOnWin()) centralizes the shell: true-on-win32 decision with explicit security reasoning (args stay an argv array — no command-string concatenation, no shell-injection vector).
  • Updated spawn sitessrc/cli/index.ts, src/cli/hooks.ts, src/cli/doctor.ts, src/services/schema_registry.ts, src/mcp_dev_shim.ts now use the helper. doctor.ts also maps whichwhere on Windows.
  • Testssrc/shared/spawn_platform.test.ts covers both platform branches and the spread-into-options shape.

Session identity inspector origin (#1591 / #1688)

Agents were defaulting Inspector links to sandbox.neotoma.io when no configured origin was available. GET /session and MCP get_session_identity now expose origins.inspector_origin and origins.app_origin from NEOTOMA_PUBLIC_BASE_URL when set, otherwise from the inbound request — never a hardcoded sandbox guess. MCP instructions require agents to use session-provided origins for turn-summary links.

  • Serversrc/services/session_info.ts builds normalized origin info; OpenAPI documents SessionOriginInfo.
  • Tests — unit coverage for empty/malformed origins; integration test confirms configured URL wins over request-derived host headers.

Known issues (won't ship a fix this release)

These were surfaced during the RC audit and are tracked for follow-up; they do not block v0.16.0 but are worth user awareness.

  • #1668store: two agent_message rows in one request can silently merge when message_id is omitted. A single /store request with both a user and assistant agent_message (or conversation_message) sharing one turn_key and no message_id collapses to one entity (matched_existing action) instead of two distinct rows. Server-side protection (ERR_CONVERSATION_MESSAGE_ROLE_CONFLICT) has been in place since v0.12.0 for the standard ordering and now has additional single-batch regression coverage; if the guard does not fire in your environment, ensure you are on the latest server. Workaround: use the :assistant suffix on the closing message (turn_key: "{conversation_id}:{turn_id}:assistant") — the canonical pattern the MCP turn lifecycle already documents.
  • #1598 / #1587 — auto-enhance queue / schema drift errors in server logs (AUTO_ENHANCE_QUEUE). Visible in production logs as APIError:store events on certain entity types (e.g. checkpoint_brief); does not corrupt stored data — observations are preserved, but the snapshot reducer may exclude undeclared fields. Use audit_undeclared_fragments (MCP) or neotoma schemas audit-fragments (CLI) to triage; promote high-occurrence fields via update_schema_incremental / register_schema per the per-store unknown_fields hint.
  • #1667 — public endpoints returning 401 / tight CORS posture. RC audit identified some endpoints that surface 401 where 200/anonymous would be more appropriate, and a tighter-than-needed CORS configuration for public read paths. Read paths intended for public consumption should continue to be inspected against the auth posture documented in docs/subsystems/auth.md before relying on them anonymously.

What changed for npm package users

@neotoma/agent protocol-enforcing harness SDK (#318)

Provider-agnostic agent harness that wraps @neotoma/client with the canonical Neotoma turn protocol so custom agent loops get correct memory behavior without hand-implementing MCP instruction rules.

  • New package packages/agent/ (@neotoma/agent): withMemory() wrapper, explicit NeotomaMemory (open_turn / close_turn), turn_helpers, turn_report, and diagnose utilities.
  • Turn lifecycle by construction — on each call: bounded retrieval from the user message, user-phase conversation + conversation_message store with PART_OF and REFERS_TO, agent invocation with ctx.retrieved, assistant-phase store with separate turn_key suffix and idempotency key.
  • Contract teststests/contract/sdk_client_store_shape.test.ts and tests/unit/agent_memory.test.ts / tests/integration/agent_memory_turn_lifecycle.test.ts lock store payload shapes against the live client.
  • Docsdocs/developer/sdk_agent.md and site page docs/site/pages/en/sdk-agent.mdx.
npm install @neotoma/agent @neotoma/client
import { HttpTransport } from "@neotoma/client";
import { withMemory } from "@neotoma/agent";

const wrapped = withMemory(yourAgentFn, {
  transport: new HttpTransport({ baseUrl, token }),
  conversationId: "conv-2026-05-20",
  platform: "my-agent",
});

Python NeotomaMemory protocol layer (#322)

Python parity for the same store-first turn protocol — HTTP-only client reaching the Node Neotoma engine over REST.

  • New modules in packages/client-python/: memory.py, with_memory.py, helpers.py with sync and async with_memory / NeotomaMemory.open_turn / close_turn.
  • Claude Code hookspackages/claude-code-plugin/hooks/neotoma_client/ gains the same memory layer for Python hook plugins.
  • Testspackages/client-python/tests/test_memory.py.
  • Docsdocs/developer/sdk_python.md and site page docs/site/pages/en/sdk-python.mdx.
pip install neotoma-client
from neotoma_client import NeotomaClient, with_memory

client = NeotomaClient(base_url="http://127.0.0.1:3080", token="dev-local")
wrapped = with_memory(my_agent, transport=client, conversation_id="conv-1")
result = wrapped("Tell me about Acme Corp")

Inspector skinning via NEOTOMA_INSPECTOR_SKIN (#1585)

Embedders and operators can theme the bundled Inspector SPA without forking the React app.

  • NEOTOMA_INSPECTOR_SKIN=<name> — load a bundled preset from dist/inspector/skins/<name>.json (source: inspector/public/skins/). Ships with a neutral sample preset for verification.
  • **`NEO...
Read more

v0.15.0

29 May 16:59

Choose a tag to compare

Install

npm install -g neotoma@0.15.0
npm https://www.npmjs.com/package/neotoma/v/0.15.0
Compare v0.14.0v0.15.0view diff

v0.15.0

Summary

This release seeds a first-class pull_request entity type, extends agent grants to cover GitHub-harness operations, hardens the issue-submission path for keyless and guest agents, and fixes a graph-query bug that silently dropped source records. It also restores the main CI baseline (broken inspector submodule pin) and ships the LaunchAgent deployment tooling for running Neotoma daemons under launchd.

What changed for npm package users

  • New pull_request entity type. The schema registry now seeds a pull_request type with declared fields (resolves #158), so agents can store and retrieve pull requests as first-class entities instead of untyped records.
  • retrieve_graph_neighborhood now returns source records correctly. The node_type: "source" branch and the entity-branch include_sources sub-path queried a singular source table that does not exist, so they silently returned no rows for every user. Both now query the canonical sources table (resolves #389, #394).
  • Faster full re-mirror. The canonical mirror no longer performs a dynamic import() once per entity inside the per-profile render loop; the renderer is imported once at module load (resolves #371).
  • New /end session-close audit skill that surfaces remaining work and verifies session data intended for Neotoma is actually stored before context is lost (#373).
  • MCP transport preset e added for the MCP server, with Node-version pinning in the LaunchAgent run scripts.

API surface & contracts

  • Additive only. npm run openapi:bc-diff against v0.14.0 reports no breaking changes.
  • pull_request is a new declared schema; no existing request or response shapes were narrowed.

Behavior changes

  • Agents that query retrieve_graph_neighborhood for a source node, or request include_sources on an entity node, now receive the source rows they previously did not.
  • submit_issue no longer hard-fails for agents without an AAuth keypair: it skips AAuth when no keypair is present and retries as an unsigned guest when AAuth returns AUTH_REQUIRED (resolves #944, #937). Issue submission also orders Neotoma-first.
  • Agent grants can now authorize github_harness operations and repo scopes via an extended AgentCapabilityOp (closes #934), enabling attributed GitHub actions through the harness.

Docs site & CI / tooling

  • CI baseline restored. main's baseline lane had failed since 2026-05-25 because the inspector submodule was pinned to a commit never pushed to the inspector remote. The pin is repointed to the last-good published commit (#1471).
  • Husky v10 readiness. Removed the deprecated v9 shebang lines from .husky/pre-commit that printed a deprecation warning on every commit and would fail under Husky v10 (resolves #400).
  • Instruction docs updated for mandatory extraction, GitHub entity types, and an awaiting-reply rule (#174, #175, #176).

Internal changes

  • LaunchAgent deployment tooling. Templatized LaunchAgent plists for the prod server, dev server, issues-sync, and watch-build daemons, with an install.sh, a README covering install/load/unload/logs/template vars, and .gitignore rules so only .tmpl sources are tracked.
  • NEOTOMA_LOCAL_PORT_DISK_PROFILE now overrides the write-side disk profile for the local HTTP port file.
  • The prod-server LaunchAgent bypasses pick-port.js (resolves ateles#10), and NEOTOMA_TRUST_PROD_LOOPBACK=1 is set in both LaunchAgent run scripts.
  • Machine-specific configs are gitignored; .cursor/ uses relative symlinks; MCP configs synced.
  • content_field heading-skip fix in renderEntityMarkdown (resolves #262).

Fixes

  • #389 / #394retrieve_graph_neighborhood queried a nonexistent singular source table; now uses sources.
  • #371 — dynamic import inside the per-entity mirror render loop, hoisted to module load.
  • #400 — deprecated Husky v9 shebang removed from .husky/pre-commit.
  • #262content_field heading-skip in renderEntityMarkdown.
  • #944 / #937submit_issue keyless/guest handling.
  • ateles#10 — prod-server LaunchAgent port-pick bypass.

Tests and validation

  • New HTTP-level integration regression (tests/integration/graph_neighborhood_source_branch.test.ts) boots the Express app and asserts the source branch returns rows; verified to fail against the singular table and pass after the fix.
  • Mirror and markdown suites pass (54 tests) after the import hoist.
  • New pull_request schema covered by tests/unit/pull_request_schema.test.ts.
  • Automated test catalog regenerated (400 files).
  • npm run type-check, lint (0 errors), Prettier, and site-copy lint all clean.

Security hardening

The diff classifier flagged this release as sensitive because src/actions.ts is in the diff (the v0.11.1 auth-bypass surface heuristic). The actual change is two db.from("source")db.from("sources") substitutions; adversarial review of all six prompt axes (alternate-path auth, proxy trust, local-dev widening, unauth public route, guest-access policy, AAuth downgrade) found no security regression. See docs/releases/in_progress/v0.15.0/security_review.md for the full walkthrough and sign-off verdict (with-caveats). No advisories opened or referenced by this release.

Breaking changes

No breaking changes.


Commits (v0.14.0v0.15.0)

  • 60cbe8b Bump version to v0.15.0
  • b0e9c21 Merge pull request #1474 from markmhendrickson/release/v0.15.0
  • 0347e22 chore(release): prettier-format regenerated openapi_types.ts
  • f8befc1 chore(release): v0.15.0 release artifacts + openapi AgentCapabilityEntry fix
  • e9ee621 fix: graph source-table bug (#389/#394) + mirror import perf (#371) + Husky v9 deprecation (#400) (#1469)
  • 902d1cc fix(inspector): repoint submodule to last-good published pin 206e14e (#1471)
  • 03df670 chore(merge): resolve conflicts from #936 fix merge
  • dd001b1 fix(issues): Neotoma-first ordering + skip AAuth when no keypair (resolves #944)
  • 0a98c7d fix(issues): retry submit_issue as unsigned guest when AAuth returns AUTH_REQUIRED (#937)
  • 85e932b Merge branch 'main' of https://github.com/markmhendrickson/neotoma
  • 7818ec0 feat(mcp): add transport preset e + LaunchAgent node-version pinning
  • 172f8e4 Add NEOTOMA_TRUST_PROD_LOOPBACK=1 to both LaunchAgent run scripts
  • d6ee8c8 chore(inspector): bump submodule to logo path fix
  • 3cd06f4 chore(inspector): bump submodule to basename fix
  • 43e7116 fix(local-port-file): NEOTOMA_LOCAL_PORT_DISK_PROFILE overrides write-side disk profile
  • 2dab6c3 chore(config): gitignore machine-specific configs; relative symlinks in .cursor/; sync MCP configs
  • 8907b62 feat(agent-grants): extend AgentCapabilityOp for github_harness ops (closes #934)
  • 302a51b fix(launchd): bypass pick-port.js in prod server launchagent (resolves ateles#10)
  • 353328a feat(schema): seed pull_request entity type (resolves #158) (#929)
  • c06142b docs(instructions): mandatory extraction, GitHub entity types, awaiting-reply rule (#174 #175 #176) (#931)
  • 8582ba0 fix(mirror): content_field heading-skip in renderEntityMarkdown (resolves #262) (#930)
  • e5c42d6 chore(deploy): gitignore rendered plists — only track .tmpl sources
  • b8c5864 docs(deploy): add README for launchagents — install, load/unload, logs, template vars
  • da268d0 chore(deploy): templatize launchagent plists; add install.sh
  • 25be539 chore(deploy): add launchagent plists for prod-server, dev-server, issues-sync, watch-build
  • 38e8b00 feat(skills): add /end session-close audit skill (#373)
  • 94a6b25 fix(release): correct nested path for v0.14.0 probe report
  • 48adc81 chore(release): move v0.14.0 release artifacts to completed
  • 0537296 Merge branch 'main' of github.com:markmhendrickson/neotoma
  • d07c060 fix(release-skill): tighten Step 5.2 GHSA publication to check live API state
  • b3b197a Merge pull request #391 from markmhendrickson/fix/release-skill-review-gate
  • 0392013 chore(release): archive v0.14.0 supplement and security review to completed/
  • 055576a fix(release-skill): add @claude review gate on release candidate PR (Step 3.7.2b)

Full compare: v0.14.0...v0.15.0

v0.14.0

22 May 05:21
3d60590

Choose a tag to compare

v0.14.0 ships substantial improvements across search, ingestion, agent ergonomics, and security. Headlines: smarter entity search that ranks by entity-type intent and hides chat bookkeeping; persistent issue-filing consent; paginated graph neighborhood traversal; structured cold-start error responses on update_schema_incremental; per-user data scoping on relationship query endpoints (GHSA-wrr4-782v-jhwh); a /review skill wired into the automated PR review workflow; the preference entity schema is now registered; and neotoma schemas repair-plural-types is fixed for global / npx installs.

Highlights

  • Smarter entity search. When a query token names an entity type (e.g. "plans", "tasks", "transactions"), retrieve_entities now boosts that type's results by 280 points and filters by type instead of matching the token against snapshot text — so "newest plans" actually surfaces plans, not chat messages mentioning the word "plans". Singular/plural normalization included.
  • Chat bookkeeping no longer pollutes product search. The Inspector header search and /search automatically exclude conversation, conversation_message, and related bookkeeping entity types unless the caller explicitly filters by one of those types. Pass exclude_bookkeeping: true on retrieve_entities to apply the same filter from any caller.
  • Issue-filing preference persists across sessions. On first encounter, agents ask once and store your choice (always / ask / never) as a preference entity so future sessions skip the prompt. neotoma issues config --mode still sets the runtime flag; the preference entity is the cross-session layer that feeds it.
  • Paginate large graph neighborhood results. retrieve_graph_neighborhood and POST /retrieve_graph_neighborhood now accept limit (default 100, max 500) and offset parameters and return total_count and has_more, so callers can page through densely-connected nodes without truncation.
  • Tenant isolation fix on relationship query endpoints. GHSA-wrr4-782v-jhwh/list_relationships and /retrieve_graph_neighborhood previously authenticated callers but did not scope database queries to the requesting user. An authenticated user with a known cross-user entity ID could read another user's relationship metadata. Severity Low under current single-tenant deployments; escalates to Medium for multi-tenant. Fixed with explicit .eq("user_id", userId) on every query and a new tenant_isolation_matrix.test.ts gate.
  • /review skill wired into automated PR review. The PR review workflow now invokes a versioned /review skill that walks the full architectural + product-principles + agent-instruction coherence checklist instead of a hand-rolled prompt. The same skill runs as a hard gate inside /release Step 3.6.
  • preference entity schema registered. The schema is now seeded at boot so preference entities (used by the issue-filing consent flow, future agent settings) have proper canonical-name derivation, last-write merge policy, and field declarations.
  • neotoma schemas repair-plural-types works from a global or npx install. A dynamic import in the compiled CLI used the wrong relative path (../../services/ instead of ../services/), which silently failed after installation. Fixed, with new dist-level smoke tests covering this class of bug going forward.

What changed for npm package users

CLI (neotoma)

  • neotoma schemas repair-plural-types — fixed: the dist-level dynamic import path for plural_type_repair was one directory level off (../../services/plural_type_repair.js instead of ../services/plural_type_repair.js). The bug was invisible to TypeScript compilation and source-level tests because both resolve from src/; only a subprocess spawned against the compiled dist/ catches it. New smoke tests at tests/contract/cli_handler_dist_smoke.test.ts cover this class of regression for schemas repair-plural-types, schemas audit, schemas list, and status.

Runtime / data layer

  • Entity search ranking and bookkeeping exclusion (retrieve_entities, POST /retrieve_entities) — substantial rework of src/shared/action_handlers/entity_handlers.ts (~430 lines):
    • New ENTITY_TYPE_KEYWORD_BOOST = 280. When a search token equals an entity_type's name (canonical or singular-normalized via suggestSingular), matching entities of that type get ranked 280 points higher in the result list.
    • New exclude_bookkeeping parameter on retrieve_entities (boolean, default false on direct API calls; default true for Inspector header and /search). When set, conversation, conversation_message, and related BOOKKEEPING_ENTITY_TYPES are omitted from results.
    • New buildEntityTypeFilterTokens(searchTokens, knownEntityTypes) and textTokensForEntityMatch(searchTokens, typeFilterTokens) helpers: when the query names a known entity_type, that token is removed from snapshot-text matching and becomes a type filter instead. The remaining tokens still match snapshot content.
    • New buildEntityLexicalSearchText(canonicalName, snapshot, rawFragmentText) builds the canonical lexical haystack (canonical name + snapshot + raw fragments) used for ranking.
    • lexicalSearchEntityIds now resolves active entity types from schema_registry to drive the type-filter logic; falls back to a warning log if the schema registry query fails.
    • Net effect: a query like "newest plans" now narrows the candidate query to entity_type='plan' and boosts ranking accordingly, rather than fuzzy-matching the literal string "plans" against every entity's snapshot.
  • retrieve_graph_neighborhood pagination — accepts limit (1–500, default 100) and offset (default 0) query parameters. Response now includes total_count (total relationships for the node before pagination) and has_more. Use these to page through high-degree nodes.
  • list_relationships filter expansion + OpenAPI declarationsrc/actions.ts: the handler now supports source_entity_id and target_entity_id as direct filter params in addition to the legacy entity_id + direction pattern. Pagination (limit, offset) added. The request schema requires at least one of entity_id, source_entity_id, target_entity_id, or relationship_type. Optional user_id filter added. openapi.yaml now declares the full request and response shape including the closed relationship_type enum (matching RelationshipTypeSchema) and an anyOf "at least one identifying field" constraint. Non-breaking addition.
  • Per-user data scoping on /list_relationships and /retrieve_graph_neighborhood (GHSA-wrr4-782v-jhwh) — both endpoints now resolve getAuthenticatedUserId and apply .eq("user_id", userId) to every relationship, entity, observation, and source lookup. Closes #365 and the tenant-isolation portion of #366. Test gate added: tests/security/tenant_isolation_matrix.test.ts.
  • update_schema_incremental cold-start handling — when called for an entity_type with no registered or code-defined schema, previously threw an opaque McpError(-32603); now returns a structured non-throwing response with error_code: ERR_NO_SCHEMA_FOR_ENTITY_TYPE, no_schema_for_entity_type: true, and a stable hint ("Pick register_schema for the new entity_type. The MCP tool is register_schema; the HTTP route is POST /register_schema...") that no longer interpolates per-type strings. When the entity_type has an existing schema that lacks both canonical_name_fields and identity_opt_out, the R2 error is now surfaced as ERR_SCHEMA_MISSING_IDENTITY_CONFIG with a hint to call register_schema with a complete schema definition.
  • preference entity schema — registered at boot under src/services/schema_definitions.ts. Fields: title (canonical name source), value (last-write merge policy), scope, description. Backs the cross-session issue-filing consent flow and is available for any future agent-settings entity. Closes #339.
  • Profile mirror render correctness (rebuildProfile / mirrorEntity)mirrorEntity now dispatches to renderProfileEntity when render_mode is frontmatter_content or content_only, matching rebuildProfile behavior. Previously the live-write path always called renderEntityMarkdown, ignoring render_mode, frontmatter_fields, and content_field. When content_field was "body", this produced a spurious ## body heading in the output. Fixed via dynamic import of renderProfileEntity from canonical_markdown.js. Closes #262.
  • Graceful entity_types fallback in search (src/shared/action_handlers/entity_handlers.ts) — when schema_registry queries fail (cold start, transient DB error), resolveEntityTypesForTypeFilters now logs a warning and returns an empty set rather than throwing. Search falls back to the un-typed match path instead of failing the whole request. Closes #342.

Shipped artifacts

  • openapi.yaml — substantial additions:
    • POST /retrieve_graph_neighborhood gains limit, offset, user_id request fields and total_count, has_more, node_id, node_type, entity, relationships, related_entities, observations, sources response fields.
    • POST /list_relationships gains a fully-declared request body (entity_id, source_entity_id, target_entity_id, direction, relationship_type closed enum, limit, offset, user_id) with anyOf "at least one identifying field" constraint, plus full response shape (relationships, total, limit, offset).
  • .dockerignore — substantially trimmed: build context reduced from ~15 GB to ~50 MB by excluding non-source dirs (backups, data_backups, tmp, site_pages, writ, packages, mcp, public, frontend, .claude,...
Read more

v0.13.0

19 May 11:02
534f91c

Choose a tag to compare

v0.13.0 Release Supplement

Summary

v0.13.0 is a substantial feature release covering everything since v0.12.1. Headline additions:

  • Schema-level and per-entity agent instructions — entity types and individual entities can carry behavioral guidance that agents must apply when the entity is retrieved.
  • Multi-harness preflight CLI — replaces the multi-prompt onboarding flow.
  • Bulk harness-transcript import from ~/.claude/, ~/.codex/, and ~/.cursor/.
  • MCP integration guides for Continue, Windsurf, VS Code, and Letta.
  • Bidirectional column-encryption migration command for self-hosted deployments.
  • Plan-entity refactor — replaces feature units with first-class plan entities and a neotoma-plans mirror profile.
  • Server-rendered /docs index over repo docs, with fail-closed visibility.
  • Prettier baseline + CI format gate.
  • Selective Claude PR review on substantial PRs.
  • Corrective fixes to schema discovery, idempotency, intra-batch relationships, raw_fragments routing, and timeline determinism.

GitHub Releases now stage as draft and publish only after the sandbox deployment is verified. The release flow opens an RC branch + PR for public review before execute.

What changed for npm package users

New CLI commands

  • neotoma preflight [--tool <harness>] [--apply] [--scope project|user|both] [--dry-run] — prints a copy-paste allowlist block for the specified harness or writes it directly with --apply. Allowlist writes are supported for claude-code, cursor, and codex; for MCP-only harnesses (claude-desktop, openclaw, windsurf, continue, vscode) the command prints a redirect to neotoma setup. For claude-code, --scope selects project (.claude/settings.local.json), user (~/.claude/settings.json), or both. Replaces the multi-prompt manual setup that previously plagued the onboarding flow.
  • neotoma db migrate-encryption <encrypt|decrypt> — bidirectional bulk column encryption migration that operates directly on the SQLite file (no running server). Migrates observations.fields, entity_snapshots.snapshot/provenance, relationship_snapshots.snapshot/provenance, raw_fragments.fragment_value/fragment_envelope, and schema_recommendations.fields_*/converters_to_add. Uses the same key configuration as the runtime (NEOTOMA_KEY_FILE_PATH or NEOTOMA_MNEMONIC + optional NEOTOMA_MNEMONIC_PASSPHRASE). Covered by tests/cli/db_migrate_encryption.test.ts (encrypt→decrypt identity, idempotency, dry-run non-mutation, NULL preservation, missing-table skip, wrong-key per-row failure, INTEGER PRIMARY KEY rowid-aliasing fix).
  • neotoma db repair-schema-lag [--dry-run] [--types <entity_types>] [--rollback <run_id>] — audit and repair raw_fragments rows that were misrouted due to the schema-projection-lag bug (#142). Rows whose fragment_key now matches a declared field in the active schema are promoted to observations and snapshots recomputed. Every inserted observation carries a _migration_run_id field for rollback. Covered by tests/cli/db_repair_schema_lag.test.ts.
  • neotoma db migrate-env-split — repairs npm-installed deployments that had previously written user data to a dev database. Subsequent installs now default to a production DB; this command moves existing data into the production location (#172, #244).
  • neotoma schemas repair-plural-types — coalesces accidentally-plural entity types (e.g. postspost) back to the canonical singular form, declaring the plural as an alias on the canonical schema (#162).
  • neotoma onboarding import-transcripts and neotoma init --import-transcripts — bulk-import all detectable harness transcripts in one step during onboarding (#143).
  • neotoma reporter setup — guided setup for the issue reporter flow (auth, scope, default labels), supersedes the multi-step manual procedure (#199).

New CLI flags on existing commands

  • neotoma discover --harness-transcripts — also detects Claude Code (~/.claude/projects/*/conv-*.jsonl), Codex (~/.codex/archived_sessions/*.jsonl), and Cursor (~/.cursor/chats/**/store.db, plus state.vscdb) transcript locations. Prints a structured summary with file counts, sample titles, date ranges, and SQLite requirement flags.
  • neotoma ingest-transcript [path] --harness <claude-code|codex|cursor>path is now optional. When --harness is given and path is omitted, bulk-imports all transcripts from the corresponding well-known location.
  • neotoma cursor-hooks --global — installs cursor hooks into ~/.cursor/hooks.json instead of the project-local .cursor/hooks.json (#144).
  • neotoma store --turn-key <key> — stable per-turn idempotency key surface for replay-safe stores; used internally by the test suite and supported for external callers.
  • neotoma sync-issues --push — new push leg that mirrors local public Neotoma issues to GitHub with PII redaction applied at the boundary.

Behavior changes in existing commands

  • neotoma store / retrieve_entities — entity responses now include two new nullable string fields:
    • schema_instructions — markdown sourced from SchemaDefinition.agent_instructions for the entity's registered schema.
    • entity_instructions — markdown sourced from the entity's own snapshot agent_instructions field.
      Agents MUST treat these as behavioral context for the entity type and apply them to the current turn.
  • neotoma store — unknown-field surfacing improved: the response now includes a concrete list of unknown field names (not just a count) when fields are dropped to raw_fragments, and emits a structured recovery hint pointing the caller at the right corrective action (#185, #187). A pre-resolution pass prevents partial batch writes — if any entity in a batch fails to resolve, none are written (#203). Intra-batch relationships are honored: a relationship targeting another entity created in the same store call now resolves correctly (#203, #221).
  • neotoma store — schema/type discovery is required before the store completes; callers receive a clear error when targeting an unregistered entity type instead of silently routing all fields to raw_fragments (#196, #208). When the target type has no registered schema, the response surfaces the no-schema state explicitly so callers can register a schema and retry (#164).
  • neotoma store — idempotency key reuse with a different payload is now detected via content-hash comparison and returns ERR_IDEMPOTENCY_MISMATCH instead of silently overwriting (#186).
  • neotoma store aliases — the MCP dispatcher now recognises store_structured and store_unstructured aliases for the unified store tool.
  • neotoma store ranking — store-tool ranking improved so agents surface the right entry point when multiple variants match (#181, #182, #183, #191, #206).
  • neotoma retrieve / list_timeline_eventslist_timeline_events returns an empty result for an unknown event_type instead of erroring (#207).
  • neotoma sources access mutation commands now fail fast when --base-url or --api-only are present (these commands are local-only).
  • neotoma issue add-message treats partial success (GitHub write succeeded, remote Neotoma append failed) as success, returning a non-null remote_submission_error so callers can react without an end-to-end failure (#43, #90).
  • neotoma cli access reset-issue-policy correctly writes the default policy to disk (#40, #89).
  • neotoma doctor — reports the source of the resolved data_dir so users can tell when the path came from an env var, default, or explicit flag (#170).
  • neotoma upload--local correctly uses the local data dir for source persistence (#168).
  • neotoma submit-issue / add-issue-messagereporter_app_version is auto-populated when not supplied; AUTH_REQUIRED errors now surface a structured hint directing the caller at the right next step (#181, #182).
  • neotoma plans — new top-level surface backed by plan entities (see Plan refactor below).

New seeded entity types

  • plan — first-class entity for engineering and design plans, replacing the previous filesystem-only feature units. Plans are mirrored back to plans/ (was docs/plans/) via the new neotoma-plans mirror profile.
  • gist — GitHub Gists and similar code/text snippets shared via URL. Identity uses gist URL; preserves description casing; last-write merge for description (#72, #75, #77, #84).
  • neotoma_repair — records a repair or remediation action taken within Neotoma. Identity is composed of action + timestamp + actor.
  • external_link — generic external URL entity with gist-style metadata fields (title, description, source).
  • conversation — promoted from inferred to bootstrap-registered schema; session_uuid field added as a bridge to coalesce slug-style conversation IDs with harness-issued UUIDs (#138, #145, #256).
  • workout_session — new schema with an exercises field using merge_array semantics (#209).
  • product_feedback — adds a feedback_source discriminator and tightened identity validation (#136, #137).

Plan refactor

Plans are now first-class Neotoma entities, not filesystem documents. Highlights:

  • Plans live as plan entities with structured fields, retrieval routing, and graph edges to objectives, gates, and feedback.
  • The new neotoma-plans mirror profile snapshots plan entities into the repo with canonical-name filenames and YAML frontmatter for harness compatibility.
  • Plan content moved out of .cursor/plans/ and docs/plans/ flat files into Neotoma; the mirror writes them back to plans/ for harness visibility (b1d163696).
  • Selective mirror profiles support snapshot field tokens, slug truncation, and a remote API client for profile-based hydration (8d39d1000, 7a441614f).
  • Plan-entity re...
Read more

v0.12.1

12 May 15:06
3860745

Choose a tag to compare

Install

npm install -g neotoma@0.12.1
npm https://www.npmjs.com/package/neotoma/v/0.12.1
Compare v0.12.0v0.12.1view diff

v0.12.1 hardens the v0.12.0 surface area without changing its shape. It closes a guest-token validation gap on the auth path, restores Codex / OpenAI function-tool compatibility for the issue MCP tools (server-side enforcement is unchanged), tightens the prepublish Inspector build, and ships the operator-facing v0.12 documentation that the v0.12.0 tag advertised but did not yet include — a Doctor CLI reference, the operator hardening knobs, the LaunchAgent zombie-cleanup flag, the documented bulk_close_issues / bulk_remove_issues tools, and dedicated site pages for peer sync, substrate subscriptions, issue reporting, and security hardening.

Highlights

  • Guest auth: invalid bearer tokens no longer downgrade to anonymous. maybeStampGuestPrincipal is now async and explicitly validates an Authorization: Bearer … guest access token against validateGuestAccessToken before stamping the request principal. Guest-scoped entity reads also re-assert the token via a new assertValidGuestAccessToken helper. The error envelope on a missing or invalid guest principal now reads Not authenticated - guest principal cannot resolve a user_id … so operators can grep for it. Behavior under a valid token is unchanged. Regression coverage: tests/integration/guest_invalid_bearer_routes.test.ts asserts 401 for /issues/submit, /issues/add_message, /issues/status, /subscribe, /unsubscribe, /list_subscriptions, /get_subscription_status, /events/stream, and /entities/duplicates when the bearer is not a valid guest token.
  • Codex / OpenAI function-tool compatibility for the issue MCP tools. submit_issue, add_issue_message, and get_issue_status no longer carry a top-level anyOf in their JSON Schema, because OpenAI's function-tool registry rejects schemas with a top-level combinator. Server-side enforcement is unchanged: submit_issue still returns 400 ERR_REPORTER_ENVIRONMENT_REQUIRED when neither reporter_git_sha nor reporter_app_version is supplied (declared in details.acceptable_field_groups), and add_issue_message / get_issue_status still require entity_id or issue_number. Tool descriptions in docs/developer/mcp/tool_descriptions.yaml now describe the constraints in prose so MCP clients see the same contract without the schema combinator.
  • Operator hardening knobs are now documented in the security tree. SECURITY.md and docs/security/threat_model.md add the Operator hardening knobs (v0.12+) section: NEOTOMA_GUEST_WRITE_RATE_LIMIT_PER_MIN (default 30/min, key precedence AAuth thumbprint > hashed guest token > IP), NEOTOMA_GUEST_TOKEN_TTL_SECONDS (default 2592000, with revoked_at-aware revocation), NEOTOMA_HOSTED_MODE=1 (rejects private/loopback/link-local sender_peer_url on inbound peer-sync), and MCP_PROXY_FAIL_CLOSED=1 (refuses unsigned downstream requests on AAuth proxies). All four were already shipping behaviors in v0.12.0; this release is what makes them findable from the security landing page.
  • neotoma doctor --json is now spec-documented. docs/developer/cli_reference.md adds a Doctor section that describes the --json shape, every data.risks[].code (icloud_drive, macos_synced_desktop_or_documents, prior_sqlite_repair_artifacts), suggested_safe_data_dir, the migration command (neotoma storage set-data-dir <path> --move-db-files), and the --tool override consumed by neotoma setup --output json.
  • reload_neotoma_launchagents.sh --kill-zombies is documented end to end. docs/developer/launchd_dev_servers.md and docs/developer/scripts_reference.md describe the four orphan patterns the flag SIGTERMs (legacy node dist/index.js adopted by launchd, with_branch_ports.js → tsx → src/actions.ts chains, tsx watch … src/actions.ts watchers from integration tests, and npm exec tsx … src/actions.ts debug runs) and call out that the steady-state orphan rate after the v0.12.0 process-group fix is near zero — --kill-zombies is the recovery path for pre-v0.12.0 leftovers and force-killed test parents.
  • bulk_close_issues / bulk_remove_issues are now declared in the spec table. docs/specs/MCP_SPEC.md adds rows for both tools with their HTTP twins (POST /issues/bulk_close, POST /issues/bulk_remove); docs/subsystems/issues.md documents their MCP signatures and notes that bulk_remove_issues is a soft delete via deleteEntity observations and restoration goes through restore_entity. The tools shipped in v0.12.0; the spec table omitted them.
  • store write-classification, peer attribution, and external-actor fields are spelled out in the spec. docs/specs/MCP_SPEC.md documents the v0.12+ observation_source (sensor / workflow_state / llm_summary / human / import / sync), source_peer_id, and external_actor fields on the store request, including the reducer tie-break behavior (source_priority first, then observation_source) and the AAuth-vs-external_actor distinction (signing agent vs the human/account on whose behalf the agent wrote).
  • Inspector packaging fails closed. scripts/build_inspector.js now exits non-zero when the inspector/ submodule is missing during prepublishOnly / pack:local, instead of silently skipping. This prevents shipping an npm tarball without the bundled Inspector. tests/contract/package_scripts.test.ts pins the Inspector Vite entrypoints (dev:vite, build:vite, build:watch, preview) to --config vite.config.ts so the build cannot regress to a stale vite.config.js.
  • Four new operator-facing site pages cover the v0.12 subsystems. /peer-sync, /subscriptions, /issue-reporting, and /security-hardening are wired into the docs nav, the SEO metadata, the route table, and the doc manifest. Each page links back to its repo source of truth (docs/subsystems/peer_sync.md, docs/subsystems/subscriptions.md, docs/subsystems/issues.md, SECURITY.md + docs/security/threat_model.md). The changelog page surfaces a v0.12.0 highlight banner pointing at these pages and the breaking submit_issue reporter-provenance contract.
  • Release skill now hard-gates security review. .cursor/skills/release/SKILL.md and .claude/skills/release/SKILL.md add a hard gate before Step 4 that requires explicit G1 / G2 / G3 / G4 evidence and a populated security_review.md with the supplement linked under a Security hardening section. The skill also requires re-running Step 3.5 when any commit is added after the security review ran. This is the workflow change that produced this v0.12.1 release plan.

What changed for npm package users

MCP tools

  • submit_issue, add_issue_message, get_issue_status JSON Schemas no longer carry a top-level anyOf. The server still returns 400 ERR_REPORTER_ENVIRONMENT_REQUIRED on submit_issue when neither reporter_git_sha nor reporter_app_version is supplied, and still requires entity_id or issue_number on the other two. Codex and other strict OpenAI function-tool consumers can now register the schemas without rejection. Existing MCP clients that already pass a valid payload see no behavior change.
  • Updated tool descriptions surface the reporter-environment requirement and the entity_id-or-issue_number requirement in prose.

HTTP API

  • No new operations. No openapi:bc-diff breaking changes vs v0.12.0.
  • tests/integration/guest_invalid_bearer_routes.test.ts codifies that the following routes return 401 (not anonymous downgrade) when called with Authorization: Bearer <invalid-guest-token>: GET /entities/duplicates, GET /events/stream, POST /get_subscription_status, POST /issues/add_message, POST /issues/status, POST /issues/submit, POST /list_subscriptions, POST /subscribe, POST /unsubscribe.

CLI

  • neotoma api start --help now surfaces the --env dev / --env prod requirement explicitly. tests/cli/cli_infra_commands.test.ts pins the help output to mention --env dev or --env prod and the neotoma api start --env prod invocation.

API surface & contracts

  • OpenAPI: unchanged vs v0.12.0. npm run openapi:bc-diff reports no breaking changes.
  • MCP tool schemas: submit_issue, add_issue_message, get_issue_status drop the top-level anyOf for OpenAI / Codex compatibility (server-side enforcement preserved). tests/contract/openclaw_plugin.test.ts codifies the absence of top-level anyOf and the presence of properties.reporter_git_sha / properties.reporter_app_version on submit_issue.
  • Schema seeding: unchanged.
  • store request schema documentation: the optional v0.12+ fields observation_source, source_peer_id, and external_actor are now described in docs/specs/MCP_SPEC.md together with their reducer semantics.

Behavior changes

  • Guest auth path treats invalid bearer tokens as 401, not as anonymous downgrade. Routes that accept guests now require the guest principal to validate against the persisted token grant before being stamped on the request. This closes a gap where a syntactically valid but unrecognized bearer could bypass the validation step on guest-capable surfaces.
  • prepublishOnly / pack:local fail closed when the Inspector submodule is missing. Operators who package or publish must run git submodule update --init inspector first; the previous "skip and continue" behavior is gone.

Agent-facing instruction changes

  • .cursor/skills/release/SKILL.md and .claude/skills/release/SKILL.md add the Hard gate before Step 4 with the G1–G5 evidence checklist and the explicit "rerun Step 3.5 if any commit is added after the security review" rule.
  • docs/specs/MCP_SPEC.md documents the `bu...
Read more

v0.12.0

12 May 12:19
7e606e5

Choose a tag to compare

Install

npm install -g neotoma@0.12.0
npm https://www.npmjs.com/package/neotoma/v/0.12.0
Compare v0.11.1v0.12.0view diff

v0.12.0 turns Neotoma into a multi-instance State Layer. Substrate subscriptions, peer-to-peer sync, and a first-class issues subsystem replace the legacy feedback path; the auth hardening introduced in v0.11.1 is carried forward here and extended with pre-release gates G1–G5, stricter proxy/loopback handling, and clearer operator guidance; and the dev/prod LaunchAgents, MCP stdio shims, and CLI surfaces are reworked to stop orphaning processes, stop drifting off canonical ports, and give operators a real processes servers view, plans capture/list, and a doctor that flags risky data directories.

Highlights

  • Cross-instance peer sync becomes a first-class subsystem. add_peer / list_peers / get_peer_status / remove_peer / sync_peer ship with POST /sync/webhook inbound delivery (HMAC-signed X-Neotoma-Sync-Signature-256), AAuth-thumbprint loop prevention, and resolve_sync_conflict for prefer-local vs prefer-remote reconciliation. get_peer_status now includes remote_health (/health probe + neotoma compat semver check) so operators can see immediately when a peer is offline or runs an incompatible version. applyInboundSyncWebhook rejects mismatched sender_peer_url values and blocks private/loopback hostnames when NEOTOMA_HOSTED_MODE=1. See docs/subsystems/peer_sync.md.
  • Substrate subscriptions with webhook + SSE transport. subscribe / unsubscribe / list_subscriptions / get_subscription_status plus GET /events/stream (SSE) let agents and external services watch entity / event / relationship changes for specific entity_types, entity_ids, or event_types. Webhook deliveries are HMAC-signed; SSE uses the same auth as the API. Loop-prevention sync_peer_id is wired through both transports.
  • Issues replace the feedback subsystem end-to-end. submit_issue, add_issue_message, get_issue_status, sync_issues, bulk_close_issues, bulk_remove_issues are the canonical reporting flow, with GitHub mirror + operator forwarding + guest read-back tokens. Public submit + public-thread message paths run through the existing scanAndRedact PII guard as a backstop, ISO-date literals no longer false-positive as phone numbers, and loadIssueThreadMessages deduplicates across remote + local + multi-conversation threads. New CI workflows auto-label issues from issue_kind and post upgrade-guidance comments on releases.
  • Reporter environment is required on submit_issue, soft-required on add_issue_message. The MCP submit_issue JSON Schema gains anyOf: [{ required: [reporter_git_sha] }, { required: [reporter_app_version] }], so MCP clients fail validation locally before sending; the HTTP POST /issues/submit route returns 400 ERR_REPORTER_ENVIRONMENT_REQUIRED with details.acceptable_field_groups. On public add_issue_message threads, the server emits a stderr warning but still persists the message.
  • Security follow-through after v0.11.1. This branch carries forward the auth-bypass hardening from the v0.11.1 hotfix line and adds the work that makes it operationally durable: isLocalRequest keeps the stricter forwarded-hop handling, production loopback remains non-local by default (set NEOTOMA_TRUST_PROD_LOOPBACK=1 to opt back in), a new CI security_gates job runs G1 (security:classify-diff), G2 (security:lint), G3 (security:manifest:check + test:security:auth-matrix) on every PR, the sandbox weekly reset workflow now runs G5 deployed probes against https://sandbox.neotoma.io, SECURITY.md is rewritten with the disclosure flow and advisories index, and docs/developer/mcp/proxy.md documents the operator-required MCP_PROXY_FAIL_CLOSED=1 for AAuth-signed hosted deployments.
  • Operator security middleware. A dedicated guest write-rate limiter keys by AAuth thumbprint → hashed guest token → IP (NEOTOMA_GUEST_WRITE_RATE_LIMIT_PER_MIN, default 30/min). /mcp now validates OAuth Bearer tokens and responds with a proper 401 invalid_token envelope and WWW-Authenticate resource-metadata header when the token is unknown or expired. Guest access tokens carry an explicit TTL (NEOTOMA_GUEST_TOKEN_TTL_SECONDS, default 30 days) and a revoked_at field, and persistence errors are no longer swallowed silently.
  • LaunchAgent and MCP shim reliability. The dev-server chokidar watcher now spawns the API as a process-group leader and SIGTERMs the whole group on reload, eliminating the orphan-process explosion that accumulated 50+ stale dev API instances on ports 3145–3179. Both LaunchAgents pre-kill incumbents on 3080 / 3180 so dev and prod always bind their canonical ports. scripts/reload_neotoma_launchagents.sh --kill-zombies recognizes the actual orphan patterns observed in the wild. All MCP stdio shim wrappers (signed / unsigned, dev / prod, Cursor / Claude Code / Codex) source the new shared helpers (scripts/lib/neotoma_mcp_source_env.sh, scripts/lib/neotoma_mcp_resolve_downstream_url.sh), the resolver treats an explicit NEOTOMA_MCP_LOCAL_HTTP_PORT_PROFILE=dev|prod as sufficient to enable port-file mode (Cursor strips "1" flag values), and the downstream resolver warns on (but never honors) cross-profile MCP_PROXY_DOWNSTREAM_URL leakage.
  • CLI: new processes servers, plans capture/list, access list/set/reset, doctor risk detection. neotoma processes servers collapses parent-child process trees into one row per listener, surfaces LAUNCHAGENT / DATA_DIR / LOGS, and supports --watch. neotoma plans capture <file> / --all ingests harness .plan.md files (.cursor/plans, .claude/plans, .codex/plans, .openclaw/plans) via the canonical combined store path. neotoma access list shows the winning policy source (env / schema_metadata / config_file / default); access set / reset / enable-issues / disable-issues write through SchemaMetadata.guest_access_policy as the canonical source (the legacy config file is now a deprecated fallback only). neotoma doctor --json adds data.risks for iCloud-synced / Documents / Desktop data directories and prior SQLite repair artifacts, plus a suggested_safe_data_dir.
  • OpenClaw plugin entry point. A new src/openclaw_entry.ts registers Neotoma MCP tools as OpenClaw agent tools, declares kind: "memory" so users can wire it via plugins.slots.memory = "neotoma", and persists session lifecycle events (session.start, session.end, afterToolCall) into Neotoma using the same store-first contract as MCP.
  • Site, Inspector, agent-instruction expansion. ~80 new MDX pages under docs/site/pages/en/ cover personas (CRM, customer-ops, financial-ops, government, healthcare, logistics, compliance, diligence, crypto-engineering), comparisons (vs database, vs files, vs mem0, vs platform memory, vs RAG, vs Zep), integrations (Claude / Claude Code / Codex / Cursor / ChatGPT remote MCP), and risk/guarantee primitives (auditable change log, deterministic state evolution, human inspectability, conflicting-facts risk, false-closure risk, memory guarantees, non-destructive testing). The Inspector submodule advances to its peers + access-policy UI commit. Agent-facing instructions (docs/developer/mcp/instructions.md, docs/specs/MCP_SPEC.md, docs/developer/cli_reference.md) gain Inspector-linked display headings, an ISSUE REPORTING section keyed off issues.reporting_mode (proactive / consent / off), and explicit reporter-env requirements.

What changed for npm package users

MCP tools

  • New: subscribe, unsubscribe, list_subscriptions, get_subscription_status, add_peer, list_peers, get_peer_status, remove_peer, sync_peer, resolve_sync_conflict, bulk_close_issues, bulk_remove_issues, restore_entity, restore_relationship, analyze_schema_candidates, get_schema_recommendations, update_schema_incremental.
  • submit_issue: required anyOf: [reporter_git_sha, reporter_app_version] at the JSON Schema level. Accepts visibility: "advisory" as a hidden alias for "private" for one minor release; response includes _deprecation: "visibility 'advisory' is deprecated; use 'private' instead.". Per-row data_source and external_actor propagated through the store contract.
  • add_issue_message: accepts reporter_git_sha, reporter_git_ref, reporter_channel, reporter_app_version. On public threads the server emits a stderr warning when both reporter_git_sha and reporter_app_version are missing; the message still persists.
  • get_issue_status / add_issue_message: both accept either entity_id or issue_number via anyOf (issue_number is an integer).
  • store: request shape gains optional external_actor (GitHub upstream author for sync-replayed observations) and source_peer_id (peer that originated the observation). observation_source enum gains "sync" for cross-instance replayed writes.
  • /mcp Bearer auth: invalid or expired OAuth tokens now return 401 invalid_token with a WWW-Authenticate header and a JSON-RPC error envelope instead of silently falling through to anonymous.

HTTP API

  • 27 new operations added since v0.11.1. Issues: issuesSubmit, issuesAddMessage, issuesGetStatus, issuesSync, bulkCloseIssues, bulkRemoveIssues. Subscriptions: subscribe, unsubscribe, listSubscriptions, getSubscriptionStatus, eventsStream (SSE). Peers + sync: addPeer, listPeers, getPeerStatus, removePeer, syncPeer, applySyncWebhook, listSyncEntities, resolveSyncConflict. Lifecycle: deleteEntity, deleteRelationship, restoreEntity, restoreRelationship. Schema: `analyzeSc...
Read more