Skip to content

feat(workbuddy): recognize the 5.7+ .workbuddy-ai root and deliver skills there (#1273) - #1290

Merged
SaulMoro merged 14 commits into
Tencent:mainfrom
kittimzhe:feat/workbuddy-new-generation-1273
Oct 26, 2026
Merged

SaulMoro merged 14 commits into
Tencent:mainfrom
kittimzhe:feat/workbuddy-new-generation-1273

Conversation

@kittimzhe

@kittimzhe kittimzhe commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Refs #1273 (Phase 1 — the skills half; the hooks half needs the plugin-route design)

What

WorkBuddy 5.7+ moved its runtime to .workbuddy-ai/ and stops reading .workbuddy/. Before this change, teamai treated a member with only .workbuddy-ai/ as not having WorkBuddy installed. On an upgraded member, where both roots exist, it delivered skills into .workbuddy/skills, which the app no longer scans, and doctor stayed green.

Changes:

  • Skills install gate accepts either root: .workbuddy (≤5.6) or .workbuddy-ai (5.7+) counts as installed for skills. Every other surface keeps requiring .workbuddy/.
  • Skills delivery swaps to the new root whenever .workbuddy-ai/ exists at the delivery base (HOME in user scope, project root in project scope), including when an upgrade left .workbuddy/ behind: the default .workbuddy/skills becomes .workbuddy-ai/skills. Only the default swaps — a team that redirected skills on purpose keeps its own path. Rules, team instructions, agents, MCP servers and hooks keep their .workbuddy/ paths. With only .workbuddy-ai/ they are held and nothing is written under .workbuddy/.
  • Doctor names the held surfaces. On a .workbuddy-ai-only member, doctor fails workbuddy receives rules, team instructions, agents, MCP servers, hooks, naming the .workbuddy/ root they wait for, and exits 1. Before, it printed "All checks passed!" while pull delivered only skills. The post-pull pass prints the same row after each pull. The check comes from the installed gates locate already returns, so it fires for any tool whose skills arrive while another surface's root is missing. Hooks are listed when neither root the hook writer installs into exists, also for a team that maps WorkBuddy to skills and settings only. A member with .workbuddy/ (alone or beside .workbuddy-ai/) gets no new row.
  • Pull says Held N rule(s) only when no tool takes rules. A rules file pull can write counts, and so does a session hook, extension or plugin whose gates are met, so Codex, Pi, Muse, DSH and ZCode in a workspace still print Synced N rule(s), as on main.
  • Docs. docs/guide/sharing.md (both languages) and skill-data/setup/references/manage-admin.md say what a .workbuddy-ai-only member gets. skill-data/core/references/troubleshooting.md no longer sends that member to register hooks by hand.

Verification

Real-CLI record on 495daec (npm run build, then node dist/index.js, sandbox HOME, local bare team remote).

Team with one skill, rule, agent, MCP server and team hook, HOME with only .workbuddy-ai/, init <remote> --scope user --agent workbuddy --provider git --force:

$ teamai pull --force
✔ [user] Synced 1 skills (1 new, 0 updated)
ℹ [user] Held 1 rule(s): no installed tool reads rules in this scope
⚠   ✖ workbuddy receives rules, team instructions, agents, MCP servers, hooks
    → teamai delivers workbuddy's skills to <home>/.workbuddy-ai/skills, but writes its rules, team instructions, agents, MCP servers, hooks only once <home>/.workbuddy exists, and it does not, so a pull holds them back from workbuddy. teamai does not write them where this install reads its skills yet, so there is nothing to fix on this machine.
pull exit 0

$ teamai doctor
  ✖ workbuddy receives rules, team instructions, agents, MCP servers, hooks
doctor exit 1

Team whose toolPaths.workbuddy has only skills and settings, sharing one skill and one hook, same HOME:

$ teamai pull --force
✔ [user] Synced 1 skills (1 new, 0 updated)
ℹ Applying 1 team hook(s):
⚠   ✖ workbuddy receives hooks

$ teamai doctor --json
doctor exit 1, ok: false
  FAIL workbuddy receives hooks

$ find .workbuddy* (in HOME)
.workbuddy-ai/skills/team-skill/SKILL.md
.workbuddy-ai/skills/teamai/SKILL.md

On b32608d the same run printed no receives row, and doctor --json exited 0 with ok: true.

Workspace scope, one team rule, init <remote> --scope workspace --agent codex (and --agent pi), the tool's root in HOME and in the project:

codex: ✔ [workspace] Synced 1 rule(s)    hook-dispatch session-start --tool codex returns "Team rule body"
pi:    ✔ [workspace] Synced 1 rule(s)    hook-dispatch instructions --tool pi returns "Team rule body"

On b32608d both printed ℹ [workspace] Held 1 rule(s): no installed tool reads rules in this scope while delivering the rule. main prints Synced 1 rule(s).

Other runs on the same build:

  • Both roots, user scope (mkdir ~/.workbuddy, then pull --force): Synced 1 rule(s), Synced 1 agents, doctor All checks passed! with no receives row, the same as main.
  • Workspace scope, only .workbuddy-ai/ at the project root: skills land in <project>/.workbuddy-ai/skills, and doctor fails workbuddy receives rules, team instructions, agents, MCP servers naming <project>/.workbuddy. Hooks join the row when ~/.workbuddy is missing too. With ~/.workbuddy present they are written there and are not listed.

The earlier record from this branch still holds (workspace scope, only .workbuddy-ai/: Synced 2 skills (2 new), no .workbuddy/ created). It matches @XiaoWanWH's live 5.7.6 result in the issue (13 team skills visible in the app's / menu after the same redirect).

Unit tests: probe states for old root, new root and both, a bare .codebuddy not counting, the swap firing only for the default path, team redirects kept, project-root resolution, a .workbuddy-ai-only home where a team rule and an MCP server find no target, doctor failing the held-surface check on a .workbuddy-ai-only home (also with only skills and settings mapped, where it names hooks) and staying silent with the old root, and rulesReceivingTools (empty on a .workbuddy-ai-only member, counting a single-file target such as Codex's AGENTS.md, and counting Codex's session hook and Pi's extension in a workspace). The hooks-only doctor test and the two workspace cases fail on b32608d.

npx tsc --noEmit, npm run lint, npx vitest run (577 files, 16472 tests) and npm run test:e2e -- doctor-cli doctor-delivery-cli enabled-agents-whitelist instruction-targets local-agent-rules-993 pass. No tests deleted. Not run: WorkBuddy 5.7.6 itself, Windows, and providers other than git.

The hooks half (not here)

Context injection needs a plugin-route hooks writer (per the issue's evidence: no user-level hooks.json is read on 5.7.6, only plugin-carried ones) — that design depends on the plugin mechanism and the event vocabulary captured in the issue, and I'll bring it as a follow-up once the direction is agreed.

The bundled runtime (PortableGit and Node under .workbuddy-ai/binaries/) is a separate contract from where teamai writes resources — src/bundled-runtime.ts uses neither the probe nor locate — and is tracked as a follow-up, not part of this PR. So is removing the .workbuddy/skills copies a 5.6 install left behind after an upgrade.

@github-actions

Copy link
Copy Markdown
  • [P1 blocking] An upgraded installation retaining the old root still receives skills in the unread directory — src/types.ts:2751. When WorkBuddy 5.7+ has both .workbuddy-ai/ and a leftover .workbuddy/, the old-root check prevents the swap. Default skills continue landing in .workbuddy/skills, which the new runtime ignores. Prefer the new root when it exists.

  • [P1 blocking] User-scope overrides can undo the generation swap — src/types.ts:2761. For a team entry with userScope.skills: '.workbuddy/skills', the helper adjusts the top-level path, but the subsequent user-scope merge restores the old path. With only ~/.workbuddy-ai/ present, user-scope delivery still targets the unread directory. Adjust the effective skills path after scope overrides.

The PR description provides a representative real-CLI verification record; no missing-testing finding applies.

Review limitation: The requested three-dot diff cannot resolve in this shallow checkout, and remote access failed. These findings come from the two WorkBuddy commits ending at the specified head; I cannot certify the complete requested diff. No PR code was run, built, or installed.

@SaulMoro SaulMoro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This was generated by AI during triage.

@kittimzhe Thanks. The branch at da90ceef conflicts with main in src/doctor.ts, src/resources/base.ts and src/types.ts, mostly because of the locate work from #1221. That resolution touches the same delivery and install-probe code this PR changes, so we'll review the rebased head rather than this one. Please rebase onto current main and rerun the real-CLI record on the result.

@SaulMoro SaulMoro left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Adding to the review above, after the rebase:

  • The first P1 from the bot review (both roots present) is the reporter's own machine: the issue says ~/.workbuddy/ is still there with logs, settings.json and skills. So as written this PR does not fix the reported install.
  • The same check may also flip back on a clean 5.7 install. The probe now says WorkBuddy is installed, so if any surface still pointed at .workbuddy/ (user rules, agents, MCP) creates ~/.workbuddy/ on the first pull, the swap stops from the second pull on. I have not run that case. A user-scope record with a team that has rules would show it.
  • [P2 non-blocking] Fixes #1273 closes the issue at merge, while context injection on 5.7.6 still has no surface. Refs #1273 keeps it open for the hooks work.

@SaulMoro
SaulMoro self-requested a review October 22, 2026 12:01
@kittimzhe

Copy link
Copy Markdown
Contributor Author

Both P1s taken, pushed:

  • Leftover old root: the swap no longer requires the old root to be absent — the new root wins whenever it exists, matching the upgraded-install shape from the issue (both roots present, the app reading only .workbuddy-ai). Real-CLI record, dual-root project root: pull --force delivers fixture-skill, teamai into .workbuddy-ai/skills/ and writes nothing into .workbuddy/skills.
  • userScope undo: the swap is now re-applied after the user-scope merge (idempotent), so a userScope.skills carrying the default path no longer restores the unread directory; a userScope redirect of its own is still never stomped (covered by a guard test).

Red-first: three new/changed tests — dual-root preference, swap surviving the default userScope merge, custom userScope redirect untouched.

@github-actions

Copy link
Copy Markdown

No new confident findings in the available WorkBuddy changes.

  • Resolved: New-root detection now prefers .workbuddy-ai even when .workbuddy remains.
  • Resolved: The generation swap runs again after user-scope overrides, preserving the corrected default skills path without overwriting custom redirects.
  • Testing: The PR description includes a representative real-CLI verification record; no missing-testing finding applies.

Review limitation: The requested three-dot diff fails with no merge base in this shallow checkout. I reviewed the three available WorkBuddy commits through c388d93; I cannot certify the complete requested diff. No PR code was run, built, or installed.

@SaulMoro

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

@kittimzhe Thanks, the two fixes in c388d93f cover what my review raised: the new root now wins when both exist, and the swap survives the user-scope merge. Refs #1273 is right too.

Two things before we review it again:

@SaulMoro

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

@kittimzhe Thanks for the update. c388d93f still conflicts with main, now in src/doctor.ts, src/doctor-delivery.ts, src/resources/base.ts, src/types.ts and src/__tests__/doctor-toolpaths-dropped-keys.test.ts. Main caused it: the locate work in #1221, the toolPaths doctor check in #1274 (0d57ac46) and #1234 (2401d047) changed those files after this branch's base d60e68f5. The earlier request stands until there is a rebased head. Please rebase onto current main and rerun the real-CLI record on the result.

@kittimzhe
kittimzhe force-pushed the feat/workbuddy-new-generation-1273 branch from c388d93 to 49ac887 Compare October 25, 2026 09:25
@github-actions

Copy link
Copy Markdown
  • [P1 blocking] Custom skills paths prevent new-root install detection — src/locate.ts:177. With only .workbuddy-ai/ present and skills: 'custom/skills', the path condition leaves newGenerationRoot null, so the install gate probes the absent .workbuddy/. writableDir() consequently returns null, skipping delivery despite WorkBuddy being installed. Detect the generation independently of the skills path; restrict only the path swap to defaults. The custom-path test checks writesOf(), which ignores gates.

Resolved: Both earlier findings are fixed: the new root wins when both remain, and the swap runs after user-scope overrides.

Testing: The description documents a representative real-CLI verification; no missing-testing finding applies.

Limitation: The requested three-dot diff fails with no merge base in this shallow checkout. I reviewed the four available WorkBuddy commits through 49ac887; I cannot certify the complete requested diff. No PR code was run, built, or installed.

@kittimzhe
kittimzhe force-pushed the feat/workbuddy-new-generation-1273 branch from 49ac887 to f427280 Compare October 25, 2026 09:31
@kittimzhe

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (99fd56c) — twice in one sitting, since #1265 (the wider locate migration: rules/blocks/agents/MCP) landed right after the first rebase. The generation swap is now re-homed inside that architecture: the write side lives in locateSkills beside the other skills special cases, the install proof in installedGateOf's own-root case (shared by every resource), and NEW_GENERATION_INSTALL_ROOTS moved to tools.ts beside the tool registry, where base.ts's probe shares it. The old doctor commit (515a18b) is not carried: it is already in main via #1274.

Real-CLI record rerun on the rebased head (same fixture: workspace scope, only .workbuddy-ai/ at the project root): pull --force reports Synced 2 skills (2 new) — fixture-skill, teamai — both land in .workbuddy-ai/skills/, and no .workbuddy/ directory is created. Also added seven locate-level tests against the in-memory Host (mirroring locate-matrix's style): new root alone, both roots (new wins, #1290), old root alone, neither (gate closed), team redirect keeps its path, and both spellings of the default under user scope.

Full suite on the rebased head matches main's baseline here — the four git-discovery/submodule-checkout/workflow-workspace failures reproduce on pristine main in this environment, so they are pre-existing rather than from this branch.

@github-actions

Copy link
Copy Markdown
  • [P2 non-blocking] Generation detection bypasses the supplied host — src/types.ts:2910. scopedToolPaths() now probes the process HOME with fs.existsSync(), even when locate() supplies a different Host. If the process HOME contains .workbuddy-ai but the supplied host has only .workbuddy, user-scope resolution selects <host.home>/.workbuddy-ai/skills while the old-root install gate passes. Keep generation detection host-backed so another machine’s filesystem cannot change the resolved destination.

Resolved: All three earlier findings are fixed: the new root wins when both exist, default user-scope overrides retain the swap, and install detection no longer depends on the skills path.

Testing: The description includes a representative real-CLI verification record; no missing-testing finding applies.

Reviewed the complete requested three-dot diff successfully. No PR code was run, built, or installed.

@SaulMoro SaulMoro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This was generated by AI during triage.

@kittimzhe Thanks for the rebase. The skills half works with the built CLI. With only .workbuddy-ai/, WorkBuddy is detected as installed and skills land in .workbuddy-ai/skills in both user and project scope. A .workbuddy/-only member is unchanged, the new root wins when both exist, a redirected skills path is kept, and uninstall removes the skills from the new root. main has none of this yet. tsc, lint, the 18 new tests (8 fail on the base) and the related WorkBuddy unit and e2e files pass. One thing blocks.

  • [P1 blocking] Opening the install gate makes every other WorkBuddy surface write into .workbuddy/ with doctor green. Reproduced in user scope. HOME has only .workbuddy-ai/, and the team has a skill, a rule and an MCP server. teamai init --scope user --agent workbuddy, then teamai pull --force, exits 0. It prints Synced 1 rule(s) and Updated teamai hooks in ~/.workbuddy/settings.json, and creates .workbuddy/rules/team-rule.md, .workbuddy/settings.json with the Claude-format hooks, and .workbuddy/.mcp.json. doctor then reports ✔ for teamai hooks in workbuddy settings, workbuddy rules are where the last pull wrote them, Rules delivered to workbuddy and MCP servers delivered to workbuddy. On the base, the same member gets nothing written and ✖ workbuddy is installed. That is the false green #1273 reports, and this PR now produces it for 5.7-only members. The body calls these writes "no-ops the app ignores", but only the skills location is confirmed on 5.7.6. Project scope does not show it. Either keep the old-root writers (rules, MCP, hooks, agents) off for a member whose only root is .workbuddy-ai/, so only skills follow the new root, or have doctor stop reporting those surfaces as delivered there.
  • [P2 non-blocking] The issue comment that scoped the first PR asked for the bundled runtime to move with the probe. src/bundled-runtime.ts still looks for PortableGit and Node only under .workbuddy/binaries/ and .workbuddy/bundled/node/. Please add it here or say in the body that it is a follow-up.
  • [P2 non-blocking] After a 5.6 to 5.7 switch, the old .workbuddy/skills copies stay, through the next pull and through uninstall. The pull notice tells the user to delete them, which is acceptable for now.
  • [P2 non-blocking] The new-generation rule is spelled out in four places, plus a one-entry NEW_GENERATION_INSTALL_ROOTS map. One helper that takes the host would keep them from drifting.
  • [P3 nit] The body says nine red-first tests; 8 of the 18 new tests fail on the base. Some test names cite review labels ("#1290 P1"), which will not mean anything once this merges.

Not run: WorkBuddy 5.7.6 itself, so whether it reads .workbuddy/rules or .workbuddy/.mcp.json is unverified; Windows.

The CI review's two [P1 blocking] findings on earlier heads are resolved here; we confirmed both with the built CLI. Its remaining [P2 non-blocking] note (the types.ts probe uses fs.existsSync and ignores the host) is right about the layering, but no CLI path makes it behave differently, so we rate it a nit. All CI jobs pass; the GitHub-provider e2e job is skipped by the fork policy.

@kittimzhe

Copy link
Copy Markdown
Contributor Author

Both P1s are already resolved in the rebased head — I believe the review saw a stale diff (its own limitation notes the three-dot diff could not resolve in the shallow checkout, from only two of the WorkBuddy commits; the reported lines types.ts:2751/2761 sit in the RELOCATABLE_TOOLS block here). P1-1: applyWorkBuddyGeneration has no old-root check — the new root wins whenever it exists (src/types.ts:2898, comment cites #1290), covered by the both-roots test in locate-workbuddy.test.ts. P1-2: the helper is re-applied after the user-scope merge precisely so a userScope.skills default cannot restore the old path (src/types.ts:2950).

On @SaulMoro's wider observation — agreed, and it is the next change I'll bring: the relaxed probe currently activates every surface on a 5.7-only member, but only skills have verified 5.7+ path evidence (the 13-skill / menu check). Plan: keep the skills swap, and make the other surfaces fail closed on 5.7-only (their own-root gate keeps requiring .workbuddy/, so nothing is written to the dead layout and doctor no longer reports it delivered) until each surface's real 5.7+ path is confirmed. Hooks stay parked on the plugin-mechanism answer in the issue.

…#1273)

WorkBuddy 5.7+ moved its runtime to .workbuddy-ai/ and stops reading
.workbuddy/, so a member on the new generation has only the new root
and the install probe reported the tool as not installed — teamai
integrated nothing, while every self-check stayed green. The probe now
accepts either root as install proof, per generation list; which paths
teamai writes for the new generation follows in the write-side change,
blocked on the three questions in the issue (hooks file location,
event vocabulary, old-format compatibility).
WorkBuddy 5.7+ scans skills from .workbuddy-ai/skills and stops reading
.workbuddy/, so on a member whose install left only the new root, skills
landed in a directory the app never looks at. scopedToolPaths now swaps
the default skills path to .workbuddy-ai/skills when only the new root
exists at the delivery base (user HOME or project root, by scope) —
live-verified in the issue: 13 team skills delivered this way showed in
the app's / menu on 5.7.6. Only the default path swaps, so a team that
redirected skills on purpose keeps its own; other surfaces keep their
configured paths (writes into the dead old layout are no-ops).

Real-CLI record (workspace scope, .workbuddy-ai alone at the project
root): pull --force delivers 'fixture-skill, teamai' into
.workbuddy-ai/skills/, and no .workbuddy/ directory is created.
…-scope merge (Tencent#1273)

Two findings from the PR review, both taken:

- An upgraded 5.7+ install typically still has the leftover .workbuddy/
  beside .workbuddy-ai/ (the reporter's machine is exactly that shape),
  so gating the swap on the old root's absence kept delivering skills
  into the directory the new runtime never reads. The new root now wins
  whenever it exists.
- scopedToolPaths applied the swap before the user-scope merge, so a
  userScope.skills carrying the default .workbuddy/skills restored the
  unread old path over the adjusted one. The swap is re-applied after
  the merge (idempotent); a userScope redirect of its own is still never
  stomped.

Real-CLI record, dual-root project root (.workbuddy + .workbuddy-ai):
pull --force still delivers fixture-skill and teamai into
.workbuddy-ai/skills/ and writes nothing into .workbuddy/skills.
…eline (Tencent#1273)

Main's Tencent#1221 moved skills delivery behind locate(), beside the probe
re-homed into the own-root gate and the scopedToolPaths swap. locate now
writes and probes .workbuddy-ai/ when the new root is the live
generation: user scope may already carry the swapped default through
scopedToolPaths, so both spellings count as the default. The constant
moves to tools.ts, the tool registry, where base.ts's probe shares it.

Real-CLI record rerun on the rebased head (workspace scope, only
.workbuddy-ai/ at the project root): pull --force reports Synced 2
skills (2 new) — fixture-skill, teamai — both in .workbuddy-ai/skills/,
no .workbuddy/ created.
@SaulMoro

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

@kittimzhe Agreed on the two CI-review P1s: our review already lists both as resolved at f427280, checked with the built CLI (both roots present, and the user-scope override keeping the swap). The one blocking point from us is the wider one, and your plan covers it. Keep the skills swap, and let rules, MCP, hooks and agents keep requiring .workbuddy/ on a 5.7-only member, so nothing is written to the old layout and doctor stops reporting those surfaces as delivered. When you push it, please add a test with a team rule and an MCP server on a .workbuddy-ai/-only home that asserts no .workbuddy/ is created. We will re-review that head. The bundled-runtime note (PortableGit and Node under .workbuddy-ai/binaries/) is still open, here or as the follow-up you prefer.

…encent#1290)

The relaxed install probe activated every surface on a WorkBuddy 5.7-only
member, but only skills have verified 5.7+ delivery evidence (the 13-skill
`/` menu check in Tencent#1273) — rules, MCP, agents, blocks and hooks were being
written into the dead `.workbuddy/` layout with doctor reporting them
delivered.

Scope the new root to the surface that earned it: `installedGateOf` now
takes the resource, and only `locateSkills` passes `'skills'`, so every
other locate surface keeps requiring `.workbuddy/` and skips a 5.7-only
member until its real 5.7+ path is confirmed. `isToolInstalledForConfig`
goes back to the strict root (its consumers are the non-skills surfaces:
doctor's enabled-tool probe, uninstall's shared-path protection,
known-agents), and `NEW_GENERATION_INSTALL_ROOTS` retires with it.

A pull whose rules found no writable target now says so instead of
counting rules no tool took (`Held N rule(s): no installed tool reads
rules in this scope`) — the same reported-success-received-nothing the
codebase's own doctor comment warns about.

Verification: full suite 16388 passed, 6 failures baseline-verified on
current main (git-discovery, submodule-checkout x2, workflow-workspace,
gh-deadline, and the new workflow-place one from Tencent#1381; the lease-timeout
flake passes isolated). Includes the reviewer-requested test: a team
rule and an MCP server on a `.workbuddy-ai`-only home (user scope, the
full default entry) find no writable target, so nothing creates
`.workbuddy/`, while skills still take the new root. Real CLI matches:
5.7-only project with a team rule and an MCP server — skills synced to
`.workbuddy-ai/skills`, rules held with nothing written, no `.workbuddy/`
or MCP file created; old root present: rules delivered to
`.codebuddy/rules` with frontmatter.
@kittimzhe
kittimzhe force-pushed the feat/workbuddy-new-generation-1273 branch from f427280 to 651693b Compare October 26, 2026 07:52
@kittimzhe

Copy link
Copy Markdown
Contributor Author

Pushed at 651693b (rebased onto current main first). The requested test is in locate-workbuddy.test.ts: a team rule and an MCP server on a .workbuddy-ai-only home — the full default entry in user scope, so every surface is configured — assert that rules and MCP find no writable target (installed gate probing the old root unmet, writable(...) === null for both), so nothing ever creates .workbuddy/, while skills still take the new root on the same member. The real CLI matches: with a team rule and an MCP server declared, a 5.7-only member syncs skills to .workbuddy-ai/skills, holds the rule with nothing written, and creates no .workbuddy/ or MCP file.

The bundled-runtime note (PortableGit and Node under .workbuddy-ai/binaries/) I'd like to keep as the follow-up — it is a separate contract from where teamai writes resources, and this PR should stay the probe/gate semantics. Happy to take it next once this head lands.

@github-actions

Copy link
Copy Markdown
  • [P2 non-blocking] Inline rule delivery is incorrectly reported as held — src/resources/rules.ts:1393. In a user-scope installation with only Codex selected, pullAllRules() writes rules into ~/.codex/AGENTS.md, but writableRulesTools() excludes file-based destinations. Pull consequently reports “Held … no installed tool reads rules” after successful delivery. Include writable inline-rule destinations in this check.

  • [P2 non-blocking] Generation detection still bypasses the supplied host — src/types.ts:2931. If the process HOME contains .workbuddy-ai but the supplied host contains only .workbuddy, user-scope resolution selects <host.home>/.workbuddy-ai/skills while the old-root install gate passes. Use host-backed generation detection; the earlier finding remains unresolved.

Resolved: The three earlier blockers are fixed: new-root preference, swapping after user-scope overrides, and install detection independent of custom skills paths.

Testing: The description includes a representative real-CLI verification record; no missing-testing finding applies.

Limitation: The requested three-dot diff fails with no merge base in this shallow checkout. I reviewed the five available WorkBuddy commits through 651693b2; I cannot certify the complete requested diff. No PR code was run, built, or installed.

@SaulMoro

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

@kittimzhe Thanks, the plan works. On a member with only .workbuddy-ai/, in both user and project scope, the built CLI puts skills in .workbuddy-ai/skills and creates no .workbuddy/, .mcp.json, settings.json or agents file. Doctor no longer reports those surfaces as delivered. Members with only .workbuddy/ get the same files as on main. Two things block merge, both small:

  • [P1 blocking] Lint & Test is red on all six jobs. npx tsc --noEmit fails on the new test: src/__tests__/locate-workbuddy.test.ts(137,23): error TS2345: Argument of type 'Location<"mcp" | "rules">' is not assignable to parameter of type 'Located<EntryPlace>'. The for (const resource of ['rules', 'mcp'] as const) loop passes a union to writable(). Two explicit locate calls, one for rules and one for mcp, pass tsc and keep all 11 tests green. npm run lint doesn't type-check test files, which is likely why it passed locally.
  • [P1 blocking] A working Codex pull now prints a false "Held". In user scope with init --agent codex and one team rule, this head prints Held 1 rule(s): no installed tool reads rules in this scope, yet ~/.codex/AGENTS.md gets the rule. main prints Synced 1 rule(s) for the same run. writableRulesTools in src/resources/rules.ts requires rulesDirOf(location) !== null, which is null for a single-file target like Codex's AGENTS.md. Keeping only writable(location) !== null brings back Synced 1 rule(s) with the same write. Please also run that change on the 5.7-only gate.
  • [P2 non-blocking] A 5.7-only member isn't told what was skipped. Pull prints Held 1 rule(s) but says nothing about MCP servers, agents or hooks, and doctor is green with no row for them. One line per skipped surface, naming the .workbuddy/ root it waits for, would tell the member why their team MCP servers and agents are missing. Pull or doctor would both work.
  • [P2 non-blocking] The body is behind this head. It still says "Nine red-first unit tests". It also says writes into the old layout "are no-ops the app ignores", which isn't verified for the reporter's setup with both roots, where rules, agents, .mcp.json and settings.json are still written under .workbuddy/. Please drop or verify that sentence, and say that the bundled-runtime change is a follow-up.

Agreed that the bundled runtime is a separate contract: src/bundled-runtime.ts doesn't use the probe or locate. We'll track it separately. CI fails only on Lint & Test. The CI review missed the tsc failure and rated the Codex message P2. We rate it P1 because it's a regression in this PR's own output, on a tool that works on main.

Review follow-up: `writableRulesTools` also required a rules directory,
so a pull whose only rules target was a single file — Codex's user-scope
`AGENTS.md` — printed 'Held N rule(s): no installed tool reads rules in
this scope' while writing the rule, a regression against main in this
PR's own output. Only `writable` decides now; directory and single-file
targets report alike.

Also splits the reviewer-requested test's loop into two explicit
`locate` calls: `writable()` narrows by resource, so a union-typed
`Location<'mcp' | 'rules'>` did not pass tsc (CI's Lint & Test caught
what `npm run lint`, which skips test files, could not).

Verified end to end on both gates: user scope with codex installed and
one team rule prints 'Synced 1 rule(s)' and lands the rule in
`~/.codex/AGENTS.md`; the 5.7-only workbuddy member still prints
'Held 1 rule(s)' with nothing written and no `.workbuddy/` created.
@kittimzhe

Copy link
Copy Markdown
Contributor Author

Both P1s are fixed at 268c782:

  • tsc: the loop is two explicit locate calls now. My local check had piped tsc through head and read the pipe's exit code — the error was there and I reported a clean run; CI was right and I've stopped trusting my own pipeline for gates.
  • False "Held": writableRulesTools keeps only writable(location) !== null. Verified on both ends with the built CLI: user scope with codex installed and one team rule prints Synced 1 rule(s) and lands the rule in ~/.codex/AGENTS.md; the .workbuddy-ai-only member still prints Held 1 rule(s) with nothing written and no .workbuddy/ created.

The body is updated: the "no-ops the app ignores" sentence is dropped (it was not verified for the both-roots setup, where the old layout is still live), the test list reflects the current set, and the bundled runtime is stated as a follow-up. The skipped-surface hint I'd also leave for a follow-up — it touches the mcp/agents/hooks branches of pull and this PR is already carrying the probe semantics.

@github-actions

Copy link
Copy Markdown
  • [P2 non-blocking] Generation detection still bypasses the supplied host — src/types.ts:2931. If the process HOME contains .workbuddy-ai but the supplied Host contains only .workbuddy, scopedToolPaths() selects <host.home>/.workbuddy-ai/skills while the old-root install gate passes. Skills then target the wrong generation. Use host-backed detection; this earlier finding remains unresolved.

Resolved: All three earlier blockers are fixed: new-root preference, swapping after user-scope overrides, and install detection independent of custom skills paths. The inline-rule reporting finding is also fixed: writableRulesTools() now accepts single-file destinations.

Testing: The description documents a representative real-CLI verification; no missing-testing finding applies.

Limitation: The requested three-dot diff fails with no merge base in this shallow checkout. I reviewed the six available WorkBuddy commits through 268c782; I cannot certify the complete requested diff. No PR code was run, built, or installed.

@SaulMoro

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

@kittimzhe Both blockers are fixed at 268c782. tsc passes and so do the PR's tests. A Codex user-scope pull prints Synced 1 rule(s) and writes ~/.codex/AGENTS.md. A .workbuddy-ai-only member still holds rules and gets nothing under .workbuddy/. The full unit suite passes. With the built CLI, Pi, JoyCode and Hermes also write their rules file whenever pull reports Synced, so dropping rulesDirOf didn't create the reverse problem.

I need to revisit one point. Last round I rated it non-blocking, and this round's run changes that:

  • [P1 blocking] On a .workbuddy-ai-only member, doctor now passes while MCP, agents and hooks are not delivered. With a team MCP server, agent and hook declared, pull prints only Held 1 rule(s), and doctor exits 0 with "All checks passed!", with no row for those surfaces. On main the same member fails doctor (✖ workbuddy is installed). The message is wrong, but it's visible. So this PR turns a visible failure into a silent pass, which is the false green [bug] WorkBuddy 5.7.6 的配置已迁移到 ~/.workbuddy-ai(且 hooks 为 Codex 风格),teamai 写入 ~/.workbuddy 的 hooks 永远不会被执行 #1273 is about. The gate that holds these surfaces is new in this PR (the own-root branch in locate.ts), so its explanation belongs here too. One doctor note or pull line per held surface, naming the .workbuddy/ root it waits for, would close it. Sorry for not weighing it this way last round.
  • [P2 non-blocking] The body lists a unit test for the single-file Synced case, but no test covers writableRulesTools. Please add one, which keeps the false Held from coming back, or drop the line.
  • [P3 nit] The comment at src/types.ts:2912-2917 still says writes into the old layout "are no-ops the app ignores". On a member with both roots, rules, MCP, hooks and agents are still written there. The test names in workbuddy-generation.test.ts end in (#1290 P1), a review label rather than a behavior.

The bundled runtime and the leftover .workbuddy/skills copies stay as agreed follow-ups.

…et (Tencent#1273)

On a member whose only WorkBuddy root is .workbuddy-ai/, skills arrive
there, while rules, team instructions, agents, MCP servers and hooks
still need .workbuddy/, so pull writes none of them. `workbuddy is
installed` passes on the skills root and the delivery checks skip the
gated surfaces, so doctor reported "All checks passed!".

Doctor now fails one check per tool and missing root, naming the held
surfaces and the root they wait for. The post-pull pass prints the same
row after every pull.
…encent#1290)

Pin that a single-file rules target such as Codex's AGENTS.md counts as
writable, so pull does not report "Held" for rules it wrote, and that a
.workbuddy-ai-only member has no rules target.

Correct the applyWorkBuddyGeneration comment, which still called writes
under .workbuddy/ no-ops, move the helper above scopedToolPaths' own
docblock, and drop review labels from test names.
@github-actions

Copy link
Copy Markdown
  • [P2 non-blocking] Generation detection still bypasses the supplied host — src/types.ts:2912. If the process HOME contains .workbuddy-ai but the supplied Host contains only .workbuddy, scopedToolPaths() selects <host.home>/.workbuddy-ai/skills while the old-root install gate passes. Skills therefore target the wrong generation. Use host-backed detection; this earlier finding remains unresolved.

Resolved: All three earlier blockers are fixed: new-root preference, swapping after user-scope overrides, and install detection independent of custom skills paths. Inline-rule reporting is also fixed: writableRulesTools() accepts single-file destinations.

Testing: The PR description documents a representative real-CLI verification; no missing-testing finding applies.

Reviewed the complete requested three-dot diff successfully. No PR code was run, built, or installed.

…ped (Tencent#1273)

The hooks row was added only to a root another held surface had already
created. A team that maps WorkBuddy to skills and settings alone left the
map empty, so on a member with only `.workbuddy-ai/` doctor passed while
no hook was written. Record every missing root the other surfaces wait
for, configured or not, and hold hooks when neither of the hook writer's
install roots exists.
…encent#1290)

In a workspace, Codex, Pi, Muse, DSH and ZCode take rules through
teamai's session hook or extension, which writes no rules file, so pull
printed "Held ... no installed tool reads rules" while the rules were
delivered. A run-time rules channel whose gates are met now counts as a
receiver. The helper is renamed to rulesReceivingTools to match.
…ent#1273)

Skills move to `.workbuddy-ai/skills`; every other surface waits for
`.workbuddy/`, and doctor names the held ones. The troubleshooting note no
longer sends that member to register hooks by hand.
@github-actions

Copy link
Copy Markdown
  • [P2 non-blocking] Generation detection still bypasses the supplied host — src/types.ts:2912. When process HOME contains .workbuddy-ai but the supplied Host contains only .workbuddy, scopedToolPaths() selects <host.home>/.workbuddy-ai/skills while the old-root install gate passes. Skills target the wrong generation. Use host-backed detection; this earlier finding remains unresolved.

Resolved: New-root preference, swapping after user-scope overrides, install detection independent of custom skills paths, and inline-rule reporting are fixed. No other confident findings.

Testing: The description includes a representative real-CLI verification record; no missing-testing finding applies. Its older commit reference is not blocking.

Reviewed the complete requested three-dot diff. No PR code was run, built, or installed.

@SaulMoro SaulMoro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @kittimzhe. I pushed the remaining fixes on top: doctor now names the surfaces a .workbuddy-ai-only member does not receive (hooks included, even when the team maps nothing else), workspace rules delivered through a session hook or extension count as synced again as on main, and the sharing, admin and troubleshooting docs say what the new root gets. writableRulesTools is now rulesReceivingTools with its own tests. CI is green at 495daec. The bundled runtime and the leftover .workbuddy/skills copies stay as follow-ups.

@SaulMoro
SaulMoro merged commit 79074f1 into Tencent:main Oct 26, 2026
18 checks passed
jeff-r2026 pushed a commit that referenced this pull request Oct 27, 2026
…) (#1404)

* feat(sessions): resolve each tool's session store through locate (#1221)

Each TOOLS entry now declares its session platforms, and each platform
declares its store and resume command in SESSION_PLATFORM_FACTS.
locate(tool, 'sessions') and the session adapters resolve the store in one
place, sessionStoreDir, so a store follows the tool's recorded root or home.

CodeBuddy sessions now follow a moved home (CODEBUDDY_CONFIG_DIR, or a
recorded one) instead of always ~/.codebuddy.

* fix(sessions): locate and the adapters put a default session store under the same profile home (#1221)

* refactor(sessions): drop the adapters' uncalled isAvailable and getDefaultStoragePath statics (#1221)

* test(locate): give the WorkBuddy test host a profile home (#1221)

#1290 added an in-memory Host before Host gained profileHome.
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.

3 participants