# Codex App Server Persisted

> This skill should be used when building a low-latency, long-lived Codex controller using `codex app-server` (JSON-RPC over stdio) to keep one PID alive across turns while preserving `sse_lines.jsonl` observability.

- Skill: `tankygranny05/codex-app-server-persisted` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tankygranny05/codex-app-server-persisted`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tankygranny05/codex-app-server-persisted/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: tankygranny05 (https://skillmd.com/u/tankygranny05)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/tankygranny05/codex-app-server-persisted

---


# Codex App Server Persisted
*[Created by Codex: 019b74f5-a7d5-7121-ac48-8e66cd2bdc92]*

## Purpose

Provide a repeatable workflow to keep a single Codex process running in memory via `codex app-server`, and drive multi-turn interactions by sending `thread/start` once and `turn/start` repeatedly on the same `threadId`.

## When To Use

- Need a warm, long-lived Codex PID to minimize turn-to-turn latency
- Need programmatic control over turns (JSON-RPC over stdio) instead of a TUI
- Need built-in observability via `sse_lines.jsonl` (works with `app-server`, not with `mcp-server`)

## Workflow

### 1) Confirm requirements

- Identify whether the goal is: single-controller (one process drives Codex) or multi-client daemon/broker.
- Identify whether approvals must be supported or bypassed (risk/permissions).
- Identify desired observability target: centralized `~/centralized-logs/codex/sse_lines.jsonl` or isolated `--log-dir`.

### 2) Start a long-lived app-server process

- Spawn `codex app-server` as a subprocess with `stdin=PIPE` and keep stdin open for the lifetime of the controller.
- Read stdout line-by-line and parse each line as JSON (JSON-RPC-like).
- Treat stderr as inherited or actively drained to avoid deadlocks.

### 3) Create a thread once, then reuse it

- Send `initialize`.
- Send `thread/start` and store `threadId`.
- For each user prompt, send `turn/start` with the same `threadId`.

### 4) Stream events and detect completion

- Expect notifications interleaved with responses on stdout.
- Print/collect assistant output using `codex/event/agent_message_content_delta`.
- Consider a turn complete when either:
  - notification method `codex/event/task_complete` arrives, or
  - notification method `turn/completed` arrives.

### 5) Handle approvals if enabled

- Detect server→client JSON-RPC requests (messages that include both `method` and `id` but no `result`).
- For V2 approval requests, handle at least:
  - `item/commandExecution/requestApproval`
  - `item/fileChange/requestApproval`
- Reply with a JSON-RPC response `{ "id": <same>, "result": { "decision": "accept" | "decline" } }`.

### 6) Validate observability logging

- Prefer to run `codex` with `--log-dir` when isolation is needed (creates `sse_lines.jsonl` under that directory).
- Otherwise, verify the centralized `~/centralized-logs/codex/sse_lines.jsonl` changes while the app-server PID stays alive.

## Bundled Resources

- Reference guide: `references/codex-app-server-persisted-process.md`
- Starter script: `scripts/app_server_persisted_repl.py`

