@alphacoder-v0/pi-loops 0.17.6 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,45 @@
3
3
  All notable changes to pi-loops are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow SemVer.
5
5
 
6
+ ## [0.18.0] - 2026-09-14
7
+
8
+ ### Added
9
+ - **Recipes: a project run on loops, installed in one command.** A recipe is a directory —
10
+ `recipe.toml`, one playbook per job, an optional setup script — and `/recipe add <name>` installs
11
+ it into the open project: one question (the autonomy level, `report` / `propose` / `act`, written
12
+ as the first line of each playbook), one confirmation showing every file, the setup script and
13
+ every `/cron add` line, then the jobs through the same code path `/cron add` uses. The playbooks
14
+ are copied to `.agents/skills/<name>/` — where pi also discovers them as `/skill:` commands — and
15
+ the directory is listed in `.git/info/exclude`, so the repository is untouched; a job's prompt is
16
+ a pointer to its playbook, read fresh on every run, so editing the file changes the next run.
17
+ `/recipe update` is a three-way merge against the untouched copy kept at install (under `.orig/`), and a conflict
18
+ is handed to the agent to resolve with you rather than left as markers in a file a loop would
19
+ follow. `/recipe remove` takes the jobs and leaves the files unless `--purge`. Each `[[job]]` in a
20
+ manifest is validated by building the `/cron add` line it stands for and parsing it with the same
21
+ parser. The one step no template can do — describing this project's tracker — is handed to the
22
+ session with the prompt in `recipes/_tracker-setup.md`, the way `/inbox claim` hands over a
23
+ finding, written to `docs/agents/issue-tracker.md` in the layout Matt Pocock's engineering
24
+ skills use and excluded from the repository like the playbooks — and the wizard resumes on its
25
+ own once that turn ends with the file in place. `pi-loops recipe list|show|add` in a shell does the deterministic part and stops
26
+ before the setup script and the jobs. `docs/recipes.md`; vocabulary in `CONTEXT.md`, decisions in
27
+ `docs/design.md` §15–18.
28
+ - **Two recipes.** `issue-loop`: the tracker as a state machine (Matt Pocock's five triage states
29
+ plus `agent-working`, `in-review`, `agent-blocked`) that two loops turn, a triage loop that
30
+ reproduces, checks `.out-of-scope/` and writes agent briefs, and an implement loop that claims
31
+ one issue per run, builds it in a worktree and opens the pull request; a person promotes and
32
+ merges. `autoresearch`: one experiment per run against a `RESEARCH.md` contract you wrote, a
33
+ `results.tsv` ledger where retired ideas stay as negative evidence, a worktree per experiment,
34
+ and promotion only when the `--verify` checker has re-run the held-out command itself; with a
35
+ pure-Python exact k-NN example whose baseline is a speedup of 1.0. `changelog-draft` is packaged
36
+ as the release-side half of the issue loop.
37
+
38
+ ### Fixed
39
+ - **The browser front end reported a slash command as timed out while it waited in a dialog.** A
40
+ `/…` prompt is answered by pi when the command has finished, and a command that shows a setup
41
+ script and asks for a yes finishes when the person answers; sixty seconds later the feed said
42
+ `timed out after 60000ms` and the install went on to succeed. A slash command now gets fifteen
43
+ minutes; everything else keeps sixty seconds.
44
+
6
45
  ## [0.17.6] - 2026-09-14
7
46
 
8
47
  ### Added
package/README.md CHANGED
@@ -38,7 +38,7 @@ the first sign of credentials that do not work should not be an empty inbox tomo
38
38
 
39
39
  ```bash
40
40
  pi install npm:@alphacoder-v0/pi-loops # from npm, following new releases
41
- pi install git:github.com/alphacoder-v0/pi-loops@v0.17.6 # or from GitHub, at a pinned tag
41
+ pi install git:github.com/alphacoder-v0/pi-loops@v0.18.0 # or from GitHub, at a pinned tag
42
42
  pi install /path/to/pi-loops # or a local checkout — `pi install .` in this repo
43
43
  pi -e /path/to/pi-loops # or none of them: try it for one run, installing nothing
44
44
  ```
@@ -138,6 +138,11 @@ A job records its directory and model at creation, so it is not tied to the wind
138
138
  `--cwd` runs it in another checkout (absolute, or relative to this project — no shell, so nothing
139
139
  expands `~`), and `--model` pins it whatever this session is on (`/cron set <ref> --model -` unpins).
140
140
 
141
+ And two you do not write at all: `/recipe add issue-loop` runs the issue tracker as a state machine
142
+ that two loops turn, `/recipe add autoresearch` runs one experiment per run against a contract you
143
+ wrote — each a directory of playbooks copied into the project, installed with one question and one
144
+ confirmation ([docs/recipes.md](docs/recipes.md)).
145
+
141
146
  Two that are not loops:
142
147
 
143
148
  ```text
@@ -289,6 +294,7 @@ State stays in `~/.pi/agent/loops` until you delete it.
289
294
  | `/triggers panel [on\|off]` | The same panel, toggled from the trigger side |
290
295
  | `/session-export [path]`, `/session-import <path>` | Portable `.pisession` archive: transcript + jobs + rules + loop state |
291
296
  | `/session-share [--public]` | Upload a redacted transcript as a GitHub gist via `gh`, after showing you what it contains. (pi has its own `/share`, which sends the raw session elsewhere first — see [docs/session-archive.md](docs/session-archive.md)) |
297
+ | `/recipe [list\|show\|add\|update\|remove <name>]` | Install a packaged way of running this project on loops — the issue tracker as a state machine, or one research experiment per run — with one question and one confirmation ([docs/recipes.md](docs/recipes.md)) |
292
298
  | `/pi-loops [install-launcher]` | Version and paths; `install-launcher` puts the `pi-loops` command on your `PATH` |
293
299
 
294
300
  A schedule is a 5-field cron expression, or one of `hourly` / `daily` / `weekly` (also `每天`), or
@@ -317,6 +323,7 @@ notifications, and lifecycle hooks — each has a page here.
317
323
  - [docs/mcp.md](docs/mcp.md) — MCP notification sources and tool registration (`mcp.toml`)
318
324
  - [docs/hooks.md](docs/hooks.md) — lifecycle hooks (`hooks.toml`), including `run_start` / `run_end` for scheduled runs
319
325
  - [docs/goal.md](docs/goal.md) — `/goal`: holding a session to a stop condition
326
+ - [docs/recipes.md](docs/recipes.md) — `/recipe`: a project run on loops, installed in one command; the issue loop and autoresearch, and how to write your own
320
327
  - [docs/session-archive.md](docs/session-archive.md) — `/session-export`, `/session-import`
321
328
  - [docs/cli.md](docs/cli.md) — the `pi-loops` command line: export, import, and looking in on the host
322
329
  - [docs/web-ui-parity.md](docs/web-ui-parity.md) — what the browser front end owes you, line by line
package/README.zh-CN.md CHANGED
@@ -45,7 +45,7 @@ pi-loops 自己没有任何运行时依赖。
45
45
 
46
46
  ```bash
47
47
  pi install npm:@alphacoder-v0/pi-loops # 从 npm 装,跟着新版本走
48
- pi install git:github.com/alphacoder-v0/pi-loops@v0.17.6 # 或者从 GitHub 装,钉住一个 tag
48
+ pi install git:github.com/alphacoder-v0/pi-loops@v0.18.0 # 或者从 GitHub 装,钉住一个 tag
49
49
  pi install /path/to/pi-loops # 或者本地检出;本仓库里就是 pi install .
50
50
  ```
51
51
 
@@ -215,6 +215,19 @@ pi update --extensions # 对齐已安装的包
215
215
 
216
216
  任务在创建时就记下自己的目录和模型,所以它不绑在敲出它的那个窗口上。`--cwd` 让它在另一个检出里跑——绝对路径,或相对当前项目;这里没有 shell,`~` 不会展开。`--model` 把模型钉死,`/cron set <ref> --model -` 解钉。
217
217
 
218
+ ### 不用自己写的:recipe
219
+
220
+ ```text
221
+ /recipe 有哪些打包好的 recipe,这个项目装了哪些
222
+ /recipe add issue-loop 把 issue tracker 跑成状态机:分诊成 agent brief、在 worktree 里实现、开 PR;推进和合并留给人
223
+ /recipe add autoresearch 按你写的研究合同每次跑一个实验,账本记下每次尝试,只凭 held-out 数据提议晋升
224
+ ```
225
+
226
+ 一个 recipe 是一组 loop 加上它们各自每次 run 都会读的 playbook。安装只问一个问题(自治级别
227
+ `report` / `propose` / `act`)、确认一次(每个要写的文件、setup 脚本全文、每一行 `/cron add`),
228
+ playbook 拷到 `.agents/skills/<name>/`,通过 `.git/info/exclude` 排除在仓库之外——你随时可以改它,
229
+ 下一次 run 就照改后的做。见 [docs/recipes.md](docs/recipes.md)。
230
+
218
231
  ## 用法
219
232
 
220
233
  会话里的命令分几摊:`/cron` 管任务,`/inbox` 管分诊,`/goal` 管「做到什么算完」,`/triggers` 管不看钟的那些规则,`/session-share` 把这次会话脱敏后发出去。
@@ -0,0 +1,34 @@
1
+ # Issue tracker: GitHub
2
+
3
+ Work items for this repository live as GitHub Issues in `alphacoder-v0/pi-loops`; pull requests
4
+ are the review surface. Use the `gh` CLI for every operation; it infers the repository from the
5
+ remote when run in a clone. Loops shell out to `gh`, so the account must be authenticated in the
6
+ environment a loop runs in — `gh auth status` answers that.
7
+
8
+ ## Operations
9
+
10
+ - **List**: `gh issue list --state open --limit 200 --json number,title,labels,updatedAt,author` (add `--label <state>` to filter by state)
11
+ - **Read**: `gh issue view <n> --comments --json number,title,body,labels,author,createdAt,comments`
12
+ - **Comment**: `gh issue comment <n> --body "..."` (a heredoc for multi-line bodies)
13
+ - **Change state**: `gh issue edit <n> --add-label "<new state>" --remove-label "<old state>"` — exactly one state label at a time
14
+ - **Claim**: `gh issue edit <n> --add-label agent-working --remove-label ready-for-agent --add-assignee @me`
15
+ - **Close**: `gh issue close <n> --comment "..."`
16
+ - **Pull requests**: `gh pr create`, `gh pr list --state open --json number,url,headRefName,reviewDecision,comments,updatedAt`, `gh pr view <n> --comments`, `gh pr diff <n>`
17
+
18
+ ## State vocabulary
19
+
20
+ One category label (`bug` | `enhancement`) and exactly one state label per open issue. The state
21
+ labels are `needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `agent-working`,
22
+ `in-review`, `agent-blocked`, `wontfix`. They already exist in this repository; `labels.sh`
23
+ refreshes their colour and description and touches no issue. A playbook that moves an issue names
24
+ the label it moves to.
25
+
26
+ ## Blocking
27
+
28
+ A `Blocked by: #<n>, #<m>` line near the top of an issue body (or the tracker's native
29
+ dependency) gates it: the item is unblocked when every listed issue is closed.
30
+
31
+ ## Who counts as the agent
32
+
33
+ Comments and assignments made by loops are made as the account `gh` is signed in as — currently
34
+ `alphacoder-v0`. Every comment a loop posts starts with a line saying it was generated by AI.
package/docs/cli.md CHANGED
@@ -260,3 +260,19 @@ accepted). `host stop` ends the host; the next pi to open would have taken the c
260
260
 
261
261
  The channel is a unix socket at `host.sock` in the loops directory, created 0600, and it is
262
262
  read-mostly on purpose: a host you could prompt would be a second chat.
263
+
264
+ ## recipe
265
+
266
+ ```sh
267
+ pi-loops recipe list # the packaged recipes, and which are installed in this directory
268
+ pi-loops recipe show issue-loop # its files, jobs, levels, setup script
269
+ pi-loops recipe add issue-loop [--cwd <dir>] [--level report|propose|act] [--overwrite]
270
+ ```
271
+
272
+ `add` is the deterministic half of `/recipe add` ([recipes.md](recipes.md)): it copies the
273
+ playbooks to `.agents/skills/<name>/`, lists that directory in `.git/info/exclude` and writes the
274
+ record — and stops. The setup script and the jobs need a pi open in the project: `/recipe add
275
+ <name>` there finds the copies in place, shows the script and the `/cron add` lines, and creates
276
+ them after you say yes. Without `--level` the lowest level the recipe supports is written; an edited
277
+ copy is kept unless `--overwrite` says otherwise.
278
+
package/docs/design.md CHANGED
@@ -117,6 +117,49 @@ machine. Everything here follows from that, and each one has a price.
117
117
  failed — the slot is still owed and the failure streak does not advance. Diagnostics go to
118
118
  `logs/pi-<pid>.log` rather than only to a chat notification that a new session erases.
119
119
 
120
+ 15. **Recipes are files, not code.** A recipe (`CONTEXT.md` has the vocabulary) is a directory:
121
+ a `recipe.toml` manifest whose `[[job]]` fields are the arguments of `/cron add` and nothing
122
+ else, one playbook per job, an optional setup script. Anything the wizard does with one is
123
+ something a person could have done by hand with `/cron add` and `cp`. The first catalogue is
124
+ seven: issue-loop, daily-digest, changelog-draft, pr-watch, ci-sweeper, autoresearch, and
125
+ ecosystem — the last capped at `propose`, because every outward word it drafts is a finding a
126
+ person claims before it is said.
127
+
128
+ The cost: a project cannot add a recipe by writing TypeScript, only by writing a directory,
129
+ and the wizard can only ask what a manifest can declare.
130
+
131
+ 16. **Playbooks are copied into the project and kept out of its history.** `/recipe add` copies
132
+ them to `<project>/.agents/skills/<recipe>/` — where pi also discovers them as `/skill:`
133
+ commands, so a person can run one step by hand — and lists the directory in
134
+ `.git/info/exclude`, so the repository is not touched. A loop's prompt is a pointer to that
135
+ file; the procedure is read fresh on every run. The tracker description the playbooks read
136
+ (`docs/agents/issue-tracker.md`, in the layout Matt Pocock's engineering skills use, so a
137
+ repository that has those reads the same file) is excluded the same way: it names an account
138
+ and a workflow, which are the project's to keep and not the repository's to publish.
139
+
140
+ The cost: two clones of one project each install the recipe, and a playbook edited on one
141
+ machine is not on the other. Upgrading pi-loops upgrades the packaged recipes, not the copies:
142
+ `/recipe update` is a three-way merge against the untouched copy kept at install (under
143
+ `.orig/` beside the playbooks), silent when the person changed nothing, and conflicts are handed to the
144
+ session as a prompt to resolve with the person rather than left as markers in a file the next
145
+ run will read.
146
+
147
+ 17. **The wizard is deterministic; one step is not.** Choosing a recipe, its autonomy level, the
148
+ copy and the `/cron add` lines run with no model and end in a confirmation that shows exactly
149
+ what will be created. The one thing a template cannot do — describe *this* project's tracker —
150
+ is handed to the running session with `sendUserMessage`, the way `/inbox claim` hands over a
151
+ finding: explore the remote, propose, confirm, write the file — and when that turn settles with
152
+ the file there, the wizard resumes by itself, so the command is typed once. `pi-loops recipe`
153
+ in the terminal does the deterministic part only.
154
+
155
+ 18. **One autonomy dial, three positions, in prose.** `report` reads and files findings; `propose`
156
+ may also write to the tracker and open draft pull requests but never reach a terminal state;
157
+ `act` may. A manifest declares which positions a recipe supports, the wizard defaults to the
158
+ lowest, and the chosen one is a line at the top of each playbook — text the model reads and a
159
+ person edits, enforced by nothing in code. The cost is exactly that: the level is an instruction,
160
+ not a permission, and the permissions that exist (the danger policy, the daily budget, branch
161
+ protection on the remote) are the ones that hold.
162
+
120
163
  ## Where the browser front end came from
121
164
 
122
165
  pi owns the `pi` command and its terminal, so a second front end cannot replace the first one. It
@@ -0,0 +1,239 @@
1
+ # Recipes: a project run on loops, installed in one command
2
+
3
+ A **recipe** is a packaged way of running a project on loops: one or more jobs, the **playbook**
4
+ each of them reads on every run, a **manifest** that says what to create, and sometimes a setup
5
+ script. `/recipe add <name>` installs one into the project you have open; what you get is exactly
6
+ what you could have made by hand with `cp` and `/cron add`, which is the point — a recipe cannot do
7
+ anything a person could not have typed.
8
+
9
+ ```text
10
+ /recipe what is packaged, and what is installed here
11
+ /recipe show issue-loop the files, the jobs, the levels, the setup script
12
+ /recipe add issue-loop install it: a question, a confirmation, done
13
+ /recipe update issue-loop merge a newer pi-loops' playbooks into your copies
14
+ /recipe remove issue-loop its jobs go; the files stay unless you say --purge
15
+ ```
16
+
17
+ Two recipes ship in this version, and the shape is meant to be copied:
18
+
19
+ | recipe | jobs | what it runs | levels |
20
+ |---|---|---|---|
21
+ | [issue-loop](../recipes/issue-loop/) | `issue-triage` every 30 min, `issue-implement` every 30 min offset | the issue tracker as a state machine: triage into agent briefs, build accepted issues in a worktree, open pull requests | `propose`, `act` |
22
+ | [autoresearch](../recipes/autoresearch/) | `autoresearch` every hour, with `--verify` | one experiment per run against a contract you wrote, a ledger of every attempt, promotion only on held-out evidence | `propose`, `act` |
23
+
24
+ `changelog-draft` (a nightly changelog entry and version proposal) is packaged with its playbook
25
+ and manifest but is still the release-side half of the issue loop; it and four more — a daily
26
+ digest, a pull-request watch, a CI sweeper, an ecosystem scan — are the next batch.
27
+
28
+ ## What `/recipe add` does, in order
29
+
30
+ 1. **Tracker first, if the recipe needs one.** issue-loop reads `docs/agents/issue-tracker.md` on
31
+ every run to learn where the project's work items live — GitHub Issues, or one Markdown file
32
+ per item under `.scratch/issues/` — and how to list, comment, label and close them. If the file
33
+ is missing, the wizard hands that one step to the agent in your chat (the way `/inbox claim`
34
+ hands over a finding): it looks at the remote, proposes, writes the file after you agree — and
35
+ the moment that turn ends with the file in place, the wizard resumes on its own with the
36
+ question below. Everything else is done without a model. The file's layout
37
+ is the one Matt Pocock's engineering skills use, so a repository that has `/triage` reads the
38
+ same description. Like the playbooks it is kept out of the repository through
39
+ `.git/info/exclude`: it names an account and a workflow, which are the project's to keep and
40
+ not the repository's to publish. Another clone is asked the same questions once.
41
+ 2. **The autonomy level.** One question, defaulting to the lowest the recipe supports (below).
42
+ `--level act` skips it.
43
+ 3. **A name check.** A job with the same name already in `jobs.json` stops the install and says
44
+ which recipe or `/cron add` it came from.
45
+ 4. **The confirmation.** Every file that will be written and where, every `/cron add` line that
46
+ will be run, the budget hint. The setup script is printed into the transcript first, whole and
47
+ as written — it will run with this session's environment, and a dialog clips what does not fit,
48
+ so it is not put in one; a script too long to show is not run at all. A recipe installed from a path
49
+ rather than by name is flagged as not shipped with pi-loops, with the playbooks to read first.
50
+ Nothing has happened yet.
51
+ 5. **The install.** The playbooks are copied to `.agents/skills/<recipe>/`, with an untouched copy of each
52
+ under `.orig/` and a `.recipe.json` record (version, level, when). The directory (and the
53
+ tracker description) is listed in `.git/info/exclude` — git's own place for a rule that belongs to one clone — so the repository
54
+ is not touched and nothing shows in `git status`. pi discovers the copies as `/skill:` commands,
55
+ which is how a person runs one step by hand when the loop's judgement needs checking — once the
56
+ project is trusted: a directory that gains `.agents/skills/` is one pi asks about at its next
57
+ start (`/trust`). The loops do not depend on that; they read the files by path.
58
+ 6. **The setup script**, if any, runs once in the project (issue-loop's creates the tracker's
59
+ labels; it is idempotent). A failure stops before any job is created and prints the output; the
60
+ files stay in place and `/recipe add` again resumes.
61
+ 7. **The jobs**, through the same code path as `/cron add`, each carrying `recipe: "<name>"` so
62
+ `/recipe list` and `/recipe remove` can find them. Each prompt is a pointer:
63
+ `Read .agents/skills/issue-loop/triage.md and do what it says for this repository.` The
64
+ procedure is read fresh on every run; edit the file and the next run follows the edit.
65
+
66
+ `pi-loops recipe list|show|add` in a shell does steps 5 and nothing after: the setup script and the
67
+ jobs are things a person should see before they exist, and only the pi inside `/recipe add` can show
68
+ them. It leaves the files in place and says so; `/recipe add` then finds nothing to copy.
69
+
70
+ ## The autonomy level
71
+
72
+ One dial with three positions, declared per recipe in its manifest and written as the first line
73
+ of each playbook — `Autonomy: propose` — where the model reads it and a person can change it:
74
+
75
+ | level | may |
76
+ |---|---|
77
+ | `report` | read, and file findings; nothing is written outside the inbox |
78
+ | `propose` | also write to the tracker (comments, non-terminal labels) and open draft pull requests; never reach a terminal state |
79
+ | `act` | also promote, close and merge — the terminal states |
80
+
81
+ It is an instruction, not a permission. What actually holds an unattended run are the things that
82
+ were there before recipes: the [dangerous-command policy](loops.md#when-something-looks-wrong),
83
+ `[limits] daily_budget_usd`, and branch protection on the remote. Set the budget before the first
84
+ night ([loops.md](loops.md#what-it-costs-and-capping-it)); each recipe's `show` says roughly what
85
+ its default schedules cost.
86
+
87
+ ## Editing, updating, removing
88
+
89
+ The copies are yours. `/recipe update <name>` after a pi-loops upgrade is a three-way merge of the
90
+ packaged playbook against your copy with the untouched copy in `.orig/` as the base: files you never touched are
91
+ replaced silently, your edits are kept where they do not overlap the upstream change, and a file
92
+ with overlapping edits is **not written** — git's merge with markers goes to `.orig/<file>.merge`,
93
+ and the agent in your chat is handed the four paths (yours, the base, the packaged version, the
94
+ merge) to resolve with you, because conflict markers in a playbook are text the next run would follow.
95
+ A playbook installed by hand, with no untouched copy, is left alone and named.
96
+
97
+ `/recipe remove <name>` removes the recipe's jobs and keeps the files and the loops' notes;
98
+ `--purge` deletes both — of the files, only what the install wrote, since `.agents/skills/` may
99
+ hold the project's own. `/cron` shows recipe jobs like any other, and `/cron set` edits them like
100
+ any other — a recipe is how they were made, not what they are.
101
+
102
+ ## Writing a recipe
103
+
104
+ A directory with a `recipe.toml`; `/recipe add ./path/to/it` installs from a directory as readily
105
+ as from the packaged set (no git URLs: a playbook is an instruction a model will follow unattended,
106
+ and should be read before it is installed).
107
+
108
+ ```toml
109
+ name = "issue-loop" # lowercase, digits, dashes; also the install directory
110
+ summary = "one line"
111
+ needs_tracker = true # gate on docs/agents/issue-tracker.md
112
+ levels = ["propose", "act"] # which positions of the dial the playbooks understand
113
+ setup = "labels.sh" # optional; shown, then run once, before the jobs exist
114
+ files = ["RESEARCH.template.md"] # optional; copied beside the playbooks unchanged
115
+ budget_hint_usd = 10 # optional; only a hint in `show` and the confirmation
116
+
117
+ [[job]]
118
+ name = "issue-triage" # the /cron add --name
119
+ schedule = "*/30 * * * *" # anything /cron add takes, except in/at (a recipe job recurs)
120
+ playbook = "triage.md" # the file this job's runs read
121
+ timeout = "45m" # optional: verify, timeout, thinking, tools, prompt
122
+ ```
123
+
124
+ Each `[[job]]` is checked by building the `/cron add` line it stands for and parsing it with the
125
+ same parser: a bad schedule, a `--timeout` that is not a duration, an expression that never
126
+ matches, is refused when the manifest is read, not on the first run. A playbook is Markdown with
127
+ pi's skill frontmatter (`name`, `description`) and an `Autonomy:` line the wizard will set; the
128
+ rest is what a run should do, written for a sub-agent that has only its notes, the files, and the
129
+ tools. The two packaged recipes are the reference for the voice.
130
+
131
+ ---
132
+
133
+ ## issue-loop
134
+
135
+ The tracker becomes a state machine that two loops turn, with the two decisions that need a person
136
+ — *is this worth building?* and *is this worth merging?* — left in the inbox with everything
137
+ prepared. The state machine is Matt Pocock's `triage` skill's (five states, one category, a brief
138
+ that outlives the codebase it describes) plus three states for the implement side. Every open issue
139
+ carries one category label (`bug` | `enhancement`) and **exactly one** state label:
140
+
141
+ ```mermaid
142
+ stateDiagram-v2
143
+ [*] --> needs_triage: triage loop, first sighting
144
+ needs_triage --> needs_info: triage loop asks
145
+ needs_info --> needs_triage: reporter replies
146
+ needs_triage --> ready_for_agent: maintainer, after reading the brief (act: the loop, for a reproduced bug)
147
+ needs_triage --> ready_for_human: maintainer
148
+ needs_triage --> wontfix: maintainer (act: the loop, for a duplicate or an already-built request)
149
+ ready_for_agent --> agent_working: implement loop claims
150
+ agent_working --> in_review: implement loop opens the PR
151
+ agent_working --> agent_blocked: implement loop cannot finish
152
+ agent_blocked --> ready_for_agent: maintainer answers
153
+ in_review --> agent_working: reviewer requests changes
154
+ in_review --> [*]: maintainer merges (Closes #n)
155
+ ```
156
+
157
+ | state | meaning | leaves it |
158
+ |---|---|---|
159
+ | *(none)* | never looked at | the triage loop labels it `needs-triage` |
160
+ | `needs-triage` | being evaluated; a brief or questions get posted here | the triage loop (→ `needs-info`) or the maintainer (→ the three below) |
161
+ | `needs-info` | waiting on the reporter | the triage loop, once the reporter has replied |
162
+ | `ready-for-agent` | the brief is accepted; an agent may build it | the implement loop claims it |
163
+ | `ready-for-human` | judgement, access, design, manual testing | a person |
164
+ | `agent-working` | claimed: a worktree and a branch exist | the implement loop (→ `in-review` or `agent-blocked`) |
165
+ | `in-review` | a pull request is open | the maintainer merges, or a reviewer requests changes |
166
+ | `agent-blocked` | the loop stopped; its last comment says what it needs | the maintainer answers and moves it back |
167
+ | `wontfix` | closed; the reason is on the issue, and for a rejected enhancement in `.out-of-scope/` | — |
168
+
169
+ Four rules make it run unattended:
170
+
171
+ - **The tracker is the truth; a loop's notes are a cache.** Every run reads labels and comments
172
+ fresh. Notes hold only what the tracker cannot say — the comment timestamp a run last handled,
173
+ the worktree a run was cut off in. A person can move any issue at any time, from the web, and
174
+ the next run sees the new state; two machines sharing a `$HOME` see the same thing.
175
+ - **The claim is the first write.** `agent-working` plus an assignee; a run that finds the label
176
+ already gone picks the next issue. Nothing is held in memory across runs. It is a soft lock —
177
+ the tracker has no compare-and-swap — and at thirty-minute cadence that has been enough.
178
+ - **The brief is the contract.** An *Agent Brief* comment describes behaviour, interfaces and
179
+ acceptance criteria, never file paths or line numbers, so it is still right after the weeks it
180
+ may wait. The implement loop builds from the latest brief; when the brief and the code disagree
181
+ in a way the brief did not foresee, that is `agent-blocked`, not a guess.
182
+ - **Every AI comment says so** on its first line.
183
+
184
+ The two checkpoints are pushed as far right as they go. `#14 brief posted — recommend
185
+ ready-for-agent (bug, reproduced by npm test)` arrives after the loop has reproduced the bug,
186
+ checked `.out-of-scope/` and the open issues for a prior answer, and written the brief; your
187
+ click on the label is the whole approval (`act` makes that click for reproduced bugs). `#12 PR
188
+ opened — <url> (3 commits, checks green)` arrives after the build, the project's check command and
189
+ a test plan; requesting changes sends it back to the loop, which addresses each comment and
190
+ re-requests review. Merging stays with a person at every level.
191
+
192
+ What a run looks like when it goes wrong is in the playbooks themselves: a run cut off
193
+ mid-implementation resumes from its branch and notes; a check command failing twice on one issue
194
+ is a block, not a third attempt; the loop and you editing the same issue is settled by the
195
+ tracker, which wins.
196
+
197
+ Specific to this repository: the labels are on
198
+ [github.com/alphacoder-v0/pi-loops](https://github.com/alphacoder-v0/pi-loops/labels), the check
199
+ command is `npm run ci`, and a release needs a one-time password — so the release side can only
200
+ propose, which is what `changelog-draft` does everywhere.
201
+
202
+ ## autoresearch
203
+
204
+ The shape Karpathy's autoresearch and Arbor made familiar, without a kernel: a **research
205
+ contract** a person writes, a **ledger** of every attempt including the failed ones, one isolated
206
+ worktree per experiment, and a rule that the held-out number decides — never the dev number a run
207
+ was tuning against.
208
+
209
+ - **`RESEARCH.md`** at the project root is the contract: objective, metric and direction, the dev
210
+ and held-out commands (each prints `metric=<number>`), which files may change, which are
211
+ protected, the promotion rule, the time budget. The loop never writes it; a run that finds it
212
+ missing files one finding and stops, and a run that finds a protected file's hash changed does
213
+ the same. `RESEARCH.template.md` is installed beside the playbook; `example/` is a filled-in one
214
+ with a naive exact k-NN in pure Python whose baseline speedup is 1.0.
215
+ - **`results.tsv`** (the path the contract names) is the ledger: one row per experiment with its
216
+ branch, hypothesis, dev and held-out numbers and a status — `baseline`, `running`, `retired`,
217
+ `kept`, `promoted`. A retired row is negative evidence the next run reads before choosing; the
218
+ loop writes the file and never commits it.
219
+ - **One run, one experiment.** Choose a hypothesis the ledger has not retired, write its row as
220
+ `running`, branch in a worktree, change only the editable files, commit, measure on dev. Not
221
+ better: `retired`, worktree removed, branch deleted, no finding — a retired experiment is the
222
+ normal outcome and the row is what matters. Better on dev: measure on held-out; a dev-only gain
223
+ is `retired` too, with that note.
224
+ - **Promotion** is the checkpoint. Under `propose` the finding names the branch and both numbers
225
+ and a person merges; under `act` the loop merges into the checkout's current branch and the
226
+ finding says so. The job runs with `--verify`, and the playbook's *For the checker* section tells
227
+ the checker what verifying means here: check out the branch, run the held-out command yourself,
228
+ keep the finding only if your number satisfies the rule.
229
+
230
+ Try it on the example before your own problem:
231
+
232
+ ```sh
233
+ cp -r .agents/skills/autoresearch/example /tmp/knn && cd /tmp/knn && git init -q && git add -A && git commit -qm baseline
234
+ pi # /recipe add autoresearch, then /cron run autoresearch
235
+ ```
236
+
237
+ The first run measures the baseline and creates the ledger; each later one tries one idea. With
238
+ the example's five-percent rule and a four-second evaluation, a promotion arrives within a few
239
+ runs — and so do the retired ideas, in the ledger, which is what makes the runs after that better.
@@ -173,6 +173,8 @@ weaker, and worth converting whenever one of them breaks.
173
173
  be read as prose and waved through. `test/web-page.test.ts`: *a confirmation shows what is
174
174
  about to run*.
175
175
  - [x] Enter does not approve: the focus starts on cancel.
176
+ - [x] A slash command that waits in a dialog is not reported as timed out while the person reads:
177
+ the browser waits up to fifteen minutes for a `/…` prompt, sixty seconds for anything else.
176
178
  - [x] Clicking away from any dialog closes it. `test/web-page.test.ts`: *clicking outside a dialog
177
179
  closes it*.
178
180
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alphacoder-v0/pi-loops",
3
- "version": "0.17.6",
3
+ "version": "0.18.0",
4
4
  "description": "An automation layer for pi: cron + stateful loops with a triage inbox, maker/checker verification, dynamic triggers, MCP notifications and tools, lifecycle hooks, session archives. A non-invasive pi extension.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -32,6 +32,7 @@
32
32
  "skills",
33
33
  "docs",
34
34
  "examples",
35
+ "recipes",
35
36
  "README.md",
36
37
  "README.zh-CN.md",
37
38
  "CHANGELOG.md",
@@ -0,0 +1,31 @@
1
+ # Issue tracker: GitHub
2
+
3
+ Work items for this repository live as GitHub Issues; pull requests are the review surface. Use
4
+ the `gh` CLI for every operation; it infers the repository from the remote when run in a clone.
5
+
6
+ ## Operations
7
+
8
+ - **List**: `gh issue list --state open --limit 200 --json number,title,labels,updatedAt,author` (add `--label <state>` to filter by state)
9
+ - **Read**: `gh issue view <n> --comments --json number,title,body,labels,author,createdAt,comments`
10
+ - **Comment**: `gh issue comment <n> --body "..."` (a heredoc for multi-line bodies)
11
+ - **Change state**: `gh issue edit <n> --add-label "<new state>" --remove-label "<old state>"` — exactly one state label at a time
12
+ - **Claim**: `gh issue edit <n> --add-label agent-working --remove-label ready-for-agent --add-assignee @me`
13
+ - **Close**: `gh issue close <n> --comment "..."`
14
+ - **Pull requests**: `gh pr create`, `gh pr list --state open --json number,url,headRefName,reviewDecision,comments,updatedAt`, `gh pr view <n> --comments`, `gh pr diff <n>`
15
+
16
+ ## State vocabulary
17
+
18
+ One category label (`bug` | `enhancement`) and exactly one state label per open issue. The state
19
+ labels are `needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `agent-working`,
20
+ `in-review`, `agent-blocked`, `wontfix`. The recipe's setup script creates them; a playbook that
21
+ moves an issue names the label it moves to.
22
+
23
+ ## Blocking
24
+
25
+ A `Blocked by: #<n>, #<m>` line near the top of an issue body (or the tracker's native
26
+ dependency) gates it: the item is unblocked when every listed issue is closed.
27
+
28
+ ## Who counts as the agent
29
+
30
+ Comments and assignments made by loops are made as the account `gh` is signed in as. Every comment
31
+ a loop posts starts with a line saying it was generated by AI.
@@ -0,0 +1,38 @@
1
+ # Issue tracker: local Markdown
2
+
3
+ Work items for this repository live as Markdown files in `.scratch/issues/`, one file per item,
4
+ committed with the code. There are no pull requests: a change is a branch, and the review
5
+ checkpoint is a finding in the inbox that names the branch.
6
+
7
+ ## Layout
8
+
9
+ - `.scratch/issues/<NN>-<slug>.md`, numbered from `01`; the number is the item's id (`#07`)
10
+ - The first lines of a file:
11
+
12
+ ```markdown
13
+ # 07: <title>
14
+
15
+ **Category:** bug | enhancement
16
+ **Status:** needs-triage
17
+ **Blocked by:** 03, 05 (or "none")
18
+ ```
19
+
20
+ - Discussion appends to the bottom under `## Comments`, one `### <date> — <who>` heading per
21
+ comment; a comment by a loop starts with a line saying it was generated by AI
22
+ - An *Agent Brief* is a `## Agent Brief` section in the file, not a comment
23
+
24
+ ## Operations
25
+
26
+ - **List**: read every file in `.scratch/issues/`; the `**Status:**` line is the state
27
+ - **Read**: read the file
28
+ - **Comment**: append under `## Comments`
29
+ - **Change state**: edit the `**Status:**` line — exactly one state
30
+ - **Claim**: set `**Status:** agent-working` and add `**Assignee:** <who>`, and commit that edit on the work branch before any other work
31
+ - **Close**: set the status to `wontfix` or `done` and move the file to `.scratch/issues/closed/`
32
+ - **Review**: push the branch (or leave it local) and file a finding that names the branch and the item; a person merges with git
33
+
34
+ ## State vocabulary
35
+
36
+ `needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `agent-working`, `in-review`,
37
+ `agent-blocked`, `wontfix`, plus `done` for a merged item. A playbook that moves an item names the
38
+ state it moves to.
@@ -0,0 +1,12 @@
1
+ `/recipe add {recipe}` stopped before installing anything: that recipe's playbooks read `docs/agents/issue-tracker.md` on every run to learn where this project's work items live and how to list, read, comment on, label and close them — and `{project}` has no such file yet. Write it with me now. This is a conversation, not a template fill: explore first, propose, and write only after I have agreed.
2
+
3
+ 1. **Explore.** Run `git remote -v` in `{project}`. Look for an existing `.scratch/` directory (a sign the local Markdown tracker is already in use), and for an `## Agent skills` section in `AGENTS.md` or `CLAUDE.md` (a sign Matt Pocock's engineering skills were set up here; if so, their `docs/agents/issue-tracker.md` convention is the one we are writing, and it may already be partly there).
4
+
5
+ 2. **Propose, one question.** Lead with the recommendation so I can accept it in a word:
6
+ - a GitHub remote → recommend **GitHub Issues** (the `gh` CLI; check `gh auth status` works);
7
+ - no remote, or I say so → recommend **local Markdown**: one file per item under `.scratch/issues/`, a `**Status:**` line as the state.
8
+ Anything else (GitLab, Jira, Linear): ask me to describe the workflow in a paragraph and record it as prose.
9
+
10
+ 3. **Write `docs/agents/issue-tracker.md`** from the matching template in `{templates}/` (`issue-tracker-github.md` or `issue-tracker-local.md`), adjusted to what we agreed. Show me the draft before writing. Keep the state vocabulary section as it is: the playbooks name those states. The file stays out of the repository (the wizard lists it in `.git/info/exclude`, like the playbooks), but it is still read by every run: keep it to how the tracker works — no secrets, no tokens.
11
+
12
+ 4. **Stop there.** The wizard is waiting for this file: as soon as this turn ends with it in place, `/recipe add {recipe}` resumes on its own — the level question, the setup script, the confirmation. Do not create cron jobs, labels, worktrees or branches yourself, and do not tell me to run anything; the wizard does the rest after showing me exactly what it will do.
@@ -0,0 +1,27 @@
1
+ # autoresearch — one experiment per run, a ledger, held-out evidence before promotion
2
+
3
+ The shape is the one Karpathy's autoresearch and Arbor made familiar: a **research contract** a
4
+ person writes (objective, metric, which files may change, which are protected, dev and held-out
5
+ commands, a promotion rule), a **ledger** of every attempt including the failed ones, an isolated
6
+ worktree per experiment, and a rule that the held-out number decides — never the dev number a run
7
+ was tuning against. What pi-loops adds is that nothing here needs a kernel: the contract and the
8
+ ledger are files in the repository, each run is one stateful loop run, and the checker of
9
+ `--verify` is the evaluator that re-measures before a promotion reaches you.
10
+
11
+ | file | what it is |
12
+ |---|---|
13
+ | [recipe.toml](recipe.toml) | one job, `every 1h`, `--verify`, 40-minute timeout |
14
+ | [experiment.md](experiment.md) | the playbook: contract → ledger → one hypothesis → worktree → measure → row → maybe promote |
15
+ | [RESEARCH.template.md](RESEARCH.template.md) | copy to the project root as `RESEARCH.md` and fill in; the loop stops until it exists |
16
+ | [example/](example/) | a filled-in contract with a naive exact k-NN in pure Python: `bash eval.sh dev` prints `metric=<speedup>` |
17
+
18
+ Try it on the example first:
19
+
20
+ ```sh
21
+ cp -r .agents/skills/autoresearch/example /tmp/knn && cd /tmp/knn && git init -q && git add -A && git commit -qm "baseline"
22
+ pi # then: /recipe add autoresearch and /cron run autoresearch
23
+ ```
24
+
25
+ The first run measures the baseline and writes `results.tsv`; the next ones each try one idea.
26
+ Under `propose` a promotable branch arrives in `/inbox` with both numbers; under `act` it is
27
+ merged into the checkout and the finding says so.