@phamvuhoang/otto-core 0.4.1 → 0.6.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/dist/branch.d.ts +20 -0
- package/dist/branch.d.ts.map +1 -1
- package/dist/branch.js +34 -1
- package/dist/branch.js.map +1 -1
- package/dist/cli-help.d.ts +42 -0
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +56 -2
- package/dist/cli-help.js.map +1 -1
- package/dist/gh-main.d.ts.map +1 -1
- package/dist/gh-main.js +1 -0
- package/dist/gh-main.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/linear-api.d.ts +1 -0
- package/dist/linear-api.d.ts.map +1 -1
- package/dist/linear-api.js +6 -1
- package/dist/linear-api.js.map +1 -1
- package/dist/linear-cli.d.ts.map +1 -1
- package/dist/linear-cli.js +11 -3
- package/dist/linear-cli.js.map +1 -1
- package/dist/linear-main.d.ts.map +1 -1
- package/dist/linear-main.js +4 -1
- package/dist/linear-main.js.map +1 -1
- package/dist/run-bin.d.ts +10 -0
- package/dist/run-bin.d.ts.map +1 -1
- package/dist/run-bin.js +116 -0
- package/dist/run-bin.js.map +1 -1
- package/dist/task-key.d.ts +65 -0
- package/dist/task-key.d.ts.map +1 -0
- package/dist/task-key.js +112 -0
- package/dist/task-key.js.map +1 -0
- package/dist/watch.d.ts +26 -4
- package/dist/watch.d.ts.map +1 -1
- package/dist/watch.js +96 -41
- package/dist/watch.js.map +1 -1
- package/package.json +1 -1
- package/templates/acceptance-prompts.md +42 -0
- package/templates/apply-review.md +32 -2
- package/templates/ghafk-issue.md +4 -2
- package/templates/ghafk.md +2 -2
- package/templates/ghprompt-workflow.md +9 -0
- package/templates/ghprompt.md +2 -0
- package/templates/linear-completion.md +10 -0
- package/templates/linearprompt.md +3 -1
- package/templates/quality-report.md +80 -0
- package/templates/review-lens.md +1 -0
- package/templates/superpowers.md +23 -10
- package/templates/verify.md +17 -21
package/dist/watch.js
CHANGED
|
@@ -4,13 +4,18 @@ import { createLinearClient, resolveLinearAuth, LinearApiError, } from "./linear
|
|
|
4
4
|
import { runLoop } from "./loop.js";
|
|
5
5
|
import { notifyComplete, notifyError } from "./notify.js";
|
|
6
6
|
import { sleep } from "./pacing.js";
|
|
7
|
+
import { describeScope } from "./task-key.js";
|
|
7
8
|
import { bold, dim, greenOut, boldOut, dimOut, SYM_OUT, USE_COLOR, } from "./stream-render.js";
|
|
8
|
-
/**
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Poll open issues carrying `label`, via gh. Never throws. When `repo`
|
|
11
|
+
* (`owner/name`) is given the poll is confined to that repository (watch
|
|
12
|
+
* scoping) instead of the workspace's default repo.
|
|
13
|
+
*/
|
|
14
|
+
export function pollOpenIssues(label, cwd, repo) {
|
|
10
15
|
try {
|
|
11
|
-
// execFileSync (no shell) so `label`
|
|
12
|
-
// value like `$(rm -rf ~)` can never be shell-evaluated. See
|
|
13
|
-
// stderr is piped (not ignored) so
|
|
16
|
+
// execFileSync (no shell) so `label`/`repo` are passed as literal argv
|
|
17
|
+
// entries — a value like `$(rm -rf ~)` can never be shell-evaluated. See
|
|
18
|
+
// SECURITY.md. stderr is piped (not ignored) so failures can be classified.
|
|
14
19
|
const out = execFileSync("gh", [
|
|
15
20
|
"issue",
|
|
16
21
|
"list",
|
|
@@ -18,6 +23,7 @@ export function pollOpenIssues(label, cwd) {
|
|
|
18
23
|
"open",
|
|
19
24
|
"--label",
|
|
20
25
|
label,
|
|
26
|
+
...(repo ? ["--repo", repo] : []),
|
|
21
27
|
"--json",
|
|
22
28
|
"number",
|
|
23
29
|
], { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -58,6 +64,7 @@ export async function pollLinearIssues(deps) {
|
|
|
58
64
|
const issues = await client.listIssues({
|
|
59
65
|
label: deps.label,
|
|
60
66
|
team: deps.team,
|
|
67
|
+
project: deps.project,
|
|
61
68
|
limit: deps.limit ?? 50,
|
|
62
69
|
});
|
|
63
70
|
return { ok: true, count: issues.length };
|
|
@@ -71,7 +78,28 @@ export async function pollLinearIssues(deps) {
|
|
|
71
78
|
}
|
|
72
79
|
const GH_PROVIDER = { name: "gh", authCmd: "gh auth login" };
|
|
73
80
|
export async function runWatch(opts) {
|
|
74
|
-
const { stages, iterations, workspaceDir, packageDir, watchIntervalSec, watchLabel, budgetUsd, cooldownMs, maxRetries, reviewLenses, notify = false, bin = "otto-ghafk", pollIssues = pollOpenIssues, provider = GH_PROVIDER, } = opts;
|
|
81
|
+
const { stages, iterations, workspaceDir, packageDir, watchIntervalSec, watchLabel, budgetUsd, cooldownMs, maxRetries, reviewLenses, notify = false, bin = "otto-ghafk", pollIssues = pollOpenIssues, provider = GH_PROVIDER, scope, scopes, } = opts;
|
|
82
|
+
// The scopes this daemon rotates through each cycle. Multi-target watch
|
|
83
|
+
// passes `scopes`; otherwise a single `scope` (or the workspace default,
|
|
84
|
+
// represented by a lone `undefined`).
|
|
85
|
+
const scopeList = scopes && scopes.length > 0 ? scopes : [scope];
|
|
86
|
+
// Derive the gh `--repo` filter from a github scope; other providers (Linear)
|
|
87
|
+
// carry their scope in the label/team the poller already honors.
|
|
88
|
+
const ghRepoOf = (s) => s?.provider === "github" && s.owner && s.repo
|
|
89
|
+
? `${s.owner}/${s.repo}`
|
|
90
|
+
: undefined;
|
|
91
|
+
// The Linear project for a scope. Unlike github (which gets a poll `--repo`
|
|
92
|
+
// arg), the Linear poller reads OTTO_LINEAR_PROJECT from the env, so the
|
|
93
|
+
// daemon pins it before each poll/run to confine that scope.
|
|
94
|
+
const linearProjectOf = (s) => s?.provider === "linear" && s.project ? s.project : undefined;
|
|
95
|
+
// Human-readable scope prefix for a poll line (e.g. "github acme/web ").
|
|
96
|
+
const labelOf = (s) => s ? `${describeScope(s)} ` : "";
|
|
97
|
+
// The banner names every scope so a maintainer sees the exact watch surface.
|
|
98
|
+
const bannerScope = scopeList
|
|
99
|
+
.filter((s) => !!s)
|
|
100
|
+
.map(describeScope)
|
|
101
|
+
.join(", ");
|
|
102
|
+
const scopeLabel = bannerScope ? `${bannerScope} ` : "";
|
|
75
103
|
const releaser = acquire({ reason: `${bin} watch` });
|
|
76
104
|
let released = false;
|
|
77
105
|
const releaseOnce = () => {
|
|
@@ -92,7 +120,7 @@ export async function runWatch(opts) {
|
|
|
92
120
|
const onSigterm = onSig(143);
|
|
93
121
|
process.on("SIGINT", onSigint);
|
|
94
122
|
process.on("SIGTERM", onSigterm);
|
|
95
|
-
process.stderr.write(`${USE_COLOR ? dim("watching") + " " + bold(
|
|
123
|
+
process.stderr.write(`${USE_COLOR ? dim("watching") + " " + bold(`${scopeLabel}label:${watchLabel} every ${watchIntervalSec}s`) : `watching ${scopeLabel}label:${watchLabel} every ${watchIntervalSec}s`}\n`);
|
|
96
124
|
let cumulativeCost = 0;
|
|
97
125
|
// Track idle state so the "no open issues" line prints only on the
|
|
98
126
|
// idle→busy→idle transition, not on every empty poll — otherwise an
|
|
@@ -107,42 +135,69 @@ export async function runWatch(opts) {
|
|
|
107
135
|
notifyComplete(0, false);
|
|
108
136
|
return;
|
|
109
137
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
// Poll every scope this cycle. Run one loop for the FIRST scope with
|
|
139
|
+
// work, then break back to the sleep+repoll — one loop at a time, no
|
|
140
|
+
// parallel mutation of the workspace. A failed poll for one scope is
|
|
141
|
+
// logged and skipped so it never blocks polling the others.
|
|
142
|
+
let ran = false;
|
|
143
|
+
let allIdle = true;
|
|
144
|
+
for (const s of scopeList) {
|
|
145
|
+
const sRepo = ghRepoOf(s);
|
|
146
|
+
const sProject = linearProjectOf(s);
|
|
147
|
+
const sLabel = labelOf(s);
|
|
148
|
+
// Pin the Linear project before polling so the poller (which reads it
|
|
149
|
+
// from the inherited env, not a poll arg) is confined to this scope;
|
|
150
|
+
// it also stays pinned for the loop run below. GitHub uses the sRepo
|
|
151
|
+
// poll arg instead and pins OTTO_GITHUB_REPO only on the run.
|
|
152
|
+
if (sProject)
|
|
153
|
+
process.env.OTTO_LINEAR_PROJECT = sProject;
|
|
154
|
+
const poll = await pollIssues(watchLabel, workspaceDir, sRepo);
|
|
155
|
+
if (!poll.ok) {
|
|
156
|
+
// Broken poll — say *why*, distinctly from an idle queue, and keep
|
|
157
|
+
// polling (auth may get fixed / a transient failure may clear).
|
|
158
|
+
allIdle = false;
|
|
159
|
+
wasIdle = false;
|
|
160
|
+
const suffix = poll.detail ? ` — ${poll.detail}` : "";
|
|
161
|
+
const why = poll.auth
|
|
162
|
+
? `${sLabel}${provider.name} not authenticated — run '${provider.authCmd}' (label ${watchLabel})${suffix}`
|
|
163
|
+
: `${sLabel}${provider.name} issue poll failed (label ${watchLabel})${suffix}`;
|
|
164
|
+
process.stderr.write(`${dim(why)}\n`);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (poll.count > 0) {
|
|
168
|
+
allIdle = false;
|
|
169
|
+
wasIdle = false;
|
|
170
|
+
process.stderr.write(`${dim(`${sLabel}${poll.count} open issue(s) labelled ${watchLabel} — running loop`)}\n`);
|
|
171
|
+
// Confine this loop's `gh` commands (render-time tags + the spawned
|
|
172
|
+
// agent) to the selected scope by pinning OTTO_GITHUB_REPO before the
|
|
173
|
+
// run; single-target left it set in run-bin, this covers multi-target.
|
|
174
|
+
if (sRepo)
|
|
175
|
+
process.env.OTTO_GITHUB_REPO = sRepo;
|
|
176
|
+
const remaining = budgetUsd != null ? budgetUsd - cumulativeCost : undefined;
|
|
177
|
+
const outcome = await runLoop({
|
|
178
|
+
stages,
|
|
179
|
+
inputs: "",
|
|
180
|
+
iterations,
|
|
181
|
+
workspaceDir,
|
|
182
|
+
packageDir,
|
|
183
|
+
budgetUsd: remaining,
|
|
184
|
+
cooldownMs,
|
|
185
|
+
maxRetries,
|
|
186
|
+
reviewLenses,
|
|
187
|
+
noKeepAlive: true,
|
|
188
|
+
signal: daemonAbort.signal,
|
|
189
|
+
bin,
|
|
190
|
+
cliVersion: opts.cliVersion,
|
|
191
|
+
});
|
|
192
|
+
cumulativeCost += outcome.costUsd;
|
|
193
|
+
process.stderr.write(`${dim(`${sLabel}watch run done — cumulative $${cumulativeCost.toFixed(2)}`)}\n`);
|
|
194
|
+
ran = true;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
142
197
|
}
|
|
143
|
-
|
|
198
|
+
if (!ran && allIdle && !wasIdle) {
|
|
144
199
|
// First empty poll after activity — announce idle once, then stay quiet
|
|
145
|
-
// until
|
|
200
|
+
// until a queue becomes non-empty (or a poll fails) and idles again.
|
|
146
201
|
wasIdle = true;
|
|
147
202
|
process.stderr.write(`${dim(`no open issues labelled ${watchLabel} — idle, next poll in ${watchIntervalSec}s`)}\n`);
|
|
148
203
|
}
|
package/dist/watch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAiB,MAAM,gBAAgB,CAAC;AACxD,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,GAGf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EACL,IAAI,EACJ,GAAG,EACH,QAAQ,EACR,OAAO,EACP,MAAM,EACN,OAAO,EACP,SAAS,GACV,MAAM,oBAAoB,CAAC;AAa5B
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Per-mode human-acceptance prompts for the Otto quality report. Included ONCE by
|
|
3
|
+
quality-report.md, so every run mode inherits the same set through the single
|
|
4
|
+
existing contract include — never re-describe these per template (the same
|
|
5
|
+
drift-proofing as the contract itself). The generic Human Acceptance Checklist
|
|
6
|
+
stays; these add the task-fulfillment questions specific to the run's Mode.
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
**Mode-specific acceptance prompts.** Beyond the generic checklist, fold the
|
|
10
|
+
prompts for **your Mode** (from Task Source) into the Human Acceptance Checklist.
|
|
11
|
+
Answer each with cited evidence, or mark it an explicit gap — never drop one
|
|
12
|
+
silently.
|
|
13
|
+
|
|
14
|
+
### afk — plan/PRD completion
|
|
15
|
+
|
|
16
|
+
- [ ] Every PRD acceptance criterion is met or explicitly deferred.
|
|
17
|
+
- [ ] All plan tasks are checked off, or the unchecked ones are recorded as gaps.
|
|
18
|
+
- [ ] The product behavior is demonstrable, not just coded.
|
|
19
|
+
|
|
20
|
+
### ghafk — GitHub issue burn-down
|
|
21
|
+
|
|
22
|
+
- [ ] The change resolves what the issue actually asked, not an adjacent reading.
|
|
23
|
+
- [ ] Work is scoped to this issue; unrelated changes are called out.
|
|
24
|
+
- [ ] The issue will close cleanly when the PR merges (PR/issue links cited).
|
|
25
|
+
|
|
26
|
+
### linear-afk — Linear issue burn-down
|
|
27
|
+
|
|
28
|
+
- [ ] The change resolves the Linear issue's stated intent.
|
|
29
|
+
- [ ] The comment cites the branch/PR and the explicit human next step.
|
|
30
|
+
- [ ] The issue is left in the correct state (OPEN for PR-based repos).
|
|
31
|
+
|
|
32
|
+
### apply-review — external review repair
|
|
33
|
+
|
|
34
|
+
- [ ] Every CONFIRMED finding was actually fixed, not just acknowledged.
|
|
35
|
+
- [ ] The fixes introduced no regression (suites re-run green).
|
|
36
|
+
- [ ] Deferred / rejected findings are recorded with a reason.
|
|
37
|
+
|
|
38
|
+
### verify — read-only verification
|
|
39
|
+
|
|
40
|
+
- [ ] Each task's claimed status matches committed reality (evidence cited).
|
|
41
|
+
- [ ] Suite results are current, not stale.
|
|
42
|
+
- [ ] Gaps and deferrals are honest, not optimistic.
|
|
@@ -28,7 +28,17 @@
|
|
|
28
28
|
|
|
29
29
|
`<review-doc>` names a code-review document (a file path). `Read` it. It contains findings, usually with severities. Your job is to fix the actionable ones — ONE finding per iteration — and track the rest.
|
|
30
30
|
|
|
31
|
-
When every actionable finding has been addressed (fixed, or already fixed in git, or recorded as a follow-up), output `<promise>NO MORE TASKS</promise>`.
|
|
31
|
+
When every actionable finding has been addressed (fixed, or already fixed in git, or recorded as a follow-up), produce the completion report (see COMPLETION REPORT below), then output `<promise>NO MORE TASKS</promise>`.
|
|
32
|
+
|
|
33
|
+
# TASK KEY
|
|
34
|
+
|
|
35
|
+
Per-task artifacts (spec, plan, follow-ups) live together under
|
|
36
|
+
`.otto/tasks/<task-key>/`, so everything Otto knows about a task is in one place.
|
|
37
|
+
Resolve the task key for THIS run from the current git branch: run
|
|
38
|
+
`git branch --show-current` and take the **final path segment** (the part after the
|
|
39
|
+
last `/`) — e.g. `otto/issue-21` → `issue-21`, `feat/gh-acme-web-14` →
|
|
40
|
+
`gh-acme-web-14`. If the branch name has no `/`, use it whole. Use this key in the
|
|
41
|
+
follow-ups path below.
|
|
32
42
|
|
|
33
43
|
# TRIAGE
|
|
34
44
|
|
|
@@ -56,7 +66,9 @@ Pick the highest-value actionable finding not yet addressed. Implement the fix.
|
|
|
56
66
|
|
|
57
67
|
# RECORD FOLLOW-UPS
|
|
58
68
|
|
|
59
|
-
For each Deferred / follow-up finding, append a terse entry to `./.otto/
|
|
69
|
+
For each Deferred / follow-up finding, append a terse entry to the **task-local** follow-ups file `./.otto/tasks/<task-key>/followups.md` (create it and its parent dir lazily), using the task key resolved above. Use a dated `##` heading for this review, then one bullet per finding with its severity and why it is deferred. Keeping follow-ups beside the task's spec/plan means everything Otto knows about a task is in one place, while staying globally summarizable by globbing `.otto/tasks/*/followups.md`.
|
|
70
|
+
|
|
71
|
+
Read the task-local file first (it may already hold this task's prior deferrals). The legacy global `./.otto/review-followups.md` is still READ as a fallback for older runs (see `<existing-followups>`) for one release, but do NOT append new entries there. This file is git-tracked — commit it WITH the related fix (do not make a separate commit just for it).
|
|
60
72
|
|
|
61
73
|
# COMMIT
|
|
62
74
|
|
|
@@ -66,6 +78,24 @@ Make a single `git commit -am` with a short message:
|
|
|
66
78
|
- Body: which finding (and its review section), key decision, and a one-line note of any follow-ups recorded.
|
|
67
79
|
- No file lists, no `Co-Authored-By`.
|
|
68
80
|
|
|
81
|
+
# COMPLETION REPORT
|
|
82
|
+
|
|
83
|
+
Only on the final iteration — when every actionable finding has been addressed
|
|
84
|
+
and you are about to output the sentinel — hand the maintainer one readable
|
|
85
|
+
summary of the whole review-fix round. Do NOT emit it per-iteration. Map the
|
|
86
|
+
contract below onto this round:
|
|
87
|
+
|
|
88
|
+
- **What Changed / Evidence:** the findings you CONFIRMED and fixed, each with
|
|
89
|
+
its `fix(review):` commit SHA and the review section it came from; the
|
|
90
|
+
feedback loops you ran (tests / typecheck) and their result.
|
|
91
|
+
- **Gaps And Follow-Ups:** findings you DEFERRED to
|
|
92
|
+
`./.otto/tasks/<task-key>/followups.md` (with why), and any REJECTED / won't-fix
|
|
93
|
+
findings with their reason. Verdict
|
|
94
|
+
defaults to **Needs human review** when any actionable finding was left
|
|
95
|
+
unfixed.
|
|
96
|
+
|
|
97
|
+
@include:quality-report.md
|
|
98
|
+
|
|
69
99
|
# FINAL RULES
|
|
70
100
|
|
|
71
101
|
ONLY ADDRESS A SINGLE FINDING per iteration.
|
package/templates/ghafk-issue.md
CHANGED
|
@@ -12,12 +12,14 @@
|
|
|
12
12
|
|
|
13
13
|
<issue>
|
|
14
14
|
|
|
15
|
-
!?`gh issue view "$OTTO_ISSUE" --json number,title,state|||Issue not found`
|
|
15
|
+
!?`gh issue view "$OTTO_ISSUE" ${OTTO_GITHUB_REPO:+--repo "$OTTO_GITHUB_REPO"} --json number,title,state|||Issue not found`
|
|
16
16
|
|
|
17
|
-
Full issue body + comments spilled to: @spill?:issue.json=`gh issue view "$OTTO_ISSUE" --json number,title,body,comments,state|||[]`
|
|
17
|
+
Full issue body + comments spilled to: @spill?:issue.json=`gh issue view "$OTTO_ISSUE" ${OTTO_GITHUB_REPO:+--repo "$OTTO_GITHUB_REPO"} --json number,title,body,comments,state|||[]`
|
|
18
18
|
|
|
19
19
|
`Read` that file to get the full body and comments before acting on the issue.
|
|
20
20
|
|
|
21
|
+
If `$OTTO_GITHUB_REPO` is set (run scoped with `--repo owner/name`), pass `--repo "$OTTO_GITHUB_REPO"` to every `gh` command you run yourself (issue comment, pr create) so completion targets that repo. If unset, `gh` uses the workspace's own repo.
|
|
22
|
+
|
|
21
23
|
</issue>
|
|
22
24
|
|
|
23
25
|
# THE TASK
|
package/templates/ghafk.md
CHANGED
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
<issues-summary>
|
|
16
16
|
|
|
17
|
-
`gh issue list --state open --limit 50 --json number,title,labels`
|
|
17
|
+
`gh issue list ${OTTO_GITHUB_REPO:+--repo "$OTTO_GITHUB_REPO"} --state open --limit 50 --json number,title,labels`
|
|
18
18
|
|
|
19
19
|
</issues-summary>
|
|
20
20
|
|
|
21
21
|
<issues-full-file>
|
|
22
22
|
|
|
23
|
-
Full issue bodies + comments spilled to: @spill?:issues.json=`gh issue list --state open --limit 50 --json number,title,body,labels,comments|||[]`
|
|
23
|
+
Full issue bodies + comments spilled to: @spill?:issues.json=`gh issue list ${OTTO_GITHUB_REPO:+--repo "$OTTO_GITHUB_REPO"} --state open --limit 50 --json number,title,body,labels,comments|||[]`
|
|
24
24
|
|
|
25
25
|
Read that file with `Read` (use `offset`/`limit` if it is large) to get bodies and comments before picking a task. The `<issues-summary>` block above is the lean index for triage.
|
|
26
26
|
|
|
@@ -59,6 +59,15 @@ Committing the code is NOT necessarily the end of the run. How work "ships" depe
|
|
|
59
59
|
|
|
60
60
|
When unsure which applies, prefer leaving the issue OPEN and surfacing the branch — never close an issue whose work has not landed on the default branch.
|
|
61
61
|
|
|
62
|
+
## Quality report (completion handoff)
|
|
63
|
+
|
|
64
|
+
Whatever the completion surface, hand the maintainer **one readable Otto quality report** so they can accept, reject, or request follow-up without replaying the run log — green tests alone are not the handoff. Emit it into the completion surface and cite concrete links/SHAs:
|
|
65
|
+
|
|
66
|
+
- **PR-based repo:** put the report in the **PR description** (create or refresh it there) and reference it from any issue comment. Cite the PR URL, the issue link, and the commit SHAs on this branch.
|
|
67
|
+
- **Commit-to-branch repo:** put the report in the **issue comment**, citing the branch and the commit SHAs.
|
|
68
|
+
|
|
69
|
+
@include:quality-report.md
|
|
70
|
+
|
|
62
71
|
# LEARNINGS
|
|
63
72
|
|
|
64
73
|
The repo's accumulated learnings are in the `<learnings>` block — durable, reusable knowledge from prior iterations (conventions, gotchas, decisions and their why, dead ends). Consult it during EXPLORATION and IMPLEMENTATION so you don't relearn what's known or repeat a dead end.
|
package/templates/ghprompt.md
CHANGED
|
@@ -7,6 +7,8 @@ Two views of open GitHub issues are provided at the start of context:
|
|
|
7
7
|
|
|
8
8
|
You will work on the AFK issues only, not the HITL ones. Label filtering uses the `labels` field in the summary.
|
|
9
9
|
|
|
10
|
+
**Repo scope.** If the `$OTTO_GITHUB_REPO` environment variable is set (the run was scoped with `--repo owner/name`), the issue list above is already confined to that repo — work only on those issues, and pass `--repo "$OTTO_GITHUB_REPO"` to every `gh` command you run yourself (e.g. `gh issue comment`, `gh pr create`) so completion targets the same repo. If it is unset, `gh` uses the workspace's own repo as before.
|
|
11
|
+
|
|
10
12
|
You've also been passed a file containing the last few commits. Review these to understand what work has been done.
|
|
11
13
|
|
|
12
14
|
If all AFK tasks are complete, output <promise>NO MORE TASKS</promise>.
|
|
@@ -15,3 +15,13 @@ every Linear write — never raw GraphQL, and never `gh`:
|
|
|
15
15
|
the issue for a human to move.
|
|
16
16
|
|
|
17
17
|
When unsure which convention applies, comment and leave the issue OPEN.
|
|
18
|
+
|
|
19
|
+
## Quality report placement (Linear)
|
|
20
|
+
|
|
21
|
+
The FINISHING handoff above already defines the **Otto quality report** shape —
|
|
22
|
+
do not re-describe it here. On Linear the **comment body IS that report**: write
|
|
23
|
+
the full quality report (verdict, task source, what changed, evidence, human
|
|
24
|
+
acceptance checklist, gaps/follow-ups) to a file and post it with
|
|
25
|
+
`otto-linear comment <ref> --body-file <path>`, citing the branch/PR, the commit
|
|
26
|
+
SHAs, the checks run, and the explicit human next step. For this PR-based repo
|
|
27
|
+
that comment is the handoff surface — the issue stays OPEN until the PR merges.
|
|
@@ -9,7 +9,9 @@ Two views of open Linear issues are provided at the start of context:
|
|
|
9
9
|
large) once you have picked an issue you want to act on.
|
|
10
10
|
|
|
11
11
|
Issue selection is already filtered to open Linear issues carrying the `otto`
|
|
12
|
-
label (override via `OTTO_LINEAR_LABEL`, narrow to a team via `OTTO_LINEAR_TEAM
|
|
12
|
+
label (override via `OTTO_LINEAR_LABEL`, narrow to a team via `OTTO_LINEAR_TEAM`,
|
|
13
|
+
and narrow to a project via `OTTO_LINEAR_PROJECT`). Work only on the issues the
|
|
14
|
+
list shows — they are already confined to the configured team/project scope.
|
|
13
15
|
|
|
14
16
|
You've also been passed a file containing the last few commits. Review these to
|
|
15
17
|
understand what work has been done.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The Otto quality report contract. ONE readable verification artifact, reused
|
|
3
|
+
across every run mode (verify / afk / ghafk / linear-afk / apply-review) by
|
|
4
|
+
@include — never re-describe the shape per template, or the provider workflows
|
|
5
|
+
drift apart. Readable first; every claim cites concrete proof.
|
|
6
|
+
-->
|
|
7
|
+
|
|
8
|
+
Produce an **Otto quality report** with the exact section headings below. Rules:
|
|
9
|
+
|
|
10
|
+
- **Readable first.** Keep it short enough to review in a couple of minutes — a
|
|
11
|
+
maintainer should not have to replay the run log. Specific beats exhaustive.
|
|
12
|
+
- **Cite evidence for every claim.** A `file:line`, a commit SHA, a command +
|
|
13
|
+
its result, a report section, or an issue/PR link — never a vague assertion.
|
|
14
|
+
- **Tests are evidence, not the verdict.** Green checks go in the Evidence
|
|
15
|
+
section; they do not by themselves make the verdict Accepted.
|
|
16
|
+
- **Pick one honest verdict. When evidence is thin, scope is uncertain, or you
|
|
17
|
+
are unsure, choose _Needs human review_ — never self-declare _Accepted_.**
|
|
18
|
+
Model self-evaluation does not replace human review.
|
|
19
|
+
|
|
20
|
+
```markdown
|
|
21
|
+
# Otto quality report
|
|
22
|
+
|
|
23
|
+
## Verdict
|
|
24
|
+
|
|
25
|
+
One of — **Accepted** · **Accepted with follow-ups** · **Needs human review** · **Rejected**
|
|
26
|
+
(when uncertain, choose **Needs human review**)
|
|
27
|
+
|
|
28
|
+
## Task Source
|
|
29
|
+
|
|
30
|
+
- Mode: <afk | ghafk | linear-afk | apply-review | verify>
|
|
31
|
+
- Source: <plan/PRD path, GitHub issue #, or Linear ref>
|
|
32
|
+
- Issue or plan: <link or path>
|
|
33
|
+
|
|
34
|
+
## What Changed
|
|
35
|
+
|
|
36
|
+
- Summary: <one or two sentences — what was actually done>
|
|
37
|
+
- Commits: <SHAs on this branch>
|
|
38
|
+
- Files: <paths touched>
|
|
39
|
+
|
|
40
|
+
## Evidence
|
|
41
|
+
|
|
42
|
+
- Implementation evidence: <file:line or commit proving each claim>
|
|
43
|
+
- Test/typecheck evidence: <commands run + pass/fail counts>
|
|
44
|
+
- Manual or acceptance evidence: <what was observed, or "none">
|
|
45
|
+
|
|
46
|
+
## Human Acceptance Checklist
|
|
47
|
+
|
|
48
|
+
- [ ] Solves the stated problem.
|
|
49
|
+
- [ ] Behavior is observable or explained.
|
|
50
|
+
- [ ] Scope is appropriate.
|
|
51
|
+
- [ ] Docs/examples are updated when needed.
|
|
52
|
+
- [ ] Risks and assumptions are clear.
|
|
53
|
+
|
|
54
|
+
## Gaps And Follow-Ups
|
|
55
|
+
|
|
56
|
+
- Gap: <known gap that remains, or "none">
|
|
57
|
+
- Deferred: <intentionally not done in this run + why, or "none">
|
|
58
|
+
- Recommended next action: <what a maintainer should do next>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Human verdict trail
|
|
62
|
+
|
|
63
|
+
Prior **human** verdicts on past Otto runs (most recent last) — consult them so a
|
|
64
|
+
recurring reason ("scope creep", "thin evidence") informs *this* run's Verdict
|
|
65
|
+
and *Recommended next action* before you commit to one:
|
|
66
|
+
|
|
67
|
+
<verdict-trail>
|
|
68
|
+
|
|
69
|
+
!?`cat ./.otto/verdicts.md|||_No human verdicts recorded yet._`
|
|
70
|
+
|
|
71
|
+
</verdict-trail>
|
|
72
|
+
|
|
73
|
+
**Maintainer:** after reviewing this report, append your verdict to
|
|
74
|
+
`./.otto/verdicts.md` (create it lazily) — a dated `##` heading plus one line:
|
|
75
|
+
the human verdict (**Accepted** · **Accepted with follow-ups** · **Rejected** ·
|
|
76
|
+
**Needs investigation**) and *why* (what was accepted with caveats, or the
|
|
77
|
+
concrete reason it was rejected). The file is git-tracked; it feeds the existing
|
|
78
|
+
learning loop, so future runs see what was accepted or rejected and why.
|
|
79
|
+
|
|
80
|
+
@include:acceptance-prompts.md
|
package/templates/review-lens.md
CHANGED
|
@@ -27,6 +27,7 @@ You review the most recent commit (HEAD) through ONE lens only: **{{ LENS }}**.
|
|
|
27
27
|
- `correctness` — bugs, regressions, broken logic, unhandled edge cases.
|
|
28
28
|
- `security` — input validation, secrets, injection, auth bypass.
|
|
29
29
|
- `tests` — coverage gaps for the changed code; missing/weak assertions.
|
|
30
|
+
- `task-fit` — did the change solve the **right problem**? Does it map back to the source plan/issue, stay in scope (no unrequested extras, no missed sub-task), and leave a reviewer-useful trail (clear commit, evidence, surfaced gaps)? Flag scope drift, unaddressed acceptance criteria, and work that is mechanically correct but doesn't fulfil the task.
|
|
30
31
|
|
|
31
32
|
If `<head>` shows `(no commits)`, output `<lens>SKIP</lens>` and stop.
|
|
32
33
|
|
package/templates/superpowers.md
CHANGED
|
@@ -10,29 +10,41 @@ If the `superpowers:brainstorming`, `superpowers:writing-plans`, and
|
|
|
10
10
|
fuller guidance. If they are not installed, follow the inline protocol below —
|
|
11
11
|
it is self-contained.
|
|
12
12
|
|
|
13
|
-
## 0. Resolve the task key
|
|
13
|
+
## 0. Resolve the task key and artifact paths
|
|
14
14
|
|
|
15
15
|
- GitHub issue run → task-key = `issue-<issue number>`.
|
|
16
16
|
- Plan/PRD run → task-key = a stable slug from the primary plan-file basename
|
|
17
17
|
(e.g. `docs/plans/foo.md` → `foo`). If inputs are inline text, use a short
|
|
18
18
|
kebab-case of the task title.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
Per-task artifacts live together under one task directory, so everything Otto
|
|
21
|
+
knows about a task is in one place:
|
|
22
|
+
|
|
23
|
+
- Task dir: `.otto/tasks/<task-key>/`
|
|
24
|
+
- Spec path: `.otto/tasks/<task-key>/spec.md`
|
|
25
|
+
- Plan path: `.otto/tasks/<task-key>/plan.md`
|
|
26
|
+
|
|
27
|
+
Always **WRITE** the new task-grouped layout. The legacy flat layout
|
|
28
|
+
(`.otto/specs/<task-key>-design.md` + `.otto/plans/<task-key>.md`) is still
|
|
29
|
+
**READ** as a fallback (see the CLARITY GATE), so a task created before this
|
|
30
|
+
layout continues without re-brainstorming.
|
|
22
31
|
|
|
23
32
|
## 1. CLARITY GATE
|
|
24
33
|
|
|
25
|
-
Check whether
|
|
34
|
+
Check whether the spec already exists — look under the new task dir
|
|
35
|
+
`.otto/tasks/<task-key>/spec.md` first, then fall back to the legacy flat path
|
|
36
|
+
`.otto/specs/<task-key>-design.md`.
|
|
26
37
|
|
|
27
|
-
- **Spec exists** → skip brainstorming. Read the spec and
|
|
28
|
-
`.otto/
|
|
38
|
+
- **Spec exists** → skip brainstorming. Read the spec and its matching plan
|
|
39
|
+
(`.otto/tasks/<task-key>/plan.md`, or legacy `.otto/plans/<task-key>.md`),
|
|
40
|
+
pick the next unchecked task, and go to
|
|
29
41
|
TDD IMPLEMENT (section 3). If every plan task is checked AND the feedback
|
|
30
42
|
loops pass, output `<promise>NO MORE TASKS</promise>`.
|
|
31
43
|
- **No spec** → judge the input's clarity. It is UNCLEAR if any of: no
|
|
32
44
|
plan/PRD provided; a vague directive ("make it better"); missing acceptance
|
|
33
45
|
criteria; multiple plausible interpretations; internal contradictions.
|
|
34
46
|
- Clear enough → go straight to TDD IMPLEMENT (section 3). Optionally jot a
|
|
35
|
-
short plan to `.otto/
|
|
47
|
+
short plan to `.otto/tasks/<task-key>/plan.md` first.
|
|
36
48
|
- Unclear → AUTONOMOUS BRAINSTORM (section 2).
|
|
37
49
|
|
|
38
50
|
## 2. AUTONOMOUS BRAINSTORM (no human in the loop)
|
|
@@ -43,10 +55,10 @@ Play both sides of a brainstorming session:
|
|
|
43
55
|
scope, constraints, success criteria, edge cases).
|
|
44
56
|
2. Answer each one yourself with the most reasonable default given the repo's
|
|
45
57
|
existing patterns. Prefer the simplest viable option (YAGNI).
|
|
46
|
-
3. Write `.otto/
|
|
58
|
+
3. Write `.otto/tasks/<task-key>/spec.md` containing: Problem, Approach, an
|
|
47
59
|
**Assumptions** section listing each `question → chosen answer → rationale`,
|
|
48
60
|
and Testing notes.
|
|
49
|
-
4. Write `.otto/
|
|
61
|
+
4. Write `.otto/tasks/<task-key>/plan.md` as an ordered checklist of bite-sized,
|
|
50
62
|
testable tasks (one `- [ ]` per task).
|
|
51
63
|
5. Do NOT wait for approval — the written assumptions are the record.
|
|
52
64
|
|
|
@@ -63,7 +75,8 @@ Implement exactly one task, test-first:
|
|
|
63
75
|
2. Run it; confirm it fails for the right reason.
|
|
64
76
|
3. Write the minimal code to make it pass.
|
|
65
77
|
4. Run the feedback loops described below until green.
|
|
66
|
-
5. Update `.otto/
|
|
78
|
+
5. Update the plan you read (`.otto/tasks/<task-key>/plan.md`, or its legacy
|
|
79
|
+
fallback `.otto/plans/<task-key>.md`): check off the task. If a new durable,
|
|
67
80
|
reusable learning emerged, append it to `.otto/LEARNINGS.md`.
|
|
68
81
|
|
|
69
82
|
Commit the code, the updated spec/plan, and LEARNINGS together in the single
|
package/templates/verify.md
CHANGED
|
@@ -45,30 +45,26 @@ Put every task in exactly one bucket:
|
|
|
45
45
|
|
|
46
46
|
# REPORT
|
|
47
47
|
|
|
48
|
-
Write your report to `.otto-tmp/verify-report.md` using the `Write` tool (this path is gitignored scratch — it is the one write you may make).
|
|
48
|
+
Write your report to `.otto-tmp/verify-report.md` using the `Write` tool (this path is gitignored scratch — it is the one write you may make). Use the Otto quality report contract below: fold the RECONCILE/CLASSIFY results into it — DONE tasks (with their `file:line`/SHA evidence) into **What Changed** + **Evidence**, the suite pass/fail counts into the Test/typecheck evidence line, and GAP/DEFERRED tasks into **Gaps And Follow-Ups**.
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
# Verify report
|
|
50
|
+
@include:quality-report.md
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
# CROSS-RUN QUALITY SUMMARY (READ-ONLY)
|
|
54
53
|
|
|
55
|
-
|
|
54
|
+
Beyond *this* run, give the maintainer a quality rollup **across** runs so they can
|
|
55
|
+
spot recurring output-quality failures without reading every NDJSON log. `Read`
|
|
56
|
+
`./.otto/verdicts.md` (the git-tracked human-verdict trail). If it is absent, skip
|
|
57
|
+
this section. Otherwise append a short `## Cross-Run Quality Summary` block to the
|
|
58
|
+
same report file (`.otto-tmp/verify-report.md`) with:
|
|
56
59
|
|
|
57
|
-
|
|
60
|
+
- **Completions:** how many runs recorded a verdict, and the tally per verdict
|
|
61
|
+
(Accepted / Accepted with follow-ups / Rejected / Needs investigation).
|
|
62
|
+
- **Common causes:** recurring reasons behind rejections or follow-ups (e.g.
|
|
63
|
+
"scope creep", "thin evidence"), most frequent first.
|
|
64
|
+
- **Outstanding gaps & deferred work:** gaps and deferred items still open across
|
|
65
|
+
runs, so a maintainer can turn them into follow-up issues.
|
|
58
66
|
|
|
59
|
-
|
|
67
|
+
Keep it to a few lines and cite the trail entries you counted. This is read-only —
|
|
68
|
+
do not edit or commit the trail.
|
|
60
69
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
- <task> — <what is missing>
|
|
64
|
-
|
|
65
|
-
## Deferred
|
|
66
|
-
|
|
67
|
-
- <task> — <why>
|
|
68
|
-
|
|
69
|
-
## Suites
|
|
70
|
-
|
|
71
|
-
- <command> — <pass/fail counts>
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Also print the Verdict + section counts to your final message. Do not commit.
|
|
70
|
+
Also print the Verdict + a one-line tally of done/gap/deferred to your final message. Do not commit.
|