thread_goals, continuation runtime, completion audit까지 코드 레벨로 보기
1편에서는 Codex CLI /goal을 사용자 관점에서 봤습니다. 이번 글에서는 내부 구조를 봅니다.
핵심은 간단합니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다./goal은 명령 하나가 아니다.목표 상태 저장소, app-server API, model tool, runtime continuation, TUI 제어가 결합된 기능이다.
이 글은 Codex GitHub PR과 공개된 소스 파일을 기준으로 작성했습니다. 출시 직후 기능이므로 실제 구현은 이후 버전에서 달라질 수 있습니다.
분석 기준일: 2026-05-02
기준 버전: Codex CLI0.128.0
주요 참고자료: OpenAI Codex changelog, GitHub PR #18073–#18077,thread_goalsmigration,continuation.md,budget_limit.md
핵심 요약
/goal은 TUI command → app-server API → model tools → core runtime → state DB로 이어지는 5개 레이어 기능입니다.- goal 상태는
thread_goals테이블에 저장되며, status는active,paused,budget_limited,complete로 제한됩니다. - model tool은 goal을 마음대로 조작하지 못합니다.
update_goal은 완료 처리 중심으로 제한되고, pause/resume/clear/budget-limited 전이는 사용자 또는 runtime 제어에 남습니다. - core runtime은
GoalRuntimeEvent를 통해 turn start, tool completion, turn finish, interrupt, resume, idle continuation을 처리합니다. - continuation prompt는 완료 전 “현재 실제 상태”를 기준으로 completion audit을 수행하라고 요구합니다.
- 좋은 agent 설계 관점에서
/goal의 핵심은while true가 아니라 event-driven continuation + evidence audit + budget guard입니다.
1. 전체 구조: 5개 레이어로 보기
코드 기준으로 /goal은 아래 구조에 가깝습니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.TUI /goal command ↓app-server thread/goal API ↓model tools: get_goal / create_goal / update_goal ↓core runtime: continuation / accounting / interrupt / resume ↓state DB: thread_goals table
각 레이어의 역할은 다릅니다.
| 레이어 | 역할 | 핵심 포인트 |
|---|---|---|
| TUI | 사용자가 /goal을 만들고 멈추고 지우는 UI | command와 상태 표시 |
| app-server | client가 thread goal 상태를 제어하는 API | get/set/clear, notification, resume snapshot |
| model tools | 모델이 goal을 조회·생성·완료 처리하는 도구 | 권한 제한이 중요 |
| core runtime | continuation, accounting, interrupt, resume 처리 | 실제 “계속 작업”을 만드는 중심 |
| state DB | goal objective/status/usage 저장 | thread 단위 persistence |
이 구조를 보면 /goal이 단순히 “모델에게 계속하라고 말하는 프롬프트”가 아니라는 점이 분명합니다. 목표 상태는 DB에 있고, runtime은 턴 생명주기에 맞춰 그 상태를 갱신합니다.
2. State DB: thread_goals 테이블
가장 아래에는 thread_goals 테이블이 있습니다. 공개 migration 기준으로 이 테이블은 다음 정보를 저장합니다.
| 컬럼 | 의미 |
|---|---|
thread_id | goal이 붙은 thread 식별자 |
goal_id | goal 자체의 식별자 |
objective | 사용자가 지정한 목표 |
status | active, paused, budget_limited, complete 중 하나 |
token_budget | 선택적 token budget |
tokens_used | goal 수행 중 누적 token 사용량 |
time_used_seconds | goal 수행 중 누적 시간 |
created_at_ms | 생성 시각 |
updated_at_ms | 갱신 시각 |
의사 타입으로 쓰면 이렇게 볼 수 있습니다.
// 읽기 가이드: 실제 API가 아니라 구조를 설명하는 의사코드입니다.type ThreadGoal = { thread_id: string goal_id: string objective: string status: "active" | "paused" | "budget_limited" | "complete" token_budget?: number tokens_used: number time_used_seconds: number created_at_ms: number updated_at_ms: number}
여기서 중요한 건 thread_id입니다. goal은 단순 메모리 플래그가 아니라 thread 상태에 붙어 있습니다. 그래서 resume, reconnect, app-server snapshot 같은 기능과 연결될 수 있습니다.
또 하나 중요한 건 goal_id입니다. PR #18073 설명에 따르면 stale update protection이 들어갔습니다. 즉 오래된 goal update가 새 goal을 덮어쓰지 못하도록 막는 장치입니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.문제:- goal A가 진행 중이다.- 사용자가 goal B로 교체한다.- 늦게 도착한 goal A update가 goal B 상태를 덮어쓴다. 해결:- update 시 expected goal_id를 확인한다.- 현재 goal_id와 다르면 stale update로 보고 막는다.
AI agent runtime에서 이런 보호는 중요합니다. 여러 async task, tool result, user mutation이 섞이면 “늦게 도착한 업데이트”가 상태를 망가뜨릴 수 있기 때문입니다.
3. App-server API: thread goal 제어면
두 번째 레이어는 app-server API입니다. PR #18074는 v2 API로 다음 RPC와 notification을 추가했다고 설명합니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.RPC:- thread/goal/get- thread/goal/set- thread/goal/clear Notification:- thread/goal/updated- thread/goal/cleared
이 API가 필요한 이유는 client가 goal 상태를 안정적으로 읽고 제어해야 하기 때문입니다.
| API 요소 | 역할 |
|---|---|
thread/goal/get | 현재 thread의 goal 상태 조회 |
thread/goal/set | goal 설정 또는 상태 변경 |
thread/goal/clear | goal 제거 |
thread/goal/updated | goal 변경을 client에 알림 |
thread/goal/cleared | goal 삭제를 client에 알림 |
| resume/snapshot wiring | reconnect한 client가 현재 goal 상태를 볼 수 있게 함 |
이 레이어가 있으면 TUI뿐 아니라 다른 client도 동일한 goal 상태를 볼 수 있습니다. 즉 /goal은 TUI 전용 hack이 아니라 app-server를 통해 materialized thread goal을 다루는 구조입니다.
4. Model tools: 제한된 모델 권한
세 번째 레이어는 model-facing tool입니다. PR #18075에 따르면 goal 관련 tool은 다음 세 가지입니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.get_goalcreate_goalupdate_goal
여기서 설계가 흥미롭습니다. 모델이 goal을 무제한으로 조작할 수 있게 하지 않았습니다.
| Tool | 허용된 역할 | 제한 |
|---|---|---|
get_goal | 현재 goal 확인 | read 중심 |
create_goal | 명시적으로 요청된 goal 생성 | 기존 goal이 없을 때만 생성하도록 제한 |
update_goal | goal 완료 처리 | completion 중심으로 제한 |
PR 설명은 pause, resume, clear, budget_limited 전이를 모델이 마음대로 처리하지 않고 사용자 또는 runtime-controlled 상태로 남겨둔다고 설명합니다.
이 설계는 중요합니다.
모델에게 모든 상태 제어권을 주면 이런 문제가 생길 수 있습니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.- 모델이 스스로 pause 처리해서 작업을 회피한다.- 예산 초과 상태를 모델이 임의로 해제한다.- 사용자가 만든 goal을 모델이 clear한다.- 완료되지 않았는데 complete로 표시한다.
그래서 /goal은 모델이 작업을 수행하고 완료를 선언할 수는 있지만, 사용자 제어와 runtime 제어를 분리합니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.모델 권한: 조회, 명시적 생성, 완료 처리사용자 권한: pause, resume/unpause, clear, replacementruntime 권한: budget_limited, accounting, continuation scheduling
이 권한 분리는 agent 시스템을 만들 때 그대로 참고할 만합니다.
5. Core runtime: continuation 상태 머신
네 번째 레이어가 가장 중요합니다. PR #18076은 long-running goal을 client가 아니라 core runtime concern으로 봅니다. core가 turn lifecycle, tool completion boundaries, interruptions, resume behavior, token usage를 관리하기 때문입니다.
공개 코드의 goals.rs 주석을 보면 이 모듈은 core session과 state DB goal table을 연결하고, goal mutation 검증, protocol 변환, goal-update event 발행, lifecycle hook을 담당합니다.
핵심 이벤트는 다음처럼 볼 수 있습니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.GoalRuntimeEvent- TurnStarted- ToolCompleted- ToolCompletedGoal- TurnFinished- MaybeContinueIfIdle- TaskAborted- ExternalMutationStarting- ExternalSet- ExternalClear- ThreadResumed
의사코드로 정리하면 이렇습니다.
// 읽기 가이드: 실제 API가 아니라 구조를 설명하는 의사코드입니다.on TurnStarted: capture token usage baseline if current thread has active goal: mark goal active for this turn on ToolCompleted: account token/time usage reset no-tool continuation suppression if token budget exceeded: mark goal as budget_limited inject budget wrap-up steering on TurnFinished: account final usage if this was a continuation turn and tool_calls == 0: suppress next automatic continuation on MaybeContinueIfIdle: if session is idle and active goal exists: start continuation turn on TaskAborted with interrupt: account usage pause active goal on ThreadResumed: reactivate paused goal outside plan mode
여기서 /goal의 실체가 드러납니다. Codex가 “계속 작업하는 것처럼 보이는 이유”는 모델이 혼자 무한 루프를 돌기 때문이 아니라, core runtime이 idle 상태에서 continuation turn을 예약하기 때문입니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.active goal exists+ session is idle+ not suppressed+ budget not exhausted= start continuation turn
6. Continuation prompt: 완료 감사의 핵심
continuation.md 템플릿은 /goal 품질의 핵심입니다.
이 prompt는 먼저 active thread goal을 계속 수행하라고 지시합니다. 동시에 objective를 “user-provided data”로 취급하라고 명시합니다. 즉 goal 문구가 system instruction처럼 승격되는 구조가 아닙니다.
또 매 continuation마다 다음 정보를 넣습니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.Time spent pursuing goalTokens usedToken budgetTokens remaining
가장 중요한 부분은 completion audit입니다. prompt는 완료를 선언하기 전에 다음을 하라고 요구합니다.
| 요구 | 의미 |
|---|---|
| objective를 concrete deliverables/success criteria로 재정리 | 목표를 검증 가능한 형태로 바꿈 |
| 모든 explicit requirement를 evidence checklist에 매핑 | 요구사항 누락 방지 |
| 파일, 명령 출력, 테스트 결과, PR 상태 등 실제 증거 확인 | 말이 아니라 현재 상태 기준으로 판단 |
| proxy signal만으로 완료 처리하지 않기 | “테스트 통과”도 목표 전체를 커버할 때만 증거 |
| 불확실하면 완료가 아니라 계속 작업 | 애매한 상태에서 premature complete 방지 |
이 부분은 AI agent 설계에서 매우 중요합니다.
나쁜 agent loop는 이렇게 끝납니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.테스트 하나 통과함→ 아마 됐겠지→ complete
좋은 goal runtime은 이렇게 끝나야 합니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.목표 요구사항 목록화→ 각 요구사항을 실제 evidence와 매핑→ 누락/미검증 항목 확인→ 모두 충족되면 complete→ 아니면 다음 concrete action 선택
이것이 /goal과 단순 반복 프롬프트의 차이입니다.
7. Budget limit: soft stop 설계
/goal에는 token budget 개념이 있습니다. 공개 migration에는 token_budget, tokens_used가 있고, runtime PR은 token budget exhaustion을 soft stop으로 처리한다고 설명합니다.
중요한 점은 예산 도달 시 active turn을 강제로 abort하지 않는다는 것입니다. 대신 goal을 budget_limited로 표시하고 wrap-up steering을 주입합니다.
budget_limit.md의 의도는 다음과 같습니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.- active thread goal이 token budget에 도달했다.- objective는 user-provided data로 취급한다.- 새 실질 작업을 시작하지 않는다.- 진행 상황, 남은 작업, blocker, 다음 단계를 정리한다.- 실제 완료된 것이 아니라면 update_goal complete를 호출하지 않는다.
이건 좋은 설계입니다. 예산이 끝났다고 목표가 완료된 것은 아니기 때문입니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.budget exhausted != goal complete
실무 agent에서 budget limit을 잘못 설계하면 두 가지 문제가 생깁니다.
| 잘못된 설계 | 문제 |
|---|---|
| 예산 초과 시 즉시 hard abort | 사용자에게 남은 작업과 상태가 전달되지 않음 |
| 예산 초과를 complete로 처리 | 미완료 작업이 완료처럼 보임 |
Codex의 방향은 그 중간입니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.예산 초과→ budget_limited 상태 전이→ 새 작업 시작 금지→ 진행 요약과 남은 작업 보고→ complete는 실제 완료일 때만
8. Loop guard와 safety 장치
long-running goal에서 가장 위험한 것은 무한 반복입니다. /goal에는 이를 줄이기 위한 장치들이 들어가 있습니다.
8.1 No-tool continuation suppression
PR #18076은 continuation turn이 tool call 없이 끝나면 반복 automatic continuation을 suppress한다고 설명합니다.
의미는 이렇습니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.continuation turn 시작→ 모델이 실제 파일 읽기/수정/명령 실행 없이 말만 함→ tool_calls == 0→ 다음 자동 continuation 억제
이 장치는 중요합니다. 그렇지 않으면 모델이 “계속 진행하겠습니다” 같은 말만 반복하는 루프에 빠질 수 있습니다.
8.2 Interrupt pause
사용자가 중단하면 active goal은 pause됩니다. 사용자가 멈췄는데도 goal이 계속 이어지는 것을 막기 위한 구조입니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.사용자 interrupt→ active goal accounting→ goal status paused
8.3 Resume auto-reactivation
PR #18076 설명에 따르면 thread resume 시 plan mode가 아니면 paused goal을 자동 재활성화하는 동작이 들어갔습니다. 즉 중단과 재개를 goal lifecycle의 일부로 다룹니다.
8.4 Stale goal_id protection
상태 레이어에서는 goal_id 기반 stale update protection이 있습니다. 오래된 update가 새 goal을 덮어쓰지 못하게 막습니다.
8.5 Objective privilege separation
Continuation prompt는 objective를 “higher-priority instruction”이 아니라 user-provided data로 취급합니다. 사용자가 goal 안에 강한 명령을 넣더라도 system/developer instruction처럼 승격되지 않도록 하기 위한 구조입니다.
9. 나만의 Agent 설계에 적용하기
/goal에서 가장 배울 만한 점은 “자동 반복”을 runtime event로 분리한 것입니다.
나쁜 구현은 대개 이렇게 됩니다.
// 읽기 가이드: 실제 API가 아니라 구조를 설명하는 의사코드입니다.while (true) { const result = await agent.run(goal) if (result.done) break}
이 방식은 간단하지만 위험합니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.- 완료 판정이 약하다.- 비용 제한이 부실하다.- 중단/재개가 어렵다.- 사용자 입력 우선순위를 다루기 어렵다.- 도구 호출 없는 반복을 막기 어렵다.- 이전 goal update가 새 goal을 덮어쓸 수 있다.
더 나은 구조는 이런 식입니다.
// 읽기 가이드: 실제 API가 아니라 구조를 설명하는 의사코드입니다.interface GoalRuntime { state: GoalStateStore scheduler: ContinuationScheduler auditor: CompletionAuditor accounting: UsageAccounting controls: UserControls guards: LoopGuards}
각 컴포넌트의 책임은 분리합니다.
| 컴포넌트 | 책임 |
|---|---|
GoalStateStore | objective, status, usage, timestamps 저장 |
ContinuationScheduler | idle 상태에서만 다음 turn 시작 |
CompletionAuditor | 요구사항과 증거를 매핑해 완료 판단 |
UsageAccounting | token/time budget 누적 |
UserControls | pause, resume, clear, replace |
LoopGuards | no-tool suppression, stale update protection, interrupt handling |
실제 구현 의사코드는 다음처럼 잡을 수 있습니다.
// 읽기 가이드: 실제 API가 아니라 구조를 설명하는 의사코드입니다.async function maybeContinueIfIdle(session: Session) { if (!session.isIdle()) return if (session.hasPendingUserInput()) return const goal = await goalStore.get(session.threadId) if (!goal || goal.status !== "active") return if (goalRuntime.isContinuationSuppressed(goal.goal_id)) return if (goal.token_budget && goal.tokens_used >= goal.token_budget) return await session.startContinuationTurn({ prompt: renderContinuationPrompt(goal), goal_id: goal.goal_id, })}
완료 판정도 별도 auditor로 분리하는 것이 좋습니다.
// 읽기 가이드: 실제 API가 아니라 구조를 설명하는 의사코드입니다.async function auditCompletion(goal: Goal, evidence: Evidence[]) { const checklist = buildChecklist(goal.objective) const coverage = mapEvidenceToChecklist(checklist, evidence) if (coverage.hasMissingItems()) { return { complete: false, nextAction: coverage.suggestNextAction() } } if (coverage.hasWeakVerification()) { return { complete: false, nextAction: "collect stronger evidence" } } return { complete: true }}
핵심은 agent가 열심히 했는지가 아니라 요구사항이 실제 증거로 충족됐는지를 보는 것입니다.
10. 구현 체크리스트
나만의 goal 기반 agent를 만든다면 다음을 체크하는 것이 좋습니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.Goal State[ ] goal_id를 둔다.[ ] objective를 저장한다.[ ] status를 active/paused/budget_limited/complete 등으로 제한한다.[ ] token/time usage를 누적한다.[ ] stale update protection을 둔다. Runtime[ ] turn started/finished 이벤트를 분리한다.[ ] tool completed 이벤트에서 usage를 집계한다.[ ] idle 상태에서만 continuation을 시작한다.[ ] 사용자 입력을 continuation보다 우선한다.[ ] interrupt 시 active goal을 pause한다.[ ] resume 시 goal 상태를 복원한다. Completion Audit[ ] objective를 success criteria로 재정리한다.[ ] 요구사항을 checklist로 만든다.[ ] 각 항목을 파일/명령/test 결과와 매핑한다.[ ] proxy signal만으로 완료 처리하지 않는다.[ ] 불확실하면 complete가 아니라 continue로 처리한다. Budget[ ] token budget을 둘 수 있다.[ ] budget 초과 시 complete로 처리하지 않는다.[ ] budget_limited 상태에서 wrap-up을 제공한다.[ ] 새 실질 작업을 시작하지 않도록 steering한다. User Controls[ ] pause를 지원한다.[ ] resume 또는 unpause를 지원한다.[ ] clear를 지원한다.[ ] replacement 시 기존 goal과 새 goal을 구분한다. Loop Guards[ ] tool call 없는 continuation은 반복하지 않는다.[ ] long-running command timeout을 둔다.[ ] 같은 실패를 반복하지 않도록 history를 기록한다.[ ] 권한과 writable scope를 제한한다.
11. 참고자료와 불확실성
참고자료
- OpenAI Codex changelog: https://developers.openai.com/codex/changelog
- OpenAI Codex GitHub repository: https://github.com/openai/codex
- PR #18073 — goal persistence foundation: https://github.com/openai/codex/pull/18073
- PR #18074 — app-server goal API: https://github.com/openai/codex/pull/18074
- PR #18075 — model-facing goal tools: https://github.com/openai/codex/pull/18075
- PR #18076 — core runtime goal loop: https://github.com/openai/codex/pull/18076
- PR #18077 — TUI goal UX: https://github.com/openai/codex/pull/18077
thread_goalsmigration: https://raw.githubusercontent.com/openai/codex/main/codex-rs/state/migrations/0029_thread_goals.sqlcontinuation.md: https://raw.githubusercontent.com/openai/codex/main/codex-rs/core/templates/goals/continuation.mdbudget_limit.md: https://raw.githubusercontent.com/openai/codex/main/codex-rs/core/templates/goals/budget_limit.md- Issue #19910 — compaction 관련 사용자 보고: https://github.com/openai/codex/issues/19910
- Issue #20536 —
/goal문서화 요청: https://github.com/openai/codex/issues/20536
확인된 사실
thread_goals테이블은thread_id,goal_id,objective,status,token_budget,tokens_used,time_used_seconds, timestamp를 저장합니다.status는active,paused,budget_limited,complete로 제한됩니다.- app-server에는
thread/goal/get,thread/goal/set,thread/goal/clearRPC와 goal updated/cleared notification이 추가됐습니다. - model-facing tool은
get_goal,create_goal,update_goal이며,update_goal은 completion 중심으로 제한됩니다. - core runtime은 idle continuation, usage accounting, budget limit, interrupt pause, resume reactivation, no-tool suppression을 처리합니다.
작성자의 해석
/goal은 AI coding agent의 “목표 기반 runtime”을 대중 제품에 넣은 사례로 볼 수 있습니다.- 가장 중요한 설계 포인트는 continuation scheduler보다 completion audit입니다.
- 이 구조는 Codex CLI뿐 아니라 자체 AI Agent, CI repair bot, long-running coding assistant에도 응용할 수 있습니다.
불확실성
- 출시 직후 기능이라 CLI help, command alias, 문서 반영은 변경될 수 있습니다.
- GitHub issue #19910에서 언급된 compaction failure mode는 사용자 보고 기준이며, 향후 수정될 수 있습니다.
- 공개 소스 분석 기준이므로 내부 런타임 세부사항이나 제품 동작은 버전에 따라 달라질 수 있습니다.
마무리
정리하면, Codex CLI /goal은 단순한 slash command가 아니라 goal state를 중심으로 agent runtime을 구성한 기능입니다.
가장 중요한 교훈은 이겁니다.
# 읽기 가이드: 아래 블록은 명령, 상태 흐름, 또는 템플릿 예시입니다.AI Agent를 오래 돌리고 싶다면 while loop를 먼저 만들지 말고,상태, 이벤트, 감사, 예산, 사용자 제어를 먼저 설계해야 한다.
/goal은 그 방향을 잘 보여줍니다. 목표를 저장하고, runtime event로 이어가고, 실제 증거로 완료를 감사하고, budget과 interrupt를 상태 전이로 처리합니다.
AI coding agent를 직접 만들고 있다면 이 구조를 그대로 참고할 만합니다. 특히 Goal State + Evidence Checklist + Continuation Scheduler + Budget Stop + User Control 조합은 단순 반복보다 훨씬 안전한 출발점입니다.
Viewthread_goals, continuation runtime, and completion audit at the code level
In Part 1, we looked at Codex CLI/goalfrom the user's perspective. In this article, we look at the internal structure.
The key is simple.
# Reading Guide: The blocks below are examples of commands, state flows, or templates./goal is not a single command.It is a function that combines target state storage, app-server API, model tool, runtime continuation, and TUI control.
This article was written based on Codex GitHub PR and publicly available source files. This is a soon-to-be-released feature, so actual implementation may vary in future versions.
Analysis base date: 2026-05-02 Base version: Codex CLI
0.128.0Main reference materials: OpenAI Codex changelog, GitHub PR #18073–#18077,thread_goalsmigration,continuation.md,budget_limit.md
Key takeaways
/goalis a five-layer function leading to TUI command to app-server API to model tools to core runtime to state DB.- The goal status is stored in the
thread_goalstable, and the status is limited toactive,paused,budget_limited, andcomplete. - The model tool cannot manipulate goals arbitrarily.
update_goalis limited to completion processing, and pause/resume/clear/budget-limited transitions remain under user or runtime control. - The core runtime processes turn start, tool completion, turn finish, interrupt, resume, and idle continuation through
GoalRuntimeEvent. - The continuation prompt asks you to perform a completion audit based on the “current actual state” before completion.
- From a good agent design perspective, the key to
/goalis evidence event-driven continuation + audit + budget guard, notwhile true.
1. Overall structure: View in 5 layers
Based on the code,/goalis close to the structure below.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.TUI /goal command↓app-server thread/goal API↓model tools: get_goal / create_goal / update_goal↓core runtime: continuation / accounting / interrupt / resume↓state DB: thread_goals table
Each layer has a different role.
| layer | role | key points |
|---|---|---|
| TUI | UI for users to create, stop and erase/goal | Command and status display |
| app-server | API where the client controls the thread goal state | get/set/clear, notification, resume snapshot |
| model tools | A tool that allows the model to view, create, and complete goals | Permission restrictions are important |
| core runtime | Continue, accounting, interrupt, resume processing | Central to creating real “keeps going” |
| state DB | Save goal objective/status/usage | Thread-level persistence |
Looking at this structure, it is clear that/goalis not simply a “prompt telling the model to continue.” The target state is in the DB, and the runtime updates the state according to the turn life cycle.
2. State DB:thread_goalstable
At the very bottom is thethread_goalstable. On a public migration basis, this table stores the following information:
| column | meaning |
|---|---|
thread_id | Thread identifier with goal |
goal_id | Identifier of the goal itself |
objective | User-specified goals |
status | One ofactive,paused,budget_limited,complete |
token_budget | Optional token budget |
tokens_used | Cumulative token usage during goal execution |
time_used_seconds | Accumulated time during goal execution |
created_at_ms | creation time |
updated_at_ms | update time |
If you write it as a pseudo type, you can see it like this.
// Reading Guide: This is not an actual API, but pseudocode that explains the structure.type ThreadGoal = { thread_id: string goal_id: string objective: string status: "active" | "paused" | "budget_limited" | "complete" token_budget?: number tokens_used: number time_used_seconds: number created_at_ms: number updated_at_ms: number}
The important thing here isthread_id. A goal is not a simple memory flag, but is attached to thread state. So it can be connected to functions like resume, reconnect, and app-server snapshot.
Another important one isgoal_id. According to the description of PR #18073, stale update protection has been included. In other words, it is a device that prevents old goal updates from overwriting new goals.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.problem:- Goal A is in progress.- The user replaces it with goal B.- The goal A update that arrives late overwrites the state of goal B. solve:- Check expected goal_id when updating.- If it is different from the current goal_id, it is considered a stale update and blocked.
This protection is important in AI agent runtime. This is because when multiple async tasks, tool results, and user mutations are mixed, “late-arriving updates” can break the state.
3. App-server API: thread goal control plane
The second layer is the app-server API. PR #18074 explains that the following RPC and notification were added to the v2 API.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.RPC:- thread/goal/get- thread/goal/set- thread/goal/clear Notification:- thread/goal/updated- thread/goal/cleared
The reason this API is needed is because the client needs to reliably read and control the goal state.
| API elements | role |
|---|---|
thread/goal/get | Check the goal status of the current thread |
thread/goal/set | Set goal or change state |
thread/goal/clear | remove goal |
thread/goal/updated | Notify the client of goal changes |
thread/goal/cleared | Notify the client of goal deletion |
| resume/snapshot wiring | Allows the reconnected client to view the current goal status. |
With this layer, not only TUI but also other clients can see the same goal status. In other words,/goalis not a TUI-specific hack, but a structure that handles materialized thread goals through the app-server.
4. Model tools: Limited model permissions
The third layer is the model-facing tool. According to PR #18075, there are three goal-related tools:
# Reading Guide: The blocks below are examples of commands, state flows, or templates.get_goalcreate_goalupdate_goal
This is where the design gets interesting. The model does not allow unlimited manipulation of the goal.
| Tool | Allowed Roles | limits |
|---|---|---|
get_goal | Check current goal | read center |
create_goal | Create an explicitly requested goal | Restrict creation to only when there is no existing goal |
update_goal | Goal completion processing | Limited to center on completion |
The PR description explains that thepause,resume,clear, andbudget_limitedtransitions are not handled by the model at will, but are left user- or runtime-controlled.
This design is important.
Giving all state control to the model can cause problems like this.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.- The model pauses itself to avoid work.- The model arbitrarily releases the budget exceeding state.- The model clears the goal created by the user.- Marked as complete even though it is not completed.
So/goalallows the model to perform tasks and declare completion, but separates user control from runtime control.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.Model permissions: lookup, explicit creation, completion processingUser permissions: pause, resume/unpause, clear, replacementruntime permissions: budget_limited, accounting, continuation scheduling
This separation of rights is worth referring to when creating an agent system.
5. Core runtime: continuation state machine
The fourth layer is the most important. PR #18076 views long-running goals as a core runtime concern, not as a client. This is because the core manages turn lifecycle, tool completion boundaries, interruptions, resume behavior, and token usage.
Looking at thegoals.rsannotation in the public code, this module connects the core session and the state DB goal table and is responsible for goal mutation verification, protocol conversion, goal-update event issuance, and lifecycle hook.
Key events can be viewed as follows:
# Reading Guide: The blocks below are examples of commands, state flows, or templates.GoalRuntimeEvent- TurnStarted- ToolCompleted- ToolCompletedGoal- TurnFinished- MaybeContinueIfIdle- TaskAborted- ExternalMutationStarting- ExternalSet- ExternalClear- ThreadResumed
Summarized in pseudocode, it is as follows.
// Reading Guide: This is not an actual API, but pseudocode that explains the structure.on TurnStarted: capture token usage baseline if current thread has active goal: mark goal active for this turn on ToolCompleted: account token/time usage reset no-tool continuation suppression if token budget exceeded: mark goal as budget_limited inject budget wrap-up steering on TurnFinished: account final usage if this was a continuation turn and tool_calls == 0: suppress next automatic continuation on MaybeContinueIfIdle: if session is idle and active goal exists: start continuation turn on TaskAborted with interrupt: account usage pause active goal on ThreadResumed: reactivate paused goal outside plan mode
Here, the true nature of/goalis revealed. The reason Codex “appears to continue working” is not because the model runs in an infinite loop by itself, but because it schedules a continuation turn while the core runtime is idle.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.active goal exists+ session is idle+ not suppressed+ budget not exhausted= start continuation turn
6. Continuation prompt: The key to completion auditing
continuation.mdtemplate is the key to/goalquality.
This prompt instructs you to continue executing the active thread goal first. At the same time, it specifies that the objective should be treated as “user-provided data.” In other words, the goal statement is not promoted like a system instruction.
Also, the following information is included in each continuation.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.Time spent pursuing goalTokens usedtoken budgetTokens remaining
The most important part is the completion audit. The prompt asks you to do the following before declaring completion:
| request | meaning |
|---|---|
| Reorganize objectives into concrete deliverables/success criteria | Convert your goals into testable form |
| Mapping all explicit requirements to evidence checklist | Avoid missing requirements |
| View real evidence including files, command output, test results, PR status, etc. | Judge based on current status, not words |
| Do not complete with proxy signal alone | “Passing the test” is only evidence if it covers the entire goal |
| If you are uncertain, keep working instead of completing. | Prevent premature completion in ambiguous states |
This part is very important in AI agent design.
This is how a bad agent loop ends:
# Reading Guide: The blocks below are examples of commands, state flows, or templates.One test passedto It's probably okay→ complete
A good goal runtime should end like this.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.List your target requirementsto map each requirement to actual evidenceto Check missing/unverified itemsto complete if all are metto or select the next concrete action
This is the difference between/goaland a simple repeat prompt.
7. Budget limit: soft stop design
/goalhas the concept of token budget. Public migrations includetoken_budgetandtokens_used, and runtime PR explains that token budget exhaustion is treated as a soft stop.
The important thing is that active turns are not forced to abort when the budget is reached. Instead, we mark the goal asbudget_limitedand inject wrap-up steering.
The intention ofbudget_limit.mdis as follows:
# Reading Guide: The blocks below are examples of commands, state flows, or templates.- The active thread goal has reached the token budget.- Objective is treated as user-provided data.-Do not start new substantive work.- Organize progress, remaining tasks, blockers, and next steps.- Do not call update_goal complete unless it is actually completed.
This is a good design. Just because the budget is over doesn't mean the goal is complete.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.budget exhausted!= goal complete
If the budget limit is designed incorrectly in a practical agent, two problems arise.
| bad design | problem |
|---|---|
| Immediate hard abort when budget is exceeded | Remaining tasks and status are not communicated to users |
| Treat budget exceedance as complete | Unfinished tasks appear complete |
Codex's direction is somewhere in between.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.over budgetto budget_limited state transitionto prevent starting new tasksto Summary of progress and reporting of remaining workto complete only when it is actually completed
8. Loop guard and safety device
The most dangerous thing about long-running goals is endless repetition./goalcontains devices to reduce this.
8.1 No-tool continuation suppression
PR #18076 explains that automatic continuations are suppressed when the continuation turn ends without a tool call.
The meaning is this:
# Reading Guide: The blocks below are examples of commands, state flows, or templates.Start continuation turnThe to model just talks without actually reading/editing files/executing commands.→ tool_calls == 0to suppress next automatic continuation
This device is important. Otherwise, your model can get stuck in a loop where it just says things like “I’ll keep going.”
8.2 Interrupt pause
When the user stops, the active goal is paused. This is a structure to prevent the goal from continuing even if the user stops.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.user interrupt→ active goal accounting→ goal status paused
8.3 Resume auto-reactivation
According to the description of PR #18076, when thread resumes, an action has been taken to automatically reactivate paused goals if they are not in plan mode. In other words, it treats interruption and resumption as part of the goal lifecycle.
8.4 Stale goal_id protection
In the state layer, there is stale update protection based ongoal_id. Prevents old updates from overwriting new goals.
8.5 Objective privilege separation
The continuation prompt treats the objective as user-provided data rather than a “higher-priority instruction”. This is a structure to prevent it from being promoted to a system/developer instruction even if the user enters a strong command in the goal.
9. Apply to your own Agent design
The most important thing to learn from/goalis the separation of “auto-repeat” into runtime events.
Bad implementations usually end up like this.
// Reading Guide: This is not an actual API, but pseudocode that explains the structure.while (true) { const result = await agent.run(goal) if (result.done) break}
This method is simple but risky.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.- The completion judgment is weak.- Cost restrictions are poor.- Difficult to stop/resume.- Difficult to handle user input priorities.- It is difficult to prevent repetition without tool calls.- A previous goal update may overwrite the new goal.
A better structure would be like this:
// Reading Guide: This is not an actual API, but pseudocode that explains the structure.interface GoalRuntime { state: GoalStateStore scheduler: ContinuationScheduler auditor: CompletionAuditor accounting: UsageAccounting controls: UserControls guards: LoopGuards}
The responsibilities of each component are separated.
| component | responsibility |
|---|---|
GoalStateStore | Save objective, status, usage, timestamps |
ContinuationScheduler | Next turn starts only in idle state |
CompletionAuditor | Mapping requirements and evidence to determine completion |
UsageAccounting | token/time budget accumulation |
UserControls | pause, resume, clear, replace |
LoopGuards | no-tool suppression, stale update protection, interrupt handling |
The actual implementation pseudocode can be captured as follows.
// Reading Guide: This is not an actual API, but pseudocode that explains the structure.async function maybeContinueIfIdle(session: Session) { if (!session.isIdle()) return if (session.hasPendingUserInput()) return const goal = await goalStore.get(session.threadId) if (!goal || goal.status !== "active") return if (goalRuntime.isContinuationSuppressed(goal.goal_id)) return if (goal.token_budget && goal.tokens_used >= goal.token_budget) return await session.startContinuationTurn({ prompt: renderContinuationPrompt(goal), goal_id: goal.goal_id, })}
It is recommended that completion judgments be separated by a separate auditor.
// Reading Guide: This is not an actual API, but pseudocode that explains the structure.async function auditCompletion(goal: Goal, evidence: Evidence[]) { const checklist = buildChecklist(goal.objective) const coverage = mapEvidenceToChecklist(checklist, evidence) if (coverage.hasMissingItems()) { return { complete: false, nextAction: coverage.suggestNextAction() } } if (coverage.hasWeakVerification()) { return { complete: false, nextAction: "collect stronger evidence" } } return { complete: true }}
The key is not whether the agent worked hard, but whether the requirements were met with actual evidence.
10. Implementation Checklist
If you are creating your own goal-based agent, it is recommended to check the following.
# Reading Guide: The blocks below are examples of commands, state flows, or templates.Goal State[ ] Place goal_id.[ ] Save the objective.[ ] Limit status to active/paused/budget_limited/complete, etc.[ ] Accumulate token/time usage.[ ] Enable stale update protection. Runtime[ ] separates the turn started/finished events.[ ] Count usage from tool completed events.[ ] The continuation starts only in idle state.[ ] User input takes precedence over continuation.[ ] Pauses the active goal when interrupted.[ ] Restores the goal state when resumed. Completion Audit[ ] Reorganize objectives into success criteria.[ ] Make requirements into a checklist.[ ] Map each item to a file/command/test result.[ ] Do not complete processing with proxy signal alone.[ ] If uncertain, proceed with continue rather than complete. Budget[ ] A token budget can be set.[ ] If the budget is exceeded, it is not processed as complete.[ ] Provides wrap-up in budget_limited state.[ ] Steering so as not to start a new substantive task. User Controls[ ] pause is supported.[ ] Supports resume or unpause.[ ] Clear is supported.[ ] When replacing, distinguish between the existing goal and the new goal. Loop Guards[ ] A continuation without a tool call is not repeated.[ ] Set a long-running command timeout.[ ] Record history to avoid repeating the same failure.[ ] Limit permissions and writable scope.
11. References and uncertainty
References
- OpenAI Codex changelog:https://developers.openai.com/codex/changelog
- OpenAI Codex GitHub repository:https://github.com/openai/codex
- PR #18073 — goal persistence foundation:https://github.com/openai/codex/pull/18073
- PR #18074 — app-server goal API:https://github.com/openai/codex/pull/18074
- PR #18075 — model-facing goal tools:https://github.com/openai/codex/pull/18075
- PR #18076 — core runtime goal loop:https://github.com/openai/codex/pull/18076
- PR #18077 — TUI goal UX:https://github.com/openai/codex/pull/18077
thread_goalsmigration:https://raw.githubusercontent.com/openai/codex/main/codex-rs/state/migrations/0029_thread_goals.sqlcontinuation.md:https://raw.githubusercontent.com/openai/codex/main/codex-rs/core/templates/goals/continuation.mdbudget_limit.md:https://raw.githubusercontent.com/openai/codex/main/codex-rs/core/templates/goals/budget_limit.md- Issue #19910 — User report regarding compaction:https://github.com/openai/codex/issues/19910
- Issue #20536 —
/goalDocumentation Request:https://github.com/openai/codex/issues/20536
confirmed facts
- The
thread_goalstable storesthread_id,goal_id,objective,status,token_budget,tokens_used,time_used_seconds, timestamps. statusis limited toactive,paused,budget_limited,complete.thread/goal/get,thread/goal/set,thread/goal/clearRPC and goal updated/cleared notification have been added to app-server.- The model-facing tools are
get_goal,create_goal, andupdate_goal, andupdate_goalis limited to the center of completion. - The core runtime handles idle continuation, usage accounting, budget limit, interrupt pause, resume reactivation, and no-tool suppression.
Author's interpretation
/goalcan be seen as an example of incorporating the “goal-based runtime” of an AI coding agent into a popular product.- The most important design point is the completion audit rather than the continuation scheduler.
- This structure can be applied not only to Codex CLI but also to its own AI Agent, CI repair bot, and long-running coding assistant.
uncertainty
- As this is a feature immediately after release, CLI help, command alias, and documentation may be subject to change.
- The compaction failure mode mentioned in GitHub issue #19910 is based on user reports and may be modified in the future.
- This is based on open source analysis, so internal runtime details or product behavior may vary across versions.
finish
In summary, Codex CLI/goalis not a simple slash command, but a function that configures the agent runtime around the goal state.
The most important lesson is this:
# Reading Guide: The blocks below are examples of commands, state flows, or templates.If you want to run the AI Agent for a long time, do not create a while loop first,Status, events, auditing, budget, and user controls must be designed first.
/goalshows that direction well. It stores goals, continues with runtime events, audits completion with actual evidence, and handles budgets and interrupts as state transitions.
If you are creating your own AI coding agent, this structure is worth referring to. In particular, theGoal State + Evidence Checklist + Continuation Scheduler + Budget Stop + User Controlcombination is a much safer starting point than simple repetition.

댓글
GitHub 계정으로 로그인하면 댓글을 남길 수 있습니다. 댓글은 GitHub Discussions를 통해 운영됩니다.