Skip to content

fix(rules): use native formats and scope-specific delivery - #957

Open
SaulMoro wants to merge 18 commits into
Tencent:mainfrom
SaulMoro:fix/946-rules-delivery
Open

SaulMoro wants to merge 18 commits into
Tencent:mainfrom
SaulMoro:fix/946-rules-delivery

Conversation

@SaulMoro

@SaulMoro SaulMoro commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Team rules
├─ Native files     → Kiro, Qoder/CN, CodeBuddy/WorkBuddy, OMP, JoyCode project
├─ User-scope files → Codex, ZCode, dsh, Pi, JoyCode, Hermes, OpenClaw
├─ Project context  → Codex/ZCode/dsh session hooks; Pi extension
└─ Upgrade pulls    → repair formats, retire unchanged copies, preserve edits

Deliver rules through the files and formats each tool reads. Fix OpenCode namespace globs, OpenClaw event dispatch and hook activation, and diagnostics for missing delivery channels. Push and uninstall respect recorded ownership, flat names and shared files. Scoped inline rules retain Applies to files matching: <globs> as model guidance; the tool does not enforce file filtering.

README capability changes

All five README variants contain the same changes:

Agent Capability Before After
Codex rules ✓ ✓*
OpenCode rules ✓ ✓*
Pi Coding Agent rules ✓ ✓*
Hermes rules — ✓*
OpenClaw rules ✓ ✓*
DeepSeek Harness rules — ✓*
ZCode rules — ✓*

✓* identifies always-on rules without tool-enforced path scoping. Hermes and OpenClaw use their normal user-scope channel. OpenClaw's previous check counted rule files it did not read.

New JoyCode row After
skills, rules, docs, env, agents, learnings, codebase, teamwiki ✓
hooks, mcp, models, usage, sessions, dashboard —

JoyCode scopes project rules natively; its user rules.txt block is always on.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature causing existing behavior to change)
  • Documentation only
  • Refactor / internal cleanup

Test Plan

Current rebased tree, head 591dc5eb, based on main at 6c5949f8:

  • npx tsc --noEmit
  • npm run lint
  • npm run build
  • npx vitest run --maxWorkers=4: 7,965 passed, 20 skipped
  • npx vitest run src/__tests__/init.test.ts src/__tests__/doctor.test.ts src/__tests__/hooks-cmd.test.ts --maxWorkers=4: 153 passed
  • npx vitest run --config vitest.e2e.config.ts src/__tests__/e2e/hooks-project-isolation-issue373.test.ts src/__tests__/e2e/doctor-delivery-cli.test.ts: 14 passed after build. Covers shared main-checkout Claude/Codex hooks, project isolation and CLI delivery diagnostics.
  • Compiled real CLI with git provider and isolated HOME, recorded below
  • Regressions cover full/unchanged pulls, edited and undelivered flat files, deleted OpenCode namespaces, shared ownership, push, uninstall, Hermes cleanup and tolerant glob parsing

The full E2E suite was not rerun, preserving the requested waiver. Its previously recorded run had 492 passed and 26 skipped at f87b4d78. The final commit changes only the init test; the built runtime and real-CLI runs use the same runtime tree as the current head.

Evidence

Real CLI after build, git provider, isolated HOME, Kiro/OMP/Pi in user scope:

# rules/fe/style.md has unquoted paths: **/*.ts
# rules/.removed contains fe.style, the flat name of the live namespaced rule
$ teamai pull
✔ [user] Synced 1 rule(s)
$ teamai pull
✔ [user] Already synced at 7597c56, skipping

Both Kiro and OMP fe.style.md copies retain the live rule after both pulls. Pi AGENTS.md contains Applies to files matching: **/*.ts; neither pull prints a frontmatter parse error. Before the fixes, the root tombstone could delete the flat copy and strict YAML parsing dropped the inline scope hint.

A second project-only HOME with Hermes/Claude and an obsolete managed block in global SOUL.md:

$ teamai pull
ℹ Removed the team rules an older project pull wrote to <sandbox>/home-project/.hermes/SOUL.md: Hermes gets no project rules
✔ [project] Synced 1 rule(s)

The obsolete block is absent and personal SOUL.md text remains. Previously the project-only install left the global rules behind. These runs exercise CLI delivery and migration; they do not launch those host applications.

Related Issues

Fixes #946.

Dependencies #952 and #958 are merged. The branch is rebased onto origin/main; their implementation is outside this PR's diff. Conflict resolutions retain #958 automatic Codex trust, main-checkout hook sharing and doctor trust queries alongside #946 delivery notes. The init regression now checks automatic trust reporting without an unconditional manual-trust warning. English/Chinese guides retain both changes.

Notes for Reviewers

Reviewed the whole branch inventory and runtime changes against origin/main, and compared all 17 original commits with git range-diff. The rebase preserves the previous rule ownership fixes and main's read-only votes aggregation from #968. Bilingual guides, design docs and affected skill-data references are updated.

Merge danger

Door: Two-way for code. Migration removes only proven, unchanged team copies and preserves member edits; restoring a legacy layout requires a compatible release and pull. The existing data-directory migration does not support downgrades.

Blast radius: Rules, instruction files, hook configuration and diagnostics across tools.

Earlier verification and retained limits
  • Previously recorded: 54 parser/render checks with Cursor 2026.09.22, CodeBuddy 2.160.0, JoyCode 3.8.71 and OMP 18.2.1; mock-model runs with OMP/OpenCode, Pi across two turns, and OpenClaw startup/new/reset in a live gateway. These were not repeated for this rebase.
  • Only OMP parser tests run in CI. Other extracted parsers require TEAMAI_RULE_PARSER_BUNDLES; they are among the current skips.
  • Kiro CLI ignores path scoping. OMP reads project rules only at the root. Copilot CLI ≥1.0.89 also reads Claude rules; OMP can read namespaced Copilot rules twice.
  • A WorkBuddy-only project creates .codebuddy, which makes CodeBuddy count as installed.
  • ZCode/dsh lose hook text at compaction; dsh requires --patch and may miss the first request. Codex automatic hook trust comes from fix(hooks): trust Codex hooks and share project hooks across worktrees #958, with manual fallback when disabled or unsuccessful.
  • OpenClaw message/auto-reset mappings have fixture coverage only. Qoder Desktop/CN subdirectory discovery remains an accepted assumption.
  • Kiro, Qoder/CN, CodeBuddy, WorkBuddy, JoyCode, ZCode, dsh, Hermes and Cursor IDE were not run live. Additional providers remain with CI.
  • Excluded work: ZCode's 32 KB hook-output cap and dsh skills ignoring DSH_HOME.

@SaulMoro
SaulMoro marked this pull request as draft October 2, 2026 00:08
@jeff-r2026 jeff-r2026 self-assigned this Oct 2, 2026
@SaulMoro
SaulMoro force-pushed the fix/946-rules-delivery branch from b9e9378 to daf0817 Compare October 2, 2026 05:21
@SaulMoro SaulMoro changed the title [After #947, #952] fix(rules): deliver team rules through each tool's own channel [After #952] fix(rules): deliver team rules through each tool's own channel Oct 2, 2026
@SaulMoro
SaulMoro force-pushed the fix/946-rules-delivery branch from daf0817 to f87b4d7 Compare October 3, 2026 06:33
@SaulMoro SaulMoro changed the title [After #952] fix(rules): deliver team rules through each tool's own channel fix(rules): deliver team rules through each tool's own channel Oct 3, 2026
@SaulMoro
SaulMoro marked this pull request as ready for review October 3, 2026 06:33
@jeff-r2026

Copy link
Copy Markdown
Collaborator

This branch has merge conflicts with main. Please rebase onto the latest main and resolve the conflicts so review can continue.

@SaulMoro
SaulMoro force-pushed the fix/946-rules-delivery branch from f87b4d7 to 2c70f26 Compare October 3, 2026 07:04
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
  • [P1 blocking] Preserve edited OMP copies during uninstall — src/resources/rules.ts:644 treats any delivery record as proof that the current flat file is owned. If a member edits a delivered fe.style.md and runs teamai uninstall, ownedFlatCopies() schedules it for unconditional deletion, losing the edit. Require the current hash to match the recorded hash, as other uninstall cleanup does.
  • [P1 blocking] Reclaim globs for deleted OpenCode namespaces — src/resources/opencode-config.ts:112 recognizes namespace globs only from currently desired or currently existing team-rule directories. When the last fe/* rule is deleted or renamed, the previously generated absolute .../rules/fe/*.md entry is no longer considered owned, so pull and doctor leave it in opencode.json. An edited copy preserved in that directory therefore remains loaded after the team stops delivering it.

@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown

Findings

  • [P1 blocking] Preserve a personal flat-name file before deleting supersedes — src/resources/rules.ts:436. With a placement record mapping style to rules/fe/style.md, Kiro/OMP deliver the author’s copy as style.md and set supersedes to fe.style.md. If the member independently created fe.style.md, every pull deletes it without checking the delivery ledger or rendered content. Apply the same ownership/edit verification used for movedFrom before removal.
  • [P1 blocking] Use the tolerant parser when generating inline rule hints — src/resources/rules.ts:1388. inlinedRulesText() uses splitFrontmatter(), while the new native renderers use teamRuleData() specifically to support common unquoted globs such as paths: **/*.ts. For that input, inline channels receive the body without the promised Applies to files matching hint, causing Codex/ZCode/DSH/Pi/Hermes/OpenClaw to treat a scoped rule as globally applicable.

Resolved

  • The earlier OMP uninstall finding is fixed by verifying the recorded hash or rendered content.
  • The earlier OpenCode deleted-namespace glob finding is fixed by considering namespaces from previously pulled revisions.
  • The PR description includes a representative real-CLI verification at head 2428b2cf, so its testing record is sufficient.

@SaulMoro
SaulMoro force-pushed the fix/946-rules-delivery branch from 2474643 to 0ca60db Compare October 3, 2026 10:28
…ets (Tencent#946)

- Keep OpenClaw's default workspace AGENTS.md out of the retired files: its
  default profile still reads it.
- Strip a retired file of a tool with no file and no hook in this scope
  (OpenClaw in a project) without waiting for a replacement.
- Keep doctor's Pi extension check while the project has team rules, even
  with no instruction blocks.
- Adapt the Tencent#945 every-shape test to OpenClaw's workspace install probe and
  its lack of a project file; drop the Tencent#946 uninstall test Tencent#945's recorded
  entry ownership superseded.
- Hold back a hook tool's retired instruction file while its hook is not
  installed; only a tool with no project channel (OpenClaw) releases it.
- Mark Hermes and OpenClaw rules always on (✓*) in every README.
- Pin that a project uninstall keeps a .opencode/opencode.json left with
  only $schema once the recorded instructions entry goes.
- Resolve the team rules once for doctor's hook checks; use one
  RulesHandler in the uninstall plan; return early from ruleChannelNotes
  outside a project; name only the files a project pull touches when the
  team rules cannot be resolved; drop a stray CHANGELOG period.
…namespace globs (Tencent#946)

- A flat copy on record is teamai's only while it holds what was recorded
  or the render; remove and uninstall keep and name an edited one.
- OpenCode's user rules globs own every namespace directory a rule landed
  in at a revision this checkout pulled, so pull and doctor reclaim the
  glob of a namespace the team deleted.
…n inline rules (Tencent#946)

- A superseded flat copy (fe.style.md beside the author's style.md) goes
  only while it holds what was recorded or the render; an edited one is
  kept and named, a member's own file is left alone.
- inlinedRulesText reads paths: through the tolerant team-rule parse, so
  paths: **/*.ts keeps its 'Applies to files matching' line.
…Tencent#946)

parseLearningDoc logged 'Failed to parse frontmatter' at error level on
every pull for a rule with paths: **/*.ts and indexed the frontmatter as
body text. It now retries with the tolerant team-rule parse and logs at
debug.
@SaulMoro SaulMoro changed the title fix(rules): deliver team rules through each tool's own channel fix(rules): use native formats and scope-specific delivery Oct 3, 2026
@SaulMoro
SaulMoro force-pushed the fix/946-rules-delivery branch from 0ca60db to 591dc5e Compare October 3, 2026 14:32
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown

Findings

  • [P1 blocking] Preserve YAML comments outside the repaired glob scalar — src/resources/team-rule.ts:39. For paths: **/*.ts # TypeScript files, the retry produces paths: "**/*.ts # TypeScript files", so native renderers and inline channels receive the nonexistent glob **/*.ts # TypeScript files. Quote only the scalar before the YAML comment.
  • [P2 non-blocking] Create flat-tool diagnostics even when every target collides — src/doctor-delivery.ts:306. If the only rules are fe.style/x and fe/style.x, both flatten to the same OMP/Kiro filename and deliveryTargets() skips both; consequently byTool has no entry and doctor reports no collision for that tool.
  • [P2 non-blocking] Check stale activation artifacts when no rules remain — src/doctor-delivery.ts:274. The early return bypasses buildRulesActivationChecks(), so after the last rule is removed, doctor cannot report a team-owned OpenCode glob left in opencode.json after failed cleanup, even though OpenCode may continue loading the stale copies.

Resolved

  • The four previously reported ownership, OpenCode namespace, supersedes, and inline-parser findings are fixed. The PR’s real-CLI testing record is sufficient.

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.

[bug] Team rules miss most tools: each tool's own rules format, else a file only it reads, else a hook or extension in project scope

2 participants