diff --git a/.agents/skills/implement/SKILL.md b/.agents/skills/implement/SKILL.md index 8c19e964dd..0501cbf5c1 100644 --- a/.agents/skills/implement/SKILL.md +++ b/.agents/skills/implement/SKILL.md @@ -5,11 +5,14 @@ description: Autonomously implement a request on this repository (Telegram Deskt # Implement Pipeline -The tested superset of `task-think`. The parent thread stays lean: it holds only the task list and -one compact summary per task. Each task is driven to test-approval by an isolated **task-runner** -subagent that spawns its own phase subagents. +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. -This skill does not re-specify the implementation phases or the test loop. It reuses: +This tested superset of `task-think` does not re-specify the implementation phases or the test +loop. It reuses: - `.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 @@ -19,9 +22,12 @@ Read both before orchestrating. ## Inputs -`$ARGUMENTS` = ONE of: an inline task description; a path to a task-list file (e.g. -`.ai/communities/tasks.txt`); or an existing project name to resume, optionally followed by extra -work. May reference attached screenshots. +`$ARGUMENTS` = 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 + +May also reference attached images. ## Config @@ -35,79 +41,101 @@ TEST_ACCOUNT = ./out/Debug/test_TelegramForcePortable (user-prepared golden; MAX_ATTEMPTS = 4 ``` -Tasks run **sequentially** in this one checkout. App runs must serialize (one client per account). -To parallelize, run the skill in a different checkout/slot (e.g. `C:\Telegram\tdesktop`, -`D:\Telegram\tdesktop`, `D:\Telegram\twin`); give parallel slots separate test accounts so two test -runs never share one auth key. +`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. + +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. +`C:\Telegram\tdesktop`, `D:\Telegram\tdesktop`, `D:\Telegram\twin`). Each run is independent and +single-tree. Never run the **test phase** in two slots against the same account at once; concurrent +clients on one auth key can trigger a session reset, so give parallel slots separate test accounts. ## Artifacts (per project) - `.ai//implementing.md` — the canonical, final, testability-split task list (descriptions + status); the main thread is its only writer. -- `.ai//images/` — illustrations referenced by tasks. +- `.ai//images/` — illustrations referenced by tasks (`images/01.png`, ...). - `.ai///` — per-task artifacts (context, plan, review, test, result, overlay, logs). - `.ai//about.md` — project blueprint (task-think convention). ## Done (for Goal run mode) -Done when every task in `implementing.md` has `Status: approved` or `Status: blocked: `. -Resumable: re-invoking with the project name reads `implementing.md` and continues from the first -unfinished task. +The run is **done** when every task in `implementing.md` has `Status: approved` or +`Status: blocked: `. 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. ## Phase A: Setup & input resolution (main thread) -1. Record `$START_TIME`. +1. Record `$START_TIME` (for example with `Get-Date`). 2. **Test-account gate (hard precondition — before any work).** If `out/Debug/test_TelegramForcePortable` does not exist, STOP the entire skill immediately and tell - the user to prepare it (a portable-data folder authed to a throwaway test account); autonomous - testing is impossible without it. -3. **Resolve `$ARGUMENTS` 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** — first token is a path: confirm it exists (do NOT read it), SOURCE = that path; - if under `.ai//`, project = ``, else derive a short kebab name from the filename; - mode = **extend** if that project already has `implementing.md`, else new. - - **Existing project** — else if `.ai//` exists: project = `FIRST_TOKEN`; empty - remainder AND `implementing.md` present → mode = **resume**; non-empty remainder → mode = - **extend**, SOURCE = the remainder, OR — if the remainder is itself a path to an existing file — - SOURCE = that path (confirm it exists, do NOT read it). - - **New inline** — else SOURCE = all of `$ARGUMENTS`; pick a unique short kebab-case name. - After this step you have a project name and a SOURCE (inline text or a confirmed path), having read - neither the file nor any image. + 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.** + 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//`, project = + ``; else derive a short kebab name from the filename. Mode = **extend** if that project + already has `implementing.md`, else new. + - **Existing project** — else if `.ai//` exists: project = `FIRST_TOKEN`. If the + remainder is empty AND `implementing.md` exists → mode = **resume**. 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. + - **New inline** — else SOURCE = all of `$ARGUMENTS`; pick a unique short kebab-case project name + after consulting `.ai/`. + After this step you always have a project name and a SOURCE (inline text or a confirmed path) — + and you have read neither the file nor any image. 4. Create `.ai//` and `.ai//images/` if new. -5. Images must be on disk: the planner reads them as files and subagents cannot see chat - attachments, so each image a task needs must exist as a file (referenced by the SOURCE file or - under `.ai//images/`). If the user only pasted an image into the chat, get it onto disk — - ask them to drop it into `.ai//images/` as a file — or, as a lossy fallback, write a - textual description for the planner. Don't claim to have saved a paste you can't. Images the - SOURCE file *references by path* are the planner's job, not yours. +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//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//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. ## Phase B: Planning & testability split (delegate) -Spawn a worker subagent (`fork_context: false`). Give it the SOURCE — EITHER the inline request OR a -path to a task-list file (the main thread has NOT read it): tell the worker to READ the file itself -if SOURCE is a path, READ every image the source references (resolve relative to the SOURCE file's -dir), and COPY each into `.ai//images/` with a descriptive kebab-case name (the main thread -did not read or move them). Then read AGENTS.md, gauge scope, and produce the FINAL ordered task list -where EVERY task satisfies both constraints: -- **Implementable in one pass** — a single agent with a ~200k-token budget can implement it fully - without context compaction (a bounded change across a handful of files, not a sweep across dozens); - split anything bigger. -- **Independently testable** — each task yields an observable behavior the test agent can drive from - an in-app debug overlay and verify via log/screenshot; split on testable seams. -Minimal number of tasks subject to both; preserve dependency order. If the SOURCE is already a list -(inline or in the file the worker read), respect its breakdown and refine only as needed (split -too-big/untestable entries; optionally merge -trivially tiny adjacent ones if still one testable unit). Distribute the provided images across the tasks they pertain to: every -task that changes UI / visual / asset behavior MUST cite the specific mockups/resources it must match -via its `Images:` line (caption = what to match), and leave no provided image referenced by no task. -These per-task references are the oracle the test phase verifies against — be specific and per-task, -not one shared dump. - -Write `.ai//implementing.md`: +Spawn one planner subagent (`fork_context: false`) with this prompt shape: ``` +You are a planning/splitting agent for a large C++ codebase (Telegram Desktop). + +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: + +PROJECT: MODE: + +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). READ every referenced image yourself, then COPY +each into `.ai//images/` with a descriptive kebab-case name, and reference it from the +specific task(s) it pertains to (see "Images per task" below). The main thread did NOT read or move +these — that is your job. If an image exists only as a textual description because the user pasted it +into chat and it could not be saved to a file, it is provided here; treat that description as the +visual spec: + +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. +- **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. + +Use the minimal number of tasks subject to both constraints; preserve dependency order (a task comes +before any task that depends on it). If the SOURCE is already a list, respect its intended breakdown +and refine only as needed: split entries that are too big or not independently testable; you may +merge trivially tiny adjacent entries if the result is still one testable unit. + +Write `.ai//implementing.md` in EXACTLY this format: + # Implementing: ## Goal @@ -117,67 +145,89 @@ Write `.ai//implementing.md`: ### a: Status: todo -<2-4 line self-contained description: what to implement and the observable, testable result> -Images: images/ — (only if the task uses an image) +<2-4 line self-contained description: what to implement and the observable, testable result. Enough +that a fresh agent can act on it.> +Images: images/ — (this line only if the task uses an image) ### b: Status: todo <...> + +**Images per task (required).** Every provided image is a design/resource the work must satisfy. +Attach each to the task(s) it pertains to via the `Images:` line, with a caption stating what that +task must match in it (the exact wording on a mockup, the glyph/shape of a resource, etc.). A task +that changes UI / visual / asset behavior MUST cite the specific mockups/resources it has to match; +do not leave such a task without its images, and do not leave a provided image referenced by no task +(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 +compact confirmation — `ready — tasks` (extend: `ready — appended `); do NOT echo the +task list or image contents back, the main thread reads `implementing.md` itself. ``` -For **extend** mode, APPEND new lettered tasks after the existing ones, leaving prior entries and -statuses untouched. The worker replies with ONLY a compact confirmation (`ready — tasks`, or -extend: `ready — appended `), never echoing the task list or image contents. Then the main -thread reads `implementing.md` back ONCE (its first and only load of the task prose; it never reads -the images). +For **extend** mode, instead instruct the planner to APPEND new lettered tasks (continuing the +letter sequence) after the existing ones, leaving existing entries and their statuses untouched. + +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. ## Phase C: Per-task loop (main thread orchestrates) For each task whose `Status` is not `approved`/`blocked`, in order: -1. Set `Status: in-progress`. Spawn ONE **task-runner** worker (`fork_context: false`, request - `model: gpt-5.4`, `reasoning_effort: xhigh` when supported) 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). +1. Set `Status: in-progress` and mark the corresponding progress item in progress. Spawn ONE + **task-runner** worker (`fork_context: false`, request `model: gpt-5.4`, + `reasoning_effort: xhigh` when supported) 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: `. 4. Append any `DISCOVERED` tasks as new lettered `### :` blocks (`Status: todo`) after the - remaining ones. The main thread is the only writer of `implementing.md`. -5. On BLOCKED, stop and report — do not start the next task. + remaining ones, and add them to the progress list. The main thread is the only writer of + `implementing.md`. +5. On BLOCKED, stop and report — do not start the next task. Under Goal run mode, surfacing the + blocker is the correct stop; the loop should not spin on a blocked task. ### 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 MUST use subagents (spawn_agent/wait_agent) -for each phase, keeping the parent thread lean. +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. PROJECT: TASK: TASK DESCRIPTION: <the task's full description block from implementing.md> -IMAGES: <referenced .ai/<project>/images/* paths, or none> +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"). 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 `about.md` and the previous letter's `context.md`. +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, one fresh subagent per phase, writing prompt/progress/result logs per -task-think: +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. 3. ASSESS — Phase 3. -4. IMPLEMENT— Phase 4, one unit per plan phase. Do not commit in these units. -5. BUILD — Phase 5 (prefer same-thread build; fix errors; file-lock -> stop). +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 — git commit with a concise plain-language subject (≤ ~50-60 chars, matching recent - `git log` style; usually the whole message — short plain body only if needed). NO `Autotask:`/ - attempt trailer and NO `Co-Authored-By:`/attribution line (overrides the default; see test-loop.md - "Commit message"). Submodules first, then superproject pointer. Record the commit SHA as IMPL_SHA - (track the attempt number yourself). +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": (1) the TASK SPEC — this task's full description block above PLUS its referenced IMAGES (have it @@ -185,11 +235,13 @@ task-think: <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. Drive - RUN/ASSESS 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 (commits the - next attempt → new IMPL_SHA). After each run, save the overlay patch and `git reset --hard - <IMPL_SHA>`. Run the test-account SETUP before each launch; honor every test-account hard rule. + 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. @@ -200,14 +252,22 @@ Reply with only the compact summary block from test-loop.md ## Completion -Per-task summary (approved/blocked, attempts, touched files, key evidence), discovered tasks added, -the project name for follow-ups, total elapsed time, and a note that overlays are saved as -`<TASK_DIR>/test-overlay.patch` with the checkout reset to each task's implementation commit. +When the loop ends (all tasks approved/blocked, or a blocked task stopped it): +1. Summarize per task: approved vs blocked, attempts, files touched, key test evidence. +2. List any discovered tasks that were added. +3. Note the project name for `implement <project> <follow-up>`. +4. Show total elapsed time (`Xh Ym Zs`, omit zero components). +5. 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). ## Error handling - Follow task-think's retry ladder for stuck phases; a task-runner returning BLOCKED stops the loop. -- Never push past a file-lock build error. +- 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. - 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.