Skip to content

[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 #946

Description

@SaulMoro

Problem

Most tools do not get the team rules as intended:

  • teamai copies a rule to a directory the tool never reads,
  • or the tool reads the copy but ignores paths:,
  • or teamai delivers nothing,
  • or teamai writes them to the wrong place. A project pull rewrites the global Hermes SOUL.md block, and OpenCode's user-scope glob loads the project's rules/*.md instead of the user rules.

doctor still reports ✔ Rules delivered. It compares the copy with what teamai renders, not with what the tool reads.

The evidence comes from real runs of codex exec 0.159.2, OpenCode 1.18.21 against a mock model, and Copilot CLI 1.0.90 with the request captured. The rule parsers of Cursor CLI 2026.09.22, CodeBuddy 2.160.0, the JoyCode plugin 3.8.71 and Oh My Pi 18.2.1 were copied out of their bundles and run on teamai's output. Pi 0.99.2, ZCode 3.14.3, DeepSeek Harness, Hermes, OpenClaw and the WorkBuddy engine in CodeBuddy 2.160.0 come from their source, and Kiro and Qoder from their docs. Qoder Desktop's rule format comes from the rule files in alibaba/tron-one-agent, since its docs publish none.

Proposal

tool has its own rules format          → write each rule in that format, project and user scope
user scope, no rules format            → a file only that tool reads, in its home
project scope, no rules format         → the session-start hook or extension adds the project's rules
no channel reaches the model           → nothing, and init/doctor say why
never                                  → the shared AGENTS.md or another tool's file

User scope uses a file, not the hook, as #945 does for the instruction blocks. The tool reads the file in every session and again after compaction, resume does not duplicate it, it needs no hook trust, and doctor can compare its bytes. With the hook instead, Codex skips an untrusted hook without a warning, and passes output over about 2,500 tokens only as a preview unless the entry raises its limit. ZCode and DeepSeek Harness lose the hook text at compaction.

With the user rules in files, the hook carries only the project's rules, and adds nothing when the cwd resolves to user scope. hook-dispatch resolves one scope per cwd, so it needs no second config.

The hook path already exists. #940 added teamRulesHandler, which gives Codex the project's rules at session-start and subagent-start, and nothing on resume or outside a project. ZCode and DeepSeek Harness join it through getsRulesFromSessionHook (rule-format.ts). Why Codex has no project file of its own: #938. Shared AGENTS.md: why not.

teamai parses paths: once, and each renderer writes the tool's form. The channels with no path scoping (Pi, ZCode, DeepSeek Harness, OpenClaw, JoyCode's rules.txt) reuse inlinedRulesText from #940, which Codex and Hermes already get: frontmatter dropped, and a scoped rule led by Applies to files matching: <globs> (a path hint for the model, not automatic filtering). Kiro, Qoder, CodeBuddy and Oh My Pi get the team file verbatim today. CodeBuddy's parser reads lines, not YAML, so an inline paths: ["a", "b"] turns into globs with the brackets in them.

Per tool

✓ works today · ◐ partly (rules lost or paths: ignored) · ✗ never

Tool Today Change, project scope Change, user scope
Claude Code ✓ none none
Copilot CLI ✓ none none
Cursor ✓ none. Its parser removes the quotes teamai writes around globs, and Cursor writes them the same way none. Cursor CLI reads ~/.cursor/rules only by walking up from a cwd under $HOME (loadRulesFromDirAndAncestors, 2026.09.22); the IDE is not checked
Kiro ◐ inclusion: fileMatch + fileMatchPattern as a list; inclusion: always when unscoped same, ~/.kiro/steering
Qoder, Qoder CN ✓ CLI trigger: glob + one-line glob: with {a,b} expanded, the form Qoder Desktop writes; trigger: always_on when unscoped. The CLI docs say it reads Desktop's rules same, ~/.qoder/rules, ~/.qoder-cn/rules
CodeBuddy ◐ alwaysApply: false and paths: as a block list when scoped same, ~/.codebuddy/rules
WorkBuddy ✗ project · ◐ user rules into .codebuddy/rules, CodeBuddy's format, one copy when both tools are enabled. Removing one tool keeps the copy while the other still uses it, as #945 does for its blocks CodeBuddy's format, ~/.workbuddy/rules. WorkBuddy reads user rules and skills from one home, ~/.workbuddy
JoyCode ◐ project · ✗ user its own render: globs unquoted and {a,b} expanded. It keeps the quotes and splits on every comma a block in ~/.joycode/rules.txt, no path scoping
Oh My Pi ✗ alwaysApply: true when unscoped; globs + a generated description when scoped (it drops rules with neither); namespaced rules flat, since it reads one level. Its own rules, not teamai's extension, so paths: keeps its scoping same, ~/.omp/agent/rules
OpenCode ◐ project · ✗ user glob .opencode/rules/**/*.md, so namespaced rules load, registered in .opencode/opencode.json as #945 does; the glob in the root opencode.json is reclaimed. It applies every rule always glob ~/.config/opencode/rules/*.md and one per namespace directory. Today's rules/*.md resolves from the session cwd
Codex ✓ (#940) none: the session-start and SubagentStart hooks none: $CODEX_HOME/AGENTS.md
Pi ✗ the rules join the context teamai's Pi extension already fetches through teamai hook-dispatch instructions (#952), added to event.systemPrompt from before_agent_start. Pi rebuilds the prompt for each turn, so they do not pile up a block in ~/.pi/agent/AGENTS.md, which only Pi reads, beside #952's blocks
ZCode ✗ user-level SessionStart hook. Its CLI does not run project hooks a block in ~/.zcode/AGENTS.md
DeepSeek Harness ✗ session-start hook, when dsh runs with teamai's --patch a block in $DSH_HOME/AGENTS.md
Hermes ✓ nothing, and init/doctor say why. A project pull rewrites the global SOUL.md block today, and a project with no rules erases it (rules.ts:454-459) keep the $HERMES_HOME/SOUL.md block, written only by a user-scope pull
OpenClaw ✗ nothing. Its project file is the shared AGENTS.md a block in the workspace AGENTS.md, resolved the way the hooks resolve it (profile, OPENCLAW_WORKSPACE_DIR)

claude-internal and tclaude follow Claude Code's layout, and codex-internal and tcodex follow Codex's. They were not checked.

Known limits:

Also in this change:

  • teamai's OpenClaw hook does nothing, so OpenClaw gets no report or sync either. The handler teamai generates reads ctx.event (openclaw-hooks.ts:84), but OpenClaw passes an event with type and action and no event field. It also subscribes to session:start, which OpenClaw does not emit. The handler should key on ${type}:${action} and subscribe to events OpenClaw emits (docs/automation/hooks/event-types.md).

README, rules column

✓ Claude Code, Cursor, Copilot CLI, Kiro, Qoder, Qoder CN, CodeBuddy, WorkBuddy, JoyCode (new row), Oh My Pi, Hermes, OpenClaw
✓* Codex, Pi, ZCode, DeepSeek Harness, OpenCode

✓* The rules reach the tool, but always on: it does not scope them by path (scoped inline rules include path hints for the model).

Codex, Pi and OpenCode change from ✓ to ✓*. DeepSeek Harness and ZCode change from — to ✓*. Hermes changes from — to ✓, and OpenClaw keeps ✓: user scope is their normal rules channel, so both get full ticks. All 5 README*.md change.

Done when

  • Each tool gets its rules as in the table, in each scope.
  • With teamai installed in both scopes, a tool gets the user rules and the project rules, each once.
  • A project-scope pull leaves the Hermes SOUL.md block as the user-scope pull wrote it.
  • OpenCode loads the user rules from ~/.config/opencode/rules and no project rules/*.md.
  • Copies left where nothing reads them (.openclaw/rules, .pi/rules, ~/.pi/agent/rules, a project's .workbuddy/rules, ~/.joycode/rules) are reclaimed, unedited ones only, as fix(rules): give Codex the team rules: session hooks in a project, its own AGENTS.md in user scope #940 does for .codex/rules. Pi gets its rules through the extension and ~/.pi/agent/AGENTS.md.
  • A pull reclaims the unedited team rules that WorkBuddy's one-time migration copied from ~/.codebuddy/rules into ~/.workbuddy/rules.
  • Each render has a test that runs the tool's own parser where it ships one. rules.test.ts:1115-1120 locks JoyCode to Cursor's quoted output and changes.
  • OpenClaw's hook runs teamai hook-dispatch on the events it maps.
  • doctor checks what each tool reads.

Codex: fixed by #940 (#938). Instruction blocks: #945, implemented by #952, whose Pi extension, ~/.pi/agent/AGENTS.md, Hermes plugin, OpenCode .opencode/opencode.json and shared .codebuddy/rules this issue reuses.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions