Repo workflow metadata lives in .github/github.json; keep that
file aligned with branch roles, validation gates, GitHub signal capabilities,
workflow names, docs routing, and local cleanup policy when those facts change.
Every Code is the product in this repository; code is the CLI shorthand.
Upstream Codex and just-every/code are provenance and import sources, not the
repo's product identity.
Rust implementation lives under code-rs:
- Crate names are prefixed with
code-. For example, thecorefolder's crate is namedcode-core. - When using format! and you can inline variables into {}, always do that.
- Treat
codex-rsas a read-only mirror ofopenai/codex:main; edit Rust sources undercode-rsinstead.
Completion/build step
- Always validate using
./build-fast.shfrom the repo root. This is the single required check and must pass cleanly. ./build-fast.shcan take 20+min to run from a cold cache!!! Please use long timeout when running./build-fast.shor waiting for it to complete.- Policy: All errors AND all warnings must be fixed before you’re done. Treat any compiler warning as a failure and address it (rename unused vars with
_, removemut, delete dead code, etc.). - Do not run additional format/lint/test commands on completion (e.g.,
just fmt,just fix,cargo test) unless explicitly requested for a specific task. - NEVER run rustfmt
- Before pushing to
main, run./pre-release.shto mirror the release preflight (dev-fast build, CLI smokes, workspace nextest).
Optional regression checks (recommended when touching the Rust workspace):
cargo nextest run --no-fail-fast— runs all workspace tests with the TUI helpers automatically enabled. The suite is green after the resume fixtures/git-init fallback updates; older Git builds may print a warning when falling back from--initial-branch, but tests still pass.- Focused sweeps stay quick and green:
cargo test -p code-tui --features test-helpers,cargo test -p code-cloud-tasks --tests, andcargo test -p mcp-types --tests.
When debugging regressions or bugs, write a failing test (or targeted reproduction script) first and confirm it captures the issue before touching code—if it can’t fail, you can’t be confident the fix works.
- Keep docs clean, clear, and current; prune stale instructions instead of piling on caveats.
- Avoid excessive verbosity; prioritize concise guidance over long narratives.
- Do not document minor or non-core features; focus on system-critical flows and expectations.
- Never commit temporary "working" docs, plans, or scratch notes.
The TUI enforces strict, per‑turn ordering for all streamed content. Every
stream insert (Answer or Reasoning) must be associated with a stable
(request_ordinal, output_index, sequence_number) key provided by the model.
- A stream insert MUST carry a non‑empty stream id. The UI seeds an order key
for
(kind, id)from the event'sOrderMetabefore any insert. - The TUI WILL NOT insert streaming content without a stream id. Any attempt to insert without an id is dropped with an error log to make the issue visible during development.
- Review staged changes before every commit:
git --no-pager diff --staged --stat(and skimgit --no-pager diff --stagedif needed). - Write a descriptive subject that explains what changed and why. Avoid placeholders like "chore: commit local work".
- Prefer Conventional Commits with an optional scope:
feat(tui/history): …,fix(core/exec): …,docs(agents): …. - Keep the subject ≤ 72 chars; add a short body if rationale or context helps future readers.
- Use imperative, present tense: "add", "fix", "update" (not "added", "fixes").
- For merge commits, skip custom prefixes like
merge(main<-origin/main):. Use a clear subject such asMerge origin/main: <what changed and how conflicts were resolved>.
Examples:
feat(tui/history): show exit code and duration for Exec cellsfix(core/codex): handle SIGINT in on_exec_command_begin to avoid orphaned childdocs(agents): clarify commit-message expectations
mainis the Every Code product branch and the GitHub default branch.- Use
just local-code-rebuildto rebuild the current branch into the PATH-resolved binary. - After
./build-fast.sh, runjust local-code-rebuildagain before release smoke checks; the fast build validates dev-fast artifacts, while the rebuild recipe owns the PATH-resolved release binary and embeds the package version. - Before leaving a local work session, run
just local-cleanup-space --applyto remove rebuildable target/cache artifacts while preservingcode-rs/target/release/code. - Use
just local-upstream-importonly from a cleanmainbranch. The helper fetchesupstream/main, merges it into the current Every Code branch, replays any commits listed inscripts/local/overlay-picks.txt, then rebuilds the release binary. - Commits already on the product branch persist automatically across future
upstream imports. They do not need to be duplicated in
scripts/local/overlay-picks.txt. - If you make a new Every Code fix that should remain part of the product, commit it through the normal task-branch/PR flow into the product branch first. Do not leave important local changes only as an unmerged side branch.
- Add a commit SHA to
scripts/local/overlay-picks.txtonly for a patch that intentionally lives outside the product branch and still needs to be cherry-picked in duringjust local-upstream-import. Keep the list ordered and comment each entry with the source branch or purpose. - Old side branches are archival context, not the runtime source of truth. They do not need to merge cleanly as branches; only the specific carried commits must cherry-pick cleanly onto the current product branch.
- If a legacy pick no longer cherry-picks cleanly, leave it commented out in
scripts/local/overlay-picks.txt, manually re-port the fix against current upstream, commit the new port on the product branch, then replace the old SHA in the manifest if you still want automatic replay. - For Every Code-owned surfaces, release steps, remote names, and conflict hot spots, see
docs/local-overlay.md.
When the user asks you to "push" local work:
- Never rebase in this flow. Do not use
git pull --rebaseor attempt to replay local commits. - Prefer a simple merge of
origin/maininto the current branch, keeping our local history intact. - If the remote only has trivial release metadata changes (e.g.,
codex-cli/package.jsonversion bumps), adopt the remote version for those files and keep ours for everything else unless the user specifies otherwise. - If in doubt or if conflicts touch non-trivial areas, pause and ask before resolving.
Quick procedure (merge-only):
- Commit your local work first:
- Review:
git --no-pager diff --statandgit --no-pager diff - Stage + commit:
git add -A && git commit -m "<descriptive message of local changes>"
- Review:
- Fetch remote:
git fetch origin - Merge without auto-commit:
git merge --no-ff --no-commit origin/main(stops before committing so you can choose sides) - Resolve policy:
- Default to ours:
git checkout --ours . - Take remote for trivial package/version files as needed, e.g.:
git checkout --theirs codex-cli/package.json
- Default to ours:
- Stage and commit the merge with a descriptive message, e.g.:
git add -A && git commit -m "Merge origin/main: adopt remote version bumps; keep ours elsewhere (<areas>)"
- Run
./build-fast.shand thengit push
The command execution flow in Code follows an event-driven pattern:
-
Core Layer (
code-rs/core/src/codex.rs):on_exec_command_begin()initiates command execution- Creates
EventMsg::ExecCommandBeginevents with command details
-
TUI Layer (
code-rs/tui/src/chatwidget.rs):handle_codex_event()processes execution events- Manages
RunningCommandstate for active commands - Creates
HistoryCell::Execfor UI rendering
-
History Cell (
code-rs/tui/src/history_cell.rs):new_active_exec_command()- Creates cell for running commandnew_completed_exec_command()- Updates with final output- Handles syntax highlighting via
ParsedCommand
This architecture separates concerns between execution logic (core), UI state management (chatwidget), and rendering (history_cell).
- All Auto Drive escape routing lives in
code-rs/tui/src/chatwidget.rs. TheChatWidget::auto_should_handle_global_eschelper decides whether the global Esc handler inapp.rsshould defer to Auto Drive, andChatWidget::handle_key_eventowns the actual stop / pause behaviour. When you need to tweak Esc semantics, update those two locations together. - The approval pane must never swallow Esc.
code-rs/tui/src/bottom_pane/auto_coordinator_view.rsintentionally lets Esc (and the other approval shortcuts) bubble back to the chat widget; keep this contract intact when editing the view layer. - Avoid adding additional Esc handlers elsewhere for Auto Drive flows. Doing
so breaks the modal-first ordering in
app.rsand prevents users from reliably stopping a run.
code-devin/home/azureuser/.bashrcnow auto-enables local crash capture for dev runs. It setsCODEX_TUI_RECORD_SESSION=1, chooses a per-runCODEX_TUI_SESSION_LOG_PATHunder~/.code/debug_logs/code-dev/, and forcesRUST_BACKTRACE=fullunless you already overrode it.- Existing terminal sessions do not pick up the updated
code-devalias automatically. In every already-open shell that you want to use for debugging, runsource ~/.bashrc(or restart the shell withexec bash). In tmux, do this once per pane/window before launchingcode-dev. - On startup,
code-devprints the exact session log path. Keep that path after a crash; it now contains Auto Drive coordinator decisions, countdown ticks, token metrics, and structured panic records with backtraces. - TUI panics are logged in both places: the per-run session JSONL log and the regular
critical.logunder Code's log directory. Check both when debugging long-running Auto Drive crashes. - If you want telemetry to leave the machine as well, configure
[otel]in~/.code/config.toml. The TUI andcode exec --auto ...now attach the OTEL logger layer, so exportedcode_otelevents and error-level crash logs are emitted when an exporter is configured.
- Start with
make_chatwidget_manual()(ormake_chatwidget_manual_with_sender()) to build aChatWidgetin isolation with in-memory channels. - Simulate user input by defining a small enum (
ScriptStep) and feeding key events viachat.handle_key_event(); seerun_script()intests.rsfor a ready-to-use helper that also pumpsAppEvents. - After the scripted interaction, render with a
ratatui::Terminal/TestBackend, then usebuffer_to_string()(wrapsstrip_ansi_escapes) to normalize ANSI output before asserting. - Prefer snapshot assertions (
assert_snapshot!) or rich string comparisons so UI regressions are obvious. Keep snapshots deterministic by trimming trailing space and driving commit ticks just like the existing tests do. - When adding fixtures or updating snapshots, gate rewrites behind an opt-in env var (e.g.,
UPDATE_IDEAL=1) so baseline refreshes remain explicit.
- The VT100 harness lives under
code-rs/tui/tests/vt100_chatwidget_snapshot.rs. It renders the liveChatWidgetUI into aTerminal<VT100Backend>so snapshots capture the exact PTY output the user sees (including frame chrome, composer rows, and streaming inserts). - Use
ChatWidgetHarnesshelpers fromcode_tui::test_helpersto seed history events and drainAppEvents. Callrender_chat_widget_to_vt100(width, height)for a single frame, orrender_chat_widget_frames_to_vt100(&[(w,h), ...])to simulate successive draws while streaming. - The harness now exports
layout_metrics()so tests can assert scroll offsets and viewport heights without spelunking through private fields. - Snapshots are deterministic: tests set
CODEX_TUI_FAKE_HOUR=12automatically so greeting text (“What can I code for you today?”) doesn’t oscillate. If you need a different hour in a test, override the env var before constructing the harness. - To add a new scenario, push history/events onto the harness, call
render_*_to_vt100, and eitherinsta::assert_snapshot!the frame(s) or manually assert string contents. For multi-frame streaming, push deltas/events first, then capture frames in the order the UI would display them. - Run all VT100 snapshots via:
cargo test -p code-tui --test vt100_chatwidget_snapshot --features test-helpers -- --nocapture
- When you intentionally change rendering, review the
.snap.newfiles that appear incode-rs/tui/tests/snapshots/and accept them withcargo insta review/cargo insta accept(limit to this test where possible).
- Use
scripts/wait-for-gh-run.shto follow GitHub Actions releases without spamming manualghcommands. - Typical release check right after a push:
scripts/wait-for-gh-run.sh --workflow Release --branch main. - If you already know the run ID (e.g., from webhook output), run
scripts/wait-for-gh-run.sh --run <run-id>. - Adjust the poll cadence via
--interval <seconds>(defaults to 8). The script exits 0 on success and 1 on failure, so it can gate local automation. - Pass
--failure-logsto automatically dump logs for any job that does not finish successfully. - Dependencies: GitHub CLI (
gh) andjqmust be available inPATH.