Skip to content

[bug] Codex never gets the team rules: session-start hook in project scope, $CODEX_HOME/AGENTS.md in user scope #938

Description

@SaulMoro

Part of #946 (rules) and #945 (instruction blocks). This issue is the Codex case.

Problem

pull copies each team rule to .codex/rules/<name>.md, and doctor reports ✔ Rules delivered to codex. Codex never reads those files. It uses .codex/rules/ for command-policy files (*.rules). Asked for a rule's content, codex exec answers NONE. The culture, shared claudemd/ instructions and recall block never reach Codex either. codex-internal and tcodex have the same paths. Rules have been broken since 573a54c added rules: '.codex/rules'.

Fix

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
user scope      pull writes a block in $CODEX_HOME/AGENTS.md     # rules, culture, claudemd/, recall
project scope   pull writes no file for them
  on SessionStart
    source is resume            add nothing                      # the history already holds them
    startup, clear or compact   add the cwd project's rules and blocks
  on SubagentStart              add the same                     # a fresh subagent fires no SessionStart

User scope: a file. Only Codex reads $CODEX_HOME/AGENTS.md. Codex loads it in every session and again after compaction, it needs no hook trust, and doctor can compare its bytes.

Project scope: the hook. teamai already installs a teamai hook-dispatch session-start entry in Codex's hooks.json, and it already adds the secrets hint as additionalContext (#875). The project's rules and blocks become one more handler in that entry, plus a SubagentStart entry. A file does not work here:

  • The project AGENTS.md is also read by Cursor, Copilot, OpenCode and Claude, which get the rules in their own format (evidence). It is also the owners' file, and teamai leaves it unchanged ([bug] Team members with different roles overwrite each other's blocks in shared root AGENTS.md #945).
  • developer_instructions in .codex/config.toml loads only in trusted projects, and it replaces the member's own value.
  • model_instructions_file replaces Codex's base prompt. AGENTS.override.md hides AGENTS.md. project_doc_fallback_filenames is ignored when an AGENTS.md exists.

Tested on Codex 0.159.2

A real codex exec with an isolated CODEX_HOME and a hook that returns a codeword (details):

Case Result
hook trusted codeword returned
hook not trusted NONE, and codex exec prints no warning
about 6k tokens of context NONE, because Codex keeps only the start and end of anything over 2,500 tokens
same, with "additionalContextLimit": 0 codeword returned
resume --last codeword returned from the history; the hook fires again with source: "resume"
forced auto-compaction the hook fires with source: "compact"; codeword returned afterwards
fresh subagent (fork_turns: "none") codeword returned through SubagentStart (run in #940)

Expected

# Area Today (0.22.0) Expected
1 Rules, project scope copied to .codex/rules, never read the session-start hook adds them; no file
2 Rules, user scope copied to ~/.codex/rules, never read a block in $CODEX_HOME/AGENTS.md
3 Culture, claudemd/, recall never reach Codex project scope: the same hook; user scope: blocks in $CODEX_HOME/AGENTS.md
4 Rules with paths: raw copy with frontmatter rendered without frontmatter after an Applies to files matching: <globs> line (the same renderer as Hermes' SOUL.md)
5 Resume and compaction n/a added on startup, clear and compact; nothing added on resume
6 Large content n/a the entry sets "additionalContextLimit": 0, so Codex does not cut it
7 Subagents n/a a SubagentStart entry adds the same project content
8 Project AGENTS.md n/a teamai writes nothing to it
9 Copies left by earlier pulls stay in .codex/rules pull and uninstall remove the copies that match what teamai delivered; they keep edited copies and name them, and never touch *.rules
10 doctor ✔ Rules delivered to codex, a false positive checks that both hook entries are present with the limit, reminds the member to trust them, and compares the user-scope block
11 codex-internal, tcodex same as Codex same as Codex, under each tool's own home
12 Docs and skill-data/ say nothing about how Codex gets rules both usage guides and the affected skill references updated

Members approve the teamai hooks again once. additionalContextLimit and the SubagentStart entry are part of Codex's trust hash, and both land in the same pull.

Acceptance criteria

  • With Codex enabled, codex exec returns a team rule and the culture in project scope (from the hook) and in user scope (from $CODEX_HOME/AGENTS.md), from a real-CLI run of the build.
  • A pull writes nothing to .codex/rules or to the project AGENTS.md.
  • The hook adds nothing when source is resume.
  • Project content over 2,500 tokens reaches Codex whole.
  • A fresh subagent gets the project's rules and blocks.
  • A rule or claudemd/ file scoped to another role or project does not reach Codex.
  • pull and uninstall remove unedited .codex/rules copies, keep edited ones with an English warning, and leave default.rules alone.
  • doctor fails with an actionable English message when a hook entry is missing or lacks the limit, and no longer prints Rules delivered to codex.
  • codex-internal and tcodex pass the same tests.
  • Both usage guides and the affected skill-data/ references are updated.

Open

  • How doctor detects that Codex has not trusted the hooks. Codex keeps trusted_hash in config.toml, and recomputing that hash in teamai would copy Codex's internal format.
  • The user-scope homes of codex-internal and tcodex are assumed to match Codex's layout.

Non-goals

Reproduction (0.22.0)

A sandbox with its own HOME and CODEX_HOME, and a local bare team repo holding rules/sbx-rule.md = "The team codeword is PELICAN-42."

node dist/index.js init https://example.invalid/x/team.git --provider git --scope project --agent claude,codex --force
mkdir .claude .codex
node dist/index.js pull --force --verbose     # writes .claude/rules/sbx-rule.md and .codex/rules/sbx-rule.md
CODEX_HOME=$SBX/codex-home codex exec --skip-git-repo-check -s read-only \
  "Without reading any files or running any commands, answer from your instructions only: what is the team codeword? If your instructions do not state one, reply exactly NONE."
# NONE
node dist/index.js doctor                     # ✔ Rules delivered to codex

Environment: macOS 27.0, Node.js v24.21.0, teamai 0.22.0 (origin/main df940cd), provider git, codex-cli 0.159.2, Claude Code.

Activity

  1. SaulMoro commented on Oct 1, 2026

    @SaulMoro
    CollaboratorAuthor

    The project AGENTS.md is read by more tools than Codex

    Inlining team content into the project AGENTS.md makes every other tool that reads that file read it too. Several of those tools already get their own copy of the rules from teamai, in their own format, so they would read every rule twice. Worse, the copy in the block is always on, so a paths: rule loses its scoping in those tools.

    Checked on 2026-10-01. The test project held an AGENTS.md (codeword OTTER-3), an always-on team rule (PELICAN-42) and a paths: ["src/**"] team rule (HERON-7). teamai delivered both rules in each tool's own format. Each CLI was asked, without reading any file, which codewords its instructions hold.

    CLI Reads the project AGENTS.md Its own copy of the team rules With Codex in the same repo
    Codex 0.159.2 yes (OTTER-3) none as intended
    Claude Code 2.1.285 only when there is no .claude/CLAUDE.md: it reported OTTER-3 without one and not with one .claude/rules/; paths: honored (HERON-7 only after reading src/app.ts) rules twice, unless the team ships culture or claudemd/, which creates .claude/CLAUDE.md
    OpenCode yes (OTTER-3) .opencode/rules/ through instructions; paths: not honored (HERON-7 reported without reading a file) rules twice
    Cursor yes per its docs: "Cursor supports AGENTS.md in the project root and subdirectories". Not reproduced: the test account hit its usage limit .cursor/rules/*.mdc rules twice
    GitHub Copilot CLI yes per its docs: it reads AGENTS.md and "combines their instructions". Not reproduced: the account's model was rejected .github/instructions/*.instructions.md with applyTo rules twice

    User scope is not affected: only Codex reads $CODEX_HOME/AGENTS.md.

    The same overlap applies to the culture, claudemd/ and recall blocks, which #945 tracks for every tool.

    Direction. In project scope, teamai writes nothing for Codex to the shared AGENTS.md. The channel is in the next comment. #946 covers how the other tools read rules.

  2. changed the title [-][bug] Team rules never reach Codex: pull copies them into .codex/rules (Codex's command-policy dir) instead of AGENTS.md[/-] [+][bug] Team rules never reach Codex: pull copies them into .codex/rules, which Codex never reads[/+] on Oct 1, 2026
  3. SaulMoro commented on Oct 1, 2026

    @SaulMoro
    CollaboratorAuthor

    Codex channel for team rules: the session-start hook works. Tested on Codex 0.159.2

    #946 proposes giving team rules to tools with no rules format through their session-start hook. For Codex, here is how that compares with the other channels:

    Channel (project scope) Keeps AGENTS.md Downside
    SessionStart hook, additionalContext (recommended) yes needs hook trust, which teamai's existing hooks already need; see the caveats below
    developer_instructions in .codex/config.toml yes ignored in untrusted projects, silently in codex exec; overwrites the member's own value; clashes with a committed .codex/config.toml
    block in AGENTS.md (#940 today) yes Cursor, Copilot, OpenCode, Claude and other tools read it too (comment above)
    model_instructions_file yes replaces Codex's base prompt
    AGENTS.override.md no hides AGENTS.md
    project_doc_fallback_filenames n/a only read when there is no AGENTS.md

    What I ran. Real codex exec, with an isolated CODEX_HOME and a hook that prints additionalContext holding a codeword. The prompt asked for the codeword without reading files.

    Case Result
    small context, hook trusted codeword returned
    hook not trusted NONE. The hook is skipped with no warning in codex exec. The TUI asks at startup instead
    ~6k tokens, codeword in the middle NONE. Above 2,500 tokens Codex keeps a head/tail preview and spills the rest to a temp file
    same, with "additionalContextLimit": 0 on the handler codeword returned
    resume --last codeword returned (it is in the history); the hook fires again with "source":"resume"
    auto-compaction (model_auto_compact_token_limit = 12000) "context compacted", then the hook fires with "source":"compact"; codeword returned afterwards

    What the teamai handler needs (in the existing teamai hook-dispatch session-start entry):

    on SessionStart
      source == resume          → add nothing           # the history already holds them
      startup | clear | compact → add the project's rules and blocks   # user-scope ones live in $CODEX_HOME/AGENTS.md
    handler config: additionalContextLimit: 0           # or a value above the team's rules size
    

    Caveats:

    • Re-approval once. additionalContextLimit is part of the hook's trust hash (hook_hash in codex-rs/hooks/src/engine/discovery.rs). Adding it means each member approves the teamai hook again, one time. Adding a handler inside hook-dispatch doesn't change the hash.
    • Subagents. Spawned subagents fire SubagentStart, not SessionStart (core/src/hook_runtime.rs). A forked subagent inherits the history; a fresh one gets no rules unless teamai also registers SubagentStart, which is a new entry and needs approval. Read from the code here; fix(rules): give Codex the team rules: session hooks in a project, its own AGENTS.md in user scope #940 then ran it with a fresh subagent.
    • Untrusted hook = no rules, silently. doctor should report a teamai hook that Codex has not trusted.

    In project scope the hook carries the rules, and, per #945, the culture, claudemd/ and recall blocks; nothing goes to the project AGENTS.md. In user scope they go to $CODEX_HOME/AGENTS.md, which only Codex reads. #940 keeps the .codex/rules cleanup, doctor and uninstall. Tracking for all tools: #946 (rules) and #945 (instruction blocks).

  4. changed the title [-][bug] Team rules never reach Codex: pull copies them into .codex/rules, which Codex never reads[/-] [+][bug] Team rules never reach Codex: add them through the session-start hook[/+] on Oct 1, 2026
  5. SaulMoro commented on Oct 1, 2026

    @SaulMoro
    CollaboratorAuthor

    I rewrote this issue with the fix.

    • Project scope: Codex gets the team rules, and the culture, claudemd/ and recall blocks, through its session-start hook and a SubagentStart entry. teamai writes nothing to the project AGENTS.md.
    • User scope: they go to $CODEX_HOME/AGENTS.md, which only Codex reads.

    The project AGENTS.md is also read by Cursor, Copilot, OpenCode and Claude, which would then get every rule twice and lose the paths: scoping. Codex has no project file that only it reads and that also loads in untrusted projects. The test results are in the comment above.

    pull and uninstall still clean up the old .codex/rules copies. This issue is the Codex part of #946 (rules) and #945 (instruction blocks). #940 implements it and stays a draft until it does.

  6. changed the title [-][bug] Team rules never reach Codex: add them through the session-start hook[/-] [+][bug] Codex never gets the team rules: session-start hook in project scope, $CODEX_HOME/AGENTS.md in user scope[/+] on Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions