Skip to content

Commit c6fe6b0

Browse files
committed
feat(harness): add /setup, /plan-to-issues, and /teach commands
/setup — Interactive project configurator. Interviews for app name, domain, GitHub repo, Signed-off-by identity, and accent color, then rewrites <app>/<domain>/[EMAIL] placeholders across the harness. Idempotent via .opencode/setup.json manifest. Excludes aurora/ submodule. /plan-to-issues — Parses a writing-plans-format plan file and creates a GitHub epic + per-task issues via gh issue create. User confirms the parsed task list before any issues are created. /teach — Explains the most recently completed work at the user's level (what changed, why this approach, trade-offs considered). Explicit invocation; no per-task noise. Plan-by: glm-5.2 Acked-by: deepseek-v4-pro Signed-off-by: kyau <git@kyaulabs.com>
1 parent 2b68768 commit c6fe6b0

6 files changed

Lines changed: 434 additions & 1 deletion

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
---
2+
description: Parse a plan from docs/plans/ and create a GitHub epic + task issues via gh. Prints the parsed task list for confirmation before running gh issue create.
3+
agent: build
4+
---
5+
6+
Parse a writing-plans-format plan file and push it into GitHub Issues as an
7+
epic with per-task sub-issues. Runs `gh issue create` after user confirmation.
8+
9+
## 1. Prerequisites
10+
11+
```bash
12+
gh auth status 2>&1 | head -1
13+
```
14+
15+
If `gh` is not installed or not authed, stop and report:
16+
17+
```text
18+
✗ gh is not available or not authenticated.
19+
20+
Fix:
21+
gh auth login
22+
```
23+
24+
## 2. Identify the plan file
25+
26+
If the user specified a plan file path, use it. Otherwise pick the most recent
27+
plan:
28+
29+
```bash
30+
ls -t docs/plans/*.md 2>/dev/null | head -1
31+
```
32+
33+
If no plan files exist, stop: "No plan files found in docs/plans/."
34+
35+
Read the plan file and confirm it follows the `writing-plans` format
36+
(`### Task N:` headers). If parsing fails, report the error and stop.
37+
38+
## 3. Parse
39+
40+
From the plan file, extract:
41+
42+
- **Plan title** — from the `# ` H1 header.
43+
- **Goal** — from the `**Goal:**` line.
44+
- **Tasks** — each `### Task N: <Title>` block. For each task, extract:
45+
- Task number and title.
46+
- Files list (from `**Files:**` section).
47+
- Interfaces summary (from `**Interfaces:**` section — truncated to one line
48+
per produced/consumed interface).
49+
50+
## 4. Verify
51+
52+
Print a preview table:
53+
54+
```text
55+
Plan: <plan title>
56+
Goal: <goal>
57+
File: docs/plans/<file>.md
58+
59+
# Title Files
60+
- --------------------------------------- --------------------
61+
1 Shared include — EvalCase, EvalResult Create: 1, Test: 1
62+
2 Command builder Create: 2, Test: 1
63+
...
64+
65+
Parent epic: [Plan] <plan title>
66+
67+
Create 1 epic + N task issues? (y/n)
68+
```
69+
70+
Wait for confirmation before creating any issues.
71+
72+
## 5. Ensure the plan label exists
73+
74+
```bash
75+
gh label list --json name -q '.[].name' | grep -qx plan || gh label create plan --color "0ea5e9" --description "Work from a docs/plans/ implementation plan"
76+
```
77+
78+
If the label is newly created, note it in the report.
79+
80+
## 6. Create the parent epic
81+
82+
```bash
83+
gh issue create \
84+
--title "[Plan] <plan title>" \
85+
--label "plan" \
86+
--body "**Goal:** <goal>
87+
88+
Plan file: docs/plans/<file>.md
89+
90+
---
91+
92+
This epic tracks implementation of the full plan. Each task is a sub-issue."
93+
```
94+
95+
Capture the issue number from the output.
96+
97+
## 7. Create task issues
98+
99+
For each task, create an issue:
100+
101+
```bash
102+
gh issue create \
103+
--title "[Task N] <task title>" \
104+
--label "plan" \
105+
--body "Parent: #<epic-number>
106+
107+
Plan: docs/plans/<file>.md
108+
109+
## Files
110+
<files list as bullet points>
111+
112+
## Interfaces
113+
<interfaces summary>
114+
115+
---
116+
117+
Implementation follows the @tdd Red → Green → Refactor cycle per the
118+
executing-plans skill."
119+
```
120+
121+
## 8. Report
122+
123+
Print a summary table with issue numbers and URLs:
124+
125+
```text
126+
Issue Type Title URL
127+
----- ----- ---------------------------------------- ---
128+
#42 epic [Plan] <plan title> https://github.com/<repo>/issues/42
129+
#43 task [Task 1] <task title> https://github.com/<repo>/issues/43
130+
#44 task [Task 2] <task title> https://github.com/<repo>/issues/44
131+
...
132+
133+
Created 1 epic + N task issues. Label: plan.
134+
```
135+
136+
## Rules
137+
138+
- Never create issues without user confirmation of the parsed task list.
139+
- If `gh` is not available or not authed, stop (do not fall back to printing
140+
commands — the user chose auto-run).
141+
- If the plan file doesn't match the `writing-plans` format (no `### Task N:`
142+
headers), report the parse error and stop.
143+
- Only the `plan` label is applied — no triage schema, no per-project label
144+
config.
145+
- Each task issue links back to the plan file and the parent epic.
146+
- If the plan file path contains spaces or special characters, quote it.

.opencode/commands/setup.md

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
---
2+
description: Interactive project configurator. Interviews for app name, domain, repo, Signed-off-by identity, and accent color, then rewrites <app>/<domain>/[EMAIL] placeholders across the harness. Idempotent — re-runnable to update values.
3+
agent: build
4+
---
5+
6+
Replace template placeholders (`<app>`, `<domain>`, `[EMAIL]`, `kyaulabs/template`,
7+
`kyau <[EMAIL]>`) across the harness with real project values. Stores the
8+
answers in `.opencode/setup.json` for idempotent re-runs.
9+
10+
## 1. Check for existing manifest
11+
12+
If `.opencode/setup.json` exists, read it to pre-fill the interview with
13+
current values and enter re-run mode (old-value → new-value substitution).
14+
If absent, enter first-run mode (placeholder → value substitution).
15+
16+
## 2. Interview
17+
18+
Ask one question at a time. Only re-ask if the answer is empty.
19+
20+
1. **App name** — the public webroot directory name (e.g. `myapp`). Replaces
21+
`<app>` in the harness. Used in `<app>.<domain>` for the full URL.
22+
2. **Domain** — the production domain (e.g. `example.com`). Replaces `<domain>`.
23+
The full site URL is `<app>.<domain>`.
24+
3. **GitHub org/repo** — replaces `kyaulabs/template` (e.g. `myorg/myapp`).
25+
Used in `cliff.toml`, `composer.json`, `package.json`, and README.
26+
4. **Signed-off-by name** — committer name for the DCO footer (e.g. `kyau` or
27+
your name). Replaces `kyau` in Signed-off-by contexts. Must not be empty.
28+
5. **Signed-off-by email** — email for the DCO footer. Replaces `[EMAIL]`.
29+
Used in Signed-off-by, CODE_OF_CONDUCT, and SECURITY.
30+
6. **Accent color**`sky-blue` or `light-purple`. Toggles the default
31+
design tokens in `cdn/sass/_tokens.scss`. See the `frontend-design` skill.
32+
33+
When the user selects an accent color, show the palette:
34+
35+
- **sky-blue:** accent `#38bdf8`, soft `#87ceeb`, hover `#0ea5e9`
36+
- **light-purple:** accent `#a78bfa`, soft `#c4b5fd`, hover `#8b5cf6`
37+
38+
## 3. Build the token map
39+
40+
Construct the find/replace pairs in order (longest match first to avoid
41+
substring collisions):
42+
43+
| # | Find (exact string) | Replace with |
44+
|---|---|---|
45+
| 1 | `kyau <[EMAIL]>` | `{name} <{email}>` |
46+
| 2 | `kyaulabs/template` | `{org}/{repo}` |
47+
| 3 | `<app>` | `{app}` |
48+
| 4 | `<domain>` | `{domain}` |
49+
| 5 | `<username>` | `{name}` |
50+
| 6 | `[EMAIL]` | `{email}` |
51+
52+
Token #1 must precede #6 — if `[EMAIL]` fires first, `kyau <[EMAIL]>` won't
53+
match.
54+
55+
In **re-run mode**, use the values from the existing manifest as the find
56+
strings instead of the literal placeholder tokens. For example, if a prior run
57+
set app to `myapp`, the find string for token #3 is `myapp`, not `<app>`.
58+
59+
## 4. Verify
60+
61+
Print the interview answers as a table:
62+
63+
```text
64+
Token Current New
65+
--------------------------- --------------------- ---------------------
66+
<app> <app> myapp
67+
<domain> <domain> example.com
68+
kyaulabs/template kyaulabs/template myorg/myapp
69+
kyau <[EMAIL]> kyau <[EMAIL]> kyau <kyau@example.com>
70+
[EMAIL] [EMAIL] kyau@example.com
71+
<username> <username> kyau
72+
accent sky-blue (active) light-purple
73+
74+
Files to sweep (19 files; aurora/ excluded):
75+
AGENTS.md, .env.example, README.md, CODE_OF_CONDUCT.md, SECURITY.md,
76+
cliff.toml, composer.json, package.json,
77+
.opencode/commands/deploy.md, .opencode/commands/prime.md,
78+
.opencode/agents/debug.md, .opencode/agents/tdd.md,
79+
.opencode/skills/aurora-page/SKILL.md, .opencode/skills/database/SKILL.md,
80+
.opencode/skills/conventional-commits/SKILL.md,
81+
.opencode/skills/writing-plans/SKILL.md,
82+
.opencode/skills/finishing-a-development-branch/SKILL.md,
83+
.opencode/docs/build-pipeline.md, cdn/sass/_tokens.scss
84+
```
85+
86+
Ask: "Proceed with rewrites? (y/n)"
87+
88+
## 5. Apply
89+
90+
For each file in the sweep list:
91+
92+
1. Skip if the file does not exist (some may not apply to every project).
93+
2. Read the file.
94+
3. Apply token map substitutions in order (tokens #1 through #6 — always apply
95+
#1 before #6 to preserve the `kyau <[EMAIL]>` composite match).
96+
4. For `cdn/sass/_tokens.scss` only: apply the accent toggle (see below).
97+
5. Write the file back.
98+
6. Count per-file replacements.
99+
100+
**Accent toggle** (`cdn/sass/_tokens.scss`):
101+
102+
The file has two accent palettes as comment-toggle lines. For each accent
103+
choice, ensure the correct lines are uncommented and the other is commented.
104+
105+
For **sky-blue:**
106+
- `--accent: #38bdf8;` — uncommented (ensure no leading `// `)
107+
- `--accent-soft: #87ceeb;` — uncommented
108+
- `// --accent: #a78bfa;` — commented
109+
- `// --accent-soft: #c4b5fd;` — commented
110+
- `--accent-hover: #0ea5e9;` — uncommented, value `#0ea5e9`
111+
112+
For **light-purple:**
113+
- `// --accent: #38bdf8;` — commented
114+
- `// --accent-soft: #87ceeb;` — commented
115+
- `--accent: #a78bfa;` — uncommented
116+
- `--accent-soft: #c4b5fd;` — uncommented
117+
- `--accent-hover: #8b5cf6;` — uncommented, value `#8b5cf6`
118+
119+
Use the Edit tool for the accent toggle — it is a small targeted change.
120+
For the token substitutions, use Edit with `replaceAll` for each token or
121+
`sed -i` when Edit would require many calls.
122+
123+
**Use `sed` for bulk token substitution:**
124+
125+
```bash
126+
# Token #1 (longest composite first)
127+
sed -i "s|kyau <[EMAIL]>|{name} <{email}>|g" <file>
128+
# Token #2
129+
sed -i "s|kyaulabs/template|{org}/{repo}|g" <file>
130+
# Token #3
131+
sed -i 's|<app>|{app}|g' <file>
132+
# Token #4
133+
sed -i 's|<domain>|{domain}|g' <file>
134+
# Token #5
135+
sed -i 's|<username>|{name}|g' <file>
136+
# Token #6 (after token #1 has already consumed the composite matches)
137+
sed -i 's|\[EMAIL\]|{email}|g' <file>
138+
```
139+
140+
Replace `{name}`, `{email}`, `{app}`, `{domain}`, `{org}`, `{repo}` with the
141+
actual interview values.
142+
143+
## 6. Save manifest
144+
145+
Write `.opencode/setup.json`:
146+
147+
```json
148+
{
149+
"setup_version": 1,
150+
"setup_date": "<ISO 8601 timestamp>",
151+
"app": "<app>",
152+
"domain": "<domain>",
153+
"repo": "<org>/<repo>",
154+
"signed_off_by_name": "<name>",
155+
"signed_off_by_email": "<email>",
156+
"accent": "<sky-blue | light-purple>"
157+
}
158+
```
159+
160+
## 7. Report
161+
162+
```text
163+
File Replacements
164+
-------------------------------------- ------------
165+
AGENTS.md 8
166+
.env.example 2
167+
README.md 12
168+
CODE_OF_CONDUCT.md 1
169+
SECURITY.md 1
170+
cliff.toml 2
171+
composer.json 1
172+
package.json 1
173+
.opencode/commands/deploy.md 8
174+
.opencode/commands/prime.md 2
175+
.opencode/agents/debug.md 6
176+
.opencode/agents/tdd.md 1
177+
.opencode/skills/aurora-page/SKILL.md 4
178+
.opencode/skills/database/SKILL.md 3
179+
.opencode/skills/conventional-commits/SKILL.md 4
180+
.opencode/skills/writing-plans/SKILL.md 1
181+
.opencode/skills/finishing-a-development-branch/SKILL.md 1
182+
.opencode/docs/build-pipeline.md 1
183+
cdn/sass/_tokens.scss accent: light-purple
184+
-------------------------------------- ------------
185+
TOTAL 59 replacements across 19 files
186+
```
187+
188+
Remind the user:
189+
190+
- Review changes with `git diff`.
191+
- Run `/prime` if `CONTEXT.md` needs domain content (glossary, entities).
192+
- The aurora/ submodule was NOT touched — it maintains its own copy of
193+
harness files.
194+
- Re-run `/setup` to change values; the manifest enables idempotent updates.
195+
196+
## Rules
197+
198+
- Never touch the `aurora/` directory — it is a git submodule with its own
199+
copies of AGENTS.md, CODE_OF_CONDUCT.md, SECURITY.md.
200+
- Never touch `.semgrep/kyaulabs.yml` or semgrep rule names (`kyaulabs-*`) —
201+
these are rule identifiers, not placeholders.
202+
- Never touch `kyaulabs/aarch`, `kyaulabs/aurora`, `kyaulabs-bot` — these are
203+
real external resource references.
204+
- Apply token #1 (`kyau <[EMAIL]>`) before token #6 (`[EMAIL]`) — the
205+
composite match must fire before the substring.
206+
- Skip missing files silently — not all projects will have every file in the
207+
sweep list.
208+
- After successful rewrites, print the report. Do not commit or push anything.
209+
- If a file contains no matches for any token, skip it (do not write it back
210+
unchanged — the Edit/sed approach inherently leaves it alone).

0 commit comments

Comments
 (0)