codex-project-instructions¶
Diagnose Codex instruction selection and the cumulative project byte limit
| Severity | warning (disabled) |
| Autofix | - |
| Since | v0.23.0 |
| Repo Types | agents-md, codex-project |
| Category | OpenAI Codex |
Why¶
OpenAI Codex reads instruction files such as AGENTS.md to learn how to work
in your repository. These files can live at the project root and in
subdirectories. Codex combines the files that apply to your working directory.
Codex limits their combined size to 32 KiB by default. If they exceed that limit, some instructions are left out, even though each file may seem small enough on its own. Guidance you wrote in a child directory may never reach Codex.
This rule checks which files Codex would select for the project root and working directory you specify. It then checks their combined byte usage and warns when the limit would cut off a file or leave later files out entirely. The rule is disabled by default; enable it when you want to check Codex's project instructions.
For example, these two files exceed the default budget together:
| Selected file | File size | Bytes loaded | Bytes lost |
|---|---|---|---|
AGENTS.md |
18 KiB | 18 KiB | 0 |
services/payments/AGENTS.md |
18 KiB | 14 KiB | 4 KiB |
The existing context-budget rule still checks estimated tokens per file.
Inspect a working directory¶
Pass the project root as the path and the working directory relative to it:
The report shows the selected files in loading order, how many bytes each
uses, and the running total. Truncated or omitted lists files that lose
content. It also shows where the settings came from and what skillsaw assumed.
Add --format json for machine-readable output.
The report keeps the working directory you requested (requested_cwd) separate
from its resolved absolute path (cwd). If the requested directory is missing,
outside the root, or is a file, JSON cwd is null and the report is incomplete.
An Incomplete result means skillsaw could not inspect part of the chain.
Check the reported paths, permissions, and exclusions before relying on the
byte count. skillsaw does not skip an inaccessible override and assume Codex
will use another file.
How to fix¶
Shorten the selected instruction files, or raise project_doc_max_bytes in
the Codex configuration you use. Moving text between selected files does not
help: they still share the budget. There is no autofix.
Enable the check in CI¶
Add the working directory and enable the rule in .skillsaw.yaml:
codex-instructions:
cwd: services/payments
rules:
codex-project-instructions:
enabled: true
severity: warning
Then run:
--strict makes warnings fail CI; --fail-on warning also works. The tree
command is for inspection: it exits 0 when it can compute the result, even if
instructions are cut off, and 1 when the result is incomplete.
Which settings skillsaw uses¶
skillsaw starts with the Codex defaults: 32,768 bytes and no fallback
filenames. It reads project_doc_max_bytes and
project_doc_fallback_filenames from .codex/config.toml files between the
supplied root and working directory. For each setting, the nearest file wins.
A fallback list replaces the earlier list rather than extending it.
Byte limits must be non-negative integers no larger than
9,223,372,036,854,775,807, the maximum accepted by Codex's TOML parser.
For both instruction settings, skillsaw also checks integers nested in arrays
or tables before merging values. An integer outside the signed 64-bit range
makes the config unreadable to Codex, even if a later setting overrides it;
skillsaw reports that analysis as incomplete. This check does not validate
unrelated Codex settings.
To supply values from a global config, profile, or CLI flag, set them explicitly
in .skillsaw.yaml. These values take priority for both tree and lint:
codex-instructions:
cwd: services/payments
project_doc_max_bytes: 65536
project_doc_fallback_filenames: [TEAM_GUIDE.md, .agents.md]
These settings tell skillsaw what to check. They do not change Codex's configuration. skillsaw never reads global, managed, profile, or CLI settings.
| Setting | Special values |
|---|---|
cwd |
Omitted or null means the supplied root. tree --cwd overrides it. |
project_doc_max_bytes |
Omitted or null uses project config, then the default. 0 means no project instructions load. |
project_doc_fallback_filenames |
Omitted or null uses project config, then the default. [] disables fallbacks. |
Which files Codex selects¶
Codex visits each directory from the root to the working directory, including both ends. It selects at most one file per directory, in this order:
AGENTS.override.mdAGENTS.md- The first existing file in the configured fallback list
For services/payments, the directories are the root, services, and
services/payments. Siblings and deeper directories do not contribute.
The final fallback list applies to every directory on this path.
An empty override still wins. Codex selects the file before reading it. If that file is empty or contains only whitespace, Codex does not try the standard file or a fallback. A directory with a candidate filename is skipped.
Fallback names are trimmed and duplicates removed. Entries must be filenames:
skillsaw ignores ., .., and names containing / or NUL; on Windows it also
ignores names containing \ or :. Symlinks are supported within the allowed
scope. If two selected paths point to the same file, its bytes count twice.
How bytes are counted¶
Codex reads each selected file using the budget left by earlier files. Once
the budget reaches zero, it stops loading files. The report still lists those
later selections as omitted, including when the configured limit is zero.
The byte report gets full file sizes from metadata and reads only the part
that fits in the remaining budget. It processes those bytes in fixed-size
chunks, so raising the limit does not require holding the selected text in
memory. Reading time still grows with the number of bytes inspected.
- Count bytes before decoding. Codex cuts the raw bytes to fit the remaining budget, then decodes UTF-8. Invalid or cut-off characters become replacement characters. A byte-order mark (BOM) and CRLF line endings count toward the limit.
- Whitespace-only content is skipped. If the part read is empty or contains only
Unicode whitespace, Codex drops it without spending any bytes. The
emptystatus describes that part;truncated: truecan still mean a suffix was lost. - Added text is separate. The two newlines (
\n\n) between included files and any extra bytes from UTF-8 replacement characters do not count toward the limit. The final rendered project text can therefore exceed it. Global, user, and thread instructions and prompt wrappers are also outside this budget.
The report distinguishes file size, bytes read, bytes counted against the
budget (charged_bytes), the running total (cumulative_bytes), and the size
of the rendered project text.
Assumptions and limits¶
This check assumes one trusted local project. Codex 0.162.1 skips project
instructions for an untrusted project. skillsaw does not inspect that trust
decision or observe a running Codex session. JSON complete: true means the
calculation succeeded under the report's assumptions.
Full Codex configuration validation is outside this check. One known parsing
difference is an overflowing float literal such as 1e400: Codex rejects it,
while skillsaw can report a complete result if a later setting replaces it.
complete: true therefore does not guarantee that Codex will accept the
configuration.
You choose the root. skillsaw does not search parent directories for root markers. Without a root marker, Codex normally uses only the working directory; pass that directory as skillsaw's root to check this case. A nested Git repository may need its own root. Remote execution and shared budgets across multiple environments are not modeled.
skillsaw respects excluded directories and lint-external-content: false.
Excluded, unreadable, unresolved, or out-of-root instruction or config paths
make the result incomplete. An exclusion for a file that does not exist has no
effect on selection. Excluding the working directory still produces a finding
at the supplied root, even if it contains no instruction files. Global and user
instruction files are never read.
Standard content checks recognize AGENTS.override.md. They discover custom
fallbacks when this analysis is requested. A selected fallback matched by
content-paths receives the instruction role and its per-file token budget.
The instruction-file-valid rule checks override and fallback prose for empty
content and read failures; Codex's lossy decoding and byte accounting still
apply independently. An override loaded as a plugin agent, command, rule,
or configured OpenCode instruction keeps that role and its existing checks.
Its full file bytes still count if Codex selects it. The content checks also apply when a plugin's
README.md shares a file with an override through a symlink, or is selected
as a fallback. Known configuration files keep their configuration checks even
when named as fallbacks. Other hosts'
files count toward the Codex budget only if explicitly configured as fallbacks.
An explicit working directory can reach instructions inside directories such as
vendor/ that the ordinary repository scan skips. Those selected files also
count as repository-type evidence, so rules configured with enabled: auto
can run. skillsaw explain uses the same configured working directory when
showing whether a rule is enabled. Explicit exclusions and the external-content
policy still apply.
Selected .codex/ layers also receive the existing hook checks for both
hooks.json and inline hooks in config.toml. Hook discovery does not change
which instruction files count toward the byte limit.
Sources¶
The selection and byte rules were verified against the released
Codex 0.162.1 loader,
its configuration code,
and local codex debug prompt-input checks. The
official guide
explains the default limit and file precedence.
Configuration¶
Run skillsaw explain codex-project-instructions to see this documentation and the rule's effective configuration in your terminal.