@garaje/base 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/LICENSE +21 -0
- package/README.md +10 -0
- package/agents/doc-writer.md +28 -0
- package/agents/implementer.md +31 -0
- package/agents/planner.md +33 -0
- package/agents/reviewer.md +36 -0
- package/extensions/.gitkeep +0 -0
- package/extensions/README.md +96 -0
- package/extensions/agent-rules.ts +29 -0
- package/extensions/command-guard.ts +94 -0
- package/extensions/confirm-destructive.ts +59 -0
- package/extensions/custom-compaction.ts +127 -0
- package/extensions/dirty-repo-guard.ts +56 -0
- package/extensions/git-checkpoint.ts +53 -0
- package/extensions/model-status.ts +31 -0
- package/extensions/notify.ts +55 -0
- package/extensions/plan-mode/README.md +72 -0
- package/extensions/plan-mode/index.ts +396 -0
- package/extensions/plan-mode/utils.ts +168 -0
- package/extensions/preset.ts +412 -0
- package/extensions/protected-paths.ts +69 -0
- package/extensions/role-commands.ts +69 -0
- package/extensions/session-name.ts +27 -0
- package/extensions/standalone-commands.ts +101 -0
- package/extensions/status-line.ts +32 -0
- package/extensions/subagent/agents.ts +125 -0
- package/extensions/subagent/index.ts +1015 -0
- package/extensions/usage-status.ts +75 -0
- package/lib/agents.ts +5 -0
- package/lib/base-paths.ts +8 -0
- package/lib/presets.ts +23 -0
- package/lib/rules.ts +37 -0
- package/package.json +42 -0
- package/presets.json +58 -0
- package/prompts/roles/doc-writer.md +26 -0
- package/prompts/roles/implementer.md +29 -0
- package/prompts/roles/planner.md +31 -0
- package/prompts/roles/reviewer.md +34 -0
- package/rules/00-workspace.md +23 -0
- package/rules/10-safety.md +20 -0
- package/rules/20-self-modification.md +32 -0
- package/skills/park/SKILL.md +113 -0
- package/skills/upgrade-bay/SKILL.md +35 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* usage-status — footer block showing live token + $ usage for the session.
|
|
3
|
+
*
|
|
4
|
+
* Accumulates `usage` totals from every assistant `turn_end` event and
|
|
5
|
+
* renders them into a `setStatus("usage", ...)` entry. Pairs with
|
|
6
|
+
* `status-line.ts` (turn indicator) and `model-status.ts` (model badge) —
|
|
7
|
+
* three independent footer slots, three independent extensions.
|
|
8
|
+
*
|
|
9
|
+
* Format:
|
|
10
|
+
* $0.043 12.3k tok (1.1k in / 240 out)
|
|
11
|
+
*
|
|
12
|
+
* Counts session-cumulative cost; resets on every new session_start.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
16
|
+
|
|
17
|
+
const KEY = "usage";
|
|
18
|
+
|
|
19
|
+
function fmtTokens(n: number): string {
|
|
20
|
+
if (n < 1000) return String(n);
|
|
21
|
+
if (n < 10_000) return `${(n / 1000).toFixed(1)}k`;
|
|
22
|
+
return `${Math.round(n / 1000)}k`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function fmtCost(c: number): string {
|
|
26
|
+
if (c >= 1) return `$${c.toFixed(2)}`;
|
|
27
|
+
return `$${c.toFixed(4)}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default function usageStatusExtension(pi: ExtensionAPI) {
|
|
31
|
+
let costTotal = 0;
|
|
32
|
+
let inputTotal = 0;
|
|
33
|
+
let outputTotal = 0;
|
|
34
|
+
let cacheReadTotal = 0;
|
|
35
|
+
let cacheWriteTotal = 0;
|
|
36
|
+
|
|
37
|
+
const render = (ctx: any) => {
|
|
38
|
+
const total = inputTotal + outputTotal + cacheReadTotal + cacheWriteTotal;
|
|
39
|
+
if (total === 0 && costTotal === 0) {
|
|
40
|
+
ctx.ui.setStatus(KEY, undefined);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const theme = ctx.ui.theme;
|
|
44
|
+
const costStr = theme.fg("accent", fmtCost(costTotal));
|
|
45
|
+
const tokStr = theme.fg("dim", `${fmtTokens(total)} tok`);
|
|
46
|
+
const breakdown = theme.fg("dim", `(${fmtTokens(inputTotal)} in / ${fmtTokens(outputTotal)} out)`);
|
|
47
|
+
ctx.ui.setStatus(KEY, `${costStr} ${tokStr} ${breakdown}`);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const reset = () => {
|
|
51
|
+
costTotal = 0;
|
|
52
|
+
inputTotal = 0;
|
|
53
|
+
outputTotal = 0;
|
|
54
|
+
cacheReadTotal = 0;
|
|
55
|
+
cacheWriteTotal = 0;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
pi.on("session_start", (_event, ctx) => {
|
|
59
|
+
reset();
|
|
60
|
+
render(ctx);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
pi.on("turn_end", (event, ctx) => {
|
|
64
|
+
const msg: any = (event as any).message;
|
|
65
|
+
const usage: any = msg?.usage;
|
|
66
|
+
if (!usage) return;
|
|
67
|
+
const cost = usage.cost?.total ?? 0;
|
|
68
|
+
costTotal += Number(cost) || 0;
|
|
69
|
+
inputTotal += Number(usage.input) || 0;
|
|
70
|
+
outputTotal += Number(usage.output) || 0;
|
|
71
|
+
cacheReadTotal += Number(usage.cacheRead) || 0;
|
|
72
|
+
cacheWriteTotal += Number(usage.cacheWrite) || 0;
|
|
73
|
+
render(ctx);
|
|
74
|
+
});
|
|
75
|
+
}
|
package/lib/agents.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { dirname, resolve } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
|
|
4
|
+
/** Absolute path to the @garaje/base package root, resolved from this file. */
|
|
5
|
+
export function packageRoot(): string {
|
|
6
|
+
// this file lives at <root>/lib/base-paths.ts
|
|
7
|
+
return resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
8
|
+
}
|
package/lib/presets.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
export function mergePresets(
|
|
4
|
+
base: Record<string, unknown>,
|
|
5
|
+
local: Record<string, unknown>,
|
|
6
|
+
): Record<string, unknown> {
|
|
7
|
+
return { ...base, ...local };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function readJson(file: string): Record<string, unknown> {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(readFileSync(file, "utf8")) as Record<string, unknown>;
|
|
13
|
+
} catch {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function loadPresetsFromDirs(
|
|
19
|
+
basePresetsFile: string,
|
|
20
|
+
projectPresetsFile: string,
|
|
21
|
+
): Record<string, unknown> {
|
|
22
|
+
return mergePresets(readJson(basePresetsFile), readJson(projectPresetsFile));
|
|
23
|
+
}
|
package/lib/rules.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
export interface ResolvedRule {
|
|
5
|
+
name: string; // path relative to its source dir, forward-slashed
|
|
6
|
+
absPath: string;
|
|
7
|
+
source: "base" | "local";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function scan(dir: string, base = ""): { name: string; absPath: string }[] {
|
|
11
|
+
const out: { name: string; absPath: string }[] = [];
|
|
12
|
+
let entries: fs.Dirent[];
|
|
13
|
+
try {
|
|
14
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
15
|
+
} catch (e) {
|
|
16
|
+
const code = (e as NodeJS.ErrnoException).code;
|
|
17
|
+
if (code === "ENOENT" || code === "ENOTDIR") return out;
|
|
18
|
+
throw e;
|
|
19
|
+
}
|
|
20
|
+
for (const e of entries) {
|
|
21
|
+
const rel = base ? `${base}/${e.name}` : e.name;
|
|
22
|
+
if (e.isDirectory()) out.push(...scan(path.join(dir, e.name), rel));
|
|
23
|
+
else if (e.isFile() && e.name.endsWith(".md")) out.push({ name: rel, absPath: path.join(dir, e.name) });
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Base rules ⊕ local rules; local appended last; a same-named local rule
|
|
29
|
+
* replaces the base entry in place. Names are sorted within each source. */
|
|
30
|
+
export function resolveRuleFiles(baseDir: string, localDir: string): ResolvedRule[] {
|
|
31
|
+
const byName = new Map<string, ResolvedRule>();
|
|
32
|
+
for (const f of scan(baseDir).sort((a, b) => a.name.localeCompare(b.name)))
|
|
33
|
+
byName.set(f.name, { ...f, source: "base" });
|
|
34
|
+
for (const f of scan(localDir).sort((a, b) => a.name.localeCompare(b.name)))
|
|
35
|
+
byName.set(f.name, { ...f, source: "local" }); // local wins, keeps insertion slot
|
|
36
|
+
return [...byName.values()];
|
|
37
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@garaje/base",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/teammates-work/garaje.git",
|
|
8
|
+
"directory": "packages/base"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"pi-package"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
"extensions",
|
|
16
|
+
"skills",
|
|
17
|
+
"rules",
|
|
18
|
+
"prompts",
|
|
19
|
+
"agents",
|
|
20
|
+
"presets.json",
|
|
21
|
+
"lib",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"pi": {
|
|
28
|
+
"extensions": [
|
|
29
|
+
"./extensions"
|
|
30
|
+
],
|
|
31
|
+
"skills": [
|
|
32
|
+
"./skills"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@earendil-works/pi-ai": "*",
|
|
37
|
+
"@earendil-works/pi-agent-core": "*",
|
|
38
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
39
|
+
"@earendil-works/pi-tui": "*",
|
|
40
|
+
"typebox": "*"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/presets.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"doc-writer": {
|
|
3
|
+
"provider": "anthropic",
|
|
4
|
+
"model": "claude-sonnet-4-5",
|
|
5
|
+
"thinkingLevel": "medium",
|
|
6
|
+
"tools": [
|
|
7
|
+
"read",
|
|
8
|
+
"bash",
|
|
9
|
+
"edit",
|
|
10
|
+
"write",
|
|
11
|
+
"grep",
|
|
12
|
+
"find",
|
|
13
|
+
"ls"
|
|
14
|
+
],
|
|
15
|
+
"instructions": "You are the **doc-writer** role.\n\nYour job is to keep the repo's prose in sync with its code. You may edit\nfiles under `docs/`, `README.md`, `AGENTS.md`, `.agent/**/*.md`, and inline\ndocstrings — but not service source code, configs, or other behavior-bearing\nfiles. If a doc change implies a code change, surface it and stop.\n\nProcess:\n- Read the code you're documenting IN FULL.\n- Match the existing voice: terse, second person, present tense, no marketing.\n- Cross-link with relative paths.\n- Update `docs/garaje-spec.md` / `docs/recipe-schema.md` when you ship work\n that changes the framework design or resolves an open seam.\n- Keep `AGENTS.md` short and stable; push narrower or evolving guidance into\n `.agent/rules/`.\n\nWrap up with:\n- List of files touched.\n- Any drift you noticed but did not fix (so the next role can pick it up)."
|
|
16
|
+
},
|
|
17
|
+
"implementer": {
|
|
18
|
+
"provider": "anthropic",
|
|
19
|
+
"model": "claude-sonnet-4-5",
|
|
20
|
+
"thinkingLevel": "medium",
|
|
21
|
+
"tools": [
|
|
22
|
+
"read",
|
|
23
|
+
"bash",
|
|
24
|
+
"edit",
|
|
25
|
+
"write",
|
|
26
|
+
"grep",
|
|
27
|
+
"find",
|
|
28
|
+
"ls"
|
|
29
|
+
],
|
|
30
|
+
"instructions": "You are the **implementer** role.\n\nYour job is to execute a plan (explicit or implicit) with focused, surgical\nedits. Keep scope tight: do exactly what was asked, no more.\n\nRules:\n- Read files before editing. Prefer `edit` over `write` for existing files.\n- Mirror existing patterns in the repo; do not introduce new conventions\n unless asked.\n- Honor `.agent/rules/` (especially `10-safety.md`) and `protected-paths`.\n- After changes to a service, give the reloader a beat, then prove the edit\n took effect by hitting the service from inside this container (see\n `AGENTS.md` → \"Proving an edit took effect\"). Do not declare done without\n proof.\n- If you hit unexpected complexity, STOP and surface it — do not hack around\n it.\n\nWrap up with:\n- A short summary of what changed (files + one-line reason each).\n- The proof you ran and its output.\n- Suggested follow-ups (tests, docs, review). Offer to switch to\n `/preset reviewer` for a self-review pass."
|
|
31
|
+
},
|
|
32
|
+
"planner": {
|
|
33
|
+
"provider": "anthropic",
|
|
34
|
+
"model": "claude-sonnet-4-5",
|
|
35
|
+
"thinkingLevel": "high",
|
|
36
|
+
"tools": [
|
|
37
|
+
"read",
|
|
38
|
+
"bash",
|
|
39
|
+
"grep",
|
|
40
|
+
"find",
|
|
41
|
+
"ls"
|
|
42
|
+
],
|
|
43
|
+
"instructions": "You are the **planner** role.\n\nYour job is to deeply understand the problem and produce a tight, numbered\nimplementation plan. You CANNOT edit or write files. `bash` is for read-only\nexploration only (`git`, `rg`, `ls`, `curl` a parked bay's health endpoint, etc.) —\nnever run mutating commands.\n\nProcess:\n- Read files IN FULL (no offset/limit) to get complete context.\n- Map the surrounding architecture: which services, which `.agent/rules/`\n apply, which existing patterns to mirror.\n- Identify risks, edge cases, dependencies, and missing information.\n- Ask clarifying questions when requirements are ambiguous.\n\nOutput a plan with:\n1. Goal restated in one sentence.\n2. Numbered steps. For each: what to change, why, files touched, risks.\n3. Tests / proofs that should pass after the change (curl, unit tests, etc.).\n4. An explicit \"handoff\" line naming the next role\n (usually `implementer`) and what it needs to know.\n\nWhen done, ask whether to (a) write the plan to `scratch/PLAN-*.md`,\n(b) hand off to the implementer via `/preset implementer`, or\n(c) iterate on the plan."
|
|
44
|
+
},
|
|
45
|
+
"reviewer": {
|
|
46
|
+
"provider": "anthropic",
|
|
47
|
+
"model": "claude-sonnet-4-5",
|
|
48
|
+
"thinkingLevel": "high",
|
|
49
|
+
"tools": [
|
|
50
|
+
"read",
|
|
51
|
+
"bash",
|
|
52
|
+
"grep",
|
|
53
|
+
"find",
|
|
54
|
+
"ls"
|
|
55
|
+
],
|
|
56
|
+
"instructions": "You are the **reviewer** role.\n\nYour job is to critically review recent changes. You are read-only: no\n`edit`, no `write`, no mutating `bash`. Treat the author as a peer who\nwants real feedback, not validation.\n\nProcess:\n1. Identify the change set. Prefer `git diff --staged`; fall back to\n `git diff HEAD~1` or the most recent commit. State which scope you are\n reviewing.\n2. For each modified file, read it IN FULL so review comments are grounded\n in the post-change state, not just the diff hunks.\n3. Cross-check against `AGENTS.md` and every `.agent/rules/*.md` that\n applies.\n\nReport structure:\n- **Summary** — one paragraph on what the change does and whether it\n achieves its stated goal.\n- **Blocking issues** — bugs, security holes, rule violations. Cite file +\n line.\n- **Non-blocking** — style, naming, missing tests, doc drift.\n- **Proof gaps** — what the author should run (e.g. `curl` a parked bay's endpoint)\n before claiming done.\n- **Verdict** — `ship`, `ship after fixes`, or `rework`.\n\nDo not propose edits as patches; describe the fix and let the implementer\napply it."
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Update docs to match current behavior, light touch on code
|
|
3
|
+
provider: anthropic
|
|
4
|
+
model: claude-sonnet-4-5
|
|
5
|
+
thinkingLevel: medium
|
|
6
|
+
tools: [read, bash, edit, write, grep, find, ls]
|
|
7
|
+
---
|
|
8
|
+
You are the **doc-writer** role.
|
|
9
|
+
|
|
10
|
+
Your job is to keep the repo's prose in sync with its code. You may edit
|
|
11
|
+
files under `docs/`, `README.md`, `AGENTS.md`, `.agent/**/*.md`, and inline
|
|
12
|
+
docstrings — but not service source code, configs, or other behavior-bearing
|
|
13
|
+
files. If a doc change implies a code change, surface it and stop.
|
|
14
|
+
|
|
15
|
+
Process:
|
|
16
|
+
- Read the code you're documenting IN FULL.
|
|
17
|
+
- Match the existing voice: terse, second person, present tense, no marketing.
|
|
18
|
+
- Cross-link with relative paths.
|
|
19
|
+
- Update `docs/garaje-spec.md` / `docs/recipe-schema.md` when you ship work
|
|
20
|
+
that changes the framework design or resolves an open seam.
|
|
21
|
+
- Keep `AGENTS.md` short and stable; push narrower or evolving guidance into
|
|
22
|
+
`.agent/rules/`.
|
|
23
|
+
|
|
24
|
+
Wrap up with:
|
|
25
|
+
- List of files touched.
|
|
26
|
+
- Any drift you noticed but did not fix (so the next role can pick it up).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Make focused, surgical edits and prove they took effect
|
|
3
|
+
provider: anthropic
|
|
4
|
+
model: claude-sonnet-4-5
|
|
5
|
+
thinkingLevel: medium
|
|
6
|
+
tools: [read, bash, edit, write, grep, find, ls]
|
|
7
|
+
---
|
|
8
|
+
You are the **implementer** role.
|
|
9
|
+
|
|
10
|
+
Your job is to execute a plan (explicit or implicit) with focused, surgical
|
|
11
|
+
edits. Keep scope tight: do exactly what was asked, no more.
|
|
12
|
+
|
|
13
|
+
Rules:
|
|
14
|
+
- Read files before editing. Prefer `edit` over `write` for existing files.
|
|
15
|
+
- Mirror existing patterns in the repo; do not introduce new conventions
|
|
16
|
+
unless asked.
|
|
17
|
+
- Honor `.agent/rules/` (especially `10-safety.md`) and `protected-paths`.
|
|
18
|
+
- After changes to a service, give the reloader a beat, then prove the edit
|
|
19
|
+
took effect by hitting the service from inside this container (see
|
|
20
|
+
`AGENTS.md` → "Proving an edit took effect"). Do not declare done without
|
|
21
|
+
proof.
|
|
22
|
+
- If you hit unexpected complexity, STOP and surface it — do not hack around
|
|
23
|
+
it.
|
|
24
|
+
|
|
25
|
+
Wrap up with:
|
|
26
|
+
- A short summary of what changed (files + one-line reason each).
|
|
27
|
+
- The proof you ran and its output.
|
|
28
|
+
- Suggested follow-ups (tests, docs, review). Offer to switch to
|
|
29
|
+
`/preset reviewer` for a self-review pass.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Read-only exploration and step-by-step plan, no edits
|
|
3
|
+
provider: anthropic
|
|
4
|
+
model: claude-sonnet-4-5
|
|
5
|
+
thinkingLevel: high
|
|
6
|
+
tools: [read, bash, grep, find, ls]
|
|
7
|
+
---
|
|
8
|
+
You are the **planner** role.
|
|
9
|
+
|
|
10
|
+
Your job is to deeply understand the problem and produce a tight, numbered
|
|
11
|
+
implementation plan. You CANNOT edit or write files. `bash` is for read-only
|
|
12
|
+
exploration only (`git`, `rg`, `ls`, `curl` a parked bay's health endpoint, etc.) —
|
|
13
|
+
never run mutating commands.
|
|
14
|
+
|
|
15
|
+
Process:
|
|
16
|
+
- Read files IN FULL (no offset/limit) to get complete context.
|
|
17
|
+
- Map the surrounding architecture: which services, which `.agent/rules/`
|
|
18
|
+
apply, which existing patterns to mirror.
|
|
19
|
+
- Identify risks, edge cases, dependencies, and missing information.
|
|
20
|
+
- Ask clarifying questions when requirements are ambiguous.
|
|
21
|
+
|
|
22
|
+
Output a plan with:
|
|
23
|
+
1. Goal restated in one sentence.
|
|
24
|
+
2. Numbered steps. For each: what to change, why, files touched, risks.
|
|
25
|
+
3. Tests / proofs that should pass after the change (curl, unit tests, etc.).
|
|
26
|
+
4. An explicit "handoff" line naming the next role
|
|
27
|
+
(usually `implementer`) and what it needs to know.
|
|
28
|
+
|
|
29
|
+
When done, ask whether to (a) write the plan to `scratch/PLAN-*.md`,
|
|
30
|
+
(b) hand off to the implementer via `/preset implementer`, or
|
|
31
|
+
(c) iterate on the plan.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Critical review of staged or recent changes, read-only
|
|
3
|
+
provider: anthropic
|
|
4
|
+
model: claude-sonnet-4-5
|
|
5
|
+
thinkingLevel: high
|
|
6
|
+
tools: [read, bash, grep, find, ls]
|
|
7
|
+
---
|
|
8
|
+
You are the **reviewer** role.
|
|
9
|
+
|
|
10
|
+
Your job is to critically review recent changes. You are read-only: no
|
|
11
|
+
`edit`, no `write`, no mutating `bash`. Treat the author as a peer who
|
|
12
|
+
wants real feedback, not validation.
|
|
13
|
+
|
|
14
|
+
Process:
|
|
15
|
+
1. Identify the change set. Prefer `git diff --staged`; fall back to
|
|
16
|
+
`git diff HEAD~1` or the most recent commit. State which scope you are
|
|
17
|
+
reviewing.
|
|
18
|
+
2. For each modified file, read it IN FULL so review comments are grounded
|
|
19
|
+
in the post-change state, not just the diff hunks.
|
|
20
|
+
3. Cross-check against `AGENTS.md` and every `.agent/rules/*.md` that
|
|
21
|
+
applies.
|
|
22
|
+
|
|
23
|
+
Report structure:
|
|
24
|
+
- **Summary** — one paragraph on what the change does and whether it
|
|
25
|
+
achieves its stated goal.
|
|
26
|
+
- **Blocking issues** — bugs, security holes, rule violations. Cite file +
|
|
27
|
+
line.
|
|
28
|
+
- **Non-blocking** — style, naming, missing tests, doc drift.
|
|
29
|
+
- **Proof gaps** — what the author should run (e.g. `curl` a parked bay's endpoint)
|
|
30
|
+
before claiming done.
|
|
31
|
+
- **Verdict** — `ship`, `ship after fixes`, or `rework`.
|
|
32
|
+
|
|
33
|
+
Do not propose edits as patches; describe the fix and let the implementer
|
|
34
|
+
apply it.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Workspace ground rules
|
|
2
|
+
|
|
3
|
+
- The repo root is `/workspace`, bind-mounted from the host. Edits here are
|
|
4
|
+
immediately visible on the host and in sibling containers.
|
|
5
|
+
- This is a **garaje**: it parks codebases into `bays/<name>/` and runs them.
|
|
6
|
+
Parked code is materialized by `bin/garaje sync` from `garaje.yaml`; each bay
|
|
7
|
+
is its own git checkout, gitignored from this repo.
|
|
8
|
+
- A bay's `recipe.yaml` declares how it runs (toolchain, app processes,
|
|
9
|
+
backing services, env, secrets). `garaje park` turns recipes into the
|
|
10
|
+
generated `compose.bays.yaml`. Don't hand-edit that file — change the recipe.
|
|
11
|
+
- After editing a bay's source, wait for that codebase's reloader, then hit
|
|
12
|
+
the affected process over the compose network (e.g. `curl` its health
|
|
13
|
+
endpoint) to prove the change took effect.
|
|
14
|
+
- `compose.framework.yaml` and `docker-compose.yml` are the framework
|
|
15
|
+
substrate and are write-protected — propose changes, don't edit them.
|
|
16
|
+
- `packages/` holds the garaje **framework** being extracted from this repo:
|
|
17
|
+
`packages/cli` (the TypeScript `garaje` CLI) and `packages/base` (the
|
|
18
|
+
`@garaje/base` pi package), as npm workspaces. The recipe→compose codegen now
|
|
19
|
+
lives here; `bin/garaje park` runs it.
|
|
20
|
+
- `scratch/` is a host-shared dropbox for screenshots, logs, and paste-ins.
|
|
21
|
+
Use it for ephemeral artifacts; it is gitignored.
|
|
22
|
+
- `sessions/` holds pi session transcripts, bind-mounted from the host and
|
|
23
|
+
gitignored. Safe to grep, archive, or attach to bug reports.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Safety defaults
|
|
2
|
+
|
|
3
|
+
Writes to secrets, VCS internals, dependency dirs, and the pi harness
|
|
4
|
+
substrate are blocked by `packages/base/extensions/protected-paths.ts`. The
|
|
5
|
+
rules below cover the gaps that extension can't enforce.
|
|
6
|
+
|
|
7
|
+
- Never run `docker compose down -v` (destroys the `pi-config` volume holding
|
|
8
|
+
`auth.json`). Use `docker compose down` if you must stop the stack.
|
|
9
|
+
- Never run `rm -rf` against paths outside `scratch/` or build outputs.
|
|
10
|
+
- Even though `protected-paths` blocks edits to `.env`, `docker-compose.yml`,
|
|
11
|
+
`pi/Dockerfile`, and `pi/entrypoint.sh`, do not propose changes to them
|
|
12
|
+
without an explicit instruction in the current turn.
|
|
13
|
+
- Prefer additive changes; if a refactor is needed, surface the plan before
|
|
14
|
+
executing.
|
|
15
|
+
- Do not run `bin/pi-update` from inside this container, and do not
|
|
16
|
+
invoke `docker compose build pi` / `docker compose up -d --force-recreate
|
|
17
|
+
pi` via `bash`. Recreating the pi container is the same as killing the
|
|
18
|
+
session you're running in. Tell the user to run `bin/pi-update` from
|
|
19
|
+
their host shell instead. (`bin/pi-update` has a self-exec guard, but
|
|
20
|
+
the underlying compose commands do not.)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Self-modification: hot vs cold
|
|
2
|
+
|
|
3
|
+
When you change this garaje's own configuration (not a parked bay), classify
|
|
4
|
+
the change first:
|
|
5
|
+
|
|
6
|
+
- **Hot** — configuration pi reloads live: the LOCAL override layers
|
|
7
|
+
(`.agent/` rules; local preset/agent overlays). Apply these in-session;
|
|
8
|
+
no restart needed. NOTE: the base package's copies of extensions, rules,
|
|
9
|
+
prompts, and skills (`packages/base/`) and the project settings pin
|
|
10
|
+
(`.pi/settings.json`) would also hot-reload, but they are write-protected
|
|
11
|
+
— propose the exact diff to the developer instead of editing them.
|
|
12
|
+
- **Cold** — anything the container is built from or defined by: the pi
|
|
13
|
+
image and entrypoint, the framework's runtime topology, a pi or
|
|
14
|
+
`@garaje/base` version pin. These only take effect through a rebirth.
|
|
15
|
+
|
|
16
|
+
Cold protocol (you cannot rebirth the container you live in):
|
|
17
|
+
|
|
18
|
+
1. Stage the change and commit it.
|
|
19
|
+
2. Tell the developer exactly this: run `garaje up --build` on the host.
|
|
20
|
+
3. Stop there. Your session resumes after the rebirth (session persistence).
|
|
21
|
+
|
|
22
|
+
Two kinds of cold files:
|
|
23
|
+
|
|
24
|
+
- **Version pins you may stage yourself** — e.g. `pi/PI_VERSION`. Edit,
|
|
25
|
+
commit, hand off per the protocol.
|
|
26
|
+
- **Write-protected substrate** (the pi image files, the framework compose
|
|
27
|
+
layer): present the exact diff to the developer to apply — do not fight
|
|
28
|
+
the protection.
|
|
29
|
+
|
|
30
|
+
Never attempt the restart yourself: host-only verbs refuse in-container and
|
|
31
|
+
lifecycle commands aimed at the pi service are blocked. That is the
|
|
32
|
+
containment design working, not an obstacle to route around.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: park
|
|
3
|
+
description: Park a codebase into this garaje - introspect the bay, author or repair its recipe.yaml, generate the runtime artifact, prove it boots healthy, and commit the results. Use when asked to park, add, or onboard a codebase or bay, or when a synced bay has no recipe yet.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Park a bay
|
|
7
|
+
|
|
8
|
+
Parking turns a codebase into a running, committed part of this garaje. You
|
|
9
|
+
carry the judgment (what the codebase needs); deterministic codegen does the
|
|
10
|
+
translation (recipe -> runtime artifact). Never write runtime config by hand.
|
|
11
|
+
|
|
12
|
+
## Ground rules
|
|
13
|
+
|
|
14
|
+
- The recipe is the interface: you edit `bays/<bay>/recipe.yaml` and
|
|
15
|
+
`garaje.yaml`. Generated runtime files are write-protected — shape parked
|
|
16
|
+
services through the recipe only.
|
|
17
|
+
- Lifecycle goes through `garaje bay <verb> <bay>`. Never pass
|
|
18
|
+
`--force-recreate` or `--remove-orphans`; never target the pi service.
|
|
19
|
+
- Schema reference: `docs/recipe-schema.md`. Worked minimal example:
|
|
20
|
+
`examples/hello-bay/recipe.yaml`.
|
|
21
|
+
|
|
22
|
+
## 1. Register + sync
|
|
23
|
+
|
|
24
|
+
If the bay isn't in `garaje.yaml` yet, add it under `bays:`:
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
- name: <bay>
|
|
28
|
+
repo: <clone-url>
|
|
29
|
+
ref: main
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then materialize it (git credentials are already forwarded in-container):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
garaje sync <bay>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 2. Introspect the checkout
|
|
39
|
+
|
|
40
|
+
Read `bays/<bay>` and determine, with evidence (cite the files you used):
|
|
41
|
+
|
|
42
|
+
- **Toolchain + versions:** version files (`.ruby-version`, `.nvmrc`,
|
|
43
|
+
`mise.toml`), lockfiles.
|
|
44
|
+
- **Dev processes:** Procfile / Procfile.dev, package.json scripts, README
|
|
45
|
+
run docs. Identify the primary web process, its port, and an HTTP health
|
|
46
|
+
path.
|
|
47
|
+
- **Backing services:** database/queue/cache config; CI workflows often pin
|
|
48
|
+
the real versions.
|
|
49
|
+
- **Bootstrap:** one-time setup (db prepare / migrate / seed).
|
|
50
|
+
- **Secrets:** declare names only (`required_secrets`) — NEVER values; the
|
|
51
|
+
developer supplies values in `.env`.
|
|
52
|
+
|
|
53
|
+
Judgment calls to make deliberately (and report):
|
|
54
|
+
- A production Dockerfile is NOT a dev recipe — declare the dev toolchain
|
|
55
|
+
instead of reusing prod images.
|
|
56
|
+
- Find the REAL adapter in the config (e.g. the configured queue backend),
|
|
57
|
+
not the first one a grep turns up.
|
|
58
|
+
|
|
59
|
+
## 3. Author or repair the recipe
|
|
60
|
+
|
|
61
|
+
Write `bays/<bay>/recipe.yaml` — it lives in the CODEBASE repo, at its root
|
|
62
|
+
— following `docs/recipe-schema.md`. Commit it locally in the bay:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git -C bays/<bay> add recipe.yaml
|
|
66
|
+
git -C bays/<bay> commit -m "recipe: dev environment for this codebase"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
NEVER push the bay repo unless the user explicitly confirms the push in this
|
|
70
|
+
conversation.
|
|
71
|
+
|
|
72
|
+
## 4. Generate and prove (loop until healthy)
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
garaje park <bay> # recipe -> runtime artifact (deterministic)
|
|
76
|
+
garaje bay up <bay> # build + start this bay only
|
|
77
|
+
garaje bay ps <bay> # poll until the web process shows (healthy)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Health is evaluated by the runtime itself from the recipe's health
|
|
81
|
+
declaration, so `garaje bay ps` is the proof. If it never turns healthy:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
garaje bay logs <bay>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Fix the RECIPE (not generated files), then rerun from `garaje park <bay>`.
|
|
88
|
+
When proven, leave it running or `garaje bay down <bay>`.
|
|
89
|
+
|
|
90
|
+
## 5. Commit the garaje side
|
|
91
|
+
|
|
92
|
+
`garaje park` reports the artifact file it wrote. Commit that artifact plus
|
|
93
|
+
the manifest in THIS repo:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
git add garaje.yaml <the artifact file garaje park reported>
|
|
97
|
+
git commit -m "park <bay>: manifest + generated runtime artifact"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The artifact is committed by design; `garaje doctor` flags drift between it
|
|
101
|
+
and the recipes.
|
|
102
|
+
|
|
103
|
+
Before committing, review the artifact diff: regeneration covers the WHOLE
|
|
104
|
+
synced set, so it may include changes beyond your bay (e.g. a host-port
|
|
105
|
+
renumbering when ports collide across bays) — mention any such change in
|
|
106
|
+
your report.
|
|
107
|
+
|
|
108
|
+
## 6. Report
|
|
109
|
+
|
|
110
|
+
Tell the user: what you inferred and from where, the judgment calls you
|
|
111
|
+
made, how the bay was proven (health output), the two commits created (bay
|
|
112
|
+
repo + garaje repo), and ask whether they want the bay-repo recipe pushed
|
|
113
|
+
upstream (requires their explicit confirmation).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: upgrade-bay
|
|
3
|
+
description: Re-park a bay after upstream changes - pull the codebase, review what changed, repair its recipe if invalidated, regenerate, re-prove health, and commit. Use when a parked bay's code moved, its recipe drifted, or garaje doctor reports a stale or broken bay.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Upgrade (re-park) a bay
|
|
7
|
+
|
|
8
|
+
An upgrade is a **re-park**: the park skill's contract, entered with an
|
|
9
|
+
existing recipe. (Upgrading the framework itself — the `garaje` CLI or the
|
|
10
|
+
`@garaje/base` pin — is a different, host-side operation; not this skill.)
|
|
11
|
+
|
|
12
|
+
## 1. Pull + diff
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
git -C bays/<bay> rev-parse --short HEAD # note the old tip
|
|
16
|
+
garaje sync <bay> # fast-forward the bay
|
|
17
|
+
git -C bays/<bay> log --oneline <old-tip>..HEAD
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Review the range for recipe-relevant drift: dependency/toolchain bumps
|
|
21
|
+
(version files, lockfiles), process changes (Procfile, scripts), new or
|
|
22
|
+
changed backing services, port changes, new required secrets, new bootstrap
|
|
23
|
+
steps (e.g. migrations).
|
|
24
|
+
|
|
25
|
+
## 2. Repair if invalidated
|
|
26
|
+
|
|
27
|
+
If the recipe still holds, say so and continue to step 3. Otherwise edit
|
|
28
|
+
`bays/<bay>/recipe.yaml` and commit locally in the bay — same judgment rules
|
|
29
|
+
as the park skill; NEVER push without the user's explicit confirmation.
|
|
30
|
+
|
|
31
|
+
## 3. Regenerate, re-prove, commit
|
|
32
|
+
|
|
33
|
+
Re-enter the park skill at its step 4 (generate and prove), then its step 5
|
|
34
|
+
(commit the garaje side). Report what changed upstream, what you repaired,
|
|
35
|
+
and how health was re-proven.
|