Skip to content

fix(rules): give Codex the team rules: session hooks in a project, its own AGENTS.md in user scope - #940

Merged
jeff-r2026 merged 41 commits into
Tencent:mainfrom
SaulMoro:fix/codex-rules-agents-md
Oct 1, 2026
Merged

jeff-r2026 merged 41 commits into
Tencent:mainfrom
SaulMoro:fix/codex-rules-agents-md

Conversation

@SaulMoro

@SaulMoro SaulMoro commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Codex never read the team rules: pull copied them to .codex/rules/, Codex's command-policy directory. Now Codex gets the rules, and the culture, claudemd/ and recall blocks, from its own AGENTS.md in user scope and from teamai's session hooks in a project. The project AGENTS.md stays the owners' file.

Green is new, dashed red is removed:

flowchart LR
    pull[teamai pull]
    old[".codex/rules/*.md"]:::removed
    userfile["$CODEX_HOME/AGENTS.md<br/>user scope: rules, culture,<br/>claudemd/, recall"]:::added
    proj["project AGENTS.md<br/>the owners' text only"]
    hook["teamai hook-dispatch<br/>session-start · subagent-start"]:::added
    subgraph codex [Codex session]
        start["startup · clear · compact"]
        sub["fresh subagent"]
        model[model context]
    end
    pull -.->|"copies today, Codex never reads them"| old
    pull -->|user scope| userfile
    userfile --> model
    proj --> model
    start --> hook
    sub --> hook
    hook -->|"additionalContext: the project's rules,<br/>culture, claudemd/, recall"| model
    classDef added fill:#2f8f4f,stroke:#1f6b39,color:#fff;
    classDef removed fill:#a33a3a,stroke:#7a2a2a,color:#fff,stroke-dasharray:4 3;
Loading
on SessionStart | SubagentStart (Codex family)
  session outside a project   add nothing          # $CODEX_HOME/AGENTS.md covers user scope
  source is resume            add nothing          # the history already holds it
  otherwise                   add the project's rules and blocks, as pull resolves them

The legacy cleanup shared by pull and uninstall preserves a tombstoned rule copy unless its recorded delivery hash matches. A missing ledger or a ledger without that file is not evidence that the copy is unchanged; the warning names the kept file without claiming it contains edits.

 on legacy cleanup of a tombstoned rule
-  remove unless the delivery ledger proves a local edit
+  remove only when the recorded delivery hash matches
+  otherwise keep the copy and warn

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

Evidence

  • npx tsc --noEmit passes
  • npm run lint passes
  • Earlier full-suite validation: npx vitest run, 363 files, 6815 passed, 1 skipped
  • Added/updated tests for the change

Review correction at 4d192c4c:

  • Before the fix, the new regressions failed with ENOENT: cleanup deleted the edited retired.md in pull, full uninstall and uninstall --agent codex.
  • After the fix, npx vitest run src/__tests__/codex-legacy-rules.test.ts src/__tests__/uninstall.test.ts passes: 2 files, 113 tests. It covers missing, empty and unrelated delivery records, plus removal of a recorded, unchanged copy.
  • npx tsc --noEmit, npm run lint, npm run build and git diff --check pass.
  • The real-CLI evidence below is retained from the earlier PR validation. E2E was not rerun for this review correction, as requested.

New tests, each red before its change:

project-scope pull for codex | codex-internal | tcodex  → project AGENTS.md byte for byte
user-scope pull                                          → team-rules block in ~/.<tool>/AGENTS.md, beside the member's text
pull at an unchanged revision after an upgrade           → writes that block, removes the old .codex/rules copy
hook in a project                                        → rules + culture + claudemd/ + recall, without markers
hook outside a project, or on resume                     → nothing
hook with a block Pi already wrote into AGENTS.md        → that block left out
doctor, user scope                                       → block current / missing / stale / shadowed by AGENTS.override.md
doctor, SubagentStart entry missing or without the limit → fails
uninstall, user scope                                    → block removed, member's text kept
recall on/off in a project                               → project AGENTS.md unchanged

Real CLI (npm run build, node dist/index.js through a teamai shim), with a sandbox HOME and CODEX_HOME, local bare team repos and codex-cli 0.159.2. The project team has a rule (PELICAN-42), culture (BADGER-8) and claudemd/ (HERON-7); the user-scope team a rule (WREN-5). The committed project AGENTS.md holds the owners' OTTER-3. Codex is asked for every codeword without reading files.

Run Before (0.22.0) After (this branch)
pull, project scope copies the rule to .codex/rules/sbx-rule.md git status clean; hooks.json has SessionStart and SubagentStart with additionalContextLimit: 0
codex exec in the project NONE OTTER-3 BADGER-8 HERON-7 PELICAN-42
pull, user scope copies the rule to ~/.codex/rules/ team-rules block in ~/.codex/AGENTS.md; no ~/AGENTS.md, no ~/.codex/rules
codex exec outside any project NONE WREN-5
codex exec in the project, both scopes n/a all five, each once; git status still clean
doctor ✔ Rules delivered to codex ✔ Team rules are inlined in Codex AGENTS.md (user), ✔ Project rules and instructions reach codex whole through its session hooks

Hook behaviour on Codex itself (over 2,500 tokens, compaction, resume, a fresh subagent, an unapproved hook): #938.

Related Issues

Closes #938. Part of #946 (rules) and #945 (instruction blocks).

Notes for Reviewers

  • Approval once. additionalContextLimit and the SubagentStart entry are part of Codex's hook trust hash. The public Codex asks each member once to approve the changed teamai hooks; until then it gets no project rules, with no warning. doctor prints the trust reminder.
  • Until [bug] Team members with different roles overwrite each other's blocks in shared root AGENTS.md #945 lands. Pi, Hermes and WorkBuddy still write their blocks into the project AGENTS.md, which Codex reads. The hook leaves those out, so Codex gets each block once.
  • Team toolPaths. A Codex-family entry needs userScope.claudemd; a top-level claudemd would put the blocks back in the project AGENTS.md. doctor names an entry that lacks it.
  • Not run live: codex-internal and tcodex, covered by unit tests only.

Post-merge review corrections

PR #940 was merged at 12:26 UTC on October 1 while these corrections were being validated. They are not part of its merged head, 4d192c4c.

A read-only adversarial subagent (Sol 6.1 xhigh) used the workflow's Codex CLI prompt against main (b2d3598b...4d192c4c). It confirmed the three P2s in the latest review and found one additional P2: deduplication against a project AGENTS.md shadowed by AGENTS.override.md.

The follow-up commit 537859a8, based on main 85ff72c7, fixes all four: legacy cleanup follows recorded tool roots and publishers' local names (also tombstoned rules), doctor requires both start hooks, and project deduplication reads the active instructions file. The fixes are published separately in #947.

Validation at 537859a8: 190 tests across codex-legacy-rules, uninstall, doctor and codex-hook-rules; npx tsc --noEmit, npm run lint, npm run build and git diff --check pass. The prior real-CLI evidence above is retained; E2E was not rerun for these fixes, as requested.

Merge danger

Two-way door: reverting brings back the old copies on the next pull, and the only deletion is the unedited .codex/rules/*.md copies, which teamai can regenerate. Blast radius: Codex-family members.

hermesRulesText becomes inlinedRulesText, the one renderer for tools that read rules from a single instructions file. It strips frontmatter and leads a path-scoped rule with 'Applies to files matching: <globs>'. Hermes SOUL.md and doctor's Hermes check use it. Part of Tencent#938.
Codex reads instructions from AGENTS.md, not from .codex/rules, so the
copies pull wrote there never reached it (Tencent#938). The codex defaults drop
rules and gain claudemd (AGENTS.md, ~/.codex/AGENTS.md at user scope).
pullAllRules syncs a [teamai:team-rules] block into that file once per
path while an enabled, installed Codex-family tool maps it, and removes
it otherwise. syncManagedInstructions probes rules ?? settings, so a
machine without Codex gets no ~/.codex.
Follows the T3 rename, so a path-scoped rule reaches AGENTS.md without frontmatter, after its Applies to line.
…tructions and recall

Codex now reaches AGENTS.md through its default claudemd path; these tests
pin user scope (~/.codex/AGENTS.md), a full project-scope pull writing all
four teamai blocks into one AGENTS.md, and recall on/off. Also corrects the
injectRecallBlockIntoTools comment, which listed Codex as skipped.
Uninstall strips the [teamai:team-rules] block and scans the legacy .codex/rules directory for teamai's copies. A shared instruction file now keeps only the blocks a remaining enabled, installed tool would write, so --agent codex drops the team-rules block while Pi keeps its own.
Codex reads no rules directory, so doctor now compares the team-rules
block in each AGENTS.md an enabled, installed Codex-family tool maps
with what pull renders. It fails on a missing or stale block, on an
AGENTS.override.md that Codex reads instead, and on an entry with no
claudemd path. The file list comes from RulesHandler, the same
resolver the pull writes through.
Codex never read the <rule>.md copies teamai wrote to .codex/rules (and
.codex-internal/rules, .tcodex/rules). Every rules sync now removes the
ones that still hold what teamai delivered, including teamai-recall.md,
keeps edited copies and names them, and leaves *.rules alone.
# Conflicts:
#	src/resources/rules.ts
…s-md

# Conflicts:
#	src/resources/rule-format.ts
A CLI upgrade with the team repo unchanged takes the "Already synced" fast path, which never ran the rules sync. So a member upgrading from 0.22.0 got no team-rules block in AGENTS.md and kept the old .codex/rules copies until the repo moved or they ran pull --force. The fast path now runs the Codex part of the rules sync (block + reclaim) and nothing else.
… block

The already-synced pull now rewrites the block, so the fix text no longer sends the member to pull --force.
codex-internal and tcodex drop their rules path and read team rules from
AGENTS.md like codex. Codex-family instruction writers probe
rules ?? settings ?? skills, so a team entry with neither rules nor settings
no longer counts as installed. writesInstructionBlock is the one answer to
which blocks a tool gets, shared by pull's writers and uninstall.
…fix/codex-rules-agents-md

# Conflicts:
#	src/__tests__/codex-instructions-rules.test.ts
removeClaudeMdSection now reports whether it removed a section and can delete a file left holding only whitespace. The team-rules sync and recall off use it, so a pull that removed nothing no longer deletes a member's own empty AGENTS.md.
When every team rule is frontmatter only, pull writes no team-rules block, so a missing block is correct and an AGENTS.override.md shadows nothing. Also note that an empty override shadows AGENTS.md too.
Editing teamai.yaml moves the team repo, so a plain pull does the full sync; --force is not needed. Matches the other Codex block checks.
The summary and result lines said CLAUDE.md for every instruction file, including Codex's AGENTS.md. They now print the file's path under an 'Instruction-file blocks' heading.
recall on now asks the same question as pull's recall writer and uninstall, so the three cannot drift. No behavior change.
The tombstone cleanup walks toolPath.rules, which Codex no longer has, so a copy of a rule tombstoned after the member's last pre-Tencent#938 pull stayed forever. The legacy reclaim now removes tombstoned names too, keeping and naming a copy the member changed since delivery (Tencent#822).
…ninstall

Parametrizes the project-scope legacy reclaim, the four Codex doctor failure cases and the full uninstall over the Codex family.
With Codex's default claudemd (Tencent#938), an HTTP prompt command reported by Codex writes the shared-instructions block into ~/.codex/AGENTS.md when ~/.codex exists, and creates nothing when it does not.
It reads a tool-neutral rule's paths: frontmatter, which both the Copilot renderer and the inlined-rules renderer use; it no longer lives in the Copilot module.
… goes

Removing the last block deleted any instructions file it left empty, so
an empty AGENTS.md a repository tracked was deleted once Codex was
disabled or the team had no rules left. injectClaudeMdSection now creates
a file as just the block, and deleteIfEmpty deletes only a file that
opens with it; a member's empty file is written back empty.

Also describe the per-block cleanup of shared instruction files in the
deployed uninstall skill.
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
  • [P1 blocking] Preserve pre-existing empty AGENTS.md during uninstall — src/uninstall.ts:1040 deletes the instruction file whenever removing its selected blocks leaves no text. If Codex was installed into an already tracked empty AGENTS.md, uninstall --agent codex deletes that user-owned file. Use the same ownership-sensitive removal behavior introduced in removeClaudeMdSection.
  • [P1 blocking] Keep role/project filtering when refreshing after rule removal — src/resources/rules.ts:425 calls pullAllRules without the resolved rule selection. The new call at src/resources/rules.ts:460 therefore writes every remaining repository rule into Codex’s AGENTS.md; for a role-scoped member, running teamai remove rules … activates rules from unrelated namespaces until another pull corrects it.
  • [P2 non-blocking] Check for obsolete Codex blocks when no rules remain — src/doctor-delivery.ts:263 returns before the new Codex instruction check when the desired rule set is empty. If removal of the last rule’s block failed, doctor reports no rule problem while Codex continues reading the stale rule.
  • [P3 nit] Sanitize marker substrings, not only whole marker lines — src/resources/rules.ts:960 removes markers only when they occupy the entire trimmed line, while injection/removal locate markers with indexOf. A rule mentioning an end marker inline causes later pulls and doctor checks to truncate the managed block incorrectly.
  • The previously reported legacy-recall, pull-time empty-file, and uninstall-skill-documentation findings are resolved. The PR description includes sufficient real-CLI testing evidence.

- uninstall and the legacy [teamai:rules] strip remove blocks through
  removeClaudeMdSection, so a member's empty AGENTS.md survives them as it
  does pull. Removing a block at the top of a file keeps the next one
  there, so a file teamai created still goes with its last block.
- `remove rules` refreshes with the rules this member's pull delivers
  (role, project and tag selection) instead of every rule in the repo.
- doctor reports a Codex team-rules block left behind when the team has
  no rules, and nothing else in that case.
- teamRulesBlock strips the block markers wherever they appear in a rule,
  not only as whole lines, since the block is located by substring.
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

Findings

  • [P1 blocking] Preserve edited legacy Codex rule copies during uninstall — src/uninstall.ts:492 selects every .md in the legacy rules directory solely by matching its name against the current team rules or built-ins. If pull preserves an edited .codex/rules/foo.md as promised, a subsequent teamai uninstall silently deletes those user edits. Apply the same ledger/hash ownership check used by reclaimLegacyRuleCopies.
  • [P2 non-blocking] Include removed rules when cleaning legacy directories — src/uninstall.ts:540 builds teamRuleNames only from rule files still present in the repository. If a user upgrades and uninstalls before running pull, legacy copies of tombstoned rules remain in .codex/rules, so uninstall does not fully remove the old TeamAI artifacts. Include .removed entries or recorded delivery paths in discovery.

The previously reported legacy-recall, empty-file, filtered-refresh, doctor, marker-sanitization, and uninstall-skill documentation issues are resolved. The PR description contains sufficient real-CLI testing evidence.

@SaulMoro
SaulMoro marked this pull request as draft October 1, 2026 06:42
…claim

legacyRuleCopies classifies each .codex/rules copy (and the codex-internal
and tcodex dirs) as teamai's or edited, on the ledger, team-render,
tombstone and shipped-recall proofs reclaimLegacyRuleCopies used inline.
Read-only and public so uninstall can apply the same check. No behavior
change.
…rules' copies

Uninstall picked every .md in a legacy rules dir whose name matched a
current team rule or a built-in, so it deleted copies a pull had kept as
the member's edits, and left copies of rules the team had tombstoned.
It now takes the legacy dirs from RulesHandler.legacyRuleCopies, the
check pull reclaims by: owned copies go, edited ones stay and are named
in one English warning. The tool's current rules dir is unchanged.

Addresses the codex-review findings on Tencent#940.
@SaulMoro

SaulMoro commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator Author

Why the project AGENTS.md carries nothing for Codex. It is the owners' file, and these tools read it too:

  • OpenCode
  • Cursor
  • GitHub Copilot CLI
  • Claude Code, when there is no CLAUDE.md

They already get the team rules in their own format, so a block there would reach them twice, and a paths: rule would lose its scoping. The checks and the evidence are in this comment on #938.

So in a project Codex gets its rules and instruction blocks from teamai's session hooks, and in user scope from its own AGENTS.md, which only Codex reads.

@SaulMoro SaulMoro changed the title fix(rules): deliver team rules to Codex through AGENTS.md [Do not merge] fix(rules): deliver team rules to Codex Oct 1, 2026
The project AGENTS.md the earlier revision wrote the rules into is read by
Cursor, Copilot, OpenCode and Claude too, which already get the rules in
their own format. The Codex family now gets them from the teamai
session-start hook instead, and pull writes no rule file for it.

- A team-rules handler adds the user-scope rules, then the cwd project's,
  as pull resolves them, skipping a scope that does not enable the tool.
  It adds nothing on resume, whose history already holds them.
- A SubagentStart entry gives a fresh subagent the same rules.
- Both entries set additionalContextLimit: 0; past 2,500 tokens Codex
  keeps only the start and end of a hook's context.
- doctor checks the limit on the session-start entry; the AGENTS.md
  block check, its markers and its uninstall handling are gone. The block
  never shipped.
- Culture, shared instructions and recall still go to AGENTS.md; the old
  .codex/rules cleanup and the remove-rules role filter are unchanged.

For Tencent#938.
@SaulMoro SaulMoro changed the title [Do not merge] fix(rules): deliver team rules to Codex fix(rules): give Codex the team rules through its session-start hook Oct 1, 2026
@SaulMoro

SaulMoro commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator Author

Codex now gets the team rules, and the culture, claudemd/ and recall blocks, as #938 and #945 describe: from its own AGENTS.md (~/.codex/AGENTS.md) in user scope, and from the session-start and subagent-start hooks in a project. pull leaves the project AGENTS.md unchanged (bf3c28e). The description has the real-CLI runs. The PR stays a draft until a maintainer is ready to review.

Tencent#942 pinned Codex's default paths before Tencent#938 moved its rules to the
session-start hook: no rules path, and an AGENTS.md that follows the
root in user scope.
The project AGENTS.md is the owners' file, and Cursor, Copilot, OpenCode
and Claude read it too. The Codex family now takes its project content
from the session hooks and its user content from its own AGENTS.md:

- Project scope: no `claudemd` in the Codex-family defaults, so pull
  writes nothing to the project AGENTS.md. The session-start and
  subagent-start hooks add the project's rules plus the culture,
  claudemd/ and recall blocks, leaving out a block another tool already
  wrote into the project AGENTS.md.
- User scope: the team rules go into a team-rules block of
  ~/.codex/AGENTS.md (and the variants' homes), beside the other blocks;
  the hook adds nothing outside a project. The "Already synced" pull
  writes the block too.
- doctor checks that block in user scope, and both hook entries' limit
  in a project. uninstall removes the block.

For Tencent#938.
@SaulMoro SaulMoro changed the title fix(rules): give Codex the team rules through its session-start hook fix(rules): give Codex the team rules: session hooks in a project, its own AGENTS.md in user scope Oct 1, 2026
@SaulMoro
SaulMoro marked this pull request as ready for review October 1, 2026 11:45
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

Findings

  • [P1 blocking] Preserve edited copies of tombstoned rules without a ledger — src/resources/rules.ts:728 treats removedCopyChanged(undefined, file) as unedited. If an older CLI wrote .codex/rules/retired.md, the member edited it, the team later tombstoned retired, and the member upgrades before a delivery ledger exists, pull or uninstall silently deletes those edits. Without a recorded hash, compare against historical team revisions or conservatively keep the file.

All earlier findings are resolved in the current diff. The PR description includes sufficient real-CLI end-to-end testing evidence.

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

Findings

  • [P2 non-blocking] Clean relocated Codex legacy directories — src/resources/rules.ts:709 constructs the legacy directory from the hard-coded .codex/rules path and ignores localConfig.toolRoots. A user whose previous pulls targeted a custom CODEX_HOME keeps all obsolete .md rule copies after both pull and uninstall.
  • [P2 non-blocking] Find legacy copies stored under the publisher’s bare name — src/resources/rules.ts:714 looks only for ${rule.name}.md. For a locally published namespaced rule such as rules/frontend/foo.md, earlier delivery used .codex/rules/foo.md via localNameFor, so upgrading or uninstalling never reclaims that TeamAI-owned copy.
  • [P2 non-blocking] Fail doctor when the Codex SessionStart entry is absent — src/doctor.ts:318 returns success when no matching SessionStart entry exists, assuming the generic hook check catches it. That check only searches for any teamai hook-dispatch command, so a hooks file containing only a Stop entry makes both checks pass while project rules are never injected.

All previously reported findings are resolved. The PR description includes sufficient real-CLI testing evidence.

@jeff-r2026
jeff-r2026 merged commit 9bcd53e into Tencent:main Oct 1, 2026
13 checks passed
SaulMoro added a commit to SaulMoro/teamai-cli that referenced this pull request Oct 2, 2026
…encent#945)

Rebased onto Tencent#940, which already moves Codex's project content to its
session hooks. The rebase kept this branch's side in conflicting hunks;
this commit restores what that dropped of Tencent#940 (teamRulesHandler, the
fast-path Codex rules sync, uninstall's per-block retention and
keptRuleFiles) and joins the two designs:

- teamRulesHandler takes Codex's culture, claudemd and recall from
  resolveInstructionBlocks, as pull and the Pi, OMP and Hermes
  extensions do, and no longer skips a block found in the project
  AGENTS.md: pull removes those, and the skip handed Codex another
  member's stale selection.
- The Codex family is a hook target in project scope, with AGENTS.md
  retired for a team override or an earlier build. Hook text drops
  block markers for every tool, as Tencent#940 did for Codex.
- Uninstall keeps Tencent#940's per-block retention and clears through the
  planner; the team-rules block is one of the blocks cleanup knows.
- An emptied file goes only when it opens with a teamai block, as
  Tencent#940 decided, and git does not track it.

AGENTS.md now assert that nothing does and that uninstall clears the
blocks left there.
jeff-r2026 pushed a commit that referenced this pull request Oct 3, 2026
… AGENTS.md (#945) (#952)

* fix(pull): write instruction blocks only for installed tools (#945)

Add src/instruction-targets.ts, one resolver for where the culture,
claudemd and recall blocks go per tool and scope. Pull, recall
enable/disable, local-agent and uninstall read targets from it.

A pull now skips tools that are not installed, whether or not they have
a rules path, so Hermes no longer writes ~/AGENTS.md when it is absent.
It also strips teamai blocks from known targets no installed tool reads,
and deletes the file when nothing else is left. Targets are unchanged.

* fix(pull): plan instruction files before writing them (#945)

Culture, claudemd and recall blocks now go through one planner that
works out each file's content first. A pull no longer rewrites a file
whose blocks are current, leaves a block with a missing or repeated
marker alone with a warning, deletes an emptied file only when git does
not track it, and reports the files it would change under --dry-run.
Recall is part of the same pass, so a pull removes the recall block
when recall is disabled, and recall enable/disable use the same
targets.

* fix(pull): give Claude its project blocks in .claude/rules (#945)

Claude's project-scope culture, claudemd and recall blocks move from
.claude/CLAUDE.md to .claude/rules/teamai-context.md. Claude loads that
file from the root and from subdirectories, and still reads AGENTS.md
and an authored CLAUDE.md the way it chose to; CLAUDE.local.md would
have stopped the native AGENTS.md load. The next pull removes the old
blocks from .claude/CLAUDE.md and keeps the rest of the file.

teamai-context is excluded from the rules sweep and from push, so the
file is neither deleted as stale nor pushed as a team rule.

An e2e test pulls as two members of one project with different roles:
each gets their own selection and AGENTS.md keeps its bytes.

* fix(pull): give Cursor an always-applied teamai-context.mdc (#945)

Cursor had no instruction target and only saw the blocks other tools
left in AGENTS.md and .claude/CLAUDE.md. It now gets them in
.cursor/rules/teamai-context.mdc with alwaysApply: true, in both
scopes.

Uninstall and local-agent go through the same planner as pull, so a
teamai-context file is removed whole, header included, and is created
with its header.

* fix(pull): give CodeBuddy and WorkBuddy their own rule files (#945)

CodeBuddy and WorkBuddy both read the project's .codebuddy/rules, so
their project blocks share one always-applied
.codebuddy/rules/teamai-context.md instead of .codebuddy/CODEBUDDY.md and
the project AGENTS.md. WorkBuddy's user blocks move from ~/AGENTS.md to
~/.workbuddy/rules/teamai-context.md. Uninstalling one of the two keeps
the shared copy while the other is installed.

The shared AGENTS.md is cleaned only once no installed tool still
targets it; Pi and Hermes keep it until their own channels land.

* fix(pull): give Hermes its user blocks in SOUL.md (#945)

Hermes' user-scope culture and claudemd blocks move from ~/AGENTS.md,
which Hermes does not read from a project under the home directory, to
$HERMES_HOME/SOUL.md beside the team rules block teamai already writes
there. Only a user-scope pull writes them, so a project pull leaves
them alone. Hermes counts as installed when $HERMES_HOME exists, the
same check rules delivery uses, instead of a ~/.hermes probe.

* fix(pull): give Oh My Pi its blocks without hiding AGENTS.md (#945)

Oh My Pi keeps one context file per level, so ~/.omp/agent/AGENTS.md
hid ~/.agents/AGENTS.md and .omp/AGENTS.md hid the project's AGENTS.md.
User-scope blocks now go to ~/.omp/agent/RULES.md, an always-applied
rule beside that slot. In a project, teamai's OMP extension asks the new
`hook-dispatch instructions` event for the member's blocks when a
session starts and appends them to each turn's system prompt; OMP
rebuilds that prompt from its base every turn, so they reach each
request once. The next pull removes the old blocks from both context
files.

Verified with OMP 18.2.1 against a local capture server: the blocks
reach each request once from the project root and a subdirectory, and
the project AGENTS.md still loads.

* fix(pull): give Pi its project blocks through its extension (#945)

Pi's project blocks went into the project AGENTS.md, the file every
member shares. teamai's Pi extension now asks `hook-dispatch
instructions` for the member's blocks when a session starts and adds
them to each run's system prompt; Pi renders that prompt from its base
for every run, so they do not pile up. The next pull removes the old
blocks from AGENTS.md once no installed tool still writes there.
User-scope blocks stay in ~/.pi/agent/AGENTS.md.

* fix(pull): give Hermes its project blocks through a plugin (#945)

Hermes' project blocks went into the project AGENTS.md even when Hermes
was not installed. teamai now installs a Hermes plugin,
$HERMES_HOME/plugins/teamai-instructions, enabled in plugins.enabled,
whose system prompt section asks `hook-dispatch instructions` for the
member's blocks for the session's directory. Hermes builds it once per
session and keeps it through compression and resume. A section holds
4,000 characters; when the blocks are longer, pull says Hermes skips
them instead of cutting them or falling back to AGENTS.md.

With Pi, Hermes and WorkBuddy moved, no tool writes the project
AGENTS.md any more, so the next pull removes the teamai blocks left
there. Uninstall also cleans a tool's retired files.

* fix(pull): give OpenCode its own team instruction file (#945)

OpenCode had no instruction target and only saw the blocks other tools
left in AGENTS.md. It now gets them in .opencode/teamai-context.md,
listed in the instructions of .opencode/opencode.json, and in user scope
in ~/.config/opencode/teamai-context.md, listed by absolute path in the
user opencode.json. Only that entry is added or removed; the member's
entries and the root opencode.json stay as they are.

While ~/.config/opencode/AGENTS.md does not exist, OpenCode reads
~/.claude/CLAUDE.md, which already holds the user blocks when Claude is
installed, so teamai adds no second copy and says so.

Verified with OpenCode 1.18.21 against a local capture server: the
blocks reach the request once from the project root and a subdirectory.

* feat(doctor): check that each tool can load its team instructions (#945)

doctor now asks what keeps a tool from loading this member's culture,
claudemd and recall blocks, not whether a file was written: each file
target must hold the current blocks, OpenCode's file must be listed in
its instructions, the Pi and Oh My Pi extensions and the Hermes plugin
must be installed as this build writes them (and the plugin enabled),
the Hermes section must fit its 4,000-character limit, and no file an
earlier release wrote may still hold blocks.

* test(e2e): cover two roles with every tool, the task diff and content removal (#945)

Three real-CLI tests for the closing criteria of #945: two members of
one project with every file-based tool installed keep the shared
AGENTS.md byte-identical across a role change and a claudemd edit; with
the generated targets excluded by the fixture, a pull that updates the
instructions leaves the task diff, the staged diff, the index and the
exclude file unchanged; and disabling recall, deleting a claudemd
source and leaving a namespace remove that content from files and from
the extension's prompt text.

Docs drop the remaining wording that named CLAUDE.md or AGENTS.md as
the injection target, and the changelog asks teams to upgrade together.

* docs(usage): name the Copilot limit of Claude's .claude/rules target (#945)

* fix(pull): deliver Codex's blocks from the same source as every tool (#945)

Rebased onto #940, which already moves Codex's project content to its
session hooks. The rebase kept this branch's side in conflicting hunks;
this commit restores what that dropped of #940 (teamRulesHandler, the
fast-path Codex rules sync, uninstall's per-block retention and
keptRuleFiles) and joins the two designs:

- teamRulesHandler takes Codex's culture, claudemd and recall from
  resolveInstructionBlocks, as pull and the Pi, OMP and Hermes
  extensions do, and no longer skips a block found in the project
  AGENTS.md: pull removes those, and the skip handed Codex another
  member's stale selection.
- The Codex family is a hook target in project scope, with AGENTS.md
  retired for a team override or an earlier build. Hook text drops
  block markers for every tool, as #940 did for Codex.
- Uninstall keeps #940's per-block retention and clears through the
  planner; the team-rules block is one of the blocks cleanup knows.
- An emptied file goes only when it opens with a teamai block, as
  #940 decided, and git does not track it.

AGENTS.md now assert that nothing does and that uninstall clears the
blocks left there.

* fix(doctor): ask for OpenCode's instructions entry only once its file exists (#945)

pull registers .opencode/teamai-context.md (or the user file) in
instructions only after writing it, so a team with no culture or
claudemd/ has no file and no entry. doctor failed that case.

* fix(pull): address review of #945: retired files only, one OpenCode path, channel reports

Standards and spec review, round 1:

- Cleanup touches only the files earlier releases wrote blocks to, never
  a tool's current target: a member without Copilot no longer strips a
  tracked .github/copilot-instructions.md a teammate's pull wrote.
- The OpenCode Claude fallback and the instructions registration live
  in instruction-targets.ts, so pull, recall enable, local-agent and
  doctor agree; a dry run reports the opencode.json change.
- pull (after installing hooks) and init name a Pi or OMP extension or
  Hermes plugin that is missing, out of date or disabled, and Hermes
  text over its limit; "Synced" is printed for file targets only.
- The Codex team-rules writer stays out of a project file when Codex's
  session hook carries the rules, even with a team claudemd override.
- Uninstall decides which blocks a remaining tool keeps from its target,
  not from toolPath.claudemd.
- One helper resolves hook text for both handlers; doctor and pull share
  the channel and limit checks and one Hermes plugins.enabled reader.
- Docs: the destination table lists every tool and marks the channels no
  live session has checked; the misplaced rows leave the recall table;
  the uninstall text in both guides and skill-data describes the shared
  CodeBuddy/WorkBuddy file; the stale Codex dedupe sentence goes.

* fix(pull): address review round 2 of #945

- Docs: pull cleans only the files earlier releases wrote, not a tool's
  current file; the Cursor and CodeBuddy notes say what the loader reads
  instead of claiming live delivery.
- init reports instruction channel problems on every path that installs
  hooks; a silent session-start pull leaves them to doctor; a failed
  check no longer logs as a skipped hook reconcile; the fix names
  `teamai hooks inject`.
- A dry run promises an OpenCode instructions entry only when it would
  write the file, and a failed registration points at doctor.
- recall disable drops OpenCode's entry once its file goes; local-agent
  defers to OpenCode's Claude fallback only when Claude's file holds the
  blocks.
- Tests: uninstall keeps the shared .codebuddy rule for a WorkBuddy
  entry without claudemd; the channel check names a missing Pi
  extension; recall enable writes no OpenCode copy beside the fallback.

* feat(recall): tell tools without the recall subagent to run teamai recall (#945)

Pi, Hermes and OpenClaw have no teamai-recall subagent, so they got no
recall block. They now get one that tells the agent to run
`teamai recall "<keywords>"` itself before code, debugging or design
work, with the subagent block's skip conditions. It uses the same
markers, so recall disable, uninstall, cleanup and doctor treat both
blocks alike; each target and hook gets the one that matches its tool.

Verified with Pi 0.99.2 against a local capture server: the block
reaches each request once from the project root and a subdirectory.
Pi's README row now shows learnings, codebase and teamwiki, the same
criterion Hermes, OpenClaw and DeepSeek Harness already meet.

* fix(pull): address review round 3 of #945

- OMP counts as installed for its team instructions only where ~/.omp
  exists, which is where teamai installs its extension: a member without
  OMP in a project that has .omp/ no longer gets a warning on every pull
  and a failing doctor check that hooks inject cannot fix.
- The Hermes over-limit message names the recall block and
  `teamai recall disable`, since the recall block now counts too.
- Uninstall keeps the recall block for every remaining tool on a shared
  file, as pull now writes one to every tool.
- Tests: recall disable removes the direct block from Pi's hook text; a
  project with .omp/ and no ~/.omp reports no OMP problem.

* fix(hooks): keep Codex's hook adding the member's blocks over AGENTS.override.md (#945)

#947 taught the Codex session hook to skip a block already present in
AGENTS.override.md. This branch removed that skip for AGENTS.md: a teamai
block in a project instructions file holds whoever pulled last, so the
hook adds the member's own selection instead. The rebase keeps that rule
for AGENTS.override.md too, inverts #947's skip test, and drops the
skip sentence from the unreleased #938 changelog entry.

* fix(pull): address review round 4 of #945

- Retired files include the claudemd a team's toolPaths gives a tool
  whose target moved, so a team override such as claude.claudemd:
  CLAUDE.md no longer keeps another member's blocks after the upgrade.
  A path that is any tool's current target is never retired; uninstall
  keeps the blocks a remaining tool still writes there.
- A team rule named teamai-context is not delivered, since it would land
  on teamai's own context rule file and block the instructions; pull
  names it.
- OpenCode's instructions list teamai-context.md only while it holds
  teamai's blocks, so a same-named file of the member's is not activated;
  doctor asks for the entry under the same condition.

* fix(pull): address review round 5 of #945

- The Hermes teamai-instructions plugin is written, enabled, disabled and
  removed only while its directory is absent or its plugin.yaml carries
  teamai's marker, so a member's same-named plugin survives inject and
  uninstall; pull and doctor name it.
- Uninstalling OpenCode drops teamai's instructions entry even when the
  member's own text keeps teamai-context.md.
- A file several tools share gets the teamai-recall subagent block only
  when every tool reading it has the subagent, so WorkBuddy without
  agents beside CodeBuddy gets the direct teamai recall block.
- Removing a block that opened a file leaves no blank lines above the
  member's text.

* refactor(hooks): share one ownership check for generated extension files (#945)

generatedFileState(file, marker) says whether a file teamai generates
into another tool's directory is absent, teamai's, or someone else's.
Pi's extension and agent hooks, the Hermes instructions plugin and the
Oh My Pi extension use it on inject and remove.

Oh My Pi had no check: inject overwrote and uninstall deleted a
same-named ~/.omp/agent/extensions/teamai-hooks.ts of the user's. Now
inject skips it with a warning and uninstall leaves it.

* fix(pull): keep the configured claudemd for a tool without a rules directory (#945)

A team toolPaths entry may omit rules, and an entry does not inherit the
defaults. Claude Code (project), Cursor and WorkBuddy (user) then had no
teamai-context target while their configured claudemd counted as
retired, so pull removed the blocks and delivered them nowhere.

contextRule falls back to the configured claudemd; a claudemd is
retired only when it is not the tool's current target; and only a
teamai-context file takes the entry's header and teamai ownership, so
the configured file stays the member's.

* fix(pull): address review round 7 of #945

- A copy of a team rule named teamai-context an earlier release
  delivered to a rules directory is removed when the record shows it
  unchanged or it matches the team rule's render, so the instructions can
  take that path; an edited copy stays and the instruction sync names it.
- A toolPaths entry with only claudemd is probed through that file's
  directory, and a bare file such as AGENTS.md counts as installed, as
  before.
- Project CodeBuddy and WorkBuddy keep their configured claudemd when the
  entry has no rules, like Claude Code and Cursor.
- The HTTP local agent's claudemd sync strips the blocks earlier releases
  left in files no installed tool reads now, as pull does.
- Uninstall drops teamai's OpenCode instructions entry whenever the
  config lists it, also after the context file was deleted or stripped.

* fix(pull): address review round 8 of #945

- The HTTP local agent's project prompts reach Pi, OMP and Hermes: a
  machine-level `instructions` handler adds the agent's cached claudemd
  for the session's project, and the sync counts such a tool as reached
  once its extension or plugin is ready.
- The HTTP sync probes each tool through its own paths, as pull does, so
  a WorkBuddy-only project without .codebuddy/ gets its prompt.
- OpenCode treats ~/.claude/CLAUDE.md as its fallback while that file
  holds teamai blocks, also ones an excluded Claude Code left there, so
  it no longer loads a second copy; pull warns that nothing keeps them
  current.
- A test resolves targets for every tool, scope and toolPaths shape
  (full, without rules, only claudemd, only settings): an installed tool
  with a claudemd keeps getting the blocks, and no target is retired.

* fix(pull): address review round 9 of #945

- OpenCode registration leaves an instructions entry alone while its
  teamai-context.md is a file of the member's: pull no longer drops an
  entry the member listed for their own file.
- The HTTP prompt sync acks failed, with the reason, when the planner
  leaves a target unchanged (a file teamai did not write, a malformed
  block) instead of counting the tool as reached.
- Hermes counts as reached only while the project's instructions, team
  blocks plus HTTP prompts, fit its 4,000-character section.

* fix(pull): address the adversarial review of #945 against main

- The HTTP prompt sync strips an old instruction file only when every
  installed tool that wrote it received this sync's instructions, so a
  CodeBuddy prompt no longer removes Claude's blocks from .claude/CLAUDE.md.
- A rule tombstone named teamai-context no longer deletes the instruction
  file the unchanged-revision pull just refreshed.
- A placed namespaced rule named teamai-context keeps its namespaced path
  instead of landing on teamai's instruction file.
- Codex project HTTP prompts reach Codex through its SessionStart and
  SubagentStart hooks; the cache handler is named http-prompt-instructions
  so the HTTP reporter wiring stays one handler per event.

* fix(pull): address review round 10 of #945

- A Codex project HTTP prompt is delivered when Codex is installed for
  the member: its hooks are user-level, so a project without .codex/
  still reaches it.
- Uninstall leaves OpenCode's instructions entry for a teamai-context.md
  that holds none of teamai's blocks: that file is the member's.

* fix(pull): address review round 11 of #945

- Pi counts as installed for project instructions when ~/.pi exists:
  teamai installs its extension there, so a project needs no .pi/.
- teamai records the OpenCode instructions entry it adds, and uninstall
  removes a recorded entry even after the member stripped the markers
  from the context file.

* fix(pull): address the second adversarial review of #945 against main

- The unchanged-revision pull reclaims an earlier release's copy of a
  team rule named teamai-context before syncing the instructions.
- Uninstall removes only this checkout's recorded OpenCode entry, and
  forgets the entries it removed.
- Rule removal skips the teamai-context file that holds teamai's blocks,
  so a targeted uninstall keeps a shared instruction file.
- Codex is probed at the member's recorded tool root.
- The HTTP ack fails when OpenCode's config cannot list the prompt file.
- A prompt whose HTTP delivery fails leaves the cache as it was, so
  session hooks do not read it.
- The HTTP agent records state in the project's data home.

* fix(pull): address review round 12 of #945

- Pull restores the alwaysApply header of teamai's own rule file when it
  was lost or changed, so doctor no longer reports it current.
- OpenCode's instructions entry is removed, by pull or uninstall, only
  when teamai recorded adding it.
- A configured claudemd named teamai-context (no rules) is the member's
  file, in pull and uninstall.
- Pull reports synced culture and instructions only when a target was
  reached.

* fix(instructions): keep failed deliveries and removals retryable (#945)

* fix(instructions): confirm replacements before retiring delivery (#945)

* fix(instructions): preserve unresolved blocks and shared tool state (#945)

* fix(instructions): preserve global Codex hooks and activation ownership (#945)

* test(instructions): retry transient hook fixture cleanup (#945)

* fix(uninstall): remove global adapters with the last install on the machine (#945)

A project uninstall kept the Pi and OMP extensions, the Hermes plugin,
Codex's user hooks and server-pushed agent hooks unconditionally, so that
other projects keep their delivery channel. On a machine with no user
scope and no other project, nothing removed them any more, unlike main:
every Pi, OMP, Hermes or Codex session kept running teamai hook-dispatch
after teamai was uninstalled.

A project uninstall now keeps them only while the user config or another
project partition exists, and the last install removes them.

* fix(uninstall): keep global adapters on project uninstall and name them (#945)

The previous commit removed the Pi/OMP extensions, the Hermes plugin,
Codex's user hooks and pushed agent hooks when no user config or other
project partition existed. That misses HTTP-only installs and self or
legacy projects, whose config stays inside <project>/.teamai and cannot
be enumerated, so one project's uninstall could cut another install off.

A project uninstall keeps them again and its summary names each one,
with `teamai hooks remove`, which removes them, as the step to run first
when no other install uses them.

pull --dry-run now previews the retired-file cleanup a real pull does
after installing a Pi, OMP, Hermes or Codex adapter, unless a member's
same-named file or a disabled Hermes plugin keeps that channel closed.

* fix(uninstall): gate empty-plan exclusion and join E2E workers (#945)

* fix(instructions): honor exclusions and retained native blocks (#945)
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] Codex never gets the team rules: session-start hook in project scope, $CODEX_HOME/AGENTS.md in user scope

2 participants