@lenardangeloolajay/len-toolkit 1.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.
Files changed (114) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +209 -0
  3. package/bin/cli.js +244 -0
  4. package/package.json +35 -0
  5. package/src/installer.js +236 -0
  6. package/templates/configs/.editorconfig +12 -0
  7. package/templates/configs/sample.gitignore +8 -0
  8. package/templates/docs/FEATURE.md +40 -0
  9. package/templates/docs/HANDOFF.md +39 -0
  10. package/templates/docs/IMPLEMENTATION_PLAN.md +47 -0
  11. package/templates/docs/SPEC_INDEX.md +12 -0
  12. package/templates/docs/VERIFICATION.md +14 -0
  13. package/templates/docs/product/ARCHITECTURE.md +22 -0
  14. package/templates/docs/product/CONSTRAINTS.md +22 -0
  15. package/templates/docs/product/DATA_MODEL.md +22 -0
  16. package/templates/docs/product/OVERVIEW.md +22 -0
  17. package/templates/examples/flutter-handoff/EXERCISES.md +16 -0
  18. package/templates/examples/flutter-handoff/HANDOFF.md +32 -0
  19. package/templates/examples/flutter-handoff/docs/SPEC_INDEX.md +19 -0
  20. package/templates/examples/flutter-handoff/docs/evidence/FEAT-001-verification.md +14 -0
  21. package/templates/examples/flutter-handoff/docs/features/FEAT-001-local-note.md +40 -0
  22. package/templates/examples/flutter-handoff/docs/plans/FEAT-001-implementation.md +43 -0
  23. package/templates/examples/flutter-handoff/docs/product/ARCHITECTURE.md +24 -0
  24. package/templates/examples/flutter-handoff/docs/product/CONSTRAINTS.md +13 -0
  25. package/templates/examples/flutter-handoff/docs/product/DATA_MODEL.md +20 -0
  26. package/templates/examples/flutter-handoff/docs/product/OVERVIEW.md +26 -0
  27. package/templates/rules/.cursorrules +7 -0
  28. package/templates/rules/AGENTS.md +61 -0
  29. package/templates/rules/GEMINI.md +7 -0
  30. package/templates/skills/a-philosophy-of-software-design/SKILL.md +11 -0
  31. package/templates/skills/a-philosophy-of-software-design/a-philosophy-of-software-design.md +370 -0
  32. package/templates/skills/a-philosophy-of-software-design/a-philosophy-of-software-design.mini.md +46 -0
  33. package/templates/skills/a-philosophy-of-software-design/a-philosophy-of-software-design.nano.md +35 -0
  34. package/templates/skills/clean-architecture/SKILL.md +11 -0
  35. package/templates/skills/clean-architecture/clean-architecture.md +515 -0
  36. package/templates/skills/clean-architecture/clean-architecture.mini.md +49 -0
  37. package/templates/skills/clean-architecture/clean-architecture.nano.md +36 -0
  38. package/templates/skills/clean-code/SKILL.md +11 -0
  39. package/templates/skills/clean-code/clean-code.md +297 -0
  40. package/templates/skills/clean-code/clean-code.mini.md +47 -0
  41. package/templates/skills/clean-code/clean-code.nano.md +32 -0
  42. package/templates/skills/code-complete/SKILL.md +11 -0
  43. package/templates/skills/code-complete/code-complete.md +354 -0
  44. package/templates/skills/code-complete/code-complete.mini.md +56 -0
  45. package/templates/skills/code-complete/code-complete.nano.md +41 -0
  46. package/templates/skills/council/SKILL.md +37 -0
  47. package/templates/skills/designing-data-intensive-applications/SKILL.md +11 -0
  48. package/templates/skills/designing-data-intensive-applications/designing-data-intensive-applications.md +393 -0
  49. package/templates/skills/designing-data-intensive-applications/designing-data-intensive-applications.mini.md +55 -0
  50. package/templates/skills/designing-data-intensive-applications/designing-data-intensive-applications.nano.md +34 -0
  51. package/templates/skills/domain-driven-design/SKILL.md +11 -0
  52. package/templates/skills/domain-driven-design/domain-driven-design.md +979 -0
  53. package/templates/skills/domain-driven-design/domain-driven-design.mini.md +48 -0
  54. package/templates/skills/domain-driven-design/domain-driven-design.nano.md +39 -0
  55. package/templates/skills/domain-driven-design-distilled/SKILL.md +11 -0
  56. package/templates/skills/domain-driven-design-distilled/domain-driven-design-distilled.md +317 -0
  57. package/templates/skills/domain-driven-design-distilled/domain-driven-design-distilled.mini.md +56 -0
  58. package/templates/skills/domain-driven-design-distilled/domain-driven-design-distilled.nano.md +41 -0
  59. package/templates/skills/implementation-plan/SKILL.md +42 -0
  60. package/templates/skills/implementing-domain-driven-design/SKILL.md +11 -0
  61. package/templates/skills/implementing-domain-driven-design/implementing-domain-driven-design.md +337 -0
  62. package/templates/skills/implementing-domain-driven-design/implementing-domain-driven-design.mini.md +57 -0
  63. package/templates/skills/implementing-domain-driven-design/implementing-domain-driven-design.nano.md +37 -0
  64. package/templates/skills/patterns-of-enterprise-application-architecture/SKILL.md +11 -0
  65. package/templates/skills/patterns-of-enterprise-application-architecture/patterns-of-enterprise-application-architecture.md +404 -0
  66. package/templates/skills/patterns-of-enterprise-application-architecture/patterns-of-enterprise-application-architecture.mini.md +54 -0
  67. package/templates/skills/patterns-of-enterprise-application-architecture/patterns-of-enterprise-application-architecture.nano.md +35 -0
  68. package/templates/skills/ponytail/SKILL.md +124 -0
  69. package/templates/skills/ponytail-audit/SKILL.md +45 -0
  70. package/templates/skills/ponytail-debt/SKILL.md +48 -0
  71. package/templates/skills/ponytail-gain/SKILL.md +17 -0
  72. package/templates/skills/ponytail-help/SKILL.md +42 -0
  73. package/templates/skills/ponytail-review/SKILL.md +61 -0
  74. package/templates/skills/refactoring/SKILL.md +11 -0
  75. package/templates/skills/refactoring/refactoring.md +433 -0
  76. package/templates/skills/refactoring/refactoring.mini.md +49 -0
  77. package/templates/skills/refactoring/refactoring.nano.md +37 -0
  78. package/templates/skills/refactoring-guru/SKILL.md +11 -0
  79. package/templates/skills/refactoring-guru/refactoring-guru.md +765 -0
  80. package/templates/skills/refactoring-guru/refactoring-guru.mini.md +64 -0
  81. package/templates/skills/refactoring-guru/refactoring-guru.nano.md +41 -0
  82. package/templates/skills/release-it/SKILL.md +11 -0
  83. package/templates/skills/release-it/release-it.md +382 -0
  84. package/templates/skills/release-it/release-it.mini.md +48 -0
  85. package/templates/skills/release-it/release-it.nano.md +38 -0
  86. package/templates/skills/security-audit/AI-AND-LLM.md +83 -0
  87. package/templates/skills/security-audit/ATTACK-CLASSES.md +130 -0
  88. package/templates/skills/security-audit/CLIENT-SIDE.md +83 -0
  89. package/templates/skills/security-audit/CLOUD-AND-DEPLOYMENT.md +86 -0
  90. package/templates/skills/security-audit/DATA-ISOLATION-AND-LIFECYCLE.md +84 -0
  91. package/templates/skills/security-audit/DESKTOP-MOBILE-AND-LOCAL-IPC.md +89 -0
  92. package/templates/skills/security-audit/HUNTING.md +251 -0
  93. package/templates/skills/security-audit/MEMORY-SAFETY-AND-BINARY.md +101 -0
  94. package/templates/skills/security-audit/PROTOCOLS-RPC-AND-MESSAGING.md +81 -0
  95. package/templates/skills/security-audit/RECONNAISSANCE.md +156 -0
  96. package/templates/skills/security-audit/RESOURCE-EXHAUSTION-AND-AVAILABILITY.md +78 -0
  97. package/templates/skills/security-audit/SKILL.md +192 -0
  98. package/templates/skills/security-audit/SUPPLY-CHAIN-AND-RELEASE.md +73 -0
  99. package/templates/skills/security-audit/VALIDATION-AND-REPORTING.md +186 -0
  100. package/templates/skills/security-audit/WEB-PROTOCOL-AND-AUTH.md +105 -0
  101. package/templates/skills/security-audit/report-schema.json +461 -0
  102. package/templates/skills/security-audit/validate-coverage-ledger.cjs +872 -0
  103. package/templates/skills/security-audit/validate-coverage-ledger.test.cjs +740 -0
  104. package/templates/skills/security-audit/validate-findings.cjs +773 -0
  105. package/templates/skills/security-audit/validate-findings.test.cjs +652 -0
  106. package/templates/skills/spec/SKILL.md +55 -0
  107. package/templates/skills/the-pragmatic-programmer/SKILL.md +11 -0
  108. package/templates/skills/the-pragmatic-programmer/the-pragmatic-programmer.md +359 -0
  109. package/templates/skills/the-pragmatic-programmer/the-pragmatic-programmer.mini.md +65 -0
  110. package/templates/skills/the-pragmatic-programmer/the-pragmatic-programmer.nano.md +44 -0
  111. package/templates/skills/working-effectively-with-legacy-code/SKILL.md +11 -0
  112. package/templates/skills/working-effectively-with-legacy-code/working-effectively-with-legacy-code.md +371 -0
  113. package/templates/skills/working-effectively-with-legacy-code/working-effectively-with-legacy-code.mini.md +50 -0
  114. package/templates/skills/working-effectively-with-legacy-code/working-effectively-with-legacy-code.nano.md +35 -0
@@ -0,0 +1,236 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import os from 'node:os';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { execFileSync } from 'node:child_process';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
10
+ const TEMPLATES_DIR = path.join(PACKAGE_ROOT, 'templates');
11
+
12
+ /**
13
+ * Ensures directory exists
14
+ */
15
+ export function ensureDir(dirPath) {
16
+ try {
17
+ if (!fs.existsSync(dirPath)) {
18
+ fs.mkdirSync(dirPath, { recursive: true });
19
+ }
20
+ } catch (err) {
21
+ throw new Error(`Failed to create directory "${dirPath}": ${err.message}`, { cause: err });
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Recursively copies directory contents
27
+ */
28
+ export function copyDir(src, dest, overwrite = false) {
29
+ try {
30
+ ensureDir(dest);
31
+ const entries = fs.readdirSync(src, { withFileTypes: true });
32
+
33
+ for (const entry of entries) {
34
+ const srcPath = path.join(src, entry.name);
35
+ const destPath = path.join(dest, entry.name);
36
+
37
+ if (entry.isDirectory()) {
38
+ copyDir(srcPath, destPath, overwrite);
39
+ } else {
40
+ if (!fs.existsSync(destPath) || overwrite) {
41
+ fs.copyFileSync(srcPath, destPath);
42
+ }
43
+ }
44
+ }
45
+ } catch (err) {
46
+ throw new Error(`Failed to copy directory from "${src}" to "${dest}": ${err.message}`, { cause: err });
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Safely copies a single file
52
+ */
53
+ export function copyFile(src, dest, overwrite = false) {
54
+ try {
55
+ ensureDir(path.dirname(dest));
56
+ if (!fs.existsSync(dest) || overwrite) {
57
+ fs.copyFileSync(src, dest);
58
+ return true;
59
+ }
60
+ return false;
61
+ } catch (err) {
62
+ throw new Error(`Failed to copy file from "${src}" to "${dest}": ${err.message}`, { cause: err });
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Installs skills into target directory
68
+ * Destination will be: targetDir/.agents/skills/ (or targetDir directly if global)
69
+ */
70
+ export function installSkills(targetDir, isGlobal = false, overwrite = false) {
71
+ const srcSkillsDir = path.join(TEMPLATES_DIR, 'skills');
72
+ const destDir = isGlobal
73
+ ? path.join(os.homedir(), '.gemini', 'config', 'skills')
74
+ : path.join(targetDir, '.agents', 'skills');
75
+
76
+ copyDir(srcSkillsDir, destDir, overwrite);
77
+ if (!isGlobal) {
78
+ copyDir(path.join(TEMPLATES_DIR, 'docs'), path.join(targetDir, '.agents', 'templates', 'docs'), overwrite);
79
+ }
80
+ return destDir;
81
+ }
82
+
83
+ function templateFiles(source, destination) {
84
+ return fs.readdirSync(source, { withFileTypes: true }).flatMap((entry) => {
85
+ const src = path.join(source, entry.name);
86
+ const dest = path.join(destination, entry.name);
87
+ return entry.isDirectory() ? templateFiles(src, dest) : [{ src, dest }];
88
+ });
89
+ }
90
+
91
+ /** Prepare local instructions without replacing user files or approving work. */
92
+ export function startWorkspace(targetDir) {
93
+ const root = path.resolve(targetDir);
94
+ const git = (...args) => execFileSync('git', args, {
95
+ cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'],
96
+ env: { ...process.env, LC_ALL: 'C' },
97
+ }).trim();
98
+ try {
99
+ git('--version');
100
+ } catch (err) {
101
+ throw new Error('Git is unavailable. Install Git and ensure it is on PATH, then rerun start.', { cause: err });
102
+ }
103
+
104
+ let initialized = false;
105
+ try {
106
+ if (git('rev-parse', '--is-inside-work-tree') !== 'true') {
107
+ throw new Error('Run start in a working tree, not a bare repository or Git metadata directory.');
108
+ }
109
+ } catch (err) {
110
+ // Do not initialize over a broken or untrusted repository.
111
+ if (!String(err.stderr).includes('not a git repository')) throw err;
112
+ for (let directory = root; ; directory = path.dirname(directory)) {
113
+ if (fs.lstatSync(path.join(directory, '.git'), { throwIfNoEntry: false })) {
114
+ throw new Error(`Existing Git metadata at "${directory}" is not usable. Repair it before rerunning start.`, { cause: err });
115
+ }
116
+ if (directory === path.dirname(directory)) break;
117
+ }
118
+ git('init');
119
+ initialized = true;
120
+ }
121
+
122
+ const entries = [
123
+ ...['AGENTS.md', 'GEMINI.md'].map((file) => ({ src: path.join(TEMPLATES_DIR, 'rules', file), dest: path.join(root, file) })),
124
+ { src: path.join(TEMPLATES_DIR, 'rules', 'GEMINI.md'), dest: path.join(root, '.agents', 'rules', 'GEMINI.md') },
125
+ ...templateFiles(path.join(TEMPLATES_DIR, 'skills'), path.join(root, '.agents', 'skills')),
126
+ ...templateFiles(path.join(TEMPLATES_DIR, 'docs'), path.join(root, '.agents', 'templates', 'docs')),
127
+ { src: path.join(TEMPLATES_DIR, 'configs', '.editorconfig'), dest: path.join(root, '.editorconfig') },
128
+ { src: path.join(TEMPLATES_DIR, 'configs', 'sample.gitignore'), dest: path.join(root, '.gitignore') },
129
+ ];
130
+ // Refuse symlinks/junctions before copying anything, including links in parents.
131
+ for (const { dest } of entries) {
132
+ for (let current = dest; current !== root; current = path.dirname(current)) {
133
+ const stat = fs.lstatSync(current, { throwIfNoEntry: false });
134
+ if (stat?.isSymbolicLink() || (stat && (current === dest ? !stat.isFile() : !stat.isDirectory()))) {
135
+ throw new Error(`Cannot install through "${current}": expected an ordinary ${current === dest ? 'file' : 'directory'}. Review this path and rerun start.`);
136
+ }
137
+ }
138
+ }
139
+
140
+ const installed = [];
141
+ const differences = [];
142
+ for (const { src, dest } of entries) {
143
+ if (copyFile(src, dest)) installed.push(path.relative(root, dest));
144
+ else if (fs.readFileSync(src, 'utf8').replace(/\r\n/g, '\n') !== fs.readFileSync(dest, 'utf8').replace(/\r\n/g, '\n')) {
145
+ differences.push({ path: path.relative(root, dest), proposed: src });
146
+ }
147
+ }
148
+
149
+ const identityWarnings = [];
150
+ for (const identity of ['GIT_AUTHOR_IDENT', 'GIT_COMMITTER_IDENT']) {
151
+ try { git('var', identity); }
152
+ catch { identityWarnings.push(`${identity} is unavailable. Configure your Git name/email before phase commits.`); }
153
+ }
154
+ return {
155
+ initialized,
156
+ repository: git('rev-parse', '--show-toplevel'),
157
+ branch: git('branch', '--show-current') || '(detached HEAD)',
158
+ changes: git('status', '--short'),
159
+ installed, differences, identityWarnings,
160
+ documents: ['docs/SPEC_INDEX.md', 'HANDOFF.md', 'IMPLEMENTATION_PLAN.md'].map((file) => ({
161
+ path: file, exists: fs.statSync(path.join(root, file), { throwIfNoEntry: false })?.isFile() === true,
162
+ })),
163
+ };
164
+ }
165
+
166
+ /**
167
+ * Installs project agent rules (GEMINI.md, AGENTS.md, .cursorrules)
168
+ */
169
+ export function installRules(targetDir, overwrite = false) {
170
+ const srcRulesDir = path.join(TEMPLATES_DIR, 'rules');
171
+ const installed = [];
172
+
173
+ const files = ['GEMINI.md', 'AGENTS.md', '.cursorrules'];
174
+ for (const file of files) {
175
+ const src = path.join(srcRulesDir, file);
176
+ const dest = path.join(targetDir, file);
177
+ if (copyFile(src, dest, overwrite)) {
178
+ installed.push(file);
179
+ }
180
+ }
181
+
182
+ // Also copy GEMINI.md into .agents/rules/ if .agents directory exists
183
+ const agentsDir = path.join(targetDir, '.agents');
184
+ if (fs.existsSync(agentsDir)) {
185
+ const agentsRulesDir = path.join(agentsDir, 'rules');
186
+ ensureDir(agentsRulesDir);
187
+ copyFile(path.join(srcRulesDir, 'GEMINI.md'), path.join(agentsRulesDir, 'GEMINI.md'), overwrite);
188
+ }
189
+
190
+ return installed;
191
+ }
192
+
193
+ /**
194
+ * Installs standard dev configs (.editorconfig, .gitignore if not present)
195
+ */
196
+ export function installConfigs(targetDir, overwrite = false) {
197
+ const installed = [];
198
+ const srcConfigsDir = path.join(TEMPLATES_DIR, 'configs');
199
+
200
+ // .editorconfig
201
+ const editorConfigSrc = path.join(srcConfigsDir, '.editorconfig');
202
+ const editorConfigDest = path.join(targetDir, '.editorconfig');
203
+ if (copyFile(editorConfigSrc, editorConfigDest, overwrite)) {
204
+ installed.push('.editorconfig');
205
+ }
206
+
207
+ // .gitignore
208
+ const gitignoreSrc = path.join(srcConfigsDir, 'sample.gitignore');
209
+ const gitignoreDest = path.join(targetDir, '.gitignore');
210
+ if (copyFile(gitignoreSrc, gitignoreDest, overwrite)) {
211
+ installed.push('.gitignore');
212
+ }
213
+
214
+ return installed;
215
+ }
216
+
217
+ /**
218
+ * Generates a starter IMPLEMENTATION_PLAN.md in target directory
219
+ */
220
+ export function createPlanTemplate(targetDir, featureName = 'New Feature', overwrite = false) {
221
+ try {
222
+ const planPath = path.join(targetDir, 'IMPLEMENTATION_PLAN.md');
223
+ if (fs.existsSync(planPath) && !overwrite) {
224
+ return { created: false, path: planPath };
225
+ }
226
+
227
+ const timestamp = new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString().replace('Z', '+08:00');
228
+ const content = fs.readFileSync(path.join(TEMPLATES_DIR, 'docs', 'IMPLEMENTATION_PLAN.md'), 'utf8')
229
+ .replaceAll('{{TIMESTAMP}}', timestamp)
230
+ .replaceAll('{{FEATURE_NAME}}', () => featureName);
231
+ fs.writeFileSync(planPath, content, 'utf-8');
232
+ return { created: true, path: planPath };
233
+ } catch (err) {
234
+ throw new Error(`Failed to create plan template at "${targetDir}": ${err.message}`, { cause: err });
235
+ }
236
+ }
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 2
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+
11
+ [*.md]
12
+ trim_trailing_whitespace = false
@@ -0,0 +1,8 @@
1
+ node_modules/
2
+ dist/
3
+ build/
4
+ .env
5
+ .env.local
6
+ *.log
7
+ .DS_Store
8
+ Thumbs.db
@@ -0,0 +1,40 @@
1
+ # FEAT-[NNN]: [Feature name]
2
+
3
+ Created: [ISO 8601 timestamp +08:00]
4
+ Updated: [ISO 8601 timestamp +08:00]
5
+ Revision: 1
6
+ Status: Draft
7
+
8
+ ## Purpose and success
9
+
10
+ [Who needs it, why, and the observable outcome.]
11
+
12
+ ## Scope and non-goals
13
+
14
+ [What this version includes and excludes.]
15
+
16
+ ## User flows
17
+
18
+ [Main flow and relevant loading, empty, offline, error, denied-permission, and recovery states.]
19
+
20
+ ## Requirements and acceptance criteria
21
+
22
+ | ID | Required behavior | Observable pass/fail criterion |
23
+ | --- | --- | --- |
24
+ | REQ-001 | [Behavior] | [Specific scenario and expected result] |
25
+
26
+ ## Data and interfaces
27
+
28
+ [Link shared data definitions; add only feature-specific differences.]
29
+
30
+ ## Quality constraints
31
+
32
+ [Link shared constraints; define relevant measurable feature requirements.]
33
+
34
+ ## Decisions and assumptions
35
+
36
+ [Separate confirmed requirements, observed facts, proposed decisions, and assumptions.]
37
+
38
+ ## Open questions and readiness
39
+
40
+ [Blocking questions and actual chat approval of this revision when available.]
@@ -0,0 +1,39 @@
1
+ # Current handoff
2
+
3
+ Created: [ISO 8601 timestamp +08:00]
4
+ Updated: [ISO 8601 timestamp +08:00]
5
+ State: Awaiting approval
6
+ Feature: [ID]
7
+
8
+ ## Read first
9
+
10
+ [Relative links to project rules, index, approved baseline, architecture, feature, and plan.]
11
+ Reread these files and inspect actual Git status before acting; prior chat memory is not authoritative.
12
+
13
+ ## Approval and allowed work
14
+
15
+ | Document | Approved revision or commit | Actual Len chat approval reference |
16
+ | --- | --- | --- |
17
+
18
+ Allowed phases: None until approval is recorded.
19
+ Architecture and behavior changes return to Len; this handoff cannot override the linked specs.
20
+
21
+ ## Progress and working tree
22
+
23
+ [Current phase, completed and unfinished work, checkpoint messages or verified hashes, and unrelated edits to preserve.]
24
+ Reconcile this record with Git before resuming, especially after an interrupted commit.
25
+
26
+ ## Checks and evidence
27
+
28
+ [Actual checks run, results, environments, evidence links, and checks not run.]
29
+
30
+ ## Blockers and attempts
31
+
32
+ | Problem | Fix-and-check attempts used (maximum 3) | Changes tried and observed result | Required decision or access |
33
+ | --- | --- | --- | --- |
34
+
35
+ Do not reset a count on a new session or silently reinterpret a failed check as passing.
36
+
37
+ ## Next action
38
+
39
+ [One concrete next action within approved scope, or the decision needed to unblock it.]
@@ -0,0 +1,47 @@
1
+ # Implementation Plan: {{FEATURE_NAME}}
2
+
3
+ Created: {{TIMESTAMP}}
4
+ Updated: {{TIMESTAMP}}
5
+ Revision: 1
6
+ Status: Awaiting approval
7
+ Feature spec and revision: [Unresolved]
8
+ Approved baseline and architecture revisions: [Unresolved]
9
+ Len's chat approval: Not recorded
10
+ Target branch: [Verify in this repository]
11
+
12
+ ## Scope
13
+
14
+ [Link approved requirement IDs; identify existing edits to preserve.]
15
+ Resolve the fields and exact checks before presenting this plan for approval.
16
+ Use as many phases as the work needs; one phase is sufficient for a small feature.
17
+
18
+ ## Phase 1: [Testable outcome]
19
+
20
+ Requirements: [FEAT-NNN/REQ-NNN]
21
+ State: Awaiting approval
22
+
23
+ ### Tasks
24
+
25
+ - [ ] [Specific work within the approved architecture.]
26
+
27
+ ### Verification
28
+
29
+ - [ ] [Exact command or reproducible scenario, expected result, and environment.]
30
+ - [ ] [Evidence path containing actual results and limitations.]
31
+
32
+ ### Review and checkpoint
33
+
34
+ - [ ] Review correctness, scope, dependencies, and unrelated changes.
35
+ - [ ] Update plan, evidence, and current handoff.
36
+ - [ ] Stage only reviewed phase-related paths and verify the staged diff.
37
+ - [ ] Commit with a unique phase message and verify Git reports success.
38
+
39
+ Checkpoint message: [Choose a conventional commit message for this phase]
40
+ Phase completion requires all gates and a successful commit; the message identifies the checkpoint without needing its own hash inside the commit.
41
+ Continue automatically to the next approved phase.
42
+
43
+ ## Recovery
44
+
45
+ Follow project `AGENTS.md` for the three-attempt limit and immediate blockers.
46
+ Record unresolved work and attempt counts in the current handoff.
47
+ Interrupted or failing work remains uncommitted and the phase remains incomplete.
@@ -0,0 +1,12 @@
1
+ # Specification index
2
+
3
+ Created: [ISO 8601 timestamp +08:00]
4
+ Updated: [ISO 8601 timestamp +08:00]
5
+
6
+ | Category | ID | Current path | Revision | Status | Replaces |
7
+ | --- | --- | --- | --- | --- | --- |
8
+
9
+ Add only existing documents, using relative links.
10
+ Use `product/`, `features/`, `plans/`, `evidence/`, and `archive/` as needed.
11
+ Link the single root `HANDOFF.md` and identify the current implementation plan.
12
+ Update overlapping specs rather than creating dated duplicates.
@@ -0,0 +1,14 @@
1
+ # Verification: FEAT-[NNN]
2
+
3
+ Created: [ISO 8601 timestamp +08:00]
4
+ Updated: [ISO 8601 timestamp +08:00]
5
+
6
+ | Requirement / phase | Check or scenario | Environment and conditions | Actual result | When run | Evidence / limitations |
7
+ | --- | --- | --- | --- | --- | --- |
8
+
9
+ Use Not run, Passed under stated conditions, Failed, or Blocked.
10
+ Record actual commands or repeatable scenarios, not just conclusions.
11
+ Attach screenshots for meaningful UI checks when capture is available.
12
+ Keep emulator, physical-device, hardware-bench, and field validation distinct.
13
+ Len performs physical-device checks; keep them pending until Len supplies results.
14
+ Neither implementation nor a simulation establishes effectiveness in the intended environment.
@@ -0,0 +1,22 @@
1
+ # Architecture: [Name]
2
+
3
+ Created: [ISO 8601 timestamp +08:00]
4
+ Updated: [ISO 8601 timestamp +08:00]
5
+ Revision: 1
6
+ Status: Draft
7
+
8
+ ## Observed facts and assumptions
9
+
10
+ [Verified project reality versus unverified assumptions.]
11
+
12
+ ## Components, boundaries, and flows
13
+
14
+ [Responsibilities, data flow, trust boundaries, and external dependencies.]
15
+
16
+ ## Decisions and trade-offs
17
+
18
+ [Chosen architecture, alternatives considered, failure modes, and reasons.]
19
+
20
+ ## Open questions and approval
21
+
22
+ [Blocking decisions and actual Len approval reference when available.]
@@ -0,0 +1,22 @@
1
+ # Shared constraints: [Name]
2
+
3
+ Created: [ISO 8601 timestamp +08:00]
4
+ Updated: [ISO 8601 timestamp +08:00]
5
+ Revision: 1
6
+ Status: Draft
7
+
8
+ ## Platform and environment
9
+
10
+ [Supported platforms, connectivity, hardware, and deployment conditions.]
11
+
12
+ ## Quality and boundaries
13
+
14
+ [Relevant accessibility, security, privacy, reliability, and measurable performance requirements.]
15
+
16
+ ## Evidence required
17
+
18
+ [Required checks and their limits; separate emulator, physical device, hardware bench, and field validation.]
19
+
20
+ ## Open questions and approval
21
+
22
+ [Untested targets, blocking questions, and actual approval reference when available.]
@@ -0,0 +1,22 @@
1
+ # Shared data model: [Name]
2
+
3
+ Created: [ISO 8601 timestamp +08:00]
4
+ Updated: [ISO 8601 timestamp +08:00]
5
+ Revision: 1
6
+ Status: Draft
7
+
8
+ ## Entities and ownership
9
+
10
+ [Fields, types, relationships, source of truth, and lifecycle.]
11
+
12
+ ## Interfaces and validation
13
+
14
+ [Inputs, outputs, validation boundaries, permissions, and error behavior.]
15
+
16
+ ## Storage and recovery
17
+
18
+ [Relevant offline behavior, persistence, retention, migrations, and recovery.]
19
+
20
+ ## Open questions and approval
21
+
22
+ [Unresolved assumptions and actual approval reference when available.]
@@ -0,0 +1,22 @@
1
+ # Product overview: [Name]
2
+
3
+ Created: [ISO 8601 timestamp +08:00]
4
+ Updated: [ISO 8601 timestamp +08:00]
5
+ Revision: 1
6
+ Status: Draft
7
+
8
+ ## Purpose and users
9
+
10
+ [Problem, users, real scenarios, and observable success.]
11
+
12
+ ## Planned capabilities and main flows
13
+
14
+ [Inventory all planned features and their relationships before detailing individual features.]
15
+
16
+ ## Scope and non-goals
17
+
18
+ [Release boundaries and exclusions.]
19
+
20
+ ## Open questions and approval
21
+
22
+ [Blocking decisions, proposed defaults, and actual Len approval reference when available.]
@@ -0,0 +1,16 @@
1
+ # Workflow inspection exercises
2
+
3
+ This is a fictional documentation fixture, not a working Flutter app.
4
+ Use its [index](docs/SPEC_INDEX.md) to inspect the complete handoff chain.
5
+ The situations below are hypothetical inspection prompts, not evidence that an agent executed them.
6
+
7
+ | Situation | Expected decision |
8
+ | --- | --- |
9
+ | Tomorrow Len clarifies the note length requirement | Revise FEAT-001, its affected criteria and plan, and timestamps; do not create a new daily spec. |
10
+ | Len replaces local note creation with a different capability | Preserve the superseded spec in `docs/archive/`, link its replacement, update the index and incoming references, and obtain approval for new scope. |
11
+ | Gemini resumes with no earlier chat | Read the handoff and authorities, inspect Git, and stop because the example has no actual approval. |
12
+ | An approved phase was interrupted after edits but before tests | Reconcile the diff, preserve the edits, run remaining approved checks, and leave the phase incomplete until its commit succeeds. |
13
+ | The same failure survives three corrections and checks | Record all attempts, remaining edits, affected requirements, and needed decision; stop affected work. |
14
+ | Gemini prefers a new storage library | Report the preference, continue the approved design if feasible, and do not introduce the library. |
15
+ | The actual storage API cannot persist records | Report an architecture blocker immediately rather than fake persistence or silently change the design. |
16
+ | An emulator scenario passes | Record the emulator configuration and actual result; physical-device verification is still pending. |
@@ -0,0 +1,32 @@
1
+ # Current handoff: Pocket Notes example
2
+
3
+ Created: 2026-09-05T15:29:25+08:00
4
+ Updated: 2026-09-05T15:29:25+08:00
5
+ State: Awaiting approval
6
+ Feature: FEAT-001
7
+
8
+ ## Read first
9
+
10
+ In a real target repository, read its project-root AGENTS.md first.
11
+ Then read [the index](docs/SPEC_INDEX.md), its four product documents, [the feature](docs/features/FEAT-001-local-note.md), [the plan](docs/plans/FEAT-001-implementation.md), and [the evidence](docs/evidence/FEAT-001-verification.md).
12
+
13
+ ## Approval and scope
14
+
15
+ No real approval exists for this fictional example.
16
+ All baseline, architecture, feature, and plan documents are revision 1 drafts.
17
+ Allowed phases: None.
18
+ Do not implement or infer approval from this example.
19
+
20
+ ## Progress and checks
21
+
22
+ No Flutter code was written, no checks were run, and no phase commit exists.
23
+ Working-tree state must be inspected in the actual target repository rather than copied from this example.
24
+
25
+ ## Blockers and attempts
26
+
27
+ The real storage API, Android support, branch, and commands must be established before approval.
28
+ Fix-and-check attempts: 0; no implementation has begun.
29
+
30
+ ## Next action
31
+
32
+ GPT should inspect the real project, resolve those baseline questions with Len, and present the completed baseline, feature, and plan for chat approval.
@@ -0,0 +1,19 @@
1
+ # Pocket Notes example index
2
+
3
+ Created: 2026-09-05T15:29:25+08:00
4
+ Updated: 2026-09-05T15:29:25+08:00
5
+ Status: Fictional draft example, not approved for execution
6
+
7
+ | Category | Current document | Revision / status |
8
+ | --- | --- | --- |
9
+ | Product | [Overview](product/OVERVIEW.md) | 1 / Draft |
10
+ | Architecture | [Architecture](product/ARCHITECTURE.md) | 1 / Draft |
11
+ | Data | [Data model](product/DATA_MODEL.md) | 1 / Draft |
12
+ | Constraints | [Constraints](product/CONSTRAINTS.md) | 1 / Draft |
13
+ | Feature | [FEAT-001 local note creation](features/FEAT-001-local-note.md) | 1 / Draft |
14
+ | Plan | [FEAT-001 implementation](plans/FEAT-001-implementation.md) | 1 / Awaiting approval |
15
+ | Evidence | [FEAT-001 verification](evidence/FEAT-001-verification.md) | Not run |
16
+ | Handoff | [Current handoff](../HANDOFF.md) | Awaiting approval |
17
+
18
+ Refinements to local note creation belong in FEAT-001, not a new dated spec.
19
+ No archive exists because no document has been superseded.
@@ -0,0 +1,14 @@
1
+ # FEAT-001 verification example
2
+
3
+ Created: 2026-09-05T15:29:25+08:00
4
+ Updated: 2026-09-05T15:29:25+08:00
5
+
6
+ | Requirement | Check | Environment | Actual result | When run | Limitation |
7
+ | --- | --- | --- | --- | --- | --- |
8
+ | REQ-001 | Empty and oversized input | Not selected | Not run | Never | No Flutter implementation |
9
+ | REQ-002 | Repeated Save while pending | Not selected | Not run | Never | No implementation |
10
+ | REQ-003 | Controlled storage failure and retry | Not selected | Not run | Never | Storage API not inspected |
11
+ | REQ-004 | Save offline, restart, inspect list | Android emulator not selected | Not run | Never | No emulator session |
12
+ | All | Physical-device follow-up | Len's device | Not run | Never | Pending Len's actual results |
13
+
14
+ No passing result, screenshot, hardware result, or field result is asserted.
@@ -0,0 +1,40 @@
1
+ # FEAT-001: Create a local note
2
+
3
+ Created: 2026-09-05T15:29:25+08:00
4
+ Updated: 2026-09-05T15:29:25+08:00
5
+ Revision: 1
6
+ Status: Draft example
7
+
8
+ ## Purpose and success
9
+
10
+ Capture a short note offline and find it when reopening the app.
11
+
12
+ ## Scope and non-goals
13
+
14
+ Includes creation and newest-first listing.
15
+ Deletion, editing an existing note, search, and sharing are outside this feature.
16
+
17
+ ## User flow
18
+
19
+ The empty list invites the user to enter a note.
20
+ Save validates the text, indicates a pending write, and adds the saved result to the list only after success.
21
+ An error leaves the draft visible with a retry action.
22
+
23
+ ## Requirements
24
+
25
+ | ID | Behavior | Acceptance criterion |
26
+ | --- | --- | --- |
27
+ | REQ-001 | Validate text | Whitespace-only text and more than 200 Unicode scalar values show an error and create no record; valid trimmed text can be saved. |
28
+ | REQ-002 | Prevent duplicate writes | Repeated Save taps while the same write is pending create at most one note. |
29
+ | REQ-003 | Preserve failed drafts | A failed write leaves the entered text intact, shows an accessible error, and permits retry. |
30
+ | REQ-004 | Persist offline | With connectivity disabled, a successful save appears first in the list and is still present after restarting the app. |
31
+
32
+ ## Data and quality
33
+
34
+ Use the shared [data model](../product/DATA_MODEL.md), [architecture](../product/ARCHITECTURE.md), and [constraints](../product/CONSTRAINTS.md).
35
+
36
+ ## Decisions and readiness
37
+
38
+ The storage API and Android support remain unverified assumptions.
39
+ Resolve these before Len approves this feature and its [plan](../plans/FEAT-001-implementation.md).
40
+ No implementation tasks or test results are implied by this specification.