Skip to content

Sandboxed execution silently degrades curate/search to FTS with misleading 'typo in the url or port' warnings and an EROFS appendEvent error #813

Description

@itlackey

Summary

Running any akm search/curate verb from inside a sandboxed agent session (Codex --sandbox read-only, and any comparable sandbox that blocks LAN egress and mounts the FS read-only) produces two streams of unactionable stderr noise and silently degrades results from semantic search to FTS keyword matching. The degraded results are materially wrong, and nothing in the JSON output indicates the degradation happened.

This is increasingly the default way akm gets invoked — the Claude/OpenCode plugins and any agent-driven loop call it from inside a sandbox — so the failure mode is common rather than exotic.

Reproduction

Reproduces 100% on this machine, byte-for-byte identical to what a user reported from an agent session:

codex sandbox -- akm curate "coordinate multi-agent implementation across three repositories with architecture decision gates independent code review and verification"
Vector search failed, skipping: Was there a typo in the url or port?
Vector search failed, skipping: Was there a typo in the url or port?
Vector search failed, skipping: Was there a typo in the url or port?
Vector search failed, skipping: Was there a typo in the url or port?
Vector search failed, skipping: Was there a typo in the url or port?
Vector search failed, skipping: Was there a typo in the url or port?
Vector search failed, skipping: Was there a typo in the url or port?
akm: appendEvent failed: Error: EROFS: read-only file system, open '/home/founder3/.local/share/akm/maintenance.barrier.lock'

The identical command outside the sandbox is completely clean — no warnings, no EROFS.

Root cause

Both messages are the sandbox, not a misconfiguration:

  1. Network egress is blocked, so embed() (src/llm/embedder.ts:112) cannot reach the embedding endpoint. vectorScores() catches it at src/indexer/search/db-search.ts:888 and warns.
  2. The filesystem is read-only, so appendEvent() (src/core/events.ts:275) cannot create the maintenance-barrier lockfile (src/core/paths.ts:272) that opening the state DB acquires.

Critically, the configuration is fine. Verified from an unsandboxed shell on the same machine:

$ curl -s -w '\nHTTP:%{http_code}\n' http://192.168.0.205:1234/v1/embeddings \
    -H 'Content-Type: application/json' \
    -d '{"model":"text-embedding-nomic-embed-text-v1.5@q8_0","input":"hello"}'
# → HTTP:200, valid 768-dim embedding returned; model is loaded
$ ls -ld ~/.local/share/akm   # writable, ext4 rw,noatime

So "Was there a typo in the url or port?" — Bun's connect-failure string, surfaced verbatim — actively sends the reader to check a URL that is correct. That message costs real debugging time; it did here.

The actual harm: silent result degradation

The noise is annoying. The result quality collapse is the bug. Same query, same machine, same moment:

Unsandboxed (semantic search):

extracted-c19c2368//skills/autonomous-loops
agent-stash//agents/development/agentic-systems-architect
knowledge/wave-based-agent-coordination-patterns

Sandboxed (FTS fallback):

extracted-c19c2368//skills/autonomous-loops
extracted-c7403802//skills/platform-magento/magento-multi-store
extracted-c7403802//skills/catalog-inventory/multi-warehouse
extracted-c7403802//skills/payments-checkout/multi-currency

Three of the four sandboxed results are Magento e-commerce skills that match only on the literal token "multi". For a query about multi-agent coordination, that is noise crowding out the two genuinely relevant assets that semantic search found.

The JSON output carries no indication this happened. summary reads "Selected 4 curated results" with the same confident reason strings ("Strong specialized agent prompt match for…") as a healthy run. An agent consuming this — which is the whole point of --shape agent — cannot tell it is being handed keyword noise, and will act on it.

Three distinct defects

  1. The warning does not name the endpoint and repeats 7× per invocation. It should state the URL it failed to reach and appear once, e.g. Vector search unavailable: cannot reach embedding endpoint http://…:1234/v1/embeddings (connection refused) — falling back to keyword search.
  2. Degradation is invisible to machine consumers. The result payload should carry a flag (degraded: true / searchMode: "fts-fallback", or an entry in the existing warnings field) so an agent can weigh the results accordingly or tell the user.
  3. A read-only verb takes a write barrier. curate is a read operation, yet it acquires the maintenance barrier to append a usage event and hard-errors on a read-only FS. Confirmed this is usage tracking: --no-track-usage suppresses the EROFS entirely (the vector warnings remain). Under a read-only FS this should degrade silently rather than printing a raw Node error with a stack-ish prefix.

Suggested fixes

  • Detect the connect-failure class in vectorScores() and emit one enriched, endpoint-naming warning per invocation instead of one per call site.
  • Thread a degradation signal into the curate/search result shape so --shape agent consumers can see it.
  • Make appendEvent() treat EROFS/EACCES as an expected no-op — best-effort telemetry should not report failure when the environment is legitimately read-only. It already declares itself best-effort; it just is not quiet about this case.
  • Consider a broader read-only-environment detection: if the data dir is not writable, skip usage tracking wholesale rather than failing per-write.

Workaround for users hitting this now

akm curate "…" --no-track-usage removes the EROFS line. There is no workaround for the vector-search degradation inside a sandbox short of granting network egress — which is worth documenting, since the results are quietly worse rather than absent.

Environment

  • akm 0.9.1
  • Linux, ext4 rw,noatime; ~/.local/share/akm writable
  • Embedding: lmstudio, http://192.168.0.205:1234/v1/embeddings, text-embedding-nomic-embed-text-v1.5@q8_0, dim 768 — verified reachable and returning 200 from an unsandboxed shell
  • akm info: semanticSearch: mode auto, status ready-vec, hasEmbeddings: true, vecAvailable: true, 23510 indexed entries
  • Sandbox used for reproduction: codex sandbox (Codex CLI 0.147.0)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions