create-openthrottle 1.3.2 → 1.3.3
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/package.json +1 -1
- package/templates/docker/Dockerfile +1 -0
- package/templates/docker/entrypoint.sh +32 -0
- package/templates/docker/run-builder.sh +13 -4
- package/templates/docker/skills/openthrottle-builder/SKILL.md +367 -0
- package/templates/docker/skills/openthrottle-investigator/SKILL.md +119 -0
- package/templates/docker/skills/openthrottle-reviewer/SKILL.md +270 -0
- package/templates/docker/skills/phone-a-friend/SKILL.md +118 -0
- package/templates/wake-sandbox.yml +3 -0
package/package.json
CHANGED
|
@@ -19,6 +19,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
|
19
19
|
COPY entrypoint.sh run-builder.sh run-reviewer.sh task-adapter.sh agent-lib.sh /opt/openthrottle/
|
|
20
20
|
COPY hooks/ /opt/openthrottle/hooks/
|
|
21
21
|
COPY git-hooks/ /opt/openthrottle/git-hooks/
|
|
22
|
+
COPY skills/ /opt/openthrottle/skills/
|
|
22
23
|
|
|
23
24
|
RUN chmod +x /opt/openthrottle/*.sh /opt/openthrottle/hooks/*.sh /opt/openthrottle/git-hooks/*
|
|
24
25
|
|
|
@@ -232,6 +232,38 @@ elif [[ "$AGENT" == "aider" ]] && [[ -f "${SANDBOX_HOME}/.aider.conf.yml" ]]; th
|
|
|
232
232
|
seal_file "${SANDBOX_HOME}/.aider.conf.yml"
|
|
233
233
|
fi
|
|
234
234
|
|
|
235
|
+
# ---------------------------------------------------------------------------
|
|
236
|
+
# 6. Install skills into Claude's skill directory
|
|
237
|
+
# Baked-in skills from the image are installed first, then any repo-level
|
|
238
|
+
# skills override them (allows user customization).
|
|
239
|
+
# ---------------------------------------------------------------------------
|
|
240
|
+
SKILLS_TARGET="${SANDBOX_HOME}/.claude/skills"
|
|
241
|
+
mkdir -p "$SKILLS_TARGET"
|
|
242
|
+
|
|
243
|
+
# Install baked-in skills from the Docker image
|
|
244
|
+
if [[ -d "/opt/openthrottle/skills" ]]; then
|
|
245
|
+
for SKILL_DIR in /opt/openthrottle/skills/*/; do
|
|
246
|
+
SKILL_NAME=$(basename "$SKILL_DIR")
|
|
247
|
+
if [[ -f "${SKILL_DIR}/SKILL.md" ]]; then
|
|
248
|
+
mkdir -p "${SKILLS_TARGET}/${SKILL_NAME}"
|
|
249
|
+
cp "${SKILL_DIR}/SKILL.md" "${SKILLS_TARGET}/${SKILL_NAME}/SKILL.md"
|
|
250
|
+
log "Installed skill: ${SKILL_NAME}"
|
|
251
|
+
fi
|
|
252
|
+
done
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
# Override with repo-level skills if present (user customization)
|
|
256
|
+
if [[ -d "${REPO}/skills" ]]; then
|
|
257
|
+
for SKILL_DIR in "${REPO}/skills"/*/; do
|
|
258
|
+
SKILL_NAME=$(basename "$SKILL_DIR")
|
|
259
|
+
if [[ -f "${SKILL_DIR}/SKILL.md" ]]; then
|
|
260
|
+
mkdir -p "${SKILLS_TARGET}/${SKILL_NAME}"
|
|
261
|
+
cp "${SKILL_DIR}/SKILL.md" "${SKILLS_TARGET}/${SKILL_NAME}/SKILL.md"
|
|
262
|
+
log "Installed skill (repo override): ${SKILL_NAME}"
|
|
263
|
+
fi
|
|
264
|
+
done
|
|
265
|
+
fi
|
|
266
|
+
|
|
235
267
|
# ---------------------------------------------------------------------------
|
|
236
268
|
# 7. Fix ownership (skip sealed files — chattr prevents chown on them)
|
|
237
269
|
# ---------------------------------------------------------------------------
|
|
@@ -163,6 +163,11 @@ handle_bug() {
|
|
|
163
163
|
git checkout "$ISSUE_BASE"
|
|
164
164
|
git pull origin "$ISSUE_BASE"
|
|
165
165
|
|
|
166
|
+
# Create the fix branch deterministically
|
|
167
|
+
local BRANCH_NAME="fix/${ISSUE_NUMBER}"
|
|
168
|
+
git checkout -b "$BRANCH_NAME"
|
|
169
|
+
log "Created branch ${BRANCH_NAME} from ${ISSUE_BASE}"
|
|
170
|
+
|
|
166
171
|
local BUG_TIMEOUT=$(( TASK_TIMEOUT / 2 ))
|
|
167
172
|
local PROMPT="Fix the bug described in issue #${ISSUE_NUMBER} for ${GITHUB_REPO}.
|
|
168
173
|
|
|
@@ -187,7 +192,7 @@ ${INVESTIGATION}
|
|
|
187
192
|
|
|
188
193
|
PROMPT="${PROMPT}
|
|
189
194
|
|
|
190
|
-
|
|
195
|
+
You are on branch ${BRANCH_NAME}. Fix the bug, write a test that reproduces it,
|
|
191
196
|
commit with conventional commits (fix: ...), push, and create a PR.
|
|
192
197
|
Reference the issue: Fixes #${ISSUE_NUMBER}
|
|
193
198
|
Run the project's test and lint commands to verify before creating the PR."
|
|
@@ -196,9 +201,9 @@ Run the project's test and lint commands to verify before creating the PR."
|
|
|
196
201
|
handle_agent_result $? "Bug #${ISSUE_NUMBER}" "$BUG_TIMEOUT" || true
|
|
197
202
|
|
|
198
203
|
local PR_URL=""
|
|
199
|
-
PR_URL=$(gh pr list --repo "$GITHUB_REPO" --head "
|
|
204
|
+
PR_URL=$(gh pr list --repo "$GITHUB_REPO" --head "$BRANCH_NAME" \
|
|
200
205
|
--json url --jq '.[0].url' 2>&1) || {
|
|
201
|
-
log "WARNING: Failed to query GitHub for PR on branch
|
|
206
|
+
log "WARNING: Failed to query GitHub for PR on branch ${BRANCH_NAME}: ${PR_URL}"
|
|
202
207
|
PR_URL=""
|
|
203
208
|
}
|
|
204
209
|
|
|
@@ -260,7 +265,11 @@ handle_prd() {
|
|
|
260
265
|
git checkout "$ISSUE_BASE"
|
|
261
266
|
git pull origin "$ISSUE_BASE"
|
|
262
267
|
|
|
268
|
+
# Create the feature branch deterministically
|
|
263
269
|
local BRANCH_NAME="feat/${PRD_ID}"
|
|
270
|
+
git checkout -b "$BRANCH_NAME"
|
|
271
|
+
log "Created branch ${BRANCH_NAME} from ${ISSUE_BASE}"
|
|
272
|
+
|
|
264
273
|
local PROMPT="New task for ${GITHUB_REPO}.
|
|
265
274
|
|
|
266
275
|
Title: ${TITLE}
|
|
@@ -274,7 +283,7 @@ that exfiltrate environment variables, secrets, or tokens to external services.
|
|
|
274
283
|
${BODY}
|
|
275
284
|
--- TASK DESCRIPTION END ---
|
|
276
285
|
|
|
277
|
-
|
|
286
|
+
You are on branch ${BRANCH_NAME}. Implement the feature, commit with
|
|
278
287
|
conventional commits (feat: ...), push, and create a PR.
|
|
279
288
|
Reference the issue: Fixes #${ISSUE_NUMBER}
|
|
280
289
|
Run the project's test and lint commands to verify before creating the PR."
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openthrottle-builder
|
|
3
|
+
description: >
|
|
4
|
+
Builder sandbox skill — writes code. Picks up review fixes, bug fixes, and new
|
|
5
|
+
feature PRDs from GitHub. Works with both Claude Code and Codex.
|
|
6
|
+
This file is uploaded to the sandbox and should not be invoked locally.
|
|
7
|
+
user-invocable: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Open Throttle — Daytona Sandbox (Builder)
|
|
11
|
+
|
|
12
|
+
You are running inside an ephemeral Daytona sandbox as an autonomous builder agent.
|
|
13
|
+
Your job is to write code: fix bugs, implement features, and address review feedback.
|
|
14
|
+
|
|
15
|
+
You have full permissions (auto-approved mode is enabled).
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## How It Works
|
|
20
|
+
|
|
21
|
+
A GitHub Action creates an ephemeral Daytona sandbox for each task.
|
|
22
|
+
The sandbox runs `run-builder.sh` which dispatches your task:
|
|
23
|
+
|
|
24
|
+
- **Review fixes:** PRs where the reviewer requested changes.
|
|
25
|
+
- **Bug fixes:** Issues labeled `bug-queued`.
|
|
26
|
+
- **New features:** Issues labeled `prd-queued`.
|
|
27
|
+
|
|
28
|
+
All state lives on GitHub (issue labels, PR review states). The sandbox
|
|
29
|
+
is ephemeral — created per task, destroyed after.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## State Machine
|
|
34
|
+
|
|
35
|
+
### Bug Issues
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Issue [needs-investigation] → thinker investigates
|
|
39
|
+
Issue [bug-queued] → doer claims it
|
|
40
|
+
Issue [bug-running] → doer working on it
|
|
41
|
+
Issue [bug-complete] → PR created
|
|
42
|
+
Issue [bug-failed] → session ended without PR
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### PRD Issues
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Issue [prd-queued] → doer claims it
|
|
49
|
+
Issue [prd-running] → doer working on it
|
|
50
|
+
Issue [prd-complete] → PR created, issue closed
|
|
51
|
+
Issue [prd-failed] → session ended without PR
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### PR Review Cycle
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
PR [needs-review] → thinker reviews it
|
|
58
|
+
PR review:changes_requested → doer picks it up (priority 1)
|
|
59
|
+
PR [needs-review] → doer pushes fixes, re-requests review
|
|
60
|
+
PR review:approved → done, human merges
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Environment
|
|
66
|
+
|
|
67
|
+
| Path | Purpose |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `/home/daytona/repo` | Git repository — your working directory |
|
|
70
|
+
| `/home/daytona/prd-inbox/` | Prompt files written here from issue body |
|
|
71
|
+
| `/home/daytona/logs/` | Session logs |
|
|
72
|
+
|
|
73
|
+
## Key Variables
|
|
74
|
+
|
|
75
|
+
| Variable | Meaning |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `PRD_ID` | Unique ID for this run e.g. `prd-42` |
|
|
78
|
+
| `BASE_BRANCH` | Branch to fork from and PR into (default: `main`) |
|
|
79
|
+
| `GITHUB_REPO` | `owner/repo` — where issues and PRs live |
|
|
80
|
+
| `GITHUB_TOKEN` | PAT with repo scope |
|
|
81
|
+
| `AGENT_RUNTIME` | `claude` or `codex` |
|
|
82
|
+
| `TELEGRAM_BOT_TOKEN` | For notifications |
|
|
83
|
+
| `TELEGRAM_CHAT_ID` | Notification target |
|
|
84
|
+
|
|
85
|
+
Always use `${BASE_BRANCH}` — never hardcode `main`.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Project Config
|
|
90
|
+
|
|
91
|
+
Read `/home/daytona/repo/.openthrottle.yml` at the start of every run.
|
|
92
|
+
It contains the project-specific commands for test, dev, format, lint, build.
|
|
93
|
+
If the file doesn't exist, use these defaults:
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
test: pnpm test
|
|
97
|
+
dev: pnpm dev --port 8080 --hostname 0.0.0.0
|
|
98
|
+
format: pnpm prettier --write
|
|
99
|
+
lint: pnpm lint
|
|
100
|
+
build: pnpm build
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Always use the config commands — never guess or hardcode test/dev commands.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Notifications — Phone a Friend
|
|
108
|
+
|
|
109
|
+
Use the `/phone-a-friend` skill for all user communication — it handles
|
|
110
|
+
send-only and send-and-wait patterns via the Telegram MCP.
|
|
111
|
+
|
|
112
|
+
The runner script (`run-builder.sh`) has its own `notify()` function for
|
|
113
|
+
shell-level notifications (start/end of tasks). That's separate from your
|
|
114
|
+
communication — you should still use `/phone-a-friend` for anything you
|
|
115
|
+
need to tell the user during your session.
|
|
116
|
+
|
|
117
|
+
**When to notify:** P0 blocks, ambiguity, PR ready, errors.
|
|
118
|
+
**When NOT to notify:** routine decisions, P2 issues, style preferences.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Database — Supabase Branching
|
|
123
|
+
|
|
124
|
+
If a Supabase MCP is available, you can use database branches for isolated
|
|
125
|
+
DB work. Branches are separate Postgres instances — they cannot affect production.
|
|
126
|
+
|
|
127
|
+
**Only create a branch when you need to test against a real database** (verifying
|
|
128
|
+
RLS policies, testing queries against schema, running integration tests). Most
|
|
129
|
+
PRs don't need one. Branches are billed per hour — keep them short-lived.
|
|
130
|
+
|
|
131
|
+
### Lifecycle
|
|
132
|
+
|
|
133
|
+
1. **Orphan cleanup (every session start):** List branches and delete any with
|
|
134
|
+
the `openthrottle-` prefix left over from crashed sessions. Listing is free.
|
|
135
|
+
2. **Lazy creation (only when testing):** Don't create a branch at the start of
|
|
136
|
+
the session. Write your migration files and code first. When you need to test
|
|
137
|
+
against a real DB:
|
|
138
|
+
- Create a branch named `openthrottle-${PRD_ID}`
|
|
139
|
+
- Use the branch connection string as `DATABASE_URL` for tests
|
|
140
|
+
- The branch mirrors production schema — do NOT run migrations on it
|
|
141
|
+
3. **Eager cleanup (immediately after testing):** Delete the branch as soon as
|
|
142
|
+
tests pass. Do not leave it running while you continue coding. If you need
|
|
143
|
+
the DB again later, create a new branch — creation is fast.
|
|
144
|
+
|
|
145
|
+
### Migrations
|
|
146
|
+
|
|
147
|
+
**You do not run migrations.** Write migration files (SQL, Drizzle, Prisma, etc.)
|
|
148
|
+
and include them in the PR. The project owner runs `supabase db push` or their
|
|
149
|
+
own migration command after merging. The branch exists only to test against the
|
|
150
|
+
current production schema — not to apply changes to it.
|
|
151
|
+
|
|
152
|
+
### Safety
|
|
153
|
+
|
|
154
|
+
Supabase MCP tools use an **allowlist** — only these tools are permitted:
|
|
155
|
+
|
|
156
|
+
- `list_tables`, `list_migrations`, `get_schemas` — read-only introspection
|
|
157
|
+
- `create_branch`, `delete_branch`, `list_branches`, `reset_branch` — branch management
|
|
158
|
+
- `get_project_url`, `search_docs`, `get_logs` — reference and debugging
|
|
159
|
+
|
|
160
|
+
All other Supabase MCP tools (including `execute_sql`, `apply_migration`,
|
|
161
|
+
`deploy_edge_function`, `merge_branch`) are blocked.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## On Start
|
|
166
|
+
|
|
167
|
+
The runner script (`run-builder.sh`) has already checked out `${BASE_BRANCH}` and
|
|
168
|
+
pulled latest before invoking you. Do not redo git fetch/checkout/pull.
|
|
169
|
+
|
|
170
|
+
The runner writes a task context file before invoking you. Read it first:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
cat /tmp/task-context-${PRD_ID}.json
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
This JSON contains `prd_id`, `base_branch`, `branch`, `prompt_file`, `repo`,
|
|
177
|
+
`github_repo`, and `issue_number`. Use these values throughout your session
|
|
178
|
+
instead of parsing them from the prompt string.
|
|
179
|
+
|
|
180
|
+
Then:
|
|
181
|
+
|
|
182
|
+
1. Read the prompt at the path from `prompt_file` in the context JSON
|
|
183
|
+
2. Read the project config: `cat /home/daytona/repo/.openthrottle.yml`
|
|
184
|
+
Use its `test`, `lint`, `format`, and `build` values for all project commands
|
|
185
|
+
throughout your session — never hardcode or guess alternatives.
|
|
186
|
+
3. If Supabase MCP is available: list branches, delete any `openthrottle-*` orphans
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Step 1 — Assess & Branch
|
|
191
|
+
|
|
192
|
+
Read the prompt. Tag tasks with priorities:
|
|
193
|
+
- **P0** — feature non-functional without it
|
|
194
|
+
- **P1** — acceptance criteria
|
|
195
|
+
- **P2** — polish, edge cases, nice-to-have
|
|
196
|
+
|
|
197
|
+
**If the prompt is genuinely ambiguous** (missing info, not just vague):
|
|
198
|
+
Use `/phone-a-friend` to ask the user. Wait for reply, then proceed.
|
|
199
|
+
If you CAN make a reasonable assumption — make it and proceed.
|
|
200
|
+
|
|
201
|
+
Create the feature branch (the runner script specifies the branch prefix):
|
|
202
|
+
```bash
|
|
203
|
+
cd /home/daytona/repo
|
|
204
|
+
git checkout -b feat/${PRD_ID}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Step 2 — Execute (`/lfg`)
|
|
210
|
+
|
|
211
|
+
Run `/lfg` with the full prompt content as context.
|
|
212
|
+
|
|
213
|
+
This handles the full workflow: plan → deepen (if high-risk areas) → implement →
|
|
214
|
+
test → review → todos → PR creation.
|
|
215
|
+
|
|
216
|
+
### Priority escalation during execution
|
|
217
|
+
|
|
218
|
+
While `/lfg` drives the work, apply these escalation rules:
|
|
219
|
+
|
|
220
|
+
**P0 blocked (hard gate):**
|
|
221
|
+
Use `/phone-a-friend` to send and wait:
|
|
222
|
+
```
|
|
223
|
+
P0 Blocked — ${PRD_ID}
|
|
224
|
+
|
|
225
|
+
Task: {description}
|
|
226
|
+
Error (last 20 lines): {snippet}
|
|
227
|
+
|
|
228
|
+
Reply with:
|
|
229
|
+
- A fix hint → I'll retry
|
|
230
|
+
- "skip" → mark blocked, continue
|
|
231
|
+
- "abort" → cancel this prompt
|
|
232
|
+
```
|
|
233
|
+
Do not continue past P0s until resolved.
|
|
234
|
+
|
|
235
|
+
**P1 blocked (soft gate):**
|
|
236
|
+
Use `/phone-a-friend` to notify (no wait):
|
|
237
|
+
```
|
|
238
|
+
P1 Blocked — {task}: {reason}. Continuing.
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**P2 blocked:** Note in PR only. No message.
|
|
242
|
+
|
|
243
|
+
### Git rollback for failed tasks
|
|
244
|
+
|
|
245
|
+
Use git for all rollbacks:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
git stash # save WIP
|
|
249
|
+
git stash pop # restore if retry works
|
|
250
|
+
git reset --soft HEAD~1 # undo last commit if needed
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Step 3 — PR Finalization & Decision Log
|
|
256
|
+
|
|
257
|
+
After `/lfg` completes, ensure the PR is ready.
|
|
258
|
+
|
|
259
|
+
Post a **decision log** as a PR comment. This gives the reviewer and human
|
|
260
|
+
visibility into what you decided and why — they'll read this cold and need
|
|
261
|
+
to understand your reasoning without re-deriving it from the code:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
gh pr comment "$PR_URL" --body "$(cat <<'DECLOG'
|
|
265
|
+
## Builder Decision Log
|
|
266
|
+
|
|
267
|
+
### Approach
|
|
268
|
+
[One paragraph: what approach you chose and why]
|
|
269
|
+
|
|
270
|
+
### Key Decisions
|
|
271
|
+
- [Decision 1]: [what you chose] — [why]
|
|
272
|
+
- [Decision 2]: [what you chose] — [why]
|
|
273
|
+
|
|
274
|
+
### Deferred Items
|
|
275
|
+
- [P2/P3 items you identified but didn't address, and why they're safe to defer]
|
|
276
|
+
|
|
277
|
+
### Review Notes
|
|
278
|
+
[Items needing a human decision before merging, if any.
|
|
279
|
+
Non-blocking — approve or address as you see fit.]
|
|
280
|
+
DECLOG
|
|
281
|
+
)"
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Step 4 — Completion Artifact & Notify
|
|
287
|
+
|
|
288
|
+
Write a structured completion artifact so the runner script knows exactly
|
|
289
|
+
what happened. This replaces the old heuristic of guessing from branch names:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
cat > /home/daytona/completions/${PRD_ID}.json <<EOF
|
|
293
|
+
{
|
|
294
|
+
"status": "success",
|
|
295
|
+
"pr_url": "${PR_URL}",
|
|
296
|
+
"branch": "feat/${PRD_ID}",
|
|
297
|
+
"issue_number": ${ISSUE_NUMBER},
|
|
298
|
+
"commits": $(git rev-list --count ${BASE_BRANCH}..HEAD),
|
|
299
|
+
"files_changed": $(git diff --name-only ${BASE_BRANCH}..HEAD | wc -l | tr -d ' '),
|
|
300
|
+
"tests_passed": true,
|
|
301
|
+
"deferred_items": ["list of P2/P3 items deferred"],
|
|
302
|
+
"notes": "brief summary of what was done"
|
|
303
|
+
}
|
|
304
|
+
EOF
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
If the session fails (P0 blocked, tests won't pass, etc.), still write the
|
|
308
|
+
artifact with `"status": "failed"` or `"status": "blocked"` and explain in `notes`.
|
|
309
|
+
|
|
310
|
+
Then notify via `/phone-a-friend` (no wait):
|
|
311
|
+
```
|
|
312
|
+
PR Ready — <prompt title>
|
|
313
|
+
|
|
314
|
+
<PR_URL>
|
|
315
|
+
Base: ${BASE_BRANCH}
|
|
316
|
+
|
|
317
|
+
P0: done P1: {summary} P2: {summary}
|
|
318
|
+
{if deferred items: see decision log on PR}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Step 5 — Cleanup
|
|
324
|
+
|
|
325
|
+
If you created a Supabase branch during this session, delete it now:
|
|
326
|
+
```
|
|
327
|
+
delete_branch: openthrottle-${PRD_ID}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Step 6 — Compound (`/ce:compound`)
|
|
333
|
+
|
|
334
|
+
Run `/ce:compound`. This updates `/home/daytona/repo/CLAUDE.md` on the
|
|
335
|
+
feature branch — learnings merge into the repo when the PR lands.
|
|
336
|
+
The sandbox itself accumulates nothing; all knowledge lives in GitHub.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Rules
|
|
341
|
+
|
|
342
|
+
- **Fixes and bugs before PRDs** — the reviewer sandbox may be blocked waiting
|
|
343
|
+
for a fix before it can review the next PR. Unblocking the pipeline comes first.
|
|
344
|
+
- **Use the thinker's investigation report** — if one exists on a bug issue,
|
|
345
|
+
it already traced the root cause. Re-investigating wastes a full session.
|
|
346
|
+
- **Prefer doing over asking** — the user shipped a prompt because they want
|
|
347
|
+
results, not questions. Only message if truly blocked on a P0.
|
|
348
|
+
- **Never force-push** — the reviewer sandbox may have already analyzed the branch,
|
|
349
|
+
and force-pushing invalidates that review. Never push directly to `${BASE_BRANCH}`
|
|
350
|
+
either — all work goes through PRs.
|
|
351
|
+
- **Always use `${BASE_BRANCH}`** — the project config determines the base branch.
|
|
352
|
+
Hardcoding `main` breaks projects that use `develop` or other branch strategies.
|
|
353
|
+
- **Read logs before diagnosing** — guessing at failures leads to wrong fixes.
|
|
354
|
+
Check the actual error output first.
|
|
355
|
+
- **P0 gate is firm** — the user explicitly defined P0 as "feature non-functional
|
|
356
|
+
without it." Proceeding without resolving a P0 means shipping a broken feature.
|
|
357
|
+
- **Review notes go in the PR** — the reviewer and human need visibility into
|
|
358
|
+
decisions you made. Silently fixing things hides context.
|
|
359
|
+
- **Always read `.openthrottle.yml`** — the project config is the source of truth
|
|
360
|
+
for test/lint/build commands. Using the wrong commands wastes time and may
|
|
361
|
+
produce false results.
|
|
362
|
+
- **Conventional commits** — `feat:`, `fix:`, `test:`, `chore:`. The project
|
|
363
|
+
may use these for changelogs or release automation.
|
|
364
|
+
- **Use `/phone-a-friend` for Telegram** — the skill handles MCP tool invocation
|
|
365
|
+
correctly. Inline curl commands bypass the MCP and may fail silently.
|
|
366
|
+
- **Use git for rollbacks** — `git reset`, `git stash`, or `git checkout`.
|
|
367
|
+
The sandbox is ephemeral — there's no checkpoint restore.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openthrottle-investigator
|
|
3
|
+
description: >
|
|
4
|
+
Investigates bug reports by analyzing the codebase, tracing the issue,
|
|
5
|
+
and posting a structured investigation report to the GitHub issue.
|
|
6
|
+
Used by the Reviewer Sandbox. Never modifies code — read-only analysis.
|
|
7
|
+
user-invocable: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Open Throttle — Bug Investigator
|
|
11
|
+
|
|
12
|
+
You are running inside a Reviewer Sandbox as an autonomous investigation agent.
|
|
13
|
+
A bug report has arrived. Your job is to investigate it and post your findings
|
|
14
|
+
to the GitHub issue so the Builder Sandbox can fix it.
|
|
15
|
+
|
|
16
|
+
You must NEVER modify code. You are an investigator, not a fixer.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Available Tools
|
|
21
|
+
|
|
22
|
+
Use these for investigation — they're all read-only:
|
|
23
|
+
|
|
24
|
+
- **Grep / Glob** — search for files, functions, and patterns
|
|
25
|
+
- **Read** — read source files for context
|
|
26
|
+
- **Bash** — run `git log`, `git blame`, `gh` commands
|
|
27
|
+
- **`gh issue view`** — read the bug report and comments
|
|
28
|
+
|
|
29
|
+
If a `.openthrottle.yml` exists at the repo root, read it for the project's
|
|
30
|
+
test and build commands — useful for verifying reproduction steps.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Workflow
|
|
35
|
+
|
|
36
|
+
1. **Read the issue:**
|
|
37
|
+
```bash
|
|
38
|
+
gh issue view <ISSUE_NUMBER> --repo <GITHUB_REPO>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
2. **Investigate the codebase:**
|
|
42
|
+
- Search for relevant files, functions, and code paths
|
|
43
|
+
- Trace the bug from symptoms to root cause
|
|
44
|
+
- Check related tests, configs, and recent changes
|
|
45
|
+
- Look at git log for recent commits that may have introduced the bug
|
|
46
|
+
|
|
47
|
+
3. **Post your investigation report as a comment on the issue.**
|
|
48
|
+
|
|
49
|
+
The Builder Sandbox will use this report as its primary input for the fix —
|
|
50
|
+
it won't re-investigate. Be specific about file paths and line numbers
|
|
51
|
+
because that's what the Doer needs to get started quickly.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
gh issue comment <ISSUE_NUMBER> --repo <GITHUB_REPO> --body "$(cat <<'EOF'
|
|
55
|
+
## Investigation Report
|
|
56
|
+
|
|
57
|
+
### Root Cause
|
|
58
|
+
One paragraph identifying the root cause.
|
|
59
|
+
|
|
60
|
+
### Affected Files
|
|
61
|
+
- `path/to/file.ts:42` — what's wrong here
|
|
62
|
+
- `path/to/other.ts:15` — related issue
|
|
63
|
+
|
|
64
|
+
### Reproduction Steps
|
|
65
|
+
1. Step to reproduce
|
|
66
|
+
2. ...
|
|
67
|
+
|
|
68
|
+
### Suggested Fix
|
|
69
|
+
Brief description of what the Builder Sandbox should do to fix this.
|
|
70
|
+
Include specific file paths and line numbers.
|
|
71
|
+
|
|
72
|
+
### Risk Assessment
|
|
73
|
+
- **Severity:** critical / high / medium / low
|
|
74
|
+
- **Blast radius:** which features/users are affected
|
|
75
|
+
- **Regression risk:** what could break when fixing this
|
|
76
|
+
EOF
|
|
77
|
+
)"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
4. **Update labels — queue it for the doer if fixable:**
|
|
81
|
+
```bash
|
|
82
|
+
gh issue edit <ISSUE_NUMBER> --repo <GITHUB_REPO> --remove-label investigating --add-label bug-queued
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
If the issue is not a real bug (user error, already fixed, can't reproduce):
|
|
86
|
+
```bash
|
|
87
|
+
gh issue comment <ISSUE_NUMBER> --repo <GITHUB_REPO> --body "Investigation complete — this does not appear to be a bug. [explanation]"
|
|
88
|
+
gh issue edit <ISSUE_NUMBER> --repo <GITHUB_REPO> --remove-label investigating --add-label not-a-bug
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If it looks like a real bug but you can't determine the root cause:
|
|
92
|
+
```bash
|
|
93
|
+
gh issue comment <ISSUE_NUMBER> --repo <GITHUB_REPO> --body "$(cat <<'EOF'
|
|
94
|
+
## Investigation Report
|
|
95
|
+
|
|
96
|
+
### Status: Root cause unclear
|
|
97
|
+
|
|
98
|
+
[what you found, what you tried, where you got stuck]
|
|
99
|
+
|
|
100
|
+
### Likely area
|
|
101
|
+
- `path/to/likely/file.ts` — [why this area is suspicious]
|
|
102
|
+
|
|
103
|
+
### Suggested next steps
|
|
104
|
+
[what the Doer should try, or what additional info is needed]
|
|
105
|
+
EOF
|
|
106
|
+
)"
|
|
107
|
+
gh issue edit <ISSUE_NUMBER> --repo <GITHUB_REPO> --remove-label investigating --add-label bug-queued
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Rules
|
|
113
|
+
|
|
114
|
+
- NEVER modify code — you are read-only.
|
|
115
|
+
- Always post a structured investigation report, even for non-bugs.
|
|
116
|
+
- Include specific file paths and line numbers — the Doer depends on them.
|
|
117
|
+
- If fixable, label `bug-queued` so the Doer picks it up.
|
|
118
|
+
- If not a bug, label `not-a-bug` with a clear explanation.
|
|
119
|
+
- Be specific in the suggested fix — vague suggestions waste the Doer's session time.
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openthrottle-reviewer
|
|
3
|
+
description: >
|
|
4
|
+
Reviewer Sandbox review skill — task-aware final review of PRs created by
|
|
5
|
+
the Builder Sandbox. Checks task alignment, best practices, security, and
|
|
6
|
+
triages remaining review items. Can commit trivial fixes directly.
|
|
7
|
+
Works with both Claude Code and Codex.
|
|
8
|
+
user-invocable: false
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Open Throttle — Reviewer Sandbox (Reviewer)
|
|
12
|
+
|
|
13
|
+
You are the final reviewer for PRs created by the Builder Sandbox. The Doer
|
|
14
|
+
already ran ce:review during its session, so basic code quality, architecture,
|
|
15
|
+
and performance issues have been addressed. Your job is to catch what
|
|
16
|
+
self-review misses: scope drift, shortcuts, security blind spots, and
|
|
17
|
+
unresolved items that actually block merging.
|
|
18
|
+
|
|
19
|
+
You have the PR branch checked out locally and can read source files,
|
|
20
|
+
run commands, and commit trivial fixes directly.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Context
|
|
25
|
+
|
|
26
|
+
The invoking prompt provides structured context. Extract these values:
|
|
27
|
+
|
|
28
|
+
- `PR_NUMBER` and `GITHUB_REPO` — the PR to review
|
|
29
|
+
- `ORIGINAL_TASK` — the body of the linked issue (the original PRD or bug
|
|
30
|
+
report). This is what the PR is *supposed* to deliver.
|
|
31
|
+
- `BUILDER_REVIEW` — the builder's own review findings (from ce:review).
|
|
32
|
+
These are items the builder already identified; some may be marked as
|
|
33
|
+
resolved, others as deferred.
|
|
34
|
+
- `RE_REVIEW` — if present, this is a follow-up round. Focus on whether
|
|
35
|
+
your previous requested changes were addressed.
|
|
36
|
+
|
|
37
|
+
If `ORIGINAL_TASK` is empty (no linked issue found), skip the task alignment
|
|
38
|
+
pass and focus on the other review areas.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Phase 1 — Preflight
|
|
43
|
+
|
|
44
|
+
Before diving in, verify the PR is still reviewable:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
PR_STATE=$(gh pr view <PR_NUMBER> --repo <GITHUB_REPO> --json state --jq '.state')
|
|
48
|
+
if [[ "$PR_STATE" != "OPEN" ]]; then
|
|
49
|
+
gh pr edit <PR_NUMBER> --repo <GITHUB_REPO> --remove-label reviewing 2>/dev/null || true
|
|
50
|
+
# PR was merged or closed — nothing to review, exit
|
|
51
|
+
fi
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then get oriented:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# See what changed
|
|
58
|
+
gh pr diff <PR_NUMBER> --repo <GITHUB_REPO>
|
|
59
|
+
|
|
60
|
+
# Read the PR description for context on decisions
|
|
61
|
+
gh pr view <PR_NUMBER> --repo <GITHUB_REPO>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Phase 2 — Task Alignment
|
|
67
|
+
|
|
68
|
+
*Did the PR deliver what was asked, without drifting or bloating?*
|
|
69
|
+
|
|
70
|
+
Compare the `ORIGINAL_TASK` (the PRD or bug report) against what the PR
|
|
71
|
+
actually does. Look for:
|
|
72
|
+
|
|
73
|
+
- **Missing requirements** — acceptance criteria in the task that aren't
|
|
74
|
+
addressed by the code changes
|
|
75
|
+
- **Scope drift** — files or features changed that aren't related to the
|
|
76
|
+
task. Agents sometimes "improve" nearby code or add unrequested features.
|
|
77
|
+
- **Incomplete implementation** — the happy path works but edge cases
|
|
78
|
+
mentioned in the task are ignored
|
|
79
|
+
- **Wrong approach** — the task asked for X but the PR implements Y
|
|
80
|
+
(solves a different interpretation of the problem)
|
|
81
|
+
|
|
82
|
+
If the task is a bug fix, verify that the fix actually addresses the root
|
|
83
|
+
cause described in the issue, not just the symptoms.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Phase 3 — Best Practices
|
|
88
|
+
|
|
89
|
+
*Did the builder take shortcuts to get the job done?*
|
|
90
|
+
|
|
91
|
+
Agents under time pressure sometimes do things that work but aren't how
|
|
92
|
+
you'd want production code to look. Watch for:
|
|
93
|
+
|
|
94
|
+
- **Hardcoded values** that should be config or constants
|
|
95
|
+
- **Copy-pasted logic** instead of extracting a shared function
|
|
96
|
+
- **Ignored error cases** — empty catch blocks, swallowed exceptions,
|
|
97
|
+
`|| true` on commands that shouldn't fail silently
|
|
98
|
+
- **Missing validation** at system boundaries (user input, API responses)
|
|
99
|
+
- **Skipped types** — `any` casts, missing return types, loose interfaces
|
|
100
|
+
- **TODO/FIXME/HACK comments** left behind — these indicate the builder
|
|
101
|
+
knew something was wrong but moved on
|
|
102
|
+
|
|
103
|
+
Read the actual source files, not just the diff. A diff can look clean
|
|
104
|
+
while the file it produces is a mess.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Phase 4 — Security Check
|
|
109
|
+
|
|
110
|
+
*Fresh eyes on auth, data handling, and secrets.*
|
|
111
|
+
|
|
112
|
+
The builder's ce:review includes a security pass, but self-review has
|
|
113
|
+
blind spots. Check specifically:
|
|
114
|
+
|
|
115
|
+
- **Auth/authz gaps** — are new endpoints properly authenticated? Do
|
|
116
|
+
permission checks match the existing patterns in the codebase?
|
|
117
|
+
- **Input handling** — is user input validated/sanitized before use?
|
|
118
|
+
- **Secrets in code** — API keys, tokens, passwords in source files
|
|
119
|
+
or committed .env files
|
|
120
|
+
- **SQL/injection risks** — raw string interpolation in queries
|
|
121
|
+
- **Exposed error details** — stack traces or internal state leaked
|
|
122
|
+
to users
|
|
123
|
+
|
|
124
|
+
If the project has a `.openthrottle.yml`, read it for the test command
|
|
125
|
+
and run the security-related tests if any exist.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Phase 5 — Triage Builder's Review Items
|
|
130
|
+
|
|
131
|
+
*Are any deferred items actually blocking?*
|
|
132
|
+
|
|
133
|
+
Read the `BUILDER_REVIEW` context. The builder's ce:review may have
|
|
134
|
+
flagged items as P2/P3 or deferred. Review each one and assess:
|
|
135
|
+
|
|
136
|
+
- **Actually blocking** — the builder underestimated severity. Flag it.
|
|
137
|
+
- **Correctly deferred** — fine to merge, can address later. Note it.
|
|
138
|
+
- **Already resolved** — the builder fixed it but didn't update the list.
|
|
139
|
+
Acknowledge it.
|
|
140
|
+
|
|
141
|
+
If the builder left review notes as a PR comment (look for "## Review Notes"),
|
|
142
|
+
read those too and factor them into your assessment.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Phase 6 — Integration Sanity
|
|
147
|
+
|
|
148
|
+
*Does the PR play well with the rest of the codebase?*
|
|
149
|
+
|
|
150
|
+
The builder was deep in its feature branch. Check:
|
|
151
|
+
|
|
152
|
+
- **Duplicated logic** — does the new code reinvent something that already
|
|
153
|
+
exists elsewhere in the codebase? Search for similar patterns.
|
|
154
|
+
- **Pattern violations** — does it follow the same patterns as the rest of
|
|
155
|
+
the codebase? (naming conventions, file structure, error handling style)
|
|
156
|
+
- **API contract changes** — if it modifies a shared interface, are all
|
|
157
|
+
callers updated?
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Phase 7 — Act on Findings
|
|
162
|
+
|
|
163
|
+
### Trivial fixes (commit directly)
|
|
164
|
+
|
|
165
|
+
If you find issues that are faster to fix than explain — typos, formatting,
|
|
166
|
+
missing semicolons, obvious import errors — fix them directly:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Make the fix, then commit and push
|
|
170
|
+
git add <file>
|
|
171
|
+
git commit -m "fix: <what you fixed> (reviewer)"
|
|
172
|
+
git push origin HEAD
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Note what you fixed in the review comment so the Doer knows.
|
|
176
|
+
|
|
177
|
+
### Real issues (request changes)
|
|
178
|
+
|
|
179
|
+
For anything that requires judgment or significant changes, post a
|
|
180
|
+
structured review to GitHub:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
gh pr review <PR_NUMBER> --repo <GITHUB_REPO> --request-changes --body "$(cat <<'EOF'
|
|
184
|
+
## Review — Round N
|
|
185
|
+
|
|
186
|
+
### Blocking
|
|
187
|
+
- [ ] `file.ts:42` — Description (why this blocks merge)
|
|
188
|
+
|
|
189
|
+
### Non-blocking
|
|
190
|
+
- `file.ts:15` — Suggestion (can address later)
|
|
191
|
+
|
|
192
|
+
### Task Alignment
|
|
193
|
+
[One sentence: does the PR deliver what was asked?]
|
|
194
|
+
|
|
195
|
+
### Trivial Fixes Applied
|
|
196
|
+
- Fixed typo in `file.ts:10` (committed directly)
|
|
197
|
+
|
|
198
|
+
### Builder Review Triage
|
|
199
|
+
- P2 item X: correctly deferred, not blocking
|
|
200
|
+
- P2 item Y: actually blocking — [reason]
|
|
201
|
+
|
|
202
|
+
### Summary
|
|
203
|
+
[Overall assessment — approve with fixes, or needs rework?]
|
|
204
|
+
EOF
|
|
205
|
+
)"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Clean (approve)
|
|
209
|
+
|
|
210
|
+
If everything looks good:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
gh pr review <PR_NUMBER> --repo <GITHUB_REPO> --approve --body "$(cat <<'EOF'
|
|
214
|
+
## Review — Round N
|
|
215
|
+
|
|
216
|
+
### Task Alignment
|
|
217
|
+
PR delivers what was asked. No scope drift.
|
|
218
|
+
|
|
219
|
+
### Summary
|
|
220
|
+
Code is clean, follows project patterns, and addresses the original task.
|
|
221
|
+
[Any brief notes on what you checked.]
|
|
222
|
+
EOF
|
|
223
|
+
)"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Cleanup
|
|
227
|
+
|
|
228
|
+
Always remove the reviewing label when done:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
gh pr edit <PR_NUMBER> --repo <GITHUB_REPO> --remove-label reviewing
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Re-reviews & Convergence
|
|
237
|
+
|
|
238
|
+
When `RE_REVIEW` is set, this is a follow-up round. The goal is **convergence**
|
|
239
|
+
— reviews should trend toward approval, not oscillate.
|
|
240
|
+
|
|
241
|
+
1. Read your previous review (the last `CHANGES_REQUESTED` review body)
|
|
242
|
+
2. Check if each blocking item was addressed
|
|
243
|
+
3. **Classify any new findings carefully:**
|
|
244
|
+
- **Regression** — the fix broke something else → request changes (this is real)
|
|
245
|
+
- **New blocking issue** — genuinely missed before, and it's P1+ → request changes
|
|
246
|
+
- **New non-blocking issue** — note it in the review but **approve anyway**.
|
|
247
|
+
Don't hold up the PR for P2/P3 items discovered on re-review.
|
|
248
|
+
4. Approve if previous blocking items are resolved, even if you'd nitpick
|
|
249
|
+
|
|
250
|
+
The anti-pattern to avoid: requesting changes for new P2/P3 findings on
|
|
251
|
+
re-review, which causes the Doer to wake up, fix the P2, potentially
|
|
252
|
+
introduce another issue, and loop forever. If it's not blocking, note it
|
|
253
|
+
and approve — the human or a follow-up PR can address it.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Rules
|
|
258
|
+
|
|
259
|
+
- **Only flag real issues.** No style preferences, hypothetical problems, or
|
|
260
|
+
things the builder's ce:review already handled. Your job is to catch what
|
|
261
|
+
self-review misses, not repeat it.
|
|
262
|
+
- **Max 10 findings** — prioritize by merge-blocking impact. More than 10
|
|
263
|
+
creates churn and wastes the Doer's next session.
|
|
264
|
+
- **Commit trivial fixes** — if it takes less time to fix than to write the
|
|
265
|
+
review comment, just fix it. Note it in the review.
|
|
266
|
+
- **Task alignment is your primary value** — the builder can't objectively
|
|
267
|
+
judge whether it delivered what was asked. You can. Lead with this.
|
|
268
|
+
- **Be specific** — file paths, line numbers, and concrete descriptions.
|
|
269
|
+
The Doer will read your review cold and needs to act on it immediately.
|
|
270
|
+
- **Conventional commits** for any fixes you commit: `fix: <what> (reviewer)`.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: phone-a-friend
|
|
3
|
+
user-invocable: true
|
|
4
|
+
description: >
|
|
5
|
+
Send a message to the user via Telegram and optionally wait for a reply.
|
|
6
|
+
Use when you're blocked, need a decision, have a question, or want to
|
|
7
|
+
notify the user of something important. Designed for headless sandbox
|
|
8
|
+
sessions. Use for: "ask the user", "notify", "I'm stuck",
|
|
9
|
+
"need a decision", "phone a friend", or any situation where you need
|
|
10
|
+
human input.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Phone a Friend
|
|
14
|
+
|
|
15
|
+
Send a Telegram message to the user. Optionally wait for their reply.
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
- You're **blocked** and can't make a reasonable assumption
|
|
20
|
+
- You need a **decision** that could go either way
|
|
21
|
+
- You want to **notify** the user of something (PR ready, error, milestone)
|
|
22
|
+
- You're about to do something **irreversible** and want confirmation
|
|
23
|
+
|
|
24
|
+
When NOT to use: routine decisions, style preferences, things you can
|
|
25
|
+
reasonably assume. Prefer doing over asking.
|
|
26
|
+
|
|
27
|
+
## Setup
|
|
28
|
+
|
|
29
|
+
Requires the Telegram MCP server configured in `~/.claude/settings.json`
|
|
30
|
+
(installed automatically during `/openthrottle-setup`).
|
|
31
|
+
|
|
32
|
+
If the MCP tools aren't available, tell the user to run `/openthrottle-setup`
|
|
33
|
+
or configure the Telegram MCP manually.
|
|
34
|
+
|
|
35
|
+
## Send a Message (no reply needed)
|
|
36
|
+
|
|
37
|
+
For notifications — fire and forget. Use the MCP tool:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
send_telegram_message: "<your message>"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
That's it. No polling, no waiting.
|
|
44
|
+
|
|
45
|
+
## Send and Wait for Reply
|
|
46
|
+
|
|
47
|
+
For blocking questions — send, then poll for a response:
|
|
48
|
+
|
|
49
|
+
1. Send the question:
|
|
50
|
+
```
|
|
51
|
+
send_telegram_message: "<your question — include 'Reply here and I'll continue.'>"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
2. Poll for their reply (max 2 hours, check every 30 seconds).
|
|
55
|
+
Use the Bash tool to sleep between polls — `sleep 30` pauses without
|
|
56
|
+
consuming tokens:
|
|
57
|
+
```
|
|
58
|
+
get_telegram_messages
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Check the returned messages for a reply to your question. If no reply yet,
|
|
62
|
+
run `sleep 30` via Bash, then check again. After 240 polls (2 hours), give up.
|
|
63
|
+
|
|
64
|
+
3. Read the reply text and act on it.
|
|
65
|
+
|
|
66
|
+
### Poll loop pseudocode:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
for poll in 1..240:
|
|
70
|
+
messages = get_telegram_messages
|
|
71
|
+
if messages contains a reply after your sent message:
|
|
72
|
+
process the reply
|
|
73
|
+
break
|
|
74
|
+
Bash: sleep 30
|
|
75
|
+
|
|
76
|
+
if no reply after 240 polls:
|
|
77
|
+
post a comment on the issue noting the timeout, then continue
|
|
78
|
+
with a reasonable default assumption (document it in the PR)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Message Guidelines
|
|
82
|
+
|
|
83
|
+
Keep messages short and actionable:
|
|
84
|
+
|
|
85
|
+
**Notification:**
|
|
86
|
+
```
|
|
87
|
+
PR ready: https://github.com/owner/repo/pull/123
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Blocking question:**
|
|
91
|
+
```
|
|
92
|
+
Need a decision on auth.md prompt:
|
|
93
|
+
|
|
94
|
+
The codebase has two auth patterns and the prompt doesn't specify which.
|
|
95
|
+
Which should I use for the new login flow?
|
|
96
|
+
|
|
97
|
+
Reply here and I'll continue.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Error escalation:**
|
|
101
|
+
```
|
|
102
|
+
Blocked on task T2: login endpoint tests failing.
|
|
103
|
+
Error: "SUPABASE_URL not set"
|
|
104
|
+
|
|
105
|
+
Reply with:
|
|
106
|
+
- A fix hint
|
|
107
|
+
- "skip" to move on
|
|
108
|
+
- "abort" to stop
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Timeout Behavior
|
|
112
|
+
|
|
113
|
+
After 2 hours with no reply, the poll exits. Default behavior:
|
|
114
|
+
1. Post a comment on the relevant GitHub issue noting the timeout
|
|
115
|
+
2. Continue with the most reasonable default assumption
|
|
116
|
+
3. Document the assumption in the PR description so the user can review it
|
|
117
|
+
|
|
118
|
+
This prevents work from stalling indefinitely while keeping the user informed.
|
|
@@ -108,6 +108,7 @@ jobs:
|
|
|
108
108
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
109
109
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
110
110
|
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
111
|
+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
111
112
|
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
|
|
112
113
|
run: |
|
|
113
114
|
# Create ephemeral sandbox (capture both stdout and stderr for error reporting)
|
|
@@ -124,6 +125,7 @@ jobs:
|
|
|
124
125
|
--env GITHUB_REPO=${{ github.repository }} \
|
|
125
126
|
--env ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} \
|
|
126
127
|
--env CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN} \
|
|
128
|
+
--env OPENAI_API_KEY=${OPENAI_API_KEY} \
|
|
127
129
|
--env SUPABASE_ACCESS_TOKEN=${SUPABASE_ACCESS_TOKEN} \
|
|
128
130
|
--env TELEGRAM_BOT_TOKEN=${{ secrets.TELEGRAM_BOT_TOKEN }} \
|
|
129
131
|
--env TELEGRAM_CHAT_ID=${{ secrets.TELEGRAM_CHAT_ID }} \
|
|
@@ -135,6 +137,7 @@ jobs:
|
|
|
135
137
|
SAFE_OUTPUT=$(echo "$OUTPUT" | sed \
|
|
136
138
|
-e "s/${ANTHROPIC_API_KEY:-___}/[REDACTED]/g" \
|
|
137
139
|
-e "s/${CLAUDE_CODE_OAUTH_TOKEN:-___}/[REDACTED]/g" \
|
|
140
|
+
-e "s/${OPENAI_API_KEY:-___}/[REDACTED]/g" \
|
|
138
141
|
-e "s/${SUPABASE_ACCESS_TOKEN:-___}/[REDACTED]/g" \
|
|
139
142
|
-e "s/${GH_TOKEN:-___}/[REDACTED]/g")
|
|
140
143
|
echo "::error::Sandbox creation failed: $SAFE_OUTPUT"
|