-
Notifications
You must be signed in to change notification settings - Fork 21
feat(AI-81): author stage-chapters SKILL.md scaffold #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
dastratakos
merged 6 commits into
main
from
dean/ai-81-issue-14-author-skillmd-scaffold-frontmatter-prerequisites
May 4, 2026
Merged
Changes from 5 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
bc2170d
feat(AI-81): author stage-chapters SKILL.md scaffold
dastratakos a14ab7b
fix(AI-81): correct stage-chapters SKILL.md per PR review
dastratakos 6653b18
fix(AI-81): keep full origin/HEAD ref so base works in single-branch …
dastratakos 01f1cc9
fix(AI-81): align chapter diff with SPA rendering, fix BSD mktemp tem…
dastratakos 11b7833
fix(AI-81): add origin/main and origin/master to base-detection fallb…
dastratakos 1d2ff0f
fix(AI-81): fail fast when merge-base cannot be computed
dastratakos File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| --- | ||
| name: stage-chapters | ||
| description: Generate Stage chapters for the current local git branch and open them in a browser for review. | ||
| user-invocable: true | ||
| --- | ||
|
|
||
| # stage-chapters | ||
|
|
||
| Generates a Stage chapter run for the current local git branch and opens it in a browser. The skill detects the base ref, computes the diff, generates chapters from it, writes a JSON file matching the `stage-cli` schema, and hands the file to `stage-cli show` to launch the SPA. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| Run these checks before any other work. If either fails, stop with the error message — do not continue. | ||
|
|
||
| 1. **`stage-cli` is installed.** Run `which stage-cli`. If it exits non-zero, instruct the user: | ||
|
|
||
| ``` | ||
| stage-cli is not installed. Run: | ||
|
|
||
| npm install -g stagereview | ||
|
|
||
| Then retry /stage-chapters. | ||
| ``` | ||
|
|
||
| Stop. | ||
|
|
||
| 2. **The current directory is a git repo.** Run `git rev-parse --is-inside-work-tree`. If it does not print `true`, stop with: | ||
|
|
||
| ``` | ||
| /stage-chapters must be run inside a git repository. | ||
| ``` | ||
|
|
||
| ## Step 1 — Detect base ref | ||
|
|
||
| Find the branch the user reviews against. Try each of the following in order; the first that succeeds becomes `<base>`: | ||
|
|
||
| 1. `git rev-parse --abbrev-ref origin/HEAD 2>/dev/null` — typically prints `origin/main`. Use the full output (e.g. `origin/main`) as `<base>`; do **not** strip `origin/`, because the bare name (`main`) may not exist locally in single-branch clones. | ||
| 2. `git rev-parse --verify main 2>/dev/null` — local `main` branch; use `main` as `<base>`. | ||
| 3. `git rev-parse --verify master 2>/dev/null` — older repos; use `master` as `<base>`. | ||
| 4. `git rev-parse --verify origin/main 2>/dev/null` — remote-tracking fallback when `origin/HEAD` is unset; use `origin/main` as `<base>`. | ||
| 5. `git rev-parse --verify origin/master 2>/dev/null` — remote-tracking fallback for older repos; use `origin/master` as `<base>`. | ||
|
|
||
| If all five fail, stop with: | ||
|
|
||
| ``` | ||
| No default branch detected. Tried origin/HEAD, main, master, origin/main, and origin/master. | ||
| ``` | ||
|
|
||
| `<base>` is whatever ref expression was verified above and is passed verbatim to `git merge-base` / `git rev-parse` in Step 2. | ||
|
|
||
| ## Step 2 — Get the diff | ||
|
|
||
| Compute the merge-base and dump the unified diff for the committed range only: | ||
|
|
||
| ```bash | ||
| MERGE_BASE=$(git merge-base <base> HEAD) | ||
| HEAD_SHA=$(git rev-parse HEAD) | ||
|
|
||
| git diff "$MERGE_BASE..HEAD" | ||
|
dastratakos marked this conversation as resolved.
|
||
| ``` | ||
|
|
||
| `git diff <merge-base>..HEAD` covers exactly the commits on the branch since it diverged from the base — the same range the SPA renders for a `committed` run (`baseSha..headSha` in `packages/cli/src/routes/diff.ts`). Save the full diff text into context for Step 3. | ||
|
|
||
| This skill scopes review to *committed* work. If the user has uncommitted changes to tracked files, instruct them to commit first; mixing committed and working-tree changes into a single run would produce `hunkRefs`/`lineRefs` that don't line up with the diff the SPA serves. | ||
|
|
||
| `MERGE_BASE` and `HEAD_SHA` are full 40-character SHAs that feed directly into the JSON `scope` field in Step 4. | ||
|
|
||
| ## Step 3 — Cluster + narrate | ||
|
|
||
| > **TODO:** See Issue 11 for the chapter generation prompt port. For now, leave this step as a placeholder. The next revision of this skill will produce a `chapters` array shaped per the schema documented in Step 4. | ||
|
dastratakos marked this conversation as resolved.
|
||
|
|
||
| ## Step 4 — Write JSON file | ||
|
|
||
| Compute a unique temp path. The trailing `XXXXXX` (with no suffix after) is required by macOS BSD `mktemp` — placing characters after the X's causes BSD `mktemp` to return the template verbatim instead of substituting random characters: | ||
|
|
||
| ```bash | ||
| TMPFILE=$(mktemp "${TMPDIR:-/tmp}/stage-chapters.XXXXXX") | ||
| ``` | ||
|
|
||
| `stage-cli show` reads JSON regardless of file extension, so the missing `.json` suffix is fine. | ||
|
|
||
| The `${TMPDIR:-/tmp}` fallback matters on macOS, where `os.tmpdir()` resolves to `/var/folders/...` but `$TMPDIR` is not always set in every shell. Avoid `date +%s%N` — the `%N` (nanoseconds) format is a GNU extension and on macOS BSD `date` it emits a literal `N`, breaking uniqueness. | ||
|
|
||
| Write a JSON file at `"$TMPFILE"` matching the shape below. The file must validate against `ChaptersFileSchema` in `packages/cli/src/schema.ts`; mismatched fields will be rejected by `stage-cli show`. | ||
|
|
||
| High-level shape: | ||
|
|
||
| ``` | ||
| { scope: {...}, chapters: [...], generatedAt: "..." } | ||
| ``` | ||
|
|
||
| Full example: | ||
|
|
||
| ```jsonc | ||
| { | ||
| "scope": { | ||
| "kind": "committed", | ||
| // Set baseSha = mergeBaseSha = $MERGE_BASE so the SPA renders | ||
| // baseSha..headSha — the same range chapters were generated from. | ||
| "baseSha": "<MERGE_BASE>", | ||
| "headSha": "<HEAD_SHA>", | ||
| "mergeBaseSha": "<MERGE_BASE>" | ||
| }, | ||
| "chapters": [ | ||
| { | ||
| "id": "ch-1", | ||
| "order": 1, | ||
| "title": "Short imperative title", | ||
| "summary": "Why this chapter matters to the reviewer.", | ||
| "hunkRefs": [ | ||
| { "filePath": "path/to/file.ts", "oldStart": 42 } | ||
| ], | ||
| "keyChanges": [ | ||
| { | ||
| "content": "A judgment-call question for the reviewer (not source code).", | ||
| "lineRefs": [ | ||
| { | ||
| "filePath": "path/to/file.ts", | ||
| "side": "additions", | ||
| "startLine": 50, | ||
| "endLine": 55 | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| "generatedAt": "2026-05-04T12:34:56.000Z" | ||
| } | ||
| ``` | ||
|
|
||
| Field rules: | ||
|
|
||
| | Field | Constraint | | ||
| |-------|------------| | ||
| | `scope.kind` | `"committed"` or `"workingTree"` | | ||
| | `scope.ref` | Required when `kind` is `"workingTree"`; one of `"work"`, `"staged"`, `"unstaged"` | | ||
| | `scope.baseSha` / `headSha` / `mergeBaseSha` | Full 40-character lowercase hex SHAs | | ||
| | `chapters[].id` | Non-empty, unique within the run | | ||
| | `chapters[].order` | Positive integer (1-indexed) | | ||
| | `chapters[].hunkRefs[].oldStart` | Non-negative integer — the pre-image start line from the unified-diff `@@` header (`0` for new files) | | ||
| | `chapters[].keyChanges[].lineRefs` | Array with at least one entry | | ||
| | `lineRefs[].side` | `"additions"` (right side) or `"deletions"` (left side) | | ||
| | `lineRefs[].startLine` / `endLine` | Positive integers; `endLine >= startLine` | | ||
| | `generatedAt` | ISO 8601 datetime string | | ||
|
|
||
| ## Step 5 — Display generated chapters | ||
|
|
||
| Hand the file to `stage-cli`: | ||
|
|
||
| ```bash | ||
| stage-cli show "$TMPFILE" | ||
| ``` | ||
|
|
||
| `stage-cli show` validates the JSON, inserts a new `chapter_run` plus chapters and key changes into the local SQLite database, boots a loopback HTTP server, and opens the browser to the new run. The command stays running and serves the SPA until the user kills it with Ctrl+C — invoke it as the final command in the workflow rather than expecting it to print a value and exit. | ||
|
|
||
| Do not pass a `runId` and do not call a separate `stage-cli ingest`. `show <path>` does ingestion and serving in one step. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.