Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fdc66c5
feat(protocol): add thread goal operations
CSRessel May 28, 2026
a74d9d6
feat(protocol): add goal client events
CSRessel May 28, 2026
09aeaa6
feat(acp): maintain session goal state
CSRessel May 28, 2026
81519ff
feat(tui): dispatch goal slash command
CSRessel May 28, 2026
c5e3e2d
style: format goal code
CSRessel May 28, 2026
d2dcbcd
feat(acp): replay goal client events
CSRessel May 28, 2026
c71d283
feat(acp): rehydrate goal state on resume
CSRessel May 28, 2026
6c31a15
test(tui): cover goal slash arguments
CSRessel May 28, 2026
473d128
feat(acp): prepend goal context to prompts
CSRessel May 28, 2026
079f0ad
feat(acp): track goal token usage
CSRessel May 28, 2026
99f2457
docs: document ACP goal flow
CSRessel May 28, 2026
dd7c5f4
fix(acp): avoid expect in goal setup
CSRessel May 28, 2026
21b52f4
docs(progress): record goal parity gaps
CSRessel May 28, 2026
7c570b3
feat(acp): auto-submit goal continuation prompts
CSRessel May 28, 2026
0c1a0ff
docs: document goal continuations
CSRessel May 28, 2026
cb16dea
feat(tui): confirm goal replacement
CSRessel May 28, 2026
d5a4459
docs(tui): document goal replacement confirmation
CSRessel May 28, 2026
3a85a42
fix(tui): clear stale goal edit requests
CSRessel May 28, 2026
d8a4096
feat(acp): show resumed paused goal notices
CSRessel May 28, 2026
69388e2
fix(acp): prompt usage-limited goals on resume
CSRessel May 28, 2026
3c80efc
feat(acp): expose thread goal MCP tools
CSRessel May 28, 2026
4c766d6
feat(acp): chain goal continuations for capable agents
CSRessel May 28, 2026
c77d6d5
docs: Track pending fixes
CSRessel May 28, 2026
c25a271
fix(acp): serve goal MCP over loopback HTTP
CSRessel May 28, 2026
09ee1b9
test(tui): stabilize vertical footer snapshot
CSRessel May 28, 2026
2028b2d
docs: visualize and document goal architecture
CSRessel May 29, 2026
846c27c
fix(goal): quiet status updates and accumulate usage
CSRessel May 29, 2026
efffbd6
docs(goal): update goal progress log
CSRessel May 29, 2026
eb7fd17
fix(goal): start active goals immediately
CSRessel May 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
278 changes: 278 additions & 0 deletions CURRENT-PROGRESS.md

Large diffs are not rendered by default.

276 changes: 276 additions & 0 deletions goal-command-architecture-diagrams.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
# Goal Command Architecture Diagrams

This note compares two implementations of the same user-facing idea: a long-lived
thread goal that keeps the agent aligned across turns until the model marks the
goal complete or blocked.

- In the raw Codex harness, goals are native session/runtime state.
- In Nori CLI over ACP, goals are owned by the Nori ACP backend and projected
into an external ACP agent through prompt context plus a local `nori-goal`
MCP server.

## Raw Codex Harness

Codex keeps the goal loop inside the core harness. The app-server persists the
goal, the running `Session` observes goal lifecycle events, and the model marks
completion through the built-in `update_goal` tool.

### Mermaid Sequence Diagram

```mermaid
sequenceDiagram
autonumber
actor User
participant App as Codex app-server
participant DB as State DB
participant Session as Codex Session
participant Runtime as GoalRuntimeState
participant History as ContextManager
participant Model as Model turn
participant Tool as update_goal handler

User->>App: thread/goal/set(objective)
App->>DB: create or update ThreadGoal(status=Active)
App-->>User: thread/goal/updated
App->>Session: ExternalSet(goal)
Session->>Runtime: GoalRuntimeEvent::ExternalSet

User->>Session: user turn
Session->>Runtime: GoalRuntimeEvent::TurnStarted
Session->>History: record prompt and context
History-->>Model: prompt input with thread history
Model-->>Session: assistant output and tool activity
Session->>Runtime: GoalRuntimeEvent::TurnFinished
Session->>Runtime: GoalRuntimeEvent::MaybeContinueIfIdle

alt goal is active and session is idle
Runtime->>DB: re-read current ThreadGoal
Runtime->>History: enqueue hidden GoalContext continuation
Runtime->>Session: start RegularTask with empty visible input
History-->>Model: history plus hidden continuation prompt
Model-->>Session: continues work toward objective
else user work, mailbox work, inactive goal, or plan mode
Runtime-->>Session: no automatic continuation
end

alt model proves goal complete or blocked
Model->>Tool: update_goal(status="complete" or "blocked")
Tool->>Runtime: GoalRuntimeEvent::ToolCompletedGoal
Tool->>DB: set ThreadGoal.status
Tool-->>Model: updated goal and usage report
Runtime-->>Session: status is no longer Active, so continuation stops
end
```

### ASCII Overview

```text
User/App
|
| thread/goal/set
v
Codex app-server
|
| validate + write ThreadGoal(status=Active)
v
State DB -------------------------------+
| |
| ExternalSet |
v |
Codex Session + GoalRuntimeState |
| |
| normal user turn |
v |
Model sees session history |
| |
| turn finishes |
v |
MaybeContinueIfIdle |
| |
| re-read DB; if active goal + idle |
v |
Hidden GoalContext continuation ---------+
|
| starts another RegularTask in same thread
v
Model keeps working
|
| when evidence proves done or blocked
v
update_goal(status="complete" | "blocked")
|
v
ThreadGoal.status changes; continuation loop stops
```

### Codex Source Notes

- `thread/goal/set` writes the goal through the app-server and applies runtime
effects to a running thread:
`../other-repos/codex/codex-rs/app-server/src/request_processors/thread_goal_processor.rs`.
- Goal runtime events and continuation scheduling live in
`../other-repos/codex/codex-rs/core/src/goals.rs`.
- Hidden continuation text is wrapped as `GoalContext` with `<goal_context>`
markers in `../other-repos/codex/codex-rs/core/src/context/goal_context.rs`.
- Turns call `MaybeContinueIfIdle` after the active turn is cleared in
`../other-repos/codex/codex-rs/core/src/tasks/mod.rs`.
- The completion/blocking state transition is the built-in `update_goal` tool in
`../other-repos/codex/codex-rs/core/src/tools/handlers/goal/update_goal.rs`.

## Nori CLI Over ACP

Nori keeps the user-facing goal state in the ACP backend. During ACP session
setup, it advertises a local `nori-goal` MCP server when the agent connection
reports HTTP MCP support. Per turn, it sends goal context to the external ACP
agent as prompt text, and the external agent marks completion/blocking through
that local MCP server.

### Mermaid Sequence Diagram

```mermaid
sequenceDiagram
autonumber
actor User
participant TUI as Nori TUI
participant Backend as Nori ACP backend
participant GoalState as ThreadGoalState
participant Runtime as SessionRuntimeDriver
participant ACP as ACP connection
participant Agent as External ACP agent
participant MCP as local nori-goal MCP server

Backend->>MCP: ensure local nori-goal server exists
Backend->>ACP: session/new or session/load with mcpServers[nori-goal]
ACP-->>Agent: advertise nori-goal HTTP MCP server
Agent->>MCP: connect and initialize goal tools

User->>TUI: /goal <objective> or /goal resume
TUI->>Backend: goal command request
alt /goal <objective>
Backend->>GoalState: set objective and status=Active
else /goal resume
Backend->>GoalState: set status=Active
end
GoalState-->>Backend: ThreadGoalSnapshot
Backend-->>TUI: ThreadGoalUpdated

User->>TUI: visible prompt
TUI->>Backend: submit prompt
Backend->>GoalState: render <goal_context>
Backend->>Runtime: enqueue user prompt with prepended goal context
Runtime->>ACP: send prompt
ACP->>Agent: user message plus goal context
Agent-->>ACP: response stream
ACP-->>Runtime: EndTurn

Runtime->>GoalState: ask for continuation_prompt()
alt goal is active, runtime is idle, queue is empty, and chaining is allowed
GoalState-->>Runtime: hidden goal continuation text
Runtime->>Runtime: enqueue GoalContinuation prompt
Runtime->>ACP: send hidden continuation
ACP->>Agent: hidden continuation prompt
Agent-->>ACP: continues work
else inactive goal, pending work, or unconnected goal MCP after a hidden turn
Runtime-->>Backend: no hidden continuation
end

alt agent proves goal complete or blocked
Agent->>MCP: update_goal(status="complete" or "blocked")
MCP->>GoalState: set_status(...)
GoalState-->>MCP: updated ThreadGoalSnapshot
MCP-->>Backend: emit ThreadGoalUpdated event
Backend-->>TUI: updated goal status
Runtime-->>Runtime: future continuation_prompt() returns none
end
```

### ASCII Overview

```text
ACP session setup
|
| if connection supports HTTP MCP
v
Advertise local nori-goal HTTP MCP server
|
| external agent connects and initializes tools
v
External ACP agent has goal tools

-- Goal command --

User / Nori TUI
|
| /goal <objective> or /goal resume
v
Nori ACP backend
|
| owns ThreadGoalState
| emits ThreadGoalUpdated

-- Per-turn steering loop --

Visible user prompt
|
| Nori prepends <goal_context>
v
ACP prompt to agent
|
| agent responds, ACP reports EndTurn
v
SessionRuntimeDriver
|
| if goal active + idle + queue empty
| user turns may start a continuation;
| hidden turns only chain after goal MCP connects
v
Hidden GoalContinuation prompt
|
| sent over same ACP session
v
External ACP agent keeps working
|
| when evidence proves done or blocked
v
nori-goal.update_goal(status="complete" | "blocked")
|
v
ThreadGoalState status changes; continuation loop stops
```

### Nori Source Notes

- `ThreadGoalState` renders visible `<goal_context>` and hidden continuation
text in `acp/src/backend/thread_goal.rs`.
- User prompts are augmented with goal context before submission in
`acp/src/backend/user_input.rs`.
- The ACP runtime schedules hidden continuations after `EndTurn` in
`acp/src/backend/session_runtime_driver.rs`.
- Nori registers the local goal MCP server during ACP session setup/load and
advertises it only when the connection reports HTTP MCP support:
`acp/src/backend/spawn_and_relay.rs`, `acp/src/backend/session.rs`, and
`acp/src/backend/thread_goal_mcp.rs`.
- The ACP connection forwards `mcpServers` to the external agent when creating a
session in `acp/src/connection/sacp_connection.rs`.
- The local `nori-goal` MCP server exposes `get_goal`, `create_goal`, and
`update_goal` in `acp/src/backend/thread_goal_mcp.rs`.

## Comparison

| Concern | Raw Codex harness | Nori CLI over ACP |
| --- | --- | --- |
| Goal state owner | Codex state DB plus core `Session` runtime | Nori ACP backend `ThreadGoalState` |
| Model-facing goal context | Hidden `GoalContext` response item | Prepended prompt text and hidden continuation prompt |
| Continuation scheduler | `GoalRuntimeState::MaybeContinueIfIdle` | `SessionRuntimeDriver::maybe_submit_goal_continuation` |
| Completion evaluator | The model self-audits against current evidence | The external ACP agent self-audits against current evidence |
| Completion actuator | Built-in Codex `update_goal` tool | Local `nori-goal` MCP `update_goal` tool |
| Context window | Same Codex thread/session history, compacted as needed | External ACP agent's session context, steered by Nori prompts |
| Subagents | Separate Codex threads only when explicitly spawned | Determined by the external ACP agent, not by Nori goal state |

## Mental Model

Both implementations are intentionally simple at the decision point: the model
decides whether the objective is complete or blocked, and a narrow tool changes
goal status. The harness/backend does not independently prove completion. Its
job is to keep the objective visible, continue work while the goal remains
active, persist status, and stop the loop once the status changes.
Loading
Loading