pi-baton 0.7.1 → 0.7.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/CHANGELOG.md CHANGED
@@ -4,6 +4,27 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  This project follows semantic versioning.
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ### Changed
10
+
11
+ - Bump package version to `0.7.3` for the next patch release.
12
+
13
+ ## [0.7.2] - 2026-07-04
14
+
15
+ ### Added
16
+
17
+ - `/baton:status` now shows the most recent finished run summary (state, last step, iteration, run directory) after a run reaches `completed` or `failed`, with clear finished-run framing instead of the no-active-run message.
18
+
19
+ - Buy Me a Coffee sponsor button in README and native GitHub funding link via `.github/FUNDING.yml`.
20
+
21
+ ### Changed
22
+
23
+ - Merged Dependabot PR #14: bump `@earendil-works/pi-ai` devDependency from 0.78.1 to 0.80.2 (type-check clean, 57/57 tests passing).
24
+ - Removed leftover template scaffolding (`prompts/`, `themes/`, `skills/`).
25
+ - Deleted stale template bootstrap docs (`docs/examples.md`, `docs/github-template.md`, `docs/repository-settings.md`, `docs/typescript.md`, `docs/template-checklist.md`) that shipped to npm consumers describing non-existent commands.
26
+ - Updated ROADMAP.md to reflect current version (0.7.2), test count (57), and seed completion status for S-101, S-102, S-103, S-105.
27
+
7
28
  ## [0.7.1] - 2026-06-27
8
29
 
9
30
  ### Changed
@@ -128,3 +149,4 @@ This project follows semantic versioning.
128
149
  - Initial Pi package template.
129
150
  - Example extension, Agent Skill, prompt, and theme.
130
151
  - CI and npm Trusted Publishing workflow.
152
+
package/README.md CHANGED
@@ -11,6 +11,7 @@
11
11
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
12
12
  [![Pi package](https://img.shields.io/badge/pi-package-purple.svg)](https://pi.dev/packages)
13
13
  [![Trusted Publishing](https://img.shields.io/badge/npm-Trusted%20Publishing-blue.svg)](docs/release.md)
14
+ <a href="https://buymeacoffee.com/ekawano114m"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" width="217" height="60"></a>
14
15
 
15
16
  > Run YAML-defined review loops in Pi with per-step model switching and isolated step context.
16
17
 
@@ -36,7 +37,7 @@ pi install npm:pi-baton
36
37
  Pin a specific version when you want reproducible installs:
37
38
 
38
39
  ```bash
39
- pi install npm:pi-baton@0.7.1
40
+ pi install npm:pi-baton@0.7.3
40
41
  ```
41
42
 
42
43
  Install into the current project instead of your user Pi settings:
@@ -134,7 +135,7 @@ steps:
134
135
  | `agents/` | Builtin `worker` and `reviewer` subagent definitions |
135
136
  | `workflows/` | Builtin `default-review-loop.yaml` |
136
137
  | `assets/` | README / package branding assets |
137
- | `docs/` | Release and maintainer docs |
138
+ | `docs/` | Release and maintainer documentation |
138
139
 
139
140
  ## Development
140
141
 
@@ -0,0 +1,249 @@
1
+ # Incident — 2026-07-04 `Publish to npm` failed with duplicate-version E403
2
+
3
+ > Status: **investigation report only.** No release workflow, package version,
4
+ > CHANGELOG, npm registry state, or release was changed to produce this document.
5
+ > Correction options below are proposals for a separate follow-up issue.
6
+
7
+ ## Summary
8
+
9
+ The `Publish to npm` run
10
+ [28704529442](https://github.com/eiei114/pi-baton/actions/runs/28704529442)
11
+ (`v0.7.2`, dispatched 2026-07-04) failed at the final `npm publish` step with:
12
+
13
+ ```text
14
+ npm error code E403
15
+ npm error 403 403 Forbidden - PUT https://registry.npmjs.org/pi-baton
16
+ npm error 403 You cannot publish over the previously published versions: 0.7.2.
17
+ ```
18
+
19
+ **Root cause (classification: trigger/configuration):** a version-bump push to
20
+ `main` fans out into **two concurrent `publish.yml` runs** for the same version,
21
+ keyed by **different concurrency groups** so they are not serialized. The
22
+ "Skip already published version" guard is a non-atomic check-then-publish
23
+ (TOCTOU) and was defeated by ~11s of npm registry propagation latency, so the
24
+ losing run reached `npm publish` after the winning run had already published
25
+ `0.7.2`.
26
+
27
+ This is **not** an authentication / Trusted Publishing failure (OIDC provenance
28
+ was signed successfully) and **not** a duplicate-version-at-dispatch (the version
29
+ was unpublished when the run started).
30
+
31
+ **Impact:** none on the registry. `pi-baton@0.7.2` is correctly published and is
32
+ `dist-tags.latest`. The failed run is a harmless duplicate that lost the race.
33
+
34
+ ## Evidence
35
+
36
+ ### Failed run
37
+
38
+ | Field | Value |
39
+ | --- | --- |
40
+ | Run | [`Publish to npm` · 28704529442](https://github.com/eiei114/pi-baton/actions/runs/28704529442) |
41
+ | Workflow | `.github/workflows/publish.yml` |
42
+ | Event / trigger | `workflow_dispatch` |
43
+ | Ref checked out | `v0.7.2` (tag), via `actions/checkout@v7` (`ref: v0.7.2`) |
44
+ | Package | `pi-baton@0.7.2` |
45
+ | Started / failed | 2026-07-04T11:18:38Z / 2026-07-04T11:19:11Z |
46
+ | Failed step | `Publish to npm` (`npm publish --access public`) |
47
+ | Conclusion | failure, exit code 1 |
48
+
49
+ Step-by-step status (from the run): `Set up job`, `Checkout`, `Setup Node.js`,
50
+ `Ensure npm supports trusted publishing`, `Install dependencies`, `Validate
51
+ package`, `Skip already published version` all **passed**; `Publish to npm`
52
+ **failed**.
53
+
54
+ Failure output excerpt (from the failed step log):
55
+
56
+ ```text
57
+ npm notice 📦 pi-baton@0.7.2
58
+ ...
59
+ npm notice Publishing to https://registry.npmjs.org/ with tag latest and public access
60
+ npm notice publish Signed provenance statement with source and build information from GitHub Actions
61
+ npm notice publish Provenance statement published to transparency log: https://search.sigstore.dev/?logIndex=2069634820
62
+ npm error code E403
63
+ npm error 403 403 Forbidden - PUT https://registry.npmjs.org/pi-baton - You cannot publish over the previously published versions: 0.7.2.
64
+ npm error A complete log of this run can be found in: /home/runner/.npm/_logs/2026-07-04T11_19_08_227Z-debug-0.log
65
+ ##[error]Process completed with exit code 1.
66
+ ```
67
+
68
+ Note: provenance **was** signed (Trusted Publishing / OIDC worked); the failure is
69
+ the publish PUT, not authentication.
70
+
71
+ ### Who dispatched it (trigger chain)
72
+
73
+ The `workflow_dispatch` run was dispatched by the `Auto Release` workflow, not by
74
+ a human clicking "Run workflow" in the UI:
75
+
76
+ - PR #25 (`chore/sponsor-funding-patch-20260704`) merged to `main` at
77
+ **11:18:31Z**, bumping `package.json` to `0.7.2`.
78
+ - The merge push fired two workflows on `main`:
79
+ - [`Publish to npm` · 28704526901](https://github.com/eiei114/pi-baton/actions/runs/28704526901)
80
+ (event `push`, ref `refs/heads/main`) — **success**.
81
+ - [`Auto Release` · 28704526903](https://github.com/eiei114/pi-baton/actions/runs/28704526903)
82
+ (event `push`, ref `refs/heads/main`) — **success**.
83
+ - `Auto Release` detected the version bump, created tag `v0.7.2` and the GitHub
84
+ Release (11:18:35–37Z), then ran its final step:
85
+ `gh workflow run publish.yml --ref v0.7.2 -f ref=v0.7.2`
86
+ (log: `Run TAG="v0.7.2"` → `gh workflow run publish.yml --ref "$TAG" -f ref="$TAG"`).
87
+ - That dispatch produced the failed run **28704529442** at **11:18:38Z**.
88
+
89
+ So a single version-bump merge produced **two** `publish.yml` runs for `0.7.2`:
90
+ one from the `push` trigger (main) and one from `Auto Release`'s explicit
91
+ `workflow_dispatch` (v0.7.2). This double-trigger is consistent with the design
92
+ documented in [`docs/release.md`](../release.md) (the push trigger and the
93
+ auto-release handoff both fire; the tag/`release.published` triggers are
94
+ unreliable for `GITHUB_TOKEN`-created tags, which is why auto-release dispatches
95
+ explicitly).
96
+
97
+ ### Race timeline (all times UTC)
98
+
99
+ | Time | Run | Event |
100
+ | --- | --- | --- |
101
+ | 11:18:31 | 28704526901 / 28704526903 | merge push to `main` fires `publish.yml` (push) + `auto-release.yml` |
102
+ | 11:18:35–37 | 28704526903 | `Auto Release` creates tag `v0.7.2`, release, dispatches `publish.yml` |
103
+ | 11:18:38 | 28704529442 | dispatched `publish.yml` (v0.7.2) starts — the failed run |
104
+ | 11:18:52 | 28704526901 | skip guard says `Publishing pi-baton@0.7.2.` (0.7.2 not yet on npm) |
105
+ | **11:18:56** | **28704526901** | **`+ pi-baton@0.7.2` — push run publishes 0.7.2** |
106
+ | 11:19:07 | 28704529442 | skip guard runs `npm view pi-baton@0.7.2 version` → **404** (skip=false) |
107
+ | 11:19:08 | 28704529442 | prints `Publishing pi-baton@0.7.2.`, starts `npm publish` |
108
+ | 11:19:11 | 28704529442 | `E403` — cannot publish over `0.7.2` (already published 11s earlier) |
109
+
110
+ The decisive detail: the failed run's `npm view pi-baton@0.7.2 version` returned
111
+ **404 at 11:19:07**, ~11 seconds **after** the push run actually published
112
+ `0.7.2` at 11:18:56. The skip guard therefore proceeded, and `npm publish` hit
113
+ the real-time conflict.
114
+
115
+ ### npm public state (read-only)
116
+
117
+ ```console
118
+ $ npm view pi-baton version dist-tags.latest
119
+ 0.7.2
120
+ { latest: '0.7.2' }
121
+
122
+ $ npm view pi-baton time --json
123
+ {
124
+ "0.7.2": "2026-07-04T11:18:56.171Z",
125
+ ...
126
+ }
127
+ ```
128
+
129
+ The `0.7.2` timestamp was published by the winning push run (28704526901).
130
+
131
+ `pi-baton@0.7.2` is present, is `dist-tags.latest`, and was published at
132
+ 11:18:56Z — i.e. by the parallel push run (28704526901), not by the failed run.
133
+ Published versions: `0.2.2, 0.2.3, 0.3.0, 0.4.0, 0.5.0, 0.6.0, 0.7.0, 0.7.1,
134
+ 0.7.2`. No registry correction is needed.
135
+
136
+ ## Cause classification
137
+
138
+ **Trigger / configuration** — specifically a concurrent-duplicate-publish race:
139
+
140
+ 1. **Double trigger for one version bump.** A `package.json` version bump on
141
+ `main` fires `publish.yml` twice: once via the `push` (branches: `main`,
142
+ paths: `package.json`) trigger, and once via `auto-release.yml`'s explicit
143
+ `gh workflow run publish.yml --ref "$TAG" -f ref="$TAG"`.
144
+ 2. **Concurrency groups do not collide.** `publish.yml` uses
145
+ `group: npm-publish-${{ github.event.inputs.ref || github.ref }}`:
146
+ - push run → `npm-publish-refs/heads/main`
147
+ - dispatch run → `npm-publish-v0.7.2`
148
+
149
+ Different keys ⇒ `concurrency` does not serialize the two runs; they execute
150
+ in parallel for the same version.
151
+ 3. **Non-atomic idempotency guard (TOCTOU).** "Skip already published version"
152
+ runs `npm view <name>@<version>` and, on 404, proceeds to `npm publish` in a
153
+ later step. There is no lock between check and publish, and `npm view` reads
154
+ registry metadata that lags the actual publish (here by ~11s). The losing run
155
+ therefore sees "not published", then loses the race to `npm publish`.
156
+
157
+ Explicitly **not** the cause:
158
+
159
+ - **Duplicate-version at dispatch.** No — `0.7.2` was not on npm when the run was
160
+ dispatched (11:18:38) or when its skip guard ran (the guard returned 404).
161
+ - **Trusted Publishing / authentication.** No — provenance was signed
162
+ successfully, `permissions.id-token: write` is set, `registry-url` is correct,
163
+ and no `NPM_TOKEN` is used (Trusted Publishing). Auth was healthy.
164
+
165
+ ## Reproducible non-publish check
166
+
167
+ These commands are **read-only** — they do not publish, rerun the workflow, or
168
+ touch the registry/versions. They reproduce the diagnosis from a clean checkout.
169
+
170
+ ```bash
171
+ # 1) Confirm 0.7.2 is published and is latest (read-only registry query).
172
+ npm view pi-baton version # -> 0.7.2
173
+ npm view pi-baton dist-tags.latest # -> 0.7.2
174
+ npm view pi-baton@0.7.2 time --json # -> "0.7.2": "2026-07-04T11:18:56.171Z"
175
+
176
+ # 2) Show the two concurrent publish runs produced by one version-bump merge.
177
+ # (--created takes a date, not a full timestamp.)
178
+ gh run list --repo eiei114/pi-baton --workflow "Publish to npm" \
179
+ --created 2026-07-04 --limit 10 \
180
+ --json databaseId,event,headBranch,conclusion,createdAt
181
+ # Expect both:
182
+ # 28704526901 push main success (published 0.7.2)
183
+ # 28704529442 workflow_dispatch v0.7.2 failure (E403 duplicate)
184
+
185
+ # 3) Show the dispatch origin (Auto Release triggered the failed run).
186
+ gh run view 28704526903 --repo eiei114/pi-baton --log \
187
+ | grep -E 'gh workflow run publish.yml|released=true|TAG="v0.7.2"'
188
+
189
+ # 4) Prove the two runs had DIFFERENT concurrency groups (so they raced).
190
+ # publish.yml: group: npm-publish-${{ github.event.inputs.ref || github.ref }}
191
+ # push run -> github.event.inputs.ref is unset, github.ref = refs/heads/main
192
+ # => "npm-publish-refs/heads/main"
193
+ # dispatch run -> github.event.inputs.ref = "v0.7.2" (-f ref=v0.7.2)
194
+ # => "npm-publish-v0.7.2"
195
+ node -e '
196
+ const g = (ref, inputRef) => `npm-publish-${inputRef || ref}`;
197
+ console.log("push :", g("refs/heads/main", undefined));
198
+ console.log("dispatch:", g("refs/tags/v0.7.2", "v0.7.2"));
199
+ console.log("collide :", g("refs/heads/main", undefined) === g("refs/tags/v0.7.2", "v0.7.2"));
200
+ '
201
+ # => push : npm-publish-refs/heads/main
202
+ # => dispatch: npm-publish-v0.7.2
203
+ # => collide : false
204
+ ```
205
+
206
+ ## Minimal safe correction options
207
+
208
+ None of these are applied here — they are candidates for a **separate
209
+ correction issue** (release/publish workflows remain human-owned). Listed from
210
+ smallest/safest to largest behavior change.
211
+
212
+ - **Option A — make `npm publish` idempotent (recommended, smallest).** In the
213
+ `Publish to npm` step, treat the specific "cannot publish over the previously
214
+ published versions" `E403` as success instead of failure. This makes the
215
+ workflow resilient to the double-trigger race regardless of concurrency or
216
+ propagation lag. Scope the match to that exact message so genuine permission
217
+ errors still fail. Sketch (not applied):
218
+
219
+ ```bash
220
+ set +e
221
+ npm publish --access public 2>&1 | tee /tmp/publish.log
222
+ status=${PIPESTATUS[0]}
223
+ set -e
224
+ if [ "$status" -ne 0 ] && grep -Eq 'cannot publish over the previously published versions' /tmp/publish.log; then
225
+ echo "Version already published; treating publish as success."
226
+ exit 0
227
+ fi
228
+ exit "$status"
229
+ ```
230
+
231
+ - **Option B — serialize the two runs via one concurrency group.** Replace the
232
+ ref-keyed group with a single constant group (e.g. `group: npm-publish`) and
233
+ keep `cancel-in-progress: false`, so the push run and the auto-release dispatch
234
+ queue instead of racing. Best combined with Option A, since the skip guard is
235
+ still non-atomic. Avoid `cancel-in-progress: true` here — cancelling mid-publish
236
+ risks a partial publish.
237
+
238
+ - **Option C — collapse to a single handoff path.** Remove the `push`
239
+ (`branches: [main]`, `paths: [package.json]`) trigger from `publish.yml` so a
240
+ version bump publishes only via `auto-release.yml`'s explicit dispatch (the path
241
+ `docs/release.md` already describes as the reliable one). Largest behavior
242
+ change; needs validation that the manual tag / `release.published` /
243
+ `workflow_dispatch` entry points still cover intended cases.
244
+
245
+ ## Out of scope for this issue (enforced)
246
+
247
+ Per the issue brief, this slice intentionally does **not**: edit release/publish
248
+ workflows, publish a package, rerun the workflow, change the package version, or
249
+ update the CHANGELOG. A safe correction should be tracked in a follow-up issue.
@@ -5,7 +5,12 @@ import { MissingAgentsError, validateWorkflowAgents } from "../lib/agents.ts";
5
5
  import { ensureBatonScaffolding } from "../lib/paths.ts";
6
6
  import { formatRunResultSummary, runContinuous } from "../lib/run-engine.ts";
7
7
  import { createRunUiController } from "../lib/run-ui.ts";
8
- import { ActiveRunGuardError, createIdleRun, loadActiveRun } from "../lib/run-store.ts";
8
+ import {
9
+ ActiveRunGuardError,
10
+ createIdleRun,
11
+ loadActiveRun,
12
+ loadMostRecentTerminalRun,
13
+ } from "../lib/run-store.ts";
9
14
  import { NO_ACTIVE_RUN_MESSAGE, formatStatusSummary } from "../lib/status.ts";
10
15
  import { createSubagentRunner } from "../lib/subagent-runner.ts";
11
16
  import { WorkflowNameCollisionError, createWorkflowScaffold } from "../lib/workflow-scaffold.ts";
@@ -185,7 +190,7 @@ export default function (pi: ExtensionAPI) {
185
190
  pi.registerCommand("baton:status", {
186
191
  description: "Show the active Baton run summary",
187
192
  handler: async (_args, ctx) => {
188
- const manifest = await loadActiveRun(ctx.cwd);
193
+ const manifest = (await loadActiveRun(ctx.cwd)) ?? (await loadMostRecentTerminalRun(ctx.cwd));
189
194
  if (!manifest) {
190
195
  ctx.ui.notify(NO_ACTIVE_RUN_MESSAGE, "info");
191
196
  return;
package/lib/run-store.ts CHANGED
@@ -41,13 +41,32 @@ export async function readRunManifest(cwd: string, runId: string): Promise<RunMa
41
41
  return readJson<RunManifest>(getRunManifestPath(cwd, runId));
42
42
  }
43
43
 
44
+ function isTerminalRunState(state: RunState): boolean {
45
+ return state === "completed" || state === "failed";
46
+ }
47
+
44
48
  export async function loadActiveRun(cwd: string): Promise<RunManifest | null> {
45
49
  const pointer = await readActiveRunPointer(cwd);
46
- if (!pointer) return null;
50
+ if (!pointer?.runId) return null;
51
+
52
+ try {
53
+ const manifest = await readRunManifest(cwd, pointer.runId);
54
+ if (isTerminalRunState(manifest.state)) {
55
+ return null;
56
+ }
57
+ return manifest;
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ export async function loadMostRecentTerminalRun(cwd: string): Promise<RunManifest | null> {
64
+ const pointer = await readActiveRunPointer(cwd);
65
+ if (!pointer?.runId) return null;
47
66
 
48
67
  try {
49
68
  const manifest = await readRunManifest(cwd, pointer.runId);
50
- if (manifest.state === "completed" || manifest.state === "failed") {
69
+ if (!isTerminalRunState(manifest.state)) {
51
70
  return null;
52
71
  }
53
72
  return manifest;
package/lib/status.ts CHANGED
@@ -1,7 +1,17 @@
1
1
  import type { RunManifest } from "./types.ts";
2
2
 
3
+ function isTerminalRunState(state: RunManifest["state"]): boolean {
4
+ return state === "completed" || state === "failed";
5
+ }
6
+
3
7
  export function formatStatusSummary(manifest: RunManifest): string {
4
- return [
8
+ const lines: string[] = [];
9
+
10
+ if (isTerminalRunState(manifest.state)) {
11
+ lines.push(`This Baton run has finished (${manifest.state}).`);
12
+ }
13
+
14
+ lines.push(
5
15
  `workflow: ${manifest.workflowName}`,
6
16
  `task brief: ${manifest.taskBrief}`,
7
17
  `last step: ${manifest.lastStep ?? "(none)"}`,
@@ -9,7 +19,9 @@ export function formatStatusSummary(manifest: RunManifest): string {
9
19
  `run state: ${manifest.state}`,
10
20
  `iteration count: ${manifest.iteration}`,
11
21
  `run directory: .pi/baton/runs/${manifest.id}`,
12
- ].join("\n");
22
+ );
23
+
24
+ return lines.join("\n");
13
25
  }
14
26
 
15
27
  export const NO_ACTIVE_RUN_MESSAGE =
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-baton",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Pi-native workflow baton runner with per-step model switching and isolated step context.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -58,8 +58,8 @@
58
58
  "typebox": "*"
59
59
  },
60
60
  "devDependencies": {
61
- "@earendil-works/pi-ai": "latest",
62
- "@earendil-works/pi-coding-agent": "latest",
61
+ "@earendil-works/pi-ai": "^0.80.6",
62
+ "@earendil-works/pi-coding-agent": "^0.80.6",
63
63
  "typebox": "latest",
64
64
  "@types/node": "^26.0.1",
65
65
  "typescript": "^6.0.3"
package/docs/examples.md DELETED
@@ -1,49 +0,0 @@
1
- # Examples
2
-
3
- This template ships one minimal example for each Pi package resource type.
4
-
5
- ## Extension
6
-
7
- `extensions/hello.ts` registers:
8
-
9
- - `/template-hello`
10
- - a small session status indicator
11
-
12
- Try it with:
13
-
14
- ```bash
15
- pi -e .
16
- ```
17
-
18
- Then run:
19
-
20
- ```txt
21
- /template-hello YourName
22
- ```
23
-
24
- ## Agent Skill
25
-
26
- `skills/example-skill/SKILL.md` demonstrates a minimal Agent Skill.
27
-
28
- Replace it with your real workflow instructions.
29
-
30
- ## Prompt template
31
-
32
- `prompts/example.md` demonstrates a tiny prompt template with one variable.
33
-
34
- ## Theme
35
-
36
- `themes/example-theme.json` is a placeholder theme. Replace it or remove `themes/` if your package does not ship themes.
37
-
38
- ## Typed custom tool
39
-
40
- `extensions/index.ts` registers:
41
-
42
- - `/template-info`
43
- - `template_greet` custom tool
44
-
45
- The tool demonstrates:
46
-
47
- - TypeBox object parameters
48
- - a string enum schema via `StringEnum`
49
- - shared logic imported from `lib/greeting.ts`
@@ -1,63 +0,0 @@
1
- # GitHub Template Repository
2
-
3
- > **Template bootstrap doc.** Use while setting up a new repo from this template. Delete this file or merge any project-specific steps into README / Vault notes once setup is done, unless it still adds maintainer value.
4
-
5
- ## Recommended development flow
6
-
7
- After generating a repo from this template, use this default order:
8
-
9
- ```txt
10
- Vault notes -> PRD -> Issues -> implement -> ci/check -> release -> save learnings
11
- ```
12
-
13
- In practice:
14
-
15
- 1. Create Vault notes under `4_Project/<ProjectName>/`.
16
- 2. Add `CONTEXT.md`, `README.md`, `ROADMAP.md`, `Docs/`, `Issues/`, and `Progress/`.
17
- 3. Write the PRD in `Docs/`.
18
- 4. Split approved issue files into `Issues/`.
19
- 5. Implement in the OSS repo created from this template.
20
- 6. Run CI and package checks before release.
21
- 7. Save release notes and follow-up decisions back to the Vault project.
22
-
23
- Enable template mode on the source repository:
24
-
25
- ```txt
26
- GitHub repo → Settings → General → Template repository
27
- ```
28
-
29
- Create a public repository from the template:
30
-
31
- ```bash
32
- gh repo create OWNER/new-pi-extension \
33
- --public \
34
- --template OWNER/pi-extension-template \
35
- --clone
36
- ```
37
-
38
- Create a private repository from the template:
39
-
40
- ```bash
41
- gh repo create OWNER/new-pi-extension \
42
- --private \
43
- --template OWNER/pi-extension-template \
44
- --clone
45
- ```
46
-
47
- Include all branches if needed:
48
-
49
- ```bash
50
- gh repo create OWNER/new-pi-extension \
51
- --public \
52
- --template OWNER/pi-extension-template \
53
- --include-all-branches \
54
- --clone
55
- ```
56
-
57
- After creation:
58
-
59
- ```bash
60
- cd new-pi-extension
61
- npm install
62
- npm run ci
63
- ```\n
@@ -1,43 +0,0 @@
1
- # Repository Settings
2
-
3
- > **Template bootstrap doc.** Use while configuring GitHub About, topics, and branch protection after generating a repo. Delete this file or merge needed settings into README once setup is done, unless it still adds maintainer value.
4
-
5
- Use this file after creating a real repository from the template.
6
-
7
- ## GitHub About
8
-
9
- Suggested fields:
10
-
11
- - Description: one-line pitch for the Pi package
12
- - Website: npm package URL or project docs URL
13
- - Topics:
14
- - `pi`
15
- - `pi-package`
16
- - `agent-skill`
17
- - `typescript`
18
-
19
- ## Template mode
20
-
21
- If this repository itself should be reusable as a template:
22
-
23
- ```txt
24
- Settings → General → Template repository
25
- ```
26
-
27
- ## Branch protection
28
-
29
- Recommended for public packages:
30
-
31
- - Require pull request before merging
32
- - Require status checks to pass
33
- - Require `CI` workflow
34
- - Block force pushes on the default branch
35
-
36
- ## npm package page
37
-
38
- After first publish:
39
-
40
- - Confirm README renders correctly
41
- - Confirm package provenance appears
42
- - Confirm package contents are intentional
43
- - Add npm URL to GitHub About and README
@@ -1,140 +0,0 @@
1
- # Template Setup Checklist
2
-
3
- このテンプレートから新しい Pi 拡張OSSを作った後に埋めること。
4
-
5
- ## Recommended flow
6
-
7
- - [ ] Vault project notes を `4_Project/<ProjectName>/` に作る
8
- - [ ] `CONTEXT.md` / `README.md` / `ROADMAP.md` / `Docs/` / `Issues/` / `Progress/` を揃える
9
- - [ ] PRD を `4_Project/<ProjectName>/Docs/` に置く
10
- - [ ] approved issue を `4_Project/<ProjectName>/Issues/` に切る
11
- - [ ] OSS repo 側で実装する
12
- - [ ] `npm run ci` / `npm test` / `npm pack --dry-run` を通す
13
- - [ ] release 後に Vault へ learnings / release notes を戻す
14
-
15
- ## Repository
16
-
17
- - [ ] GitHub repository name を決める
18
- - [ ] GitHub About 欄を書く
19
- - [ ] GitHub topics を設定する
20
- - [ ] `pi`
21
- - [ ] `pi-package`
22
- - [ ] `agent-skill`
23
- - [ ] `typescript`
24
- - [ ] GitHub Settingsで `Template repository` をONにする
25
- - [ ] Repository URL を `package.json` に反映する
26
- - [ ] README の `OWNER/REPO` を実リポジトリに置き換える
27
-
28
- ## Package metadata
29
-
30
- - [ ] `package.json` の `name` を変更する
31
- - [ ] `description` を書く
32
- - [ ] `author` を入れる
33
- - [ ] `repository.url` を埋める
34
- - [ ] `bugs.url` を埋める
35
- - [ ] `homepage` を埋める
36
- - [ ] `keywords` を見直す
37
- - [ ] `LICENSE` の年・名前を更新する
38
-
39
- ## README placeholders
40
-
41
- - [ ] `PACKAGE_DISPLAY_NAME` を置き換える
42
- - [ ] `PACKAGE_NAME` を置き換える
43
- - [ ] `OWNER/REPO` を置き換える
44
- - [ ] one-line pitch を書く
45
- - [ ] feature list を書く
46
- - [ ] quick start command を実コマンドにする
47
- - [ ] npm URL を確認する
48
- - [ ] GitHub URL を確認する
49
-
50
- ## Pi package manifest
51
-
52
- - [ ] `pi.extensions` に公開する拡張だけを残す
53
- - [ ] `pi.skills` に公開する skill だけを残す
54
- - [ ] 不要なら `prompts/` を消す
55
- - [ ] 不要なら `themes/` を消す
56
- - [ ] サンプル名を実名に変える
57
-
58
- ## Documentation
59
-
60
- `docs/` は固定6ファイル必須ではない。README を正とし、価値がある doc だけ残す。
61
-
62
- ### Required root files (public)
63
-
64
- - [ ] `README.md` — GitHub/npm の入口。Install / Quick start / Release / Security を含める
65
- - [ ] `LICENSE`
66
- - [ ] `SECURITY.md`
67
- - [ ] `CHANGELOG.md`
68
- - [ ] Release 手順が README と workflow で明確(Trusted Publishing 設定含む)
69
-
70
- ### Recommended public docs (keep when useful)
71
-
72
- - [ ] `docs/examples.md` — 例が README に載り切らないとき
73
- - [ ] `docs/release.md` — Trusted Publishing や release 手順の詳細が README だけでは足りないとき
74
- - [ ] `docs/usage.md` — 使い方が README に載り切らないとき(必要なら新規作成)
75
-
76
- ### Optional maintainer docs
77
-
78
- - [ ] `docs/template-checklist.md` — このファイル。成熟 repo では README からの主ナビにしない。不要なら削除可
79
-
80
- ### Post-generation cleanup (delete or merge template setup docs)
81
-
82
- テンプレート生成直後の bootstrap 用。プロジェクト固有の価値がなければ削除し、必要な内容は README / `docs/release.md` / `docs/examples.md` に統合する。
83
-
84
- - [ ] `docs/github-template.md` を削除するか、固有の手順だけ README / Vault に移す
85
- - [ ] `docs/repository-settings.md` を削除するか、About/topics など必要分だけ README に移す
86
- - [ ] `docs/typescript.md` を削除するか、TypeScript 方針は README Development に要約する
87
- - [ ] README の Docs 節から、削除したファイルへのリンクを外す
88
- - [ ] `package.json` の `files` から、削除した `docs/` パスを外す(残す doc だけ明示する)
89
-
90
- ## TypeScript
91
-
92
- - [ ] `extensions/index.ts` を実装に合わせて更新する
93
- - [ ] `extensions/hello.ts` が不要なら削除する
94
- - [ ] 共通ロジックを `lib/` に切り出す
95
- - [ ] `strict: true` を維持する
96
- - [ ] custom tool parameters は TypeBox schema で定義する
97
- - [ ] string choices は `StringEnum` helper を使う
98
- - [ ] runtime dependency は `dependencies`、Pi提供packageは `peerDependencies` に置く
99
- - [ ] `package.json.files` に公開対象だけを入れる
100
- - [ ] 詳細はセットアップ中だけ `docs/typescript.md` を参照し、不要なら post-generation cleanup で削除
101
-
102
- ## GitHub Template repo
103
-
104
- - [ ] `gh repo create --template OWNER/pi-extension-template` で作成できることを確認する
105
- - [ ] public/privateどちらの作成例もdocsに載せる(`docs/github-template.md` を残す場合)
106
-
107
- ## CI / Release
108
-
109
- - [ ] `npm run ci` が通る
110
- - [ ] `npm pack --dry-run` が通る
111
- - [ ] npm Trusted Publishing を設定する
112
- - [ ] npm Trusted Publisher の workflow filename が `publish.yml` になっている
113
- - [ ] `NPM_TOKEN` を使っていないことを確認する
114
- - [ ] `auto-release.yml` が `main` の version bump から tag/release を作ることを確認する
115
- - [ ] `publish.yml` が `workflow_dispatch` と `release.published` に対応していることを確認する
116
- - [ ] 初回リリースで npm provenance が付いているか確認する
117
-
118
- ### Workflow handoff guard
119
-
120
- - [ ] `.github/workflows/auto-release.yml` exists before first release
121
- - [ ] `.github/workflows/publish.yml` exists before first release
122
- - [ ] `auto-release.yml` has `permissions: actions: write` and `contents: write`
123
- - [ ] `publish.yml` has `permissions: id-token: write` for npm Trusted Publishing
124
- - [ ] Auto release explicitly hands off to publish: `gh workflow run publish.yml --ref "$TAG" -f ref="$TAG"`, or `publish.yml` has an equivalent `workflow_run` / `repository_dispatch` trigger
125
- - [ ] Do not rely only on `push.tags` or `release.published` when the tag/release is created by `GITHUB_TOKEN`; that can leave npm unchanged after merge
126
-
127
- ## npm page
128
-
129
- - [ ] npm package URL を README に追加する
130
- - [ ] npm description が適切に表示されるか確認する
131
- - [ ] provenance が付いているか確認する
132
- - [ ] 不要なファイルが package に含まれていないか確認する(`npm pack --dry-run` で `docs/` の残し方も確認)
133
-
134
- ## Before first release
135
-
136
- - [ ] サンプルコードを実機 Pi でロードする
137
- - [ ] `pi install git:github.com/OWNER/REPO` を試す
138
- - [ ] `pi -e .` を試す
139
- - [ ] README のコマンドがコピペで動くか確認する
140
- - [ ] CHANGELOG に `0.1.0` を書く
@@ -1,77 +0,0 @@
1
- # TypeScript Guide
2
-
3
- > **Template bootstrap doc.** Use while learning this template's TypeScript layout and dependency rules. Delete this file or summarize the policies you keep in README Development once setup is done, unless it still adds maintainer value.
4
-
5
- This is a TypeScript-first Pi package template.
6
-
7
- ## Layout
8
-
9
- ```txt
10
- extensions/*.ts Pi extension entrypoints
11
- lib/*.ts Shared TypeScript helpers
12
- skills/*/SKILL.md Agent Skills
13
- prompts/*.md Prompt templates
14
- themes/*.json Themes
15
- tests/*.test.mjs Smoke tests
16
- tests/*.test.ts Optional TypeScript tests if you add a TS test runner
17
- ```
18
-
19
- Pi loads TypeScript extensions directly, so no build step is required for normal use.
20
-
21
- ## Strict mode
22
-
23
- `tsconfig.json` keeps `strict: true`. Prefer fixing types over loosening compiler options.
24
-
25
- ## Extension entrypoints
26
-
27
- Two entrypoint styles are shown:
28
-
29
- - `extensions/hello.ts`: single-file extension
30
- - `extensions/index.ts`: index-style extension that imports shared code from `lib/`
31
-
32
- For larger packages, keep entrypoints thin and put reusable logic in `lib/`.
33
-
34
- ## TypeBox schemas
35
-
36
- Use TypeBox schemas for custom tool parameters.
37
-
38
- ```ts
39
- import { Type } from "typebox";
40
-
41
- const parameters = Type.Object({
42
- name: Type.String({ description: "Name to greet" }),
43
- });
44
- ```
45
-
46
- ## String enums
47
-
48
- For string choices, use the local `StringEnum` helper from `lib/schema.ts`.
49
-
50
- ```ts
51
- import { StringEnum } from "../lib/schema.ts";
52
-
53
- const mode = StringEnum(["short", "friendly"], {
54
- description: "Greeting style",
55
- });
56
- ```
57
-
58
- This emits a JSON Schema `enum`, which is friendlier to model providers than a union of string literals.
59
-
60
- ## Runtime dependencies vs peer dependencies
61
-
62
- Pi bundles core packages for extension authors. Keep Pi-provided packages as `peerDependencies` and also install them as `devDependencies` for local typechecking.
63
-
64
- Use `peerDependencies` for:
65
-
66
- - `@earendil-works/pi-coding-agent`
67
- - `@earendil-works/pi-ai`
68
- - `@earendil-works/pi-tui`
69
- - `typebox`
70
-
71
- Use `dependencies` for runtime packages your extension imports that Pi does not provide.
72
-
73
- Use `devDependencies` for local-only tools such as TypeScript, test runners, and linters.
74
-
75
- ## Package contents
76
-
77
- Control npm package contents with `package.json` `files`. Prefer this over `.npmignore` so the published package stays explicit.