You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
memtrace route returns {"action":"allow_raw","reason":"outside_indexed_root"} for every path I can test, including repositories that are current members of the active workspace and present in ~/.memtrace/watches.json.
Because the OpenCode rail plugin (memtrace-rail.js, written by memtrace install) acts only on action == "suppress_raw_with_result", the rail is a permanent no-op: it spawns a memtrace route subprocess on every bash/grep/glob call and can never influence the outcome, at any MEMTRACE_RAIL setting.
The rest of Memtrace is healthy — the MCP server resolves the same repositories fine — so this looks specific to route's indexed-root resolution, not to indexing or the backend.
This is the OpenCode-side counterpart of the enforcement mechanism requested in #78: the mechanism exists here, but currently cannot fire.
Environment
memtrace
1.1.8
opencode
1.18.21
OS
macOS 26.5.2, arm64
MemDB mode
local
Workspace
dev, 9 members
Runtime
memtrace start --workspace dev --headless, listening on 127.0.0.1:3030
{"action":"allow_raw","mode":"rail","surface":"outside_root",
"reason":"outside_indexed_root",
"message":"Target is outside every indexed root; allowed."}
Expected: the target is inside an indexed root, so route should evaluate the Grep against the graph and, in rail mode, be able to return suppress_raw_with_result.
mode correctly reflects MEMTRACE_RAIL (observe / nudge / rail), so the env var is read. Only the root resolution fails.
The path is genuinely indexed
list_indexed_repositories reports the same repo as a current member of workspace dev:
So this is not a stale-registry problem — the path is in both registries and on disk. I initially assumed it was, and the data refuted it.
Scope of the failure
Five paths tested, all returning outside_indexed_root:
cwd
indexed
in watches.json
result
<repo-a> (5,947 nodes)
yes
yes
outside_indexed_root
<repo-a>/tools (subdirectory)
yes
via parent
outside_indexed_root
<repo-b> (14,790 nodes)
yes
—
outside_indexed_root
<repo-c> (3,096 nodes)
yes
—
outside_indexed_root
<repo-d>
—
yes
outside_indexed_root
watches.json holds 367 entries and every one of their paths still exists on disk (0 dangling). No path tested, from either registry, resolved as inside an indexed root.
Workspace scoping cannot be supplied
route appears not to accept a workspace selector, so it cannot be pointed at dev explicitly:
memtrace route --json --workspace dev - → prints Named workspace dev: 9 member(s) (data dir: …) then fails with unknown flag: dev
memtrace route --json --workspace=dev - → resolves the workspace on the same line, then fails with unknown flag: -
MEMTRACE_WORKSPACE=dev memtrace route --json - → ignored; still outside_indexed_root
memtrace route --help shows the top-level help; it documents no route-specific flags
Note that with --workspace=dev the workspace is resolved — its 9 members and data dir are printed — and the argument parser then rejects the - stdin operand. So workspace lookup itself works; the two just cannot be combined.
Impact
memtrace-rail.js runs on tool.execute.before for bash, grep and glob, and fails open on anything that is not an explicit [Memtrace Rail] throw. With route never returning suppress_raw_with_result:
the rail cannot steer OpenCode away from raw grep/bash toward Memtrace, at any mode;
every bash/grep/glob call still pays for an execFileSync subprocess spawn (1500 ms timeout) to reach a decision that can never act.
Workaround: remove the plugin from ~/.config/opencode/plugin/. That costs only the already-inert rail and leaves the MCP server and skills fully functional.
Secondary observations
plugin/ and plugins/ are both loaded.memtrace install wrote a byte-identical memtrace-rail.js into both ~/.config/opencode/plugin/ and ~/.config/opencode/plugins/. OpenCode 1.18.21's own help string reads .opencode/plugin/` or `.opencode/plugins/, so the hook registers twice and the subprocess spawns twice per tool call. The installer should pick one directory.
memtrace status is misleading outside a workspace-aware cwd. Run from an indexed repo it reports Store present: no and No reachable owner. Run 'memtrace start' while a healthy runtime is serving that very repo — it resolves ./.memdb rather than the pinned workspace store. memtrace status --workspace dev is correct. Suggest falling back to the pinned workspace, or naming it in the error. (Adjacent to memtrace status prints a UI URL when no dashboard listener is running #64.)
Summary
memtrace routereturns{"action":"allow_raw","reason":"outside_indexed_root"}for every path I can test, including repositories that are current members of the active workspace and present in~/.memtrace/watches.json.Because the OpenCode rail plugin (
memtrace-rail.js, written bymemtrace install) acts only onaction == "suppress_raw_with_result", the rail is a permanent no-op: it spawns amemtrace routesubprocess on everybash/grep/globcall and can never influence the outcome, at anyMEMTRACE_RAILsetting.The rest of Memtrace is healthy — the MCP server resolves the same repositories fine — so this looks specific to
route's indexed-root resolution, not to indexing or the backend.This is the OpenCode-side counterpart of the enforcement mechanism requested in #78: the mechanism exists here, but currently cannot fire.
Environment
dev, 9 membersmemtrace start --workspace dev --headless, listening on 127.0.0.1:3030Reproduction
From inside an indexed repository:
Actual:
{"action":"allow_raw","mode":"rail","surface":"outside_root", "reason":"outside_indexed_root", "message":"Target is outside every indexed root; allowed."}Expected: the target is inside an indexed root, so
routeshould evaluate the Grep against the graph and, inrailmode, be able to returnsuppress_raw_with_result.modecorrectly reflectsMEMTRACE_RAIL(observe/nudge/rail), so the env var is read. Only the root resolution fails.The path is genuinely indexed
list_indexed_repositoriesreports the same repo as a current member of workspacedev:{"repo_id":"<repo-a>", "repo_path":"/Users/<user>/dev/<repo-a>", "branch":"<branch>", "nodes":5947, "edges":14145, "last_indexed_at":"2026-09-02T08:05:24.949393000Z"}~/.memtrace/runtime.jsonlists it first inworkspaceMembers, and~/.memtrace/watches.jsonhas a matching entry registered the same day:{"path":"/Users/<user>/dev/<repo-a>", "repo_id":"<repo-a>", "branch":"<branch>", "registered_at":"2026-09-02T09:05:24.287875+00:00", "origin":"manual"}So this is not a stale-registry problem — the path is in both registries and on disk. I initially assumed it was, and the data refuted it.
Scope of the failure
Five paths tested, all returning
outside_indexed_root:watches.json<repo-a>(5,947 nodes)outside_indexed_root<repo-a>/tools(subdirectory)outside_indexed_root<repo-b>(14,790 nodes)outside_indexed_root<repo-c>(3,096 nodes)outside_indexed_root<repo-d>outside_indexed_rootwatches.jsonholds 367 entries and every one of their paths still exists on disk (0 dangling). No path tested, from either registry, resolved as inside an indexed root.Workspace scoping cannot be supplied
routeappears not to accept a workspace selector, so it cannot be pointed atdevexplicitly:memtrace route --json --workspace dev -→ printsNamed workspace dev: 9 member(s) (data dir: …)then fails withunknown flag: devmemtrace route --json --workspace=dev -→ resolves the workspace on the same line, then fails withunknown flag: -MEMTRACE_WORKSPACE=dev memtrace route --json -→ ignored; stilloutside_indexed_rootmemtrace route --helpshows the top-level help; it documents noroute-specific flagsNote that with
--workspace=devthe workspace is resolved — its 9 members and data dir are printed — and the argument parser then rejects the-stdin operand. So workspace lookup itself works; the two just cannot be combined.Impact
memtrace-rail.jsruns ontool.execute.beforeforbash,grepandglob, and fails open on anything that is not an explicit[Memtrace Rail]throw. Withroutenever returningsuppress_raw_with_result:bash/grep/globcall still pays for anexecFileSyncsubprocess spawn (1500 ms timeout) to reach a decision that can never act.Workaround: remove the plugin from
~/.config/opencode/plugin/. That costs only the already-inert rail and leaves the MCP server and skills fully functional.Secondary observations
plugin/andplugins/are both loaded.memtrace installwrote a byte-identicalmemtrace-rail.jsinto both~/.config/opencode/plugin/and~/.config/opencode/plugins/. OpenCode 1.18.21's own help string reads.opencode/plugin/` or `.opencode/plugins/, so the hook registers twice and the subprocess spawns twice per tool call. The installer should pick one directory.memtrace statusis misleading outside a workspace-aware cwd. Run from an indexed repo it reportsStore present: noandNo reachable owner. Run 'memtrace start'while a healthy runtime is serving that very repo — it resolves./.memdbrather than the pinned workspace store.memtrace status --workspace devis correct. Suggest falling back to the pinned workspace, or naming it in the error. (Adjacent to memtrace status prints a UI URL when no dashboard listener is running #64.)list_watched_pathsreturnscount: 0whilewatches.jsonholds 367 entries. These may intentionally mean different things (registered vs. actively watched), but the naming invites confusion and it is a plausible neighbour of the root-resolution bug above. (Possibly related to watch_directory registers but ingests nothing: 0 episodes in 17h across 42 non-merge commits and a controlled probe save (1.1.1, Windows) #71.)