Charley Cunningham
ccunningham@openai.com
90d · built 2026-05-28
90-day totals
- Commits
- 31
- Grow
- 5.8
- Maintenance
- 5.3
- Fixes
- 0.5
- Total ETV
- 11.6
Where this dev ranks
Percentile against the global top-100 leaderboard (all-time totals).
- By commits
- Top 100 %
- By Growth share
- Top 31 %
30-day trajectory
Last 30 days vs. the 30 days before. Up arrows on Growth and ETV mean improvement; up arrow on Fixes share means more time on fixes (worse).
Daily performance
Daily ETV, stacked by Growth, Maintenance and Fixes.
Work-mix over time
Share of Growth / Maintenance / Fixes over a rolling 7-day window. Reads as 'where is effort flowing right now'.
Bug flow over time
Monthly bug flow attributed to this developer. The left bar (red) is bug impact this dev authored that was addressed in the given month — combining bugs others fixed for them and bugs they fixed themselves. The right bar is fixes they personally shipped that month, split between self-fixes (overlap with the red bar) and fixes done for someone else. X-axis is fix-time, not introduction-time — the Navigara API attributes bugs backward to the author at the moment the fix lands.
- Self-fix share
- 15%
- Bugs you introduced
- 4.7
- Bugs you fixed
- 4.6
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
Most impactful commits
Top 20 by ETV in the 90-day window.
- 2.3ETVReuse guardian session across approvals (#14668) ## Summary - reuse a guardian subagent session across approvals so reviews keep a stable prompt cache key and avoid one-shot startup overhead - clear the guardian child history before each review so prior guardian decisions do not leak into later approvals - include the `smart_approvals` -> `guardian_approval` feature flag rename in the same PR to minimize release latency on a very tight timeline - add regression coverage for prompt-cache-key reuse without prior-review prompt bleed ## Request - Bug/enhancement request: internal guardian prompt-cache and latency improvement request --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · 6fdeb1d6 · 2026-03-16
- 1.8ETVAdd guardian approval MVP (#13692) ## Summary - add the guardian reviewer flow for `on-request` approvals in command, patch, sandbox-retry, and managed-network approval paths - keep guardian behind `features.guardian_approval` instead of exposing a public `approval_policy = guardian` mode - route ordinary `OnRequest` approvals to the guardian subagent when the feature is enabled, without changing the public approval-mode surface ## Public model - public approval modes stay unchanged - guardian is enabled via `features.guardian_approval` - when that feature is on, `approval_policy = on-request` keeps the same approval boundaries but sends those approval requests to the guardian reviewer instead of the user - `/experimental` only persists the feature flag; it does not rewrite `approval_policy` - CLI and app-server no longer expose a separate `guardian` approval mode in this PR ## Guardian reviewer - the reviewer runs as a normal subagent and reuses the existing subagent/thread machinery - it is locked to a read-only sandbox and `approval_policy = never` - it does not inherit user/project exec-policy rules - it prefers `gpt-5.4` when the current provider exposes it, otherwise falls back to the parent turn's active model - it fail-closes on timeout, startup failure, malformed output, or any other review error - it currently auto-approves only when `risk_score < 80` ## Review context and policy - guardian mirrors `OnRequest` approval semantics rather than introducing a separate approval policy - explicit `require_escalated` requests follow the same approval surface as `OnRequest`; the difference is only who reviews them - managed-network allowlist misses that enter the approval flow are also reviewed by guardian - the review prompt includes bounded recent transcript history plus recent tool call/result evidence - transcript entries and planned-action strings are truncated with explicit `<guardian_truncated ... />` markers so large payloads stay bounded - apply-patch reviews include the full patch content (without duplicating the structured `changes` payload) - the guardian request layout is snapshot-tested using the same model-visible Responses request formatter used elsewhere in core ## Guardian network behavior - the guardian subagent inherits the parent session's managed-network allowlist when one exists, so it can use the same approved network surface while reviewing - exact session-scoped network approvals are copied into the guardian session with protocol/port scope preserved - those copied approvals are now seeded before the guardian's first turn is submitted, so inherited approvals are available during any immediate review-time checks ## Out of scope / follow-ups - the sandbox-permission validation split was pulled into a separate PR and is not part of this diff - a future follow-up can enable `serde_json` preserve-order in `codex-core` and then simplify the guardian action rendering further --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · e84ee33c · 2026-03-07
- 1.6ETVtui: align pending steers with core acceptance (#12868) ## Summary - submit `Enter` steers immediately while a turn is already running instead of routing them through `queued_user_messages` - keep those submitted steers visible in the footer as `pending_steers` until core records them as a user message or aborts the turn - reconcile pending steers on `ItemCompleted(UserMessage)`, not `RawResponseItem` - emit user-message item lifecycle for leftover pending input at task finish, then remove the TUI `TurnComplete` fallback - keep `queued_user_messages` for actual queued drafts, rendered below pending steers ## Problem While the assistant was generating, pressing `Enter` could send the input into `queued_user_messages`. That queue only drains after the turn ends, so ordinary steers behaved like queued drafts instead of landing at the next core sampling boundary. The first version of this fix also used `RawResponseItem` to decide when a steer had landed. Review feedback was that this is the wrong abstraction for client behavior. There was also a late edge case in core: if pending steer input was accepted after the final sampling decision but before `TurnComplete`, core would record that user message into history at task finish without emitting `ItemStarted(UserMessage)` / `ItemCompleted(UserMessage)`. TUI had a fallback to paper over that gap locally. ## Approach - `Enter` during an active turn now submits a normal `Op::UserTurn` immediately - TUI keeps a local pending-steer preview instead of rendering that user message into history immediately - when core records the steer as `ItemCompleted(UserMessage)`, TUI matches and removes the corresponding pending preview, then renders the committed user message - core now emits the same user-message lifecycle when `on_task_finished(...)` drains leftover pending user input, before `TurnComplete` - with that lifecycle gap closed in core, TUI no longer needs to flush pending steers into history on `TurnComplete` - if the turn is interrupted, pending steers and queued drafts are both restored into the composer, with pending steers first ## Notes - `Tab` still uses the real queued-message path - `queued_user_messages` and `pending_steers` are separate state with separate semantics - the pending-steer matching key is built directly from `UserInput` - this removes the new TUI dependency on `RawResponseItem` ## Validation - `just fmt` - `cargo test -p codex-core task_finish_emits_turn_item_lifecycle_for_leftover_pending_user_input -- --nocapture` - `cargo test -p codex-tui`github.com-openai-codex · 299b8ac4 · 2026-03-03
- 1.2ETVtui: queue follow-ups during manual /compact (#15259) ## Summary - queue input after the user submits `/compact` until that manual compact turn ends - mirror the same behavior in the app-server TUI - add regressions for input queued before compact starts and while it is running Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · e838645f · 2026-03-23
- 0.7ETVAdd fork snapshot modes (#15239) ## Summary - add `ForkSnapshotMode` to `ThreadManager::fork_thread` so callers can request either a committed snapshot or an interrupted snapshot - share the model-visible `<turn_aborted>` history marker between the live interrupt path and interrupted forks - update the small set of direct fork callsites to pass `ForkSnapshotMode::Committed` Note: this enables /btw to work similarly as Esc to interrupt (hopefully somewhat in distribution) --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · f547b79b · 2026-03-24
- 0.5ETVtui: clarify pending steer follow-ups (#13841) ## Summary - split the pending input preview into labeled pending-steer and queued follow-up sections - explain that pending steers submit after the next tool call and that Esc can interrupt and send them immediately - treat Esc as an interrupt-plus-resubmit path when pending steers exist, with updated TUI snapshots and tests Queues and steers: <img width="1038" height="263" alt="Screenshot 2026-03-07 at 10 17 17 PM" src="https://github.com/user-attachments/assets/4ef433ef-27a3-4b7c-ad69-2046f6eb89e6" /> After pressing Esc: <img width="1046" height="320" alt="Screenshot 2026-03-07 at 10 17 21 PM" src="https://github.com/user-attachments/assets/0f4d89e0-b6b9-486a-9f04-b6021f169ba7" /> ## Codex author `codex resume 019cc6f4-2cca-7803-b717-8264526dbd97` --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · 4ad3b59d · 2026-03-09
- 0.5ETVAlign SQLite feedback logs with feedback formatter (#13494) ## Summary - store a pre-rendered `feedback_log_body` in SQLite so `/feedback` exports keep span prefixes and structured event fields - render SQLite feedback exports with timestamps and level prefixes to match the old in-memory feedback formatter, while preserving existing trailing newlines - count `feedback_log_body` in the SQLite retention budget so structured or span-prefixed rows still prune correctly - bound `/feedback` row loading in SQL with the retention estimate, then apply exact whole-line truncation in Rust so uploads stay capped without splitting lines ## Details - add a `feedback_log_body` column to `logs` and backfill it from `message` for existing rows - capture span names plus formatted span and event fields at write time, since SQLite does not retain enough structure to reconstruct the old formatter later - keep SQLite feedback queries scoped to the requested thread plus same-process threadless rows - restore a SQL-side cumulative `estimated_bytes` cap for feedback export queries so over-retained partitions do not load every matching row before truncation - add focused formatting coverage for exported feedback lines and parity coverage against `tracing_subscriber` ## Testing - cargo test -p codex-state - just fix -p codex-state - just fmt codex author: `codex resume 019ca1b0-0ecc-78b1-85eb-6befdd7e4f1f` --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · ebbbc52c · 2026-03-18
- 0.3ETVUse Shift+Left to edit queued messages in tmux (#15480) ## Summary - use Shift+Left to edit the most recent queued message when running under tmux - mirror the same binding change in the app-server TUI - add tmux-specific tests and snapshot coverage for the rendered queued-message hint ## Testing - just fmt - cargo test -p codex-tui - cargo test -p codex-tui-app-server - just argument-comment-lint -p codex-tui -p codex-tui-app-server Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · 5e3793de · 2026-03-23
- 0.3ETVfix(tui): clean up pending steer preview wrapping (#13642) ## Summary - render pending steer previews with a single `pending steer:` prefix instead of repeating it for each source line - reuse the same truncation path for pending steers and queued drafts so multiline previews behave consistently - add snapshot coverage for the multiline pending steer case Before <img width="969" height="219" alt="Screenshot 2026-03-05 at 3 55 11 PM" src="https://github.com/user-attachments/assets/b062c9c8-43d3-4a52-98e0-3c7643d1697b" /> After <img width="965" height="203" alt="Screenshot 2026-03-05 at 3 56 08 PM" src="https://github.com/user-attachments/assets/40935863-55b3-444f-9e14-1ac63126b2e1" /> ## Codex author `codex resume 019cc054-385e-79a3-bb85-ec9499623bd8` Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · e15e191f · 2026-03-06
- 0.3ETVapp-server: source /feedback logs from sqlite at trace level (#12969) ## Summary - write app-server SQLite logs at TRACE level when SQLite is enabled - source app-server `/feedback` log attachments from SQLite for the requested thread when available - flush buffered SQLite log writes before `/feedback` queries them so newly emitted events are not lost behind the async inserter - include same-process threadless SQLite rows in those `/feedback` logs so the attachment matches the process-wide feedback buffer more closely - keep the existing in-memory ring buffer fallback unchanged, including when the SQLite query returns no rows ## Details - add a byte-bounded `query_feedback_logs` helper in `codex-state` so `/feedback` does not fetch all rows before truncating - scope SQLite feedback logs to the requested thread plus threadless rows from the same `process_uuid` - format exported SQLite feedback lines with the log level prefix to better match the in-memory feedback formatter - add an explicit `LogDbLayer::flush()` control path and await it in app-server before querying SQLite for feedback logs - pass optional SQLite log bytes through `codex-feedback` as the `codex-logs.log` attachment override - leave TUI behavior unchanged apart from the updated `upload_feedback` call signature - add regression coverage for: - newest-within-budget ordering - excluding oversized newest rows - including same-process threadless rows - keeping the newest suffix across mixed thread and threadless rows - matching the feedback formatter shape aside from span prefixes - falling back to the in-memory snapshot when SQLite returns no logs - flushing buffered SQLite rows before querying ## Follow-up - SQLite feedback exports still do not reproduce span prefixes like `feedback-thread{thread_id=...}:`; there is a `TODO(ccunningham)` in `codex-rs/state/src/log_db.rs` for that follow-up. ## Testing - `cd codex-rs && cargo test -p codex-state` - `cd codex-rs && cargo test -p codex-app-server` - `cd codex-rs && just fmt`github.com-openai-codex · c4bd0aa3 · 2026-03-03
- 0.3ETVfix(ci): restore guardian coverage and bazel unit tests (#13912) ## Summary - restore the guardian review request snapshot test and its tracked snapshot after it was dropped from `main` - make Bazel Rust unit-test wrappers resolve runfiles correctly on manifest-only platforms like macOS and point Insta at the real workspace root - harden the shell-escalation socket-closure assertion so the musl Bazel test no longer depends on fd reuse behavior ## Verification - cargo test -p codex-core guardian_review_request_layout_matches_model_visible_request_snapshot - cargo test -p codex-shell-escalation - bazel test //codex-rs/exec:exec-unit-tests //codex-rs/shell-escalation:shell-escalation-unit-tests Supersedes #13894. --------- Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com> Co-authored-by: viyatb-oai <viyatb@openai.com> Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · 7ba1fccf · 2026-03-08
- 0.3ETVDefer initial context insertion until the first turn (#14313) ## Summary - defer fresh-session `build_initial_context()` until the first real turn instead of seeding model-visible context during startup - rely on the existing `reference_context_item == None` turn-start path to inject full initial context on that first real turn (and again after baseline resets such as compaction) - add a regression test for `InitialHistory::New` and update affected deterministic tests / snapshots around developer-message layout, collaboration instructions, personality updates, and compact request shapes ## Notes - this PR does not add any special empty-thread `/compact` behavior - most of the snapshot churn is the direct result of moving the initial model-visible context from startup to the first real turn, so first-turn request layouts no longer contain a pre-user startup copy of permissions / environment / other developer-visible context - remote manual `/compact` with no prior user still skips the remote compact request; local first-turn `/compact` still issues a compact request, but that request now reflects the lack of startup-seeded context --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · f5bb338f · 2026-03-11
- 0.2ETVUse workspace requirements for guardian prompt override (#14727) ## Summary - move `guardian_developer_instructions` from managed config into workspace-managed `requirements.toml` - have guardian continue using the override when present and otherwise fall back to the bundled local guardian prompt - keep the generalized prompt-quality improvements in the shared guardian default prompt - update requirements parsing, layering, schema, and tests for the new source of truth ## Context This replaces the earlier managed-config / MDM rollout plan. The intended rollout path is workspace-managed requirements, including cloud enterprise policies, rather than backend model metadata, Statsig, or Jamf-managed config. That keeps the default/fallback behavior local to `codex-rs` while allowing faster policy updates through the enterprise requirements plane. This is intentionally an admin-managed policy input, not a user preference: the guardian prompt should come either from the bundled `codex-rs` default or from enterprise-managed `requirements.toml`, and normal user/project/session config should not override it. ## Updating The OpenAI Prompt After this lands, the OpenAI-specific guardian prompt should be updated through the workspace Policies UI at `/codex/settings/policies` rather than through Jamf or codex-backend model metadata. Operationally: - open the workspace Policies editor as a Codex admin - edit the default `requirements.toml` policy, or a higher-precedence group-scoped override if we ever want different behavior for a subset of users - set `guardian_developer_instructions = """..."""` to the full OpenAI-specific guardian prompt text - save the policy; codex-backend stores the raw TOML and `codex-rs` fetches the effective requirements file from `/wham/config/requirements` When updating the OpenAI-specific prompt, keep it aligned with the shared default guardian policy in `codex-rs` except for intentional OpenAI-only additions. ## Testing - `cargo check --tests -p codex-core -p codex-config -p codex-cloud-requirements --message-format short` - `cargo run -p codex-core --bin codex-write-config-schema` - `cargo fmt` - `git diff --check` Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · 226241f0 · 2026-03-18
- 0.2ETVTrim pre-turn context updates during rollback (#15577) ## Summary - trim contiguous developer/contextual-user pre-turn updates when rollback cuts back to a user turn - add a focused history regression test for the trim behavior - update the rollback request-boundary snapshots to show the fixed non-duplicating context shape --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · 2d61357c · 2026-03-24
- 0.2ETVMove sqlite logs to a dedicated database (#13772) ## Summary - move sqlite log reads and writes onto a dedicated `logs_1.sqlite` database to reduce lock contention with the main state DB - add a dedicated logs migrator and route `codex-state-logs` to the new database path - leave the old `logs` table in the existing state DB untouched for now ## Testing - just fmt - cargo test -p codex-state --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · 4e6c6193 · 2026-03-06
- 0.1ETVguardian initial feedback / tweaks (#13897) ## Summary - remove the remaining model-visible guardian-specific `on-request` prompt additions so enabling the feature does not change the main approval-policy instructions - neutralize user-facing guardian wording to talk about automatic approval review / approval requests rather than a second reviewer or only sandbox escalations - tighten guardian retry-context handling so agent-authored `justification` stays in the structured action JSON and is not also injected as raw retry context - simplify guardian review plumbing in core by deleting dead prompt-append paths and trimming some request/transcript setup code ## Notable Changes - delete the dead `permissions/approval_policy/guardian.md` append path and stop threading `guardian_approval_enabled` through model-facing developer-instruction builders - rename the experimental feature copy to `Automatic approval review` and update the `/experimental` snapshot text accordingly - make approval-review status strings generic across shell, patch, network, and MCP review types - forward real sandbox/network retry reasons for shell and unified-exec guardian review, but do not pass agent-authored justification as raw retry context - simplify `guardian.rs` by removing the one-field request wrapper, deduping reasoning-effort selection, and cleaning up transcript entry collection ## Testing - `just fmt` - full validation left to CI --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · f23fcd6c · 2026-03-09
- 0.1ETVAdd guardian follow-up reminder (#15262) ## Summary - add a short guardian follow-up developer reminder before reused reviews - cache prior-review state on the guardian session instead of rescanning full history on each request - update guardian follow-up coverage and snapshot expectations --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · b3a4da84 · 2026-03-20
- 0.1ETVtui: restore draft footer hints (#13202) ## Summary - restore `Tab to queue` when a draft is present and the agent is running - keep draft-idle footers passive by showing the normal footer or status line instead of `? for shortcuts` - align footer snapshot coverage with the updated draft footer behavior ## Codex author `codex resume 019c7f1c-43aa-73e0-97c7-40f457396bb0` --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · 7979ce45 · 2026-03-02
- 0.1ETV[codex] Stabilize second compaction history test (#15605) ## Summary - replace the second-compaction test fixtures with a single ordered `/responses` sequence - assert against the real recorded request order instead of aggregating per-mock captures - realign the second-summary assertion to the first post-compaction user turn where the summary actually appears ## Root cause `compact_resume_after_second_compaction_preserves_history` collected requests from multiple `mount_sse_once_match` recorders. Overlapping matchers could record the same HTTP request more than once, so the test indexed into a duplicated synthetic list rather than the true request stream. That made the summary assertion depend on matcher evaluation order and platform-specific behavior. ## Impact - makes the flaky test deterministic by removing duplicate request capture from the assertion path - keeps the change scoped to the test only ## Validation - `just fmt` - `just argument-comment-lint` - `env -u CODEX_SANDBOX_NETWORK_DISABLED cargo test -p codex-core compact_resume_after_second_compaction_preserves_history -- --nocapture` - repeated the same targeted test 10 times --------- Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · 910cf492 · 2026-03-24
- 0.1ETVThread guardian Responses API errors into denial rationale (#15516) ## Summary - capture the last guardian `EventMsg::Error` while waiting for review completion - reuse that error as the denial rationale when the review turn completes without an assessment payload - add a regression test for the `/responses` HTTP 400 path ## Testing - `just fmt` - `cargo test -p codex-core guardian_review_surfaces_responses_api_errors_in_rejection_reason` - `just argument-comment-lint -p codex-core` ## Notes - `cargo test -p codex-core` still fails on the pre-existing unrelated test `tools::js_repl::tests::js_repl_imported_local_files_can_access_repl_globals` in this environment (`mktemp ... Operation not permitted` while downloading `dotslash`) Co-authored-by: Codex <noreply@openai.com>github.com-openai-codex · 332edba7 · 2026-03-23