feat(trace): add Codex provider
Developers can record Codex sessions with chainloop trace init --codex or chainloop trace run --codex. Native hooks capture session rollouts, token usage and estimated cost, tool calls, and per-file attribution for multi-file patches and shell commands.
Codex conversations and tool exchanges use the message shape expected by the existing session viewer, so it renders their text, calls, and results. Each converted entry preserves its original event in source_event. Codex regression and E2E checks reject native-only conversations, malformed tool calls, and missing or unreadable matching tool results. The shared raw_session schema stays open, and other providers retain their existing formats and transcript checks. A common versioned transcript contract is deferred to a separate change.
The repository is initialized with project-local Codex hooks. The provider preserves existing user hooks, validates transcript paths and identity, and works with the shared local-storage pipeline. The Codex E2E harness isolates personal skills and preserves native model metadata when running through OpenRouter.
Implements R-001 through R-006 in docs/specs/issue-3657-codex-trace-provider.md.
Implements milestone 1 of #3657. Milestone 2 adds Codex skill tracking, spec copy pointers, and pasted-image capture. The task remains open until both milestones are delivered.
Codex hook commands skip successfully when chainloop is absent from PATH. When available, the wrapper preserves stdin, stdout, and exit status. A native commandWindows override avoids requiring a POSIX shell on Windows. Re-running init upgrades old commands while retaining user hooks. Each hook has a descriptive Chainloop Trace status label in the Codex hooks menu; init also upgrades previously unlabeled hooks. Hook definition changes require a new trust review in Codex. Follow-up for Claude and Cursor: #3687.
Session storage caching reloads the current record before saving its root, preserving metadata written during discovery. A damaged optional record no longer prevents copying a valid transcript from configured storage.
Validation
- Full CLI unit test suite passes, with Git signing disabled only for the test subprocess.
- Other-provider live E2E regression run: Claude Code 2.1.305 with Haiku 5.5 through OpenRouter and OpenCode 2.0.32 with
openrouter/anthropic/claude-haiku-5.5both pass, with no failed feature checks. Claude's first-party run was blocked by the account's weekly usage limit; the successful retry used OpenRouter. These installed versions are newer than the suite pins. Cursor was skipped as requested; Pi's unsupported column skips all features. - Codex CLI 0.163.0 /
openrouter/openai/gpt-6-luna: 22 feature checks pass, zero failures; 4 unsupported optional features are skipped, and 7 cells have no coverage. The run includes the new net contribution, session updates, and rename/rewrite checks from main. After narrowing validation to Codex, the live transcript check was rerun and passed. - Go formatting and
git diff --checkare clean. Change-scoped lint reports zero issues. Full lint still reports 77 existing issues. - Codex provider and E2E regressions cover normalized messages, matching readable tool results, original events, native output arrays, malformed tool calls, and rejection of native-only conversations. A regression verifies that the Codex checks do not constrain other provider formats. The targeted tests pass after narrowing the change.
- Actual platform renderer tested against new live E2E evidence: prompts, assistant content, calls, and nonempty tool results render. The original uploaded native evidence reproduces the empty conversation. This is a local renderer integration check, not a browser E2E test.
- Codex CLI 0.163.0 interactive verification: the welcome banner appears after the first user message, and the session link appears after push. Both compatibility cells are Yes; this manual verification is separate from local-mode E2E coverage.
- CLI reference regenerated; root README and provider compatibility tables updated from E2E results.
Limits
Child-session transcripts, skills tracking, spec source pointers, and pasted-image pointers are deferred. Control-plane uploads and headless hook-message delivery are not verified by this local-mode suite. Windows execution tests are present but skipped on the Linux validation host. In linked worktrees, Codex 0.163 discovers project hooks from the primary checkout; that checkout also needs the installed hooks. Previously uploaded native-only artifacts retain their original format; normalized output applies to new captures. Rollout format changes may require parser updates; cost uses standard API estimates rather than subscription billing.
AI assistance: Codex.
Provider checklist
Provider package (app/cli/internal/trace/<agent>/)
-
Nameconstant andvar _ trace.Provider = (*Provider)(nil). -
InstallHooks: a second call changes nothing. The hooks of the user stay. -
InstallHooksForTraceRun: all hooks except session end. -
SettingsFile: the file that install writes. -
UninstallHooks: removes only the Chainloop hooks. -
HooksInstalled: true only for the Chainloop hooks. - Hook events: session start, user prompt (if the agent has it), and session end.
- Hook events: before and after each file tool and shell tool, and after the skill tool (for skills tracking). (No skill tool integration in this provider.)
-
ReadHookInput: typed struct, size limit, absoluteFilePath,CwdandTranscriptPath,ToolUseIDandAgentID,Command,AgentVersionandModelwhen the transcript does not hold them. (Multi-file patch paths are expanded into per-file inputs by the shared handlers; version comes from the rollout.) -
IsFileWritingToolandIsCommandTool: one Go slice is the source of each list (and of the plugin, if there is one). - Attribution strategy selected: snapshot (
CaptureFileSnapshot,ResolveBeforeContent,CleanupAfterEdit) or reverse edits (HookInput.Edits). - Shell tool sends pre and post hooks with the same
ToolUseID. -
CopySessionData: safe to repeat, checks paths from the payload, does not fail the hook when the agent or the transcript is missing. -
ParseSession: reads only the copy inopts.SessionDir. -
CopySessionDataandParseSession: no control plane and no network, so that local mode works. - Trace state only through the
*state.Store, so thattrace run --localworks outside a git repository. - Evidence: agent name and version, session ID and times, primary model, models used, model provider.
- Evidence: token usage (input, output, total, cache read, cache write).
- Evidence: cost from the agent, or from an embedded price table, or zero with a warning.
- Evidence: tools used, conversation counts, subagents (if the agent has them). Root-session tools and conversation counts are implemented; child-session capture is deferred.
- Evidence:
RawSession["main"]is nevernil. Each line is a JSON object. - Evidence: a warning for each data item that cannot be read.
- Session-start, prompt-submit, and post-tool responses: one JSON document each, and nothing for an empty message.
-
Supports*methods tell the truth about each channel. -
AnnounceToUserreturnstrace.ErrAnnounceUnsupportedwhen there is no channel. Codex has a documented announcement channel. - Optional:
SkillTracker,SpecCopyReplacer,PastedImageFinder, each with a compile-time check. Deferred in this provider; the compatibility table marks these features No. - Unit tests: hooks, parse with real
testdata/, announce responses, copy.
CLI wiring
- Registered in
providers/registry.go. -
traceProviderFlagsfield,any(),names(). -
--<agent>flag intrace init(with help text) and intrace run. -
chainloop trace hook <agent> …subcommands incmd/trace_hook.go, withskipActionOptsInit. - Pre-tool response written first, if the agent blocks tools without one. Not required by Codex.
-
providers/capabilities_test.goupdated. -
cmd/trace_init_providers_test.goandcmd/trace_init_test.goupdated. -
make generaterun for the CLI reference. CLI reference regenerated withgo generate ./app/cli/documentation; full API generation was unnecessary.
End-to-end tests and documentation
-
e2e/<agent>.goimplementse2e.Harness. - Harness in the
harnessesmap ofe2e/e2e_test.go. - Version and models in
e2e/config.yaml. - Suite run for the new column, with the results checked.
-
README.md: new column in each feature table, with values from the suite. -
README.md: a "Why not Yes" line for each cell that is not Yes. -
README.md: row in "How each agent is hooked in", and provider list at the top updated. - Spec in
docs/specs/for a large provider, with requirement IDs cited in the pull request. - License header year updated in each changed file.
-
make -C app/cli lintandmake -C app/cli testpass. CLI tests pass; full lint reports 77 existing issues. Change-scoped lint reports zero issues.