ai-engineering-starter-kit 0.4.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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marcus Bransbury
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # AI Engineering Starter Kit
2
+
3
+ [![CI](https://github.com/bransbury/ai-engineering-starter-kit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/bransbury/ai-engineering-starter-kit/actions/workflows/ci.yml)
4
+ [![License](https://img.shields.io/github/license/bransbury/ai-engineering-starter-kit)](LICENSE.md)
5
+ [![Release](https://img.shields.io/github/v/release/bransbury/ai-engineering-starter-kit)](https://github.com/bransbury/ai-engineering-starter-kit/releases)
6
+
7
+ AI coding agents are now part of everyday engineering work, but the process is often inconsistent. Engineers can prompt normally, yet the quality of the outcome still depends on whether the agent inspects the right code, asks only the necessary questions, plans a safe change, and proves it before PR.
8
+
9
+ **Plan. Patch. Prove.**
10
+
11
+ The practical AI coding loop: inspect first, change safely, verify before PR.
12
+
13
+ ![Plan. Patch. Prove workflow overview](docs/images/plan-prove-patch-header.png)
14
+
15
+ ```text
16
+ Inspect → Clarify → Plan → Prove → Patch → Review → PR
17
+ ```
18
+
19
+ PPP is a simple, practical workflow for everyday tasks and tickets. It gives AI coding agents a fast, reliable, consistent, and token-efficient loop: inspect first, plan the smallest safe complete change, patch in small validated steps, and prove the result before handoff.
20
+
21
+ The starter kit includes:
22
+
23
+ - **Plan. Patch. Prove. (`/ppp`)** — an interactive workflow for engineers using an IDE agent
24
+ - **Plan. Patch. Prove. Cloud (`ppp-cloud`)** — a non-interactive workflow for autonomous cloud coding agents
25
+ - repo templates for agent guidance, Copilot instructions, PR templates, and Cursor rules
26
+ - practical docs and examples for adoption
27
+
28
+ ## Quick start
29
+
30
+ ```bash
31
+ npx ai-engineering-starter-kit install
32
+ ```
33
+
34
+ If slash commands are supported in your tool, run:
35
+
36
+ ```text
37
+ /ppp <prompt>
38
+ ```
39
+
40
+ ## If `/ppp` does not work
41
+
42
+ `/ppp` works only where your agent tool loads skills as slash commands.
43
+
44
+ Fallback invocation:
45
+
46
+ ```text
47
+ Use the Plan. Patch. Prove workflow on this prompt:
48
+ <paste prompt>
49
+ ```
50
+
51
+ Not sure which setup to use? See [IDE setup](docs/ide-setup.md).
52
+
53
+ Prefer shell scripts instead of `npx`?
54
+
55
+ ```bash
56
+ git clone https://github.com/bransbury/ai-engineering-starter-kit
57
+ cd ai-engineering-starter-kit
58
+ ./install.sh
59
+ ```
60
+
61
+ ## How PPP works
62
+
63
+ PPP stands for:
64
+
65
+ - **Plan** the smallest safe complete change.
66
+ - **Patch** the code in small, controlled steps.
67
+ - **Prove** it works before PR.
68
+
69
+ The actual workflow is deliberately proof-first:
70
+
71
+ ```text
72
+ Inspect → Clarify → Plan → Prove → Patch → Review → PR
73
+ ```
74
+
75
+ Prove starts before Patch: the agent defines the proof first, then patches in small loops and runs the proof as it goes.
76
+
77
+ ### IDE flow
78
+
79
+ ```text
80
+ Ticket
81
+
82
+ /ppp
83
+
84
+ Inspect → Clarify → Plan → Prove → Patch → Review → PR
85
+
86
+ PR handoff
87
+ ```
88
+
89
+ ### Cloud flow
90
+
91
+ ```text
92
+ Issue
93
+
94
+ ppp-cloud
95
+
96
+ Draft PR or blocker
97
+ ```
98
+
99
+ ## Which setup should I use?
100
+
101
+ | I am... | Do this |
102
+ | --- | --- |
103
+ | Trying PPP personally | Run `npx ai-engineering-starter-kit install` |
104
+ | Rolling out to a repo | Copy `templates/AGENTS.md` and `templates/copilot-instructions.md` |
105
+ | Using Cursor | Copy `templates/cursor-ppp-rule.mdc` |
106
+ | Assigning cloud-agent tasks | Use `ppp-cloud` and repo instructions |
107
+
108
+ ## What gets installed?
109
+
110
+ The installers copy the skills to both common personal skill locations:
111
+
112
+ ```text
113
+ ~/.agents/skills/ppp/SKILL.md
114
+ ~/.agents/skills/ppp-cloud/SKILL.md
115
+ ~/.copilot/skills/ppp/SKILL.md
116
+ ~/.copilot/skills/ppp-cloud/SKILL.md
117
+ ```
118
+
119
+ If a `.cursor/` directory is detected in the current directory, it also installs the Cursor rule:
120
+
121
+ ```text
122
+ .cursor/rules/ppp.mdc
123
+ ```
124
+
125
+ Run `npx ai-engineering-starter-kit install` or `./install.sh` from each project where you want the Cursor rule active.
126
+
127
+ ## Repo-local install
128
+
129
+ GitHub supports project skills in `.github/skills`, `.claude/skills`, or `.agents/skills`. If you want PPP to live with a specific repo instead of your personal environment, copy the skills into one of those project-local locations.
130
+
131
+ For GitHub project skills:
132
+
133
+ ```bash
134
+ npx ai-engineering-starter-kit install --repo-local
135
+ ```
136
+
137
+ For most teams, the most reliable repo rollout is:
138
+
139
+ - repo-local skills for `/ppp` and `ppp-cloud`
140
+ - `AGENTS.md` at the repo root
141
+ - `.github/copilot-instructions.md` for VS Code + Copilot
142
+ - `.cursor/rules/ppp.mdc` for Cursor projects
143
+
144
+ ## When to use `/ppp`
145
+
146
+ Use `/ppp` for normal engineering work that should fit in one focused PR:
147
+
148
+ - bug fixes
149
+ - small features
150
+ - tests
151
+ - UI tweaks
152
+ - small refactors
153
+
154
+ Good examples:
155
+
156
+ ```text
157
+ /ppp Fix whitespace-only report names being accepted.
158
+ /ppp Add an empty state to the experiment results table when there are no rows.
159
+ ```
160
+
161
+ ## When not to use `/ppp`
162
+
163
+ Do not use `/ppp` to implement a whole large feature in one go.
164
+
165
+ Examples that are too large:
166
+
167
+ ```text
168
+ /ppp Build a new analytics dashboard.
169
+ /ppp Implement the new permissions system.
170
+ ```
171
+
172
+ For large work, ask `/ppp` to identify the smallest first task, or use a feature-slicing workflow.
173
+
174
+ ## What good looks like
175
+
176
+ A good PPP run should:
177
+
178
+ - inspect relevant code before editing
179
+ - ask only important questions
180
+ - define how the change will be verified before editing
181
+ - add or update tests/checks where appropriate
182
+ - stop after two focused failed fix attempts
183
+ - review production readiness
184
+ - prepare a PR title/body using repo conventions
185
+
186
+ See a [full example run](examples/prompts/ppp-examples.md#what-good-output-looks-like).
187
+
188
+ ## Cloud agent usage
189
+
190
+ | | `/ppp` | `ppp-cloud` |
191
+ | --- | --- | --- |
192
+ | **Who drives it** | Engineer in IDE | Autonomous cloud agent |
193
+ | **Interaction** | Interactive menus | Non-interactive, runs to completion |
194
+ | **Output** | Guided session → PR handoff | Draft PR or blocker report |
195
+ | **Best for** | Any normal ticket with a human in the loop | Clear, bounded tasks you can assign and review |
196
+
197
+ Use `ppp-cloud` for autonomous coding agents. It is designed for clear, bounded, verifiable tasks where the agent should either:
198
+
199
+ - create one focused draft PR; or
200
+ - stop with a clear blocker explaining why it could not proceed safely.
201
+
202
+ See [Cloud agent usage](docs/cloud-agent-usage.md).
203
+
204
+ ## How is this different?
205
+
206
+ - Some skills are broad libraries of composable expert workflows.
207
+ - Some tools are opinionated operating systems for full-stack or product development.
208
+ - PPP is a narrow, practical workflow for everyday engineering tasks.
209
+ - It focuses on a simple loop: inspect first, plan the smallest safe change, prove it before patching broadly, and hand off a reviewable PR.
210
+
211
+ ## Docs and templates
212
+
213
+ ### Docs
214
+
215
+ - [How to use PPP](docs/how-to-use-ppp.md)
216
+ - [IDE setup](docs/ide-setup.md)
217
+ - [Cloud agent usage](docs/cloud-agent-usage.md)
218
+ - [Adoption rollout](docs/adoption-rollout.md)
219
+ - [Release automation spec](docs/release-automation-spec.md)
220
+ - [Troubleshooting](docs/troubleshooting.md)
221
+
222
+ ### Templates
223
+
224
+ If you don't already have them, copy these into your repos to give AI agents consistent guidance:
225
+
226
+ | Template | Copy to | Purpose |
227
+ | --- | --- | --- |
228
+ | `templates/AGENTS.md` | `AGENTS.md` (repo root) | Tells agents which workflow to use and what requires human approval |
229
+ | `templates/copilot-instructions.md` | `.github/copilot-instructions.md` | Repo-level Copilot instructions picked up automatically in VS Code |
230
+ | `templates/PULL_REQUEST_TEMPLATE.md` | `.github/PULL_REQUEST_TEMPLATE.md` | Consistent PR descriptions across human and AI-authored PRs |
231
+ | `templates/cursor-ppp-rule.mdc` | `.cursor/rules/ppp.mdc` | Cursor project rule — automatically installed by `npx ai-engineering-starter-kit install` or `./install.sh` if `.cursor/` exists |
232
+
233
+ Each template is intentionally minimal. Add repo-specific conventions (architecture rules, test commands, forbidden areas) directly in `AGENTS.md` and `copilot-instructions.md`.
234
+
235
+ ## Security note
236
+
237
+ Skills are operational instructions that can influence AI agent behaviour. Review changes to `SKILL.md` files carefully.
238
+
239
+ Do not add secrets, credentials, internal-only URLs, or sensitive customer data to skills or examples.
240
+
241
+ ## License
242
+
243
+ [MIT](LICENSE.md) © 2026 Marcus Bransbury
@@ -0,0 +1,295 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const os = require("os");
5
+ const path = require("path");
6
+ const readline = require("readline");
7
+
8
+ const root = path.resolve(__dirname, "..");
9
+ const home = os.homedir();
10
+ const skills = ["ppp", "ppp-cloud"];
11
+ const personalTargets = [
12
+ path.join(home, ".agents", "skills"),
13
+ path.join(home, ".copilot", "skills"),
14
+ ];
15
+ const repoLocalTargets = [path.join(process.cwd(), ".github", "skills")];
16
+
17
+ function parseArgs(argv) {
18
+ const positional = [];
19
+ const flags = new Set();
20
+
21
+ for (const arg of argv) {
22
+ if (arg.startsWith("-")) {
23
+ flags.add(arg);
24
+ } else {
25
+ positional.push(arg);
26
+ }
27
+ }
28
+
29
+ return {
30
+ command: positional[0] || null,
31
+ dryRun: flags.has("--dry-run"),
32
+ force: flags.has("--force"),
33
+ yes: flags.has("--yes") || flags.has("-y"),
34
+ repoLocal: flags.has("--repo-local"),
35
+ help: flags.has("--help") || flags.has("-h"),
36
+ };
37
+ }
38
+
39
+ function usage() {
40
+ console.log(`AI Engineering Starter Kit
41
+
42
+ Usage:
43
+ ai-engineering-starter-kit install [--yes] [--dry-run] [--force] [--repo-local]
44
+ ai-engineering-starter-kit uninstall [--yes] [--dry-run] [--repo-local]
45
+ ai-engineering-starter-kit help
46
+
47
+ Examples:
48
+ npx ai-engineering-starter-kit install --yes
49
+ npx ai-engineering-starter-kit install --dry-run
50
+ npx ai-engineering-starter-kit install --repo-local
51
+ `);
52
+ }
53
+
54
+ function log(message = "") {
55
+ console.log(message);
56
+ }
57
+
58
+ function skillVersion(skillName) {
59
+ const src = path.join(root, "skills", skillName, "SKILL.md");
60
+ const content = fs.readFileSync(src, "utf8");
61
+ const match = content.match(/^version:\s*(.+)$/m);
62
+ return match ? match[1].trim() : "unknown";
63
+ }
64
+
65
+ function timestamp() {
66
+ const now = new Date();
67
+ const pad = (value) => String(value).padStart(2, "0");
68
+ return [
69
+ now.getFullYear(),
70
+ pad(now.getMonth() + 1),
71
+ pad(now.getDate()),
72
+ pad(now.getHours()),
73
+ pad(now.getMinutes()),
74
+ pad(now.getSeconds()),
75
+ ].join("");
76
+ }
77
+
78
+ function actionWord(dryRun, verb) {
79
+ return dryRun ? `Would ${verb}` : verb[0].toUpperCase() + verb.slice(1);
80
+ }
81
+
82
+ function runMkdir(destDir, dryRun) {
83
+ if (dryRun) {
84
+ log(`[dry-run] mkdir -p ${destDir}`);
85
+ return;
86
+ }
87
+ fs.mkdirSync(destDir, { recursive: true });
88
+ }
89
+
90
+ function runCopy(src, dest, dryRun) {
91
+ if (dryRun) {
92
+ log(`[dry-run] copy ${src} -> ${dest}`);
93
+ return;
94
+ }
95
+ fs.copyFileSync(src, dest);
96
+ }
97
+
98
+ function runRemove(target, dryRun) {
99
+ if (dryRun) {
100
+ log(`[dry-run] remove ${target}`);
101
+ return;
102
+ }
103
+ fs.rmSync(target, { recursive: true, force: true });
104
+ }
105
+
106
+ function backupFile(filePath, dryRun) {
107
+ const backupPath = `${filePath}.bak.${timestamp()}`;
108
+ runCopy(filePath, backupPath, dryRun);
109
+ log(`${actionWord(dryRun, "back up existing file")} to ${backupPath}`);
110
+ }
111
+
112
+ async function confirmOverwrite(targetFile) {
113
+ const rl = readline.createInterface({
114
+ input: process.stdin,
115
+ output: process.stderr,
116
+ });
117
+
118
+ const reply = await new Promise((resolve) => {
119
+ rl.question(`Overwrite ${targetFile}? [y/N] `, resolve);
120
+ });
121
+ rl.close();
122
+
123
+ return /^(y|yes)$/i.test(reply.trim());
124
+ }
125
+
126
+ async function shouldOverwrite(targetFile, options) {
127
+ if (!fs.existsSync(targetFile)) {
128
+ return true;
129
+ }
130
+
131
+ if (options.force) {
132
+ return true;
133
+ }
134
+
135
+ if (options.yes || !process.stdin.isTTY) {
136
+ log(`Exists at ${targetFile} - skipping (use --force to overwrite)`);
137
+ return false;
138
+ }
139
+
140
+ const confirmed = await confirmOverwrite(targetFile);
141
+ if (!confirmed) {
142
+ log(`Skipping ${targetFile}`);
143
+ return false;
144
+ }
145
+ return true;
146
+ }
147
+
148
+ async function installSkill(skillName, targetRoot, options) {
149
+ const src = path.join(root, "skills", skillName, "SKILL.md");
150
+ const destDir = path.join(targetRoot, skillName);
151
+ const destFile = path.join(destDir, "SKILL.md");
152
+
153
+ if (!fs.existsSync(src)) {
154
+ throw new Error(`Missing skill source: ${src}`);
155
+ }
156
+
157
+ runMkdir(destDir, options.dryRun);
158
+
159
+ if (!(await shouldOverwrite(destFile, options))) {
160
+ return;
161
+ }
162
+
163
+ if (fs.existsSync(destFile)) {
164
+ backupFile(destFile, options.dryRun);
165
+ }
166
+
167
+ runCopy(src, destFile, options.dryRun);
168
+ log(`${actionWord(options.dryRun, "install")} ${skillName} ${skillVersion(skillName)} to ${destFile}`);
169
+ }
170
+
171
+ async function installCursorRule(options) {
172
+ const src = path.join(root, "templates", "cursor-ppp-rule.mdc");
173
+ const destDir = path.join(process.cwd(), ".cursor", "rules");
174
+ const destFile = path.join(destDir, "ppp.mdc");
175
+
176
+ if (!fs.existsSync(src)) {
177
+ throw new Error(`Missing Cursor rule template: ${src}`);
178
+ }
179
+
180
+ if (!fs.existsSync(path.join(process.cwd(), ".cursor"))) {
181
+ log("Cursor not detected in current directory - skipping Cursor rule install.");
182
+ log("To install manually: copy templates/cursor-ppp-rule.mdc to .cursor/rules/ppp.mdc");
183
+ return;
184
+ }
185
+
186
+ runMkdir(destDir, options.dryRun);
187
+
188
+ if (!(await shouldOverwrite(destFile, options))) {
189
+ return;
190
+ }
191
+
192
+ if (fs.existsSync(destFile)) {
193
+ backupFile(destFile, options.dryRun);
194
+ }
195
+
196
+ runCopy(src, destFile, options.dryRun);
197
+ log(`${actionWord(options.dryRun, "install")} Cursor rule to ${destFile}`);
198
+ }
199
+
200
+ async function install(options) {
201
+ const targetRoots = options.repoLocal ? repoLocalTargets : personalTargets;
202
+
203
+ log("PPP installer");
204
+ log(`Version: ${skillVersion("ppp")}`);
205
+ if (options.repoLocal) {
206
+ log("Mode: repo-local");
207
+ }
208
+ if (options.dryRun) {
209
+ log("Mode: dry-run");
210
+ }
211
+ if (options.force) {
212
+ log("Overwrite mode: force");
213
+ }
214
+ log();
215
+
216
+ for (const skill of skills) {
217
+ for (const targetRoot of targetRoots) {
218
+ await installSkill(skill, targetRoot, options);
219
+ }
220
+ }
221
+
222
+ log();
223
+ if (!options.repoLocal) {
224
+ await installCursorRule(options);
225
+ }
226
+
227
+ log();
228
+ log("Done.");
229
+ log("Important: /ppp works only where your tool loads skills as slash commands.");
230
+ log("Fallback: Use the Plan. Patch. Prove workflow on this prompt:");
231
+ log("<paste prompt>");
232
+ }
233
+
234
+ function removeSkillDirs(targetRoots, options) {
235
+ for (const skill of skills) {
236
+ for (const targetRoot of targetRoots) {
237
+ const targetDir = path.join(targetRoot, skill);
238
+ if (fs.existsSync(targetDir)) {
239
+ runRemove(targetDir, options.dryRun);
240
+ log(`${actionWord(options.dryRun, "remove")} ${targetDir}`);
241
+ } else {
242
+ log(`Not found, skipping: ${targetDir}`);
243
+ }
244
+ }
245
+ }
246
+ }
247
+
248
+ function removeCursorRule(options) {
249
+ const cursorRule = path.join(process.cwd(), ".cursor", "rules", "ppp.mdc");
250
+ if (fs.existsSync(cursorRule)) {
251
+ runRemove(cursorRule, options.dryRun);
252
+ log(`${actionWord(options.dryRun, "remove")} ${cursorRule}`);
253
+ } else {
254
+ log(`Not found, skipping: ${cursorRule}`);
255
+ }
256
+ }
257
+
258
+ function uninstall(options) {
259
+ const targetRoots = options.repoLocal ? repoLocalTargets : personalTargets;
260
+
261
+ removeSkillDirs(targetRoots, options);
262
+ if (!options.repoLocal) {
263
+ removeCursorRule(options);
264
+ }
265
+
266
+ log("Done.");
267
+ }
268
+
269
+ async function main() {
270
+ const options = parseArgs(process.argv.slice(2));
271
+
272
+ if (!options.command || options.help || options.command === "help") {
273
+ usage();
274
+ process.exit(0);
275
+ }
276
+
277
+ if (options.command === "install") {
278
+ await install(options);
279
+ return;
280
+ }
281
+
282
+ if (options.command === "uninstall") {
283
+ uninstall(options);
284
+ return;
285
+ }
286
+
287
+ console.error(`Unknown command: ${options.command}`);
288
+ usage();
289
+ process.exit(1);
290
+ }
291
+
292
+ main().catch((error) => {
293
+ console.error(error.message);
294
+ process.exit(1);
295
+ });
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "ai-engineering-starter-kit",
3
+ "version": "0.4.0",
4
+ "description": "Plan. Patch. Prove. Practical AI-assisted engineering workflows for IDE and cloud coding agents.",
5
+ "license": "MIT",
6
+ "private": false,
7
+ "type": "commonjs",
8
+ "bin": {
9
+ "ai-engineering-starter-kit": "bin/ai-engineering-starter-kit.js",
10
+ "aesk": "bin/ai-engineering-starter-kit.js"
11
+ },
12
+ "files": [
13
+ "bin",
14
+ "skills",
15
+ "templates",
16
+ "README.md",
17
+ "LICENSE.md"
18
+ ],
19
+ "engines": {
20
+ "node": ">=18"
21
+ }
22
+ }