Skip to content

Commit c2d602e

Browse files
committed
docs: PLAN-PROGRESS.md — how Claude shows plan and progress, what LevelCode does, the owner's queue decision; release notes
1 parent 8cd7d97 commit c2d602e

2 files changed

Lines changed: 211 additions & 0 deletions

File tree

‎RELEASE-NOTES.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,25 @@ These are the same eleven the browser edition allows.
2626
- **They are now shared by all your profiles.** VS Code keeps settings like these in the Default profile. A value written in another profile's `settings.json` is ignored, and changing one from another profile writes it to the Default profile for you.
2727
- **Nothing changes if you only ever set them in your user settings**, which is where the Settings editor and the chat's own menus put them.
2828

29+
### The agent shows its plan, and you can keep typing while it works
30+
31+
**Enter no longer stops the agent.** Until now, pressing Enter while the agent was working stopped the run. Now what you type waits just above the message box and is sent as your next message when the run finishes. To stop a run, use ■ with the message box empty.
32+
33+
- **A task list under the latest message.** When a job has more than one step, the agent keeps a short task list as the last thing in the conversation. The step it is on spins (it stops spinning while the agent waits for you to approve something), finished steps turn grey, and a long list shows the steps around the current one with "earlier steps" and "more to go" counts. The list goes away when the run ends. It replaces the "Plan 2/5" bar above Keep all / Undo all.
34+
- **A clear hand-back.** When a run ends with a decision for you, the agent asks one question with one or two answers to click ("Run the tests now?"). Clicking an answer sends it as your next message. Before that box appears, the files the agent changed are checked (the editor's diagnostics, and your verify command if you set one); if the check fails, the agent fixes the problems first.
35+
- **Messages that wait their turn.** One waiting message shows as a single row; several fold into "3 messages queued · Next: …". **Send now** hands a message to the agent at its next step without stopping the run. You can also edit a waiting message in the message box, reorder several, or remove them. If a run is stopped or fails, anything still waiting comes back into the message box instead of being sent.
36+
2937
## Not in this release
3038

3139
<!-- TODO -->
40+
- **Send now is for text.** A waiting message with an image is sent when the run ends, not mid-run. And a message sent with Send now is read after the step the agent is on: it does not interrupt a command that is already running, and it does not hold back the agent's next edit while it waits.
3241

3342
## Test coverage
3443

3544
<!-- TODO measure with scripts/draft-release-notes.mjs (counted cases only). -->
3645
- `settingsScope` (4 cases): every LevelCode AI setting is user-only unless it is on the list above; every scope is one the editor knows, because it reads a misspelt one as a setting a folder can set; and the desktop and the browser edition allow the same list.
46+
- `turnPlan` (20 cases), `agentPlanProgress` (11) and `planProgressUi` (24): how the task list and the hand-back are read and moved; the agent loop ending on a hand-back with a question without another model call, checking its edits there, and delivering Send now at the next step (or handing it back when the run stops); and the chat page's list, box and queue, down to Enter queueing instead of stopping.
47+
- `scripts/plan-progress-editor-check.js` runs a scripted agent in the real editor (17 checks, light and dark), and `web/test/e2e-plan-progress.mjs` does the same in the browser edition (9 checks). Neither is part of the gate.
3748
- `scripts/folder-settings-editor-check.js` opens the real editor on a project that tries all of the above and checks that none of it takes effect. It is not part of the gate.
3849

3950
**Full changelog:** https://github.com/levelcodeai/levelcode/compare/v1.4.0...vX.Y.Z

‎docs/PLAN-PROGRESS.md‎

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# Plan and progress in the agent chat
2+
3+
How the agent shows its plan while it works, how a run hands back, and what happens to a message you
4+
send while it is busy. Modelled on the Code tab of the Claude desktop app, which the owner asked us to
5+
match ("I really love how Claude desktop is rendering the plan and tasks and queue of the work").
6+
7+
This note has three parts: what Claude does (read from the shipped app, with the evidence to check it
8+
again), what LevelCode does, and which differences are on purpose.
9+
10+
## 1. What Claude does
11+
12+
Read on 2026-10-19 from Claude 2.42304.2 (`/Applications/Claude.app`). Nothing was copied: the
13+
behaviour and the look are reimplemented below in LevelCode's own code and words.
14+
15+
### Where it lives
16+
17+
The desktop app is an Electron shell around claude.ai. Its `app.asar` holds the **tool schemas and the
18+
host's plan state**; the **components that draw the plan, the next-step box and the queue** are part of
19+
the claude.ai web bundle, which the app downloads at run time. They were read from the app's own HTTP
20+
cache (`~/Library/Application Support/Claude/Cache/Cache_Data`, the bundle cached at 20:23 UTC that day).
21+
22+
| What | Where | sha256 |
23+
| --- | --- | --- |
24+
| The app | `Contents/Resources/app.asar` | `f0a063c8c2c7fb21eb51bca00f086e5b7355d7208e3d9f28600ea79961830907` |
25+
| `update_plan` / `wrap_up` schemas, descriptions, the host's step arithmetic and replies | `app.asar:/.vite/build/index.chunk-B8PX1nMp.js` (the `ccd_turn` MCP server) | `c32451d17b2d4e8392c7921f750e2b72587a3fdb2373f7e79ea0fb6781b4a2ea` |
26+
| Parsing a plan / wrap-up from the transcript, the same step arithmetic in the page | `…/assets/v1/cb27dab29-QZ5yQ8Vk.js` | `7e861c878f205e1bcfd69718dff20eecdb03e6deadc0618ffaca61fbac449f2d` |
27+
| Deriving the turn's state (plan, plan before wrap-up, stale, settled) | `…/assets/v1/cc8868388-HuTgCGZg.js` | `6f2e05af57882d7481abd81aa94cd2d4724dfa3411737843d14c456fe45e19f3` |
28+
| The turn box (task list + next-step box) | `…/assets/v1/cccc2cf0a-DgImlUHB.js` | `cf4c01a825117eab0cd55f5eb250272458e7b91c457d342d29e4bdb7f40c0a46` |
29+
| The step list and its status icons | `…/assets/v1/cb6930dae-CGtVbuxy.js` | `41992d1f5690b46639e486ab42923eec8b84887b76836994c4356a97acb085bf` |
30+
| The long-list window | `…/assets/v1/c26f8455e-GCVxaQcT.js` | `4f0ac8bd4e4a3fa22ec6cd07432d441337bb1fe3aab86ed8af26aff723864cdd` |
31+
| The queued-messages band | `…/assets/v1/c81c42cdb-DeYTkBpl.js` | `8a7a95b0201e3d59dcb590023b9ec46add8e4790b6f94e3137df983b71bad65c` |
32+
| Hiding the two tools from the transcript | `…/assets/v1/c06cf64bb-BYFl_HkI.js` | `985598ae1d555f6a1794fdf9e43c40f83a94537bf9a8d1074530dd53e5dca191` |
33+
| Animations and tokens | `…/assets/v1/c6a992d55-BGPwQXHG.css` | `6dcdf6e00e5592118918b0c990b27f29f17d206cc1574a9e07e6f955898a6252` |
34+
35+
`…` is `https://assets-proxy.anthropic.com/claude-ai/v2`. The web bundle changes with every claude.ai
36+
deploy, so these hashes pin what was read, not what the app shows tomorrow.
37+
38+
### The task list
39+
40+
- **The model's tool.** `update_plan` takes the whole list (`items`: 1–12 steps, each `content` and a
41+
`status` of `pending`, `in_progress` or `completed`) or a small update: `advance: true` completes the
42+
step in progress and starts the next pending one; `done: [n]` and `start: n` name steps by number,
43+
counted from 1. The host keeps only each step's **status**, by number, so an update never resends the
44+
words. Its reply says where the list stands ("step 3 of 7 is in progress"), warns when more than one
45+
step is in progress, and refuses a step number that does not exist — naming how many steps there are.
46+
Step text is cut at 160 characters; a 13th step is dropped. The model is told to send the list with
47+
its first tool call and each update *with* the call that starts the step, never as a message of its
48+
own, and not to also write the plan out as prose.
49+
- **Where it shows.** In a card pinned under the latest message — the last thing in the transcript, not
50+
a bar above the composer. The card fades in (0.3 s). The tool calls themselves never appear in the
51+
transcript.
52+
- **A step.** A 16 px icon column and the step's text (inline Markdown). Completed: a filled check
53+
circle, the row in the secondary text colour (no strike-through). In progress: a spinner while the
54+
agent is working, a still "dots" circle when it is not (waiting on the user). Pending: an empty
55+
circle in the muted colour. Each icon carries a screen-reader word: done / in progress / not done.
56+
- **Long lists.** At most 12 rows show. The window starts one step above the step in progress (so the
57+
last finished step stays in view); "N earlier steps" above and "N more to go" below count what is cut.
58+
- **A plan from an earlier message.** While a new request runs and the model has not touched the list
59+
yet, the old list stays with the caption "Plan from before your last message" — unless every step was
60+
already done, in which case nothing shows.
61+
- **When the turn ends,** the list goes away. A list whose steps are all done but the last, still in
62+
progress, is completed when a turn ends cleanly.
63+
64+
### The end of a turn
65+
66+
- **The model's tool.** `wrap_up` takes a `recap` (2–3 sentences, about 300 characters: what is now
67+
true, and what is not done or not verified), and — only when the next move is the user's — an `ask`
68+
(one decision, about 100 characters) with 1–2 `actions` (a reply: a 1–3 word `label` and the
69+
`message` a click sends, or one of the app's own actions). `blocked: true` says the agent cannot go on
70+
without an answer. Calling it also completes every step of the task list.
71+
- **The next-step box.** Drawn only when there is a question with buttons (or the agent is blocked).
72+
It rises into place (4 px, 0.3 s) in the same card as the list, which hides while the box has
73+
something in it. Recap in the secondary colour, the question in the primary colour, then the buttons:
74+
the first one is the recommendation and is drawn as the primary button. A × dismisses it (and stays
75+
dismissed). A blocked turn with no question reads "Claude is waiting on you. Pick a reply or type
76+
your own." A recap alone draws no box: it becomes the session's status line in the sidebar, and the
77+
model's closing message says the rest.
78+
- **The box ends the turn.** When the box holds a question, the tool result tells the model to write
79+
nothing more, and the host ends the turn without another model call.
80+
- **Checks on the buttons.** A reply whose label or message starts with `/` or `!`, holds `@`, or holds
81+
invisible characters is dropped (a click would run a command or hide what it sends); a third button is
82+
dropped; over-long labels and messages are reported back to the model as advice for next time.
83+
84+
### Messages sent while the agent works
85+
86+
- **They queue.** Enter while the agent works does not stop it: the message waits in a band above the
87+
composer and **is sent on its own when the agent is ready**. If the run fails or is stopped, queued
88+
messages are not sent: they go back into the message box, and a note says so.
89+
- **One queued message:** one row — "1 message queued", the text cut to a line, and three icon
90+
buttons: **Send now** (the agent reads it at its next step, without stopping), **Edit in composer**,
91+
**Remove from queue**.
92+
- **Several:** a collapsed row — "3 messages queued · Next: …" with a chevron. Open, each row shows two
93+
lines of its text, a drag handle to reorder, and a menu (Edit in composer, Send now, Remove from
94+
queue); the list scrolls past about 22 rem and has **Clear all** at the foot.
95+
- The band leaves by sliding 6 px down and fading. Every animation is off under reduced motion.
96+
97+
## 2. What LevelCode had
98+
99+
- `update_plan` took the whole list every time (`todos`: `title` + `pending` / `in_progress` / `done`,
100+
up to 20) and the model resent it for every change.
101+
- The webview drew a sticky "Plan 2/5" card above the Keep all / Undo all bar, with a progress bar, a
102+
collapse toggle and ×. It cleared when the next run started and collapsed itself when all done.
103+
- A run ended when the model wrote a line starting with `Done:`. There was no recap or next-step box.
104+
- Enter while the agent worked **stopped the run** (the send button is a stop button while streaming).
105+
There was no queue, and nothing could reach the agent mid-run.
106+
107+
## 3. What LevelCode does now
108+
109+
### The tools (agent.js)
110+
111+
- `update_plan` takes Claude's shape — `items` (1–12 steps, `content` + `pending` / `in_progress` /
112+
`completed`), or `advance`, `done`, `start` — and still accepts the old `todos` / `title` / `done`, so
113+
a conversation started on an older build keeps working. The steps' state lives with the conversation
114+
(extension.js), so `advance` works across runs and a new chat starts empty.
115+
- `wrap_up` takes `recap`, `ask`, `actions` (replies only: `label` + `message`) and `blocked`.
116+
**Calling it is the end of the work**, so auto-verify runs there: if the configured verify command or
117+
the editor's diagnostics find problems in the files the agent changed, the box is not shown and the
118+
tool result carries the problems instead; the agent fixes them and calls `wrap_up` again. When the box
119+
holds a question the run ends on the spot, with no further model call.
120+
- The prompt asks for the list with the first tool call and `advance` with the call that starts the
121+
next step, and for `wrap_up` at the end of every run that kept a list, changed files or ran commands.
122+
A run that ends with a `Done:` line and no `wrap_up` still ends as before (some models will not call
123+
it), and the last in-progress step is completed then, as Claude does.
124+
125+
### The chat page (media/chat.html)
126+
127+
- The **turn box** is a card that is always the last thing in the transcript, holding the task list
128+
while a run works and the next-step box when it ends. Same states as Claude's, in the editor's theme
129+
colours and LevelCode's own icons.
130+
- The **queue band** sits above the composer. Enter while the agent works queues (the send button reads
131+
"Queue" once something is typed); ■ with an empty composer still stops. When a run ends normally the
132+
first queued message is sent; a stopped or failed run puts every queued message back into the message
133+
box, after anything already typed there. A reply button in the next-step box queues the same way if
134+
a run is going. A message counts as "busy" from the moment it is sent until its run starts, so the
135+
queue can never start a second run beside the first.
136+
- **Send now** posts the message to the extension, which hands it to the running agent at its next step:
137+
after the tool results of the current step (in the same message, so every tool call still has its
138+
result), or, if the agent had just answered with no tool call, as a new message that keeps the run
139+
going. It then appears in the transcript as your message, where it landed.
140+
141+
### Where the pieces are
142+
143+
| Piece | File |
144+
| --- | --- |
145+
| What the two tools decide (reading a list, `advance`, replies a click may send) | `extensions/levelcode-ai/turnPlan.js` |
146+
| The tools' schemas and prompt lines; wrap_up in the loop (verify, end the run); delivering Send now | `extensions/levelcode-ai/agent.js` |
147+
| The conversation's list (`agentPlan`), the Send-now inbox, `steer` from the page | `extensions/levelcode-ai/extension.js` |
148+
| The turn box, the queue band, the send button | `extensions/levelcode-ai/media/chat.html` |
149+
| `wrap_up` reserved from MCP tool names | `extensions/levelcode-ai/mcpConfig.js` |
150+
151+
Host → page messages: `plan` {steps}, `wrapUp` {recap, ask, actions, blocked}, `steersDelivered` {ids},
152+
`steersReturned` {ids}. Page → host: `steer` {id, text}.
153+
154+
## 4. Differences on purpose
155+
156+
| Claude | LevelCode | Why |
157+
| --- | --- | --- |
158+
| Window of 12 rows | Window of 8 | The chat is a side panel, usually narrower and shorter than Claude's transcript column. |
159+
| A recap alone is the sidebar status | A recap alone shows nothing (the closing message has it) | LevelCode has no session sidebar status line. |
160+
| App actions as buttons (commit, create PR, fix CI …) | Replies only | LevelCode has no such app actions yet; Keep all / Undo all stay in their bar. |
161+
| A keyboard shortcut presses the recommended button | Buttons are focusable; no shortcut | Enter in the composer must keep meaning "send". |
162+
| Steps can name a side session | Not supported | LevelCode has no side sessions. |
163+
| "N running tasks" under the step in progress | Not shown there | Background commands already have their tray (`#bgTasksBar`). |
164+
| Send now on a message with images | Text only; a queued message with images waits for its turn | Mid-run delivery carries text into a tool-result message. |
165+
| A queued message's menu opens below its button | Below, or above when the window has no room below | The band sits low, over the composer, in a short panel. |
166+
| No closing-line convention | The closing answer still starts with `Done:` unless the box holds the question | The loop has always used it to tell a finished answer from a stall, and a model that never calls `wrap_up` still ends cleanly with it. |
167+
168+
## 5. Decisions
169+
170+
1. **Enter while the agent works queues the message, as in Claude** (owner, 2026-10-19). It waits
171+
above the composer and sends itself when the run ends; *Send now* hands it to the agent at its next
172+
step without stopping. This supersedes, for now, the Mid-Run Messaging Spec (2026-10-04), where
173+
Enter *steers* (delivered at the next step, with write and command calls held until the agent
174+
re-decides) and ⌘Enter queues. The owner was offered that spec's behaviour, and "this now, the spec
175+
later", and chose this alone: so the spec's steering by default and its holding of write and command
176+
calls are not built. *Send now* is the only way a message reaches a run in progress.
177+
178+
## 6. How to check it
179+
180+
- The gate (`./scripts/test-extensions.sh`) runs three suites for this: `test/turnPlan.test.js` (the rules),
181+
`test/agentPlanProgress.test.js` (the real agent loop on scripted turns) and `test/planProgressUi.test.js`
182+
(the page's decisions, lifted out of `chat.html`). 23 hand-made mutations of the feature's key lines were
183+
each caught by one of them.
184+
- In the real editor, with no key: `node extensions/levelcode-ai/scripts/plan-progress-editor-check.js --vscode <checkout with vscode/>`.
185+
A stand-in model is scripted turn by turn and held at three points, so the page is looked at and typed into
186+
while the agent "works"; it writes screenshots in LevelCode One Dark and LevelCode One Light.
187+
- In the browser edition: build the extension (`node web/ai-extension/build.mjs --out <dir> --vscode <checkout>`,
188+
then copy `web/workspace` to `<dir>/levelcode-web`) and run
189+
`node web/test/e2e-plan-progress.mjs --static <vscode-web> --extensions <dir> --scheme dark` (and `light`).
190+
191+
## 7. Not verified
192+
193+
- No real model has driven it: every run so far used a scripted stand-in. Whether real models call
194+
`update_plan` with `advance` (rather than resending the list) and `wrap_up` with a sensible question is
195+
untested — Claude, GPT and the OpenRouter models may differ.
196+
- Only the OpenAI-compatible route ran (a BYOK custom provider). The Anthropic-native route and the
197+
LevelCode gateway were not exercised end to end. A run that ends on a question leaves the history ending in a tool
198+
result, and the next message follows it; that shape already occurs after ■, but was not re-checked here.
199+
- Drag-to-reorder was checked from the keyboard (Alt+↑ / Alt+↓) only; dragging with the mouse was not driven.
200+
- Linux and Windows were not run; neither were Safari or Firefox for the browser edition.

0 commit comments

Comments
 (0)