> For the complete documentation index, see [llms.txt](https://faction-os.gitbook.io/faction-os-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/phases/phase_09/prd_phase_09.md).

# PRD Phase 09: Codex Provider-Neutral Foundation

**Status**: Complete **Sessions**: 3 **Estimated Duration**: 3-6 days

**Progress**: 3/3 sessions (100%)

***

## Overview

Phase 09 turns the Claude-centered hook and ingest foundation into a provider-neutral base that can accept OpenAI Codex CLI events without changing current Claude Code behavior. It owns shared protocol naming, Codex-safe event types, hook runtime normalization, and the first Codex hook map and handlers.

The phase must preserve FactionOS as local-first and privacy-safe. Hook handlers must continue to post bounded event summaries only. Raw prompts, patch bodies, command output, transcript contents, MCP arguments, absolute paths, token-like values, and provider credentials must not be emitted.

***

## Source Baseline

Current FactionOS wiring is Claude-centered:

* `apps/hooks/hooks.json` is a Claude Code hook map installed into `~/.claude/settings.json`.
* `apps/hooks/src/*` handlers are named and commented as Claude Code handlers, but much of their payload shaping already resembles Codex hook vocabulary.
* `apps/cli/src/commands/init.js` writes `~/.factionos/settings.json`, backs up Claude settings, merges FactionOS-managed hooks, sets `CLAUDE_PLUGIN_ROOT`, and defaults `settings.cli` to `claude-code`.
* `apps/cli/src/commands/uninstall.js` delegates to the hook package Claude uninstaller.
* `packages/protocol/src/heroes.ts` defines `HeroCli` without `codex-cli`.
* `packages/protocol/src/ingest.ts` names the lifecycle union `CLAUDE_HOOK_EVENT_NAMES`, even though `/event` is already tolerant enough to accept compatibility payloads.
* `apps/server/src/lib/eventIngest.ts` dispatches on `eventName ?? hook`, then recognizes selected `type`-only compatibility payloads.
* `docs/api/event-api-hook-contracts.md`, `README.md`, `apps/hooks/README_hooks.md`, and `apps/cli/README_cli.md` document Claude as the only installed hook path.

Useful existing behavior to preserve:

* Hook handlers are dependency-light Node scripts.
* Normal hook runs are silent and timeout-bound.
* Server-down failures spool sanitized local recovery entries.
* The listener is local-only, bounded, and non-executing.
* `/event` already accepts `sessionId`, `heroId`, `cli`, `cwd`, `modelId`, `tool`, `toolUseId`, `command`, `path`, `permission_request`, `subagent_spawn`, and `subagent_complete`.
* CLI `status` and `doctor` already avoid raw local data and inspect hook, listener, spool, orchestration, isolation, and hosted-operation posture.

***

## Codex CLI Constraints

Authoritative OpenAI docs were reviewed on 2026-05-31:

* Codex hooks: `https://developers.openai.com/codex/hooks`
* Codex configuration reference: `https://developers.openai.com/codex/config-reference#configtoml`
* Codex CLI slash commands: `https://developers.openai.com/codex/cli/slash-commands`
* Codex CLI reference: `https://developers.openai.com/codex/cli/reference#global-flags`

Design against these constraints:

* Codex supports lifecycle hooks through `hooks.json` or inline `[hooks]` tables in `config.toml`.
* Useful hook locations include `~/.codex/hooks.json`, `~/.codex/config.toml`, `<repo>/.codex/hooks.json`, and `<repo>/.codex/config.toml`.
* Project-local `.codex` config and hooks load only after the project is trusted.
* Non-managed command hooks must be reviewed and trusted in Codex before they run. FactionOS should guide users to `/hooks`; it must not bypass trust by default.
* Supported hook events include `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PermissionRequest`, `PostToolUse`, `SubagentStart`, `SubagentStop`, `Stop`, `PreCompact`, and `PostCompact`.
* Command hooks receive one JSON object on stdin. Common fields include `session_id`, `transcript_path`, `cwd`, `hook_event_name`, `model`, and `permission_mode`.
* `PreToolUse`, `PermissionRequest`, and `PostToolUse` can match `Bash`, `apply_patch`, and MCP tool names. For `apply_patch`, Codex also accepts `Edit` and `Write` matcher aliases, while hook input still reports `tool_name: "apply_patch"`.
* `PostToolUse` happens after a tool has already run and cannot undo side effects.
* Codex exposes built-in slash commands such as `/hooks`, `/mcp`, `/status`, `/debug-config`, `/plan`, `/goal`, `/review`, `/agent`, `/apps`, and `/plugins`. FactionOS must not assume custom slash commands unless a later Codex feature explicitly supports them.
* Project `.codex/config.toml` cannot override provider, auth, notification, profile, telemetry, and related machine-local keys. Provider and auth setup must stay user-owned.

***

## Provider-Neutral Architecture

Use a provider-neutral hook runtime with provider-specific hook maps:

```
apps/hooks/
  hooks.json
  hooks.claude.json
  hooks.codex.json
  src/
    _lib.js
    providers/
      claude.js
      codex.js
    factionos-*.js
    factionos-codex-subagent-start.js
  scripts/
    install-claude.js
    uninstall-claude.js
    install-codex.js
    uninstall-codex.js
```

Keep `apps/hooks/hooks.json` as a compatibility alias or copy of `hooks.claude.json` for one release cycle so existing tests, scripts, and docs references do not break abruptly.

Use `~/.codex/hooks.json` as the default Codex install target. Avoid mutating `~/.codex/config.toml` for the initial integration because hooks are enabled by default and TOML merging adds risk. Treat project-local `.codex/hooks.json` as an explicit later option such as `factionos init --cli codex --scope project`.

Codex hook commands should be absolute or resolved from a stable install root. For direct user-level installs, prefer commands shaped like:

```json
{
  "type": "command",
  "command": "FACTIONOS_CLI=codex-cli node /absolute/path/to/apps/hooks/src/factionos-hero-spawn.js",
  "timeout": 30,
  "statusMessage": "Reporting FactionOS session start"
}
```

Do not require `CODEX_HOME`. Respect it when present by resolving the Codex home as `process.env.CODEX_HOME || ~/.codex`.

***

## Provider Contract Details

Protocol changes belong in `packages/protocol` first:

* Add `"codex-cli"` to `HeroCli`.
* Add display metadata helpers for CLI labels if the web app currently uses raw strings in many places.
* Rename `CLAUDE_HOOK_EVENT_NAMES` to a provider-neutral `AGENT_HOOK_EVENT_NAMES` or `FACTIONOS_HOOK_EVENT_NAMES`; keep a deprecated alias export for compatibility.
* Include Codex-relevant hook events: `SubagentStart`, `PreCompact`, and `PostCompact`.
* Add optional ingest fields that Codex provides and FactionOS may safely store or summarize: `turnId`, `permissionMode`, `hookEventName`, `agentId`, `agentType`, `toolName`, and compact `mcpToolName`.
* Keep `transcript_path` and `transcriptPath` out of promoted event payloads except as local-only handler input used for safe ID derivation.

Hook runtime changes should extend `_lib.js` with normalization helpers instead of duplicating handler logic:

* `detectCli()` returns `codex-cli` when `FACTIONOS_CLI=codex-cli` is set.
* `hookEventName(event)` reads `event.hook_event_name`, `event.eventName`, or `event.hook`.
* `resolveSessionId(event, tty)` continues reading `session_id` and `sessionId`.
* `toolName(event)` reads `tool_name`, `tool`, or provider-specific aliases.
* `toolInput(event)` reads `tool_input` and returns an object.
* `modelId(event)` reads `model`, `modelId`, or provider-specific env fallbacks.
* `permissionMode(event)` reads `permission_mode` and maps it to compact diagnostic metadata.
* `promptText(event)` reads Codex `prompt` and Claude `user_message`.
* `subagentMetadata(event)` prefers Codex `agent_id` and `agent_type`, then falls back to the current Claude transcript-path parser.

Provider-specific gaps to keep explicit:

* Codex has no Claude `AskUserQuestion` matcher in the reviewed docs. Keep the existing Claude input-wait hooks, but do not claim Codex awaiting-input parity unless a real Codex tool event is found and tested.
* Codex file reads are not equivalent to Claude `Read` hooks. The Codex MVP should observe `apply_patch` edits and relevant MCP filesystem calls, then document that read-only file inspection may not be hook-visible.
* Codex `PostToolUse` cannot undo executed tools. FactionOS must treat it as observability and feedback only.

***

## Codex Hook Map

Initial `apps/hooks/hooks.codex.json` should cover:

| Codex event         | Matcher                         | Handler                                               | FactionOS event intent                                                    |
| ------------------- | ------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------- |
| `SessionStart`      | \`startup                       | resume                                                | clear                                                                     |
| `UserPromptSubmit`  | omitted                         | `factionos-hero-active.js`                            | Start or reuse active mission.                                            |
| `Stop`              | omitted                         | `factionos-hero-idle.js`                              | Complete mission or return hero to idle.                                  |
| `PreToolUse`        | `Bash`                          | `factionos-git-guard.js`, `factionos-bash-command.js` | Guard dangerous commands only in restricted mode; report command preview. |
| `PreToolUse`        | \`apply\_patch                  | Edit                                                  | Write\`                                                                   |
| `PostToolUse`       | \`Bash                          | apply\_patch                                          | mcp\_\_.\*\`                                                              |
| `PermissionRequest` | \`Bash                          | apply\_patch                                          | mcp\_\_.\*\`                                                              |
| `SubagentStart`     | omitted or selected agent types | new `factionos-subagent-start.js`                     | Emit `subagent_spawn` from Codex `agent_id` and `agent_type`.             |
| `SubagentStop`      | omitted or selected agent types | `factionos-subagent-complete.js`                      | Emit `subagent_complete` from Codex agent fields.                         |
| `PreCompact`        | \`manual                        | auto\`                                                | optional compact diagnostics handler                                      |
| `PostCompact`       | \`manual                        | auto\`                                                | optional compact diagnostics handler                                      |

Do not add Codex hooks for every possible tool on day one. Start with events that map to current product behavior, then add MCP-specific detail only after tests prove the shape and privacy treatment.

***

## Progress Tracker

| Session | Name                                       | Status   | Est. Tasks | Validated |
| ------- | ------------------------------------------ | -------- | ---------- | --------- |
| 01      | Contracts and Naming Baseline              | Complete | \~14-20    | PASS      |
| 02      | Hook Runtime Normalization                 | Complete | \~16-24    | PASS      |
| 03      | Codex Hook Map and Codex-Specific Handlers | Complete | \~16-24    | PASS      |

***

## Completed Sessions

* Session 01: Contracts and Naming Baseline
* Session 02: Hook Runtime Normalization
* Session 03: Codex Hook Map and Codex-Specific Handlers

***

## Upcoming Sessions

None for Phase 09.

***

## Objectives

1. Add `codex-cli` as a first-class provider in shared protocol contracts.
2. Rename Claude-specific ingest names behind backward-compatible aliases.
3. Normalize hook runtime inputs so Claude and Codex payloads can share safe posting, spooling, logging, and redaction behavior.
4. Add the initial Codex hook map and Codex-specific handler coverage.

***

## Prerequisites

* Phase 08 completed and release posture reviewed.
* Codex source baseline and provider-neutral architecture sections in this phase PRD reviewed.
* Current Claude hook behavior, protocol tests, hook tests, and ingest docs understood before changing shared names.
* Current OpenAI Codex hook documentation checked before fixture updates.

***

## Technical Considerations

### Architecture

Shared CLI/provider identifiers belong in `packages/protocol` before server, web, hooks, or CLI code consumes them. Hook-specific differences should be isolated in provider normalization helpers rather than branching throughout handlers.

### Technologies

* TypeScript shared contracts in `packages/protocol`
* JavaScript hook handlers in `apps/hooks`
* JSON hook maps for Claude Code and Codex CLI
* Vitest or existing package test runners for protocol and hook fixtures

### Risks

* Provider naming churn can create broad regressions: keep compatibility aliases and change external docs/source names incrementally.
* Codex hook payloads may evolve: keep source-backed fixtures and isolated normalization helpers.
* Patch or MCP payload leakage would be a privacy regression: summarize only bounded metadata and add redaction tests.

### Relevant Considerations

* \[P03-packages/protocol] **Protocol leads cross-package work**: provider and event naming changes should start in shared protocol contracts.
* \[P03-apps/cli+apps/hooks] **Lifecycle state is local and file-based**: provider normalization must keep existing hook state, logs, spool, backup, and listener behavior stable.
* \[P07] **Redaction is boundary-specific**: Codex hook boundaries need explicit minimization rather than broad payload forwarding.

***

## Success Criteria

Phase complete when:

* [x] All 3 sessions completed and validated.
* [x] `codex-cli` is represented in protocol contracts with compatibility for current Claude identifiers.
* [x] Shared hook runtime helpers accept Claude and Codex-shaped fixtures.
* [x] Codex lifecycle, Bash, `apply_patch`, permission, subagent, and optional compact events have bounded handler coverage.
* [x] Existing Claude behavior remains unchanged.

***

## Dependencies

### Depends On

* Phase 08: Release Hardening and Legacy Decommission

### Enables

* Phase 10: Codex Product Integration


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/phases/phase_09/prd_phase_09.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
