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.
Files changed (89) hide show
  1. package/ATTRIBUTION.md +38 -0
  2. package/LICENSE +21 -0
  3. package/README.md +357 -0
  4. package/dist/agents/councillor.d.ts +1 -0
  5. package/dist/agents/councillor.js +14 -0
  6. package/dist/agents/designer.d.ts +1 -0
  7. package/dist/agents/designer.js +31 -0
  8. package/dist/agents/explorer.d.ts +1 -0
  9. package/dist/agents/explorer.js +15 -0
  10. package/dist/agents/fixer.d.ts +1 -0
  11. package/dist/agents/fixer.js +23 -0
  12. package/dist/agents/index.d.ts +2 -0
  13. package/dist/agents/index.js +55 -0
  14. package/dist/agents/lazy.d.ts +1 -0
  15. package/dist/agents/lazy.js +3 -0
  16. package/dist/agents/librarian.d.ts +1 -0
  17. package/dist/agents/librarian.js +26 -0
  18. package/dist/agents/observer.d.ts +1 -0
  19. package/dist/agents/observer.js +20 -0
  20. package/dist/agents/oracle.d.ts +1 -0
  21. package/dist/agents/oracle.js +30 -0
  22. package/dist/council/council-manager.d.ts +42 -0
  23. package/dist/council/council-manager.js +223 -0
  24. package/dist/council/index.d.ts +2 -0
  25. package/dist/council/index.js +1 -0
  26. package/dist/hooks/apply-patch-rescue.d.ts +7 -0
  27. package/dist/hooks/apply-patch-rescue.js +150 -0
  28. package/dist/hooks/background-job-board.d.ts +92 -0
  29. package/dist/hooks/background-job-board.js +452 -0
  30. package/dist/hooks/chat-params.d.ts +16 -0
  31. package/dist/hooks/chat-params.js +30 -0
  32. package/dist/hooks/deepwork.d.ts +9 -0
  33. package/dist/hooks/deepwork.js +55 -0
  34. package/dist/hooks/error-recovery.d.ts +21 -0
  35. package/dist/hooks/error-recovery.js +216 -0
  36. package/dist/hooks/index.d.ts +3 -0
  37. package/dist/hooks/index.js +61 -0
  38. package/dist/hooks/lazy-command.d.ts +16 -0
  39. package/dist/hooks/lazy-command.js +178 -0
  40. package/dist/hooks/messages-transform.d.ts +40 -0
  41. package/dist/hooks/messages-transform.js +358 -0
  42. package/dist/hooks/permission-guard.d.ts +5 -0
  43. package/dist/hooks/permission-guard.js +38 -0
  44. package/dist/hooks/runtime.d.ts +169 -0
  45. package/dist/hooks/runtime.js +653 -0
  46. package/dist/hooks/session-events.d.ts +16 -0
  47. package/dist/hooks/session-events.js +65 -0
  48. package/dist/hooks/system-transform.d.ts +8 -0
  49. package/dist/hooks/system-transform.js +113 -0
  50. package/dist/hooks/task-session.d.ts +32 -0
  51. package/dist/hooks/task-session.js +177 -0
  52. package/dist/hooks/workflow-classifier.d.ts +17 -0
  53. package/dist/hooks/workflow-classifier.js +170 -0
  54. package/dist/index.d.ts +13 -0
  55. package/dist/index.js +85 -0
  56. package/dist/opencode-control-plane.d.ts +20 -0
  57. package/dist/opencode-control-plane.js +95 -0
  58. package/dist/ponytail.d.ts +1 -0
  59. package/dist/ponytail.js +33 -0
  60. package/dist/skills/index.d.ts +5 -0
  61. package/dist/skills/index.js +10 -0
  62. package/dist/skills/lazy/build/SKILL.md +62 -0
  63. package/dist/skills/lazy/debug/SKILL.md +17 -0
  64. package/dist/skills/lazy/grill/SKILL.md +54 -0
  65. package/dist/skills/lazy/plan/SKILL.md +52 -0
  66. package/dist/skills/lazy/review/SKILL.md +29 -0
  67. package/dist/skills/lazy/security/SKILL.md +29 -0
  68. package/dist/skills/lazy/simplify/SKILL.md +52 -0
  69. package/dist/skills/lazy/specify/SKILL.md +62 -0
  70. package/dist/skills/lazy/worktree/SKILL.md +66 -0
  71. package/dist/tools/cancel-task.d.ts +3 -0
  72. package/dist/tools/cancel-task.js +37 -0
  73. package/dist/tools/council.d.ts +6 -0
  74. package/dist/tools/council.js +41 -0
  75. package/dist/tools/index.d.ts +2 -0
  76. package/dist/tools/index.js +2 -0
  77. package/dist/v2.d.ts +1 -0
  78. package/dist/v2.js +42 -0
  79. package/docs/architecture.md +47 -0
  80. package/docs/council.md +200 -0
  81. package/docs/desktop-distribution.md +36 -0
  82. package/docs/opencode-integration.md +54 -0
  83. package/docs/positioning.md +44 -0
  84. package/docs/product-audit.md +187 -0
  85. package/docs/product-plan.md +56 -0
  86. package/docs/state-machine.md +35 -0
  87. package/docs/user-manual.md +439 -0
  88. package/docs/work-plan.md +190 -0
  89. 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.";
@@ -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,5 @@
1
+ /**
2
+ * Returns the absolute path to the lazy skills directory.
3
+ * Registered in config.skills.paths so OpenCode discovers them.
4
+ */
5
+ export declare function getSkillsDir(): string;
@@ -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`.