kracked-core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +146 -0
- package/bin/kracked-core.mjs +35 -0
- package/package.json +30 -0
- package/src/detect.mjs +106 -0
- package/src/scaffold.mjs +192 -0
- package/src/wizard.mjs +276 -0
- package/templates/global/identity.md +37 -0
- package/templates/global/lessons-archive.md +29 -0
- package/templates/global/lessons.md +23 -0
- package/templates/global/preferences.md +53 -0
- package/templates/global/projects.md +26 -0
- package/templates/loaders/AGENTS.md +67 -0
- package/templates/loaders/CLAUDE.md +5 -0
- package/templates/loaders/antigravity-rules.md +8 -0
- package/templates/project/decisions.md +34 -0
- package/templates/project/project.md +49 -0
- package/templates/project/sdd/specs/.gitkeep +0 -0
- package/templates/project/sdd/tracker.md +36 -0
- package/templates/project/session.md +23 -0
- package/templates/skills/kracked-boot/SKILL.md +53 -0
- package/templates/skills/kracked-explain/SKILL.md +69 -0
- package/templates/skills/kracked-sdd/SKILL.md +92 -0
- package/templates/skills/kracked-wrap/SKILL.md +60 -0
package/src/wizard.mjs
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
// Interactive prompt flow for `npx kracked-core init`.
|
|
2
|
+
// Follows the wizard flow in CONTRACT.md exactly — question order matters.
|
|
3
|
+
|
|
4
|
+
import readline from 'node:readline/promises';
|
|
5
|
+
import { stdin, stdout } from 'node:process';
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import os from 'node:os';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
globalMemoryExists,
|
|
12
|
+
globalMemoryDir,
|
|
13
|
+
classifyProjectDir,
|
|
14
|
+
scanExistingProject,
|
|
15
|
+
stackSummaryLine,
|
|
16
|
+
} from './detect.mjs';
|
|
17
|
+
import {
|
|
18
|
+
writeGlobalMemory,
|
|
19
|
+
registerProject,
|
|
20
|
+
writeProjectMemory,
|
|
21
|
+
writeLoaders,
|
|
22
|
+
writeSkills,
|
|
23
|
+
} from './scaffold.mjs';
|
|
24
|
+
|
|
25
|
+
/** Expand a leading ~ to the home directory. Leaves other paths untouched. */
|
|
26
|
+
function expandTilde(inputPath) {
|
|
27
|
+
if (!inputPath) return inputPath;
|
|
28
|
+
if (inputPath === '~') return os.homedir();
|
|
29
|
+
if (inputPath.startsWith('~/') || inputPath.startsWith('~\\')) {
|
|
30
|
+
return path.join(os.homedir(), inputPath.slice(2));
|
|
31
|
+
}
|
|
32
|
+
return inputPath;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Format today's date as YYYY-MM-DD. */
|
|
36
|
+
function isoDate() {
|
|
37
|
+
return new Date().toISOString().slice(0, 10);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Turn detected package.json scripts into a ready-to-read "how to run it" block.
|
|
42
|
+
* The scan already knows these commands — writing them into project.md is the
|
|
43
|
+
* difference between a drafted memory and an empty one full of TODOs.
|
|
44
|
+
*/
|
|
45
|
+
function runCommandsBlock(summary) {
|
|
46
|
+
const scripts = summary?.scripts ? Object.keys(summary.scripts) : [];
|
|
47
|
+
if (!scripts.length) return '- _(not set yet)_';
|
|
48
|
+
|
|
49
|
+
// Surface the commands people actually reach for first, then the rest.
|
|
50
|
+
const priority = ['dev', 'start', 'build', 'test', 'lint', 'typecheck'];
|
|
51
|
+
const ordered = [
|
|
52
|
+
...priority.filter((s) => scripts.includes(s)),
|
|
53
|
+
...scripts.filter((s) => !priority.includes(s)),
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
return ordered.map((s) => `- \`${s}\` — \`npm run ${s}\``).join('\n');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function runInit() {
|
|
60
|
+
// Non-interactive stdin (e.g. piped input, CI) can't drive a wizard —
|
|
61
|
+
// fail clearly instead of hanging on a prompt that will never resolve.
|
|
62
|
+
if (!stdin.isTTY) {
|
|
63
|
+
process.stderr.write(
|
|
64
|
+
'kracked-core init needs an interactive terminal to ask setup questions.\n' +
|
|
65
|
+
'Run it directly in a terminal (not piped or in a non-interactive script).\n'
|
|
66
|
+
);
|
|
67
|
+
process.exitCode = 1;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
72
|
+
|
|
73
|
+
let interrupted = false;
|
|
74
|
+
const onSigint = () => {
|
|
75
|
+
interrupted = true;
|
|
76
|
+
stdout.write('\n\nCancelled. Nothing after this point was written.\n');
|
|
77
|
+
rl.close();
|
|
78
|
+
process.exit(130);
|
|
79
|
+
};
|
|
80
|
+
process.on('SIGINT', onSigint);
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await wizardFlow(rl);
|
|
84
|
+
} catch (err) {
|
|
85
|
+
// Ctrl+D (EOF) mid-question surfaces as readline's AbortError. Treat it
|
|
86
|
+
// the same as Ctrl+C — a clean cancel, not a crash with a scary stack.
|
|
87
|
+
if (err.code === 'ABORT_ERR' || /ctrl\+d/i.test(err.message || '')) {
|
|
88
|
+
stdout.write('\n\nCancelled. Nothing after this point was written.\n');
|
|
89
|
+
process.exitCode = 130;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
throw err;
|
|
93
|
+
} finally {
|
|
94
|
+
process.off('SIGINT', onSigint);
|
|
95
|
+
if (!interrupted) rl.close();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Ask a question with a default; Enter alone accepts the default. */
|
|
100
|
+
async function ask(rl, question, defaultValue) {
|
|
101
|
+
const suffix = defaultValue ? ` [${defaultValue}]` : '';
|
|
102
|
+
const answer = (await rl.question(`${question}${suffix} `)).trim();
|
|
103
|
+
return answer === '' ? defaultValue : answer;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Ask a yes/no question. Returns boolean. Default shown as Y/n or y/N. */
|
|
107
|
+
async function askYesNo(rl, question, defaultYes) {
|
|
108
|
+
const suffix = defaultYes ? '[Y/n]' : '[y/N]';
|
|
109
|
+
const answer = (await rl.question(`${question} ${suffix} `)).trim().toLowerCase();
|
|
110
|
+
if (answer === '') return defaultYes;
|
|
111
|
+
return answer === 'y' || answer === 'yes';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Prompt for how to resolve a file-already-exists conflict. */
|
|
115
|
+
async function askConflict(rl, destPath) {
|
|
116
|
+
stdout.write(`\n Already exists: ${destPath}\n`);
|
|
117
|
+
const answer = (
|
|
118
|
+
await rl.question(' skip / overwrite / write alongside as .kracked-new? [skip] ')
|
|
119
|
+
).trim().toLowerCase();
|
|
120
|
+
|
|
121
|
+
if (answer === 'o' || answer === 'overwrite') return 'overwrite';
|
|
122
|
+
if (answer === 'a' || answer === 'alongside' || answer === 'write alongside') return 'alongside';
|
|
123
|
+
return 'skip';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function wizardFlow(rl) {
|
|
127
|
+
const created = [];
|
|
128
|
+
const reporter = (entry) => created.push(entry);
|
|
129
|
+
const conflictAsk = (destPath) => askConflict(rl, destPath);
|
|
130
|
+
|
|
131
|
+
stdout.write('kracked-core — set up memory for your AI coding agent\n\n');
|
|
132
|
+
|
|
133
|
+
// 1. Agent name
|
|
134
|
+
const agentName = (await ask(rl, 'What should we call your agent?', 'KC')) || 'KC';
|
|
135
|
+
|
|
136
|
+
// 2. User name
|
|
137
|
+
const systemUser = os.userInfo().username || 'you';
|
|
138
|
+
const userName = (await ask(rl, 'Your name?', systemUser)) || systemUser;
|
|
139
|
+
|
|
140
|
+
// 3. Global memory
|
|
141
|
+
const hasGlobal = globalMemoryExists();
|
|
142
|
+
let setUpGlobal;
|
|
143
|
+
if (!hasGlobal) {
|
|
144
|
+
setUpGlobal = await askYesNo(rl, 'Set up global memory now?', true);
|
|
145
|
+
} else {
|
|
146
|
+
const reuse = await askYesNo(rl, 'Global memory found. Reuse it?', true);
|
|
147
|
+
setUpGlobal = !reuse; // if not reusing, we still (re)write it below
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 4. Project setup
|
|
151
|
+
const setUpProject = await askYesNo(rl, 'Set up this project?', true);
|
|
152
|
+
|
|
153
|
+
let projectDir = process.cwd();
|
|
154
|
+
let projectMode = null; // 'new' | 'existing'
|
|
155
|
+
let stackLine = 'unknown — not auto-detected';
|
|
156
|
+
let projectSummary = null;
|
|
157
|
+
|
|
158
|
+
if (setUpProject) {
|
|
159
|
+
const pathAnswer = await ask(rl, 'Project directory?', '.');
|
|
160
|
+
const expanded = expandTilde(pathAnswer);
|
|
161
|
+
projectDir = path.resolve(expanded === '' ? '.' : expanded);
|
|
162
|
+
|
|
163
|
+
const classification = classifyProjectDir(projectDir);
|
|
164
|
+
|
|
165
|
+
if (classification === 'existing') {
|
|
166
|
+
const modeAnswer = (
|
|
167
|
+
await ask(rl, 'New project or existing codebase? (new/existing)', 'existing')
|
|
168
|
+
).toLowerCase();
|
|
169
|
+
projectMode = modeAnswer.startsWith('n') ? 'new' : 'existing';
|
|
170
|
+
} else {
|
|
171
|
+
const modeAnswer = (
|
|
172
|
+
await ask(rl, 'New project or existing codebase? (new/existing)', 'new')
|
|
173
|
+
).toLowerCase();
|
|
174
|
+
projectMode = modeAnswer.startsWith('e') ? 'existing' : 'new';
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (projectMode === 'existing') {
|
|
178
|
+
if (!fs.existsSync(projectDir)) {
|
|
179
|
+
stdout.write(`\n ${projectDir} doesn't exist yet — nothing to scan. Treating as new.\n`);
|
|
180
|
+
projectMode = 'new';
|
|
181
|
+
} else {
|
|
182
|
+
projectSummary = scanExistingProject(projectDir);
|
|
183
|
+
stackLine = stackSummaryLine(projectSummary);
|
|
184
|
+
|
|
185
|
+
stdout.write('\n Scanned project:\n');
|
|
186
|
+
stdout.write(` Name: ${projectSummary.name}\n`);
|
|
187
|
+
stdout.write(` Stack: ${stackLine}\n`);
|
|
188
|
+
stdout.write(` Git: ${projectSummary.isGitRepo ? 'yes' : 'no'}\n`);
|
|
189
|
+
const scriptNames = Object.keys(projectSummary.scripts);
|
|
190
|
+
if (scriptNames.length) {
|
|
191
|
+
stdout.write(` Scripts: ${scriptNames.join(', ')}\n`);
|
|
192
|
+
}
|
|
193
|
+
stdout.write('\n');
|
|
194
|
+
|
|
195
|
+
const confirmed = await askYesNo(rl, 'Does this look right?', true);
|
|
196
|
+
if (!confirmed) {
|
|
197
|
+
const manualStack = await ask(rl, 'Describe the stack yourself:', stackLine);
|
|
198
|
+
stackLine = manualStack;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Ensure the target directory exists before we try to write into it.
|
|
204
|
+
try {
|
|
205
|
+
fs.mkdirSync(projectDir, { recursive: true });
|
|
206
|
+
} catch (err) {
|
|
207
|
+
throw new Error(`Can't create or write to ${projectDir}: ${err.message}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// 5. Editors
|
|
212
|
+
const editorAnswer = (
|
|
213
|
+
await ask(rl, 'Which editor(s) do you use? (antigravity/claude/both/other)', 'both')
|
|
214
|
+
).toLowerCase();
|
|
215
|
+
|
|
216
|
+
let editors;
|
|
217
|
+
if (editorAnswer.startsWith('both')) {
|
|
218
|
+
editors = ['antigravity', 'claude'];
|
|
219
|
+
} else if (editorAnswer.startsWith('a')) {
|
|
220
|
+
editors = ['antigravity'];
|
|
221
|
+
} else if (editorAnswer.startsWith('c')) {
|
|
222
|
+
editors = ['claude'];
|
|
223
|
+
} else {
|
|
224
|
+
// "other" or anything unrecognized — still write both loader formats,
|
|
225
|
+
// since AGENTS.md/CLAUDE.md are cheap and cover most tools either way.
|
|
226
|
+
editors = ['antigravity', 'claude'];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 6. Write files
|
|
230
|
+
const projectName = projectSummary?.name || (setUpProject ? path.basename(projectDir) : 'unnamed-project');
|
|
231
|
+
|
|
232
|
+
const tokens = {
|
|
233
|
+
AGENT_NAME: agentName,
|
|
234
|
+
USER_NAME: userName,
|
|
235
|
+
PROJECT_NAME: projectName,
|
|
236
|
+
PROJECT_PATH: projectDir,
|
|
237
|
+
DATE: isoDate(),
|
|
238
|
+
STACK: stackLine,
|
|
239
|
+
RUN_COMMANDS: runCommandsBlock(projectSummary),
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
stdout.write('\nWriting files...\n');
|
|
243
|
+
|
|
244
|
+
if (setUpGlobal) {
|
|
245
|
+
await writeGlobalMemory({ tokens, ask: conflictAsk, report: reporter });
|
|
246
|
+
}
|
|
247
|
+
// Registering the project in the global registry is independent of whether
|
|
248
|
+
// global memory was just (re)written — it should happen whenever global
|
|
249
|
+
// memory exists at all, so kracked knows about every project touched.
|
|
250
|
+
if (setUpProject && (hasGlobal || setUpGlobal)) {
|
|
251
|
+
registerProject({ tokens });
|
|
252
|
+
created.push({ path: path.join(globalMemoryDir(), 'projects.md'), action: 'updated (registry)' });
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (setUpProject) {
|
|
256
|
+
await writeProjectMemory({ projectDir, tokens, ask: conflictAsk, report: reporter });
|
|
257
|
+
await writeLoaders({ projectDir, tokens, ask: conflictAsk, report: reporter });
|
|
258
|
+
await writeSkills({ projectDir, tokens, editors, ask: conflictAsk, report: reporter });
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
printSummary(created, agentName, setUpProject);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function printSummary(created, agentName, setUpProject) {
|
|
265
|
+
stdout.write('\nDone. Files:\n');
|
|
266
|
+
for (const entry of created) {
|
|
267
|
+
stdout.write(` ${entry.action.padEnd(32)} ${entry.path}\n`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
stdout.write('\nNext step:\n');
|
|
271
|
+
if (setUpProject) {
|
|
272
|
+
stdout.write(` Open this project in your editor and run /kracked-boot to load ${agentName}'s memory.\n`);
|
|
273
|
+
} else {
|
|
274
|
+
stdout.write(' Run kracked-core init again inside a project directory to wire it up.\n');
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Identity — {{AGENT_NAME}}
|
|
2
|
+
|
|
3
|
+
You are **{{AGENT_NAME}}**, {{USER_NAME}}'s coding agent. This file is your identity — it survives
|
|
4
|
+
every project and every session restart. Load it first, every boot.
|
|
5
|
+
|
|
6
|
+
## Role
|
|
7
|
+
|
|
8
|
+
You write code, explain tradeoffs, and help {{USER_NAME}} ship. You are not a search engine and not
|
|
9
|
+
a yes-machine — you have an opinion, and you say so when something looks wrong.
|
|
10
|
+
|
|
11
|
+
## How I work
|
|
12
|
+
|
|
13
|
+
- **Direct.** Answer the question first, then explain if needed. No preamble, no throat-clearing.
|
|
14
|
+
- **Honest.** If something won't work, say so before writing the code, not after it fails.
|
|
15
|
+
- **Admit uncertainty.** "I don't know" or "I'm not sure, here's my best guess" beats a confident wrong answer.
|
|
16
|
+
- **No flattery.** Don't praise the user's ideas to be agreeable. Evaluate them on merit.
|
|
17
|
+
- **Show, don't just tell.** Prefer a working example over a paragraph describing one.
|
|
18
|
+
- **Ask when blocked.** If a decision needs information only {{USER_NAME}} has, ask — don't guess and
|
|
19
|
+
move on silently.
|
|
20
|
+
|
|
21
|
+
## Communication style
|
|
22
|
+
|
|
23
|
+
- Plain language over jargon. Explain jargon the first time it's used.
|
|
24
|
+
- Short answers for short questions. Depth when the problem needs it, not by default.
|
|
25
|
+
- No filler enthusiasm ("Great question!", "Absolutely!"). State what's true and move on.
|
|
26
|
+
|
|
27
|
+
## Boundaries
|
|
28
|
+
|
|
29
|
+
- This file is global — it does not contain anything about a specific project. Project-specific
|
|
30
|
+
conventions live in that project's `project.md`, not here.
|
|
31
|
+
- Don't rename yourself or adopt a different persona mid-session. You are {{AGENT_NAME}}.
|
|
32
|
+
|
|
33
|
+
## See also
|
|
34
|
+
|
|
35
|
+
- `preferences.md` — how {{USER_NAME}} likes to work (fill in over time)
|
|
36
|
+
- `lessons.md` — patterns learned across projects
|
|
37
|
+
- `projects.md` — what {{USER_NAME}} is currently building
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Lessons — Archive
|
|
2
|
+
|
|
3
|
+
Full detail for every lesson in `lessons.md`. This file is **not** read at boot — it's opened on
|
|
4
|
+
demand, when a lesson looks relevant to the problem at hand, or when {{USER_NAME}} asks to see the
|
|
5
|
+
detail behind an index line. Keeping it out of the boot payload is what lets the lessons list grow
|
|
6
|
+
indefinitely without slowing every session down.
|
|
7
|
+
|
|
8
|
+
## Entry format
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
## [YYYY-MM-DD] <project> — <short title>
|
|
12
|
+
|
|
13
|
+
**What happened:** <the situation that produced the lesson>
|
|
14
|
+
**Why it matters:** <the cost of getting it wrong>
|
|
15
|
+
**Going forward:** <the concrete rule to follow next time>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Entries
|
|
19
|
+
|
|
20
|
+
## [2026-01-15] todo-app — Destructive migration ran without a backup
|
|
21
|
+
|
|
22
|
+
**What happened:** Asked to drop an unused column, {{AGENT_NAME}} generated and ran the migration
|
|
23
|
+
immediately. The column turned out to still be read by a reporting script that wasn't in the repo
|
|
24
|
+
{{AGENT_NAME}} could see, and the data was gone.
|
|
25
|
+
**Why it matters:** Destructive schema changes are not reversible once applied, even if the code
|
|
26
|
+
change itself was correct.
|
|
27
|
+
**Going forward:** Before any migration that drops or alters a column/table, state what will be
|
|
28
|
+
lost and ask for explicit confirmation first. Never batch a destructive migration with unrelated
|
|
29
|
+
changes.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Lessons — Index
|
|
2
|
+
|
|
3
|
+
This is the INDEX of everything {{AGENT_NAME}} has learned across all your projects. It is read
|
|
4
|
+
**every boot**, so it must stay flat — one line per lesson, no exceptions.
|
|
5
|
+
|
|
6
|
+
The full story behind each lesson (what happened, why it matters, how to avoid it) lives in
|
|
7
|
+
`lessons-archive.md`. That file is opened **on demand only** — when a lesson looks relevant to
|
|
8
|
+
the current problem, or when {{USER_NAME}} asks for the detail. Loading it every boot would make
|
|
9
|
+
the boot payload grow forever, so it doesn't happen automatically.
|
|
10
|
+
|
|
11
|
+
**Rule:** new lesson → full entry appended to `lessons-archive.md` + exactly ONE line added here.
|
|
12
|
+
Never paste full entries into this index.
|
|
13
|
+
|
|
14
|
+
## Format
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
- [YYYY-MM-DD] <project> — <one-line summary of the lesson>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Index
|
|
21
|
+
|
|
22
|
+
- [2026-01-15] todo-app — Don't run destructive DB migrations without a backup step first; ask before dropping columns.
|
|
23
|
+
- [2026-02-03] my-blog — Check for an existing util before writing a new date-formatting helper; duplicated logic drifted twice.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Preferences — {{USER_NAME}}
|
|
2
|
+
|
|
3
|
+
How {{USER_NAME}} likes to work, across every project. This file ships mostly empty — fill it in as
|
|
4
|
+
you learn, or edit it directly yourself. {{AGENT_NAME}} reads this every boot, so keep it short and
|
|
5
|
+
concrete: rules, not essays.
|
|
6
|
+
|
|
7
|
+
## Communication style
|
|
8
|
+
|
|
9
|
+
<!--
|
|
10
|
+
Example:
|
|
11
|
+
- Keep explanations to 2-3 sentences unless I ask for more.
|
|
12
|
+
- Show me the diff before you explain it, not after.
|
|
13
|
+
-->
|
|
14
|
+
|
|
15
|
+
- _(not set yet — add a few bullets, or let {{AGENT_NAME}} propose some after a few sessions)_
|
|
16
|
+
|
|
17
|
+
## Code style
|
|
18
|
+
|
|
19
|
+
<!--
|
|
20
|
+
Example:
|
|
21
|
+
- Prefer early returns over nested if/else.
|
|
22
|
+
- No comments that just restate the code. Comment the "why", not the "what".
|
|
23
|
+
- Match the file's existing quote style / indentation instead of your default.
|
|
24
|
+
-->
|
|
25
|
+
|
|
26
|
+
- _(not set yet)_
|
|
27
|
+
|
|
28
|
+
## Always do
|
|
29
|
+
|
|
30
|
+
<!--
|
|
31
|
+
Example:
|
|
32
|
+
- Run the linter before saying a change is done.
|
|
33
|
+
- Write a migration for any schema change.
|
|
34
|
+
-->
|
|
35
|
+
|
|
36
|
+
- _(not set yet)_
|
|
37
|
+
|
|
38
|
+
## Never do
|
|
39
|
+
|
|
40
|
+
<!--
|
|
41
|
+
Example:
|
|
42
|
+
- Never commit without asking first.
|
|
43
|
+
- Never install a new dependency without flagging it.
|
|
44
|
+
- Never touch files outside the current task's scope.
|
|
45
|
+
-->
|
|
46
|
+
|
|
47
|
+
- _(not set yet)_
|
|
48
|
+
|
|
49
|
+
## How to fill this in
|
|
50
|
+
|
|
51
|
+
At the end of a session (`/kracked-wrap`), if {{AGENT_NAME}} notices a recurring preference, it
|
|
52
|
+
should propose adding a line here. {{USER_NAME}} can also edit this file directly at any time —
|
|
53
|
+
it's just a text file.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Projects
|
|
2
|
+
|
|
3
|
+
Registry of every project {{USER_NAME}} is working on. Each row points to the project's own
|
|
4
|
+
`.kracked/` folder, where the real detail (stack, conventions, session state) lives. This file
|
|
5
|
+
only tracks what exists and where — never project-specific truth.
|
|
6
|
+
|
|
7
|
+
## Format
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
| Project | Path | Stack | Status |
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- **Status** is one of: `active`, `paused`, `done`.
|
|
14
|
+
|
|
15
|
+
## Registry
|
|
16
|
+
|
|
17
|
+
| Project | Path | Stack | Status |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| todo-app | ~/code/todo-app | Next.js, Postgres | active |
|
|
20
|
+
| my-blog | ~/code/my-blog | Astro, Markdown | paused |
|
|
21
|
+
|
|
22
|
+
## How this fills in
|
|
23
|
+
|
|
24
|
+
When `/kracked-boot` or the setup wizard runs in a new project, add a row here pointing at its
|
|
25
|
+
path. Don't copy that project's stack details or conventions here beyond the one-line summary —
|
|
26
|
+
that belongs in the project's own `project.md`.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# AGENTS.md — {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
This is the canonical loader. Every harness (Antigravity, Claude Code, others) reads this file
|
|
4
|
+
first. If a harness has its own shim (`CLAUDE.md`, `.agents/rules/kracked.md`), that shim points
|
|
5
|
+
back here — the instructions live in exactly one place, here, so they can't drift apart.
|
|
6
|
+
|
|
7
|
+
## Who you are
|
|
8
|
+
|
|
9
|
+
You are **{{AGENT_NAME}}**. Your identity, communication style, and how you work are defined in
|
|
10
|
+
global memory at `~/.kracked/identity.md`. Read it — don't assume a different persona.
|
|
11
|
+
|
|
12
|
+
## Boot sequence (run this at the start of every session)
|
|
13
|
+
|
|
14
|
+
Read these files, in this exact order, before doing any work:
|
|
15
|
+
|
|
16
|
+
1. `~/.kracked/identity.md` — who you are
|
|
17
|
+
2. `~/.kracked/preferences.md` — how {{USER_NAME}} likes to work, across all projects
|
|
18
|
+
3. `~/.kracked/lessons.md` — the lessons INDEX only (one line per lesson)
|
|
19
|
+
4. `~/.kracked/projects.md` — what else {{USER_NAME}} is building
|
|
20
|
+
5. `.kracked/project.md` — what THIS project is (stack, conventions, structure)
|
|
21
|
+
6. `.kracked/session.md` — working memory: current state, next step, blockers
|
|
22
|
+
7. `.kracked/decisions.md` — this project's decision log
|
|
23
|
+
8. `.kracked/sdd/tracker.md` — story status ledger, if this project uses SDD
|
|
24
|
+
|
|
25
|
+
**Important: do NOT read `~/.kracked/lessons-archive.md` at boot.** It holds the full detail
|
|
26
|
+
behind each line in `lessons.md` and is opened on demand only — when a lesson looks relevant to
|
|
27
|
+
the current problem, or {{USER_NAME}} asks for it. Reading it every boot would make the boot
|
|
28
|
+
payload grow without bound as more lessons accumulate; the index/archive split exists specifically
|
|
29
|
+
to prevent that.
|
|
30
|
+
|
|
31
|
+
After reading, orient in one line before starting work: state the project, the last known state
|
|
32
|
+
from `session.md`, and the next step. Example: "{{PROJECT_NAME}}: last session left off building
|
|
33
|
+
the signup flow, next step is wiring the email step. Ready."
|
|
34
|
+
|
|
35
|
+
## Boundary rule
|
|
36
|
+
|
|
37
|
+
- **Global memory** (`~/.kracked/`) — identity, cross-project preferences, cross-project lessons,
|
|
38
|
+
the project registry. Nothing about a specific codebase belongs here.
|
|
39
|
+
- **Project memory** (`.kracked/`) — this codebase's stack, conventions, session state, decisions,
|
|
40
|
+
and SDD tracker. Nothing here should be copied up into global memory.
|
|
41
|
+
- Putting project-specific detail into global memory poisons every other project that shares it.
|
|
42
|
+
If you're unsure which layer something belongs in, ask: "would this make sense in a totally
|
|
43
|
+
different project?" If no, it's project memory.
|
|
44
|
+
|
|
45
|
+
## Available commands
|
|
46
|
+
|
|
47
|
+
| Command | Does |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `/kracked-boot` | Runs the boot sequence above and orients in one line |
|
|
50
|
+
| `/kracked-sdd` | Runs the SDD flow: idea → spec → docs → build → review |
|
|
51
|
+
| `/kracked-wrap` | Writes lessons + updates session state, closes the session cleanly |
|
|
52
|
+
| `/kracked-explain` | Walks {{USER_NAME}} through what kracked-core installed and why |
|
|
53
|
+
|
|
54
|
+
## Writing memory (wrap)
|
|
55
|
+
|
|
56
|
+
When a session ends (`/kracked-wrap`), update `.kracked/session.md` with the new "Last Active"
|
|
57
|
+
state and next step. If something non-obvious was learned that would help a future session avoid
|
|
58
|
+
the same mistake, append a full entry to `~/.kracked/lessons-archive.md` and add exactly ONE line
|
|
59
|
+
to `~/.kracked/lessons.md`. Never paste a full lesson entry into the index — that's the mistake
|
|
60
|
+
this split exists to prevent.
|
|
61
|
+
|
|
62
|
+
## Terminology
|
|
63
|
+
|
|
64
|
+
Use these words, consistently: **global memory**, **project memory**, **boot**, **wrap**, **SDD**,
|
|
65
|
+
**tracker**. Don't call this system "the core," "the brain," "context files," or "rules" — those
|
|
66
|
+
terms don't appear anywhere else in this project's docs, and mixing terminology makes the memory
|
|
67
|
+
model harder to reason about over time.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
@AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file is a shim. The canonical instructions live in `AGENTS.md` — duplicating them here would
|
|
4
|
+
let the two drift apart, which is the exact bug kracked-core exists to prevent. If you need to
|
|
5
|
+
change how the agent boots or behaves, edit `AGENTS.md`, not this file.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Antigravity — {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
This file is a pointer, not the source of truth. The full instructions — who the agent is, the
|
|
4
|
+
boot sequence, the boundary rule, and available commands — live in `AGENTS.md` at the project
|
|
5
|
+
root. Read `AGENTS.md` and follow the boot sequence defined there before doing any work.
|
|
6
|
+
|
|
7
|
+
Do not duplicate `AGENTS.md`'s content here. If these instructions ever disagree, `AGENTS.md`
|
|
8
|
+
wins — update it there, not in this file.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Decisions — {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
A log of decisions made on this project, with the reasoning behind them. The point of this file
|
|
4
|
+
is the **why**, not the what — the code already shows what was decided; this file is for the
|
|
5
|
+
reasoning a future session couldn't re-derive just by reading the code.
|
|
6
|
+
|
|
7
|
+
Not every choice belongs here. Skip anything obvious or easily reversible. Log it when getting
|
|
8
|
+
it wrong would mean redoing real work, or when a future session (human or agent) might look at
|
|
9
|
+
the code and reasonably ask "why was it done this way?"
|
|
10
|
+
|
|
11
|
+
## Format
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
## [YYYY-MM-DD] <short title>
|
|
15
|
+
|
|
16
|
+
**Decision:** <what was decided>
|
|
17
|
+
**Rationale:** <why, including what alternatives were considered and rejected>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Log
|
|
21
|
+
|
|
22
|
+
<!--
|
|
23
|
+
Example:
|
|
24
|
+
|
|
25
|
+
## [2026-01-10] Use Postgres instead of SQLite
|
|
26
|
+
|
|
27
|
+
**Decision:** Store data in Postgres from day one, even though SQLite would be simpler for a
|
|
28
|
+
solo project this size.
|
|
29
|
+
**Rationale:** Planning to add a second concurrent writer (a background job) within a few weeks.
|
|
30
|
+
SQLite's single-writer lock would force a migration later anyway, and doing it now while the
|
|
31
|
+
schema is small is cheaper than doing it after there's real data.
|
|
32
|
+
-->
|
|
33
|
+
|
|
34
|
+
_(empty — add an entry the first time a non-obvious decision gets made)_
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Project — {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
What this project IS. This file is project memory — it never leaves `{{PROJECT_PATH}}`, and it
|
|
4
|
+
never gets copied into global memory. If a fact only makes sense inside this codebase, it lives
|
|
5
|
+
here.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
- **Name:** {{PROJECT_NAME}}
|
|
10
|
+
- **Path:** {{PROJECT_PATH}}
|
|
11
|
+
- **Stack:** {{STACK}}
|
|
12
|
+
- **Created:** {{DATE}}
|
|
13
|
+
|
|
14
|
+
_(Add a sentence or two here on what this project actually does, once there's something to say.)_
|
|
15
|
+
|
|
16
|
+
## Conventions
|
|
17
|
+
|
|
18
|
+
<!--
|
|
19
|
+
Example:
|
|
20
|
+
- Components live in src/components, one file per component, PascalCase.
|
|
21
|
+
- API routes return { data, error } shape, never throw to the client.
|
|
22
|
+
- Tests sit next to the file they test as *.test.ts.
|
|
23
|
+
-->
|
|
24
|
+
|
|
25
|
+
- _(not set yet)_
|
|
26
|
+
|
|
27
|
+
## Structure
|
|
28
|
+
|
|
29
|
+
<!--
|
|
30
|
+
Example:
|
|
31
|
+
- src/app — routes
|
|
32
|
+
- src/lib — shared logic
|
|
33
|
+
- src/components — UI
|
|
34
|
+
-->
|
|
35
|
+
|
|
36
|
+
- _(not set yet)_
|
|
37
|
+
|
|
38
|
+
## How to run it
|
|
39
|
+
|
|
40
|
+
<!--
|
|
41
|
+
Detected at install time from this project's scripts. Correct anything that's wrong —
|
|
42
|
+
editing this file directly is faster than explaining it to the agent every session.
|
|
43
|
+
-->
|
|
44
|
+
|
|
45
|
+
{{RUN_COMMANDS}}
|
|
46
|
+
|
|
47
|
+
## How to test it
|
|
48
|
+
|
|
49
|
+
- _(not set yet)_
|
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Tracker — {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
The story status ledger for this project's SDD flow (idea → spec → docs → build → review).
|
|
4
|
+
Every story tracked here goes through the same four statuses, and status changes are never
|
|
5
|
+
batched up and applied later — the moment a story's state actually changes, this table changes
|
|
6
|
+
with it.
|
|
7
|
+
|
|
8
|
+
## Statuses
|
|
9
|
+
|
|
10
|
+
- `backlog` — written down, not started
|
|
11
|
+
- `in-progress` — actively being built
|
|
12
|
+
- `review` — built, being checked against the spec
|
|
13
|
+
- `done` — reviewed and confirmed working
|
|
14
|
+
|
|
15
|
+
## Rule: evidence before `done`
|
|
16
|
+
|
|
17
|
+
A story **cannot** be marked `done` without an `Evidence` entry stating how it was confirmed
|
|
18
|
+
(e.g. "manual test: signup flow works end-to-end", "3 unit tests passing", "verified in prod").
|
|
19
|
+
No evidence, no `done` — it stays in `review` until there's something concrete to point at.
|
|
20
|
+
|
|
21
|
+
## Spec
|
|
22
|
+
|
|
23
|
+
_(no spec yet — run `/kracked-sdd` to create one)_
|
|
24
|
+
|
|
25
|
+
## Stories
|
|
26
|
+
|
|
27
|
+
| ID | Story | Status | Evidence |
|
|
28
|
+
|---|---|---|---|
|
|
29
|
+
| 1.1 | _(example)_ User can sign up with email | backlog | — |
|
|
30
|
+
|
|
31
|
+
<!--
|
|
32
|
+
ID format is <epic>.<story> — 1.1, 1.2, then 2.1 when the next epic starts.
|
|
33
|
+
Add a row per story as specs are generated under sdd/specs/, and point the Spec heading above at
|
|
34
|
+
the spec file this batch of stories came from. Keep the Story column short — the detail lives in
|
|
35
|
+
the spec file. This is a ledger, not a spec.
|
|
36
|
+
-->
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Session — {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
Working memory for this project. This is the file that makes a session restart survivable —
|
|
4
|
+
{{AGENT_NAME}} reads it at boot and should be able to orient in one line without re-reading the
|
|
5
|
+
whole codebase.
|
|
6
|
+
|
|
7
|
+
## Last Active
|
|
8
|
+
|
|
9
|
+
- **Date:** {{DATE}}
|
|
10
|
+
- **State:** Project scaffolded, no work started yet.
|
|
11
|
+
- **Doing now:** _(what the current task is)_
|
|
12
|
+
- **Next step:** _(the very next action, specific enough to act on immediately)_
|
|
13
|
+
- **Blockers:** none
|
|
14
|
+
|
|
15
|
+
## Prior sessions
|
|
16
|
+
|
|
17
|
+
<!--
|
|
18
|
+
When you wrap a session, the current "Last Active" block moves down here (most recent first),
|
|
19
|
+
and a new "Last Active" block is written above it. Keep roughly the last 2-3 blocks — older
|
|
20
|
+
history that still matters belongs in decisions.md or the SDD tracker, not stacked up here.
|
|
21
|
+
-->
|
|
22
|
+
|
|
23
|
+
_(empty — this fills in as sessions wrap)_
|