diff --git a/AGENTS.md b/AGENTS.md index 35afb83..26ddd80 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,9 @@ ## What this is -A Pi coding agent extension that registers the `/ralpi` slash command. Not a standalone app — it runs inside Pi's extension host. +A Pi coding agent extension that registers the `/ralpi` slash commands +(`/ralpi`, `/ralpi-run`, `/ralpi-plan`, `/ralpi-resume`, `/ralpi-reset`). +Not a standalone app — it runs inside Pi's extension host. ## Type checking @@ -10,6 +12,8 @@ A Pi coding agent extension that registers the `/ralpi` slash command. Not a sta npm run typecheck # tsc --noEmit ``` +Tests: `bun test` (parser and DAG suites in `tests/`). + No build step needed — Pi loads extensions via [jiti](https://github.com/unjs/jiti), which compiles TypeScript at runtime. `index.ts` is the entry point directly. ## Entry point @@ -23,22 +27,41 @@ The extension imports from Pi SDK packages (not in `package.json` — provided b - `@earendil-works/pi-coding-agent` — `ExtensionAPI`, `ExtensionContext`, `createAgentSession`, etc. - `@earendil-works/pi-tui` — `Box`, `Text` for custom message renderer -The only real npm dependency is `yaml` (^2.4.0). +The only real npm dependency is `yaml` (^2.4.0). It is used for parsing YAML +task files (`src/parser.ts`) and config files (`parseSimpleYaml` in +`src/utils.ts`, which falls back to a flat key:value parser when the package +is unavailable). ## Source structure -- `index.ts` — extension entry, command routing, UI registration, reload detection +- `index.ts` — extension entry, command registration (`ralpi`, `ralpi-run`, + `ralpi-plan`, `ralpi-resume`, `ralpi-reset`), execution-mode + loop-option + prompts, reload auto-resume via `session_start`, progress message renderer - `src/` — all logic modules: - - `parser.ts` — task file parsing (Fio, checkbox, YAML formats) - - `dag.ts` — Kahn's algorithm dependency resolution, batch planning - - `executor.ts` — task execution, retry, parallel/sequential modes - - `progress.ts` — `.ralpi/progress.json` state management + - `parser.ts` — task file parsing (Fio/README numbered, phased, checkbox, + YAML formats), dependency + parallel-group + timeout parsing, + `updateTaskInFile()` for PRD checkbox updates + - `dag.ts` — Kahn's algorithm dependency resolution, group-aware batching, + cycle detection, sequential/parallel plan builders + - `executor.ts` — task execution, parallel/sequential modes, model + round-robin + failover, review-gated loop, worktree orchestration, + batch-level conflict resolution + - `review.ts` — review verdict extraction (`## REVIEW VERDICT`), review + save/load to `.ralpi/reviews/` + - `worktree.ts` — git worktree create/merge/cleanup helpers, stale-worktree + cleanup, `finalizeCommittedWorktrees()` + - `progress.ts` — `.ralpi/progress.json` state management (multi-PRD) - `prompts.ts` — prompt generation for spawned agent sessions - `reflection.ts` — reflection extraction from agent output - - `utils.ts` — config loading, progress discovery, `runAgentSession()` + - `utils.ts` — config loading, progress/PRD discovery, `runAgentSession()`, + model resolution (`resolveModelSpec`), loop-active marker - `types.ts` — all interfaces and `DEFAULT_CONFIG` - `widget-batcher.ts` — debounced widget updates for parallel tasks - - `constants.ts` — static constants + - `task-manager-prompt.ts` — loads and expands the bundled + `prompts/task-manager.md` template for `/ralpi-plan` + - `constants.ts` — static constants (slash command, task file names, + reflection/review patterns) +- `tests/` — bun test suites for parser and DAG behavior - `skills/ralpi-use.md` — Pi skill definition for task execution - `prompts/task-manager.md` — Pi prompt for task planning @@ -47,27 +70,70 @@ The only real npm dependency is `yaml` (^2.4.0). All runtime state lives in `.ralpi/` in the **project directory** (not this extension directory): - `.ralpi/progress.json` — execution progress, supports multiple PRDs +- `.ralpi/loop-active.json` — marker written while a loop runs; drives + auto-resume after a session reload - `.ralpi/reflections/` — per-task reflection JSON files +- `.ralpi/reviews//` — full review output JSON (only when + `saveReviews` is on) - `.ralpi/prompts/` — generated prompts (timestamped, for debugging) -- `.ralpi/sessions/` — full session transcripts +- `.ralpi/config.yaml` — project-level config (optional) + +There is no `.ralpi/sessions/` directory anymore — full task output is shown +inline via expandable `ralpi-progress` chat messages, and review output is +persisted under `.ralpi/reviews/`. ## Task ID convention -Task IDs are zero-padded strings (`"01"`, `"02"`, etc.). The parser prepends `0` to parsed digits. Never use raw numeric IDs. +Task IDs are zero-padded strings (`"01"`, `"02"`, etc.) with an optional +single lowercase letter suffix for sub-tasks (`"02b"`, `"02c"`). The parser +normalizes `2b` → `02b` (see `normalizeTaskId` in `src/parser.ts`). Never +use raw numeric IDs. ## Command routing -`/ralpi` with no args → plan. First token looks like a path (`@path`, `./path`, `.md`, etc.) → run. Otherwise dispatches to subcommand (`run`, `plan`, `resume`, `reset`). +- `/ralpi` — no args → show plan for `README.md`; first token looks like a + path (`@path`, `./path`, `.md`, `.yaml`, etc.) → run; anything else → + error suggesting the dash commands +- `/ralpi-run [task-file]` — run tasks (auto-resumes when progress already + exists for the file; otherwise prompts for execution mode + loop options) +- `/ralpi-plan [prompt]` — loads the bundled `prompts/task-manager.md` + template and sends it as a user message. Pi's `sendUserMessage()` sends + with `expandPromptTemplates: false`, so the extension does its own + frontmatter stripping and `$@`/`$1` arg substitution + (`loadTaskManagerPrompt` in `src/task-manager-prompt.ts`) +- `/ralpi-resume [task-file]` — resume from persisted progress; prompts for + the PRD when multiple loops have progress. Reuses the loop snapshot in + `loop-active.json` (mode + autoCommit/autoReview/saveReviews) to resume + non-interactively +- `/ralpi-reset [task-file]` — reset execution progress (does not modify the PRD) + +The old `/ralpi plan|resume|reset` subcommand dispatch, plus `status` and +`next`, were removed. ## Config -Read from `.ralpi/config.yaml` in project directory (and global `~/.pi/ralpi/config.yaml`). Falls back to `DEFAULT_CONFIG` in `src/types.ts` when files are missing. Config is loaded at `projectDir` level, not extension level. +Read from `.ralpi/config.yaml` in project directory (and global +`~/.pi/ralpi/config.yaml`), project overrides global. Falls back to +`DEFAULT_CONFIG` in `src/types.ts` when files are missing. Config is loaded +at `projectDir` level, not extension level. Execution keys explicitly +present in a loaded YAML are tracked in `execution.explicitKeys` so the +loop-startup interactive prompts (`selectLoopOptions` in `index.ts`) can be +skipped for fields the user already set. Key config fields in `execution`: -- `autoCommit` / `autoReview` — toggle follow-up commit and review agent sessions (also selectable at loop startup via `selectLoopOptions`) -- `models` — round-robin model list for parallel mode -- `implModel` / `commitModel` / `reviewModel` — `/` strings resolved via `resolveModelSpec` in `utils.ts` +- `autoCommit` / `autoReview` / `saveReviews` — loop options (selectable at + loop startup via `selectLoopOptions`; review is asked FIRST, commit is + mandated when review is on) +- `models` — slot-aware round-robin model list for parallel mode, with + automatic failover to the next model per task +- `implModel` / `commitModel` / `reviewModel` — `/` strings + resolved via `resolveModelSpec` in `utils.ts` +- `maxReviewRetries` / `reviewBlockOnFail` — review-gated loop retry behavior +- `worktrees` — `"never" | "parallel" | "always"` git worktree isolation + (default `"parallel"`; see `shouldUseWorktrees` in `src/executor.ts`) - `commitTimeoutMs` / `reviewTimeoutMs` — timeouts for follow-up sessions -- `loopTimeoutMs` — max total loop duration in ms (0 = no limit; checked between batches in `executePlanBatches`) +- `loopTimeoutMs` — max total loop duration in ms (0 = no limit; checked + between batches in `executePlanBatches`) - `timeoutMs` — per-task execution timeout +- `prompts.projectContext` / `prompts.reflectionPrompt` — prompt-level settings diff --git a/README.md b/README.md index 7418cf9..8df97a2 100644 --- a/README.md +++ b/README.md @@ -8,35 +8,59 @@ pi install npm:@mikefreno/ralpi ## Features -- **Parallel batching**: Independent tasks in each batch can run concurrently -- **Persistent progress**: Execution state saved to `.ralpi/progress.json` +- **DAG-based execution**: Tasks ordered via dependencies (arrow notation, natural language, "must be done before", or YAML) +- **Parallel batching**: Independent tasks in each batch run concurrently, round-robin across configured models +- **Persistent progress**: Execution state saved to `.ralpi/progress.json`, supporting multiple PRDs simultaneously +- **Resume & auto-resume**: `/ralpi-resume` continues paused execution; a session reload mid-loop auto-resumes via `.ralpi/loop-active.json` - **Reflection system**: Each task produces a reflection for downstream tasks -- **Retry with backoff**: Failed tasks retry with exponential backoff -- **Multiple formats**: Supports simple checkboxes, and YAML -- **Tool usage tracking**: Detects and reports tool usage (read, write, edit, bash) from task execution -- **Configurable timeouts**: Task-level timeouts via meta blocks, with global fallback -- **Session saving**: Saves full task output for expandable session review -- **Resume auto-discovery**: Automatically finds and resumes interrupted execution +- **Phased plans**: `## Phase N — Title` sections add implicit phase-boundary dependencies +- **Model failover**: Unreachable providers cycle to the next model in the list before a task fails +- **Auto-commit / auto-review loop**: Optional per-task commit and review-gated re-execution until pass +- **Worktree isolation**: Parallel tasks run in separate git worktrees so they can't stomp each other, with batch-level merge-conflict resolution +- **Multiple formats**: Fio README (numbered + dependencies), phased, simple checkboxes, and YAML +- **Tool usage tracking**: Reports read/write/edit/bash usage from task execution +- **Configurable timeouts**: Task-level timeouts (inline, meta block, or YAML) with global fallback ## Usage ``` -/ralpi [task-file] # Execute all tasks -/ralpi plan # Alias to /task-manager to plan new tasks -/ralpi resume # Resume paused execution -/ralpi reset # Reset progress and .ralpi directory - does not modify PRD +/ralpi [task-file] # No args → show plan for README.md; path arg → run tasks +/ralpi-run [task-file] # Execute tasks from a task file +/ralpi-plan [prompt] # Open the Task Manager to plan tasks +/ralpi-resume [task-file] # Resume paused/interrupted execution +/ralpi-reset [task-file] # Reset execution progress — does not modify the PRD ``` -### Highly recommended to use the task-manager prompt for prd construction, it's output pairs perfectly - /task-manager or /ralpi plan +`/ralpi` with no arguments shows the execution plan for the default task file. When the first token looks like a path (`@path`, `./path`, `path/file.md`, `.yaml`, etc.) it routes to `/ralpi-run`. Everything else is handled by the dedicated dash commands above (the old `/ralpi plan|resume|reset` subcommand syntax is gone). + +> The task-manager prompt (`/ralpi-plan`) pairs perfectly with ralpi's task file formats — use it for PRD construction. ## Tasks ### Simple Checkbox Format ```markdown -- [ ] 01: Setup project structure -- [ ] 02: Implement auth -- [ ] 03: Build API +- [ ] Setup project structure +- [ ] Implement auth +- [ ] Build API +``` + +Checkbox-only files get sequential IDs (`01`, `02`, ...). Status characters: `[ ]` pending, `[x]` done, `[~]` in progress, `[!]` failed, `[-]` skipped. + +### Fio Format (numbered tasks + dependencies) + +```markdown +# Build a web application + +## Tasks + +- [ ] 01 — Setup project structure +- [ ] 02 — Implement auth +- [ ] 03 — Build API + +## Dependencies + +01 -> 02, 03 ``` ### YAML Format @@ -72,40 +96,98 @@ Use lettered sub-tasks when you discover mid-stream that a step needs to be split. They let you preserve sibling numbering (`01`, `02`, `03`, ...) while adding granularity between two existing steps. +## Phases + +`## Phase N — Title` headings group tasks into phases and add an implicit +dependency from the first task of each phase to the last task of the +previous one, so phases always run in order: + +```markdown +## Phase 1 — Push-to-Talk MVP + +- [ ] 01 — Voice capture +- [ ] 02 — Transmission + +## Phase 2 — Group Chat + +- [ ] 03 — Channels +- [ ] 04 — Presence +``` + ## Dependencies +Dependency lines live in a `## Dependencies` section (or a plain +`Dependencies` heading). Multiple formats are supported and can be mixed. + ### Arrow Notation (recommended) +``` 1 -> 2,3,4 5 -> 6 -This means: "Task 1 must complete before tasks 2, 3, and 4 can start." +``` + +"Task 1 must complete before tasks 2, 3, and 4 can start." Also supports +chains (`03 -> 04 -> 05`) and multi-prereq sources (`05, 07, 08 -> 13`). ### Natural Language +``` 13 depends on 17, 18, 19, 20 14 depends on 13, 15, 16 +22, 23, 24 depend on 21 +``` -This means: "Task 13 depends on tasks 17, 18, 19, and 20." +"Task 13 depends on tasks 17, 18, 19, and 20." `also depends on` is accepted. -### Parallel Groups (informational only) +### "must be done before" -1, 2, 3, 4 can be done in parallel +``` +21 must be done before 22, 23, 24 +02, 03 must be done before 04 +``` + +### Parallel Groups + +``` +1, 2, 3, 4 can be done in parallel (Play Store prep) 5, 6, 7, 8 can be done in parallel +``` -Note: These lines are ignored by the parser. Use explicit dependencies to control execution order. +Tasks listed in a parallel group are allowed to run concurrently. Group +declarations imply no cross-group dependencies, and intra-group +dependencies are still respected — group-aware batching produces a plan +where tasks from any group run as soon as their dependencies are +satisfied. ## Configuration ### Task-Level Timeout -You can set a timeout for individual tasks using a meta block in the task file: +Timeouts can be set inline on the task line, as an inline comment, via a +meta block in the Dependencies section, or in YAML: ```markdown -- [ ] 01: Setup project structure - timeout: 10m +- [ ] 01 — Setup project structure timeout: 10m +- [ ] 02 — Implement auth # timeout=30s ``` -Supported formats: `10m` (minutes), `600s` (seconds), `3600000` (milliseconds) +```markdown +## Dependencies + +01 -> 02 +01 [timeout] = 10m +``` + +```yaml +tasks: + - id: "01" + title: Setup project structure + timeout: 15m +``` + +Supported units: `m` / `min` (minutes), `s` (seconds), `ms` (milliseconds). +Bare numbers default to minutes; in YAML, numeric values ≥ 1000 are treated +as milliseconds. ### Config files @@ -114,23 +196,31 @@ Supported formats: `10m` (minutes), `600s` (seconds), `3600000` (milliseconds) | **Global** | `~/.pi/ralpi/config.yaml` | | **Project** | `./.ralpi/config.yaml` | +Project config overrides global, which overrides defaults. Keys set +explicitly in YAML skip the corresponding loop-startup prompt. + ```yaml execution: - maxParallel: 3 # ralpi-level concurrency only - models: # round-robin in / format - - google/gemini-3.5-flash # 1st and 3rd task in parallel - - openai/gpt-5.5 # 2nd task in parallel - autoCommit: true # commit after each task (mandated when autoReview is on; standalone toggle when off) - autoReview: false # commit → review → loop on fail → merge on pass - implModel: "" # model for task impl (sequential mode, empty = inherit parent) - commitModel: "" # model for commit sessions (empty = inherit task model) - reviewModel: "" # model for review sessions (empty = inherit task model) - timeoutMs: 0 # per-task timeout in ms (0 = inherit Pi's defaults) - commitTimeoutMs: 60000 # timeout for auto-commit agent sessions - reviewTimeoutMs: 120000 # timeout for auto-review agent sessions - loopTimeoutMs: 0 # max total loop duration in ms (0 = no limit) + maxParallel: 3 # ralpi-level concurrency only (0 = unlimited) + models: # round-robin for parallel tasks, / + - anthropic/claude-sonnet-4 + - openai/gpt-4o + autoCommit: true # commit after each task (mandated when autoReview is on) + autoReview: false # commit → review → loop on fail → merge on pass + saveReviews: false # persist full review output to .ralpi/reviews/ (only with autoReview) + maxReviewRetries: 2 # re-executions on a 'fail' verdict before giving up + reviewBlockOnFail: false # true = mark task failed after retries exhausted instead of merging + implModel: "" # model for task impl (empty = inherit parent session model) + commitModel: "" # model for commit sessions (empty = inherit task model) + reviewModel: "" # model for review sessions (empty = inherit task model) + timeoutMs: 0 # per-task timeout in ms (0 = inherit Pi's defaults) + commitTimeoutMs: 0 # timeout for auto-commit agent sessions (0 = inherit) + reviewTimeoutMs: 0 # timeout for auto-review agent sessions (0 = inherit) + loopTimeoutMs: 0 # max total loop duration in ms (0 = no limit; checked between batches) + worktrees: parallel # "never" | "parallel" (default) | "always" — git worktree isolation prompts: projectContext: "Additional context for all tasks" + reflectionPrompt: "" # custom suffix for reflection extraction ``` > `execution.models` uses slot-aware round-robin: with 3 models and 2 concurrent @@ -140,8 +230,9 @@ prompts: > **Automatic failover**: if a provider/API is unreachable (rate limit, 503, etc.), > the task automatically cycles to the next model in the list without counting it > as a task failure. Each model is tried once before the task is marked as failed. -> **NOTE**: this is only used in parallel execution, in sequential mode the -> parent pi session's model is used +> **NOTE**: model lists are only used in parallel execution. In sequential mode +> (or parallel mode with no `models` list) the parent pi session's model is used, +> unless `implModel` is set. #### Auto-review and Auto-commit @@ -158,19 +249,27 @@ state — original work plus fixes. On pass, the changes are already committed and the worktree merges. When `autoReview` is disabled, `autoCommit` runs a follow-up commit -agent after each task with no review. Both options can be overridden at -loop startup via a selection prompt (config YAML values are honored -without prompting when set explicitly). +agent after each task with no review. With `autoReview` on, the user is +also asked whether to persist full review output to +`.ralpi/reviews//.json` (`saveReviews` — this is what +enables review feedback recovery when resuming interrupted loops). Both +options can be overridden at loop startup via a selection prompt (config +YAML values are honored without prompting when set explicitly). `commitModel` and `reviewModel` accept `/` strings (e.g. `anthropic/claude-sonnet-4`) resolved via the model registry. When empty, the task's model is inherited. `implModel` sets the model for task implementation -in sequential mode (overridden by `execution.models` round-robin in parallel -mode). +(used whenever no round-robin model is assigned — sequential mode, or parallel +mode with an empty `models` list; overridden by `execution.models` round-robin +in parallel mode). ## State Files -- `.ralpi/progress.json` - Execution progress -- `.ralpi/reflections/` - Per-task reflections -- `.ralpi/prompts/` - Generated prompts -- `.ralpi/sessions/` - Full task output for review +``` +.ralpi/progress.json # Execution progress (supports multiple PRDs) +.ralpi/loop-active.json # Active-loop marker used for auto-resume after a reload +.ralpi/reflections/ # Per-task reflections +.ralpi/reviews// # Full review output (when saveReviews is on) +.ralpi/prompts/ # Generated prompts (timestamped, for debugging) +.ralpi/config.yaml # Project-level config (optional) +``` diff --git a/skills/ralpi-use.md b/skills/ralpi-use.md index 342ca0f..f887220 100644 --- a/skills/ralpi-use.md +++ b/skills/ralpi-use.md @@ -1,38 +1,44 @@ --- -description: Executes individual tasks from ralpi task files using DAG-based dependency resolution, with progress tracking and reflection support +description: Execute tasks from ralpi task files / PRDs using DAG-based dependency resolution, with persistent progress tracking and reflection support --- # ralpi-task -Execute a single task from a ralpi task file. +Execute tasks from a ralpi task file (checkbox, Fio, phased, or YAML) using DAG-based dependency resolution, with persistent progress tracking and reflection support. ## When to Use -- User asks to execute a specific task from a task file -- User provides a task ID and wants to run it -- User wants to run the next task in sequence +- User asks to execute a task file, PRD, or task list (e.g. "run the tasks", "execute the plan") +- User wants to run a full ralpi loop from a task file in the project +- User wants to resume an interrupted or paused ralpi run +- User wants to plan new tasks with the task-manager prompt ## Usage ``` -/ralpi run [task-file] # Run all tasks -/ralpi next [task-file] # Run next batch -/ralpi status [task-file] # Check progress +/ralpi [task-file] # No args → show plan; path arg → run all tasks +/ralpi-run [task-file] # Run all tasks (auto-resumes if progress exists) +/ralpi-resume [task-file] # Resume paused/interrupted execution +/ralpi-plan [prompt] # Open the Task Manager to plan tasks ``` +Note: ralpi runs whole task plans — there is no single-task or next-batch subcommand. To execute only part of a plan, edit the task file and remove/adjust the tasks first. + ## Task File Location -Default: `README.md` in current directory. Can be overridden with explicit path. +Default: `README.md` in the current directory. Can be overridden with an explicit path (`@path`, `./path`, `*.md`, `*.yaml`, `*.yml`). ## Reflection Format -After completing a task, include: +After completing a task, the task agent ends its response with a reflection block, which the extension parses and passes to downstream tasks: ``` ## REFLECTION -SUMMARY: [what was done] -FILES: [files changed] +SUMMARY: [1-2 sentence description of what was accomplished] +FILES: [comma-separated list of files created or modified] LEARNINGS: -- [key learning] -BLOCKERS: [issues or 'none'] +- [key decision, pattern, or architectural choice] +- [important API or interface details] +- [anything downstream tasks need to know] +BLOCKERS: [any unresolved issues, or 'none'] ```