lazyopencode-core 0.0.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/ATTRIBUTION.md +38 -0
- package/LICENSE +21 -0
- package/README.md +357 -0
- package/dist/agents/councillor.d.ts +1 -0
- package/dist/agents/councillor.js +14 -0
- package/dist/agents/designer.d.ts +1 -0
- package/dist/agents/designer.js +31 -0
- package/dist/agents/explorer.d.ts +1 -0
- package/dist/agents/explorer.js +15 -0
- package/dist/agents/fixer.d.ts +1 -0
- package/dist/agents/fixer.js +23 -0
- package/dist/agents/index.d.ts +2 -0
- package/dist/agents/index.js +55 -0
- package/dist/agents/lazy.d.ts +1 -0
- package/dist/agents/lazy.js +3 -0
- package/dist/agents/librarian.d.ts +1 -0
- package/dist/agents/librarian.js +26 -0
- package/dist/agents/observer.d.ts +1 -0
- package/dist/agents/observer.js +20 -0
- package/dist/agents/oracle.d.ts +1 -0
- package/dist/agents/oracle.js +30 -0
- package/dist/council/council-manager.d.ts +42 -0
- package/dist/council/council-manager.js +223 -0
- package/dist/council/index.d.ts +2 -0
- package/dist/council/index.js +1 -0
- package/dist/hooks/apply-patch-rescue.d.ts +7 -0
- package/dist/hooks/apply-patch-rescue.js +150 -0
- package/dist/hooks/background-job-board.d.ts +92 -0
- package/dist/hooks/background-job-board.js +452 -0
- package/dist/hooks/chat-params.d.ts +16 -0
- package/dist/hooks/chat-params.js +30 -0
- package/dist/hooks/deepwork.d.ts +9 -0
- package/dist/hooks/deepwork.js +55 -0
- package/dist/hooks/error-recovery.d.ts +21 -0
- package/dist/hooks/error-recovery.js +216 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +61 -0
- package/dist/hooks/lazy-command.d.ts +16 -0
- package/dist/hooks/lazy-command.js +178 -0
- package/dist/hooks/messages-transform.d.ts +40 -0
- package/dist/hooks/messages-transform.js +358 -0
- package/dist/hooks/permission-guard.d.ts +5 -0
- package/dist/hooks/permission-guard.js +38 -0
- package/dist/hooks/runtime.d.ts +169 -0
- package/dist/hooks/runtime.js +653 -0
- package/dist/hooks/session-events.d.ts +16 -0
- package/dist/hooks/session-events.js +65 -0
- package/dist/hooks/system-transform.d.ts +8 -0
- package/dist/hooks/system-transform.js +113 -0
- package/dist/hooks/task-session.d.ts +32 -0
- package/dist/hooks/task-session.js +177 -0
- package/dist/hooks/workflow-classifier.d.ts +17 -0
- package/dist/hooks/workflow-classifier.js +170 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +85 -0
- package/dist/opencode-control-plane.d.ts +20 -0
- package/dist/opencode-control-plane.js +95 -0
- package/dist/ponytail.d.ts +1 -0
- package/dist/ponytail.js +33 -0
- package/dist/skills/index.d.ts +5 -0
- package/dist/skills/index.js +10 -0
- package/dist/skills/lazy/build/SKILL.md +62 -0
- package/dist/skills/lazy/debug/SKILL.md +17 -0
- package/dist/skills/lazy/grill/SKILL.md +54 -0
- package/dist/skills/lazy/plan/SKILL.md +52 -0
- package/dist/skills/lazy/review/SKILL.md +29 -0
- package/dist/skills/lazy/security/SKILL.md +29 -0
- package/dist/skills/lazy/simplify/SKILL.md +52 -0
- package/dist/skills/lazy/specify/SKILL.md +62 -0
- package/dist/skills/lazy/worktree/SKILL.md +66 -0
- package/dist/tools/cancel-task.d.ts +3 -0
- package/dist/tools/cancel-task.js +37 -0
- package/dist/tools/council.d.ts +6 -0
- package/dist/tools/council.js +41 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +2 -0
- package/dist/v2.d.ts +1 -0
- package/dist/v2.js +42 -0
- package/docs/architecture.md +47 -0
- package/docs/council.md +200 -0
- package/docs/desktop-distribution.md +36 -0
- package/docs/opencode-integration.md +54 -0
- package/docs/positioning.md +44 -0
- package/docs/product-audit.md +187 -0
- package/docs/product-plan.md +56 -0
- package/docs/state-machine.md +35 -0
- package/docs/user-manual.md +439 -0
- package/docs/work-plan.md +190 -0
- package/package.json +44 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createAgents } from "./agents/index.js";
|
|
2
|
+
import { createHooks } from "./hooks/index.js";
|
|
3
|
+
import { registerLazyCommands } from "./hooks/lazy-command.js";
|
|
4
|
+
import { createLazyRuntime } from "./hooks/runtime.js";
|
|
5
|
+
import { getSkillsDir } from "./skills/index.js";
|
|
6
|
+
import { createCancelTaskTool, createCouncilTool } from "./tools/index.js";
|
|
7
|
+
import { LazyOpenCodeV2Plugin } from "./v2.js";
|
|
8
|
+
import { createOpenCodeControlPlane } from "./opencode-control-plane.js";
|
|
9
|
+
/**
|
|
10
|
+
* @lazyopencode/core — Governed team runtime for AI coding in OpenCode.
|
|
11
|
+
*
|
|
12
|
+
* One plugin. Zero config. Total takeover.
|
|
13
|
+
*
|
|
14
|
+
* Install: { "plugin": ["@lazyopencode/core"] }
|
|
15
|
+
*/
|
|
16
|
+
const LazyOpenCodePluginV1 = async (ctx) => {
|
|
17
|
+
const agents = createAgents();
|
|
18
|
+
const runtime = createLazyRuntime({
|
|
19
|
+
project: ctx.project,
|
|
20
|
+
directory: ctx.directory,
|
|
21
|
+
worktree: ctx.worktree,
|
|
22
|
+
});
|
|
23
|
+
runtime.setControlPlane(createOpenCodeControlPlane(ctx.client));
|
|
24
|
+
const hooks = createHooks(runtime);
|
|
25
|
+
const councilTool = createCouncilTool(ctx.client, () => runtime.config.council, () => {
|
|
26
|
+
const council = runtime.config.council;
|
|
27
|
+
if (council.eligibility === "always")
|
|
28
|
+
return { eligible: true };
|
|
29
|
+
const level = runtime.workflow.lastDecision?.level;
|
|
30
|
+
if (level === "high_risk" || level === "ambiguous")
|
|
31
|
+
return { eligible: true };
|
|
32
|
+
if (runtime.workflow.stage === "debug")
|
|
33
|
+
return { eligible: true };
|
|
34
|
+
return {
|
|
35
|
+
eligible: false,
|
|
36
|
+
reason: 'Council blocked: not eligible for current workflow. Run /lazy start for risk classification, enter debug, or set council.eligibility = "always".',
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
const cancelTaskTool = createCancelTaskTool(runtime.jobBoard);
|
|
40
|
+
return {
|
|
41
|
+
runtime,
|
|
42
|
+
tool: {
|
|
43
|
+
council_session: councilTool,
|
|
44
|
+
cancel_task: cancelTaskTool,
|
|
45
|
+
},
|
|
46
|
+
config: async (config) => {
|
|
47
|
+
const cfg = config;
|
|
48
|
+
runtime.configure(cfg.lazyopencode);
|
|
49
|
+
await runtime.load();
|
|
50
|
+
cfg.agent = mergeAgents(cfg.agent ?? {}, agents);
|
|
51
|
+
cfg.skills = cfg.skills || {};
|
|
52
|
+
const paths = cfg.skills.paths || [];
|
|
53
|
+
const skillsDir = getSkillsDir();
|
|
54
|
+
if (!paths.includes(skillsDir)) {
|
|
55
|
+
paths.push(skillsDir);
|
|
56
|
+
}
|
|
57
|
+
cfg.skills.paths = paths;
|
|
58
|
+
// deno-lint-ignore no-explicit-any
|
|
59
|
+
const mcp = cfg.mcp;
|
|
60
|
+
if (!mcp?.context7) {
|
|
61
|
+
// deno-lint-ignore no-explicit-any
|
|
62
|
+
;
|
|
63
|
+
cfg.mcp = {
|
|
64
|
+
...(mcp || {}),
|
|
65
|
+
context7: { command: ["npx", "-y", "@agentdesk/context7-mcp"] },
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
registerLazyCommands(cfg, runtime);
|
|
69
|
+
},
|
|
70
|
+
dispose: async () => {
|
|
71
|
+
await runtime.save();
|
|
72
|
+
},
|
|
73
|
+
...hooks,
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
const LazyOpenCodePlugin = LazyOpenCodePluginV1;
|
|
77
|
+
export { LazyOpenCodePlugin, LazyOpenCodePluginV1, LazyOpenCodeV2Plugin };
|
|
78
|
+
export default LazyOpenCodeV2Plugin;
|
|
79
|
+
function mergeAgents(existing, lazyAgents) {
|
|
80
|
+
const merged = { ...existing };
|
|
81
|
+
for (const [name, defaults] of Object.entries(lazyAgents)) {
|
|
82
|
+
merged[name] = { ...defaults, ...merged[name] };
|
|
83
|
+
}
|
|
84
|
+
return merged;
|
|
85
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface OpenCodeControlPlaneSnapshot {
|
|
2
|
+
sessionStatus: string;
|
|
3
|
+
pendingPermissions: number;
|
|
4
|
+
todos: number;
|
|
5
|
+
diffSummary: string;
|
|
6
|
+
worktree: string;
|
|
7
|
+
capabilities: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface OpenCodeControlPlane {
|
|
10
|
+
snapshot(sessionID?: string): Promise<OpenCodeControlPlaneSnapshot>;
|
|
11
|
+
wait(sessionID: string): Promise<{
|
|
12
|
+
ok: boolean;
|
|
13
|
+
reason?: string;
|
|
14
|
+
}>;
|
|
15
|
+
revert(checkpointID: string): Promise<{
|
|
16
|
+
ok: boolean;
|
|
17
|
+
reason?: string;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
export declare function createOpenCodeControlPlane(client: unknown): OpenCodeControlPlane;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export function createOpenCodeControlPlane(client) {
|
|
2
|
+
const c = (client ?? {});
|
|
3
|
+
return {
|
|
4
|
+
async snapshot(sessionID) {
|
|
5
|
+
const capabilities = detectCapabilities(c);
|
|
6
|
+
const sessionStatus = await callString(c, ["sessionStatus", "status"], sessionID, "unknown");
|
|
7
|
+
const pendingPermissions = await callCount(c, ["pendingPermissions", "permissions"], sessionID);
|
|
8
|
+
const todos = await callCount(c, ["todos", "todo"], sessionID);
|
|
9
|
+
const diffSummary = await callString(c, ["diffSummary", "diff"], sessionID, "not collected");
|
|
10
|
+
const worktree = await callString(c, ["worktree", "projectWorktree"], sessionID, "unknown");
|
|
11
|
+
return { sessionStatus, pendingPermissions, todos, diffSummary, worktree, capabilities };
|
|
12
|
+
},
|
|
13
|
+
async wait(sessionID) {
|
|
14
|
+
return await callOk(c, ["wait", "sessionWait"], sessionID);
|
|
15
|
+
},
|
|
16
|
+
async revert(checkpointID) {
|
|
17
|
+
return await callOk(c, ["revert", "revertCheckpoint"], checkpointID);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function detectCapabilities(client) {
|
|
22
|
+
const names = [
|
|
23
|
+
["sessionStatus", "status"],
|
|
24
|
+
["children"],
|
|
25
|
+
["wait", "sessionWait"],
|
|
26
|
+
["context"],
|
|
27
|
+
["messages"],
|
|
28
|
+
["diffSummary", "diff"],
|
|
29
|
+
["todos", "todo"],
|
|
30
|
+
["pendingPermissions", "permissions"],
|
|
31
|
+
["worktree", "projectWorktree"],
|
|
32
|
+
["revert", "revertCheckpoint"],
|
|
33
|
+
];
|
|
34
|
+
return names
|
|
35
|
+
.filter((group) => group.some((name) => typeof client[name] === "function"))
|
|
36
|
+
.map((group) => group[0]);
|
|
37
|
+
}
|
|
38
|
+
async function callString(client, names, arg, fallback) {
|
|
39
|
+
try {
|
|
40
|
+
const value = await callFirst(client, names, arg);
|
|
41
|
+
if (value === undefined || value === null)
|
|
42
|
+
return fallback;
|
|
43
|
+
if (typeof value === "string")
|
|
44
|
+
return value;
|
|
45
|
+
if (typeof value === "object") {
|
|
46
|
+
const record = value;
|
|
47
|
+
return String(record.summary ?? record.status ?? record.path ?? fallback);
|
|
48
|
+
}
|
|
49
|
+
return String(value);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return fallback;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function callCount(client, names, arg) {
|
|
56
|
+
try {
|
|
57
|
+
const value = await callFirst(client, names, arg);
|
|
58
|
+
if (Array.isArray(value))
|
|
59
|
+
return value.length;
|
|
60
|
+
if (typeof value === "number")
|
|
61
|
+
return value;
|
|
62
|
+
if (value && typeof value === "object") {
|
|
63
|
+
const record = value;
|
|
64
|
+
if (typeof record.count === "number")
|
|
65
|
+
return record.count;
|
|
66
|
+
if (Array.isArray(record.items))
|
|
67
|
+
return record.items.length;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
async function callOk(client, names, arg) {
|
|
76
|
+
try {
|
|
77
|
+
const value = await callFirst(client, names, arg);
|
|
78
|
+
if (value && typeof value === "object" && "ok" in value) {
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
return { ok: true };
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function callFirst(client, names, arg) {
|
|
88
|
+
for (const name of names) {
|
|
89
|
+
const fn = client[name];
|
|
90
|
+
if (typeof fn === "function") {
|
|
91
|
+
return await fn(arg);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const PONYTAIL_MODE = "PONYTAIL MODE ACTIVE \u2014 level: full\n\nYou are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written.\n\n## The ladder \u2014 stop at the first rung that holds\n1. Does this need to exist at all? (YAGNI) Speculative need = skip.\n2. Stdlib does it? Use it.\n3. Native platform feature covers it? CSS over JS, DB constraint over app code.\n4. Already-installed dependency solves it? Use it. Never add new deps for spare change.\n5. Can it be one line? One line.\n6. Only then: the minimum code that works.\n\n## Rules\n- No unrequested abstractions. One implementation = no interface, one product = no factory.\n- No boilerplate, no scaffolding \"for later\". Later can scaffold for itself.\n- Deletion over addition. Boring over clever.\n- Fewest files possible. Shortest working diff wins.\n- Two stdlib options? Pick the one correct on edge cases \u2014 lazy means less code, not sloppy algorithms.\n- Mark deliberate simplifications with `ponytail:` comment + ceiling + upgrade path.\n\n## Output discipline\n- Code first. No unrequested essays, feature tours, or design notes.\n- Explanation longer than the code \u2192 delete the explanation.\n- Pattern: `[code] \u2192 skipped: X, add when Y.`\n\n## When NOT to be lazy\n- Input validation at trust boundaries\n- Error handling that prevents data loss\n- Security measures, accessibility basics\n- Anything explicitly requested full-version by the user\n\n## Lazy check \u2014 a reflex\nEvery task, every file, every function: ask \"does this need to exist?\" first.";
|
package/dist/ponytail.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const PONYTAIL_MODE = `PONYTAIL MODE ACTIVE — level: full
|
|
2
|
+
|
|
3
|
+
You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written.
|
|
4
|
+
|
|
5
|
+
## The ladder — stop at the first rung that holds
|
|
6
|
+
1. Does this need to exist at all? (YAGNI) Speculative need = skip.
|
|
7
|
+
2. Stdlib does it? Use it.
|
|
8
|
+
3. Native platform feature covers it? CSS over JS, DB constraint over app code.
|
|
9
|
+
4. Already-installed dependency solves it? Use it. Never add new deps for spare change.
|
|
10
|
+
5. Can it be one line? One line.
|
|
11
|
+
6. Only then: the minimum code that works.
|
|
12
|
+
|
|
13
|
+
## Rules
|
|
14
|
+
- No unrequested abstractions. One implementation = no interface, one product = no factory.
|
|
15
|
+
- No boilerplate, no scaffolding "for later". Later can scaffold for itself.
|
|
16
|
+
- Deletion over addition. Boring over clever.
|
|
17
|
+
- Fewest files possible. Shortest working diff wins.
|
|
18
|
+
- Two stdlib options? Pick the one correct on edge cases — lazy means less code, not sloppy algorithms.
|
|
19
|
+
- Mark deliberate simplifications with \`ponytail:\` comment + ceiling + upgrade path.
|
|
20
|
+
|
|
21
|
+
## Output discipline
|
|
22
|
+
- Code first. No unrequested essays, feature tours, or design notes.
|
|
23
|
+
- Explanation longer than the code → delete the explanation.
|
|
24
|
+
- Pattern: \`[code] → skipped: X, add when Y.\`
|
|
25
|
+
|
|
26
|
+
## When NOT to be lazy
|
|
27
|
+
- Input validation at trust boundaries
|
|
28
|
+
- Error handling that prevents data loss
|
|
29
|
+
- Security measures, accessibility basics
|
|
30
|
+
- Anything explicitly requested full-version by the user
|
|
31
|
+
|
|
32
|
+
## Lazy check — a reflex
|
|
33
|
+
Every task, every file, every function: ask "does this need to exist?" first.`;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Returns the absolute path to the lazy skills directory.
|
|
5
|
+
* Registered in config.skills.paths so OpenCode discovers them.
|
|
6
|
+
*/
|
|
7
|
+
export function getSkillsDir() {
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
return join(__dirname, "lazy/");
|
|
10
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lazy/build
|
|
3
|
+
description: Implement one vertical slice at a time, test-first, YAGNI-gated. Supports --prototype for throwaway verification.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Implement a piece of work from a PRD or issue. Default to TDD. YAGNI at every step.
|
|
7
|
+
|
|
8
|
+
## Modes
|
|
9
|
+
|
|
10
|
+
### Normal mode (default)
|
|
11
|
+
|
|
12
|
+
For production code. Red-green-refactor per vertical slice.
|
|
13
|
+
|
|
14
|
+
Before starting:
|
|
15
|
+
|
|
16
|
+
- [ ] Confirm interface changes with user
|
|
17
|
+
- [ ] Prioritize behaviors to test
|
|
18
|
+
- [ ] Identify deep-module opportunities (small interface, deep implementation)
|
|
19
|
+
|
|
20
|
+
Per behavior:
|
|
21
|
+
|
|
22
|
+
1. **RED**: Write one test for one behavior → fails
|
|
23
|
+
2. **GREEN**: Minimal code to pass → passes
|
|
24
|
+
3. Verify the test describes behavior, not implementation
|
|
25
|
+
|
|
26
|
+
After all tests pass:
|
|
27
|
+
|
|
28
|
+
- [ ] Look for refactor candidates (deepen modules, extract duplication)
|
|
29
|
+
- [ ] Never refactor while RED
|
|
30
|
+
|
|
31
|
+
### --prototype mode
|
|
32
|
+
|
|
33
|
+
For fast verification before committing to production code. Skips tests and polish.
|
|
34
|
+
|
|
35
|
+
- Write minimal code to answer a specific question
|
|
36
|
+
- No tests, no error handling beyond what keeps it runnable
|
|
37
|
+
- One command to run
|
|
38
|
+
- State in memory, no persistence
|
|
39
|
+
- Mark clearly as PROTOTYPE — the user must know it's throwaway
|
|
40
|
+
- Surface full state after every action
|
|
41
|
+
|
|
42
|
+
When done, either:
|
|
43
|
+
|
|
44
|
+
- Delete the prototype (question answered "no"), or
|
|
45
|
+
- Fold validated decisions into real code (question answered "yes")
|
|
46
|
+
- Do NOT leave it rotting in the repo
|
|
47
|
+
|
|
48
|
+
### Phased mode (large tasks)
|
|
49
|
+
|
|
50
|
+
If the work spans 3+ files or 2+ agents, break into phases automatically:
|
|
51
|
+
|
|
52
|
+
1. Phase 1: core logic + test
|
|
53
|
+
2. Phase 2: integration + test
|
|
54
|
+
3. Phase 3: polish + final review
|
|
55
|
+
|
|
56
|
+
Run phase N+1 only after phase N passes review.
|
|
57
|
+
|
|
58
|
+
## Verification
|
|
59
|
+
|
|
60
|
+
- Run typecheck after each slice
|
|
61
|
+
- Run the full test suite at the end
|
|
62
|
+
- If `lazy/review` is available, run it on completion
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lazy/debug
|
|
3
|
+
description: Systematic diagnosis loop for bugs where the cause is unclear.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Process
|
|
7
|
+
|
|
8
|
+
1. **Reproduce.** Can you reliably trigger it? Gather exact steps/logs. If unreproducible, document environment/conditions.
|
|
9
|
+
2. **Isolate.** Narrow scope: what changed (git log/bisect)? Smallest triggering input? Boundary? If bug involves a library API, check current docs via context7.
|
|
10
|
+
3. **Hypothesize.** Form exactly one hypothesis. State it clearly.
|
|
11
|
+
4. **Test hypothesis.** Smallest test/log that proves/disproves it. Do NOT fix yet.
|
|
12
|
+
5. **Iterate.** Disproven → new hypothesis. Proven → go to 6. Stuck after 3 cycles → escalate to @lazy-oracle.
|
|
13
|
+
6. **Fix.** Fix root cause, not symptoms. Confirm root cause → write failing test → minimal fix → verify test passes → full suite regression check. Then load `lazy/review`.
|
|
14
|
+
|
|
15
|
+
## Output Contract
|
|
16
|
+
|
|
17
|
+
- Repro, hypothesis, proof, root cause (1 line), minimal fix
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lazy/grill
|
|
3
|
+
description: Interview relentlessly to sharpen a plan or design before building.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Run a relentless interview to stress-test a plan or design before committing to implementation.
|
|
7
|
+
|
|
8
|
+
Do NOT build. Do NOT write code. Only ask questions.
|
|
9
|
+
|
|
10
|
+
## Process
|
|
11
|
+
|
|
12
|
+
### 1. Start from the user's prompt
|
|
13
|
+
|
|
14
|
+
If the user says "grill me on X" or "I want to build Y", start grilling. If the request is vague, start from the broadest question.
|
|
15
|
+
|
|
16
|
+
### 2. The questions — not a script, a posture
|
|
17
|
+
|
|
18
|
+
Every question must be one of:
|
|
19
|
+
|
|
20
|
+
- **Goal**: What does success look like? What must not break? Who is the user?
|
|
21
|
+
- **Constraint**: What's out of scope? What's non-negotiable? What's the deadline?
|
|
22
|
+
- **Risk**: What's the hardest part? What have you tried before? What went wrong?
|
|
23
|
+
- **Evidence**: Why this approach over alternatives? What data supports it?
|
|
24
|
+
- **Seam**: Where does this touch existing code? What's the interface boundary?
|
|
25
|
+
|
|
26
|
+
Do not ask all five categories every session. Pick the ones the user's plan is weakest on.
|
|
27
|
+
|
|
28
|
+
### 3. Iterate until the user says "enough"
|
|
29
|
+
|
|
30
|
+
You don't need to cover everything. Stop when:
|
|
31
|
+
|
|
32
|
+
- The user says "that's enough, let's build"
|
|
33
|
+
- The user's answers are specific enough to write a spec
|
|
34
|
+
- You've identified the top 2-3 risks
|
|
35
|
+
|
|
36
|
+
### 4. Output: a crisp summary
|
|
37
|
+
|
|
38
|
+
After the session, produce:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Grill summary:
|
|
42
|
+
- 3 things we know (confirmed by user)
|
|
43
|
+
- 2 things we decided (boundaries, constraints)
|
|
44
|
+
- 1 biggest risk
|
|
45
|
+
- Outcome: build / prototype / kill
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Do NOT generate a PRD. That's lazy/specify's job.
|
|
49
|
+
|
|
50
|
+
### When to stop grilling
|
|
51
|
+
|
|
52
|
+
- User says "just do it" → output summary, stop
|
|
53
|
+
- Task is trivial (one-liner, typo, config change) → skip grill entirely
|
|
54
|
+
- User cannot answer the basics → flag as "not ready to build"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lazy/plan
|
|
3
|
+
description: Break a PRD or spec into independently-grabbable tracer-bullet issues.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Break a spec or PRD into vertical-slice issues. Each issue is a thin, end-to-end path through ALL layers — NOT horizontal (all schema, then all API, then all UI).
|
|
7
|
+
|
|
8
|
+
## Process
|
|
9
|
+
|
|
10
|
+
### 1. Gather context
|
|
11
|
+
|
|
12
|
+
Read the PRD or spec from context. If the user passes an issue reference, fetch it.
|
|
13
|
+
|
|
14
|
+
### 2. Explore the codebase (if needed)
|
|
15
|
+
|
|
16
|
+
Read CONTEXT.md. Check ADRs. Look for prefactoring opportunities — "make the change easy, then make the easy change."
|
|
17
|
+
|
|
18
|
+
### 3. Draft vertical slices
|
|
19
|
+
|
|
20
|
+
Each slice must be:
|
|
21
|
+
|
|
22
|
+
- **Demoable alone**: after this slice, something visible or verifiable works
|
|
23
|
+
- **End-to-end**: cuts through schema → API → UI → tests
|
|
24
|
+
- **Dependency-orderable**: blocker-first
|
|
25
|
+
|
|
26
|
+
### 4. Present to user
|
|
27
|
+
|
|
28
|
+
For each slice, show: title, blocked-by, user stories covered. Ask:
|
|
29
|
+
|
|
30
|
+
- Granularity feel right?
|
|
31
|
+
- Dependencies correct?
|
|
32
|
+
- Merge or split any?
|
|
33
|
+
|
|
34
|
+
### 5. Publish
|
|
35
|
+
|
|
36
|
+
Create issues on the tracker in dependency order (blockers first). Use body template:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
## What to build
|
|
40
|
+
|
|
41
|
+
End-to-end behavior, not layer-by-layer.
|
|
42
|
+
|
|
43
|
+
## Acceptance criteria
|
|
44
|
+
|
|
45
|
+
- [ ] Criterion 1
|
|
46
|
+
|
|
47
|
+
## Blocked by
|
|
48
|
+
|
|
49
|
+
- Issue reference or "None"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Do NOT close or modify the parent spec issue.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lazy/review
|
|
3
|
+
description: Code review focused on bugs, missing cases, and deletion opportunities — not additions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Review code for correctness and simplicity. Default stance: **what can we delete?**
|
|
7
|
+
|
|
8
|
+
## Process
|
|
9
|
+
|
|
10
|
+
1. Read the diff. Understand the problem it solves.
|
|
11
|
+
2. Find bugs: logic errors, off-by-one, null/undefined risks, edge cases, broken tests.
|
|
12
|
+
3. Find deletions: unused code, dead branches, one-use abstractions, stdlib-replaceable code, "for later" scaffolding.
|
|
13
|
+
4. Check `ponytail:` comments — do they name the ceiling and upgrade path? Mark unmarked debt.
|
|
14
|
+
5. Produce review output.
|
|
15
|
+
|
|
16
|
+
## Output Contract
|
|
17
|
+
|
|
18
|
+
| Priority | Label | What |
|
|
19
|
+
| -------- | ------------- | ----------------------------------------------- |
|
|
20
|
+
| 1 | 🔴 Must fix | real bugs, security issues |
|
|
21
|
+
| 2 | 🟡 Should fix | code quality, simplifications |
|
|
22
|
+
| 3 | 🟢 Can delete | removable dead code |
|
|
23
|
+
| 4 | ponytail: | unmarked shortcuts needing `ponytail:` comments |
|
|
24
|
+
|
|
25
|
+
## Rules
|
|
26
|
+
|
|
27
|
+
- Default to "delete" over "add validation/abstraction/logging."
|
|
28
|
+
- Unsure if a bug is real → mark 🟡 not 🔴.
|
|
29
|
+
- One finding per bullet. No essays.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lazy/security
|
|
3
|
+
description: OWASP-bucketed security audit, concrete PoC required per finding
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# lazy/security
|
|
7
|
+
|
|
8
|
+
## Process
|
|
9
|
+
|
|
10
|
+
1. **Scope trust boundaries.** Identify user/API/file inputs, sensitive data, and auth boundaries.
|
|
11
|
+
2. **Audit by OWASP.** Check injection, authn, authz, data exposure, input validation.
|
|
12
|
+
3. **PoC every finding.** For each: exact attack vector → impact → minimal fix.
|
|
13
|
+
|
|
14
|
+
## Output format
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
## Security Review: [scope]
|
|
18
|
+
|
|
19
|
+
### 🔴 Critical (exploitable now)
|
|
20
|
+
- [OWASP category]: [finding] → [PoC] → [fix]
|
|
21
|
+
|
|
22
|
+
### 🟡 Warning (defense-in-depth)
|
|
23
|
+
- [OWASP category]: [finding] → [mitigation]
|
|
24
|
+
|
|
25
|
+
### 🟢 Clean
|
|
26
|
+
- [area reviewed]: no issues found
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Only report real, exploitable issues. 🔴 requires concrete PoC. Mark theoretical risks 🟡.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lazy/simplify
|
|
3
|
+
description: Find code to delete or collapse. Ponytail: deletion over addition, one line over fifty.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Find what to delete, one line per finding. The goal is not "cleaner" — it's "less."
|
|
7
|
+
|
|
8
|
+
Ponytail rule: every simplification must pass the deletion test — "would removing this concentrate complexity or just move it?" Only the former counts as simplification.
|
|
9
|
+
|
|
10
|
+
## When to simplify
|
|
11
|
+
|
|
12
|
+
- After a feature works and tests pass, but feels heavier than needed
|
|
13
|
+
- During review when complexity is flagged
|
|
14
|
+
- When you encounter deep nesting, long functions, dead code, or wrappers that add no value
|
|
15
|
+
- After merging changes that introduced duplication
|
|
16
|
+
|
|
17
|
+
Do NOT simplify code you don't understand yet.
|
|
18
|
+
|
|
19
|
+
## Process
|
|
20
|
+
|
|
21
|
+
### Step 1: Understand before touching
|
|
22
|
+
|
|
23
|
+
- What does this code do?
|
|
24
|
+
- What calls it? What does it call?
|
|
25
|
+
- Are there tests?
|
|
26
|
+
- Why was it written this way?
|
|
27
|
+
|
|
28
|
+
### Step 2: Scan for deletion opportunities
|
|
29
|
+
|
|
30
|
+
- Dead code (exports no one imports, branches that never trigger)
|
|
31
|
+
- Wrappers that add no value (a function that just calls another function with no extra logic)
|
|
32
|
+
- Duplicated logic
|
|
33
|
+
- Boolean flag parameters (replace with two functions)
|
|
34
|
+
- Nested ternaries (replace with control flow)
|
|
35
|
+
- Wrappers or abstractions that could be inlined without losing clarity
|
|
36
|
+
|
|
37
|
+
### Step 3: Deep scan (absorbed from improve-codebase-architecture)
|
|
38
|
+
|
|
39
|
+
For modules in the affected area, check:
|
|
40
|
+
|
|
41
|
+
- **Depth**: is the interface nearly as complex as the implementation? If so, it's shallow — look for ways to move complexity behind the interface.
|
|
42
|
+
- **Seam**: can you alter behavior without editing in that place? If not, there's no real seam.
|
|
43
|
+
- **Leverage**: does one implementation serve N call sites? If N=1 and the abstraction has overhead, inline it.
|
|
44
|
+
- **Locality**: does understanding one concept require bouncing between many small modules? If so, consider merging.
|
|
45
|
+
|
|
46
|
+
Use the vocabulary exactly: **module**, **interface**, **depth**, **seam**, **adapter**, **leverage**, **locality**.
|
|
47
|
+
|
|
48
|
+
### Step 4: Verify
|
|
49
|
+
|
|
50
|
+
- Make one change at a time
|
|
51
|
+
- Run tests after each change
|
|
52
|
+
- The result must be easier to understand AND have fewer lines than the original
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lazy/specify
|
|
3
|
+
description: Turn grilled discussion into a PRD with domain terms and acceptance criteria.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Synthesize what you already know into a PRD. Do NOT interview the user — just write it from the conversation.
|
|
7
|
+
|
|
8
|
+
## Process
|
|
9
|
+
|
|
10
|
+
### 1. Explore the codebase
|
|
11
|
+
|
|
12
|
+
Read CONTEXT.md if it exists. Check ADRs in the affected area. Use domain vocabulary from the project's glossary.
|
|
13
|
+
|
|
14
|
+
### 2. Identify seams
|
|
15
|
+
|
|
16
|
+
Sketch the interfaces where this feature connects to existing code. Use the vocabulary of codebase-design: **module**, **seam**, **adapter**, **leverage**. Prefer existing seams over new ones. Fewer seams = better; ideal = one.
|
|
17
|
+
|
|
18
|
+
Check with the user that these seams match their expectations.
|
|
19
|
+
|
|
20
|
+
### 3. Write the PRD
|
|
21
|
+
|
|
22
|
+
Use this template:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
## Problem Statement
|
|
26
|
+
|
|
27
|
+
The problem from the user's perspective.
|
|
28
|
+
|
|
29
|
+
## Solution
|
|
30
|
+
|
|
31
|
+
The solution, from the user's perspective.
|
|
32
|
+
|
|
33
|
+
## User Stories
|
|
34
|
+
|
|
35
|
+
1. As an <actor>, I want <feature>, so that <benefit>
|
|
36
|
+
|
|
37
|
+
Extensive. Cover all aspects.
|
|
38
|
+
|
|
39
|
+
## Implementation Decisions
|
|
40
|
+
|
|
41
|
+
Modules to build/modify, interfaces, architectural decisions, schema changes, API contracts.
|
|
42
|
+
|
|
43
|
+
Do NOT include file paths or code snippets unless a prototype produced a decision-rich snippet.
|
|
44
|
+
|
|
45
|
+
## Domain Glossary (new terms added)
|
|
46
|
+
|
|
47
|
+
Any new terms introduced by this feature. Existing terms in CONTEXT.md should be referenced, not redefined.
|
|
48
|
+
|
|
49
|
+
## Testing Decisions
|
|
50
|
+
|
|
51
|
+
What makes a good test (external behavior only). Which seam to test at. Prior art.
|
|
52
|
+
|
|
53
|
+
## Out of Scope
|
|
54
|
+
|
|
55
|
+
## Further Notes
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 4. Publish
|
|
59
|
+
|
|
60
|
+
Create a tracking issue (or write to a file). Apply the `ready-for-plan` label.
|
|
61
|
+
|
|
62
|
+
If user wants an ADR, write it to `docs/adr/<NNNN>-<title>.md`.
|