From 4b02b45a058340dbba28fa073c63af417d270fe4 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 10 Jul 2026 00:31:00 +0400 Subject: [PATCH] [ai] Improve Codex implement command. --- .agents/shared/test-loop.md | 96 ++-- .agents/skills/implement/SKILL.md | 483 +++++++++++------- .agents/skills/implement/agents/openai.yaml | 4 + .../references/computer-use-testing.md | 185 +++++++ .agents/skills/task-think/PROMPTS.md | 81 +-- .agents/skills/task-think/SKILL.md | 56 +- .claude/commands/implement.md | 31 +- 7 files changed, 645 insertions(+), 291 deletions(-) create mode 100644 .agents/skills/implement/agents/openai.yaml create mode 100644 .agents/skills/implement/references/computer-use-testing.md diff --git a/.agents/shared/test-loop.md b/.agents/shared/test-loop.md index 3d6c7a9d67..38332010d2 100644 --- a/.agents/shared/test-loop.md +++ b/.agents/shared/test-loop.md @@ -1,10 +1,11 @@ # Test Loop Protocol (harness-neutral) -The portable core of autonomous, tested implementation. Both `/implement` (Claude Code) -and `$implement` (Codex) read and follow THIS file verbatim for the testing phase, so the -impl⇄test loop behaves identically across harnesses. The harness-specific wrappers own -project setup, task splitting, and the spawn/wait mechanics; this file owns everything from -"a single task's implementation is committed" onward. +The portable core of autonomous, tested implementation. Both `/implement` (Claude Code) and +`$implement` (Codex) read it. This file defines shared defaults after one task's implementation is +committed; wrappers own setup, splitting, and spawn/wait mechanics. A wrapper may explicitly adapt +commit ownership, task baseline/attempt caps, staging/source restoration, account swapping, +`EVIDENCE_DIR`, or an optional UI driver. Its named rule wins only at that +adapter point; every other rule here still applies. ## Vocabulary @@ -21,7 +22,9 @@ project setup, task splitting, and the spawn/wait mechanics; this file owns ever ## Inputs the wrapper passes in - `TASK_DIR` — `.ai///` for this task. -- `TASK_ID` — stable id used in commit trailers (e.g. the project + letter). +- `TASK_ID` — stable artifact/log identifier (e.g. the project + letter); never a commit trailer. +- `EVIDENCE_DIR` — per-run logs and screenshots; defaults to `TASK_DIR` unless the wrapper passes a + run-specific directory. - **TASK SPEC** — the task's full description block (from `implementing.md`) and its referenced images (`images/` design mockups / screenshots / graphic resources for this isolated task). This is half of what the tests are designed against (the diff is the other half); the design READS @@ -57,9 +60,10 @@ Early-escalation rule: if two consecutive ASSESS rounds produce the **same failu the attempt budget chasing it. UNRECOVERABLE conditions: the app reaches a login screen / `AUTH_KEY_DUPLICATED` and re-copying the -test account does not recover it; a file-lock build error (`LNK1104`, `C1041`) that persists after -the path-scoped kill; `test_TelegramForcePortable` missing when SETUP runs; or a crash with no usable -diagnostic after one retry. +test account does not recover it; `test_TelegramForcePortable` is missing when SETUP runs; or a crash +has no usable diagnostic after one retry. A file-lock build error (`LNK1104`, `C1041`, access denied, +file in use) is a repository hard stop: do not retry or work around it; ask the user to close the app +and debugger. ## Handoff tokens @@ -67,8 +71,9 @@ diagnostic after one retry. message" below (and, if submodules changed, commit inside each submodule first, then bump the superproject pointer in the same logical attempt — real commits, never stash). The runner records the resulting SHA as that attempt's IMPL_SHA. -- **Result doc** (`result.md`) is the only thing handed back to a fix agent and the only thing - the runner reads to decide. See format below. +- **Test report** (`test.md`) is the only fix-agent handoff. Give it the latest Attempt/Run section, + especially Root cause / Fix hint and Failure signature. Reserve wrapper-owned `result.md` for the + terminal task result; never create `result.md`. ## Commit message @@ -230,14 +235,14 @@ highest level that still exercises the change (often a direct data-layer call li - Drive the scenario on the Qt event loop, preferring **condition-waits over fixed timers** (wait until the target widget/data actually exists, with a timeout fallback). Fixed sleeps are the main source of screenshot flake. -- Write a flushed log to `/test_log.txt` (open Append|Text, flush after each write) and - save screenshots to `/screenshots/`. Delete the old log at the first step. +- Write a flushed log to `/test_log.txt` (open Append|Text, flush after each write) and + save screenshots to `/screenshots/`. Delete the old log at the first step. - **Capture the target tightly.** Grab the specific widget / row / glyph (or crop the saved PNG to it) so the target is unambiguously in frame at usable resolution. A full-window grab that leaves the target clipped, off-screen, or thumbnail-sized is NOT acceptable evidence — if the target isn't clearly captured, that is a TEST_FLAW (re-frame), never a pass. - **Lay down the oracle's reference.** For an asset/visual check, also save the OLD and intended-NEW - art as PNGs beside the crop (`screenshots/_old.png`, `_new.png`) so the assessment is + art beside the crop (`/screenshots/_{old,new}.png`) so the assessment is a direct three-way comparison, not a memory test. - Emit these markers, one per line: `TEST_STEP: ` · `TEST_RESULT: PASS: ` / `TEST_RESULT: FAIL: -
` · @@ -279,10 +284,10 @@ fix it; it is a real bug in the overlay, not a stale build. ### Log to an ABSOLUTE path (the launcher chdir's) The Windows launcher changes the working directory to the exe folder before the app runs, so a -**relative** overlay log path (`/test_log.txt`) silently fails to write (`QFile` won't -create missing parents) — the run looks "clean" but produces no evidence. Resolve `` to an -absolute path up front (e.g. `QDir::current().absoluteFilePath(...)` computed at inject time, or an -absolute path baked into the overlay) so flushes actually land; likewise for screenshots. +**relative** overlay log path (`/test_log.txt`) silently fails to write (`QFile` won't +create missing parents) — the run looks "clean" but produces no evidence. Create and resolve +`EVIDENCE_DIR` to an absolute path up front (or bake its absolute path into the overlay) so flushes +actually land; likewise for screenshots. ### Git mechanics for the overlay (no stash) @@ -292,26 +297,27 @@ absolute path baked into the overlay) so flushes actually land; likewise for scr touched submodules). The overlay never enters an impl commit. - Next round, re-apply on top of the new implementation: `git apply --3way /test-overlay.patch`. This succeeds ~90% of the time when the tail change was small. -- On conflict, **re-author the conflicting hunk from the spec** in `test.md` (which records - intent: injection point, fake values, assertions) rather than fighting the conflict markers. +- On conflict, **re-author the conflicting hunk from the latest Attempt/Run in `test.md`** (which + records injection point, fake values, and assertions) rather than fighting conflict markers. Scenario steps that only call public APIs should live in their own block so they never conflict; only true in-situ injections land inside impl files. ## Build & run discipline - Build with `BUILD`. A single changed TU compiles fast; only the overlay-touched files + link - rebuild between rounds. On `LNK1104`/`C1041`, run the path-scoped kill (Test account → "Serialize - app runs"), wait, retry once; if it persists -> UNRECOVERABLE. + rebuild between rounds. Proactive path-scoped cleanup may run before the build. If the build reports + `LNK1104`, `C1041`, access denied, or file in use, follow `AGENTS.md`: stop immediately, do not + retry or attempt a workaround, and ask the user to close the app/debugger. - **Codegen does not track resource mtimes.** If the task changed only a resource the style codegen consumes (an icon `.svg`, etc.) without touching a `.style`, an incremental build will NOT re-pack it and the binary keeps the OLD asset. Before building such a task force regeneration — touch the referencing `.style` (or clean the codegen output) — so the change actually ships. A render that shows no difference from before is the symptom of skipping this. -- Run: run the SETUP steps (Test account) -> launch `EXE` **with `-testagent`** in the background, - redirecting BOTH stdout and stderr to `/app_stderr.txt` (see "Crashes & assertions" - below — this flag is what stops a crash from hanging on a modal dialog, and the redirect is what - captures the assertion text) -> **start a hard wall-clock deadline (~90s) from launch** -> poll - `test_log.txt` every ~5s -> on each `SCREENSHOT:` read the image and judge it -> detect +- Run: run the SETUP steps (Test account) -> create `EVIDENCE_DIR` -> launch `EXE` **with + `-testagent`** in the background, redirecting stdout to `/app_stdout.txt` and stderr + to `/app_stderr.txt` (this flag prevents modal crash hangs, and stderr captures + assertion text) -> **start a hard wall-clock deadline (~90s) from launch** -> poll + `/test_log.txt` every ~5s -> on each `SCREENSHOT:` read the image and judge it -> detect `TEST_COMPLETE` (success) or process death (crash) or no new output for the watchdog cap, or the hard deadline elapsing (hang) -> path-scoped kill of any straggler (Test account → "Serialize app runs") -> optional CLEANUP -> save the overlay (`git diff > /test-overlay.patch`) -> @@ -321,8 +327,8 @@ absolute path baked into the overlay) so flushes actually land; likewise for scr $exe = (Resolve-Path "$EXE").Path Start-Process -FilePath $exe -ArgumentList '-testagent' ` - -RedirectStandardError "$TASK_DIR/app_stderr.txt" ` - -RedirectStandardOutput "$TASK_DIR/app_stdout.txt" -PassThru + -RedirectStandardError "$EVIDENCE_DIR/app_stderr.txt" ` + -RedirectStandardOutput "$EVIDENCE_DIR/app_stdout.txt" -PassThru ### Crashes & assertions (always launch the test binary with `-testagent`) @@ -336,7 +342,7 @@ set, the binary: - converts any such assertion into a real crash that the crash reporter records, so the process **terminates immediately** instead of waiting; - writes the assertion text (expression + file:line) to **stderr** — captured in - `/app_stderr.txt`, tagged `[testagent]`; + `/app_stderr.txt`, tagged `[testagent]`; - also turns on debug logging (`-testagent` implies `-debug`). **Do NOT key the crash decision on exit code.** Breakpad handles the crash and the process usually @@ -345,7 +351,7 @@ process is gone WITHOUT a `TEST_COMPLETE` marker, AND a fresh non-empty `/tdata/working` exists. So **always pass `-testagent`**, and on a crash gather diagnostics in this order before deciding the verdict: -1. **`/app_stderr.txt`** — the `[testagent] assert: …` line gives the failed expression and +1. **`/app_stderr.txt`** — the `[testagent] assert: …` line gives the failed expression and `file:line` (e.g. `vector(1931) : … vector subscript out of range`). Usually enough to localize. 2. **`/tdata/working`** — the crash report the reporter wrote: the `Assertion:` / `CrtAssert:` annotations, the failed `file:line`, and `Caught signal …` / minidump id. Plain text; @@ -428,29 +434,33 @@ correct. ## Test report (`/test.md`) — human-readable, append per attempt -The file the human opens to see how testing went. The test-author writes the checks (Expected / -Oracle / Observed via) BEFORE running; ASSESS fills Actual / Result and the verdict. Append a new -`## Attempt` section each round — never overwrite prior attempts. +The file the human opens to see how testing went. The test-author writes checks before running; +ASSESS fills Actual / Result and the verdict. Create one `## Attempt` per implementation commit and +append one `### Run` per execution. A TEST_FLAW adds a Run under the same Attempt; an IMPL_BUG fix +starts the next Attempt. Never overwrite history. ``` # Test report — /: -## Attempt <n> — commit <sha> — strategy <...> — verdict: <APPROVED|TEST_FLAW|IMPL_BUG|UNRECOVERABLE> +## Attempt <n> — commit <sha> -### Test 1 — <aspect of THIS change> +### Run <m> — strategy <...> — driver <overlay|hybrid> — verdict <APPROVED|TEST_FLAW|IMPL_BUG|UNRECOVERABLE> +- Evidence directory: <EVIDENCE_DIR> + +#### Test 1 — <aspect of THIS change> - Expected: <observable effect the change should produce> - Oracle: <what would make this check FAIL> - Observed via: <surface + how captured: tight crop of widget X; refs _old/_new> - Actual: <what is literally visible / logged> -- Screenshots: screenshots/<after>.png (refs: _old.png, _new.png) +- Screenshots: <EVIDENCE_DIR>/screenshots/<after>.png (refs: _old.png, _new.png) - Result: PASS | FAIL -### Test 2 — ... +#### Test 2 — ... -### Verdict reasoning +#### Verdict reasoning <1-3 lines tying the checks to the verdict> -### Root cause / Fix hint (only if IMPL_BUG — the impl-fix agent reads this) -### Failure signature (one line, for early-escalation comparison) +#### Root cause / Fix hint (only if IMPL_BUG — the impl-fix agent reads this) +#### Failure signature (one line, for early-escalation comparison) ``` ## Compact summary the task-runner returns up @@ -458,10 +468,10 @@ Oracle / Observed via) BEFORE running; ASSESS fills Actual / Result and the verd ``` TASK: <TASK_ID> STATUS: <DONE|BLOCKED> -VERDICT: <APPROVED|reason if blocked> +VERDICT: <APPROVED|NOT_APPLICABLE|reason if blocked> ATTEMPTS: <n> TOUCHED: <repo paths or none> -DISCOVERED: <new follow-up tasks to append to implementing.md, or none> +DISCOVERED: <none|present in result.md|inline concise follow-ups when the wrapper has no result.md> NOTES: <one or two lines, or none> ``` diff --git a/.agents/skills/implement/SKILL.md b/.agents/skills/implement/SKILL.md index ad4a5298f0..f43cb32575 100644 --- a/.agents/skills/implement/SKILL.md +++ b/.agents/skills/implement/SKILL.md @@ -1,64 +1,75 @@ --- name: implement -description: Autonomously implement a request on this repository (Telegram Desktop). Accept an inline description, a task-list file, or just a project name with a prepared .ai/<project>/tasks/about.md default task source, normalize it into a project with a testability-split task list, then drive each task to test-approval through an isolated per-task runner subagent that does context, planning, implementation, build, a single review pass, and an in-app test loop. Use when the user wants one prompt — ideally under Goal run mode — to carry work all the way to a tested, approved state with persistent .ai/ artifacts and a thin parent thread. Reuses task-think's phase prompts and the shared test-loop protocol; prefers spawn_agent/wait_agent and keeps the main thread lean. +description: Autonomously implement and verify Telegram Desktop changes from an inline request, task-list path, or a prepared project task source under .ai. Use when Codex should split work into independently testable tasks and drive each through context, planning, implementation, a Debug build, one review pass, and artifact-grounded in-app testing with optional Computer Use, resumable artifacts, a lean parent task, and native-Windows CRLF normalization. --- # Implement Pipeline -You are the top orchestrator. Take a request -- an inline description OR a task-list file -- -normalize it into a project with a testability-split task list, and drive each task to -test-approval through an isolated per-task **task-runner** subagent. Keep your context lean: hold -only the task list and one compact summary per task. All heavy work (planning, coding, building, -testing) happens inside subagents whose context is discarded. +You are the top orchestrator. Normalize an inline description or task-list file into a project with +a testability-split task list, then drive each task to test-approval through an isolated per-task +**task-runner**. Keep only the task list and one compact summary per task in the parent. Heavy work +happens in the disposable runner and, when nested delegation is available, fresh leaf phase agents. This tested superset of `task-think` does not re-specify the implementation phases or the test -loop. It reuses: +loop. Read and reuse: - `.agents/skills/task-think/PROMPTS.md` — Phase 0-6 prompt templates and the Codex execution-mode / wait-ladder / progress-heartbeat / compact-reply rules. -- `.agents/shared/test-loop.md` — the harness-neutral impl⇄test loop (state machine, commit - handoff, overlay mechanics, `--3way`/re-author, test-account swap, watchdog, escalation). - -Read both before orchestrating. +- `.agents/shared/test-loop.md` — the harness-neutral impl⇄test loop (state machine, handoff, + overlay, account swap, watchdog); `references/computer-use-testing.md` adds a Codex-only UI driver. ## Inputs -`$ARGUMENTS` = ONE of: +Set `REQUEST` to the invoking user text, including attached-image references; skills do not receive +the deprecated custom-prompt `$ARGUMENTS` macro. `REQUEST` is one of: - an inline task description (e.g. `add a dark-mode toggle to settings`) - a path to a task-list file (e.g. `.ai/communities/tasks.txt` -- a rough list of tasks to refine) - an existing project name to resume, optionally followed by extra work -- **just a project name with a prepared `.ai/<project>/tasks/about.md`** -- the default task source - (see Artifacts). With no other input, `implement <project>` plans and implements straight from that - file, so `implement communities` alone fires the full pipeline off `.ai/communities/tasks/about.md`. - -May also reference attached images. +- **just a project name with a prepared `.ai/<project>/tasks/about.md`** -- the default task source. + With no other input, `implement <project>` runs it (see Artifacts). ## Config -Runs in the **current checkout** — wherever the skill is invoked. No worktrees are created; paths -below are relative to that repository root. +Run in the **current checkout** without creating a worktree. Resolve platform, build tree, command, +and executable together; never mix native-Windows commands with a WSL tree. ``` -BUILD = cmake --build ./out --config Debug --target Telegram -EXE = ./out/Debug/Telegram.exe (or ./out/Debug/Telegram on WSL/Linux — verify the tree) -TEST_ACCOUNT = ./out/Debug/test_TelegramForcePortable (user-prepared golden; launch gate aborts if absent) -MAX_ATTEMPTS = 4 -SUBAGENT_MODEL = highest-quality available non-fast model (currently gpt-5.5) -SUBAGENT_REASONING = xhigh +NATIVE_WINDOWS_BUILD = cmake --build ./out --config Debug --target Telegram +WSL_BUILD = Telegram/build/docker/centos_env/build_debug.sh +EXE_CANDIDATES = out/Debug/Telegram.exe | out/Debug/Telegram | out/Debug/Telegram.app/Contents/MacOS/Telegram +COMPUTER_USE_APP_TARGET = Windows: absolute EXE | macOS: absolute outer .app containing EXE | other: none unless supported +TEST_ACCOUNT = out/Debug/test_TelegramForcePortable +MAX_ATTEMPTS = 4 +MAX_TEST_RUNS = 12 +COMPUTER_USE_POLICY = auto | overlay-only | required (default auto; user request overrides) +SUBAGENT_QUALITY = inherit the parent task's selected model and reasoning effort ``` -`EXE` is also the process-cleanup scope. Any autonomous kill step must match the full executable -path for THIS checkout's built binary only; never blanket-kill all `Telegram.exe` processes. +Follow `AGENTS.md` if it names a different command. Build Debug only. Verify `EXE` from the actual +tree. Scope proactive cleanup to its resolved full path; never kill processes by image name. -The test binary is **always launched with `-testagent`** (see test-loop.md "Crashes & assertions"): -it suppresses the Debug Abort/Retry/Ignore dialogs that would hang the run, turns any CRT/STL -assertion (and a frozen main thread) into an immediate crash with a written `tdata/working` report, -and writes the assertion text to a captured stderr file so a crash is diagnosable instead of a silent -hang. Key crash detection on the report file, not the exit code. +The test binary is **always launched with `-testagent`** (test-loop.md "Crashes & assertions"). It +suppresses modal assertion dialogs, turns assertions and a frozen main thread into a crash with a +`tdata/working` report, and writes assertion text to captured stderr. Detect crashes from the report, +not the exit code. -For every subagent spawned by this skill — planner, task-runner, per-phase implementation/review -agents, test-author agents, and impl-fix agents — request `SUBAGENT_MODEL` and -`SUBAGENT_REASONING` when the host supports model overrides. If model names change, choose the -smartest/frontier model available, never a mini, fast, spark, or cost-optimized variant. +Keep the parent model/reasoning selection for all subagents; a GPT-5.6 Sol Ultra parent therefore +keeps that quality. Do not invent model, reasoning, or role fields missing from `spawn_agent`. If a +host exposes overrides, match the parent. Custom agents use `model_reasoning_effort`. + +### Codex collaboration contract + +- Use `spawn_agent` with a unique lowercase/digit/underscore `task_name`; save its canonical target. +- Use `fork_turns: "none"` with self-contained prompts; fork minimal turns only for thread-only context. +- The top orchestrator spawns the task-runner; the runner selects NESTED only after its first real + phase-leaf spawn succeeds. An immediate depth/capacity/policy rejection before phase work selects + SAME-RUNNER; then execute the same prompt checklists locally. Never switch modes for a wait timeout. +- Every delegated planner or phase worker is a leaf and must not spawn more agents, especially under + Ultra's proactive delegation. Keep implementation phases sequential unless their plan proves + disjoint write sets and the current checkout has safe capacity. +- `wait_agent` can wake for any agent or new user input, not just the intended target. After every + wake, inspect the saved target with `list_agents` and validate its artifact. Follow the detailed + wait/retry contract in `task-think/PROMPTS.md`. +- Never duplicate a task-runner. It owns stateful writes, commits, and test attempts. Tasks run **sequentially** in this one checkout (the build cache stays warm; app runs must serialize against the account anyway). To parallelize, run the skill in a different checkout/slot (e.g. @@ -73,38 +84,52 @@ clients on one auth key can trigger a session reset, so give parallel slots sepa This is the file the user prepares; the planner reads it as SOURCE when `implement <project>` is invoked with no other input. It is **distinct** from the project blueprint `.ai/<project>/about.md` (the `tasks/` subdir is what disambiguates them). -- `.ai/<project>/implementing.md` — the canonical, final, testability-split task list (descriptions - + status); the main thread is its only writer. +- `.ai/<project>/implementing.md` — the canonical, final, testability-split task list. The planner + creates or rewrites it in Phase B; after the main thread adopts it, only the main thread edits it. - `.ai/<project>/images/` — illustrations referenced by tasks (`images/01.png`, ...). -- `.ai/<project>/<letter>/` — per-task artifacts (context, plan, review, test, result, overlay, logs). +- `.ai/<project>/<letter>/` — task context, plan, visual contract, review, test, result, overlay, logs. - `.ai/<project>/about.md` — project blueprint (task-think convention). -## Done (for Goal run mode) +## Terminal state and Goal mode -The run is **done** when every task in `implementing.md` has `Status: approved` or -`Status: blocked: <reason>`. Under Goal run mode this is the stop condition. The run is -**resumable**: re-invoking with the project name reads `implementing.md` and continues from the -first unfinished task. +The pipeline is terminal when every task is `approved` or `blocked: <reason>`, but successful only +when all are approved. A blocked task is a loud terminal result, not goal achievement. + +If a Goal mode objective is active, do not create or replace it. Complete it only when every task is +approved; use blocked-state rules only when their threshold is satisfied. Reinvocation continues +`todo` or `in-progress` tasks; a blocked task stays terminal until explicitly requeued or replaced. ## Phase A: Setup & input resolution (main thread) -1. Record `$START_TIME` (for example with `Get-Date`). -2. **Test-account gate (hard precondition — before any work).** If +1. Record `START_TIME` with the host's current-time facility. +2. Detect native Windows vs WSL/Linux vs macOS/other; read `AGENTS.md`; resolve `BUILD`, `EXE`, + `TEST_ACCOUNT`, `COMPUTER_USE_APP_TARGET`, `COMPUTER_USE_POLICY`, and the active Computer Use + skill path (or `none`). On macOS require EXE to realpath under `<target>.app/Contents/MacOS/`, never + use the inner binary as the app target. Strip only a driver-policy directive from `REQUEST`. On WSL use Docker + and LF/no-BOM; on native Windows use the configured Debug tree and later CRLF phase. + Verify path-scoped process control, safe folder ops, launch/capture, and a usable app-run display + (WSLg/Xvfb counts) or stop. Never build Release; Computer Use capability is separate and optional. +3. **Test-account gate (hard precondition — before planning or implementation).** If `out/Debug/test_TelegramForcePortable` does not exist, STOP the entire skill immediately and tell the user that the test account is not prepared: create `out/Debug/test_TelegramForcePortable` (a portable-data folder authed to a throwaway test account) before `implement` can run, because autonomous testing is impossible without it. Do no implementation work. -3. **Resolve `$ARGUMENTS` into (project, SOURCE, mode) — without reading task files or images.** +4. **Clean-checkout gate.** Require a clean tracked worktree and clean submodules before the first + planner or runner spawn. Ignored `.ai/` artifacts are allowed. If unrelated tracked, staged, + untracked, or submodule changes exist, stop without stashing, committing, or resetting them. + Record `BASE_SHA`; invocation authorizes destructive resets only for changes proven to belong to + this workflow. +5. **Resolve `REQUEST` into (project, SOURCE, mode) — without reading task files or images.** The main thread never loads task prose or assets; resolving needs only paths and existence checks. SOURCE ends as EITHER inline text OR a confirmed file path that the planner will read. - - **File input** — if the first token is a path: confirm it exists (for example with `Test-Path`, - do NOT read it) and set SOURCE = that path. If the path is under `.ai/<name>/`, project = - `<name>`; else derive a short kebab name from the filename. Mode = **extend** if that project - already has `implementing.md`, else new. + - **File input** — if `REQUEST` as a whole or its first quoted token resolves to an existing path, + confirm existence without reading it and set SOURCE to that path. If it is under `.ai/<name>/`, + project = `<name>`; otherwise derive a short kebab name from the filename. Mode = **extend** if + that project already has `implementing.md`, else new. - **Existing project** — else if `.ai/<FIRST_TOKEN>/` exists: project = `FIRST_TOKEN`. - - If there is a **remainder** → mode = **extend**: if the remainder is itself a path to an - existing file, SOURCE = that path (confirm it exists, do NOT read it); otherwise SOURCE = the - remainder text. + - If there is a **remainder**: if it is a path to an existing file, SOURCE = that path (confirm + it exists, do NOT read it); otherwise SOURCE = the remainder text. Mode = **extend** only when + `implementing.md` exists; otherwise mode = **new** within this existing project directory. - If the remainder is **empty**, resolve SOURCE in this priority order (existence checks only, do NOT read): 1. If `.ai/<project>/tasks/about.md` exists → SOURCE = that file (the **default task @@ -114,33 +139,36 @@ first unfinished task. still-unfinished tasks). 3. Else there is nothing to implement — tell the user to prepare `.ai/<project>/tasks/about.md` (or pass a description / task-file path) and stop. - - **New inline** — else SOURCE = all of `$ARGUMENTS`; pick a unique short kebab-case project name + - **New inline** — else SOURCE = all of `REQUEST`; pick a unique short kebab-case project name after consulting `.ai/`. After this step you always have a project name and either a SOURCE (inline text or a confirmed path) or mode = **resume** — and you have read neither the file nor any image. -4. Create `.ai/<project>/` and `.ai/<project>/images/` if new. -5. **Images must be on disk.** The planner reads images as files, and subagents cannot see chat - attachments, so every image a task needs must exist as a file (referenced by the SOURCE file, or - under `.ai/<project>/images/`). The main thread usually cannot save a pasted/inline chat image to - disk from text-only tools. If the user only pasted an image into chat, either ask them to drop it - into `.ai/<project>/images/` as a file, or, as a lossy fallback, write a textual description for - the planner. Do not claim to have saved it. Images the SOURCE file *references by path* are the - planner's job, not handled here. -6. If mode = **resume**, skip Phase B and go to Phase C. + Set `FIRST_TASK_ID` after a narrow heading scan to the next id after the union of task headings + in `implementing.md` and artifact directories (`a`...`z`, `aa`...); never reuse an id. +6. Create `.ai/<project>/` and `.ai/<project>/images/` if new. +7. **Persist visual inputs.** Every later phase needs a stable file path or an artifact description. + Prefer images already referenced by SOURCE or under `.ai/<project>/images/`. If an attachment is + visible only in recent chat turns, either fork the smallest necessary turn window to the planner + and require a detailed visual description in the task artifacts, or ask the user to save it under + the project images folder. Do not claim a chat-only image was saved. The planner copies any + filesystem-visible referenced image into `.ai/<project>/images/`. +8. If mode = **resume**, skip Phase B and go to Phase C. ## Phase B: Planning & testability split (delegate) -Spawn one planner subagent (`fork_context: false`, request `SUBAGENT_MODEL` and -`SUBAGENT_REASONING` when supported) with this prompt shape: +Spawn one planner with a unique tool-valid task name and `fork_turns: "none"`, except for the +smallest recent-turn fork explicitly selected in Phase A for a chat-only visual. It inherits the +parent quality setting and is a leaf: it must not delegate. Use this prompt shape: ``` You are a planning/splitting agent for a large C++ codebase (Telegram Desktop). +You are a leaf worker. Do not spawn or delegate to other agents. SOURCE — EITHER an inline request OR a path to a task-list file. If it is a PATH, READ it yourself (and any task files it points to); the main thread has NOT read it. If it is inline text, use it as the request: <the inline description, or the file path> -PROJECT: <project> MODE: <new | extend> +PROJECT: <project> MODE: <new | extend> FIRST_TASK_ID: <next unused id> IMAGES — the SOURCE and/or its task file may reference images by path (resolve them relative to the SOURCE file's directory, or use absolute paths; when SOURCE is `.ai/<project>/tasks/about.md`, its @@ -155,9 +183,9 @@ visual spec: <description(s) or none> Read AGENTS.md. Briefly scan the codebase to gauge scope. Produce the FINAL ordered task list that satisfies BOTH constraints for every task: -- **Implementable in one pass**: a single agent with a ~200k-token budget must be able to implement - the task fully on its own WITHOUT triggering context compaction — i.e. a bounded change it can - read and edit across a handful of files, not a sweep across dozens. If a unit is too big, split it. +- **Implementable in one pass**: a fresh implementation agent must be able to complete the task with + comfortable context headroom and without relying on compaction — a bounded change across a + handful of related files, not a sweep across dozens. If a unit is too big, split it. - **Independently testable**: each task must yield an observable behavior the test agent can drive from an in-app debug overlay and verify via log/screenshot. Split on testable seams, so each task ends at a point where something concrete can be exercised and checked. @@ -176,13 +204,16 @@ Write `.ai/<project>/implementing.md` in EXACTLY this format: ## Tasks -### a: <imperative title> +### <FIRST_TASK_ID>: <imperative title> Status: todo <2-4 line self-contained description: what to implement and the observable, testable result. Enough that a fresh agent can act on it.> +Depends-On: none | <comma-separated earlier task ids> +Observable: <specific runtime evidence that proves this task works> +Visual: layout | appearance (UI tasks only — see "Visual classification" below; omit otherwise) Images: images/<file> — <caption> (this line only if the task uses an image) -### b: <imperative title> +### <next id>: <imperative title> Status: todo <...> @@ -194,7 +225,23 @@ do not leave such a task without its images, and do not leave a provided image r (if one genuinely applies to none, note why). These per-task references are the oracle the test phase verifies against — be specific and per-task, not one shared dump on the first task. -Use letters a, b, c... as task ids. Do not plan internals or implement. When done, reply with ONLY a +**Visual classification (required for UI tasks).** For every task that changes how something looks, +add a `Visual:` line; it routes the task-runner: +- `Visual: layout` — reproduce composition: element sizes, proportions, spacing, margins, + alignment, or component geometry. This triggers a dedicated design-spec phase and a + geometry-measuring oracle. Such a task must cite its mockup(s) with `Images:`. +- `Visual: appearance` — match color, wording, style choice, or glyph identity without changing + proportions or geometry. This uses the lighter visual comparison without a numeric contract. +- Omit `Visual:` only when the task changes no appearance. +When uncertain, use `layout` for anything composed from multiple sized or positioned pieces. The +user may override the classification by editing `implementing.md`. + +Every task must include `Depends-On:` and `Observable:`. Dependencies may name only earlier tasks. +Use `Depends-On: none` when the task can still run after any earlier task is blocked. The observable +must name the exact log value, action/state transition, or tightly framed visual evidence the test +will verify; "screen opens" is not sufficient. + +Use spreadsheet-style ids a...z, aa... without reusing an existing task artifact id. Do not plan internals or implement. When done, reply with ONLY a compact confirmation — `ready — <N> tasks` (extend: `ready — appended <letters>`); do NOT echo the task list or image contents back, the main thread reads `implementing.md` itself. ``` @@ -203,37 +250,54 @@ For **extend** mode, instead instruct the planner to FIRST read the existing `im rewrite it as: (1) a TRIMMED completed-history — keep only the **three most recent** `Status: approved` task blocks (the three nearest the bottom of the file) and drop all earlier approved ones; (2) every still-unfinished task left untouched, in place and with its status — that is all `todo`, `in-progress`, -and `blocked` blocks (never drop these); then (3) APPEND new lettered tasks (continuing the letter -sequence from the highest letter still present after the trim) after them. The trim only removes +and `blocked` blocks (never drop these); then (3) APPEND new tasks starting at FIRST_TASK_ID after +them. FIRST_TASK_ID follows the pre-trim task-heading/artifact union. The trim only removes already-approved entries from the list — it never touches the per-task `.ai/<project>/<letter>/` artifacts on disk, so a follow-up letter can still read an earlier letter's `context.md` even after its -block was trimmed out of `implementing.md`. It must append ONLY tasks from SOURCE not already -represented in `implementing.md` — so re-running `implement <project>` against an unchanged default -`tasks/about.md` appends nothing (the planner replies `ready — appended (none)`, still applying the -completed-history trim) and Phase C just finishes whatever is still unfinished. (Any +block was trimmed out of `implementing.md`. It must append only work from SOURCE not already +represented either in `implementing.md` or in the preserved per-task `context.md`, `result.md`, and +test artifacts. Deduplication must include trimmed history, so re-running `implement <project>` +against an unchanged default `tasks/about.md` appends nothing (the planner replies +`ready — appended (none)`, still applying the completed-history trim). Any `todo`/`in-progress` leftovers from an interrupted run are picked up by Phase C regardless, so -defaulting to extend never loses an in-flight batch — it is a superset of resume.) +defaulting to extend never loses an in-flight batch; it is a superset of resume. -After the planner replies `ready`, read `implementing.md` back ONCE (your first and only load of the -task prose; you never read the images). Initialize a progress list mirroring the tasks so progress -is visible. +After the planner replies `ready`, read `implementing.md` once (the first and only load of task +prose; never read images) and initialize a progress list mirroring the tasks. + +For **resume**, read and validate `implementing.md` once here before Phase C and initialize the same +progress list. Treat any status line beginning with `Status: approved` or `Status: blocked` as the +corresponding legacy terminal state, then normalize it to the canonical grammar the next time the +main thread edits that block. For a legacy unfinished block without `Depends-On:` or `Observable:`, +assume `Depends-On: none` and use its self-contained result sentence as the observable rather than +blocking resume on a format migration. ## Phase C: Per-task loop (main thread orchestrates) -For each task whose `Status` is not `approved`/`blocked`, in order: +For each task whose normalized `Status` is neither `approved` nor `blocked`, in order: -1. Set `Status: in-progress` and mark the corresponding progress item in progress. Spawn ONE - **task-runner** worker (`fork_context: false`, request `SUBAGENT_MODEL` and - `SUBAGENT_REASONING` when supported; currently `model: gpt-5.5` and - `reasoning_effort: xhigh`) with the prompt below. Apply task-think's wait ladder - (5-min waits while in progress, 1-2 min near completion; inspect the task's progress/result - artifacts on timeout; one follow-up then one fresh retry before escalating). -2. Read only its compact reply block. Detail is in `.ai/`. -3. Update the task's `Status:` — `approved` (STATUS DONE) or `blocked: <reason>`. -4. Append any `DISCOVERED` tasks as new lettered `### <letter>:` blocks (`Status: todo`) after the - remaining ones, and add them to the progress list. The main thread is the only writer of - `implementing.md`. -5. On BLOCKED, **do NOT stop the loop — prioritize continuing development.** This often runs +1. If any id in `Depends-On:` is blocked, do not spawn a runner. Set + `Status: blocked: prerequisite <ids> blocked`, record the missing behavior, and continue to the + next independent task. The main thread creates its canonical `result.md` with `STATUS: BLOCKED`, + `Blocker-Type: impl`, HEAD as base, no implementation/test, and prerequisite results as evidence. +2. Record `TASK_BASE_SHA = HEAD`, set `Status: in-progress`, and mark the progress item in progress. + Spawn exactly one **task-runner** with a unique task name and `fork_turns: "none"`, using the + prompt below. It inherits the parent model and reasoning selection. +3. Poll with waits no longer than 60 seconds. Each wake may belong to another agent or user input; + check the runner's canonical target and its progress/result artifacts. Use `send_message` while + it is running and `followup_task` if it is idle but owes the final result. Never fresh-retry the + whole runner. If it becomes irrecoverably unresponsive, interrupt it, audit the checkout and + artifacts, and classify the task as blocked only if the tree is clean and buildable; otherwise + hard-stop. +4. Validate `<TASK_DIR>/result.md`, its referenced commit, `test.md` when applicable, cleanup state, + and a clean worktree. The compact reply is a notification, not proof. Update the canonical task + status to `approved` only for a validated `STATUS: DONE`; otherwise write + `blocked: <specific reason>`. +5. When `Discovered: present`, accept ordered blocks headed `discovered-1`, `discovered-2`, etc. Rescan + current task headings and artifact dirs, assign unused spreadsheet ids, and rewrite earlier placeholder + dependencies before appending. Reject collisions/forward dependencies; send malformed blocks through a leaf planner. Only the main thread assigns ids and writes + `implementing.md` after Phase B. +6. On BLOCKED, **do NOT stop the loop — prioritize continuing development.** This often runs unattended for hours, so NEVER pause to ask the user whether to go on; record the blocker and move to the next task as long as further progress is possible: - **Test-blocked** — the runner committed a building impl and only its in-app verification could @@ -245,81 +309,155 @@ For each task whose `Status` is not `approved`/`blocked`, in order: - **Hard stop ONLY when continuing is truly impossible** — a broken / uncommitted / non-buildable checkout, or a global environment failure (file lock needing the user to close `Telegram.exe`, the test-account gate). Only then stop and report. - Before spawning the next task, confirm the working tree is clean and at a buildable commit - (`git status` + the runner's summary); if a blocked runner left it dirty or broken, reset to the - last known-good commit first, else hard-stop. Every blocked/unverified task MUST be surfaced - LOUDLY in Completion — continuing is never the same as silently passing. + Before spawning the next task, confirm the tree is clean and HEAD is a known buildable commit. + Never reset an unexpected or unrelated path. If the runner cannot prove and restore only its own + changes to a known-good SHA, hard-stop. Every blocked/unverified task must be surfaced loudly in + Completion with its exact `<TASK_DIR>/test.md` or `<TASK_DIR>/result.md` path. ### task-runner prompt -``` +```` You are a task-runner for ONE task in an autonomous implement-and-test workflow on Telegram -Desktop (C++ / Qt). You own this task end to end and isolate its context from the orchestrator. -You MUST use subagents (spawn_agent/wait_agent) for each phase, keeping the parent thread lean. -When spawning any subagent for context, plan, assess, implementation, review, test-author, or -impl-fix work, request the highest-quality available non-fast model and highest reasoning effort -(`model: gpt-5.5`, `reasoning_effort: xhigh` when available). Never choose mini, fast, spark, or -cost-optimized model variants. - +Desktop (C++ / Qt). You own this stateful task end to end; no second runner may operate on it. +Inherit the parent model and reasoning setting. At startup, select one execution mode for the task: +- NESTED: choose only after the first real phase-leaf spawn succeeds. Give every leaf a unique + tool-valid name, `fork_turns: "none"`, and an instruction not to delegate. +- SAME-RUNNER: choose if that first spawn is immediately rejected by depth, capacity, or policy; + execute the same task-think prompts as strict checklists. This is not degraded failure. +After selection, do not switch modes merely because a wait timed out. PROJECT: <project> TASK: <letter> — <title> TASK DESCRIPTION: <the task's full description block from implementing.md> IMAGES: <referenced .ai/<project>/images/* paths, or none — Read them if present> TASK_DIR: .ai/<project>/<letter>/ TASK_ID: <project>-<letter> -Config (paths relative to this checkout): BUILD/EXE/MAX_ATTEMPTS = <values>. Test account = the -out/Debug/ portable-data folders (see test-loop.md "Test account"). - +TASK_BASE_SHA: <HEAD before this runner was spawned> +HOST_KIND: <native-windows | wsl-linux | macos | other> +Config: BUILD=<value>; EXE=<absolute executable>; COMPUTER_USE_APP_TARGET=<absolute outer .app | absolute Windows EXE | none>; MAX_ATTEMPTS/MAX_TEST_RUNS=<values>; COMPUTER_USE_POLICY=<value>; COMPUTER_USE_SKILL=<active path | none>. Read first: AGENTS.md; REVIEW.md; `.agents/skills/task-think/PROMPTS.md` (Phase 1-6 templates + execution rules); `.agents/shared/test-loop.md` (testing). Read any IMAGES listed above. For a -follow-up letter, also read `.ai/<project>/about.md` and the previous letter's `context.md`. -Create `<TASK_DIR>/` and `<TASK_DIR>/logs/`. - -Pipeline for THIS task only, spawning a fresh subagent per phase (so each phase's output stays in -YOUR context, not the orchestrator's), writing prompt/progress/result logs per task-think: -1. CONTEXT — task-think Phase 1 (or 1F) -> context.md (+ about.md). -2. PLAN — Phase 2 -> plan.md. +follow-up letter, also read `.ai/<project>/about.md` and the nearest earlier task `context.md` that +exists; prerequisite-blocked tasks may have none. Within +task-think instructions, "main/current session" means this runner, not the orchestrator. +Create `<TASK_DIR>/` and `<TASK_DIR>/logs/`. Maintain +`<TASK_DIR>/logs/task-runner.progress.md` at phase boundaries so the orchestrator can distinguish a +long phase from a stalled runner. +This wrapper overrides shared commit ownership: leaf workers never commit; the runner stages exact +owned paths and commits without `git add -A`. Safety rules below replace conflicting generic reset, +account, and file-lock mechanics. +Pipeline for THIS task only, writing prompt/progress/result logs per task-think: +1. CONTEXT — use Phase 1F whenever earlier project context exists, including the first + `implementing.md` batch in an older task-think project; otherwise use Phase 1. Preserve the + current `about.md` if present, then let the + context phase write its future-looking blueprint, then move that new file to + `<TASK_DIR>/about.proposed.md` and restore the prior project blueprint (or leave it absent for a + new project). Current downstream phases use context.md, not the proposed blueprint. Promote + about.proposed.md to the project `about.md` only after this task is approved; a blocked task must + not make future follow-ups believe missing behavior exists. +1b. DESIGN-SPEC — only for `Visual: layout`. Read the task mockups closely and inspect the existing + desktop widgets/style tokens it should reuse. Write `<TASK_DIR>/visual.md` as the ordered, + desktop-anchored derivation required by test-loop.md "Visual contract": every dimension derives + from a font metric or existing `.style` token, never a mobile pixel, and has a tolerance. This is + the contract used by plan, implementation, review, and test. Skip it for appearance-only or + non-visual tasks. +2. PLAN — Phase 2 -> plan.md. For layout work, derive all style metrics from visual.md. 3. ASSESS — Phase 3. -4. IMPLEMENT— Phase 4, one subagent per plan phase. Implementation agents do NOT commit yet; you - commit after build passes. -5. BUILD — Phase 5 (prefer same-thread build; fix errors). On file-lock errors, run the - path-scoped kill of THIS checkout's binary only (see test-loop.md "Serialize app runs") and retry - once; if the lock persists, return BLOCKED/UNRECOVERABLE with the lock reason. This overrides the - generic task-think stop-on-lock rule for this autonomous implement workflow. -6. REVIEW — Phase 6 but a SINGLE pass (one 6a, one 6b if NEEDS_CHANGES, rebuild). -7. COMMIT — stage the task's intended changes and git commit with a concise plain-language subject - (≤ ~50-60 chars, matching recent `git log` style; usually the whole message — add a short plain - body only if the subject can't carry it). NO `Autotask:`/attempt trailer and NO - `Co-Authored-By:`/attribution line (overrides the default; see test-loop.md "Commit message"). - Commit submodules first if dirty, then bump the pointer. Record the commit SHA as IMPL_SHA (track - the attempt number yourself). -8. TEST — run `.agents/shared/test-loop.md` to APPROVED / BLOCKED / attempt cap. Spawn a - test-author subagent and feed it BOTH sides per test-loop.md "Design the tests from THIS task": +4. IMPLEMENT— Phase 4, sequentially, one leaf worker per plan phase in NESTED mode. Give layout + workers visual.md and require exact contract compliance. Implementation and later impl-fix + workers edit and report; they do NOT commit. You own every commit boundary. +5. BUILD — Phase 5, using the resolved BUILD. Proactively stop only a straggler whose executable + path exactly equals EXE before building. If the build itself reports C1041, LNK1104, a locked + output, access denied, or file in use, AGENTS.md wins: do not retry or use a workaround. Return a + global hard-stop asking the user to close this checkout's app/debugger. +6. REVIEW — Phase 6 but a SINGLE pass: one 6a, then one 6b if NEEDS_CHANGES, followed by a build. + Give the reviewer visual.md for layout work so contract violations are review findings. +6b. NORMALIZE — on native Windows only, run task-think Phase 7 on the exact task-owned source/config + paths after the last review edit and before the implementation commit. Then run one final BUILD + so the bytes about to be committed are the bytes verified. For every later impl-fix attempt, + normalize its exact touched paths before its final build and commit. On WSL/Linux/macOS keep + project and `.ai` text LF/no-BOM and never run CRLF normalization. +7. COMMIT — verify every dirty path belongs to this task and matches the owned write sets. Stage + only explicit task-owned paths; `git add -A` is forbidden. Commit an intended submodule only when + its own preflight was clean and its changes belong to this task, then stage that pointer. Use a + concise plain-language subject (about 50-60 characters, matching recent history), a short body + only when necessary, and no `Autotask:`, attempt, `Co-Authored-By:`, or assistant attribution. + Record the commit as IMPL_SHA and attempt 1. +8. TEST — run `.agents/shared/test-loop.md` to APPROVED / BLOCKED / attempt cap and read its + Codex-only `references/computer-use-testing.md` adapter. Spawn a leaf test-author and feed it BOTH + sides per test-loop.md "Design the tests from THIS task": (1) the TASK SPEC — this task's full description block above PLUS its referenced IMAGES (have it READ the mockups; they show the intended result), and (2) the implementation — `git show <IMPL_SHA>` + touched files. It designs a falsifiable oracle per change and writes the plan into - `<TASK_DIR>/test.md` BEFORE running (visual/asset changes compare the tight crop vs old vs - intended-new art — judged VISUALLY, never by hash/byte; mobile mockups are not pixel targets), - covers every surface the task names, and never reuses another task's navigate+screenshot. You - drive RUN/ASSESS yourself, ADVERSARIALLY (no pass-by-inference; missing evidence = TEST_FLAW; - no-difference-from-before = IMPL_BUG), and keep the human-readable `<TASK_DIR>/test.md` report. - Spawn an impl-fix subagent on IMPL_BUG (it commits the next attempt → new IMPL_SHA). After each - run, save the overlay patch into TASK_DIR and `git reset --hard <IMPL_SHA>` so the checkout - returns to impl-only. Run the test-account SETUP before each launch and honor every test-account - hard rule (serialize app runs; avoid destructive calls). - -Skip TEST only for docs/config-only tasks (say so). On Windows, after approval run task-think -Phase 7 (CRLF / no-BOM) on the task's touched source/config files. + `<TASK_DIR>/test.md` BEFORE running. Give it `COMPUTER_USE_POLICY` and the adapter path; it selects + `Driver: overlay` or `Driver: hybrid` per check and predeclares its action, fallback, target, ready + marker, and safety envelope. Only the task-runner operates Computer Use. Visual/asset checks compare + the tight crop with old and intended-new art, judged visually rather than by hash; mobile mockups are not pixel targets. For + `Visual: layout`, give it visual.md and require arithmetic geometry checks, a same-scale + side-by-side, and an adversarial designer pass. It must cover every `Observable:` and named + surface; never reuse another task's generic navigate-and-screenshot. + Treat TASK_BASE_SHA, not `IMPL_SHA^`, as the pre-task OLD baseline across every fix attempt. Drive + RUN/ASSESS adversarially: missing evidence = TEST_FLAW; no difference from TASK_BASE_SHA = + IMPL_BUG. If attempt equals MAX_ATTEMPTS, block before creating another impl-fix commit. Otherwise + a leaf impl-fix edits without committing; you normalize if native Windows, build, stage exact + owned paths, commit the next attempt, and update IMPL_SHA. + Codex safety overrides for the shared mechanics: + - Overlay code may modify tracked task-owned files only; it may not create untracked source files. + Inventory its paths in `<TASK_DIR>/test-overlay.paths`. + - Save it with `git diff --binary HEAD > <TASK_DIR>/test-overlay.patch`, which captures staged + changes after `git apply --3way`. Verify the patch is nonempty and reappliable. Restore only the + inventoried overlay paths to IMPL_SHA (including inside an intended submodule) rather than + resetting the whole checkout. If any unexpected path is dirty, hard-stop without resetting it. + - Use `TelegramForcePortable/.codex-implement-test-copy` as the ownership marker. SETUP may delete + only marked live; otherwise move unmarked live to real when real is absent, or stop if both + exist. Copy golden to live and mark it. At terminal cleanup delete marked live, then, only if + real exists, MOVE it back to live so later manual changes are recaptured. + - Set `RUN_DIR=<TASK_DIR>/runs/attempt-<n>/run-<m>/` and `EVIDENCE_DIR=RUN_DIR`; overlay and + assessor use it for logs, screenshots, `app_stdout.txt`, and `app_stderr.txt`. Remove stale live-copy + `tdata/working`, record a dump baseline, and stop with BLOCKED(test) at MAX_TEST_RUNS even when + TEST_FLAW repairs did not consume an implementation attempt. + - Repository file-lock instructions remain authoritative: clean up the exact EXE proactively, + but never retry after an actual lock build failure. +Skip TEST only for documentation or metadata with no runnable behavior; record +`VERDICT: NOT_APPLICABLE` and the file-level validation. "Config" alone is not a reason to skip. If you must return `STATUS: BLOCKED`, FIRST leave the checkout clean and buildable for the next -task: `git reset --hard` to your last green IMPL_SHA if you have one, else the prior task's HEAD -(never leave uncommitted or non-building changes). State the blocker TYPE in the summary: -`BLOCKED(test)` = impl committed & building, only verification incomplete (give the exact unverified -behavior + SHA); `BLOCKED(impl)` = no green impl (say whether HEAD is left clean/buildable). Reserve -a true unrecoverable stop for a broken checkout you cannot reset to a buildable commit. +task by restoring only proven task-owned paths to the last green IMPL_SHA, or TASK_BASE_SHA if no +green implementation exists. Never reset an unexpected path. State the blocker type: +`BLOCKED(test)` = a building implementation is committed and only exact named verification remains; +`BLOCKED(impl)` = no green implementation, with HEAD left at TASK_BASE_SHA. A known implementation +bug at the attempt cap is BLOCKED(impl); do not keep a behavior-known-bad commit as successful work. +Reserve unrecoverable for a checkout you cannot safely return to a clean, buildable commit. +On APPROVED or justified NOT_APPLICABLE, promote `<TASK_DIR>/about.proposed.md` to the project +blueprint before replying. On BLOCKED, keep the prior blueprint and retain the proposal only as a +task artifact. +Before replying, write `<TASK_DIR>/result.md` with these exact fields: +``` +# Task result: <TASK_ID> +STATUS: DONE | BLOCKED +Verdict: APPROVED | NOT_APPLICABLE | <specific blocker> +Blocker-Type: none | test | impl | unrecoverable +Task-Base-SHA: <sha> +Implementation-SHA: <sha or none> +Attempts: <n> +Test-Runs: <n> +UI-Driver: overlay | hybrid | mixed | hybrid-unavailable | not-applicable +Touched: <repo paths or none> +Test-Report: <path or not-applicable> +Evidence: <specific log/screenshot paths and what they prove> +Unverified: none | <exact behavior and manual follow-up> +Checkout: clean-buildable | unsafe +Discovered: none | present + +## Discovered tasks +<ordered complete `### discovered-N: ...` blocks; dependencies may name existing ids or earlier placeholders; omit when none> +``` + +`STATUS: DONE` requires APPROVED or a justified NOT_APPLICABLE verdict, a clean checkout, and all +task-owned changes committed after any native-Windows normalization. The result file is mandatory. Reply with only the compact summary block from test-loop.md -(TASK/STATUS/VERDICT/ATTEMPTS/TOUCHED/DISCOVERED/NOTES). -``` +(TASK/STATUS/VERDICT/ATTEMPTS/TOUCHED/DISCOVERED/NOTES); include result.md and test.md paths plus the +key evidence or exact unverified behavior in NOTES. +```` ## Completion @@ -328,33 +466,34 @@ When the loop ends (every task is `approved` or `blocked`): task and every task whose tests could not fully verify it gets its own bold line stating EXACTLY what failed or what is still UNVERIFIED and the manual follow-up needed, e.g. **"⚠️ <letter> — impl committed (<sha>) & review-approved, but <behavior> is UNVERIFIED - (<why, e.g. test-harness limit>); verify manually"**. Make this block impossible to miss. If - everything passed AND verified, say that explicitly instead. -2. Summarize per task: approved vs blocked, attempts, files touched, key test evidence. + (<why, e.g. test-harness limit>); verify manually — <test.md/result.md path>"**. Make this block + impossible to miss. If everything passed and was verified, say that explicitly instead. +2. Summarize each validated result.md: approved vs blocked, implementation SHA, attempts, files + touched, and the exact log/screenshot evidence or unverified behavior. 3. List any discovered tasks that were added. 4. Note the project name for `implement <project> <follow-up>`. 5. Show total elapsed time (`Xh Ym Zs`, omit zero components). -6. Remind that test overlays are saved as `.ai/<project>/<letter>/test-overlay.patch` and the - checkout is left at each task's implementation commit (overlays reset away). +6. Remind that test overlays are saved as `.ai/<project>/<letter>/test-overlay.patch`; the working + tree is clean at the final retained implementation HEAD, and overlays are not present in it. +7. In Goal mode, mark complete only if every task is approved. With any blocked task, report the + terminal pipeline state without claiming the objective was achieved. ## Error handling -- Follow task-think's retry ladder for stuck phases. A task-runner returning BLOCKED does NOT stop - the loop by default — record it and continue while the checkout stays clean and buildable (Phase C - step 5); stop only when continuing is impossible (broken/non-buildable checkout, or a global - environment failure). Report every blocker LOUDLY in Completion. -- If `implementing.md` or any artifact is malformed, re-spawn that step with tighter instructions. -- For file-lock build errors, run the autonomous path-scoped kill from test-loop.md and retry once. - Kill only the resolved `EXE` for this checkout; `taskkill /IM Telegram.exe /F` and other - image-name-wide kills are forbidden. If the lock persists after the scoped retry, return BLOCKED - with the lock reason instead of asking for user input. +- Follow task-think's retry ladder only for disposable leaf phases. Never automatically duplicate a + stateful task-runner. A runner returning BLOCKED does not stop the loop by default; record it and + continue while the checkout stays clean and buildable. Stop only when continuing is impossible. +- Retry a malformed plan with its disposable planner; repair runner artifacts in the same runner's follow-up turn, never a duplicate. +- On a file-lock build error, follow AGENTS.md: stop immediately, do not retry or attempt a + workaround, and ask the user to close this checkout's app and debugger. Proactive pre-build + cleanup remains full-path-scoped to EXE; image-name-wide termination is always forbidden. - The launch gate (Phase A) guarantees the test account exists before any work begins. -- Keep `.ai/` artifacts and edited text files LF/no-BOM on WSL; run CRLF normalization only on a - native Windows checkout. +- Never stash, stage, commit, restore, or reset unrelated user changes. Unexpected dirty paths are a + hard stop, not permission to clean the checkout. +- Keep `.ai/` artifacts and edited project text LF/no-BOM on WSL. Run CRLF/no-BOM normalization + only in a native, non-WSL Windows checkout, before each retained implementation commit. ## User invocation -`Use local implement skill: <request or path to a task file>` — ideally under Goal run mode so it -loops to a tested state. Resume/extend: `Use local implement skill: <project> [additional change]`. -Default task source: `Use local implement skill: <project>` with a prepared `.ai/<project>/tasks/about.md` -runs the whole pipeline from that file with no other input. +`Use local implement skill: <request or path>` — ideally under Goal mode; resume/extend with `Use local implement skill: <project> [additional change]`. +With a prepared `.ai/<project>/tasks/about.md`, the project-only form uses it automatically. diff --git a/.agents/skills/implement/agents/openai.yaml b/.agents/skills/implement/agents/openai.yaml new file mode 100644 index 0000000000..2af2ceda51 --- /dev/null +++ b/.agents/skills/implement/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Implement" + short_description: "Implement and verify Telegram changes" + default_prompt: "Use $implement to implement and fully verify this Telegram Desktop change." diff --git a/.agents/skills/implement/references/computer-use-testing.md b/.agents/skills/implement/references/computer-use-testing.md new file mode 100644 index 0000000000..415d3d4103 --- /dev/null +++ b/.agents/skills/implement/references/computer-use-testing.md @@ -0,0 +1,185 @@ +# Computer Use testing adapter + +Read this during `$implement` TEST when selecting or using the UI driver. This is a Codex-only +adapter over `.agents/shared/test-loop.md`; the shared task-derived scenarios, oracles, overlay, +`-testagent` launch, portable account, watchdog, crash handling, and artifact verdicts remain +authoritative. + +## Contents + +- [Driver policy](#driver-policy) +- [Capability gate](#capability-gate) +- [Exact-app gate](#exact-app-gate) +- [Hybrid handshake](#hybrid-handshake) +- [Safety envelope](#safety-envelope) +- [Unavailable result mapping](#unavailable-result-mapping) +- [Durable evidence](#durable-evidence) + +## Driver policy + +Resolve one policy from the user's request and pass it to the task-runner: + +- `auto` (default) — let the test-author choose hybrid driving only where real pointer, keyboard, + focus, scrolling, dragging, menus, windowing, or native UI materially improves coverage. +- `overlay-only` — never use Computer Use. +- `required` — use hybrid driving for the named flow; if it cannot run safely, return + `BLOCKED(test)` with the exact missing interaction rather than weakening the oracle. + +For each check, select `Driver: overlay` or `Driver: hybrid`. Keep overlay-only for internal state, +data, exact text, and geometry that the in-app harness can exercise deterministically. Select hybrid +when the user-input path itself matters. Do not approve a runnable code task from a Computer Use +narrative or an uninstrumented click-through. Even a hybrid test retains the overlay for fixture +setup, semantic assertions or geometry capture, watchdog, terminal markers, and tight screenshots. + +Have the test-author add these fields to every hybrid check in `test.md` before the run: + +``` +- Driver: hybrid +- UI action: <one ordered, bounded action or gesture> +- Ready marker: CU_READY: <scenario-id>:<step-id> +- Target: <stable AX role/name/value or exact visual target> +- Fallback: <equivalent overlay action, or test-blocked> +- Safety envelope: local-read-only | disposable-local-test-data +``` + +The test-author designs this contract but never operates Computer Use. The stateful task-runner is +the sole desktop owner and performs every Computer Use action itself, even in NESTED mode. Never let +two agents or two driver runtime sessions control the test app concurrently. + +## Capability gate + +Treat Computer Use as available for a run only when all of these are true: + +1. The parent passed the active Computer Use `SKILL.md` path from its surfaced Skills catalog. +2. That skill supports the current desktop host and its prescribed runtime tool is callable here. +3. Required OS permissions and target-app approval are already satisfied without a fresh prompt. +4. The running test build can be distinguished unambiguously from every real Telegram instance. + +Read the passed Computer Use skill completely before the first action and follow its current +bootstrap, API, state-refresh, screenshot, and confirmation rules. Do not hardcode a plugin cache +version, wrapper path, node-repl API, or macOS behavior into this workflow. Skill instructions do +not arrive through `fork_turns: "none"`; the explicit path is the handoff. + +Do not infer capability from an installed directory or config entry. An installed plugin may be +disabled by policy, lack its runtime tool, support a different platform, or still need app/OS +approval. In `auto`, fall back to the prewritten overlay action. In `required`, or when no equivalent +overlay can exercise the physical interaction, return `BLOCKED(test)` with the canonical mapping below. +Missing capability or permission is never an implementation bug. + +Computer Use runs in the foreground on Windows. Use it only on an unlocked, reserved active desktop +or isolated VM. Treat local pointer or keyboard interference, a focus steal, or a window switch as a +contaminated run and restart within `MAX_TEST_RUNS`. Treat WSL/Linux/headless as unavailable unless +the current host explicitly exposes a supported desktop adapter for the exact test app. + +## Exact-app gate + +Keep process and account ownership in the ordinary runner: + +1. Perform portable-account SETUP and launch the resolved `EXE` with `-testagent` through the + existing shell adapter. +2. Verify exactly one process PID maps to the resolved full `EXE`; record its start time too. On macOS, + `COMPUTER_USE_APP_TARGET` is the `.app` bundle containing that executable; on Windows it is the + full EXE path. Record PID, start time, EXE, app target, and test marker in the run's `driver.md`. +3. Call Computer Use only while that exact PID/start-time/resolved-EXE tuple is alive. Revalidate the + same tuple immediately after every state or action call; reject a disappearance or replacement. +4. Pass `COMPUTER_USE_APP_TARGET` to the active API. If it cannot accept that full target, treat the + driver as unavailable unless the API exposes evidence that another identifier resolves to the + recorded process. Never target the ambiguous display name `Telegram` or a user's release client. +5. If exact identity cannot be proven, perform no state/action call and mark Computer Use unavailable. + In `auto`, run the prewritten overlay fallback; in `required`, return `BLOCKED(test)`. Never risk + the user's real account. + +A state call can implicitly relaunch an app between checks. Before the first action, require its fresh +state to contain the predeclared AX/visual target for the current `CU_READY` step, then revalidate the +process tuple. On any mismatch, perform no further action, discard that state/screenshot as evidence, +and use the `auto` fallback or `required` blocker mapping. + +Computer Use must not operate terminals, ChatGPT, Git, build tools, process cleanup, portable-data +folders, or overlay patch/reset mechanics. Those stay with their existing shell and repository +protocols. + +## Hybrid handshake + +For every hybrid step: + +1. Have the overlay create deterministic local/injected/mock state, install its observers and + watchdog, then flush `CU_READY: <scenario-id>:<step-id>` and wait on a condition. +2. Have the runner observe that marker, recheck the process tuple, fetch fresh app state, recheck the + tuple, and require the predeclared target before acting. +3. Prefer a semantic accessibility target. With APIs that expose ephemeral element indices, derive + the index from the latest state and never reuse it after an action. Use a coordinate only when no + accessibility action exists, based on the latest screenshot, and record the window size and point. +4. Perform only the predeclared action, immediately recheck the tuple, then fetch fresh state and + recheck again before deciding the next action. +5. Let the overlay observe the resulting application state, log actual values and PASS/FAIL markers, + and capture the tight target or geometry. Persist supplemental Computer Use AX and screen evidence. +6. Finish through the ordinary `TEST_COMPLETE`, process/crash, watchdog, cleanup, patch-save, and + source-restore path. + +Use Computer Use for exploration only to discover a reproducible flow. Before assigning an +implementation verdict, encode the discovery as a planned overlay/hybrid check and rerun it from a +fresh test account. An exploratory impression cannot approve or fail the implementation. + +## Safety envelope + +Use only the prepared throwaway account and prefer `inject` or `mock-api` fixtures. Unattended +Computer Use must not: + +- log in, enter credentials or secrets, approve permissions, or change account/privacy/network/OS + settings; +- send, edit, forward, react to, or delete messages or other server-visible content; +- upload files, open external links, join/leave chats, log out, terminate sessions, delete accounts, + make payments, or perform any other confirmation-gated action; +- approve a system dialog, CAPTCHA, security warning, or newly requested app permission. + +If a planned action reaches a confirmation boundary, redesign it with local injection/mock APIs. If +that cannot preserve the behavior under test, return `BLOCKED(test)` with a precise manual follow-up; +do not pause an unattended pipeline waiting for approval and do not treat the invocation as blanket +permission. + +Screenshots and AX text can contain everything visible in Telegram. Keep unrelated sensitive apps +closed, capture only the test window/target, and never expose a real account merely to obtain context. + +## Unavailable result mapping + +Whenever a planned hybrid check is unavailable before a run, write +`<TASK_DIR>/computer-use-capability.md` with the policy, host, active skill path or `none`, runtime +tool status, OS/app-approval status, exact-app identity result, fallback decision, and reason. + +- `auto` with an equivalent fallback continues overlay-only. Record `UI-Driver: overlay` and cite the + capability report plus overlay evidence; capability failure is not a blocker. +- `required`, or `auto` without an equivalent fallback, records `STATUS: BLOCKED`, + `Verdict: computer-use-unavailable: <exact reason>`, `Blocker-Type: test`, + `UI-Driver: hybrid-unavailable`, and cites the capability report in `Evidence`. +- A hybrid run that began but exhausted recoverable driver/evidence repairs records + `UI-Driver: hybrid`; preserve its per-run artifacts and name the exact unverified interaction. + +## Durable evidence + +Create `<RUN_DIR>/computer-use/` for every hybrid run and persist: + +- `driver.md` — policy, capability result, active skill path, host, display scale/theme/locale when + known, exact EXE/app-target/PID/identifier, scenario id, safety envelope, and action outcomes; +- `ax-<step>-before.txt` and `ax-<step>-after.txt` — full accessibility snapshots at decisive + checkpoints; +- `screen-<step>-before.png` and `screen-<step>-after.png` — copied immediately from the tool's + temporary screenshot URL. + +Use diff accessibility state while navigating when the current API supports it, but request and save +a fresh full tree at evidence checkpoints. Emitting or viewing an image is not durable storage. Copy +the screenshot into `RUN_DIR` and reference the exact AX/screenshot and overlay-log paths from +`test.md` and `result.md`. + +Apply this evidence order when signals disagree: + +1. Fresh `-testagent` assertion/crash report. +2. Overlay semantic assertions, logged state, and measured geometry. +3. Persisted full AX role/name/value/state evidence. +4. Persisted tight screenshots judged against the task oracle and old/new references. +5. Computer Use narration, which is explanatory only and never proof. + +Classify an overlay assertion failure after the planned action demonstrably occurred as `IMPL_BUG`. +Classify stale targets, wrong-window control, permission/capability failure, missing durable evidence, +or ambiguous screenshots as `TEST_FLAW` or `BLOCKED(test)` according to recoverability. Treat an AX +mismatch as `IMPL_BUG` only when accessibility is an explicit task contract; otherwise repair the +evidence path. diff --git a/.agents/skills/task-think/PROMPTS.md b/.agents/skills/task-think/PROMPTS.md index 57e71fb53e..ff8a462707 100644 --- a/.agents/skills/task-think/PROMPTS.md +++ b/.agents/skills/task-think/PROMPTS.md @@ -1,26 +1,27 @@ # Phase Prompts -Use these templates as Codex subagent messages. Use them as same-session checklists only for Phase 0, intentional main-session build work, Phase 7, or when delegation is unavailable from the start. Replace `<TASK>`, `<PROJECT>`, `<LETTER>`, and `<REPO_ROOT>`. +Use these templates as Codex subagent messages. Use them as same-session checklists only for Phase 0, intentional current-session build work, Phase 7, or when delegation is unavailable from the start at the current agent depth. Replace every applicable placeholder: `<TASK>`, `<PROJECT>`, `<LETTER>`, `<PREV_LETTER>`, `<BUILD>`, `<N>`, `<OWNED_WRITE_SET>`, `<R>`, `<R-1>`, and `<phase-name>`. ## Orchestration Rules - Phase 0 runs in the main session. - When delegation is available, use a fresh subagent for Phase 1, Phase 2, Phase 3, each Phase 4 implementation unit, and each Phase 6 pass. Do not switch those phases to same-session midstream because of a timeout or missing artifact. -- Phase 7 runs in the main session on Windows because it depends on the final local diff and touched-file set. -- Write each phase prompt to `.ai/<PROJECT>/<LETTER>/logs/phase-<name>.prompt.md` before execution. +- Treat delegation as selected only after the first real phase spawn succeeds; tool presence is insufficient. An immediate depth/capacity/policy rejection before phase work selects same-session checklists and is not a delegated retry. +- Phase 7 runs in the current session on native, non-WSL Windows because it depends on the final local diff and touched-file set. Skip it on WSL and keep files LF/no-BOM there. +- Write each phase prompt to `.ai/<PROJECT>/<LETTER>/logs/phase-<phase-name>.prompt.md` before execution. - If you delegate a phase, send the prompt file contents as the initial `spawn_agent` message. - When writing the phase prompt file, append the standard progress file contract and the standard compact reply block below so the subagent knows how to surface progress before the final artifact. -- After each phase completes, write `.ai/<PROJECT>/<LETTER>/logs/phase-<name>.result.md` summarizing the status, files touched, and any follow-up notes. -- Use `fork_context: false` by default. If the phase depends on thread-only context or UI attachments, pass that context explicitly or enable `fork_context` only for that phase. -- Prefer `worker` for phases that write files. Use `default` for plan or review passes if that fits the host better. Use `explorer` only for narrow read-only questions. -- When supported, request the smartest/frontier model available and the highest available reasoning effort for every delegated phase (`model: gpt-5.5` and `reasoning_effort: xhigh` when available). Never choose mini, fast, spark, or cost-optimized model variants. -- Default wait budget for delegated phases is 5 minutes while the phase is clearly still in progress. Successful completion may wake earlier, so this does not delay finished work. -- When a phase appears close to landing, use 1-2 minute waits until it finishes. -- A `wait_agent` timeout is not failure. On timeout, inspect both the expected artifact and the matching progress file before deciding anything. +- After each phase completes, write `.ai/<PROJECT>/<LETTER>/logs/phase-<phase-name>.result.md` with exact + `STATUS:`, `ARTIFACTS:`, `TOUCHED:`, `BLOCKER:`, and `NOTES:` fields. +- Use `fork_turns: "none"` by default. If the phase depends on thread-only context or UI attachments, pass it explicitly or use the smallest positive turn fork needed. +- Use only fields the current `spawn_agent` schema exposes; do not invent role, model, or reasoning arguments. Inherit the parent model/reasoning selection, or match it if the host explicitly supports overrides. +- Give each phase a unique lowercase/digit/underscore task name, store the canonical target returned by `spawn_agent`, and tell the phase it is a leaf that must not delegate. +- Poll with `wait_agent` for at most 60 seconds per call; use elapsed wall-clock windows for stall decisions. Use 30-60 second polls when a phase appears close to landing. +- `wait_agent` is mailbox-wide and may wake for another agent or user input. A timeout is not failure. After every wake, handle new user input if any, inspect the saved target with `list_agents`, and check the expected artifact and matching progress file. - If the expected artifact exists and shows progress, wait again. - If the expected artifact is not ready but the progress file mtime moved or its heartbeat counter increased since the previous check, wait again. Prefer mtime checks first and avoid rereading the file unless you need detail. Do not count that as a failed wait. -- If neither the expected artifact nor the progress file moved since the previous blocked check, send one short follow-up asking the same agent to refresh the progress file, finish the required artifact, and return the standard compact reply block, then wait again. -- If the same agent still produces no usable artifact and no meaningful progress-file movement after two full default waits and one follow-up, close it and retry the phase in a fresh subagent. +- If neither the expected artifact nor progress file moved for a full five-minute blocked-check window, use `send_message` while the target is running or `followup_task` when it is idle, asking it to refresh progress, finish the artifact, and return the compact block. +- If a second five-minute window after that follow-up still produces no usable artifact or movement, use `interrupt_agent` if needed, confirm the turn stopped, and retry the disposable phase once with a new unique name. There is no close-agent operation. - For Phase 1, Phase 2, Phase 3, Phase 4, and Phase 6, if delegated retries still fail, stop and ask the user rather than rerunning the phase locally. - Never use `codex exec`, background shell child processes, or JSONL child-session logging from this skill. @@ -29,9 +30,11 @@ Use these templates as Codex subagent messages. Use them as same-session checkli Append this verbatim to every delegated phase prompt: ```text +You are a leaf phase worker. Do not spawn or delegate to other agents. + Before deep work, create or update the matching progress file in `.ai/<PROJECT>/<LETTER>/logs/`. -Use `<phase-name>.progress.md` as a concise heartbeat with: +Use `phase-<phase-name>.progress.md` as a concise heartbeat with: - `Heartbeat: <N>` on the first line, incremented on each meaningful update - Current step - Files being read or edited @@ -68,6 +71,7 @@ Do not restate the full context, plan, diff, or long reasoning in the chat reply - Phase 5 is complete only when the build outcome is known and the build checkbox is updated on success. - Phase 6a is complete only when `review<R>.md` exists and contains a verdict line. - Phase 6b is complete only when the requested fixes were applied and the post-fix build outcome is known. +- An implement-specific visual design phase is complete only when `visual.md` contains source-image references, desktop anchors, an ordered derivation, tolerances, and falsifiable geometry checks. ## Phase 0: Setup @@ -90,9 +94,9 @@ For new projects: - Set `<LETTER>` = `a`. For follow-up tasks: -- Scan `.ai/<PROJECT>/` for existing task folders (`a/`, `b/`, ...). Find the latest one (highest letter). -- The previous task letter = that highest letter. -- The new task letter = next letter in sequence. +- Scan `.ai/<PROJECT>/` for spreadsheet-style task folders (`a/`...`z/`, `aa/`...). Find the latest id. +- The previous task id = that highest id. +- The new task id = next spreadsheet-style id; never reuse an existing artifact directory. - Create `.ai/<PROJECT>/<LETTER>/` and `.ai/<PROJECT>/<LETTER>/logs/`. Then proceed to Phase 1. Follow-up tasks do not skip context gathering. They use a modified Phase 1F prompt. @@ -134,7 +138,7 @@ Write it as if the project is already fully implemented and working. It should c Do not include temporal state like "Current State", "Pending Changes", "Not yet implemented", or "TODO". Describe the project as a complete, coherent whole. -File 2: .ai/<PROJECT>/a/context.md +File 2: .ai/<PROJECT>/<LETTER>/context.md This is the primary task-specific implementation context. All downstream phases should be able to work from this file plus the referenced source files. It must be self-contained. Include: - Task Description: The full task restated clearly @@ -316,7 +320,8 @@ Rules: - Follow the plan precisely. - Follow AGENTS.md coding conventions. - You are not alone in the codebase. Respect existing changes and do not revert unrelated work. -- Do not modify .ai/ files except to update the Status section in plan.md. +- Do not modify .ai/ files except the Status section in plan.md and the matching + `logs/phase-<phase-name>.progress.md` heartbeat required by this prompt. - When done, update plan.md Status section: change `- [ ] Phase <N>: ...` to `- [x] Phase <N>: ...` - Do not work on other phases. @@ -345,7 +350,8 @@ Read these files: The implementation is complete. Your job is to build the project and fix any build errors that block the planned work. Steps: -1. Run (from repository root): cmake --build ./out --config Debug --target Telegram +1. Run the resolved Debug build command from context.md (`<BUILD>`) at the repository root. On WSL + this is the repository Docker entry point; do not run native Windows CMake against that tree. 2. If the build succeeds, update plan.md: change `- [ ] Build verification` to `- [x] Build verification` 3. If the build fails: a. Read the error messages carefully @@ -382,7 +388,7 @@ LOOP: FINISH: - Update plan.md: change `- [ ] Code review` to `- [x] Code review` - - Proceed to Phase 7 on Windows, otherwise proceed to Completion + - Proceed to Phase 7 on native, non-WSL Windows; otherwise proceed to Completion ``` ### Step 6a: Code Review @@ -463,21 +469,22 @@ Rules: - Do not modify .ai/ files except where the review process explicitly requires it. After all changes are made: -1. Build (from repository root): cmake --build ./out --config Debug --target Telegram +1. Run the resolved Debug build command from context.md (`<BUILD>`) at the repository root. 2. If the build fails, fix build errors and rebuild until it passes. 3. If build fails with file-locked errors (C1041, LNK1104, "cannot open output file", or similar access-denied lock issues), stop and report the lock. Do not retry. When finished, report what changes were made and which files you touched. ``` -## Phase 7: Windows Text Normalization +## Phase 7: Native-Windows Text Normalization -Run this phase only on Windows hosts and only after the review loop has finished. +Run this phase only in a native, non-WSL Windows checkout and only after the review loop has +finished. Keep WSL/Linux text LF/no-BOM. Use the current task's result logs as the source of truth for what Codex touched. Do not sweep the whole repo and do not rewrite unrelated files from a dirty worktree. ```text -You are performing the final Windows-only text normalization phase for task-think. +You are performing the final native-Windows-only text normalization phase for task-think. Read these files: - .ai/<PROJECT>/<LETTER>/plan.md @@ -486,7 +493,7 @@ Read these files: - .ai/<PROJECT>/<LETTER>/logs/phase-6*.result.md Your job: -- Collect the union of repo file paths listed under "Touched files" in those result logs. +- Collect the union of repo file paths listed in the exact `TOUCHED:` fields in those result logs. - Keep only files inside the repository that currently exist and are textual project files: source, headers, build/config files, localization files, style files, and similar text assets. - Exclude `.ai/`, `out/`, binary files, and unrelated user files that were not touched by Codex in this task. - Rewrite each kept file so all line endings are CRLF. @@ -494,7 +501,7 @@ Your job: - Preserve file content otherwise. Preserve whether the file ended with a trailing newline. Rules: -- Run this phase in the main session on Windows. +- Run this phase in the current session on native, non-WSL Windows. - Do not modify files outside the touched-file set for the current task. - Do not rewrite binary files. - When scripting this phase, do not use writer APIs or defaults that emit UTF-8 with BOM. @@ -517,7 +524,7 @@ When all phases, including build verification, code review, and Windows line end 2. Show which files were modified or created. 3. Note any issues encountered during implementation. 4. Summarize the code review iterations: how many rounds, what was found and fixed, or whether it was approved on the first pass. -5. On Windows, mention the text-normalization result briefly: which project files were normalized, whether any BOMs were removed, or whether nothing needed changes. +5. On native, non-WSL Windows, mention the text-normalization result briefly: which project files were normalized, whether any BOMs were removed, or whether nothing needed changes. 6. Calculate and display the total elapsed time since `$START_TIME` (format as `Xh Ym Zs`, omitting zero components). 7. Remind the user of the project name so they can request follow-up tasks within the same project. @@ -531,10 +538,11 @@ When all phases, including build verification, code review, and Windows line end ## Prompt Delivery And Logs For each phase: -1. Write the full prompt to `.ai/<PROJECT>/<LETTER>/logs/phase-<name>.prompt.md` +1. Write the full prompt to `.ai/<PROJECT>/<LETTER>/logs/phase-<phase-name>.prompt.md` 2. Delegate by sending that prompt text to a fresh subagent, or use it as a same-session checklist only for the designated main-session phases or when delegation was unavailable from the start -3. For delegated phases, expect a matching `.ai/<PROJECT>/<LETTER>/logs/phase-<name>.progress.md` heartbeat while work is in flight -4. Save a concise completion note to `.ai/<PROJECT>/<LETTER>/logs/phase-<name>.result.md` +3. For delegated phases, expect a matching `.ai/<PROJECT>/<LETTER>/logs/phase-<phase-name>.progress.md` heartbeat while work is in flight +4. Save `.ai/<PROJECT>/<LETTER>/logs/phase-<phase-name>.result.md` with `STATUS:`, `ARTIFACTS:`, + `TOUCHED:`, `BLOCKER:`, and `NOTES:` fields. For review iterations, include the iteration in the file name, for example: - `phase-6a-review-1.prompt.md` @@ -547,13 +555,12 @@ For review iterations, include the iteration in the file name, for example: Use this pattern conceptually for delegated phases: 1. Write the phase prompt file. -2. Spawn a fresh subagent with the phase prompt, usually with `fork_context: false`. +2. Spawn a fresh leaf subagent with a unique tool-valid task name and `fork_turns: "none"` unless a minimal recent-turn fork is required. 3. Require the agent to create the matching progress file early and refresh it sparingly: at natural milestones when possible, otherwise only after a longer quiet stretch such as roughly 5-10 minutes. -4. Wait in 5-minute intervals when the next step is blocked on that phase, checking both the final artifact and the progress file on timeout. -5. When the phase looks close to finishing, switch to 1-2 minute waits. -6. Prefer filesystem mtime checks on the progress file first. If its mtime moved or the heartbeat counter increased, keep waiting; do not treat that as a stall. -7. If neither the artifact nor the progress file moves, send one short follow-up to the same agent, then retry once with a fresh subagent before involving the user. -8. Validate the expected artifact or code changes with small shell summaries and the completion checks above. -9. Write the result log from the validated outcome and the compact reply block. +4. Poll for at most 60 seconds at a time. After any mailbox wake, inspect the saved target with `list_agents`; use elapsed five-minute windows rather than poll count for stall checks. +5. Prefer filesystem mtime checks on the progress file first. If its mtime moved or the heartbeat counter increased, keep waiting; do not treat that as a stall. +6. After a full blocked-check window with no movement, use `send_message` for a running target or `followup_task` for an idle one. After a second unchanged window, interrupt if needed and retry the disposable phase once with a unique task name. +7. Validate the expected artifact or code changes with small shell summaries and the completion checks above. +8. Write the result log from the validated outcome and the compact reply block. Do not replace this pattern with shell-launched `codex exec`. diff --git a/.agents/skills/task-think/SKILL.md b/.agents/skills/task-think/SKILL.md index 0199f23268..30dd71ecb2 100644 --- a/.agents/skills/task-think/SKILL.md +++ b/.agents/skills/task-think/SKILL.md @@ -1,6 +1,6 @@ --- name: task-think -description: Orchestrate a multi-phase implementation workflow for this repository with artifact files under .ai/<project-name>/<letter>/ using Codex subagents instead of shell-spawned child processes. Use when the user wants one prompt to drive context gathering, planning, plan assessment, implementation, build verification, and review with persistent artifacts, clear phase handoffs, and a thin parent thread. Prefer spawn_agent/send_input/wait_agent, keep heavy pre-build work delegated when possible, and avoid pulling timed-out phases back into the main session. +description: Orchestrate a multi-phase Telegram Desktop implementation workflow with persistent per-project task artifacts under .ai. Use when Codex should drive context gathering, planning, plan assessment, implementation, Debug build verification, review, and native-Windows text normalization through bounded phase handoffs while keeping the parent task lean. Uses current spawn_agent, wait_agent, send_message, followup_task, and interrupt_agent semantics. --- # Task Pipeline @@ -19,7 +19,7 @@ If screenshots are attached in UI but not present as files, write a brief textua ## Overview -The workflow is organized around projects. Each project lives in `.ai/<project-name>/` and can contain multiple sequential tasks (labeled `a`, `b`, `c`, ... `z`). +The workflow is organized around projects. Each project lives in `.ai/<project-name>/` and can contain sequential spreadsheet-style task ids (`a`...`z`, `aa`...). Project structure: ```text @@ -55,12 +55,14 @@ Create and maintain: - `.ai/<project-name>/<letter>/context.md` - `.ai/<project-name>/<letter>/plan.md` - `.ai/<project-name>/<letter>/review<R>.md` (up to 3 review iterations) -- `.ai/<project-name>/<letter>/logs/phase-<name>.prompt.md` -- `.ai/<project-name>/<letter>/logs/phase-<name>.progress.md` for delegated phases -- `.ai/<project-name>/<letter>/logs/phase-<name>.result.md` +- `.ai/<project-name>/<letter>/logs/phase-<phase-name>.prompt.md` +- `.ai/<project-name>/<letter>/logs/phase-<phase-name>.progress.md` for delegated phases +- `.ai/<project-name>/<letter>/logs/phase-<phase-name>.result.md` -Each `phase-<name>.result.md` should capture a concise outcome summary: whether the phase completed, which files it touched, and any follow-up notes or blockers. -Each delegated `phase-<name>.progress.md` should act as a heartbeat: a tiny monotonic counter plus current step, files being read or edited, concrete findings so far, and the next checkpoint. It is not a final artifact; it exists so the parent can distinguish active research from a truly stuck subagent without rereading large context. +Each `phase-<phase-name>.result.md` uses exact `STATUS:`, `ARTIFACTS:`, `TOUCHED:`, `BLOCKER:`, and +`NOTES:` fields. Each delegated `phase-<phase-name>.progress.md` is a heartbeat: a tiny monotonic counter +plus current step, files being read or edited, concrete findings, and next checkpoint. It lets the +parent distinguish active research from a stuck subagent without rereading large context. ## Phases @@ -73,36 +75,38 @@ Run these phases sequentially: 5. Phase 4: Implementation - Execute one implementation unit per plan phase. 6. Phase 5: Build Verification - Build the project, fix any build errors. Skip if no source code was modified. 7. Phase 6: Code Review Loop - Run review and fix iterations until approved or the iteration limit is reached. -8. Phase 7: Windows Text Normalization - On Windows only, after review passes and before the final summary, normalize LF to CRLF for the text source/config files Codex edited in this task and ensure rewritten UTF-8 project files are saved without BOM. +8. Phase 7: Windows Text Normalization - On native, non-WSL Windows only, after review passes and before the final summary, normalize LF to CRLF for the text source/config files Codex edited in this task and ensure rewritten UTF-8 project files are saved without BOM. Keep WSL/Linux files LF/no-BOM. Use the phase prompt templates in `PROMPTS.md`. ## Execution Mode -Use Codex subagents as the primary orchestration mechanism. +Use Codex subagents as the primary orchestration mechanism when they are available at the current +agent depth. - When delegation is available, Phase 1, Phase 2, Phase 3, each Phase 4 implementation unit, and each Phase 6 review or review-fix pass must run in fresh subagents. Do not rerun those phases in the main session midstream just because a wait timed out or an artifact is missing. -- Run Phase 7 in the main session on Windows because it depends on the final local file state and the exact touched-file set for the current task. -- When any same-session helper rewrites Windows project text files, preserve CRLF and write UTF-8 without BOM. Avoid writer APIs or defaults that silently inject a UTF-8 BOM. +- Run Phase 7 in the main session on native, non-WSL Windows because it depends on the final local file state and exact touched-file set. Skip it on WSL and preserve LF/no-BOM there. +- When any same-session helper rewrites native-Windows project text files, preserve CRLF and write UTF-8 without BOM. Avoid writer APIs or defaults that silently inject a UTF-8 BOM. - The main session may read `context.md` once after Phase 1 and `plan.md` once after Phase 3. After that, prefer narrow shell checks, file existence checks, and status-line reads instead of rereading full documents or diffs. -- Prefer `worker` for phases that write files. Use `explorer` only for narrow read-only questions that unblock your next local step. -- Keep `fork_context` off by default. Pass the phase prompt and explicit file paths instead of the whole thread unless the phase truly needs prior conversational context or thread-only attachments. -- When the platform supports it, request the smartest/frontier model available and the highest available reasoning effort for spawned agents in every delegated phase (`model: gpt-5.5` and `reasoning_effort: xhigh` when available). Never choose mini, fast, spark, or cost-optimized model variants. If overrides are unavailable, inherit the current session settings. -- Write the exact phase prompt to the matching `logs/phase-<name>.prompt.md` file before you delegate. Use the same prompt file as a checklist if you later need to fall back to same-session execution. -- For delegated phases, require an early `logs/phase-<name>.progress.md` heartbeat before deep work. The subagent should create or update it early, keep it tiny, and refresh it sparingly: preferably at natural milestones, and otherwise only after a longer quiet stretch such as roughly 5-10 minutes. +- Use only fields exposed by the current `spawn_agent` schema. Some hosts do not expose worker/explorer roles or per-spawn model settings; do not invent them. +- Use `fork_turns: "none"` by default. Pass the phase prompt and explicit file paths instead of the whole thread. Use the smallest positive turn count only for genuinely thread-only context or attachments. +- Inherit the parent task's model and reasoning selection. If a host exposes overrides, match the parent rather than downshifting. Custom agent files use `model_reasoning_effort`. +- Give every spawned phase a unique lowercase/digit/underscore `task_name`, save its returned canonical target, and explicitly make the phase worker a leaf that must not delegate further. +- Tool presence alone does not prove delegation is allowed. Choose delegated mode only after the first real phase spawn succeeds; an immediate depth/capacity/policy rejection before phase work selects same-session checklists. Do not block or launch `codex exec` merely because the default nesting depth is one. +- Write the exact phase prompt to the matching `logs/phase-<phase-name>.prompt.md` file before you delegate. Use the same prompt file as a checklist if you later need to fall back to same-session execution. +- For delegated phases, require an early `logs/phase-<phase-name>.progress.md` heartbeat before deep work. The subagent should create or update it early, keep it tiny, and refresh it sparingly: preferably at natural milestones, and otherwise only after a longer quiet stretch such as roughly 5-10 minutes. - In every delegated prompt, require a compact final reply with only status, artifact paths, touched files, and blocker or `none`. Detailed reasoning belongs in `.ai/` artifacts, not in the chat reply. -- After a subagent finishes, verify that the expected artifacts or code changes exist, then write a short result log in `logs/phase-<name>.result.md`. -- For delegated phases, use `wait_agent` with a 5-minute timeout by default while a phase is still clearly in progress. Successful completion may wake earlier, so this does not add latency to finished phases. -- When a phase looks close to completion — for example the final artifact has appeared, a build is in its final pass, or the agent said it is wrapping up — switch to 1-2 minute waits until it lands. +- After a subagent finishes, verify that the expected artifacts or code changes exist, then write `logs/phase-<phase-name>.result.md` with the canonical fields. +- Poll delegated work with `wait_agent` for at most 60 seconds per call. Use elapsed wall-clock windows, not the number of poll timeouts, for stall decisions. When a phase looks close to completion, use 30-60 second polls. - A timeout is not a failure; it only means no final status arrived yet. Do not treat short waits as stall detection for research-heavy phases. -- On timeout, inspect the expected artifact, the phase progress file mtime, and the worktree for movement. Prefer mtime checks first; only reread the progress file when you need detail. +- `wait_agent` is mailbox-wide and may wake for another agent or steered user input. After every wake, handle new user input if any, inspect the saved target with `list_agents`, then validate the expected artifact and progress-file mtime. Prefer mtime checks first; only reread the progress file when you need detail. - If the progress file mtime moved or its heartbeat counter increased since the previous check, treat that as active progress and wait again. - If no usable final artifact exists yet but the progress file is appearing or advancing, keep the same subagent alive. Progress-file movement does not count toward the retry limit. -- If no usable final artifact exists yet and neither the expected artifact nor the progress file has moved since the previous blocked check, send one short follow-up asking the same subagent to refresh the progress file, finish the artifact, and return the compact status block, then wait again. -- Only if the same subagent still shows no meaningful movement in either the expected artifact or the progress file after two full default waits and one follow-up should you close it and rerun that phase in a fresh subagent. +- If no usable final artifact exists and neither it nor the progress file has moved for a full five-minute blocked-check window, use `send_message` when the target is still running, or `followup_task` when it is idle, asking it to refresh progress, finish the artifact, and return the compact block. +- If there is still no meaningful movement for a second five-minute window after that follow-up, use `interrupt_agent` if it is running, confirm the turn stopped, and retry the disposable phase once with a new unique task name. There is no `close_agent` operation. - Use `wait_agent` only when the next step is blocked on the result. While the delegated phase runs, do small non-overlapping local tasks such as validating directory structure or preparing the next prompt file. - Build verification is critical-path work. Prefer running the build in the main session, and only delegate a bounded build-fix phase when there is a concrete reason. -- If subagents are unavailable in the current environment, or current policy does not allow delegation from the start, run the phase in the main session using the same prompt files. Otherwise, do not switch a pre-build phase to same-session midstream. Never fall back to shell-spawned `codex exec` child processes from this skill. +- If subagents are unavailable in the current environment, current depth, or policy from the start, run the phase in the current session using the same prompt files. Otherwise, do not switch a pre-build phase to same-session midstream. Never fall back to shell-spawned `codex exec` child processes from this skill. ## Verification Rules @@ -112,7 +116,7 @@ Use Codex subagents as the primary orchestration mechanism. - implemented code changes present - build attempt results recorded - review pass documented with any follow-up fixes - - on Windows, if the task edited project source/config text files, a CRLF / no-BOM normalization pass recorded after review + - on native, non-WSL Windows, if the task edited project source/config text files, a CRLF / no-BOM normalization pass recorded after review ## Completion Criteria @@ -120,7 +124,7 @@ Mark complete only when: - All plan phases are done - Build verification is recorded - Review issues are addressed or explicitly deferred with rationale -- On Windows, Codex-edited project source/config text files have been normalized to CRLF, any UTF-8 rewrites were saved without BOM, and the result is logged +- On native, non-WSL Windows, Codex-edited project source/config text files have been normalized to CRLF, any UTF-8 rewrites were saved without BOM, and the result is logged - Display total elapsed time since start (format: `Xh Ym Zs`, omitting zero components) - Remind the user of the project name so they can request follow-up tasks within the same project @@ -130,7 +134,7 @@ Mark complete only when: - If `context.md` or `plan.md` is not written properly by a phase, rerun that phase in a fresh subagent with more specific instructions. Do not repair it locally before build unless delegation was unavailable from the start. - If build errors persist after the build phase's attempts, report the remaining errors to the user. - If a review-fix phase introduces new build errors that it cannot resolve, report to the user. -- If Phase 7 cannot safely normalize a touched file on Windows or remove an introduced UTF-8 BOM from a touched project text file, record the failure in the result log and report it in the final summary instead of silently skipping it. +- If Phase 7 cannot safely normalize a touched file on native, non-WSL Windows or remove an introduced UTF-8 BOM from a touched project text file, record the failure in the result log and report it in the final summary instead of silently skipping it. ## User Invocation diff --git a/.claude/commands/implement.md b/.claude/commands/implement.md index 35b784dc10..e2a1f1633a 100644 --- a/.claude/commands/implement.md +++ b/.claude/commands/implement.md @@ -191,7 +191,7 @@ add a `Visual:` line — it routes the task-runner's flow: When torn between the two, choose `layout` (the safe default for anything built from multiple sized/positioned pieces). The human can override by editing the `Visual:` line in `implementing.md`. -Use letters a, b, c... as task ids. Do not plan internals or implement. When done, reply with ONLY a +Use spreadsheet-style task ids (`a`...`z`, `aa`...). Do not plan internals or implement. When done, reply with ONLY a compact confirmation — `ready — <N> tasks` (extend: `ready — appended <letters>`); do NOT echo the task list or image contents back, the main thread reads `implementing.md` itself. ``` @@ -200,8 +200,9 @@ For **extend** mode, instead instruct the planner to FIRST read the existing `im rewrite it as: (1) a TRIMMED completed-history — keep only the **three most recent** `Status: approved` task blocks (the three nearest the bottom of the file) and drop all earlier approved ones; (2) every still-unfinished task left untouched, in place and with its status — that is all `todo`, `in-progress`, -and `blocked` blocks (never drop these); then (3) APPEND new lettered tasks (continuing the letter -sequence from the highest letter still present after the trim) after them. The trim only removes +and `blocked` blocks (never drop these); then (3) APPEND new tasks starting after the highest id in +the pre-trim union of headings and `.ai/<project>/<id>/` artifact directories. Never reuse an id +merely because trimming removed its heading. The trim only removes already-approved entries from the list — it never touches the per-task `.ai/<project>/<letter>/` artifacts on disk, so a follow-up letter can still read an earlier letter's `context.md` even after its block was trimmed out of `implementing.md`. It must append ONLY tasks from SOURCE not already @@ -223,9 +224,10 @@ For each task in `implementing.md` whose `Status` is not `approved`/`blocked`, i 2. Spawn ONE `task-runner` subagent (Task, `general-purpose`) with the prompt below. Wait for it. 3. Read ONLY its compact summary block (the `task-runner` writes all detail to `.ai/`). 4. Update the task's `Status:` line — `approved` if `STATUS: DONE`, else `blocked: <reason>`. -5. If `DISCOVERED` lists new tasks, append them to `implementing.md` as new lettered `### <letter>:` - blocks (`Status: todo`) **after** the current remaining tasks, and add them to TodoWrite. (You - are the only writer of `implementing.md`, so there are no write races.) +5. If `DISCOVERED` lists follow-ups, send them through a planner to produce complete ID-free task + blocks. Rescan the union of headings and artifact dirs, assign unused spreadsheet ids, validate + dependencies, append after current tasks, and add them to TodoWrite. Only the main thread assigns + ids and writes `implementing.md`. 6. If `STATUS: BLOCKED`, **do NOT stop the loop — prioritize continuing development.** This often runs unattended for hours, so NEVER pause to ask the user whether to go on; record the blocker and move to the next task as long as further progress is possible. Distinguish: @@ -261,7 +263,8 @@ TASK_DIR: .ai/<project>/<letter>/ TASK_ID: <project>-<letter> Config (paths relative to this checkout): BUILD=<...> EXE=<...> MAX_ATTEMPTS=<...>. The test account -is the out/Debug/ portable-data folders (see test-loop.md "Test account"). +is the out/Debug/ portable-data folders (see test-loop.md "Test account"). For each test execution, +set `EVIDENCE_DIR=<TASK_DIR>/runs/attempt-<n>/run-<m>/` and create it before launch. Read first: AGENTS.md; REVIEW.md; `.claude/commands/task.md` (for the exact Phase 1-6 prompt templates); `.agents/shared/test-loop.md` (for the testing phase). For a follow-up letter, also read @@ -286,9 +289,9 @@ stays in YOUR context, not the orchestrator's): impl subagent `<TASK_DIR>/visual.md` and require its `.style` metrics to satisfy that contract exactly (no eyeballed sizes). Implementation agents do NOT commit yet; you commit after build passes. -5. BUILD — task.md Phase 5 (build with BUILD, fix errors). On file-lock errors, run the - path-scoped kill of THIS checkout's binary (see test-loop.md "Serialize app runs") and retry - once, else stop. +5. BUILD — task.md Phase 5 (build with BUILD, fix errors). Proactive cleanup may stop only THIS + checkout's full-path binary before building. If the build reports a file-lock error, stop + immediately without retry/workaround and ask the user to close the app/debugger. 6. REVIEW — task.md Phase 6 but a SINGLE pass (not 3): one review agent, then one fix agent if NEEDS_CHANGES, then rebuild. (Tests catch behavior; review catches dead code / duplication / placement / style.) For a `Visual: layout` task, also hand the review agent `<TASK_DIR>/visual.md` @@ -315,7 +318,8 @@ stays in YOUR context, not the orchestrator's): `<TASK_DIR>/test.md` report. Spawn an impl-fix subagent on IMPL_BUG (it commits the next attempt → new IMPL_SHA). After each run, save the overlay patch into TASK_DIR and `git reset --hard <IMPL_SHA>` so the checkout returns to impl-only. Run the test-account SETUP steps before each - launch and honor every test-account hard rule (serialize app runs; avoid destructive calls). + launch, set the run-specific `EVIDENCE_DIR`, and honor every test-account hard rule (serialize + app runs; avoid destructive calls). Skip TEST only if the task changed no runnable behavior (docs/config only) — say so explicitly. @@ -328,7 +332,8 @@ for this task (say whether HEAD is left clean/buildable at a prior commit). Rese unrecoverable stop for a broken checkout you cannot reset to a buildable commit. When done, write nothing new to chat except the compact summary block from test-loop.md -("TASK/STATUS/VERDICT/ATTEMPTS/TOUCHED/DISCOVERED/NOTES"). All reasoning lives in `.ai/`. +("TASK/STATUS/VERDICT/ATTEMPTS/TOUCHED/DISCOVERED/NOTES"). This wrapper has no `result.md`, so put +concise semicolon-separated follow-ups inline in `DISCOVERED`, or `none`. All reasoning lives in `.ai/`. ``` ## Completion @@ -352,7 +357,7 @@ When the loop ends (every task is `approved` or `blocked`): - A `task-runner` returning BLOCKED does NOT stop the loop by default — record the blocker and continue to the next task as long as the checkout stays clean and buildable (see Phase C step 6). Stop the loop ONLY when continuing is impossible: a broken/non-buildable checkout, or a global - environment failure (unresolved file lock, missing test account). Whatever the outcome, report + environment failure (file lock requiring user action, missing test account). Whatever the outcome, report every blocker's reason and `test.md` path LOUDLY in the Completion summary. - If `implementing.md` or any artifact is malformed, re-spawn that step with tighter instructions. - Never proceed past a file-lock build error — ask the user to close `Telegram.exe`.