@static-var/keystone 0.1.0
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/.agents/plugins/marketplace.json +24 -0
- package/.claude-plugin/marketplace.json +24 -0
- package/.claude-plugin/plugin.json +12 -0
- package/.codex-plugin/plugin.json +12 -0
- package/.pi/extensions/keystone.ts +172 -0
- package/HOW_IT_WORKS.md +424 -0
- package/Makefile +19 -0
- package/README.md +253 -0
- package/package.json +86 -0
- package/packaging.allowlist +32 -0
- package/scripts/build-metadata.py +99 -0
- package/scripts/package-keystone.sh +59 -0
- package/scripts/validate-keystone.py +261 -0
- package/scripts/validate-package.py +140 -0
- package/skills/keystone/SKILL.md +69 -0
- package/skills/keystone/modules/breakdown.md +239 -0
- package/skills/keystone/modules/build.md +284 -0
- package/skills/keystone/modules/debug.md +198 -0
- package/skills/keystone/modules/gates/isolation.md +56 -0
- package/skills/keystone/modules/gates/proof.md +54 -0
- package/skills/keystone/modules/gates/red.md +59 -0
- package/skills/keystone/modules/gates/review.md +56 -0
- package/skills/keystone/modules/gates/ship.md +57 -0
- package/skills/keystone/modules/health.md +124 -0
- package/skills/keystone/modules/helpers/subagents.md +134 -0
- package/skills/keystone/modules/research.md +86 -0
- package/skills/keystone/modules/review.md +270 -0
- package/skills/keystone/modules/router.md +36 -0
- package/skills/keystone/modules/shape.md +125 -0
- package/skills/keystone/modules/ship.md +130 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Use when the user invokes /keystone or asks Keystone to route product, research, writing, UI, design, planning, implementation, debugging, review, shipping, or health work through its canonical orchestrator.",
|
|
3
|
+
"displayName": "Keystone",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"pi-package",
|
|
6
|
+
"agent-skills",
|
|
7
|
+
"keystone",
|
|
8
|
+
"claude-code",
|
|
9
|
+
"codex",
|
|
10
|
+
"opencode",
|
|
11
|
+
"copilot",
|
|
12
|
+
"pi-coding-agent",
|
|
13
|
+
"pi-extension",
|
|
14
|
+
"workflow",
|
|
15
|
+
"skills",
|
|
16
|
+
"agent-workflows"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"name": "keystone",
|
|
20
|
+
"skills": [
|
|
21
|
+
"keystone"
|
|
22
|
+
],
|
|
23
|
+
"version": "0.1.0"
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Use when the user invokes /keystone or asks Keystone to route product, research, writing, UI, design, planning, implementation, debugging, review, shipping, or health work through its canonical orchestrator.",
|
|
3
|
+
"displayName": "Keystone",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"pi-package",
|
|
6
|
+
"agent-skills",
|
|
7
|
+
"keystone",
|
|
8
|
+
"claude-code",
|
|
9
|
+
"codex",
|
|
10
|
+
"opencode",
|
|
11
|
+
"copilot",
|
|
12
|
+
"pi-coding-agent",
|
|
13
|
+
"pi-extension",
|
|
14
|
+
"workflow",
|
|
15
|
+
"skills",
|
|
16
|
+
"agent-workflows"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"name": "keystone",
|
|
20
|
+
"skills": [
|
|
21
|
+
"keystone"
|
|
22
|
+
],
|
|
23
|
+
"version": "0.1.0"
|
|
24
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Use when the user invokes /keystone or asks Keystone to route product, research, writing, UI, design, planning, implementation, debugging, review, shipping, or health work through its canonical orchestrator.",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"name": "keystone",
|
|
5
|
+
"skills": [
|
|
6
|
+
{
|
|
7
|
+
"name": "keystone",
|
|
8
|
+
"path": "../skills/keystone/SKILL.md"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"version": "0.1.0"
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Use when the user invokes /keystone or asks Keystone to route product, research, writing, UI, design, planning, implementation, debugging, review, shipping, or health work through its canonical orchestrator.",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"name": "keystone",
|
|
5
|
+
"skills": [
|
|
6
|
+
{
|
|
7
|
+
"name": "keystone",
|
|
8
|
+
"path": "../skills/keystone/SKILL.md"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"version": "0.1.0"
|
|
12
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
5
|
+
|
|
6
|
+
const EXTREMELY_IMPORTANT_MARKER = "<EXTREMELY_IMPORTANT>";
|
|
7
|
+
const BOOTSTRAP_MARKER = "keystone:bootstrap for pi";
|
|
8
|
+
|
|
9
|
+
const extensionDir = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const packageRoot = resolve(extensionDir, "../..");
|
|
11
|
+
const skillsDir = resolve(packageRoot, "skills");
|
|
12
|
+
const keystoneSkillPath = resolve(skillsDir, "keystone", "SKILL.md");
|
|
13
|
+
|
|
14
|
+
let cachedSkillBody: string | null | undefined;
|
|
15
|
+
let cachedBootstrap: string | null | undefined;
|
|
16
|
+
|
|
17
|
+
export default function keystonePiExtension(pi: ExtensionAPI) {
|
|
18
|
+
let injectBootstrap = true;
|
|
19
|
+
|
|
20
|
+
pi.on("resources_discover", async () => ({
|
|
21
|
+
skillPaths: [skillsDir],
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
pi.on("session_start", async () => {
|
|
25
|
+
injectBootstrap = true;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
pi.on("session_compact", async () => {
|
|
29
|
+
injectBootstrap = true;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
pi.on("agent_end", async () => {
|
|
33
|
+
injectBootstrap = false;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
pi.on("context", async (event) => {
|
|
37
|
+
if (!injectBootstrap) return;
|
|
38
|
+
if (event.messages.some(messageContainsBootstrap)) return;
|
|
39
|
+
|
|
40
|
+
const bootstrap = getBootstrapContent();
|
|
41
|
+
if (!bootstrap) return;
|
|
42
|
+
|
|
43
|
+
const bootstrapMessage = {
|
|
44
|
+
role: "user" as const,
|
|
45
|
+
content: [{ type: "text" as const, text: bootstrap }],
|
|
46
|
+
timestamp: Date.now(),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const insertAt = firstNonCompactionSummaryIndex(event.messages);
|
|
50
|
+
return {
|
|
51
|
+
messages: [
|
|
52
|
+
...event.messages.slice(0, insertAt),
|
|
53
|
+
bootstrapMessage,
|
|
54
|
+
...event.messages.slice(insertAt),
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
pi.registerCommand("keystone", {
|
|
60
|
+
description: "Run the Keystone workflow router on a request",
|
|
61
|
+
handler: async (args, ctx) => {
|
|
62
|
+
const content = getCommandContent(args);
|
|
63
|
+
if (!content) {
|
|
64
|
+
ctx.ui.notify("Keystone skill not found in this package.", "error");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (ctx.isIdle()) {
|
|
69
|
+
pi.sendUserMessage(content);
|
|
70
|
+
} else {
|
|
71
|
+
pi.sendUserMessage(content, { deliverAs: "followUp" });
|
|
72
|
+
ctx.ui.notify("Queued Keystone as a follow-up.", "info");
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getBootstrapContent(): string | null {
|
|
79
|
+
if (cachedBootstrap !== undefined) return cachedBootstrap;
|
|
80
|
+
|
|
81
|
+
const body = getSkillBody();
|
|
82
|
+
if (!body) {
|
|
83
|
+
cachedBootstrap = null;
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
cachedBootstrap = `${EXTREMELY_IMPORTANT_MARKER}
|
|
88
|
+
${BOOTSTRAP_MARKER}
|
|
89
|
+
|
|
90
|
+
Keystone is available in this Pi session.
|
|
91
|
+
|
|
92
|
+
Use Keystone when the user invokes \`/keystone\` or explicitly asks for Keystone/workflow routing. Otherwise continue normally and do not override user intent.
|
|
93
|
+
|
|
94
|
+
The Keystone entrypoint is included below. When Keystone applies, follow it and route internally by reading the chosen module files. Do not expose internal modules as public slash commands.
|
|
95
|
+
|
|
96
|
+
${body}
|
|
97
|
+
|
|
98
|
+
${piToolMapping()}
|
|
99
|
+
</EXTREMELY_IMPORTANT>`;
|
|
100
|
+
return cachedBootstrap;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function getCommandContent(args: string): string | null {
|
|
104
|
+
const body = getSkillBody();
|
|
105
|
+
if (!body) return null;
|
|
106
|
+
|
|
107
|
+
const request = args.trim() || "No request supplied. Briefly explain how to use `/keystone <task>` and ask for the task.";
|
|
108
|
+
return `${EXTREMELY_IMPORTANT_MARKER}
|
|
109
|
+
${BOOTSTRAP_MARKER}
|
|
110
|
+
|
|
111
|
+
You are running Keystone via Pi's \`/keystone\` command.
|
|
112
|
+
|
|
113
|
+
Follow the Keystone entrypoint below. Route internally by reading the chosen module files. Do not expose internal modules as public slash commands.
|
|
114
|
+
|
|
115
|
+
${body}
|
|
116
|
+
|
|
117
|
+
${piToolMapping()}
|
|
118
|
+
|
|
119
|
+
User request for Keystone:
|
|
120
|
+
${request}
|
|
121
|
+
</EXTREMELY_IMPORTANT>`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function getSkillBody(): string | null {
|
|
125
|
+
if (cachedSkillBody !== undefined) return cachedSkillBody;
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
cachedSkillBody = stripFrontmatter(readFileSync(keystoneSkillPath, "utf8"));
|
|
129
|
+
return cachedSkillBody;
|
|
130
|
+
} catch {
|
|
131
|
+
cachedSkillBody = null;
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function stripFrontmatter(content: string): string {
|
|
137
|
+
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
|
|
138
|
+
return (match ? match[1] : content).trim();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function piToolMapping(): string {
|
|
142
|
+
return `## Pi tool mapping
|
|
143
|
+
|
|
144
|
+
Pi has native skills, but Keystone should use this extension's \`/keystone\` command as the public entrypoint. Internal Keystone modules are Markdown files under \`skills/keystone/modules/\`; read the selected module file instead of inventing \`/shape\`, \`/breakdown\`, \`/build\`, \`/debug\`, \`/review\`, \`/ship\`, \`/health\`, or other public module commands.
|
|
145
|
+
|
|
146
|
+
Pi's built-in coding tools are lowercase: \`read\`, \`write\`, \`edit\`, \`bash\`, plus optional \`grep\`, \`find\`, and \`ls\`. Use those for file inspection, mutation, shell commands, and search.
|
|
147
|
+
|
|
148
|
+
If \`pi-subagents\` or another subagent tool is available, follow Keystone's \`modules/helpers/subagents.md\` guidance. If no subagent tool is available, do the work in this session and state that delegation was unavailable instead of inventing unsupported tools.`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function messageContainsBootstrap(message: unknown): boolean {
|
|
152
|
+
const content = (message as { content?: unknown }).content;
|
|
153
|
+
if (typeof content === "string") return content.includes(BOOTSTRAP_MARKER);
|
|
154
|
+
if (!Array.isArray(content)) return false;
|
|
155
|
+
return content.some((part) => {
|
|
156
|
+
return (
|
|
157
|
+
part &&
|
|
158
|
+
typeof part === "object" &&
|
|
159
|
+
(part as { type?: unknown }).type === "text" &&
|
|
160
|
+
typeof (part as { text?: unknown }).text === "string" &&
|
|
161
|
+
(part as { text: string }).text.includes(BOOTSTRAP_MARKER)
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function firstNonCompactionSummaryIndex(messages: unknown[]): number {
|
|
167
|
+
let index = 0;
|
|
168
|
+
while ((messages[index] as { role?: unknown } | undefined)?.role === "compactionSummary") {
|
|
169
|
+
index += 1;
|
|
170
|
+
}
|
|
171
|
+
return index;
|
|
172
|
+
}
|
package/HOW_IT_WORKS.md
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
# How Keystone Works
|
|
2
|
+
|
|
3
|
+
Keystone is easiest to understand as a building with one front door and many private rooms.
|
|
4
|
+
|
|
5
|
+
The front door is `/keystone`. The private rooms are internal modules. The gates are checkpoints that stop the agent from doing risky work too early.
|
|
6
|
+
|
|
7
|
+
## The short version
|
|
8
|
+
|
|
9
|
+
Keystone does five things:
|
|
10
|
+
|
|
11
|
+
1. **Receives a request** through one public skill: `/keystone`.
|
|
12
|
+
2. **Routes the request** to exactly one internal module.
|
|
13
|
+
3. **Applies that module's contract** so the agent knows what it may and may not do.
|
|
14
|
+
4. **Loads gates only when needed** to protect mutation, verification, review, and shipping.
|
|
15
|
+
5. **Hands off cleanly** to the next module when the work changes shape.
|
|
16
|
+
|
|
17
|
+
When the host supports subagents, Keystone can delegate bounded work with the right reasoning level. When the host does not support that control, Keystone treats reasoning level as prompt guidance instead of a guaranteed setting.
|
|
18
|
+
|
|
19
|
+
This keeps the agent from mixing jobs. Planning stays planning. Building stays building. Review stays read-only. Shipping only happens after proof and review.
|
|
20
|
+
|
|
21
|
+
## Why Keystone exists
|
|
22
|
+
|
|
23
|
+
Agent workflows often fail for predictable reasons:
|
|
24
|
+
|
|
25
|
+
- the agent starts editing before understanding the workspace
|
|
26
|
+
- a plan is treated as proof of completion
|
|
27
|
+
- review turns into implementation
|
|
28
|
+
- shipping happens before verification
|
|
29
|
+
- too many public commands overlap and conflict
|
|
30
|
+
- platform-specific packaging drifts away from the real source
|
|
31
|
+
|
|
32
|
+
Keystone counters those failures with a small public surface and explicit internal contracts.
|
|
33
|
+
|
|
34
|
+
## The public surface
|
|
35
|
+
|
|
36
|
+
There is one public skill:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
skills/keystone/SKILL.md
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
That file is the only public entrypoint. Users invoke Keystone with `/keystone` or by asking Keystone to route work.
|
|
43
|
+
|
|
44
|
+
Everything else in the shipped skill is internal:
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
skills/keystone/modules/*.md
|
|
48
|
+
skills/keystone/modules/gates/*.md
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Internal modules are named in the public skill, but they are not separate slash commands.
|
|
52
|
+
|
|
53
|
+
Maintainer-only notes may live elsewhere in the repository, such as `maintainers/skill-engineering.md`. Those files are not part of the shipped product.
|
|
54
|
+
|
|
55
|
+
## Request lifecycle
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
1. User asks for work
|
|
59
|
+
│
|
|
60
|
+
▼
|
|
61
|
+
2. Keystone public skill loads
|
|
62
|
+
│
|
|
63
|
+
▼
|
|
64
|
+
3. Router selects one primary module
|
|
65
|
+
│
|
|
66
|
+
▼
|
|
67
|
+
4. The module contract controls the work
|
|
68
|
+
│
|
|
69
|
+
▼
|
|
70
|
+
5. Gates run only if the module needs them
|
|
71
|
+
│
|
|
72
|
+
▼
|
|
73
|
+
6. Keystone reports result or hands off to the next module
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The important phrase is **one primary module**. Keystone avoids blending roles unless a module explicitly hands off.
|
|
77
|
+
|
|
78
|
+
## Modules
|
|
79
|
+
|
|
80
|
+
Each module has the same shape:
|
|
81
|
+
|
|
82
|
+
- **Intent:** what the module is for
|
|
83
|
+
- **Load when:** when Keystone should choose it
|
|
84
|
+
- **Allowed mutation:** what files or artifacts it may change
|
|
85
|
+
- **Must not:** hard boundaries
|
|
86
|
+
- **May call:** allowed handoffs or gates
|
|
87
|
+
- **Handoff:** what it should report when done
|
|
88
|
+
- **Exit gate:** what must be true before leaving the module
|
|
89
|
+
|
|
90
|
+
### Module catalogue
|
|
91
|
+
|
|
92
|
+
| Module | Job | Hard boundary |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `router` | Choose the right module | Does not do the work itself |
|
|
95
|
+
| `research` | Inspect, summarize, gather evidence, and compare options | Does not edit or present guesses as facts |
|
|
96
|
+
| `shape` | Draft prose, shape product direction, UI/UX, visual direction, and scope | Does not implement or treat a spec as proof |
|
|
97
|
+
| `breakdown` | Convert approved direction into ordered tasks | Is not named `plan` |
|
|
98
|
+
| `build` | Mutate scoped files | Must pass isolation before first mutation |
|
|
99
|
+
| `debug` | Diagnose failures from evidence | Does not guess fixes |
|
|
100
|
+
| `review` | Evaluate work without changing it | Read-only: no fixes, commits, or shipping |
|
|
101
|
+
| `ship` | Finalize completed work | Does not start new implementation |
|
|
102
|
+
| `health` | Assess project/tooling condition | Does not silently fix issues |
|
|
103
|
+
|
|
104
|
+
## Subagents and reasoning
|
|
105
|
+
|
|
106
|
+
Keystone's subagent guidance lives in:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
skills/keystone/modules/helpers/subagents.md
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The helper records:
|
|
113
|
+
|
|
114
|
+
- which target harnesses support subagents
|
|
115
|
+
- whether they can set per-subagent reasoning or only model/prompt hints
|
|
116
|
+
- how to configure each host when support exists
|
|
117
|
+
- default reasoning levels for every Keystone module
|
|
118
|
+
|
|
119
|
+
### Host capability summary
|
|
120
|
+
|
|
121
|
+
| Harness | Subagents | Reasoning control |
|
|
122
|
+
|---|---:|---|
|
|
123
|
+
| Pi coding agent with `pi-subagents` | yes | native `thinking`, `model`, and `profile` per agent/invocation |
|
|
124
|
+
| Claude Code | yes | model selection and built-in Explore detail; no general custom-agent reasoning field confirmed |
|
|
125
|
+
| Codex CLI/app | host-dependent | global `model_reasoning_effort`; per-subagent effort not confirmed |
|
|
126
|
+
| T3 Code | not confirmed | not confirmed |
|
|
127
|
+
| OpenCode | yes | partial/provider-dependent: `model` plus provider-specific `variant`; no universal reasoning knob confirmed |
|
|
128
|
+
| GitHub Copilot / VS Code | yes | custom agent `model`; no general reasoning field confirmed |
|
|
129
|
+
|
|
130
|
+
### Module reasoning defaults
|
|
131
|
+
|
|
132
|
+
| Module group | Default reasoning |
|
|
133
|
+
|---|---|
|
|
134
|
+
| router, simple reading, simple writing | `low` to `medium` |
|
|
135
|
+
| research, shape, build, health, ship | `medium`, escalating to `high` for risk |
|
|
136
|
+
| breakdown, debug, review, high-stakes shape decisions | `high`, escalating to `xhigh` for hard or irreversible work |
|
|
137
|
+
| gates | `low`, escalating only when evidence is safety-critical |
|
|
138
|
+
|
|
139
|
+
The rule is simple: use the narrowest subagent role and the lowest reasoning level that can safely complete the task. Escalate for ambiguity, irreversible decisions, security, data loss, release risk, or root-cause uncertainty.
|
|
140
|
+
|
|
141
|
+
## Gates
|
|
142
|
+
|
|
143
|
+
Gates are small checks loaded by modules when needed.
|
|
144
|
+
|
|
145
|
+
| Gate | Purpose | Usually used by |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `isolation` | Confirm mutation is safe before editing | `build` |
|
|
148
|
+
| `red` | Establish a failing check or reproduction when practical | `build`, `debug` |
|
|
149
|
+
| `proof` | Verify claims with evidence before success reports | `debug`, `ship`, `health` |
|
|
150
|
+
| `review` | Confirm required review has no blockers | `ship` |
|
|
151
|
+
| `ship` | Confirm verified, reviewed work is ready for handoff | `ship` |
|
|
152
|
+
|
|
153
|
+
The gates are deliberately boring. Their job is to stop common mistakes, not to be clever.
|
|
154
|
+
|
|
155
|
+
## Why `breakdown`, not `plan`
|
|
156
|
+
|
|
157
|
+
Many tools already use `/plan`. Keystone keeps `/keystone` as the only public entrypoint and uses `breakdown` internally for task decomposition.
|
|
158
|
+
|
|
159
|
+
So this is correct:
|
|
160
|
+
|
|
161
|
+
```text
|
|
162
|
+
/keystone → breakdown
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
This is not:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
/plan
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The name also clarifies the job: `breakdown` turns an approved direction into verifiable work items. It does not mean the work is done.
|
|
172
|
+
|
|
173
|
+
## Build vs. ship
|
|
174
|
+
|
|
175
|
+
Keystone separates implementation from finalization.
|
|
176
|
+
|
|
177
|
+
### Build
|
|
178
|
+
|
|
179
|
+
`build` is for changing files. Before the first mutation it must check isolation:
|
|
180
|
+
|
|
181
|
+
- What branch/worktree are we in?
|
|
182
|
+
- What files are protected?
|
|
183
|
+
- Are there unrelated dirty changes?
|
|
184
|
+
- Is the requested scope clear?
|
|
185
|
+
|
|
186
|
+
`build` may implement, refactor, edit, or create files. It does not merge, publish, or call the work shippable by itself.
|
|
187
|
+
|
|
188
|
+
### Ship
|
|
189
|
+
|
|
190
|
+
`ship` is for finalizing completed work. It can prepare delivery notes, package output, PR/merge handoff, or release readiness.
|
|
191
|
+
|
|
192
|
+
It should only run after proof and review are satisfied or explicitly waived.
|
|
193
|
+
|
|
194
|
+
## Review is read-only
|
|
195
|
+
|
|
196
|
+
The `review` module never fixes. This is intentional.
|
|
197
|
+
|
|
198
|
+
A reviewer that edits while reviewing blurs evidence. Keystone keeps review as a report:
|
|
199
|
+
|
|
200
|
+
- blockers
|
|
201
|
+
- non-blocking findings
|
|
202
|
+
- evidence
|
|
203
|
+
- recommended owner module for follow-up
|
|
204
|
+
|
|
205
|
+
If something must be fixed, Keystone routes back to `build` or `debug`.
|
|
206
|
+
|
|
207
|
+
## Packaging model
|
|
208
|
+
|
|
209
|
+
Keystone uses a canonical-source packaging pipeline.
|
|
210
|
+
|
|
211
|
+
```text
|
|
212
|
+
canonical skill source
|
|
213
|
+
│
|
|
214
|
+
▼
|
|
215
|
+
make regenerate
|
|
216
|
+
│
|
|
217
|
+
├─ .claude-plugin/plugin.json
|
|
218
|
+
├─ .claude-plugin/marketplace.json
|
|
219
|
+
├─ .codex-plugin/plugin.json
|
|
220
|
+
└─ .agents/plugins/marketplace.json
|
|
221
|
+
│
|
|
222
|
+
▼
|
|
223
|
+
make package
|
|
224
|
+
│
|
|
225
|
+
▼
|
|
226
|
+
dist/keystone.zip
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The canonical source is:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
skills/keystone/
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Generated manifests should not be hand-edited. Change the canonical source or package metadata, then run:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
make regenerate
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Default-deny packaging
|
|
242
|
+
|
|
243
|
+
The archive is built from `packaging.allowlist`.
|
|
244
|
+
|
|
245
|
+
That means files are not shipped unless they are explicitly allowed.
|
|
246
|
+
|
|
247
|
+
The package script rejects known local or generated noise:
|
|
248
|
+
|
|
249
|
+
- `docs/`
|
|
250
|
+
- `plans/`
|
|
251
|
+
- `index.html`
|
|
252
|
+
- `styles.css`
|
|
253
|
+
- `dist/`
|
|
254
|
+
- `.git/`
|
|
255
|
+
- pycache and `.pyc`
|
|
256
|
+
- `*.plan.md`, `*-plan.md`
|
|
257
|
+
- `*.design.md`, `*-design.md`
|
|
258
|
+
|
|
259
|
+
This keeps the release package focused on the Keystone skill system, not local planning or preview artifacts.
|
|
260
|
+
|
|
261
|
+
## Validators
|
|
262
|
+
|
|
263
|
+
Keystone has three validation layers.
|
|
264
|
+
|
|
265
|
+
### Source validation
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
python3 scripts/validate-keystone.py
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Checks include:
|
|
272
|
+
|
|
273
|
+
- canonical skill exists
|
|
274
|
+
- skill name is `keystone`
|
|
275
|
+
- `breakdown` terminology is present
|
|
276
|
+
- public `/plan` is not introduced
|
|
277
|
+
- referenced modules/gates exist
|
|
278
|
+
- ignored artifacts are not tracked
|
|
279
|
+
- `package.json` has required package and Pi extension/skill metadata
|
|
280
|
+
|
|
281
|
+
### Package validation
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
python3 scripts/validate-package.py dist/keystone.zip
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Checks include:
|
|
288
|
+
|
|
289
|
+
- required package files exist in the archive
|
|
290
|
+
- forbidden files are absent
|
|
291
|
+
- archive contents match the expanded allowlist
|
|
292
|
+
|
|
293
|
+
### Routing validation
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
python3 -m unittest tests/test_routing.py
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Checks include:
|
|
300
|
+
|
|
301
|
+
- routing fixtures are valid
|
|
302
|
+
- every Keystone module has coverage
|
|
303
|
+
- `/plan` routes to `breakdown`, not a public planner
|
|
304
|
+
- fixture prompts match the routing table in `skills/keystone/SKILL.md`
|
|
305
|
+
|
|
306
|
+
## Full verification
|
|
307
|
+
|
|
308
|
+
Run everything with:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
make test
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
This runs metadata generation, packaging, source validation, package validation, routing tests, and Python compile checks.
|
|
315
|
+
|
|
316
|
+
## Platform outputs
|
|
317
|
+
|
|
318
|
+
Keystone currently provides:
|
|
319
|
+
|
|
320
|
+
| Host | Output |
|
|
321
|
+
|---|---|
|
|
322
|
+
| Pi | `.pi/extensions/keystone.ts` plus `package.json` with `pi.extensions` and `pi.skills` |
|
|
323
|
+
| Claude Code | `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json` |
|
|
324
|
+
| Codex | `.codex-plugin/plugin.json` |
|
|
325
|
+
| Agents/Copilot-style hosts | `.agents/plugins/marketplace.json` |
|
|
326
|
+
|
|
327
|
+
The Pi extension mirrors the Superpowers packaging pattern: it discovers bundled skills, registers `/keystone` as the public command, and injects a compact Pi-specific bootstrap while keeping internal modules private.
|
|
328
|
+
|
|
329
|
+
The Pi package gallery at `https://pi.dev/packages` indexes npm packages. Keystone publishes as `@static-var/keystone` with the `pi-package` keyword, so installs use:
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
pi install npm:@static-var/keystone
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Common maintainer workflows
|
|
336
|
+
|
|
337
|
+
### Change routing language
|
|
338
|
+
|
|
339
|
+
1. Edit `skills/keystone/SKILL.md`.
|
|
340
|
+
2. Update `tests/routing/cases.yaml` if behavior changes.
|
|
341
|
+
3. Run `make test`.
|
|
342
|
+
|
|
343
|
+
### Release Keystone
|
|
344
|
+
|
|
345
|
+
1. Confirm the npm scope in `package.json` is owned by the publisher. Keystone currently uses `@static-var/keystone`.
|
|
346
|
+
2. If the npm package does not exist yet, bootstrap it once with `npm login`, `npm run typecheck`, `make test`, and `npm publish --access public --provenance=false`; append `--otp <code>` if npm requires 2FA. npm only exposes Trusted Publisher settings after the package exists.
|
|
347
|
+
3. In npm package access settings for `@static-var/keystone`, configure Trusted Publisher → GitHub Actions with user `static-var`, repository `Keystone`, workflow filename `release.yml`, no environment, and allowed action `npm publish`.
|
|
348
|
+
4. Bump `package.json` with `npm version <patch|minor|major> --no-git-tag-version`.
|
|
349
|
+
5. Run `npm run typecheck` and `make test`.
|
|
350
|
+
6. Commit `package.json` and `package-lock.json`.
|
|
351
|
+
7. Tag the commit as `v<package.json version>` and push `main` plus tags.
|
|
352
|
+
8. The release workflow publishes npm via Trusted Publishing/OIDC with provenance and creates a GitHub Release containing the npm tarball plus `dist/keystone.zip`.
|
|
353
|
+
|
|
354
|
+
### Add a shipped module
|
|
355
|
+
|
|
356
|
+
1. Add `skills/keystone/modules/<name>.md`.
|
|
357
|
+
2. Add a routing row in `skills/keystone/SKILL.md`.
|
|
358
|
+
3. Add routing fixture coverage.
|
|
359
|
+
4. Add a `Subagents and reasoning` section to the module.
|
|
360
|
+
5. Add a module row to `skills/keystone/modules/helpers/subagents.md`.
|
|
361
|
+
6. Ensure packaging includes the module directory through `packaging.allowlist`.
|
|
362
|
+
7. Run `make test`.
|
|
363
|
+
|
|
364
|
+
### Add maintainer-only guidance
|
|
365
|
+
|
|
366
|
+
1. Put it outside `skills/keystone/`, for example under `maintainers/`.
|
|
367
|
+
2. Do not add it to `skills/keystone/SKILL.md` routing.
|
|
368
|
+
3. Do not add it to `packaging.allowlist` unless it is meant to ship.
|
|
369
|
+
4. Run `make test` and inspect `dist/keystone.zip` if packaging changed.
|
|
370
|
+
|
|
371
|
+
### Change packaging metadata
|
|
372
|
+
|
|
373
|
+
1. Edit `package.json` or canonical skill frontmatter.
|
|
374
|
+
2. Run `make regenerate`.
|
|
375
|
+
3. Inspect generated manifests if needed.
|
|
376
|
+
4. Run `make test`.
|
|
377
|
+
|
|
378
|
+
### Prepare a release package
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
make package
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Then inspect:
|
|
385
|
+
|
|
386
|
+
```text
|
|
387
|
+
dist/keystone.zip
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## What should stay out of git
|
|
391
|
+
|
|
392
|
+
These are local or generated artifacts:
|
|
393
|
+
|
|
394
|
+
```text
|
|
395
|
+
dist/
|
|
396
|
+
index.html
|
|
397
|
+
styles.css
|
|
398
|
+
plans/
|
|
399
|
+
scripts/__pycache__/
|
|
400
|
+
tests/__pycache__/
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
They may exist locally, but they should remain ignored.
|
|
404
|
+
|
|
405
|
+
## Mental checklist for Keystone behavior
|
|
406
|
+
|
|
407
|
+
Before changing Keystone, ask:
|
|
408
|
+
|
|
409
|
+
1. Is `/keystone` still the only public entrypoint?
|
|
410
|
+
2. Did we avoid creating `/plan`?
|
|
411
|
+
3. Does each request still route to one primary module?
|
|
412
|
+
4. Does `build` still check isolation before mutation?
|
|
413
|
+
5. Is `review` still read-only?
|
|
414
|
+
6. Does `ship` only finalize already-completed work?
|
|
415
|
+
7. Are generated manifests regenerated from source?
|
|
416
|
+
8. Does `make test` pass?
|
|
417
|
+
|
|
418
|
+
If the answer to any question is no, Keystone's contract has drifted.
|
|
419
|
+
|
|
420
|
+
## Design principle
|
|
421
|
+
|
|
422
|
+
Keystone is not trying to make agents more autonomous by removing structure.
|
|
423
|
+
|
|
424
|
+
It makes agents safer by giving each phase a name, a boundary, and a proof requirement.
|
package/Makefile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.PHONY: test validate package regenerate routing py-compile
|
|
2
|
+
|
|
3
|
+
test: validate routing py-compile
|
|
4
|
+
|
|
5
|
+
validate: package
|
|
6
|
+
python3 scripts/validate-keystone.py
|
|
7
|
+
python3 scripts/validate-package.py dist/keystone.zip
|
|
8
|
+
|
|
9
|
+
routing:
|
|
10
|
+
python3 -m unittest tests/test_routing.py
|
|
11
|
+
|
|
12
|
+
py-compile:
|
|
13
|
+
python3 -m py_compile scripts/build-metadata.py scripts/validate-keystone.py scripts/validate-package.py tests/test_routing.py
|
|
14
|
+
|
|
15
|
+
package: regenerate
|
|
16
|
+
scripts/package-keystone.sh
|
|
17
|
+
|
|
18
|
+
regenerate:
|
|
19
|
+
python3 scripts/build-metadata.py
|