Where Claude Code and Codex keep /goal state, and how one open-source app reads both An open-source desktop app called Kiteline reads `/goal` state from both Claude Code and Codex by parsing two different storage formats: Claude Code writes `goal_status` attachment lines into its JSONL session transcripts, while Codex keeps goals in a `thread_goals` table inside `goals_N.sqlite` under `CODEX_HOME`. The implementation, in `watcher/kiteline-watch.py`, normalizes both sources into a single shape consumed by the phone, watch and desktop UIs, and handles edge cases such as read-only SQLite connections, WAL-change polling, truncated transcripts and detecting when a goal has stalled. Both Claude Code and Codex now have /goal : you give a session a condition that can be checked, and the agent keeps working round after round until the condition is met. It is a good fit for long, well-defined jobs such as "get every unit test passing" or "first paint under 1.5 s and Lighthouse above 90", the kind of task where an agent would otherwise stop halfway and write a confident summary. The interesting part for tool builders is that the two agents record goals in completely different places. This post walks through both formats, using the implementation in Kiteline https://github.com/hon6/kiteline , an open-source desktop app Mac, Windows, Linux that follows Claude Code, Codex and other agent sessions and shows their progress on a phone. All the code mentioned below is in watcher/kiteline-watch.py . goal status attachments in the transcript Claude Code writes each session as a JSONL transcript. Once a goal is set, extra lines appear with type: "attachment" and attachment.type: "goal status" . The fields tell you what happened: | Line | Meaning | |---|---| | {met: false, sentinel: true, condition} | Goal set | | {met: true, sentinel: true} | Goal cleared /goal clear , or an unrecoverable error | | {met: false, condition, reason} | One check: not met yet, reason says what is missing | | {met: true, condition, reason, iterations, durationMs, tokens} | Goal met, with rounds, time and tokens | | {failed: true, …} | The check decided the goal can't be met | The check at the end of each round is itself a model call that judges the condition and explains why. Pauses show up as system lines instead, such as Goal paused ·