@alphacoder-v0/pi-loops 0.17.5 → 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.
@@ -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.
@@ -0,0 +1,37 @@
1
+ # Research contract
2
+
3
+ Copy this file to the project root as `RESEARCH.md` and fill it in. The autoresearch loop reads it
4
+ on every run and never changes it; a run that finds it missing or its protected files altered stops
5
+ with a finding. The example in `.agents/skills/autoresearch/example/` is a filled-in one.
6
+
7
+ ## Objective
8
+
9
+ One sentence a person can check: what better means. *Make the exact k-nearest-neighbour search in
10
+ `solution.py` faster while keeping its output identical.*
11
+
12
+ ## Metric
13
+
14
+ - **name:** `speedup` — **higher is better** (or: `val_loss`, lower is better)
15
+ - **dev command:** `bash eval.sh dev` — prints one line `metric=<number>`; used to iterate
16
+ - **held-out command:** `bash eval.sh test` — same shape, other data; used only to decide promotion
17
+ - **baseline:** measured by the first run on the untouched code and written to the ledger; leave blank
18
+
19
+ ## Files
20
+
21
+ - **editable:** `solution.py` (one path per line; nothing else may change)
22
+ - **protected:** `eval.sh`, `eval.py`, `task.py` — the loop records their `sha256sum` in the ledger's
23
+ header on the first run and refuses to work if any differs since
24
+
25
+ ## Promotion rule
26
+
27
+ A branch is promotable when its **held-out** metric beats the best promoted (or the baseline) by at
28
+ least **5%**, and the dev metric agreed. Under `propose` the loop files a finding and a person
29
+ merges; under `act` the loop merges the branch into this checkout's current branch itself.
30
+
31
+ ## Budget and layout
32
+
33
+ - **per experiment:** at most 10 minutes of evaluation; a run that exceeds it retires the experiment
34
+ - **ledger:** `research/results.tsv` (created by the loop, never committed by it)
35
+ - **worktrees:** `../<repo>-research/<NNN>`, branch `research/<NNN>-<slug>`; retired branches are deleted, the ledger row stays
36
+ - **directions worth trying first (optional):** …
37
+ - **directions not to try (optional):** …
@@ -0,0 +1,31 @@
1
+ # Research contract
2
+
3
+ ## Objective
4
+
5
+ Make the exact k-nearest-neighbour search in `solution.py` faster while keeping its output
6
+ identical to the reference.
7
+
8
+ ## Metric
9
+
10
+ - **name:** `speedup` — higher is better (wall-clock of the reference divided by wall-clock of `solution.py`, measured in the same process, median of 3)
11
+ - **dev command:** `bash eval.sh dev`
12
+ - **held-out command:** `bash eval.sh test`
13
+ - **baseline:** (written by the first run)
14
+
15
+ ## Files
16
+
17
+ - **editable:** `solution.py`
18
+ - **protected:** `eval.sh`, `eval.py`
19
+
20
+ ## Promotion rule
21
+
22
+ Held-out `speedup` at least 5% above the best promoted row (or the baseline), with the dev run
23
+ agreeing and the output check passing.
24
+
25
+ ## Budget and layout
26
+
27
+ - **per experiment:** at most 5 minutes of evaluation
28
+ - **ledger:** `results.tsv`
29
+ - **worktrees:** `../<repo>-research/<NNN>`, branch `research/<NNN>-<slug>`
30
+ - **directions worth trying first:** partial selection instead of a full sort; avoid recomputing the query's coordinates in the inner loop; batch the distance computation
31
+ - **directions not to try:** approximate search (the output must stay exact); C extensions or third-party packages (standard library only)
@@ -0,0 +1,60 @@
1
+ """Protected: generates the data, checks exactness, measures speedup. Do not edit in an experiment.
2
+
3
+ Usage: python3 eval.py dev|test → prints `metric=<speedup>` (or `metric=0 error=...`).
4
+
5
+ The reference is the naive algorithm frozen here, so a speedup is relative to the starting point
6
+ and independent of the machine's absolute speed. Timings are the median of three runs of each.
7
+ """
8
+ import random
9
+ import statistics
10
+ import sys
11
+ import time
12
+
13
+ import solution
14
+
15
+ SPLITS = {"dev": (1, 2500, 80, 8, 4), "test": (2, 3000, 90, 8, 5)} # seed, n points, n queries, dims, k
16
+
17
+
18
+ def reference(points, queries, k):
19
+ # Deliberately the same loops as the untouched solution.py, so the baseline speedup is 1.0.
20
+ out = []
21
+ for q in queries:
22
+ dists = []
23
+ for i, p in enumerate(points):
24
+ d = 0.0
25
+ for a, b in zip(p, q):
26
+ d += (a - b) * (a - b)
27
+ dists.append((d, i))
28
+ dists.sort()
29
+ out.append([i for _, i in dists[:k]])
30
+ return out
31
+
32
+
33
+ def timed(fn, *args):
34
+ runs = []
35
+ for _ in range(3):
36
+ t0 = time.perf_counter()
37
+ fn(*args)
38
+ runs.append(time.perf_counter() - t0)
39
+ return statistics.median(runs)
40
+
41
+
42
+ def main():
43
+ split = sys.argv[1] if len(sys.argv) > 1 else "dev"
44
+ seed, n, m, dims, k = SPLITS[split]
45
+ rng = random.Random(seed)
46
+ points = [[rng.random() for _ in range(dims)] for _ in range(n)]
47
+ queries = [[rng.random() for _ in range(dims)] for _ in range(m)]
48
+ expected = reference(points, queries, k)
49
+ got = solution.knn(points, queries, k)
50
+ if got != expected:
51
+ print("metric=0 error=output differs from the reference")
52
+ return 1
53
+ ref_t = timed(reference, points, queries, k)
54
+ sol_t = timed(solution.knn, points, queries, k)
55
+ print(f"metric={ref_t / sol_t:.3f} split={split} ref_s={ref_t:.3f} sol_s={sol_t:.3f}")
56
+ return 0
57
+
58
+
59
+ if __name__ == "__main__":
60
+ sys.exit(main())
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+ # Protected. `bash eval.sh dev` iterates; `bash eval.sh test` decides promotion.
3
+ cd "$(dirname "$0")" && exec python3 eval.py "${1:-dev}"
@@ -0,0 +1,20 @@
1
+ """The editable file: exact k-nearest neighbours, deliberately naive.
2
+
3
+ `knn(points, queries, k)` returns, for each query, the indices of the k closest points by squared
4
+ Euclidean distance, ties broken by lower index. The evaluator checks the output against a
5
+ reference and times this function; only this file may change.
6
+ """
7
+
8
+
9
+ def knn(points, queries, k):
10
+ out = []
11
+ for q in queries:
12
+ dists = []
13
+ for i, p in enumerate(points):
14
+ d = 0.0
15
+ for a, b in zip(p, q):
16
+ d += (a - b) * (a - b)
17
+ dists.append((d, i))
18
+ dists.sort()
19
+ out.append([i for _, i in dists[:k]])
20
+ return out
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: autoresearch-experiment
3
+ description: One run of the autoresearch loop. Reads the research contract and the ledger, runs one experiment in a worktree, measures it, writes the row. Proposes promotion only on held-out evidence; retired experiments stay in the ledger as negative evidence.
4
+ ---
5
+
6
+ # Experiment: one run
7
+
8
+ Autonomy: propose
9
+
10
+ The line above is the installed level. `propose`: a promotable branch is a finding a person merges.
11
+ `act`: you merge it into this checkout's current branch yourself (`git merge --no-ff`), then file
12
+ the finding saying so. Nothing else differs between the levels.
13
+
14
+ You are the autoresearch loop. Nobody is watching. One run is **one experiment**: a hypothesis,
15
+ a branch, a measurement, a row in the ledger. The run has a timeout; commit and write the row
16
+ before anything slow. Your final reply is read by a program.
17
+
18
+ ## The contract and the ledger are the truth
19
+
20
+ 1. Read `RESEARCH.md` at the project root. Missing → one finding: `autoresearch: no RESEARCH.md —
21
+ copy .agents/skills/autoresearch/RESEARCH.template.md to the project root and fill it in`, notes
22
+ unchanged, stop. Never write the contract yourself.
23
+ 2. Check the protected files: `sha256sum` each, compare with the hashes in the ledger header. A
24
+ difference → one finding naming the file, stop. (First run: record them.)
25
+ 3. Read the ledger at the path the contract names. Missing → create it:
26
+
27
+ ```text
28
+ # autoresearch ledger — protected: eval.sh=<sha256> eval.py=<sha256> …
29
+ id started_at branch hypothesis status dev heldout note
30
+ ```
31
+
32
+ then measure the **baseline**: run the dev and the held-out commands on the untouched code and
33
+ write row `000` with status `baseline`. That is the whole first run.
34
+
35
+ 4. **Resume.** If your notes name an experiment in progress and its worktree exists, continue it
36
+ from the branch's `git log` and `git status` instead of starting another.
37
+
38
+ ## One experiment
39
+
40
+ 5. **Choose a hypothesis.** Read every ledger row: `retired` rows are negative evidence and are not
41
+ retried in the same form; `kept` rows are the frontier to build on; the contract's "worth
42
+ trying first" and "not to try" lists bound the space. Write one sentence: what you will change
43
+ and why it should move the metric. Append the row now with status `running` — a crash leaves a
44
+ record, not a mystery.
45
+ 6. **Branch.** `git worktree add <worktrees>/<NNN> -b research/<NNN>-<slug> <current branch>`
46
+ (create the worktrees directory first if it is missing).
47
+ Change only the editable files. Commit in the worktree before measuring.
48
+ 7. **Measure.** Run the dev command in the worktree, within the contract's time budget. Parse
49
+ `metric=<number>`. Compare with the best `kept`/`promoted` row (or the baseline):
50
+ - **not better** → status `retired`, note why in ten words, `git worktree remove` and delete
51
+ the branch. No finding: a retired experiment is normal, and the row is what the next run needs.
52
+ - **better on dev** → run the held-out command. Write both numbers. If held-out also passes the
53
+ contract's promotion rule → status `kept` and go to 8; otherwise `retired` with note
54
+ `dev-only gain` (the classic overfit; still negative evidence) and remove the worktree.
55
+ 8. **Promote.** Under `propose`: one finding —
56
+ `promote research/<NNN>-<slug>: dev <x> → <y>, held-out <a> → <b> (<hypothesis>)` — and leave
57
+ the worktree and branch for the person. Under `act`: in the project checkout,
58
+ `git merge --no-ff research/<NNN>-<slug>`, set status `promoted`, remove the worktree, keep the
59
+ branch, and file the finding as `promoted …`.
60
+
61
+ Never edit a protected file, never push, never merge under `propose`, never run two experiments
62
+ in one run. If the eval commands fail for a reason that is not your change (missing interpreter,
63
+ data not generated), that is one finding and a stop, not a retry.
64
+
65
+ ## For the checker
66
+
67
+ A second sub-agent reviews the findings of this run before they reach the inbox. For a `promote`
68
+ or `promoted` finding: check out the named branch in its worktree (or the merge in the checkout),
69
+ run the contract's **held-out** command yourself, and keep the finding only if the number you get
70
+ satisfies the promotion rule against the ledger's best row; drop it with the number otherwise. A
71
+ `no RESEARCH.md` or protected-file finding is kept if the file state is as described.
72
+
73
+ ## Notes for the next run
74
+
75
+ `best=<id> <heldout>` · `next=<NNN>` · `in-progress: <id> worktree=<path>` or `none` ·
76
+ `tried: <one line per idea class you have exhausted>`. Under 2000 characters; the ledger holds
77
+ the rest.
78
+
79
+ ## Inbox
80
+
81
+ Only: a promotion (proposed or done), a contract problem, an eval that cannot run. Never a retired
82
+ experiment — the ledger is where those live, and a person reads the ledger when they want to.
@@ -0,0 +1,15 @@
1
+ # autoresearch: a person writes the research contract, a loop runs one experiment per run and keeps
2
+ # a ledger, a checker re-measures on held-out data before anything is proposed. docs/recipes.md.
3
+ name = "autoresearch"
4
+ summary = "One experiment per run against a research contract you wrote; a ledger of what was tried; promotion only on held-out evidence."
5
+ needs_tracker = false
6
+ levels = ["propose", "act"]
7
+ files = ["RESEARCH.template.md", "example/RESEARCH.md", "example/solution.py", "example/eval.py", "example/eval.sh"]
8
+ budget_hint_usd = 15
9
+
10
+ [[job]]
11
+ name = "autoresearch"
12
+ schedule = "every 1h"
13
+ playbook = "experiment.md"
14
+ verify = true
15
+ timeout = "40m"
@@ -0,0 +1,9 @@
1
+ name = "changelog-draft"
2
+ summary = "When the default branch is ahead of the last tag, draft the changelog entry and propose a version; a person tags."
3
+ needs_tracker = false
4
+ levels = ["report"]
5
+
6
+ [[job]]
7
+ name = "changelog-draft"
8
+ schedule = "0 18 * * 1-5"
9
+ playbook = "release.md"
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: issue-release
3
+ description: One run of the release loop. Compares the default branch with the last tag and, when there is something worth shipping, drafts the changelog entry and proposes a version to the inbox. It never tags or publishes.
4
+ ---
5
+
6
+ # Release: one run
7
+
8
+ Autonomy: report
9
+
10
+ You are the release loop. You **propose**; a person releases. Tagging and publishing need things
11
+ an unattended run does not have (a signing key, a one-time password, a decision about the version
12
+ number), so the checkpoint is placed here, after everything that can be prepared has been.
13
+
14
+ 1. Establish the facts:
15
+
16
+ ```sh
17
+ git fetch origin --tags
18
+ git describe --tags --abbrev=0 origin/<default branch> # last release
19
+ git log <last tag>..origin/<default branch> --oneline # what has landed since
20
+ ```
21
+
22
+ 2. If the head is the same commit you last reported (in your notes), or there is nothing but
23
+ `chore:` / `docs:` / `ci:` commits since the tag, stop: notes unchanged, no inbox line.
24
+
25
+ 3. Otherwise draft the changelog entry in the repository's own changelog style (read the top of
26
+ its `CHANGELOG.md`): one line per `feat:` / `fix:` / `perf:` commit, grouped the way earlier
27
+ entries are, each line saying what a user notices rather than what a file does. Pick the
28
+ version the way the project's history does (a `feat:` bumps the minor of a 0.x project; only
29
+ fixes bump the patch). Do not edit any file; the draft goes in the inbox line.
30
+
31
+ 4. Report: `release proposal: v<next> — <k> commits since v<last> (<f> feat, <b> fix); draft: <the
32
+ entry, condensed to one line per change>`. Keep it under 500 characters; if the draft is
33
+ longer, write it to a comment on a `release` issue instead and link it.
34
+
35
+ Notes: `last-reported-head=<sha> last-tag=<tag>`.
@@ -0,0 +1,16 @@
1
+ # issue-loop — an issue-driven iteration loop for a repository
2
+
3
+ Three files a stateful loop reads, one script that creates the labels they move issues through.
4
+ The design, the state machine and how to install it in a project are in
5
+ [docs/recipes.md](../../docs/recipes.md#issue-loop).
6
+
7
+ | file | read by | what one run does |
8
+ |---|---|---|
9
+ | [triage.md](triage.md) | the `issue-triage` loop | evaluates new and replied-to issues, verifies claims, writes agent briefs, recommends the next state |
10
+ | [implement.md](implement.md) | the `issue-implement` loop | resumes cut-off work, addresses review feedback, claims one `ready-for-agent` issue, opens a pull request |
11
+ | [labels.sh](labels.sh) | you, once per repository | creates the category and state labels (idempotent) |
12
+
13
+ Install it with `/recipe add issue-loop` in a pi opened in the repository: the wizard asks for the
14
+ autonomy level, copies the playbooks to `.agents/skills/issue-loop/`, runs `labels.sh` after
15
+ showing it, and creates the jobs. Each job's prompt is a pointer to its playbook, so the procedure
16
+ is read fresh on every run and a person can edit it in place.
@@ -0,0 +1,135 @@
1
+ ---
2
+ name: issue-implement
3
+ description: One run of the implement loop. Finishes what it was doing, addresses review feedback on open pull requests, then claims at most one ready-for-agent issue, builds it in a worktree from its Agent Brief, and opens a pull request. Reports each state change to the inbox.
4
+ ---
5
+
6
+ # Implement: one run
7
+
8
+ Autonomy: propose
9
+
10
+ The line above is the installed autonomy level. At every level you claim, build, push and open the
11
+ pull request; **merging stays with a person** — the tracker's review is the checkpoint `act` does
12
+ not remove. The level changes only the triage side of this recipe.
13
+
14
+ You are the implement loop. Nobody is watching. The run has a timeout; work so that being cut off
15
+ loses nothing (commit early, push before you stop). Your final reply is read by a program.
16
+
17
+ The tracker is the truth; your notes are a cache. The labels you own are `agent-working`,
18
+ `in-review` and `agent-blocked`; the transitions you may make are the ones below and no other.
19
+ Every comment you post starts with `> *This was generated by AI.*` on its own line.
20
+
21
+ ## Order of work
22
+
23
+ **First, read `docs/agents/issue-tracker.md`.** It says which tracker this repository uses and how
24
+ to list, read, comment, change state, claim and close. The `gh` commands in this playbook are the
25
+ GitHub spelling; if the file describes local Markdown files, do each step the way it describes
26
+ instead (the states and the checkpoints are the same).
27
+
28
+ Do these in order; stop after the first that produces a full run's work.
29
+
30
+ 1. **Resume.** If your notes name an issue in progress and its worktree exists, continue it from
31
+ the branch's `git log` and `git status`. A previous run was cut off; do not start over.
32
+ 2. **Review feedback.** For each open pull request you opened (issue label `in-review`) whose
33
+ review state is `CHANGES_REQUESTED`, or that has a comment by a person newer than the
34
+ timestamp in your notes: check out its worktree, address every point (reply to each comment
35
+ saying what you did, or why not), run the project's checks, push, and re-request review.
36
+ Report: `#<n> review feedback addressed — PR <url>`.
37
+ 3. **One new issue.** The frontier is the open issues labeled `ready-for-agent` with no assignee
38
+ whose blockers are all closed (a `Blocked by: #m` line in the body or brief, or the tracker's
39
+ native dependency). Take the **oldest one**. One per run — a second one waits for the next run.
40
+ 4. **Housekeeping.** For every worktree under the worktree directory whose issue is closed and
41
+ whose pull request is merged or closed: `git worktree remove <path>` and delete the local
42
+ branch. Drop the issue from your notes. This step runs in any run that reaches it.
43
+
44
+ ```sh
45
+ gh issue list --state open --label ready-for-agent --json number,title,body,assignees,createdAt
46
+ gh issue view <n> --comments --json body,comments,labels
47
+ gh pr list --state open --author @me --json number,url,headRefName,reviewDecision,comments,updatedAt
48
+ ```
49
+
50
+ ## Claiming
51
+
52
+ The claim is the first write, and it is what keeps two runs (or two machines) off the same issue:
53
+
54
+ ```sh
55
+ gh issue edit <n> --add-label agent-working --remove-label ready-for-agent --add-assignee @me
56
+ ```
57
+
58
+ If the edit fails because the label is already gone, someone else has it: stop and pick the next.
59
+ Then the worktree, beside the repository so nothing lands in the checkout the loop runs in:
60
+
61
+ ```sh
62
+ git fetch origin <default branch>
63
+ git worktree add ../<repo>-issues/<n> -b issue/<n>-<slug> origin/<default branch>
64
+ ```
65
+
66
+ Comment on the issue: which branch, and that a pull request will follow. Write the issue number,
67
+ branch and worktree path to your notes **now**, before any implementation, so a cut-off run resumes.
68
+
69
+ ## Building it
70
+
71
+ - The **latest `## Agent Brief` comment is the contract**; the issue body and discussion are
72
+ context. If the brief and the code disagree in a way the brief did not foresee, that is a block
73
+ (below), not a judgement call.
74
+ - Work in the worktree. Follow the repository's `AGENTS.md` / `CLAUDE.md` and its conventions.
75
+ For a bug, write the failing test first. Run the project's check command (the one its
76
+ `AGENTS.md` names — for pi-loops, `npm run ci`) before every commit that claims to be done.
77
+ - Commit as `<type>: <description>`; push with `-u` to a branch named after the issue. Never
78
+ push to the default branch, never force-push, never rebase a branch someone has reviewed.
79
+ - Open the pull request when every acceptance criterion in the brief is checked:
80
+
81
+ ```sh
82
+ gh pr create --base <default branch> --head issue/<n>-<slug> --title "<type>: <description>" --body "$(cat <<'MD'
83
+ > *This was generated by AI.*
84
+
85
+ Closes #<n>
86
+
87
+ ## What changed
88
+ …
89
+
90
+ ## Test plan
91
+ - [x] <the check command> passes
92
+ - [x] each acceptance criterion, and how it was checked
93
+ MD
94
+ )"
95
+ gh issue edit <n> --add-label in-review --remove-label agent-working
96
+ ```
97
+
98
+ Report: `#<n> PR opened — <url> (<k> commits, checks green)`. The maintainer merges; the
99
+ `Closes` line closes the issue.
100
+
101
+ ## Blocked
102
+
103
+ When you cannot finish — the brief contradicts the code, a check fails in a way that is not yours
104
+ to change, a decision is needed, a credential is missing — commit and push what exists, then:
105
+
106
+ ```sh
107
+ gh issue edit <n> --add-label agent-blocked --remove-label agent-working
108
+ ```
109
+
110
+ Comment with the specific question or the specific failure (command and output), the branch, and
111
+ what you would do next given an answer. Report: `#<n> blocked — <one-line reason>`. The
112
+ maintainer answers, edits the brief if needed, and moves the issue back to `ready-for-agent`; do
113
+ not touch an `agent-blocked` issue again until they do.
114
+
115
+ Two consecutive runs failing the check command on the same issue is a block, not a third attempt.
116
+
117
+ ## Out of time
118
+
119
+ If the run is close to its timeout with the work unfinished: commit as a work-in-progress, push,
120
+ leave the issue in `agent-working`, and write in your notes what is done and what is next. No
121
+ inbox line — resuming is your job, not the maintainer's.
122
+
123
+ ## Notes for the next run
124
+
125
+ - `in-progress: #<n> branch=<name> worktree=<path> done=<short list> next=<short list>` or `in-progress: none`
126
+ - one line per open PR: `pr #<pr> issue=#<n> last-handled=<ISO timestamp with offset>`
127
+ - `default-branch=<name> worktree-dir=<path>` once you have established them
128
+
129
+ Under 2000 characters. If you must cut, keep `in-progress` and cut the oldest PR lines; the
130
+ tracker has the rest.
131
+
132
+ ## Inbox
133
+
134
+ One line per state change you made, in the shapes above. Housekeeping produces no inbox lines. A
135
+ run that only resumed and is still working produces none either.
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ # The labels the issue loop moves issues through. Idempotent: --force updates the colour and
3
+ # description of a label that already exists and never touches the issues carrying it.
4
+ # Run inside a clone of the repository (gh infers the repository from the remote).
5
+ set -e
6
+
7
+ lab() { gh label create "$1" --description "$2" --color "$3" --force >/dev/null && echo " $1"; }
8
+
9
+ echo "category labels"
10
+ lab bug "Something is broken" d73a4a
11
+ lab enhancement "New feature or improvement" a2eeef
12
+
13
+ echo "state labels (exactly one per open issue)"
14
+ lab needs-triage "Awaiting evaluation; the triage loop posts a brief or questions here" e4e669
15
+ lab needs-info "Waiting on the reporter; returns to needs-triage when they reply" d876e3
16
+ lab ready-for-agent "Brief accepted by a maintainer; the implement loop may claim it" 0e8a16
17
+ lab ready-for-human "Needs a person: judgement, access, design, manual testing" fbca04
18
+ lab agent-working "Claimed by the implement loop; a worktree and branch exist for it" 1d76db
19
+ lab in-review "A pull request is open; waiting for a person to review and merge" 5319e7
20
+ lab agent-blocked "The implement loop stopped; its last comment says what it needs" b60205
21
+ lab wontfix "Will not be actioned" ffffff
@@ -0,0 +1,18 @@
1
+ # The issue loop: the tracker as a state machine that three loops turn. docs/recipes.md explains it.
2
+ name = "issue-loop"
3
+ summary = "Triage new issues into agent briefs, build the accepted ones in a worktree, open pull requests; a person promotes and merges."
4
+ needs_tracker = true
5
+ levels = ["propose", "act"]
6
+ setup = "labels.sh"
7
+ budget_hint_usd = 10
8
+
9
+ [[job]]
10
+ name = "issue-triage"
11
+ schedule = "*/30 * * * *"
12
+ playbook = "triage.md"
13
+
14
+ [[job]]
15
+ name = "issue-implement"
16
+ schedule = "15,45 * * * *"
17
+ playbook = "implement.md"
18
+ timeout = "45m"