Skip to content

fix(dir-config): route memory reads through .hivemind, not just capture#316

Merged
khustup2 merged 2 commits into
mainfrom
fix/dir-config-route-reads
Jul 16, 2026
Merged

fix(dir-config): route memory reads through .hivemind, not just capture#316
khustup2 merged 2 commits into
mainfrom
fix/dir-config-route-reads

Conversation

@khustup2

@khustup2 khustup2 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

The bug

A user set workspaceId in a .hivemind, opened a session, and still saw the default workspace's files. The file was correct and the feature was installed — reported against v0.7.131, and .hivemind support shipped in v0.7.123.

.hivemind resolved fine. Only the capture path ever consumed it. Every read path called loadConfig() raw and never looked at .hivemind at all:

Read path Line
VFS backing ~/.deeplake/memory src/shell/deeplake-shell.ts:62
grep/cat interception src/hooks/pre-tool-use.ts:269
Proactive recall src/hooks/recall.ts:201

So a routed directory wrote to its workspace and read from the global one.

The banner made it worse. session-start.ts:342 built the disclosure from the overlaid config, printing routed by /path/.hivemind while every readable file still came from default — confirming to the user that their config worked. That's what cost them the debugging time; an honest banner would have made this a sixty-second diagnosis.

The fix

Route the three read paths through resolveDirConfig, and separate the two concerns the file expresses:

  • orgId / workspaceId are identity — reads and writes alike
  • collect is a capture switch — writes only

collect: false previously short-circuited the whole overlay, so { "collect": false, "workspaceId": "x" } silently dropped workspaceId — the same dead-config bug in miniature. Splitting them also makes "read a shared workspace, never write to it" expressible. Reads remain authorized by the existing token; nothing new is reachable.

hivemind whoami was lying too

If you ask an agent "what workspace am I in?", it runs whoami. That read loadCredentials() directly, so it reported the global workspace inside a routed directory — while the banner said otherwise, leaving the agent two contradictory sources.

This is broken on main independently of .hivemind: whoami never called loadConfig(), so HIVEMIND_WORKSPACE_ID=x hivemind whoami misreports today. It now reports the effective identity for the cwd and discloses whether a .hivemind or the environment overrode the stored values.

Why CI stayed green

resolveDirConfig was thoroughly unit-tested and correct. Nothing asserted that any consumer used it. The bug wasn't in any file — it was in four call sites that didn't exist, which no unit test and no file-level review can see.

tests/shared/dir-config-read-routing.test.ts therefore asserts the consumer: it drives a real read through the hook and checks which workspace the backend resolves to. Verified to fail against the unfixed code (the 4 routing assertions fail; the no-op cases pass in both, as they should).

Verification

  • Typecheck clean.
  • Full suite: no new failures. 14 files still fail, all pre-existing and unrelated — 13 are tree-sitter-python missing from the graph extractor, 1 is a flush-memory network timeout that fails identically at baseline.
  • One shipped assertion in dir-config.test.ts deliberately flipped (the collect:false overlay short-circuit), rewritten rather than deleted, with the rationale inline.

Follow-ups (not in this PR)

  • The MCP server is still unrouted (src/mcp/server.ts:43). It's long-lived per-host and its process.cwd() won't track a session across directories, so it needs a different mechanism — likely cwd threaded per tool call. Deliberately not half-fixed here.
  • No other CLI command consults .hivemind (workspaces, org list, …). Lower impact since they're about the account rather than the directory, but worth a pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_017SDmiDuUn7Wqhi7qdn1p1f

Summary by CodeRabbit

  • New Features

    • Directory-based .hivemind config now routes both memory reads and trace writes to the configured workspace/org.
    • Added whoami output for the effective identity, reflecting both environment and directory overrides.
    • Session startup messaging now shows routed workspace details and capture status.
  • Bug Fixes

    • collect:false no longer blocks read routing; it only disables capture/writes.
    • Directory-specific settings are now applied consistently across recall and shell behavior.
  • Documentation

    • Expanded .hivemind documentation with clarified semantics and new routing “recipes,” including notes about auth token behavior.
  • Tests

    • Added/updated coverage for per-directory read routing and whoami routing/capture opt-out messaging.

`.hivemind` resolved correctly, but only the capture path consumed it —
every read path (memory search, proactive recall, the VFS shell) called
loadConfig() raw. A routed directory captured to its workspace while
reading from the global one, and the SessionStart banner reported the
routed identity regardless, so the misrouting presented as success.

Route the three read paths through resolveDirConfig, and separate the two
concerns the file expresses:

  - orgId / workspaceId are IDENTITY — reads and writes alike
  - collect is a CAPTURE switch — writes only

collect:false previously short-circuited the whole overlay, silently
dropping a workspaceId set alongside it. Splitting them makes "read this
workspace, never write to it" expressible, and removes a config field
that could be set and quietly ignored.

whoami reported raw stored creds, so it misreported inside a routed
directory — and, independently of this feature, under HIVEMIND_ORG_ID /
HIVEMIND_WORKSPACE_ID as well. It now reports the effective identity for
the cwd and discloses whether a .hivemind or the environment overrode the
stored values, so it agrees with the banner instead of contradicting it.

The resolver was fully unit-tested and correct; nothing asserted that any
consumer used it, which is why this shipped green. The added tests drive
a real read through the hook and assert the workspace it resolves to —
they fail against the unfixed code.

The MCP server (src/mcp/server.ts) is still unrouted: it is long-lived
per-host and its process.cwd() does not track a session across
directories, so it needs a different mechanism and is left for a
follow-up.
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ff10d300-039a-476e-9af0-abb8fded925e

📥 Commits

Reviewing files that changed from the base of the PR and between 222ad36 and 15d0dab.

📒 Files selected for processing (1)
  • tests/claude-code/recall-hook.test.ts

📝 Walkthrough

Walkthrough

Directory-based identity routing now applies to memory reads and writes, while collect:false only disables capture. whoami and session-start report effective environment and directory overrides, with tests and documentation covering routing, fallback, and capture-disabled behavior.

Changes

Directory routing and identity reporting

Layer / File(s) Summary
Identity overlay and capture semantics
src/dir-config.ts, tests/shared/dir-config.test.ts, README.md
Directory identity overlays remain active when collect:false; documentation and tests define identity as read/write behavior and collect as write-only behavior.
Routed memory operations
src/hooks/pre-tool-use.ts, src/hooks/recall.ts, src/shell/deeplake-shell.ts, tests/shared/dir-config-read-routing.test.ts, tests/claude-code/recall-hook.test.ts
Memory reads, recall, and shell operations resolve configuration from the relevant working directory, including environment overrides, ancestor routing, and process-directory fallback.
Effective identity reporting
src/commands/whoami.ts, src/commands/auth-login.ts, src/hooks/session-start.ts, tests/claude-code/auth-login-dispatch.test.ts, tests/shared/dir-config-read-routing.test.ts
whoami and session-start display effective identity, routing source, environment overrides, and capture-disabled status.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Command
  participant resolveDirConfig
  participant DeeplakeApi
  participant Memory
  Command->>resolveDirConfig: resolve config for working directory
  resolveDirConfig-->>Command: effective org and workspace
  Command->>DeeplakeApi: create memory client with effective config
  DeeplakeApi->>Memory: read or write using routed identity
  Memory-->>DeeplakeApi: memory result
  DeeplakeApi-->>Command: operation result
Loading

Possibly related PRs

Suggested reviewers: efenocchi, kaghni

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is detailed, but it does not follow the required template and omits the Summary, Version Bump, and Test plan sections. Rewrite the PR description using the repo template and add Summary, Version Bump, and Test plan sections with test status and release-bump info.
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main fix: routing memory reads through .hivemind instead of only capture.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/dir-config-route-reads

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Scope: files changed in this PR. Enforced threshold: 90% per metric (per file via vitest.config.ts).

Status Category Percentage Covered / Total
🟢 Lines 95.86% (🎯 90%) 533 / 556
🟢 Statements 94.66% (🎯 90%) 620 / 655
🟢 Functions 94.12% (🎯 90%) 48 / 51
🔴 Branches 89.29% (🎯 90%) 542 / 607
File Coverage — 7 files changed
File Stmts Branches Functions Lines
src/commands/auth-login.ts 🟢 92.2% 🟢 92.3% 🟢 90.9% 🟢 99.0%
src/commands/whoami.ts 🟢 95.5% 🔴 81.5% 🟢 100.0% 🟢 94.7%
src/dir-config.ts 🟢 100.0% 🟢 100.0% 🟢 100.0% 🟢 100.0%
src/hooks/pre-tool-use.ts 🟢 92.1% 🔴 86.0% 🟢 90.5% 🟢 91.9%
src/hooks/recall.ts 🟢 100.0% 🟢 90.9% 🟢 100.0% 🟢 100.0%
src/hooks/session-start.ts 🟢 98.9% 🟢 93.3% 🟢 100.0% 🟢 98.8%
src/shell/deeplake-shell.ts

Generated for commit cdf71c9.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/commands/whoami.ts`:
- Around line 38-48: The whoami output can pair an environment-selected org ID
with a stale credential-derived org name. In src/commands/whoami.ts lines 38-48,
update the org display in the lines array to show the effective org ID whenever
the environment changed the organization, using envMoved while preserving the
existing name display otherwise. In tests/shared/dir-config-read-routing.test.ts
lines 144-149, add a concrete HIVEMIND_ORG_ID assertion covering this behavior.

In `@src/hooks/pre-tool-use.ts`:
- Around line 328-332: Namespace the cached index used by the read-routing flow
around resolveDirConfig by session, organization, and workspace rather than
session alone, using the effective identity derived from the requested cwd. Add
coverage in tests/shared/dir-config-read-routing.test.ts lines 52-74 that
performs two routed reads in one session with a stateful cache and verifies each
organization/workspace receives its own index.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 98ac96d8-b424-45fa-83c5-0b2cb9d0fe33

📥 Commits

Reviewing files that changed from the base of the PR and between 9e3221c and 222ad36.

📒 Files selected for processing (11)
  • README.md
  • src/commands/auth-login.ts
  • src/commands/whoami.ts
  • src/dir-config.ts
  • src/hooks/pre-tool-use.ts
  • src/hooks/recall.ts
  • src/hooks/session-start.ts
  • src/shell/deeplake-shell.ts
  • tests/claude-code/auth-login-dispatch.test.ts
  • tests/shared/dir-config-read-routing.test.ts
  • tests/shared/dir-config.test.ts

Comment thread src/commands/whoami.ts
Comment on lines +38 to +48
// Attribute each override precisely: `config` has already folded the env in,
// so a diff against `creds` is the env's doing, and a diff between `eff` and
// `config` is the .hivemind's.
const envMoved = config.orgId !== creds.orgId || config.workspaceId !== storedWs;
const dirMoved = !!res.found &&
(eff.orgId !== config.orgId || eff.workspaceId !== config.workspaceId);

const lines = [
`User org: ${eff.orgName ?? eff.orgId}`,
`Workspace: ${eff.workspaceId}`,
`API: ${eff.apiUrl}`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

An environment-selected org can be printed with the stored org’s name. orgId reflects HIVEMIND_ORG_ID, while orgName can still originate from credentials.

  • src/commands/whoami.ts#L38-L48: display the effective org ID when the environment changed the organization.
  • tests/shared/dir-config-read-routing.test.ts#L144-L149: add a concrete HIVEMIND_ORG_ID assertion.
📍 Affects 2 files
  • src/commands/whoami.ts#L38-L48 (this comment)
  • tests/shared/dir-config-read-routing.test.ts#L144-L149
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands/whoami.ts` around lines 38 - 48, The whoami output can pair an
environment-selected org ID with a stale credential-derived org name. In
src/commands/whoami.ts lines 38-48, update the org display in the lines array to
show the effective org ID whenever the environment changed the organization,
using envMoved while preserving the existing name display otherwise. In
tests/shared/dir-config-read-routing.test.ts lines 144-149, add a concrete
HIVEMIND_ORG_ID assertion covering this behavior.

Comment thread src/hooks/pre-tool-use.ts
Comment on lines +328 to +332
// Reads are routed by the nearest `.hivemind` exactly like capture is: a
// directory pinned to another org/workspace must SEE that workspace's memory,
// not the global one. `collect` is a capture switch and deliberately does not
// gate reads (see src/dir-config.ts).
const config = resolveDirConfig(baseConfig, input.cwd ?? process.cwd()).config;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Directory routing does not isolate the session index cache. The effective identity changes by cwd, but /index.md remains cached only by session.

  • src/hooks/pre-tool-use.ts#L328-L332: namespace cached indexes by session, organization, and workspace.
  • tests/shared/dir-config-read-routing.test.ts#L52-L74: test two routed reads in one session using a stateful cache.
📍 Affects 2 files
  • src/hooks/pre-tool-use.ts#L328-L332 (this comment)
  • tests/shared/dir-config-read-routing.test.ts#L52-L74
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/pre-tool-use.ts` around lines 328 - 332, Namespace the cached index
used by the read-routing flow around resolveDirConfig by session, organization,
and workspace rather than session alone, using the effective identity derived
from the requested cwd. Add coverage in
tests/shared/dir-config-read-routing.test.ts lines 52-74 that performs two
routed reads in one session with a stateful cache and verifies each
organization/workspace receives its own index.

The routing change added an `input.cwd ?? process.cwd()` branch to
recall.ts but no test drove it — recall's routing shipped in the previous
commit asserted only indirectly, and the per-file branch threshold (90%)
caught it at 88.63%.

Record the DeeplakeApi ctor args in the existing mock so a test can
assert WHICH org/workspace recall searched, then cover the routing cases
directly: pinned workspace, org+workspace inherited from an ancestor,
collect:false still routing reads, the unrouted default, and the
process.cwd() fallback when the payload omits cwd.

Branch coverage for recall.ts: 88.63% -> 90.9%.
@khustup2
khustup2 merged commit ec9b152 into main Jul 16, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants