This release includes 3 security fixes for security teams reviewing exposed deployments.
Topics
+3 more
Affected surfaces
ReleasePort's take
Light signalv0.12.0 removes the legacy feedback subsystem entirely; all applications must migrate to the new issues API. MCP submit_issue now requires reporter_git_sha or reporter_app_version environment metadata.
Why it matters: Feedback subsystem is removed entirely—migrate workflows to issues API before upgrading. MCP clients must pass reporter_git_sha or reporter_app_version. Test in dev first.
Summary
AI summaryMCP submit_issue now requires reporter environment (git SHA or app version).
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Security | Medium |
OAuth Bearer token validation on /mcp; invalid tokens return 401 OAuth Bearer token validation on /mcp; invalid tokens return 401 Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Security | Medium |
Inbound peer sync webhook validates sender_peer_url and rejects private hosts Inbound peer sync webhook validates sender_peer_url and rejects private hosts Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Security | Medium |
Guest access tokens carry explicit TTL; default 30 days with revocation Guest access tokens carry explicit TTL; default 30 days with revocation Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Security | Medium |
Public issue submission redaction prevents PII; ISO dates no longer false-positive Public issue submission redaction prevents PII; ISO dates no longer false-positive Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Security | Medium |
Guest write-rate limiter for issue/subscription operations; default 30/min Guest write-rate limiter for issue/subscription operations; default 30/min Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Security | Medium |
isLocalRequest hardened; production loopback non-local by default isLocalRequest hardened; production loopback non-local by default Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Security | Medium |
Guest write‑rate limiter added for issue/subscription ops, default 30 requests per minute, keyed by AAuth thumbprint > token > IP Guest write‑rate limiter added for issue/subscription ops, default 30 requests per minute, keyed by AAuth thumbprint > token > IP Source: granite4.1:30b@2026-05-23-audit Confidence: low |
— |
| Breaking | Medium |
Legacy feedback subsystem completely removed; issues subsystem is replacement Legacy feedback subsystem completely removed; issues subsystem is replacement Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Breaking | Medium |
Access policy source precedence: env > SchemaMetadata.guest_access_policy > config Access policy source precedence: env > SchemaMetadata.guest_access_policy > config Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Breaking | Medium |
MCP submit_issue requires reporter_git_sha or reporter_app_version MCP submit_issue requires reporter_git_sha or reporter_app_version Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
Substrate subscriptions via webhook and SSE for entity/event change watching Substrate subscriptions via webhook and SSE for entity/event change watching Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Feature | Medium |
Reporter environment metadata propagates through issue messages and store Reporter environment metadata propagates through issue messages and store Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Feature | Medium |
MCP profile-aware port-file mode enabled by NEOTOMA_MCP_LOCAL_HTTP_PORT_PROFILE MCP profile-aware port-file mode enabled by NEOTOMA_MCP_LOCAL_HTTP_PORT_PROFILE Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Feature | Medium |
neotoma processes servers shows deduplicated server view with LaunchAgent info neotoma processes servers shows deduplicated server view with LaunchAgent info Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Feature | Medium |
Schema boot seeding adds plan entity with guest-access policies Schema boot seeding adds plan entity with guest-access policies Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Feature | Medium |
neotoma doctor detects iCloud-synced and risky data directory patterns neotoma doctor detects iCloud-synced and risky data directory patterns Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Feature | Medium |
Issues subsystem replaces feedback with GitHub integration and bulk operations Issues subsystem replaces feedback with GitHub integration and bulk operations Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
Cross-instance peer sync subsystem: add/remove/sync peers with conflict resolution Cross-instance peer sync subsystem: add/remove/sync peers with conflict resolution Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
27 new HTTP API operations for issues, subscriptions, peers, lifecycle, schema 27 new HTTP API operations for issues, subscriptions, peers, lifecycle, schema Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Bugfix | Medium |
Dev/prod APIs canonically bind ports 3080/3180 with incumbent pre-kill Dev/prod APIs canonically bind ports 3080/3180 with incumbent pre-kill Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Bugfix | Medium |
canonicalAauthAuthority uses NEOTOMA_PUBLIC_BASE_URL for hosted/tunnelled signing canonicalAauthAuthority uses NEOTOMA_PUBLIC_BASE_URL for hosted/tunnelled signing Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Bugfix | Medium |
MCP stdio shims source shared helpers; prevent cross-profile URL leakage MCP stdio shims source shared helpers; prevent cross-profile URL leakage Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Bugfix | Medium |
MCP stale session returns 503; uninitialized request returns 400 MCP stale session returns 503; uninitialized request returns 400 Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Bugfix | Medium |
LaunchAgent reload no longer orphans API; uses process-group SIGTERM LaunchAgent reload no longer orphans API; uses process-group SIGTERM Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Bugfix | Medium |
MCP handles stale HTTP sessions: missing session returns 400, unknown/expired session returns 503 with clear error codes MCP handles stale HTTP sessions: missing session returns 400, unknown/expired session returns 503 with clear error codes Source: granite4.1:30b@2026-05-23-audit Confidence: low |
— |
Full changelog
Install
npm install -g [email protected]
| | |
|:--|:--|
| npm | https://www.npmjs.com/package/neotoma/v/0.12.0 |
| Compare | v0.11.1 → v0.12.0 — view 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_peership withPOST /sync/webhookinbound delivery (HMAC-signedX-Neotoma-Sync-Signature-256), AAuth-thumbprint loop prevention, andresolve_sync_conflictfor prefer-local vs prefer-remote reconciliation.get_peer_statusnow includesremote_health(/healthprobe +neotoma compatsemver check) so operators can see immediately when a peer is offline or runs an incompatible version.applyInboundSyncWebhookrejects mismatchedsender_peer_urlvalues and blocks private/loopback hostnames whenNEOTOMA_HOSTED_MODE=1. Seedocs/subsystems/peer_sync.md. - Substrate subscriptions with webhook + SSE transport.
subscribe/unsubscribe/list_subscriptions/get_subscription_statusplusGET /events/stream(SSE) let agents and external services watch entity / event / relationship changes for specificentity_types,entity_ids, orevent_types. Webhook deliveries are HMAC-signed; SSE uses the same auth as the API. Loop-preventionsync_peer_idis 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_issuesare the canonical reporting flow, with GitHub mirror + operator forwarding + guest read-back tokens. Public submit + public-thread message paths run through the existingscanAndRedactPII guard as a backstop, ISO-date literals no longer false-positive as phone numbers, andloadIssueThreadMessagesdeduplicates across remote + local + multi-conversation threads. New CI workflows auto-label issues fromissue_kindand post upgrade-guidance comments on releases. - Reporter environment is required on
submit_issue, soft-required onadd_issue_message. The MCPsubmit_issueJSON Schema gainsanyOf: [{ required: [reporter_git_sha] }, { required: [reporter_app_version] }], so MCP clients fail validation locally before sending; the HTTPPOST /issues/submitroute returns400 ERR_REPORTER_ENVIRONMENT_REQUIREDwithdetails.acceptable_field_groups. On publicadd_issue_messagethreads, 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:
isLocalRequestkeeps the stricter forwarded-hop handling, production loopback remains non-local by default (setNEOTOMA_TRUST_PROD_LOOPBACK=1to opt back in), a new CIsecurity_gatesjob 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 againsthttps://sandbox.neotoma.io,SECURITY.mdis rewritten with the disclosure flow and advisories index, anddocs/developer/mcp/proxy.mddocuments the operator-requiredMCP_PROXY_FAIL_CLOSED=1for 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)./mcpnow validates OAuthBearertokens and responds with a proper401 invalid_tokenenvelope andWWW-Authenticateresource-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 arevoked_atfield, 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/3180so dev and prod always bind their canonical ports.scripts/reload_neotoma_launchagents.sh --kill-zombiesrecognizes 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 explicitNEOTOMA_MCP_LOCAL_HTTP_PORT_PROFILE=dev|prodas sufficient to enable port-file mode (Cursor strips"1"flag values), and the downstream resolver warns on (but never honors) cross-profileMCP_PROXY_DOWNSTREAM_URLleakage. - CLI: new
processes servers,plans capture/list,access list/set/reset, doctor risk detection.neotoma processes serverscollapses parent-child process trees into one row per listener, surfacesLAUNCHAGENT/DATA_DIR/LOGS, and supports--watch.neotoma plans capture <file>/--allingests harness.plan.mdfiles (.cursor/plans,.claude/plans,.codex/plans,.openclaw/plans) via the canonical combinedstorepath.neotoma access listshows the winning policy source (env / schema_metadata / config_file / default);access set/reset/enable-issues/disable-issueswrite throughSchemaMetadata.guest_access_policyas the canonical source (the legacy config file is now a deprecated fallback only).neotoma doctor --jsonaddsdata.risksfor iCloud-synced / Documents / Desktop data directories and prior SQLite repair artifacts, plus asuggested_safe_data_dir. - OpenClaw plugin entry point. A new
src/openclaw_entry.tsregisters Neotoma MCP tools as OpenClaw agent tools, declareskind: "memory"so users can wire it viaplugins.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, anISSUE REPORTINGsection keyed offissues.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: requiredanyOf: [reporter_git_sha, reporter_app_version]at the JSON Schema level. Acceptsvisibility: "advisory"as a hidden alias for"private"for one minor release; response includes_deprecation: "visibility 'advisory' is deprecated; use 'private' instead.". Per-rowdata_sourceandexternal_actorpropagated through the store contract.add_issue_message: acceptsreporter_git_sha,reporter_git_ref,reporter_channel,reporter_app_version. On public threads the server emits a stderr warning when bothreporter_git_shaandreporter_app_versionare missing; the message still persists.get_issue_status/add_issue_message: both accept eitherentity_idorissue_numberviaanyOf(issue_number is an integer).store: request shape gains optionalexternal_actor(GitHub upstream author for sync-replayed observations) andsource_peer_id(peer that originated the observation).observation_sourceenum gains"sync"for cross-instance replayed writes./mcpBearer auth: invalid or expired OAuth tokens now return401 invalid_tokenwith aWWW-Authenticateheader 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:analyzeSchemaCandidates,getSchemaRecommendations,updateSchemaIncremental. Access policy:getAccessPolicies. POST /issues/submit: the description now declares the reporter-environment requirement, and the 400 response declareserror_code: ERR_REPORTER_ENVIRONMENT_REQUIREDwithdetails.acceptable_field_groups: [["reporter_git_sha"], ["reporter_app_version"]]. (HTTP enforcement is at the application layer; the JSON Schema body is unchanged, sonpm run openapi:bc-diffreports this as non-breaking. MCP enforcement is at the JSON Schema layer viaanyOf— see Breaking changes below.)POST /issues/add_message: acceptsreporter_git_sha,reporter_git_ref,reporter_channel,reporter_app_version(all optional; soft requirement on public threads).POST /store:ErrorEnvelope.error_codeenum gainsERR_RELATIONSHIP_ENTITY_ID_FORMATso structured-store callers can detect malformedsource_entity_id/target_entity_idformats with a specific code + hint instead of a genericVALIDATION_INVALID_FORMAT.- Guest write paths (
/issues/submit,/issues/add_message,/subscribe,/unsubscribe) share a separate rate-limit bucket from the broader/storelimiter and consume a guest budget keyed by AAuth thumbprint > hashed guest token > IP.
CLI
neotoma processes servers— server-only filtered view of Neotoma processes, deduplicated by parent-child stack, withLAUNCHAGENT/DATA_DIR/LOGScolumns and--watchmode.neotoma plans capture <file>/--all— ingest harness.plan.mdfiles via the canonical combinedstorepath (raw markdown +planrow + EMBEDS). Identity is keyed by(harness, harness_plan_id), so re-running is idempotent.neotoma plans list [--source-entity-id] [--status] [--harness] [--limit]— list storedplanentities; wrapsPOST /retrieve_entities.neotoma access list— shows the winning source per entity type (env,schema_metadata,config_file, ordefault);access resetreportseffective_mode/effective_sourceafter reset so an env override that still wins is visible.neotoma issues create --advisoryis a deprecated hidden alias for--visibility private(one minor release).neotoma issues statusnow accepts--issue-numberas an alternative to--entity-id. Reporter env flags (--reporter-git-sha,--reporter-app-version,--reporter-git-ref,--reporter-channel,--reporter-ci-run-id) are accepted on bothcreateandmessage.neotoma doctor --jsonaddsdata.risks[](icloud_drive,macos_synced_desktop_or_documents,prior_sqlite_repair_artifacts) anddata.suggested_safe_data_dirso users can move the SQLite DB off iCloud-synced paths.neotoma storage set-data-dirdocuments the recommended~/Library/Application Support/neotoma/datalocation for macOS.resolveBaseUrlnow probes the preferred-env default port before pinning to it; if no API is listening, multi-instance discovery resumes so CLI commands no longer hang against a dead API.
API surface & contracts
- OpenAPI: 27 new operations (above).
ErrorEnvelope.error_codeaddsERR_RELATIONSHIP_ENTITY_ID_FORMATandERR_CONVERSATION_MESSAGE_ROLE_CONFLICT.entities/querysort_bywidens to includesubmitted_at.AgentDirectoryEntrygainsobservation_entity_type_counts. - MCP tool schemas:
submit_issueaddsanyOffor reporter env (breaking at the MCP layer for clients that previously omitted both fields).add_issue_message,get_issue_statusaddanyOf: [entity_id, issue_number]. New tool descriptors for the 17 new MCP tools listed above; updated descriptors document the advisory→private deprecation and the integer type forissue_number. - Schema seeding:
planglobal schema added at boot.issue,conversation, andconversation_messageship with seeded guest-access policies for issue submission (submitter_scopedwhenneotoma access enable-issuesruns). conversation_message: optionalreporter_git_sha,reporter_git_ref,reporter_channel,reporter_app_versionso reporter env onadd_issue_messagepersists on the thread row.
Behavior changes
- Issues replace feedback as the primary reporting surface. The legacy feedback intake artifacts (cron and Netlify) are removed;
submit_issue/add_issue_message/get_issue_statusare the canonical flow, both for in-product agents and external operators. Reporter env is enforced on submit and soft-enforced on public-thread messages. - The auth model stays on the hardened v0.11.1 path. Same-host reverse proxies (Caddy, nginx, Cloudflare tunnel, Fly) connect to Node over loopback for public-internet callers.
isLocalRequestrequires (a) loopback socket, (b) noX-Forwarded-Forclaim from a non-loopback hop, and (c) either non-production env or explicitNEOTOMA_TRUST_PROD_LOOPBACK=1. The same policy is mirrored insrc/services/root_landing/index.tsfor landing-mode resolution. - Access policy precedence reversed at the source layer. Env vars >
SchemaMetadata.guest_access_policy(new canonical source) > config file (now a deprecated fallback that logs a warning on read).loadAccessPolicies/resolveAccessPolicyreturn the same effective values;loadAccessPolicyEntriesandresolveAccessPolicyWithSourceexpose the winning source soneotoma access list/resetcan surface it. - MCP profile-aware port-file mode.
NEOTOMA_MCP_LOCAL_HTTP_PORT_PROFILE=devor=prodis now sufficient on its own to enable port-file resolution. This unblocks Cursor's MCP harness, which silently drops"1"-valued env entries while honoring sibling string values like"prod". Legacy callers that pass neither the flag nor a profile fall through to the historicalhttp://127.0.0.1:3080/mcpdefault. - MCP stale session disambiguation.
POST /mcpwith a stale or unknown session id returns503(JSON-RPC-32xx); requests that never initialized return400. Operators see distinct codes for proxy / restart / load-balancer-induced session loss. - Combined-store file sniff.
storeresolves the file MIME type from the buffer's magic bytes (sniffMimeTypeFromBuffer) before falling back to extension + caller-providedmime_type, so JPEG/PNG/GIF/WebP/PDF/Ogg/FLAC/WAV uploads classify correctly even when the extension is wrong. - Guest access tokens carry a TTL.
NEOTOMA_GUEST_TOKEN_TTL_SECONDS(default 2,592,000 = 30 days) andrevoked_atare persisted on the token observation. Generation errors now throw instead of being logged-and-swallowed. - Inbound peer sync webhook is hostname-validated.
applyInboundSyncWebhookrejects sender_peer_url values that do not match the configuredpeer_urlafter normalization (SENDER_PEER_URL_MISMATCH), and rejects private/loopback hostnames whenNEOTOMA_HOSTED_MODE=1(SENDER_PEER_URL_PRIVATE_HOST). canonicalAauthAuthorityconsultsNEOTOMA_PUBLIC_BASE_URLbefore falling back toconfig.apiBase, so AAuth signing on hosted/tunnelled deployments resolves to the public hostname rather than the bound interface.
Agent-facing instruction changes
- MCP instructions (
docs/developer/mcp/instructions.md): display rule overhauled to render🧠 Neotoma — [<conversation title>](<active Neotoma origin>/inspector/conversations/<entity_id>)headings and per-entity bullets that link the entity_type text to the Inspector record. New sections:[CROSS-INSTANCE SYNC — PEERS],[SUBSTRATE SUBSCRIPTIONS],[ISSUE REPORTING](renamed fromFEEDBACK REPORTING, gated byissues.reporting_mode:proactive/consent/offwith a one-time mode-discovery prompt).[STORE RECIPES]documentsobservation_source(sensor/workflow_state/llm_summary/human/import/sync) andsource_peer_idfor sync replays. - CLI agent instructions (
.cursor/rules/neotoma_cli.mdc+ canonical copies): same Inspector-linked display rule, plus issue-driven work updates (an issue id in the prompt requiresadd_issue_messagebefore final reply), GitHub issue URL extraction normalization (github_number+repoidentity rule), and explicit pre-release checklist references. - Skills: the existing
releaseskill is rewritten to encode the comprehensive-body coverage rule for release supplements; theevaluatesite subpage prompts agents to offer a non-destructive Test-safely shadow mode before recommending full implementation.
Tests and validation
npx tsc --noEmitnpx vitest run tests/contract/ --reporter=verbosenpx vitest run tests/cli/cli_command_coverage_guard.test.ts tests/cli/cli_doctor_setup.test.ts tests/cli/config_api_discovery.test.ts tests/cli/processes_command.test.ts --reporter=verbosenpx vitest run tests/integration/cross_instance_issues.test.ts tests/integration/tunnel_auth.test.ts tests/integration/root_landing.test.ts --reporter=verbosenpx vitest run tests/subscriptions/subscription_guest_auth.test.ts tests/contract/openclaw_plugin.test.ts tests/unit/security_hardening.test.ts tests/unit/client_turn_report.test.ts --reporter=verbosenpm run openapi:bc-diff(reports non-breaking; HTTP reporter-env enforcement is application-layer, MCP enforcement is JSON-schema-layer)npm run security:classify-diff(reports sensitive=true)npm run security:lintnpm run security:manifest:checknpm run test:security:auth-matrixnpm run build:serverbash scripts/security/deployed_probes.sh --tag v0.12.0(post-deploy)
Breaking changes
- MCP
submit_issuerequires reporter environment. The MCP tool's JSON Schema now declaresanyOf: [{ required: [reporter_git_sha] }, { required: [reporter_app_version] }], so MCP clients that previously calledsubmit_issuewith onlytitle+bodywill fail JSON-schema validation locally before the request leaves the client. HTTP callers ofPOST /issues/submitsee the same enforcement at the application layer with400 ERR_REPORTER_ENVIRONMENT_REQUIREDanddetails.acceptable_field_groups: [["reporter_git_sha"], ["reporter_app_version"]]. This is a tightening of request-shape validation (perdocs/architecture/change_guardrails_rules.mdcrule 14, that is by definition breaking) and is documented atdocs/subsystems/issues.md§ Reporter provenance. - Issues replace feedback at the subsystem boundary. The legacy feedback cron + Netlify intake artifacts are removed. Any consumer that was scripting against the feedback path must move to
submit_issue/POST /issues/submitand supply reporter env. src/services/issues/syncIssuesFromGitHub.tsis renamed tosync_issues_from_github.ts. Deep imports against the camelCase filename break; the public service barrel (src/services/issues/index.ts) is unchanged, so most consumers are unaffected.
Migration guide
- Agents and clients calling
submit_issue/POST /issues/submit: addreporter_git_sha(e.g.git rev-parse HEAD) and/orreporter_app_version(e.g. the npm package version) to every call. Daemons and CI runners may also passreporter_git_ref,reporter_channel,reporter_ci_run_id. - Agents calling
add_issue_message: when continuing a debugging thread, pass the reporter env that you re-tested against. The server only warns when these are missing on public threads — but every message you store without them loses its connection to the build it describes. - Operators running Neotoma behind a reverse proxy in production: set
NEOTOMA_BEARER_TOKEN(or enable AAuth) and verifyisLocalRequestno longer falsely accepts proxied traffic. If your deployment intentionally needs production loopback to count as local (e.g. an internal admin script), setNEOTOMA_TRUST_PROD_LOOPBACK=1explicitly. - Operators running hosted / tunnelled MCP proxies: set
MCP_PROXY_FAIL_CLOSED=1(orfailClosed: trueon the proxy options) whenever AAuth signing is required, so unsigned downstream requests never bypass the signer. - Operators on Cursor / Claude Code / Codex with profile shims: delete and re-run
neotoma mcp configso the regeneratedmcp.jsonpicks up the new resolver behaviour (NEOTOMA_MCP_LOCAL_HTTP_PORT_PROFILEalone is now sufficient). The signed and unsigned dev shim scripts both sourcescripts/lib/neotoma_mcp_resolve_downstream_url.sh, so a fresh checkout immediately gets the cross-profile-leakage fix. - Operators with stale dev API instances: reload LaunchAgents once via
bash scripts/reload_neotoma_launchagents.sh --kill-zombies. The reloader now recognizes the actual orphan patterns observed on disk (with_branch_ports.js+actions.tschains, PPID=1tsx watchzombies,npm exec tsxchains). - Operators with iCloud-synced data directories: run
neotoma doctor --jsonand checkdata.risks. MoveNEOTOMA_DATA_DIRto a local-only path (~/Library/Application Support/neotoma/datais the recommended macOS default) withneotoma storage set-data-dir <dir>while Neotoma is stopped. - Harness plan files: run
neotoma plans capture --allonce to backfill any existing.cursor/plans/,.claude/plans/,.codex/plans/,.openclaw/plans/files into Neotoma. Identity is keyed by(harness, harness_plan_id)so re-running is idempotent. - Issue submission access policy: if your operator instance accepts issues from authenticated guests, run
neotoma access enable-issuessoissue,conversation, andconversation_messageare set tosubmitter_scopedviaSchemaMetadata. The deprecated config-file fallback still works but logs a warning on read.
Security hardening
This release builds on the v0.11.1 auth-bypass hotfix and adds the follow-through that makes that fix durable in day-to-day operation: pre-release gates G1–G5, hardened loopback / forwarded-for classification, and explicit operator guidance.
isLocalRequestrewrite insrc/actions.ts(and the mirrored copy insrc/services/root_landing/index.ts): loopback + presence of any non-loopbackX-Forwarded-Forhop now disqualifies the request from local-dev auth; production loopback is non-local by default. New env knob:NEOTOMA_TRUST_PROD_LOOPBACK=1(opt-in, off by default).- CI security_gates job runs G1 (
security:classify-diffwith PR base-branch awareness), G2 (security:lint), G3 (security:manifest:check+test:security:auth-matrix) on every pull request. The sandbox weekly-reset workflow runs G5 (scripts/security/deployed_probes.sh) againsthttps://sandbox.neotoma.ioand uploads the probe report as an artifact. - MCP_PROXY_FAIL_CLOSED operator guidance added to
docs/developer/mcp/proxy.md: hosted deployments that require AAuth signing must set this so the proxy refuses to forward unsigned downstream requests if signing or session preflight fails. - Guest write rate limiter for
/issues/submit,/issues/add_message,/subscribe,/unsubscribe(NEOTOMA_GUEST_WRITE_RATE_LIMIT_PER_MIN, default 30/min), keyed by AAuth thumbprint > hashed guest token > IP to prevent IP-shared accounts from starving each other. - OAuth Bearer enforcement on
/mcp: unknown / expired tokens return401 invalid_tokenwithWWW-Authenticateresource-metadata. UUID-shaped tokens used asaccess_tokenor Bearer no longer bypass to anonymous; tests undertests/subscriptions/subscription_guest_auth.test.tsandtests/unit/security_hardening.test.tslock the regression in. - Inbound peer sync hardening:
applySyncWebhookverifies the HMAC signature against the configured peer secret, then validates thatsender_peer_urlmatches the configuredpeer_urlafter normalization, and (in hosted mode) rejects private / loopback / link-local hostnames. - Guest access token TTL + revocation:
NEOTOMA_GUEST_TOKEN_TTL_SECONDS(default 30 days) andrevoked_atare persisted on every token; generation errors throw with descriptive messages. - Redaction backstop runs on public submit / public-thread messages so submitter-side redaction bugs do not leak PII; the same regex used by the legacy feedback flow now also skips ISO-date literals so dates like
2026-05-12are not redacted as phone numbers. - SECURITY.md rewrite documents the disclosure flow (private intake → hotfix branch → gates → coordinated release → deployed probes → public advisory), the operator-visible gate summary table, the supported-version range, and the rotation guidance for operators after any advisory.
Per docs/security/threat_model.md, the post-deploy probe report for this tag will land at docs/security/probes/v0.12.0.md.
Commits (v0.11.1 → v0.12.0)
7e606e5Merge test/current-branch-build for v0.12.0c9c2e6bPre-release: include remaining v0.12.0 tests4ca8f61Pre-release: include pending changes for v0.12.080ae165fix(launchagents): pin dev/prod to canonical ports and stop chokidar reload from orphaning the API server654e450feat: expand issue submission, sync, and site surfaces33c0840fix(mcp): treat profile=prod/dev alone as sufficient to enable port-file mode5c24bbdrefactor(mcp): all stdio shim wrappers source the shared env + resolver libs1c2f98ffix(mcp): harden stdio shim downstream resolver and launchagent reload629f508chore: sync local port profile docs and contracts67e7d5ffix(mcp): support profiled local port files1f3c487fix(mcp): clarify unknown HTTP session errorsc732589feat: prepare issue workflow and site build updates
Full compare: v0.11.1...v0.12.0
Breaking Changes
- MCP `submit_issue` requires reporter environment (anyOf: [reporter_git_sha] or [reporter_app_version]).
- Legacy feedback subsystem removed; all issue reporting must use new `submit_issue`/`POST /issues/submit` APIs.
- File rename: `src/services/issues/syncIssuesFromGitHub.ts` → `sync_issues_from_github.ts` (breaks deep imports).
Security Fixes
- Hardened `isLocalRequest` to reject non‑loopback forwarded hops; production loopback disabled by default (opt‑in via NEOTOMA_TRUST_PROD_LOOPBACK=1).
- Added CI security gates G1–G5, sandbox probe deployment, and guest write rate limiting.
- Inbound peer sync webhook validates sender_peer_url and rejects private/loopback hosts in hosted mode.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About markmhendrickson/neotoma
Deterministic state layer for AI agents. Stores versioned entities (contacts, tasks, transactions, decisions) with immutable observations, full provenance, and schema-first extraction. Local-first SQLite, cross-client memory across Claude, Cursor, ChatGPT, and OpenClaw. Website
Related context
Related tools
Earlier breaking changes
- v0.12.1 Inspector build prepublish now exits non-zero if inspector submodule is missing, breaking ad-hoc npm pack runs without init.
Beta — feedback welcome: [email protected]