claudenv 1.2.4 → 1.3.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/bin/cli.js CHANGED
@@ -10,9 +10,10 @@ import { generateDocs, writeDocs, installScaffold } from '../src/generator.js';
10
10
  import { validateClaudeMd, validateStructure, crossReferenceCheck } from '../src/validator.js';
11
11
  import { runExistingProjectFlow, runColdStartFlow, buildDefaultConfig } from '../src/prompts.js';
12
12
  import { installGlobal, uninstallGlobal } from '../src/installer.js';
13
- import { runLoop, rollback, checkClaudeCli } from '../src/loop.js';
13
+ import { runLoop, rollback, checkClaudeCli, readLoopLog } from '../src/loop.js';
14
14
  import { generateAutonomyConfig, printSecuritySummary, getFullModeWarning } from '../src/autonomy.js';
15
15
  import { getProfile, listProfiles } from '../src/profiles.js';
16
+ import { readReport, formatReport, formatEventLine, watchReport } from '../src/report.js';
16
17
 
17
18
  const __dirname = dirname(fileURLToPath(import.meta.url));
18
19
  const pkgJson = JSON.parse(await readFile(join(__dirname, '..', 'package.json'), 'utf-8'));
@@ -131,6 +132,7 @@ program
131
132
  .option('-d, --dir <path>', 'Target project directory')
132
133
  .option('--allow-dirty', 'Allow running with uncommitted git changes')
133
134
  .option('--rollback', 'Undo all changes from the most recent loop run')
135
+ .option('--resume', 'Resume from last rate-limited iteration')
134
136
  .option('--unsafe', 'Remove default tool restrictions (allows rm -rf)')
135
137
  .option('--worktree', 'Run each iteration in an isolated git worktree')
136
138
  .option('--profile <name>', 'Autonomy profile: safe, moderate, full, ci')
@@ -141,6 +143,36 @@ program
141
143
  return;
142
144
  }
143
145
 
146
+ // --- Resume mode ---
147
+ if (opts.resume) {
148
+ const resumeCwd = opts.dir ? resolve(opts.dir) : process.cwd();
149
+ const prevLog = await readLoopLog(resumeCwd);
150
+ if (!prevLog || !prevLog.pausedAt) {
151
+ console.error('\n No resumable loop found. Run a loop first or check .claude/loop-log.json.\n');
152
+ process.exit(1);
153
+ }
154
+ const saved = prevLog.options || {};
155
+ console.log(`\n Resuming loop from iteration ${prevLog.pausedAt.iteration}`);
156
+ console.log(` Goal: ${saved.goal || 'General improvement'}`);
157
+ console.log(` Session: ${prevLog.pausedAt.sessionId || 'new'}\n`);
158
+
159
+ await runLoop({
160
+ iterations: opts.iterations || Infinity,
161
+ trust: saved.trust || false,
162
+ goal: saved.goal,
163
+ pause: false,
164
+ maxTurns: saved.maxTurns || 30,
165
+ model: opts.model || saved.model,
166
+ budget: saved.budget,
167
+ cwd: resumeCwd,
168
+ allowDirty: true,
169
+ worktree: saved.worktree || false,
170
+ startIteration: prevLog.pausedAt.iteration,
171
+ initialSessionId: prevLog.pausedAt.sessionId,
172
+ });
173
+ return;
174
+ }
175
+
144
176
  // --- Pre-flight: check Claude CLI ---
145
177
  const cli = checkClaudeCli();
146
178
  if (!cli.installed) {
@@ -176,6 +208,7 @@ program
176
208
  disallowedTools: profile.disallowedTools,
177
209
  maxTurns: profile.maxTurns,
178
210
  budget: profile.maxBudget,
211
+ model: profile.model,
179
212
  };
180
213
  console.log(` Profile: ${profile.name} — ${profile.description}`);
181
214
  }
@@ -189,7 +222,8 @@ program
189
222
  if (opts.worktree) console.log(` Worktree: enabled (each iteration in isolated worktree)`);
190
223
  if (opts.iterations) console.log(` Max iterations: ${opts.iterations}`);
191
224
  if (opts.goal) console.log(` Goal: ${opts.goal}`);
192
- if (opts.model) console.log(` Model: ${opts.model}`);
225
+ const model = opts.model || profileDefaults.model || undefined;
226
+ if (model) console.log(` Model: ${model}`);
193
227
  if (opts.budget || profileDefaults.budget) console.log(` Budget: $${opts.budget || profileDefaults.budget}/iteration`);
194
228
  if (opts.maxTurns || profileDefaults.maxTurns) console.log(` Max turns: ${opts.maxTurns || profileDefaults.maxTurns}`);
195
229
 
@@ -199,7 +233,7 @@ program
199
233
  goal: opts.goal,
200
234
  pause,
201
235
  maxTurns: opts.maxTurns || profileDefaults.maxTurns || 30,
202
- model: opts.model,
236
+ model,
203
237
  budget: opts.budget || profileDefaults.budget,
204
238
  cwd,
205
239
  allowDirty: opts.allowDirty || false,
@@ -209,6 +243,40 @@ program
209
243
  });
210
244
  });
211
245
 
246
+ // --- report ---
247
+ program
248
+ .command('report')
249
+ .description('View work report from autonomous loop runs')
250
+ .option('-f, --follow', 'Live stream events (tail -f style)')
251
+ .option('--last <n>', 'Show last N events', parseInt)
252
+ .option('-d, --dir <path>', 'Project directory')
253
+ .action(async (opts) => {
254
+ const cwd = opts.dir ? resolve(opts.dir) : process.cwd();
255
+ const events = await readReport(cwd);
256
+
257
+ if (opts.follow) {
258
+ // Print existing events first
259
+ if (events.length > 0) {
260
+ const show = opts.last ? events.slice(-opts.last) : events;
261
+ process.stdout.write(formatReport(show));
262
+ }
263
+ console.log(' Watching for new events... (Ctrl+C to stop)\n');
264
+ await watchReport(cwd, (event) => {
265
+ process.stdout.write(formatEventLine(event));
266
+ });
267
+ return;
268
+ }
269
+
270
+ if (events.length === 0) {
271
+ console.log('\n No work report found. Run `claudenv loop` first.\n');
272
+ return;
273
+ }
274
+
275
+ const show = opts.last ? events.slice(-opts.last) : events;
276
+ console.log();
277
+ process.stdout.write(formatReport(show));
278
+ });
279
+
212
280
  // --- autonomy ---
213
281
  program
214
282
  .command('autonomy')
@@ -220,6 +288,198 @@ program
220
288
  .option('--dry-run', 'Preview without writing')
221
289
  .action(runAutonomy);
222
290
 
291
+ // --- hook (internal entry point for Claude Code hooks) ---
292
+ program
293
+ .command('hook')
294
+ .description('Internal: dispatch a Claude Code hook by name (decisions-logger, regen-index)')
295
+ .argument('<name>', 'Hook name')
296
+ .action(async (name) => {
297
+ const { dispatch } = await import('../src/hooks/dispatcher.js');
298
+ await dispatch(name);
299
+ });
300
+
301
+ // =============================================
302
+ // 1.3.0: memory / decisions / canon / doctor
303
+ // =============================================
304
+
305
+ // --- memory ---
306
+ const memoryCmd = program.command('memory').description('Manage the global ~/.claudenv/memories/ layout');
307
+
308
+ memoryCmd
309
+ .command('init')
310
+ .description('Create the ~/.claudenv/memories/ structure (idempotent)')
311
+ .action(async () => {
312
+ const { memoryInit } = await import('../src/memory.js');
313
+ const { created, skipped } = await memoryInit();
314
+ for (const p of created) console.log(` + ${p}`);
315
+ for (const p of skipped) console.log(` ~ ${p}`);
316
+ console.log(`\n ${created.length} created, ${skipped.length} already present.`);
317
+ });
318
+
319
+ memoryCmd
320
+ .command('index')
321
+ .description('Regenerate ~/.claudenv/memories/INDEX.md from current decisions and prefs')
322
+ .action(async () => {
323
+ const { memoryIndex } = await import('../src/memory.js');
324
+ const result = await memoryIndex();
325
+ console.log(` INDEX.md regenerated → ${result.indexPath}`);
326
+ console.log(` ${result.recentCount} recent of ${result.decisionCount} total decisions`);
327
+ });
328
+
329
+ memoryCmd
330
+ .command('show')
331
+ .argument('<path>', 'Path relative to ~/.claudenv/memories/')
332
+ .description('Print a memory file to stdout')
333
+ .action(async (path) => {
334
+ const { memoryShow } = await import('../src/memory.js');
335
+ try {
336
+ process.stdout.write(await memoryShow(path));
337
+ } catch (err) {
338
+ console.error(err.message);
339
+ process.exit(2);
340
+ }
341
+ });
342
+
343
+ memoryCmd
344
+ .command('edit')
345
+ .argument('<path>', 'Path relative to ~/.claudenv/memories/')
346
+ .description('Open a memory file in $EDITOR (vi by default)')
347
+ .action(async (path) => {
348
+ const { memoryEdit } = await import('../src/memory.js');
349
+ const result = await memoryEdit(path);
350
+ process.exit(result.exitCode);
351
+ });
352
+
353
+ // --- decisions ---
354
+ const decisionsCmd = program.command('decisions').description('List, show, or search logged vibe-decisions');
355
+
356
+ decisionsCmd
357
+ .command('list')
358
+ .description('List recent decisions (newest first)')
359
+ .option('--scope <s>', 'global | project | all', 'all')
360
+ .option('--limit <n>', 'Max entries', '10')
361
+ .action(async (opts) => {
362
+ const { listDecisions, formatDecisionList } = await import('../src/decisions.js');
363
+ const limit = parseInt(opts.limit, 10) || 10;
364
+ const all = await listDecisions({ scope: opts.scope });
365
+ console.log(formatDecisionList(all.slice(0, limit)));
366
+ });
367
+
368
+ decisionsCmd
369
+ .command('show')
370
+ .argument('<id>', 'Slug or substring of the decision')
371
+ .description('Show full details of one decision')
372
+ .action(async (id) => {
373
+ const { showDecision, formatDecisionDetail } = await import('../src/decisions.js');
374
+ try {
375
+ const d = await showDecision(id);
376
+ console.log(formatDecisionDetail(d));
377
+ console.log('\n---\n');
378
+ console.log(d.text);
379
+ } catch (err) {
380
+ console.error(err.message);
381
+ process.exit(err.notFound ? 1 : 2);
382
+ }
383
+ });
384
+
385
+ decisionsCmd
386
+ .command('search')
387
+ .argument('<query>', 'Substring to search topic/reason/chose')
388
+ .description('Search decisions')
389
+ .action(async (query) => {
390
+ const { searchDecisions, formatDecisionList } = await import('../src/decisions.js');
391
+ const hits = await searchDecisions(query);
392
+ console.log(formatDecisionList(hits));
393
+ });
394
+
395
+ decisionsCmd
396
+ .command('archive')
397
+ .argument('<id>', 'Slug to archive')
398
+ .description('Move a decision into <scope-dir>/archive/')
399
+ .action(async (id) => {
400
+ const { archiveDecision } = await import('../src/decisions.js');
401
+ try {
402
+ const { from, to } = await archiveDecision(id);
403
+ console.log(` archived: ${from} → ${to}`);
404
+ } catch (err) {
405
+ console.error(err.message);
406
+ process.exit(2);
407
+ }
408
+ });
409
+
410
+ // --- canon ---
411
+ const canonCmd = program.command('canon').description('Personal canon of references (~/.claudenv/memories/canon/index.yaml)');
412
+
413
+ canonCmd
414
+ .command('add')
415
+ .argument('<topic>', 'Topic slug')
416
+ .argument('<url>', 'URL to add')
417
+ .option('--why <reason>', 'Why this reference is in the canon')
418
+ .option('--title <title>', 'Title')
419
+ .option('--author <author>', 'Author or venue')
420
+ .action(async (topic, url, opts) => {
421
+ const { canonAdd } = await import('../src/canon.js');
422
+ try {
423
+ const res = await canonAdd({
424
+ topic,
425
+ url,
426
+ why: opts.why,
427
+ title: opts.title,
428
+ author: opts.author,
429
+ });
430
+ if (res.added) console.log(` + ${topic}: ${res.entry.title || res.entry.url}`);
431
+ else console.log(` ~ duplicate url in ${topic} — skipped`);
432
+ } catch (err) {
433
+ console.error(err.message);
434
+ process.exit(2);
435
+ }
436
+ });
437
+
438
+ canonCmd
439
+ .command('list')
440
+ .argument('[topic]', 'Optional topic filter')
441
+ .action(async (topic) => {
442
+ const { canonList, formatCanon } = await import('../src/canon.js');
443
+ const data = await canonList(topic);
444
+ console.log(formatCanon(data));
445
+ });
446
+
447
+ canonCmd
448
+ .command('search')
449
+ .argument('<query>', 'Substring search')
450
+ .action(async (query) => {
451
+ const { canonSearch, formatCanon } = await import('../src/canon.js');
452
+ const data = await canonSearch(query);
453
+ console.log(formatCanon(data));
454
+ });
455
+
456
+ canonCmd
457
+ .command('prune')
458
+ .option('--months <n>', 'Age threshold in months', '6')
459
+ .action(async (opts) => {
460
+ const { canonPrune } = await import('../src/canon.js');
461
+ const stale = await canonPrune(parseInt(opts.months, 10) || 6);
462
+ if (stale.length === 0) {
463
+ console.log(' No stale entries.');
464
+ return;
465
+ }
466
+ for (const { topic, entry, reason } of stale) {
467
+ const why = reason || `added ${entry.added}`;
468
+ console.log(` ${topic}: ${entry.url} (${why})`);
469
+ }
470
+ });
471
+
472
+ // --- doctor ---
473
+ program
474
+ .command('doctor')
475
+ .description('Health-check the claudenv setup')
476
+ .action(async () => {
477
+ const { runDoctor } = await import('../src/doctor.js');
478
+ const { lines, hasFail } = await runDoctor();
479
+ for (const l of lines) console.log(l);
480
+ process.exit(hasFail ? 1 : 0);
481
+ });
482
+
223
483
  // =============================================
224
484
  // Install / Uninstall
225
485
  // =============================================
@@ -247,7 +507,8 @@ async function runInstall(opts) {
247
507
  console.log(`
248
508
  Done! Now open Claude Code in any project and type:
249
509
 
250
- /claudenv
510
+ /claudenv — Set up project documentation
511
+ /autonomy — Manage autonomy profiles
251
512
 
252
513
  Claude will analyze your project and generate documentation.
253
514
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudenv",
3
- "version": "1.2.4",
3
+ "version": "1.3.0",
4
4
  "description": "One command to integrate Claude Code into any project — installs /claudenv command for AI-powered documentation generation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,44 @@
1
+ # Project memories
2
+
3
+ This directory holds **project-scoped** memory for `vibe-decisions` and related skills. Cross-project memory lives in `~/.claudenv/memories/`.
4
+
5
+ ## Layout
6
+
7
+ ```
8
+ .claude/memories/
9
+ ├── project.md # стек, конвенции, важные urls — заполняешь вручную
10
+ ├── decisions/ # project-specific tech decisions (committed to repo)
11
+ │ └── 2026-05-27-auth-jwt.md
12
+ └── README.md # this file
13
+ ```
14
+
15
+ ## When goes here vs `~/.claudenv/memories/`
16
+
17
+ - **Здесь (project)**: выбор специфичен этому проекту — внутренний сервис, формат API, deployment target, project-only convention
18
+ - **В `~/.claudenv/memories/decisions/` (global)**: универсальный tech-выбор — какая БД, какой algo, который применим в любом проекте
19
+
20
+ Skill `vibe-decisions` решает scope автоматически по полю `scope: global|project` в frontmatter. По умолчанию `global` если непонятно.
21
+
22
+ ## project.md шаблон
23
+
24
+ Создай этот файл вручную (claudenv не генерит автоматически):
25
+
26
+ ```markdown
27
+ # <project-name>
28
+
29
+ - **Stack:** Python 3.12, FastAPI, Postgres, Redis
30
+ - **Tests:** `pytest -m "not slow"` локально; CI запускает всё
31
+ - **Package manager:** uv (NOT pip, NOT poetry)
32
+ - **Линтеры:** ruff + mypy strict
33
+ - **Deploy:** GitHub Actions → ArgoCD → k8s
34
+ - **Внутренние ADR:** `docs/adr/`
35
+ - **Слаг для decisions/:** `<project-slug>`
36
+ ```
37
+
38
+ `vibe-decisions` читает project.md перед каждым нетривиальным выбором.
39
+
40
+ ## Commit policy
41
+
42
+ - `project.md` — committed
43
+ - `decisions/*.md` — committed (это shared с командой)
44
+ - Никаких secrets (production endpoints, API keys, internal hostnames) — для них используй `~/.claudenv/memories/` с глобальным scope (выйдет за пределы repo)
@@ -0,0 +1,90 @@
1
+ ---
2
+ description: Manage autonomy profiles — switch between safe/moderate/full/ci or view current status
3
+ allowed-tools: Bash, Read, Glob, Grep
4
+ argument-hint: <status|safe|moderate|full|ci> [--dry-run]
5
+ ---
6
+
7
+ # Autonomy Profile Manager
8
+
9
+ Manage Claude Code autonomy profiles directly from within a session.
10
+
11
+ ## Instructions
12
+
13
+ Parse `$ARGUMENTS` and execute the matching action below.
14
+
15
+ ### 1. Determine the action
16
+
17
+ - If `$ARGUMENTS` is empty or `status` → go to **Status**
18
+ - If `$ARGUMENTS` starts with `safe`, `moderate`, `full`, or `ci` → go to **Switch Profile**
19
+ - Otherwise → go to **Usage Help**
20
+
21
+ ### 2. Status
22
+
23
+ Show the current autonomy configuration:
24
+
25
+ 1. Check if `.claude/hooks/pre-tool-use.sh` exists in the current project directory.
26
+ - If it exists, read the first 5 lines to find the `# Profile:` comment header and report the active profile name.
27
+ - If it doesn't exist, report "No autonomy profile configured for this project."
28
+ 2. Check if `.claude/settings.json` exists. If so, read it and summarize the permissions (allowedTools, disallowedTools counts).
29
+ 3. List available profiles: `safe`, `moderate`, `full`, `ci`.
30
+
31
+ ### 3. Switch Profile
32
+
33
+ The target profile is the first word of `$ARGUMENTS`. Check for `--dry-run` flag in the remaining arguments.
34
+
35
+ **If the profile is `full`:**
36
+ Before proceeding, display this warning:
37
+
38
+ ```
39
+ ⚠️ FULL AUTONOMY MODE — UNRESTRICTED ACCESS
40
+
41
+ This profile grants Claude Code complete access including:
42
+ • All file system operations (read, write, delete)
43
+ • Credential files (~/.ssh, ~/.aws, ~/.gnupg, ~/.kube, etc.)
44
+ • All git operations including force push
45
+ • No permission prompts (--dangerously-skip-permissions)
46
+
47
+ Safety net: audit logging + hard blocks on rm -rf / and force push to main
48
+ ```
49
+
50
+ Ask the user to confirm before proceeding. If they decline, abort.
51
+
52
+ **Apply the profile:**
53
+
54
+ Build the command:
55
+ ```
56
+ claudenv autonomy --profile <name> --yes --overwrite
57
+ ```
58
+
59
+ If `--dry-run` is present in `$ARGUMENTS`, append `--dry-run` to the command.
60
+
61
+ Run the command via Bash. If the command fails with "command not found", tell the user:
62
+
63
+ ```
64
+ claudenv is not on PATH. Install it with:
65
+ npm install -g claudenv
66
+ ```
67
+
68
+ After successful execution, show the output and confirm the profile was applied.
69
+
70
+ ### 4. Usage Help
71
+
72
+ Display:
73
+ ```
74
+ Usage: /autonomy <action> [options]
75
+
76
+ Actions:
77
+ status Show current autonomy profile and permissions
78
+ safe Switch to safe profile (read-only + limited bash)
79
+ moderate Switch to moderate profile (read/write + controlled bash)
80
+ full Switch to full profile (unrestricted — requires confirmation)
81
+ ci Switch to CI profile (optimized for CI/CD pipelines)
82
+
83
+ Options:
84
+ --dry-run Preview generated files without writing them
85
+
86
+ Examples:
87
+ /autonomy status
88
+ /autonomy moderate
89
+ /autonomy full --dry-run
90
+ ```
@@ -0,0 +1,33 @@
1
+ ---
2
+ description: Показать или добавить ссылки в личный канон (~/.claudenv/memories/canon/index.yaml)
3
+ allowed-tools: Bash(claudenv:*), Read
4
+ argument-hint: [list [<topic>]|search <query>|add <topic> <url> --why "<reason>"]
5
+ ---
6
+
7
+ # /canon — Личный канон ссылок
8
+
9
+ Wrapper над `claudenv canon` CLI.
10
+
11
+ ## Routing
12
+
13
+ Разбери `$ARGUMENTS`:
14
+
15
+ - пусто или `list` → `claudenv canon list`
16
+ - `list <topic>` → `claudenv canon list <topic>`
17
+ - `search <query>` → `claudenv canon search "<query>"`
18
+ - `add <topic> <url> --why "<reason>"` → `claudenv canon add <topic> <url> --why "<reason>"`
19
+ - иначе если выглядит как topic slug → `claudenv canon list <slug>`
20
+ - иначе → `claudenv canon search "$ARGUMENTS"`
21
+
22
+ ## Output
23
+
24
+ Печатай stdout как есть. На non-zero exit code покажи stderr и подскажи usage.
25
+
26
+ ## Когда канон пуст
27
+
28
+ Если `claudenv canon list` ничего не вернул:
29
+
30
+ ```
31
+ Канон пока пуст. Добавь первые записи когда будешь делать /deeper —
32
+ после deep dive предложу `claudenv canon add <topic> <url> --why "..."`.
33
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ description: Показать или найти принятые vibe-decisions (последние N, по slug, или по поисковому запросу)
3
+ allowed-tools: Bash(claudenv:*), Read
4
+ argument-hint: [list|show <id>|search <query>] [--limit N] [--scope global|project|all]
5
+ ---
6
+
7
+ # /decisions — Список и поиск принятых решений
8
+
9
+ Wrapper над `claudenv decisions` CLI. Запускается из Bash, результат показывается пользователю как есть.
10
+
11
+ ## Routing
12
+
13
+ Разбери `$ARGUMENTS`:
14
+
15
+ - пусто или `list` → `claudenv decisions list --limit 10`
16
+ - `list --limit N` → `claudenv decisions list --limit N`
17
+ - `list --scope <s>` → `claudenv decisions list --scope <s>`
18
+ - `show <id>` → `claudenv decisions show <id>`
19
+ - `search <query>` → `claudenv decisions search "<query>"`
20
+ - иначе если выглядит как id или slug → `claudenv decisions show "$ARGUMENTS"`
21
+ - иначе → `claudenv decisions search "$ARGUMENTS"`
22
+
23
+ ## Output
24
+
25
+ Печатай stdout команды без редактирования. Если команда вернула non-zero exit code — покажи stderr пользователю и предложи `claudenv decisions list` для проверки доступных id.
26
+
27
+ ## Если `claudenv` не на PATH
28
+
29
+ Подскажи: `npm i -g claudenv` или `npx claudenv decisions list`.
@@ -0,0 +1,55 @@
1
+ ---
2
+ description: Развернуть последнее принятое решение в подробное объяснение (deep dive — концепт, варианты, канон)
3
+ allowed-tools: Read, Glob, Grep, WebSearch, WebFetch, Bash(claudenv:*), Bash(ls:*), Write, Edit
4
+ argument-hint: [topic-or-decision-id]
5
+ ---
6
+
7
+ # /deeper — Подробное объяснение последнего решения
8
+
9
+ Развернуть последнее (или указанное в `$ARGUMENTS`) принятое vibe-decision в полный формат.
10
+
11
+ ## Step 1 — Find the target decision
12
+
13
+ If `$ARGUMENTS` is empty:
14
+
15
+ 1. Run `claudenv decisions list --limit 1` (Bash) — get the most recent decision id
16
+ 2. Run `claudenv decisions show <id>` to load its frontmatter
17
+
18
+ If `$ARGUMENTS` is a topic slug or id:
19
+
20
+ 1. Run `claudenv decisions show $ARGUMENTS` to load it
21
+ 2. If not found — fall back to `claudenv decisions search "$ARGUMENTS"` and pick the top match
22
+
23
+ If nothing matches:
24
+
25
+ ```
26
+ Не нашёл недавнего решения. Сначала сделай нетривиальный выбор — vibe-decisions залогирует его. Потом вызови /deeper.
27
+ ```
28
+
29
+ Stop here.
30
+
31
+ ## Step 2 — Expand into the deep dive format
32
+
33
+ Follow `~/.claude/skills/vibe-decisions/deep-dive-template.md` exactly:
34
+
35
+ 1. **Концептуально** (3-5 lines) — what it is, what problem it solves, name 1-2 alternatives
36
+ 2. **Как работает** (5-10 lines, optional code sketch) — simplified model + key invariants
37
+ 3. **2-3 варианта реализации** — for each: code sketch + when-suits / when-doesn't
38
+ 4. **Канон** — 2-4 references, **first** from `~/.claudenv/memories/canon/index.yaml` by topic; if no match, WebSearch and propose `claudenv canon add` afterward
39
+
40
+ ## Step 3 — Update the decision file
41
+
42
+ Edit the original decision file to set:
43
+
44
+ ```yaml
45
+ deep_dive_done: yes
46
+ sources_consulted: [<urls and canon ids you cited>]
47
+ ```
48
+
49
+ Preserve the `__VIBE_DECISION__` marker on the last line.
50
+
51
+ ## Style
52
+
53
+ - User's language
54
+ - Concrete to the actual task, not generic textbook
55
+ - If a sketch is shorter than prose — use the sketch
@@ -0,0 +1,26 @@
1
+ ---
2
+ description: Подавить vibe-decisions overview на следующий ответ — просто пиши код без brief overview
3
+ allowed-tools:
4
+ argument-hint:
5
+ ---
6
+
7
+ # /just-code — Подавить vibe overview одноразово
8
+
9
+ Эффект на ОДИН следующий ответ:
10
+
11
+ - vibe-decisions skill НЕ выдаёт brief overview / auto-log block
12
+ - Просто пишет код для текущей задачи
13
+ - Decision файл НЕ создаётся для этого ответа
14
+ - На ответ после следующего поведение возвращается к дефолту
15
+
16
+ ## В AUTO-LOG mode (loop)
17
+
18
+ В loop эта команда фактически no-op для большинства случаев — auto-log не паузит, а просто логирует. `/just-code` пропускает логирование на один шаг. Это полезно когда выбор тривиален но vibe-decisions всё равно зажёгся.
19
+
20
+ ## В INTERACTIVE mode
21
+
22
+ Пропускает паузу на следующем шаге. Используй когда явно знаешь что хочешь, без нужды в overview.
23
+
24
+ ## После использования
25
+
26
+ Не нужно ничего откатывать — действие истекает само через один turn. Если хочешь надолго отключить vibe-decisions — отредактируй его SKILL.md trigger criteria.
@@ -0,0 +1,33 @@
1
+ ---
2
+ description: Объяснить технологию или подход в контексте текущей задачи — без принятия решения и без записи в decisions/
3
+ allowed-tools: Read, Glob, Grep, WebSearch, WebFetch, Bash(claudenv:*)
4
+ argument-hint: <technology-or-question>
5
+ ---
6
+
7
+ # /why — Краткое объяснение
8
+
9
+ Объяснить `$ARGUMENTS` в контексте текущей задачи. Не вызывает vibe-decisions, не пишет в `~/.claudenv/memories/decisions/`.
10
+
11
+ ## Step 1 — Check canon first
12
+
13
+ Run `claudenv canon search "$ARGUMENTS"` (Bash). If matches found — упомяни их как primary references.
14
+
15
+ ## Step 2 — Brief explanation (3-5 lines)
16
+
17
+ Структура:
18
+
19
+ - **Что это:** 1 строка
20
+ - **Когда используется:** 1-2 строки
21
+ - **Когда не подходит:** 1 строка
22
+ - **Ссылки (опционально):** канон или WebSearch если канон пуст
23
+
24
+ ## Не делать
25
+
26
+ - Не выводи vibe-decisions overview format (это explainer, не decision)
27
+ - Не пиши файл в decisions/
28
+ - Если пользователь после `/why` начинает реальный выбор технологии — тогда уже триггерится vibe-decisions skill
29
+
30
+ ## Style
31
+
32
+ - User's language
33
+ - Краткость > полнота. Для полноты есть `/deeper` после реального decision.