pi-dev 0.1.8 → 0.2.1
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/dist/cli.js +12 -5
- package/dist/install.js +12 -3
- package/dist/manifest.js +6 -1
- package/package.json +1 -1
- package/skills/improve-skill-flow/SKILL.md +67 -67
- package/skills/where/SKILL.md +115 -40
package/dist/cli.js
CHANGED
|
@@ -9,17 +9,20 @@ function help() {
|
|
|
9
9
|
console.log(`pi-dev — autonomous engineering skill framework for the pi runtime
|
|
10
10
|
|
|
11
11
|
Usage:
|
|
12
|
-
pi-dev install [scope] [--skip-prefs] [-y]
|
|
12
|
+
pi-dev install [scope] [--skip-prefs] [--include-maintainer] [-y]
|
|
13
13
|
Install skills + seed preferences. Scope is one of:
|
|
14
14
|
--global ~/.pi/agent/skills/ (default, every pi session sees it)
|
|
15
15
|
--local .pi/skills/ in cwd (only this repo)
|
|
16
16
|
Without a flag, an interactive TTY is prompted; non-TTY defaults to global.
|
|
17
17
|
Pass -y to skip the prompt and accept the default.
|
|
18
|
+
Pass --include-maintainer to also install maintainer-only skills
|
|
19
|
+
(only useful if you are developing pi-dev itself).
|
|
18
20
|
|
|
19
|
-
pi-dev update [--include-prefs] [--global|--local]
|
|
21
|
+
pi-dev update [--include-prefs] [--include-maintainer] [--global|--local]
|
|
20
22
|
Refresh skills in place. Scope is auto-detected from disk
|
|
21
23
|
(local wins if .pi/skills/ exists in cwd). Preferences are kept by default;
|
|
22
|
-
pass --include-prefs to re-seed.
|
|
24
|
+
pass --include-prefs to re-seed. Maintainer skills already on disk are
|
|
25
|
+
preserved automatically; pass --include-maintainer to add them on update.
|
|
23
26
|
|
|
24
27
|
pi-dev list Show installed skills under both scopes (if present).
|
|
25
28
|
pi-dev uninstall <skill> [--global|--local]
|
|
@@ -32,7 +35,6 @@ After install, in any pi session, you primarily call:
|
|
|
32
35
|
/do — the one-shot engineering entry point
|
|
33
36
|
/taste — view or update preferences
|
|
34
37
|
/where — recall prior pi sessions for this cwd
|
|
35
|
-
/improve-skill-flow — audit pi sessions, propose evidence-based skill edits
|
|
36
38
|
|
|
37
39
|
All other skills are invoked automatically by /do.
|
|
38
40
|
`);
|
|
@@ -54,10 +56,15 @@ async function main() {
|
|
|
54
56
|
skipPrefs: getFlag("skip-prefs"),
|
|
55
57
|
scope: getScope(),
|
|
56
58
|
yes: getFlag("yes") || args.includes("-y"),
|
|
59
|
+
includeMaintainer: getFlag("include-maintainer"),
|
|
57
60
|
});
|
|
58
61
|
break;
|
|
59
62
|
case "update":
|
|
60
|
-
await update({
|
|
63
|
+
await update({
|
|
64
|
+
skipPrefs: !getFlag("include-prefs"),
|
|
65
|
+
scope: getScope(),
|
|
66
|
+
includeMaintainer: getFlag("include-maintainer"),
|
|
67
|
+
});
|
|
61
68
|
break;
|
|
62
69
|
case "list":
|
|
63
70
|
listInstalled();
|
package/dist/install.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, cpSync, copyFileSync, renameSync } from "node:fs
|
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { createInterface } from "node:readline";
|
|
5
|
-
import { SKILLS } from "./manifest.js";
|
|
5
|
+
import { SKILLS, CONSUMER_SKILLS } from "./manifest.js";
|
|
6
6
|
import { PKG_SKILLS_DIR, PKG_GLOBAL_PREFS_PRESET, destFor, } from "./paths.js";
|
|
7
7
|
function ask(question) {
|
|
8
8
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -41,8 +41,9 @@ export async function install(opts = {}) {
|
|
|
41
41
|
const scope = await resolveScope(opts);
|
|
42
42
|
const { agentDir, skillsDir, prefsFile } = destFor(scope);
|
|
43
43
|
mkdirSync(skillsDir, { recursive: true });
|
|
44
|
+
const skillsToInstall = opts.includeMaintainer ? SKILLS : CONSUMER_SKILLS;
|
|
44
45
|
let copied = 0;
|
|
45
|
-
for (const skill of
|
|
46
|
+
for (const skill of skillsToInstall) {
|
|
46
47
|
const src = join(PKG_SKILLS_DIR, skill.name);
|
|
47
48
|
const dst = join(skillsDir, skill.name);
|
|
48
49
|
if (!existsSync(src)) {
|
|
@@ -88,12 +89,16 @@ export async function update(opts = {}) {
|
|
|
88
89
|
else
|
|
89
90
|
scope = "global";
|
|
90
91
|
}
|
|
92
|
+
// On update, preserve the maintainer set if maintainer skills are already on
|
|
93
|
+
// disk — no need to make the user re-pass the flag every time.
|
|
94
|
+
const maintainerAlreadyInstalled = existsSync(join(destFor(scope).skillsDir, "improve-skill-flow", "SKILL.md"));
|
|
91
95
|
await install({
|
|
92
96
|
...opts,
|
|
93
97
|
scope,
|
|
94
98
|
force: true,
|
|
95
99
|
skipPrefs: !opts.skipPrefs ? true : opts.skipPrefs,
|
|
96
100
|
yes: true,
|
|
101
|
+
includeMaintainer: opts.includeMaintainer || maintainerAlreadyInstalled,
|
|
97
102
|
});
|
|
98
103
|
}
|
|
99
104
|
export function uninstallSkill(name, scope) {
|
|
@@ -121,7 +126,11 @@ export function listInstalled() {
|
|
|
121
126
|
for (const skill of SKILLS) {
|
|
122
127
|
const path = join(t.skillsDir, skill.name, "SKILL.md");
|
|
123
128
|
const installed = existsSync(path);
|
|
124
|
-
const tag = skill.kind === "human"
|
|
129
|
+
const tag = skill.kind === "human"
|
|
130
|
+
? "[user] "
|
|
131
|
+
: skill.kind === "maintainer"
|
|
132
|
+
? "[maintainer]"
|
|
133
|
+
: "[support] ";
|
|
125
134
|
const status = installed ? "ok " : "missing";
|
|
126
135
|
console.log(` ${tag} /${skill.name.padEnd(34)} ${status} — ${skill.summary}`);
|
|
127
136
|
}
|
package/dist/manifest.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `human` skills are what the user calls directly: /do, /taste, /where.
|
|
5
5
|
* `support` skills are auto-invoked by /do or /migrate.
|
|
6
|
+
* `maintainer` skills are for pi-dev framework maintenance only; they are
|
|
7
|
+
* NOT installed for consumers by default (pass --include-maintainer to opt in).
|
|
6
8
|
*
|
|
7
9
|
* The skill names match the directory names under `skills/`.
|
|
8
10
|
*/
|
|
@@ -11,7 +13,8 @@ export const SKILLS = [
|
|
|
11
13
|
{ name: "do", kind: "human", summary: "Do the engineering work end-to-end." },
|
|
12
14
|
{ name: "taste", kind: "human", summary: "View / update / onboard preferences." },
|
|
13
15
|
{ name: "where", kind: "human", summary: "Recall prior pi sessions for this cwd." },
|
|
14
|
-
|
|
16
|
+
// Maintainer-only — pi-dev framework itself, not shipped to consumers.
|
|
17
|
+
{ name: "improve-skill-flow", kind: "maintainer", summary: "Maintainer-only. Audit pi telemetry, propose SKILL.md edits, release." },
|
|
15
18
|
// Auto-invoked support skills
|
|
16
19
|
{ name: "migrate", kind: "support", summary: "Strict migration gate before /do can run." },
|
|
17
20
|
{ name: "setup", kind: "support", summary: "Scaffold issue-tracker / triage / domain docs." },
|
|
@@ -27,3 +30,5 @@ export const SKILLS = [
|
|
|
27
30
|
];
|
|
28
31
|
export const HUMAN_SKILLS = SKILLS.filter((s) => s.kind === "human");
|
|
29
32
|
export const SUPPORT_SKILLS = SKILLS.filter((s) => s.kind === "support");
|
|
33
|
+
export const MAINTAINER_SKILLS = SKILLS.filter((s) => s.kind === "maintainer");
|
|
34
|
+
export const CONSUMER_SKILLS = SKILLS.filter((s) => s.kind !== "maintainer");
|
package/package.json
CHANGED
|
@@ -1,48 +1,71 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: improve-skill-flow
|
|
3
|
-
description: Analyse real pi-runtime session telemetry from
|
|
3
|
+
description: MAINTAINER-ONLY. Analyse real pi-runtime session telemetry from any consumer repo on this machine to find where the engineering skills (especially /do's chain) drift from their stated contract, then propose evidence-anchored edits to pi-dev's own SKILL.md files. Run only from inside the pi-dev repo — it edits pi-dev sources and triggers a release. Use when the maintainer wants to improve, audit, debug, or evolve the pi-dev skill framework itself based on what actually happened in real sessions ("스킬 개선하자", "do 가 왜 멈춰", "히스토리 보고 분석해서 스킬 고치자", "메타 스킬 작업", etc).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /improve-skill-flow — Meta-skill for evidence-based skill improvement
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
**Audience: pi-dev maintainers only.** Consumers do not get this skill installed. Consumers improve their own setup by editing `docs/agents/preferences.md` (per project) or `~/.pi/agent/preferences.md` (per machine), not by editing SKILL.md bodies. The framework is fixed for them; only the maintainer changes it.
|
|
9
|
+
|
|
10
|
+
The pi-dev skills are pure markdown. They get better when the maintainer reads what real sessions did across consumer repos, compares that to what the SKILL.md said *should* happen, and edits the gap closed. This skill is the canonical loop for that.
|
|
9
11
|
|
|
10
12
|
The point: **never edit a SKILL.md from gut feeling.** Edit because session N showed phase P violated predicate Q on M occasions, and here is the line that would have prevented it.
|
|
11
13
|
|
|
14
|
+
## Pre-flight (hard gate)
|
|
15
|
+
|
|
16
|
+
Refuse to run unless cwd is the pi-dev repo. Releases happen from here; nothing else makes sense.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
origin=$(git -C "$PWD" remote get-url origin 2>/dev/null || echo "")
|
|
20
|
+
pkg_name=$(jq -r '.name // empty' package.json 2>/dev/null)
|
|
21
|
+
ok=0
|
|
22
|
+
case "$origin" in *pi-dev*|*pi-dev.git) ok=1 ;; esac
|
|
23
|
+
[ "$pkg_name" = "pi-dev" ] && ok=1
|
|
24
|
+
if [ "$ok" != 1 ]; then
|
|
25
|
+
echo "this skill is maintainer-only; cd into the pi-dev repo and re-run"
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
If the gate fails, stop. Do not proceed in a consumer repo.
|
|
31
|
+
|
|
12
32
|
## When to run
|
|
13
33
|
|
|
14
|
-
- A consumer repo has accumulated at least one real day of pi sessions (≈ 3+ `.jsonl` files).
|
|
34
|
+
- A consumer repo on this machine has accumulated at least one real day of pi sessions (≈ 3+ `.jsonl` files).
|
|
15
35
|
- A specific skill is suspected of misbehaving ("why does `/do` keep stopping?").
|
|
16
36
|
- After landing a skill change, to verify the next session(s) actually follow the new wording.
|
|
17
37
|
- Periodically (every N releases) as a regression sweep across all human-facing skills.
|
|
18
38
|
|
|
39
|
+
Always from inside the pi-dev checkout (see Pre-flight).
|
|
40
|
+
|
|
19
41
|
## What this skill is NOT
|
|
20
42
|
|
|
21
|
-
- Not for analysing the *codebase* of
|
|
43
|
+
- Not for analysing the *codebase* of any repo — that is `improve-codebase-architecture`.
|
|
22
44
|
- Not for shipping engineering work — it does not invoke `/do`. Findings turn into proposed SKILL.md diffs, which are committed via the normal release-please flow on `pi-dev`.
|
|
23
45
|
- Not a real-time monitor — it reads completed session files.
|
|
46
|
+
- Not a consumer-facing tool. Consumers don't get this skill installed; they tune their setup via `preferences.md`, not by editing SKILL bodies.
|
|
24
47
|
|
|
25
48
|
## Inputs
|
|
26
49
|
|
|
27
|
-
- **
|
|
50
|
+
- **Consumer repo path** (or its sessions directory) to audit. The maintainer names a repo on this machine; you resolve its sessions dir.
|
|
28
51
|
- Optional: a specific skill name to focus the audit on (`do`, `migrate`, `triage`, …).
|
|
29
52
|
- Optional: a date range.
|
|
30
|
-
- **
|
|
53
|
+
- **Fix scope** per finding — `framework` or `consumer-prefs`. Defaults set in Step 5.5; maintainer can flip individual rows before applying.
|
|
31
54
|
|
|
32
|
-
##
|
|
55
|
+
## Fix scopes
|
|
33
56
|
|
|
34
|
-
pi-runtime today loads skill bodies from a single location
|
|
57
|
+
pi-runtime today loads skill bodies from a single location (`~/.pi/agent/skills/<name>/SKILL.md` for global installs, `<repo>/.pi/skills/<name>/SKILL.md` for local installs). The framework's 3-layer override is on **preferences**, not on SKILL bodies. So a finding lands in one of two places:
|
|
35
58
|
|
|
36
59
|
| scope | lands in | reaches | propagation | when to pick |
|
|
37
60
|
| --- | --- | --- | --- | --- |
|
|
38
|
-
| **
|
|
39
|
-
| **
|
|
61
|
+
| **framework** | this repo's `skills/<name>/SKILL.md` | every consumer after the next `npx pi-dev update` | release-please → npm publish | the SKILL.md wording itself is wrong; gap shows up generically |
|
|
62
|
+
| **consumer-prefs** | the audited consumer repo's `docs/agents/preferences.md` (Project taboos / Diagnosis posture / Local-live playbook / Free notes — whichever section fits) | only that repo, on every `/do` bootstrap | regular consumer-repo commit | gap is the consumer repo's domain / paths / conventions, not the SKILL.md |
|
|
40
63
|
|
|
41
64
|
Notes:
|
|
42
65
|
|
|
43
|
-
- A `
|
|
44
|
-
- A `
|
|
45
|
-
- A single audit may produce a mix of
|
|
66
|
+
- A `framework` apply is **always** mirrored into `~/.pi/agent/skills/<name>/` on this machine so the next session picks it up immediately, without waiting for npm.
|
|
67
|
+
- A `consumer-prefs` apply touches no pi-dev files. It is committed to the consumer repo only.
|
|
68
|
+
- A single audit may produce a mix of framework and consumer-prefs findings. Decide scope per finding, not per audit.
|
|
46
69
|
|
|
47
70
|
## Session-data location & format
|
|
48
71
|
|
|
@@ -82,13 +105,13 @@ Timestamps on `message` records are ISO strings; some other record types use int
|
|
|
82
105
|
|
|
83
106
|
### 1 — Scope and load
|
|
84
107
|
|
|
85
|
-
Ask the
|
|
108
|
+
Ask the maintainer (one round, only if not already specified):
|
|
86
109
|
|
|
87
|
-
- target repo (or "all repos with sessions")
|
|
110
|
+
- target consumer repo (or "all repos with sessions on this machine")
|
|
88
111
|
- a skill to focus on, or "everything"
|
|
89
112
|
- a date range or "all"
|
|
90
113
|
|
|
91
|
-
Resolve the sessions directory. List the `.jsonl` files with size + line count so the
|
|
114
|
+
Resolve the sessions directory. List the `.jsonl` files with size + line count so the maintainer can see the input scale.
|
|
92
115
|
|
|
93
116
|
### 2 — Build the raw signal table
|
|
94
117
|
|
|
@@ -116,7 +139,7 @@ Use a deterministic Python or shell script you write once and check into `/tmp`
|
|
|
116
139
|
|
|
117
140
|
### 3 — Cross-reference with repo state
|
|
118
141
|
|
|
119
|
-
For the same date range, pull:
|
|
142
|
+
For the same date range, pull (against the **consumer repo** being audited):
|
|
120
143
|
|
|
121
144
|
- `git log --since=<start> --pretty=format:"%h %ad %s"` — commit cadence vs. the predicate `auto-commit-per-slice`.
|
|
122
145
|
- `gh issue list / pr list` (if GitHub) — slice/PR shape vs. `default-issue-style=vertical-slice`.
|
|
@@ -126,7 +149,7 @@ For the same date range, pull:
|
|
|
126
149
|
Cross-reference each signal against:
|
|
127
150
|
|
|
128
151
|
- The skill's **terminal predicate** in `do/SKILL.md` → "Phase contracts".
|
|
129
|
-
- The repo's **`docs/agents/preferences.md`** taboos and `auto-*` settings.
|
|
152
|
+
- The consumer repo's **`docs/agents/preferences.md`** taboos and `auto-*` settings.
|
|
130
153
|
- The hard rules in the skill being audited.
|
|
131
154
|
|
|
132
155
|
### 4 — Score the gaps
|
|
@@ -157,31 +180,17 @@ For every 🔴 / 🟡 row, quote the smallest piece of evidence that makes the g
|
|
|
157
180
|
|
|
158
181
|
If a finding cannot be backed by an excerpt, it is not actionable yet — demote to a TODO and keep digging.
|
|
159
182
|
|
|
160
|
-
### 5.5 — Decide
|
|
161
|
-
|
|
162
|
-
For each 🔴 / 🟡 finding, pick a default scope using this two-step heuristic, then show the table to the user once and let them flip individual rows before applying.
|
|
183
|
+
### 5.5 — Decide fix scope per finding (auto + maintainer-overridable)
|
|
163
184
|
|
|
164
|
-
|
|
185
|
+
For each 🔴 / 🟡 finding, pick a default scope using the heuristic below, then show the table once and let the maintainer flip individual rows before applying.
|
|
165
186
|
|
|
166
|
-
|
|
167
|
-
origin=$(git -C "$PWD" remote get-url origin 2>/dev/null || echo "")
|
|
168
|
-
pkg_name=$(jq -r '.name // empty' package.json 2>/dev/null)
|
|
169
|
-
is_maintainer=false
|
|
170
|
-
case "$origin" in *pi-dev*|*pi-dev.git) is_maintainer=true ;; esac
|
|
171
|
-
[ "$pkg_name" = "pi-dev" ] && is_maintainer=true
|
|
172
|
-
echo "operator_context=$([ \"$is_maintainer\" = true ] && echo maintainer || echo consumer)"
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
- `operator_context=maintainer` → cwd is the pi-dev repo itself; the release path is available.
|
|
176
|
-
- `operator_context=consumer` → cwd is a downstream repo; no release path. `global` findings here become "draft a patch + open an upstream PR / issue" rather than "push and release".
|
|
177
|
-
|
|
178
|
-
**Step B — score each finding.** Default to `global` if the finding matches **any** of:
|
|
187
|
+
Default to `framework` if the finding matches **any** of:
|
|
179
188
|
|
|
180
189
|
- Cites SKILL.md wording / phase / predicate / rule numbers.
|
|
181
190
|
- The proposed fix is a generic anti-pattern string, a terminator literal, a runway line, or a lockout that any repo would benefit from.
|
|
182
191
|
- The same gap would plausibly show up in two or more consumer repos.
|
|
183
192
|
|
|
184
|
-
Default to `
|
|
193
|
+
Default to `consumer-prefs` if the finding matches **any** of:
|
|
185
194
|
|
|
186
195
|
- Cites a repo-specific path (`src/core/...`, `bin/...-smoke.ts`), brand, schema, table, or domain term.
|
|
187
196
|
- The fix is a taboo, a smoke convention, an env / boot detail, or a glossary entry.
|
|
@@ -190,28 +199,28 @@ Default to `project` if the finding matches **any** of:
|
|
|
190
199
|
Present the scope-decision table:
|
|
191
200
|
|
|
192
201
|
```
|
|
193
|
-
| # | finding (short) | default scope
|
|
194
|
-
| - | ---------------------------------------- |
|
|
195
|
-
| 1 | /do hands flow back between phases |
|
|
196
|
-
| 2 | docs/handoff/ resurrected after marker |
|
|
197
|
-
| 3 | retro-action-item label still alive |
|
|
198
|
-
| 4 | smoke command name changed in S058 |
|
|
202
|
+
| # | finding (short) | default scope | target file | flip? |
|
|
203
|
+
| - | ---------------------------------------- | ---------------- | ------------------------------------ | ----- |
|
|
204
|
+
| 1 | /do hands flow back between phases | framework | pi-dev:skills/do/SKILL.md | |
|
|
205
|
+
| 2 | docs/handoff/ resurrected after marker | framework | pi-dev:skills/migrate/SKILL.md | |
|
|
206
|
+
| 3 | retro-action-item label still alive | consumer-prefs | hugn:docs/agents/preferences.md | |
|
|
207
|
+
| 4 | smoke command name changed in S058 | consumer-prefs | hugn:docs/agents/preferences.md | |
|
|
199
208
|
```
|
|
200
209
|
|
|
201
|
-
Ask
|
|
210
|
+
Ask once: "OK to proceed with these scopes? Reply with row numbers to flip, or `go`." Apply the flips and move on.
|
|
202
211
|
|
|
203
212
|
### 6 — Propose edits (per-finding, scoped)
|
|
204
213
|
|
|
205
214
|
For each 🔴 / 🟡 finding, draft the smallest possible edit that, **if it had been in place at session time, would have prevented the gap.** The shape of the draft depends on the scope from Step 5.5:
|
|
206
215
|
|
|
207
|
-
**
|
|
216
|
+
**Framework findings (target: pi-dev SKILL.md):**
|
|
208
217
|
|
|
209
218
|
- Edit a **rule** or a **step**, not a flavour sentence. The model must be able to detect the constraint in its own draft output.
|
|
210
219
|
- Prefer **explicit anti-pattern strings** ("Do not say 'shall I continue?'") over abstract injunctions ("be decisive"). The hugn-2026-05 audit showed that named anti-patterns work.
|
|
211
220
|
- Prefer **terminal markers** ("the summary's last line must be one of these two literals: …") over qualitative descriptions of "good wrap-up".
|
|
212
221
|
- Update **at most three skills per run.** More than that means findings aren't anchored well enough.
|
|
213
222
|
|
|
214
|
-
**
|
|
223
|
+
**Consumer-prefs findings (target: that repo's `docs/agents/preferences.md`):**
|
|
215
224
|
|
|
216
225
|
- Pick the *narrowest* existing section that fits before adding a new one. Mapping:
|
|
217
226
|
|
|
@@ -228,31 +237,25 @@ For each 🔴 / 🟡 finding, draft the smallest possible edit that, **if it had
|
|
|
228
237
|
- One bullet per finding. Reference the evidence ticket ("S058 smoke name", "#103 missing disclaimer") so the line stays auditable.
|
|
229
238
|
- Do **not** invent new top-level sections unless three findings legitimately share one.
|
|
230
239
|
|
|
231
|
-
Show all drafts as one unified diff per target file before applying. Group by target file: pi-dev's `skills/<name>/SKILL.md` first (
|
|
240
|
+
Show all drafts as one unified diff per target file before applying. Group by target file: pi-dev's `skills/<name>/SKILL.md` first (framework), then the consumer's `docs/agents/preferences.md` (consumer-prefs).
|
|
232
241
|
|
|
233
242
|
### 7 — Apply, release, verify (branches on scope)
|
|
234
243
|
|
|
235
244
|
Run both branches if the audit produced mixed-scope findings. Each branch has its own terminal state.
|
|
236
245
|
|
|
237
|
-
**7a.
|
|
246
|
+
**7a. Framework branch** — only if any finding was approved as `framework`:
|
|
238
247
|
|
|
239
|
-
1. From the pi-dev checkout: `git add skills/<name>/SKILL.md && git commit -m "<conventional commit anchoring the evidence>"`. Commit body must cite the signal that motivated each change.
|
|
248
|
+
1. From the pi-dev checkout (this repo): `git add skills/<name>/SKILL.md && git commit -m "<conventional commit anchoring the evidence>"`. Commit body must cite the signal that motivated each change.
|
|
240
249
|
2. `cp` each edited SKILL.md into `~/.pi/agent/skills/<name>/` so the **next** session anywhere picks up the change immediately (release-please takes a minute and a half).
|
|
241
250
|
3. `git push origin main`; release-please opens the version-bump PR; merge it; npm publish runs automatically.
|
|
242
251
|
4. Confirm `npm view pi-dev@latest version` matches the bumped tag.
|
|
243
252
|
|
|
244
|
-
**
|
|
253
|
+
**7b. Consumer-prefs branch** — only if any finding was approved as `consumer-prefs`:
|
|
245
254
|
|
|
246
|
-
1.
|
|
247
|
-
2. Open an issue on `pi-dev` (or a PR if the operator has clone+push rights) with the evidence excerpts and the patch attached.
|
|
248
|
-
3. As a hotfix for this machine only, optionally `cp` the edited bodies into `~/.pi/agent/skills/<name>/` and note in the issue that the next `pi-dev update` will overwrite them — which is the desired end state once the upstream change lands.
|
|
249
|
-
|
|
250
|
-
**7b. Project branch** — only if any finding was approved as `project`:
|
|
251
|
-
|
|
252
|
-
1. In the consumer repo: edit `docs/agents/preferences.md` per the drafts from Step 6. Keep the migration marker at the very end of the file undisturbed.
|
|
255
|
+
1. In the audited consumer repo: edit `docs/agents/preferences.md` per the drafts from Step 6. Keep the migration marker at the very end of the file undisturbed.
|
|
253
256
|
2. Bump the `last-updated` line at the top of the file to today's UTC date.
|
|
254
257
|
3. `git add docs/agents/preferences.md && git commit -m "docs(agents): <one-liner per finding>"`. Conventional Commits apply.
|
|
255
|
-
4. Push per
|
|
258
|
+
4. Push per that repo's normal workflow. No release-please involvement — preferences are not packaged.
|
|
256
259
|
|
|
257
260
|
**Verification (both branches).** After the next pi session in the affected repo:
|
|
258
261
|
|
|
@@ -265,9 +268,9 @@ Run both branches if the audit produced mixed-scope findings. Each branch has it
|
|
|
265
268
|
This skill is done when **all four** are true:
|
|
266
269
|
|
|
267
270
|
1. A signal table with severities and evidence excerpts has been presented.
|
|
268
|
-
2. Each finding has an approved scope (`
|
|
269
|
-
3. Either (a) zero 🔴 findings — flow is healthy, recorded as "no change this cycle", OR (b) each 🔴 finding has landed in its scope's target file
|
|
270
|
-
4. For any landed change: if `
|
|
271
|
+
2. Each finding has an approved scope (`framework` / `consumer-prefs` / `defer`) on record, defaulted by Step 5.5 and confirmed by the maintainer.
|
|
272
|
+
3. Either (a) zero 🔴 findings — flow is healthy, recorded as "no change this cycle", OR (b) each 🔴 finding has landed in its scope's target file.
|
|
273
|
+
4. For any landed change: if `framework`, the npm version has bumped (`npm view pi-dev@latest version`); if `consumer-prefs`, the consumer repo has the commit on its push-stream. Either way, the next-session re-audit plan is stated.
|
|
271
274
|
|
|
272
275
|
The summary's **last line** must be one of:
|
|
273
276
|
|
|
@@ -276,17 +279,14 @@ audit complete — no changes this cycle.
|
|
|
276
279
|
```
|
|
277
280
|
|
|
278
281
|
```
|
|
279
|
-
audit complete —
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
```
|
|
283
|
-
audit complete — upstream issue <#N> filed, project commit <sha>, hotfix mirrored to ~/.pi.
|
|
282
|
+
audit complete — framework v<X.Y.Z> released, consumer-prefs commit <sha>, next re-audit after the next session.
|
|
284
283
|
```
|
|
285
284
|
|
|
286
285
|
## What this skill does not do
|
|
287
286
|
|
|
288
|
-
- It does not modify a consumer repo's code
|
|
287
|
+
- It does not modify a consumer repo's code or issues. It edits **pi-dev's own `skills/`** (framework scope) and — only when the audit demands it — the consumer's `docs/agents/preferences.md` (consumer-prefs scope).
|
|
289
288
|
- It does not invent gaps from first principles. Every finding must come from a session excerpt or a repo-state probe.
|
|
289
|
+
- It does not run from a consumer repo. The Pre-flight gate refuses; cd into pi-dev first.
|
|
290
290
|
- It does not run faster than the data allows — if there is only one session, run it but say so up front; the signal is noisy.
|
|
291
291
|
|
|
292
292
|
## Heuristics
|
|
@@ -299,4 +299,4 @@ audit complete — upstream issue <#N> filed, project commit <sha>, hotfix mirro
|
|
|
299
299
|
|
|
300
300
|
## Why this skill exists
|
|
301
301
|
|
|
302
|
-
Skills are prose. Prose drifts. Without a feedback loop, the SKILL.md files become wishful thinking that the agent ignores in real sessions. This skill is the loop.
|
|
302
|
+
Skills are prose. Prose drifts. Without a feedback loop, the SKILL.md files become wishful thinking that the agent ignores in real sessions. This skill is the loop — and it is the maintainer's loop, not the consumer's.
|
package/skills/where/SKILL.md
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: where
|
|
3
|
-
description:
|
|
3
|
+
description: Answer "where are we?" for this cwd — what stage the work is at, what just happened, and what comes next — by reading prior pi sessions, git, and the issue tracker. Use when the user says "지금 어디야", "우리 어디까지 했지", "지난주에 뭐했지", "where were we", "이어서 가자", "다시 시작", "다음 로드맵", or when /do detects continuation intent.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# /where —
|
|
6
|
+
# /where — Where Are We?
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
The essence of this skill: answer three questions, in this order, about the current cwd.
|
|
9
|
+
|
|
10
|
+
1. **어디까지 왔나 (stage)** — what phase / slice / release the work is in *right now*.
|
|
11
|
+
2. **최근 뭐했나 (recent)** — what the last 1–3 sessions actually did, condensed.
|
|
12
|
+
3. **다음 뭐 할까 (next)** — the most plausible next action, with the file / issue / command that picks it up.
|
|
13
|
+
|
|
14
|
+
pi stores every session as a JSONL stream under `~/.pi/agent/sessions/<encoded-cwd>/<ts>_<sessionId>.jsonl`. That stream plus `git log` plus the issue tracker are the three signals this skill fuses to answer the three questions above. Without that fusion, "recall" is just history dumping; with it, the user can resume in one turn.
|
|
9
15
|
|
|
10
16
|
## When to use
|
|
11
17
|
|
|
@@ -19,18 +25,35 @@ Do not use:
|
|
|
19
25
|
- To bypass the migration gate (it doesn't)
|
|
20
26
|
- As a replacement for ADRs, CONTEXT.md, or issues (those are the durable channels)
|
|
21
27
|
|
|
28
|
+
## Default action (zero-message invocation)
|
|
29
|
+
|
|
30
|
+
When `/where` is invoked with **no accompanying user text** (the SKILL block is the only thing in the user turn), the invocation itself is the request: *"지금 어디야, 최근 뭐했고, 다음은 뭐야?"*
|
|
31
|
+
|
|
32
|
+
Default behaviour, executed immediately and in the same turn:
|
|
33
|
+
|
|
34
|
+
1. Run the full Process below with the **default relevance window** (last 3 sessions by mtime).
|
|
35
|
+
2. Render the position card (the three sections: stage / recent / next).
|
|
36
|
+
3. End with the next-action proposal as a question the user can confirm or correct.
|
|
37
|
+
|
|
38
|
+
Do **not** print preamble like "What would you like me to recall?" or "Please specify a date range." The user already chose the skill; the only legal opening move is to start producing the card. Ask for narrowing only if Step 1 finds zero session files **and** `git log` shows no recent commits.
|
|
39
|
+
|
|
22
40
|
## Process
|
|
23
41
|
|
|
42
|
+
Execute these steps as your **first action** after the skill loads. Do not narrate the plan, do not ask whether to proceed — run Step 1 immediately.
|
|
43
|
+
|
|
24
44
|
### 1. Resolve session directory
|
|
25
45
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
46
|
+
Run this bash, do not just describe it:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cwd="$(pwd)"
|
|
50
|
+
encoded="--$(echo "$cwd" | sed 's|^/||; s|/|-|g')--"
|
|
51
|
+
sessions_dir="$HOME/.pi/agent/sessions/$encoded"
|
|
52
|
+
[ -d "$sessions_dir" ] || { echo "no prior pi sessions for this cwd: $cwd"; exit 0; }
|
|
53
|
+
ls -t "$sessions_dir"/*.jsonl 2>/dev/null | head -3
|
|
31
54
|
```
|
|
32
55
|
|
|
33
|
-
If
|
|
56
|
+
If the directory does not exist, print exactly `no prior pi sessions for this cwd` and stop — nothing else to do.
|
|
34
57
|
|
|
35
58
|
### 2. Pick relevance window
|
|
36
59
|
|
|
@@ -44,64 +67,116 @@ ls -t ~/.pi/agent/sessions/$encoded/*.jsonl | head -3
|
|
|
44
67
|
|
|
45
68
|
For each candidate file, read just the **first 3 lines** to get session metadata (id, model, cwd, timestamp). Skip files older than the window.
|
|
46
69
|
|
|
47
|
-
### 4. Targeted extraction
|
|
70
|
+
### 4. Targeted extraction (per session) — with a hard context budget
|
|
71
|
+
|
|
72
|
+
A session jsonl can be hundreds of KB and a single tool result can be 10–20 KB. Never load full message bodies into context. Pull only what answers the three questions, truncate every excerpt, and enforce a byte budget.
|
|
73
|
+
|
|
74
|
+
**Budget (non-negotiable):**
|
|
75
|
+
|
|
76
|
+
- **≤ 8 KB total** extracted text per session into context.
|
|
77
|
+
- **≤ 3 sessions** by default → worst case ≈ 24 KB.
|
|
78
|
+
- Per user message: first 200 chars.
|
|
79
|
+
- Per assistant text block: first 400 chars (final summaries / decisions only — see filter).
|
|
80
|
+
- **Skip `toolResult` blocks entirely.** They are the biggest context killers and they rarely add signal that the surrounding text doesn't already convey.
|
|
81
|
+
- **Skip `thinking` blocks entirely.**
|
|
82
|
+
|
|
83
|
+
**What to pull from each in-window jsonl:**
|
|
84
|
+
|
|
85
|
+
- `message` where `message.role == "user"` — keep only `.message.content[].text` truncated to 200 chars, drop anything else.
|
|
86
|
+
- `message` where `message.role == "assistant"` — keep `.message.content[].text` blocks **only if** they contain one of: a heading, a final summary marker, a commit SHA-like 7-hex, an `https://` URL, or a terminator literal (`chain complete`, `audit complete`, `Final summary`, `## Summary`, `flow complete`). Truncate to 400 chars.
|
|
87
|
+
- pi tool blocks of `name in ("edit", "write")` — keep just the target `path`, drop diffs.
|
|
88
|
+
- pi tool blocks of lower-case `name == "bash"` — keep only those whose `input.command` matches `git commit|git push|gh issue|gh pr|gh release|npm publish`. Keep the command line only, drop output.
|
|
89
|
+
|
|
90
|
+
**Implementation hint (jq, pi format — messages are nested under `.message`; toolCall/toolResult blocks live inside `.message.content[]`). Note the explicit role gate — do NOT remove it; pi emits `toolResult` records with their own `message.role` and they will leak in otherwise:**
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
jq -c '
|
|
94
|
+
select(.type == "message" and (.message.role == "user" or .message.role == "assistant")) |
|
|
95
|
+
. as $m |
|
|
96
|
+
{
|
|
97
|
+
ts: .timestamp,
|
|
98
|
+
role: .message.role,
|
|
99
|
+
text: (
|
|
100
|
+
(.message.content // [])
|
|
101
|
+
| map(select(.type == "text") | .text)
|
|
102
|
+
| join(" ")
|
|
103
|
+
| if $m.message.role == "user" then .[0:200] else .[0:300] end
|
|
104
|
+
),
|
|
105
|
+
paths: (
|
|
106
|
+
(.message.content // [])
|
|
107
|
+
| map(select(.type == "toolCall" and (.name == "edit" or .name == "write")) | .arguments.path // .arguments.file_path // empty)
|
|
108
|
+
),
|
|
109
|
+
cmds: (
|
|
110
|
+
(.message.content // [])
|
|
111
|
+
| map(
|
|
112
|
+
select(.type == "toolCall" and .name == "bash")
|
|
113
|
+
| .arguments.command
|
|
114
|
+
| select(test("git commit|git push|gh issue|gh pr|gh release|npm publish"))
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
| if .role == "assistant" then
|
|
119
|
+
select(.text | test("chain complete|audit complete|Final summary|## Summary|flow complete|^## |https://|[0-9a-f]{7,}"))
|
|
120
|
+
else . end
|
|
121
|
+
| select(.text != "" or (.paths | length) > 0 or (.cmds | length) > 0)
|
|
122
|
+
' <file> | head -25
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
This drops `toolResult` and `thinking` via the explicit role gate, filters assistant text to genuine signals only, truncates per-role, and caps records per session at 25. Measured on a real 653 KB session: output ≈ 6 KB, well inside the 8 KB budget. If `jq` is unavailable, fall back to `grep -E` on raw text and live with the lower precision — still respect the 8 KB-per-session budget.
|
|
48
126
|
|
|
49
|
-
|
|
127
|
+
**If budget exceeded after filtering:** keep the first user message, the last 2 qualifying assistant text blocks, all matching `bash` commands, all edit/write paths. Drop intermediate text blocks. Never echo a `toolResult`.
|
|
50
128
|
|
|
51
|
-
-
|
|
52
|
-
- `message` where `role=assistant` AND content includes one of: a heading, a final summary block, a list of changed files, a commit SHA, an issue URL
|
|
53
|
-
- Tool calls of types: `Edit`, `Write`, `Bash` (filter by command keyword: `git commit|push|gh issue|gh pr`)
|
|
54
|
-
- Any explicit handoff strings (`flow complete`, `Final summary`, `[flow] complete`)
|
|
129
|
+
### 4b. Cross-reference live state (cheap, bounded)
|
|
55
130
|
|
|
56
|
-
|
|
131
|
+
The session log alone says "what was discussed". To answer **stage** and **next** you also need what actually landed. Each probe below caps its own output — do not remove the caps:
|
|
57
132
|
|
|
58
133
|
```bash
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
)' <file>
|
|
134
|
+
git log --since="3 days ago" --pretty=format:"%h %ad %s" --date=short | head -10
|
|
135
|
+
git status -sb | head -20
|
|
136
|
+
# if GitHub is the tracker:
|
|
137
|
+
gh pr list --state open --limit 5 --json number,title,url 2>/dev/null
|
|
138
|
+
gh issue list --state open --limit 5 --json number,title,url 2>/dev/null
|
|
65
139
|
```
|
|
66
140
|
|
|
67
|
-
|
|
141
|
+
Reconcile: a session that ended with a commit + merged PR → stage = shipped; a session that ended with `git status` dirty or an open PR → stage = in flight; a session whose last assistant turn proposed a follow-up command → that command *is* the next action. Each probe must be one command; do not page through history or fetch issue bodies.
|
|
68
142
|
|
|
69
|
-
### 5. Synthesise a
|
|
143
|
+
### 5. Synthesise a position card
|
|
70
144
|
|
|
71
|
-
Output exactly this shape, no more
|
|
145
|
+
Output exactly this three-section shape, no more. Each section answers one of the three questions.
|
|
72
146
|
|
|
73
147
|
```markdown
|
|
74
|
-
##
|
|
148
|
+
## Where we are — <cwd>
|
|
75
149
|
|
|
76
|
-
###
|
|
77
|
-
|
|
78
|
-
- **Touched**: <comma-separated file paths from Edit/Write tools>
|
|
79
|
-
- **Side effects**: <commit SHAs / issue URLs / PR URLs>
|
|
80
|
-
- **State**: <complete | incomplete: <reason>>
|
|
150
|
+
### Stage (어디까지 왔나)
|
|
151
|
+
<2–4 lines: current branch, last shipped version / merged PR, any open Release PR, any in-flight slice. One sentence per fact, no narration.>
|
|
81
152
|
|
|
82
|
-
###
|
|
83
|
-
...
|
|
153
|
+
### Recent (최근 뭐했나 — last <N> sessions)
|
|
84
154
|
|
|
85
|
-
|
|
155
|
+
- **<YYYY-MM-DD HH:MM> — <short-id>**: <intent in one line> → <files touched, condensed> → <side effects: commit SHA / PR / issue URL> — <complete | incomplete: <reason>>
|
|
156
|
+
- **<YYYY-MM-DD HH:MM> — <short-id>**: …
|
|
86
157
|
|
|
87
|
-
|
|
158
|
+
### Next (다음 뭐 할까)
|
|
159
|
+
<one paragraph: the single most plausible next action, named with the exact file / issue # / command that picks it up. If multiple candidates, rank them and pick #1; list #2–3 in one line.>
|
|
88
160
|
```
|
|
89
161
|
|
|
90
|
-
Stop here. Do not start work. The
|
|
162
|
+
Stop here. Do not start work. The Next section is the bridge to `/do` — it states an action, not a menu.
|
|
91
163
|
|
|
92
164
|
### 6. Hand off
|
|
93
165
|
|
|
94
|
-
If the user confirms the
|
|
166
|
+
End with one short question: "이걸로 갈까?" (or English equivalent). If the user confirms the Next action, invoke `/do` with the resolved intent + scope. If the user picks a different candidate or corrects the framing, run Step 1 again with the narrower window and try once more.
|
|
95
167
|
|
|
96
168
|
## Privacy / safety
|
|
97
169
|
|
|
98
170
|
- Sessions can contain secrets that were pasted in. Do not echo full message bodies in the recall card; extract only headings, file paths, URLs, SHAs.
|
|
99
171
|
- Never write the recall card to a file in the repo. It lives in conversation context only.
|
|
100
172
|
|
|
101
|
-
## Performance
|
|
173
|
+
## Performance & context budget
|
|
102
174
|
|
|
103
|
-
-
|
|
104
|
-
-
|
|
175
|
+
- **Wallclock target:** < 2 seconds for the cheap pass + targeted extraction across 3 sessions.
|
|
176
|
+
- **Context budget:** ≤ 8 KB extracted per session, ≤ 24 KB total before rendering the card. This is the limit, not a goal.
|
|
177
|
+
- **Always strip toolResult and thinking blocks.** They cause context bloat without changing the answer to the three questions.
|
|
178
|
+
- If a single jsonl is > 5 MB, sample: `head -2000` + `tail -2000` lines (still feed them through the Step 4 jq filter — do not raw-cat).
|
|
179
|
+
- If after filtering a session still exceeds 8 KB, keep first user message + last 2 qualifying assistant blocks + all matching bash commands + all edit/write paths; drop the rest.
|
|
105
180
|
|
|
106
181
|
## Limits
|
|
107
182
|
|