# pi-release-scribe

Changelog and CI/CD release notes generator for Pi. This extension reads local Git history, classifies commits, suggests the next semver version, generates human-readable release notes, and optionally creates GitHub Releases — all without sending your code to external services.

The package is local-first, telemetry-free, and designed for both interactive Pi sessions and headless CI/CD workflows through GitHub Actions.

## Table of Contents

- [Overview](#overview)
- [Core Capabilities](#core-capabilities)
- [Command Surface](#command-surface)
- [LLM Tools](#llm-tools)
- [Documentation Map](#documentation-map)
- [Tech Stack](#tech-stack)
- [Getting Started](#getting-started)
- [Configuration](#configuration)
- [CI/CD](#cicd)
- [Privacy And Security](#privacy-and-security)
- [Development Workflow](#development-workflow)
- [Testing And Verification](#testing-and-verification)
- [Project Structure](#project-structure)
- [Publishing Notes](#publishing-notes)

## Overview

`pi-release-scribe` helps Pi generate release notes without manual copy-paste of Git history. It indexes commits since the latest tag, classifies them (features, fixes, breaking changes, maintenance), suggests the next semver version, and produces audience-aware release notes in multiple formats (markdown, GitHub, Keep a Changelog, Slack, JSON).

This repository is responsible for:

- Pi extension entrypoint and package manifest.
- Git repo discovery and identity detection (including GitHub remote parsing).
- Config schema, loading, validation, and local storage (`.pi/release-scribe.json`).
- Git tag detection, semantic version sorting, and fallback to initial release mode.
- Commit collection with bounded output, delimiter-safe parsing, PR/issue ref extraction.
- Conventional Commit parsing, fallback heuristic classification, and semver suggestion.
- Release notes rendering with audience modes (developer, client, internal, executive) and output formats.
- Prompt generation with structured JSON markers and no-invention instruction.
- Changelog insert/update with Keep a Changelog detection and dry-run preview.
- Annotated local tag creation with safety validation and optional push.
- GitHub Release creation and update via `gh` CLI or `GITHUB_TOKEN` API after explicit approval.
- Pi commands, LLM tools, status UI, release panel, and CI entrypoint script.
- Headless CI/CD support with `release-scribe:ci` bundled script and GitHub Actions documentation.

## Core Capabilities

| Capability                  | Status                                                               |
| --------------------------- | -------------------------------------------------------------------- |
| Repo discovery              | Implemented through git root, branch, remote detection               |
| Config management           | Implemented through `/release-scribe-config`                         |
| Status health               | Implemented through `/release-scribe-status`                         |
| Status UI widget            | Implemented through status bar widget (ready/no-tag/drafting/etc)    |
| Commit collection           | Bounded, delimiter-safe, PR/issue ref extraction                     |
| Conventional Commit parsing | Deterministic with type, scope, breaking detection                   |
| Fallback classifier         | Heuristic keyword matching with confidence scoring                   |
| Semver suggestion           | Based on classified changes with configurable bump rules             |
| Release notes rendering     | Audience modes + output formats + structured JSON markers            |
| Assistant prompt contract   | No-invention instruction, markdown-first, JSON markers               |
| Changelog update            | Dry-run preview, Keep a Changelog detection, safe insert             |
| Annotated tag creation      | Semver validation, existence check, dirty-block, optional push       |
| GitHub Release              | Draft-first via `gh` CLI or `GITHUB_TOKEN`, published with flag      |
| Monorepo release notes      | Helper APIs available; command UX still limited                      |
| PR enrichment               | Optional helper, explicit network only                               |
| Local templates             | Helper support for repo-local templates                              |
| Asset upload safety         | Planning helpers only; upload requires explicit caller integration   |
| Release quality score       | Warnings for missing migrations, dirty/shallow repos, low confidence |
| CI/CD support               | Headless script, GitHub Actions docs, `--yes` for CI approval        |
| Tool output bounding        | All tools use bounded text results (50 KB default)                   |

## Command Surface

```text
/release-scribe-status [--json]
/release-scribe-config [--create]
/release-scribe-draft [--from <ref>] [--to <ref>] [--audience <mode>] [--format <format>] [--json]
/release-scribe-changelog [--dry-run] [--yes] [--from <ref>] [--to <ref>] [--output <path>]
/release-scribe-tag <version> [--push] [--allow-dirty] [--yes] [--message <text>]
/release-scribe-publish <tag> [--draft] [--publish] [--update] [--notes <text>] [--title <text>] [--yes]
/release-scribe-panel
/release-scribe-ci-help
```

### Command details

**`/release-scribe-status`** — Show release-scribe health snapshot. Reports git root, current branch, latest tag, commit count since tag, working tree state, config health, GitHub remote detection, and `gh` CLI auth status. Supports `--json` for machine-readable output.

```text
release-scribe: ready
repoRoot: /path/to/repo
branch: main
latestTag: v1.2.0
commitCount: 14
workingTree: clean
configPath: /path/to/repo/.pi/release-scribe.json
configEnabled: true
github: owner/repo
ghAuth: username (github.com)
```

**`/release-scribe-config`** — Show or create config. Add `--create` to write the default config file when it does not exist.

**`/release-scribe-draft`** — Generate release notes draft from commits since latest tag and queue it as an assistant prompt. Supports `--from`/`--to` for custom commit range, `--audience` (developer/client/internal/executive), `--format` (markdown/github/keep-a-changelog/slack/json), and `--json` for structured output without prompting the agent.

```text
/release-scribe-draft
/release-scribe-draft --audience client --format slack
/release-scribe-draft --from v1.1.0 --to v1.2.0 --json
```

**`/release-scribe-changelog`** — Preview or update `CHANGELOG.md`. DRY-RUN by default (no file written). Use `--yes` to write without confirmation. Falls back to deterministic local release notes when no draft exists.

```text
/release-scribe-changelog
/release-scribe-changelog --yes
/release-scribe-changelog --from v1.1.0 --to v1.2.0 --dry-run
```

**`/release-scribe-tag`** — Create an annotated local git tag. Validates semver, checks tag existence (local and remote), requires clean working tree by default. Supports `--push`, `--allow-dirty`, `--yes`, and `--message`.

```text
/release-scribe-tag v1.3.0
/release-scribe-tag v1.3.0 --push
/release-scribe-tag v1.3.0 --allow-dirty --yes
```

**`/release-scribe-publish`** — Create or update a GitHub Release. SAFE DEFAULTS: dry-run, no network. Use `--draft` to create a draft (default safe mode), `--update` to update existing, `--publish` for final release. Never deletes releases or tags.

```text
/release-scribe-publish v1.3.0 --draft
/release-scribe-publish v1.3.0 --publish --yes
/release-scribe-publish v1.3.0 --update --draft
```

**`/release-scribe-panel`** — Show the latest release notes draft in the editor or as text. Run `/release-scribe-draft` first to generate a draft.

**`/release-scribe-ci-help`** — Print CI/CD usage examples including GitHub Actions workflow templates and `release-scribe:ci` script usage.

## LLM Tools

```text
release_scribe_collect_commits
release_scribe_classify_commits
release_scribe_suggest_version
release_scribe_generate_notes_context
release_scribe_stats
release_scribe_update_changelog
release_scribe_github_release
```

Tool outputs are bounded and truncated to Pi-style limits before reaching the model. Mutating tools (`update_changelog`, `github_release`) default to dry-run and require explicit `apply`, `publish`, or `update` flags.

| Tool                                    | Purpose                                                |
| --------------------------------------- | ------------------------------------------------------ |
| `release_scribe_collect_commits`        | Collect commits from a git range with bounded metadata |
| `release_scribe_classify_commits`       | Classify commits into release categories               |
| `release_scribe_suggest_version`        | Recommend the next semver version                      |
| `release_scribe_generate_notes_context` | Build structured release context for LLM               |
| `release_scribe_stats`                  | Show release-scribe health snapshot                    |
| `release_scribe_update_changelog`       | Preview or update CHANGELOG.md (dry-run default)       |
| `release_scribe_github_release`         | Create or update GitHub Release (draft default)        |

## Documentation Map

Use this reading order for review or release handoff:

1. `docs/PRIVACY_SECURITY.md` for local-first behavior, secrets handling, and telemetry stance.
2. `docs/CI_GITHUB_ACTIONS.md` for headless CI/CD workflow setup and troubleshooting.
3. `docs/RELEASE.md` for package release checklist and maintainer gates.

## Tech Stack

| Area                | Choice                                         |
| ------------------- | ---------------------------------------------- |
| Runtime target      | Pi extension runtime through TypeScript loader |
| Development runtime | Bun                                            |
| Language            | TypeScript                                     |
| Formatter/linter    | Biome                                          |
| Schema validation   | TypeBox                                        |
| Test runner         | `bun test`                                     |
| Publish target      | npm package with Pi manifest                   |

## Getting Started

Install published package:

```bash
pi install npm:pi-release-scribe
/reload
/release-scribe-status
```

Run first draft:

```text
/release-scribe-draft
/release-scribe-panel
/release-scribe-changelog --dry-run
```

Local package smoke:

```bash
bun install
bun run build
pi install .
/reload
/release-scribe-status
```

Direct extension smoke (when testing built output without package install):

```bash
pi install ./dist/index.ts
/reload
```

Repo-local files created or used by the package:

```text
.pi/release-scribe.json
.pi/release-scribe/latest-draft.md
.pi/release-scribe/latest-draft.json
```

## Configuration

Default config path:

```text
.pi/release-scribe.json
```

Create it with `/release-scribe-config --create`.

Key options:

| Option                                              | Purpose                                        |
| --------------------------------------------------- | ---------------------------------------------- |
| `enabled`                                           | Enable or disable release features for repo    |
| `tagPattern`                                        | Glob pattern for release tags (default: `v*`)  |
| `versionPrefix`                                     | Tag prefix for new versions (default: `v`)     |
| `defaultAudience`                                   | Default audience mode for draft                |
| `defaultFormat`                                     | Default output format                          |
| `changelogPath`                                     | Path to CHANGELOG.md (relative to repo root)   |
| `includeScopes` / `excludeScopes`                   | Filter commits by conventional commit scope    |
| `hideCategories`                                    | Categories to hide from public release notes   |
| `collapseMaintenance`                               | Collapse maintenance entries under one heading |
| `linkCommits` / `linkPullRequests`                  | Generate links in release notes                |
| `semver.allowZeroMajorBreakingAsMinor`              | Breaking changes at 0.x are minor              |
| `semver.depsAsPatch` / `semver.securityAsPatch`     | Dependency/security bumps as patch             |
| `git.requireCleanWorkingTreeForTag`                 | Require clean tree for tag creation            |
| `github.draftByDefault`                             | Create drafts instead of published releases    |
| `safety.requireConfirmBeforeFileWrite` / `Tag/Push` | Require explicit approval for mutations        |
| `output.maxCommits` / `maxCommitBodyChars`          | Bound commit collection and body text          |

## Post-MVP hardening

Post-MVP helper modules exist for monorepos, PR enrichment, local templates, additional providers, asset upload planning, and release quality scoring. These helpers are not full end-user workflows yet; public commands remain focused on single-repo draft/changelog/tag/GitHub release flows.

Optional GitHub enrichment can fetch PR title/body/labels/contributors only when caller explicitly opts into network and `GITHUB_TOKEN` or `GH_TOKEN` is available.

Repo-local templates live under:

```text
.pi/release-scribe/templates/<name>.md
```

Allowed template variables: `{{version}}`, `{{title}}`, `{{summary}}`, `{{compareUrl}}`, `{{markdown}}`, `{{contributors}}`, `{{generatedAt}}`.

Asset upload helpers only plan allowed uploads and require an explicit filename allowlist such as `*.tgz`; no asset is uploaded by default.

Release quality scoring reports actionable warnings for breaking changes without migration notes, low-confidence classification, unclassified commits, missing tags, dirty tree, and shallow clone.

## CI/CD

`pi-release-scribe` supports headless CI/CD via its bundled script `release-scribe:ci`:

```bash
bun run release-scribe:ci -- --tag v1.3.0 --draft --yes
```

The script requires no interactive input. It detects `CI`/`GITHUB_ACTIONS` environment variables and auto-adopts headless mode. GitHub Actions examples include draft-only, publish, audience/format overrides, and Pi print mode alternatives.

See `docs/CI_GITHUB_ACTIONS.md` for full workflow templates and troubleshooting.

See `/release-scribe-ci-help` for a quick CLI reference.

## Privacy And Security

`pi-release-scribe` is local-first.

- No telemetry.
- No default network calls for draft, changelog, tag, or status operations.
- Network usage only for explicit GitHub Release operations or optional enrichment, and only with approval flags/confirmation.
- No token storage — GitHub authentication uses `gh` CLI or `GITHUB_TOKEN`/`GH_TOKEN` env at runtime.
- No raw large diffs sent to the prompt by default.
- `/release-scribe-draft` sends bounded Git metadata (subjects, authors, SHAs, classifications) to the model provider configured in Pi; this package itself sends no telemetry.
- All subprocess calls use fixed argv arrays (no shell interpolation).
- File writes, tag creation, tag push, and GitHub publish all require explicit flags and/or confirmation.

See `docs/PRIVACY_SECURITY.md` for full details.

## Development Workflow

Install dependencies:

```bash
bun install
```

Run local checks:

```bash
bun run check
```

Build package output:

```bash
bun run build
```

Run npm package dry-run:

```bash
bun run pack:dry-run
```

Run audit before publish:

```bash
bun run prepublish:audit
```

## Testing And Verification

Fast verification before handoff:

```bash
bun run typecheck
bun run lint
bun test ./test
bun run pack:dry-run
```

Release verification should also include:

```bash
bun run smoke:release-flow
pi install .
/reload
/release-scribe-status
/release-scribe-draft --json
```

## Project Structure

```text
.
|-- docs/
|   |-- CI_GITHUB_ACTIONS.md
|   |-- PRIVACY_SECURITY.md
|   `-- RELEASE.md
|-- scripts/
|   |-- build-package.ts
|   |-- audit-npm-package.ts
|   |-- release-scribe-ci.ts
|   `-- smoke-release-flow.ts
|-- src/
|   |-- commands/
|   |   |-- changelog.ts
|   |   |-- ciHelp.ts
|   |   |-- config.ts
|   |   |-- context.ts
|   |   |-- draft.ts
|   |   |-- publish.ts
|   |   |-- status.ts
|   |   `-- tag.ts
|   |-- config/
|   |   |-- schema.ts
|   |   `-- load.ts
|   |-- git/
|   |   |-- commits.ts
|   |   |-- diff.ts
|   |   |-- repo.ts
|   |   |-- tags.ts
|   |   `-- workingTree.ts
|   |-- github/
|   |   |-- api.ts
|   |   `-- ghCli.ts
|   |-- release/
|   |   |-- changelog.ts
|   |   |-- classifier.ts
|   |   |-- context.ts
|   |   |-- model.ts
|   |   |-- parser.ts
|   |   |-- prompt.ts
|   |   |-- renderer.ts
|   |   |-- safety.ts
|   |   |-- templates.ts
|   |   |-- types.ts
|   |   `-- version.ts
|   |-- store/
|   |   `-- draftStore.ts
|   |-- tools/
|   |   `-- register.ts
|   |-- ui/
|   |   |-- releasePanel.ts
|   |   `-- statusWidget.ts
|   |-- util/
|   |   |-- exec.ts
|   |   |-- ghAuth.ts
|   |   |-- json.ts
|   |   `-- truncate.ts
|   `-- extension.ts
|-- test/
|-- index.ts
|-- package.json
`-- README.md
```

## Publishing Notes

Publish path:

1. Complete maintainer release checklist (see `docs/RELEASE.md`).
2. Run `bun run check`.
3. Run `bun run pack:dry-run`.
4. Run `bun run prepublish:audit`.
5. Run `bun run smoke:release-flow`.
6. Create and push release tag.
7. Let `.github/workflows/publish.yml` publish through npm trusted publishing/OIDC.

The Pi manifest is declared in `package.json`:

```json
{
  "pi": {
    "extensions": ["./dist/index.ts"]
  }
}
```

The npm package file whitelist includes runtime dist, selected public docs, README, license, and package metadata.

## Troubleshooting

| Condition                 | Behavior                                                |
| ------------------------- | ------------------------------------------------------- |
| Not a git repo            | Status reports disabled with instruction to enter repo  |
| No tags found             | Initial release mode — collects all commits from root   |
| Shallow clone             | Warns and fails in CI with `fetch-depth: 0` instruction |
| Dirty tree during tag     | Blocks unless `--allow-dirty` is set                    |
| Tag already exists        | Blocks with instruction to inspect existing tag         |
| `gh` not authenticated    | Falls back to `GITHUB_TOKEN` or reports clear error     |
| GitHub API rate/auth fail | Reports status, does not retry aggressively             |
| Too many commits          | Truncates, warns, suggests manual range                 |
| Assistant JSON invalid    | Keeps markdown, warns structured parse failed           |
