Skip to content

fix(skillify): route push/pull through .hivemind, not the global workspace#317

Closed
khustup2 wants to merge 1 commit into
mainfrom
fix/skillify-route-dir-config
Closed

fix(skillify): route push/pull through .hivemind, not the global workspace#317
khustup2 wants to merge 1 commit into
mainfrom
fix/skillify-route-dir-config

Conversation

@khustup2

@khustup2 khustup2 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

What DevOps hit

Artyom set up a directory with a .hivemind config, but saving a skill from it wrote to the global workspace, not the routed one. His words in #devops:

saved a local skill to deeplake, skill got appeared in default workspace

That test happens to exercise the one writer that never got routed.

Root cause

src/commands/skillify.ts read loadConfig() raw at the push and pull sites and passed the global workspaceId straight to DeeplakeApi — no resolveDirConfig. Session capture, session-end summaries, and graph push all route through .hivemind already; skillify was a straggler nobody threaded. The DeeplakeApi constructor puts the workspace in the URL path (/workspaces/{workspaceId}/tables/query), so that argument decides where the row lands — and it was always the global one.

To be clear about scope: regular session capture routes correctly (traced end-to-end: resolveCaptureConfigworkspaceId → URL path → write). Artyom's complaint was phrased about sessions but the only thing he tested was skillify, which is the single broken path. This PR fixes that path.

The fix

Resolve the nearest .hivemind at both the push and pull sites, so skills write to — and read from — the directory's routed workspace, symmetric with where that tree's traces are captured.

  • orgId/workspaceId are identity → apply to reads and writes.
  • collect:false gates capture only, so a routed + opted-out directory still pushes/pulls to its workspace.
  • unpull is untouched — it's a local-filesystem operation that never queries a workspace (only reads userName for --not-mine).

Test

tests/claude-code/skillify-dir-routing.test.ts runs resolveDirConfig for real against the process cwd and asserts which workspace DeeplakeApi was constructed against — the URL path that decides where the write goes. Covers push + pull, ancestor inheritance, collect:false still routing, and the no-.hivemind global fallback. Verified to fail against the pre-fix code (the 4 routing assertions fail; the 2 global-fallback cases pass in both, as they should).

Verification

  • Typecheck clean.
  • All skillify suites green; full suite has no new failures (the 14 pre-existing failures are the tree-sitter-python-missing graph suites + the flush-memory network timeout, all unrelated).
  • No coverage threshold on skillify.ts; coverage run clean.

Still open (not in this PR)

The rules/goals CLI writers use the same loadConfig()-raw pattern and will behave identically — nobody's tested them yet, but they're the next straggler. Happy to fold them into a follow-up.

🤖 Generated with Claude Code

https://claude.ai/code/session_017SDmiDuUn7Wqhi7qdn1p1f

Summary by CodeRabbit

  • Bug Fixes
    • skillify push and skillify pull now honor the nearest .hivemind workspace configuration.
    • Commands correctly inherit workspace settings from parent directories.
    • Added fallback to the global workspace when no directory-specific configuration is available.
    • Improved handling of collect:false while preserving the selected workspace.

…space

`hivemind skillify push` read `loadConfig()` raw and passed the global
`workspaceId` straight to the API, so a skill saved from a directory
routed by `.hivemind` landed in the GLOBAL workspace — the exact symptom
DevOps reported ("saved a local skill, it showed up in the default
workspace"). Session capture already routes via resolveDirConfig; skillify
was a straggler that never got threaded.

Resolve the nearest `.hivemind` at both the push and pull sites so skills
write to, and read from, the directory's routed workspace — symmetric with
where that tree's traces are captured. org/workspace are identity and apply
to reads and writes alike; `collect:false` gates capture only, so a
routed+opted-out directory still pushes/pulls to its workspace.

unpull is untouched: it is a local-filesystem operation that never queries a
workspace (it only reads userName for --not-mine).

The DeeplakeApi ctor puts the workspace in the URL path
(/workspaces/{workspaceId}/tables/query), so that arg is where the write
lands; the new test asserts on it with resolveDirConfig running for real.
Verified to fail against the pre-fix code.
@coderabbitai

coderabbitai Bot commented Jul 17, 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: 214f54c5-f254-4b42-96b3-8af0ee33d42e

📥 Commits

Reviewing files that changed from the base of the PR and between 0f1d412 and 60bb489.

📒 Files selected for processing (2)
  • src/commands/skillify.ts
  • tests/claude-code/skillify-dir-routing.test.ts

📝 Walkthrough

Walkthrough

skillify pull and skillify push now resolve Deeplake settings from the nearest applicable .hivemind configuration. Tests cover local and inherited workspace routing, collect:false, and fallback to the global workspace.

Changes

Skillify workspace routing

Layer / File(s) Summary
Directory-scoped configuration resolution
src/commands/skillify.ts
pull and push validate the loaded base configuration, then use resolveDirConfig with the current directory to select the effective Deeplake workspace.
Routing behavior coverage
tests/claude-code/skillify-dir-routing.test.ts
Tests verify local and ancestor .hivemind routing, collect:false, and global-workspace fallback for both commands.

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

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Skillify
  participant resolveDirConfig
  participant DeeplakeApi
  User->>Skillify: run pull or push
  Skillify->>resolveDirConfig: resolve config for current directory
  resolveDirConfig-->>Skillify: routed or global workspace
  Skillify->>DeeplakeApi: read or write skills
Loading

Possibly related PRs

Suggested reviewers: efenocchi

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the skillify push/pull routing fix and matches the change set.
Description check ✅ Passed It covers the bug, root cause, fix, and tests, but doesn't follow the template's Summary, Version Bump, and Test plan sections.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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/skillify-route-dir-config

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

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 88.64% (🎯 90%) 195 / 220
🟢 Statements 90.38% (🎯 90%) 235 / 260
🟢 Functions 96.30% (🎯 90%) 26 / 27
🔴 Branches 82.61% (🎯 90%) 171 / 207
File Coverage — 1 file changed
File Stmts Branches Functions Lines
src/commands/skillify.ts 🟢 90.4% 🔴 82.6% 🟢 96.3% 🔴 88.6%

Generated for commit 3d0059f.

@khustup2

Copy link
Copy Markdown
Contributor Author

Superseded by #318, which folds this skillify fix into a single-source-of-truth refactor (one loadRoutedConfig entry point + a guard that prevents the whole class of unrouted-writer bugs).

@khustup2 khustup2 closed this Jul 17, 2026
pull Bot pushed a commit to danielabelski/hivemind that referenced this pull request Jul 17, 2026
`.hivemind` routing was wired writer-by-writer, so every new path that built
a DeeplakeApi from a raw loadConfig() silently used the GLOBAL workspace
instead of the directory's routed one. Skillify was the latest to bite
(DevOps: "saved a skill, it landed in the default workspace"); goals, rules,
and the Codex/Cursor/Hermes memory hooks had the identical latent bug.

Introduce ONE entry point — loadRoutedConfig(cwd) in dir-config.ts — that
folds the nearest .hivemind (and the HIVEMIND_* env locks, via
resolveDirConfig) in one place, and migrate every workspace-touching site to
it:

  - CLI writers/readers: goal, rules, context, skillify (push/pull),
    flush-memory
  - other-agent memory hooks: codex/cursor/hermes pre-tool-use
  - session-start-setup, skillify auto-pull + skillopt-worker
  - mcp/server, graph deeplake-pull (symmetric with the already-routed push)

A guard test (dir-config-single-source.test.ts) enumerates every
`new DeeplakeApi(` site and fails the build unless it routes or is
allow-listed with a reason — so an unrouted writer can no longer be added
silently. Five sites are allow-listed (session-prune, docs, cowork-ingest,
and the creds-based banner/resume-brief reads) each with a documented reason.

This supersedes and folds in PR activeloopai#317 (skillify-only fix).

Deliberately NOT routed, tracked as follow-up: the notification reads
(resume-brief, open-goals) build from creds.workspaceId and need a resolved
workspace threaded in — a different change from a loadConfig swap; and docs,
which use a separate per-(org,repo) consent model.

Verified: loadRoutedConfig routes end-to-end (skillify push/pull behavioral
test, fails against unrouted code); the guard catches a reverted file;
typecheck clean; no new suite failures; touched files clear their coverage
gates.
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.

1 participant