claudenv 1.2.5 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +93 -3
  2. package/bin/cli.js +294 -0
  3. package/package.json +1 -1
  4. package/scaffold/.claude/memories/README.md +44 -0
  5. package/scaffold/global/.claude/commands/add-source.md +31 -0
  6. package/scaffold/global/.claude/commands/canon.md +33 -0
  7. package/scaffold/global/.claude/commands/decisions.md +29 -0
  8. package/scaffold/global/.claude/commands/deeper.md +55 -0
  9. package/scaffold/global/.claude/commands/just-code.md +26 -0
  10. package/scaffold/global/.claude/commands/why.md +33 -0
  11. package/scaffold/global/.claude/skills/source-connector/SKILL.md +128 -0
  12. package/scaffold/global/.claude/skills/vibe-decisions/SKILL.md +127 -0
  13. package/scaffold/global/.claude/skills/vibe-decisions/deep-dive-template.md +41 -0
  14. package/scaffold/global-claudenv/config.yaml +16 -0
  15. package/scaffold/global-claudenv/memories/INDEX.md +25 -0
  16. package/scaffold/global-claudenv/memories/canon/index.yaml +21 -0
  17. package/scaffold/global-claudenv/memories/user/preferences.md.example +16 -0
  18. package/src/autonomy.js +6 -1
  19. package/src/canon.js +214 -0
  20. package/src/decisions.js +161 -0
  21. package/src/doctor.js +201 -0
  22. package/src/hooks/decisions-logger.js +183 -0
  23. package/src/hooks/dispatcher.js +91 -0
  24. package/src/hooks/regen-index.js +198 -0
  25. package/src/hooks-gen.js +43 -1
  26. package/src/installer.js +57 -14
  27. package/src/loop.js +26 -1
  28. package/src/memory-context.js +63 -0
  29. package/src/memory-paths.js +128 -0
  30. package/src/memory.js +111 -0
  31. package/src/sources.js +78 -0
  32. package/src/workspaces.js +129 -0
  33. package/templates/connector-mssql.ejs +62 -0
  34. package/templates/connector-rest.ejs +59 -0
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # claudenv
2
2
 
3
- Set up [Claude Code](https://docs.anthropic.com/en/docs/claude-code) in any project with one command. claudenv analyzes your codebase and generates everything Claude needs to work effectively — documentation, rules, hooks, MCP servers, and slash commands.
3
+ [![npm](https://img.shields.io/npm/v/claudenv.svg)](https://www.npmjs.com/package/claudenv)
4
+
5
+ Set up [Claude Code](https://docs.anthropic.com/en/docs/claude-code) in any project with one command. claudenv analyzes your codebase and generates everything Claude needs to work effectively — documentation, rules, hooks, MCP servers, slash commands, **plus cross-session memory and vibe-decisions logging (1.3.0).**
6
+
7
+ > **New in 1.3.0** — split memory layout (`~/.claudenv/memories/` global + `.claude/memories/` project), `vibe-decisions` skill (auto-log in loop, pause-and-ask interactive), new CLI: `memory`, `decisions`, `canon`, `doctor`. Companion Python package `claudenv-memory` on PyPI (alpha). See [CHANGELOG.md](./CHANGELOG.md).
4
8
 
5
9
  ## Quick Start
6
10
 
@@ -17,8 +21,8 @@ Claude reads your code, asks a few questions, and generates:
17
21
  - **CLAUDE.md** — project overview, architecture, key commands
18
22
  - **Rules** — coding style, testing patterns, workflow guidelines (`.claude/rules/`)
19
23
  - **MCP servers** — auto-detected from your stack, configured in `.mcp.json`
20
- - **Slash commands** — `/init-docs`, `/update-docs`, `/validate-docs`, `/setup-mcp`, `/improve`
21
- - **Hooks** — validation on tool use, audit logging (`.claude/settings.json`)
24
+ - **Slash commands** — `/init-docs`, `/update-docs`, `/validate-docs`, `/setup-mcp`, `/improve`, **`/deeper`**, **`/why`**, **`/decisions`**, **`/canon`**, **`/just-code`** (1.3.0)
25
+ - **Hooks** — validation on tool use, audit logging, decisions-logger (PostToolUse Write), regen-index (SessionEnd) — `.claude/settings.json`
22
26
 
23
27
  Everything is committed to your repo. Team members get the same Claude experience.
24
28
 
@@ -151,6 +155,87 @@ claudenv loop --profile moderate --goal "add types" # sonnet, deny-list guard
151
155
  claudenv loop --profile ci --model sonnet # ci profile but with sonnet
152
156
  ```
153
157
 
158
+ ## Memory & vibe-decisions (1.3.0)
159
+
160
+ Persistent memory across sessions + brief overview before non-trivial technical choices. Auto-log inside `claudenv loop` (no pauses — `autonomy=law`), pause-and-ask in interactive Claude Code chats.
161
+
162
+ ### Layout (split)
163
+
164
+ ```
165
+ ~/.claudenv/memories/ # global, cross-project
166
+ ├── INDEX.md # briefing — auto-regenerated
167
+ ├── decisions/ # universal tech decisions
168
+ ├── canon/index.yaml # personal canon of references
169
+ └── user/preferences.md # cross-project preferences
170
+
171
+ <project>/.claude/memories/ # project-scoped, committed
172
+ ├── project.md # stack, conventions, internal urls
173
+ └── decisions/ # project-only decisions
174
+ ```
175
+
176
+ ### Commands
177
+
178
+ ```bash
179
+ # Memory
180
+ claudenv memory init # initialise ~/.claudenv/memories/
181
+ claudenv memory index # regenerate INDEX.md
182
+ claudenv memory show <path> # print a memory file
183
+ claudenv memory edit <path> # open in $EDITOR
184
+
185
+ # Decisions
186
+ claudenv decisions list [--scope all|global|project] [--limit N]
187
+ claudenv decisions show <id-or-slug>
188
+ claudenv decisions search <query>
189
+ claudenv decisions archive <id>
190
+
191
+ # Canon
192
+ claudenv canon add <topic> <url> --why "<reason>" [--title <t>] [--author <a>]
193
+ claudenv canon list [<topic>]
194
+ claudenv canon search <query>
195
+ claudenv canon prune --months 6 # find stale entries
196
+
197
+ # Health
198
+ claudenv doctor # OK/WARN/FAIL check
199
+ ```
200
+
201
+ ### Slash-commands (in Claude Code session)
202
+
203
+ | Command | Purpose |
204
+ |---|---|
205
+ | `/deeper` | Develop the most recent decision into a full deep dive (concept → variants → trade-offs → canon) |
206
+ | `/why <X>` | Explain technology X without logging a decision |
207
+ | `/decisions` | List/search logged decisions via the CLI |
208
+ | `/canon` | Browse the personal canon |
209
+ | `/just-code` | Suppress vibe-decisions overview for the next response only |
210
+
211
+ ### How auto-log works in `claudenv loop`
212
+
213
+ `claudenv loop` appends a system-prompt fragment that switches the `vibe-decisions` skill into **auto-log mode** — it picks the approach, writes the decision file (`/memories/decisions/<date>-<slug>.md`), and continues coding without pausing. Outside loop (interactive Claude Code) the skill defaults to **pause-and-ask** mode.
214
+
215
+ After each iteration, `claudenv loop` regenerates `INDEX.md` so the next iteration's briefing reflects what was just decided.
216
+
217
+ ### Python companion: `claudenv-memory`
218
+
219
+ Building your own agent on Claude Agent SDK and want the same memory layout?
220
+
221
+ ```bash
222
+ pip install claudenv-memory
223
+ ```
224
+
225
+ ```python
226
+ from claudenv_memory import LocalFileMemoryBackend
227
+ from claude_agent_sdk import ClaudeAgentOptions
228
+
229
+ backend = LocalFileMemoryBackend() # ~/.claudenv/memories + ./.claude/memories
230
+ options = ClaudeAgentOptions(
231
+ model="claude-opus-4-7",
232
+ extra_headers={"anthropic-beta": "context-management-2025-06-27"},
233
+ tools=[backend.as_tool()],
234
+ )
235
+ ```
236
+
237
+ Status: 0.1.x alpha — first production consumer is claudenv 2.0. See `python/README.md`.
238
+
154
239
  ## MCP Server Setup
155
240
 
156
241
  `/claudenv` auto-detects your tech stack and recommends MCP servers from the [official registry](https://registry.modelcontextprotocol.io). You can also run `/setup-mcp` independently.
@@ -221,6 +306,11 @@ claudenv autonomy [-p <profile>] Configure autonomy profiles
221
306
  claudenv init [dir] [-y] Legacy: static analysis (no AI)
222
307
  claudenv generate [-d <dir>] Templates only, no scaffold
223
308
  claudenv validate [-d <dir>] Check documentation completeness
309
+
310
+ claudenv memory init|index|show|edit Manage ~/.claudenv/memories/ (1.3.0+)
311
+ claudenv decisions list|show|search Logged vibe-decisions (1.3.0+)
312
+ claudenv canon add|list|search|prune Personal canon (1.3.0+)
313
+ claudenv doctor Health check (1.3.0+)
224
314
  ```
225
315
 
226
316
  ## Run Without Installing
package/bin/cli.js CHANGED
@@ -288,6 +288,300 @@ program
288
288
  .option('--dry-run', 'Preview without writing')
289
289
  .action(runAutonomy);
290
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
+ // =============================================
473
+ // Workspaces (isolated per-company/context memory)
474
+ // =============================================
475
+ const wsCmd = program.command('workspace').description('Isolated memory spaces (~/.claudenv/workspaces/)');
476
+
477
+ wsCmd
478
+ .command('add')
479
+ .argument('<id>', 'Workspace id (slug: a-z0-9-_)')
480
+ .option('--name <name>', 'Human-readable name')
481
+ .option('--desc <description>', 'Description')
482
+ .option('--path <path...>', 'Project path(s) bound to this workspace')
483
+ .action(async (id, opts) => {
484
+ const { createWorkspace } = await import('../src/workspaces.js');
485
+ try {
486
+ await createWorkspace(id, { name: opts.name, description: opts.desc, paths: opts.path });
487
+ console.log(` + workspace "${id}" created`);
488
+ } catch (err) {
489
+ console.error(err.message);
490
+ process.exit(2);
491
+ }
492
+ });
493
+
494
+ wsCmd
495
+ .command('list')
496
+ .action(async () => {
497
+ const { listWorkspaces } = await import('../src/workspaces.js');
498
+ const list = await listWorkspaces();
499
+ if (list.length === 0) {
500
+ console.log(' No workspaces yet — create one with `claudenv workspace add <id>`');
501
+ return;
502
+ }
503
+ for (const w of list) {
504
+ console.log(` ${w.active ? '*' : ' '} ${w.id}${w.name && w.name !== w.id ? ` — ${w.name}` : ''}`);
505
+ }
506
+ });
507
+
508
+ wsCmd
509
+ .command('use')
510
+ .argument('<id>', 'Workspace id to activate')
511
+ .action(async (id) => {
512
+ const { useWorkspace } = await import('../src/workspaces.js');
513
+ try {
514
+ await useWorkspace(id);
515
+ console.log(` active workspace → ${id}`);
516
+ } catch (err) {
517
+ console.error(err.message);
518
+ process.exit(2);
519
+ }
520
+ });
521
+
522
+ wsCmd
523
+ .command('show')
524
+ .action(async () => {
525
+ const { showActive } = await import('../src/workspaces.js');
526
+ const w = await showActive();
527
+ if (!w) {
528
+ console.log(' No active workspace (set CLAUDENV_WORKSPACE or run `claudenv workspace use <id>`)');
529
+ return;
530
+ }
531
+ console.log(` active: ${w.id} (${w.source})`);
532
+ if (w.name && w.name !== w.id) console.log(` name: ${w.name}`);
533
+ if (w.description) console.log(` desc: ${w.description}`);
534
+ if (w.paths && w.paths.length) console.log(` paths: ${w.paths.join(', ')}`);
535
+ });
536
+
537
+ // =============================================
538
+ // Sources (connectors in the active workspace)
539
+ // =============================================
540
+ const srcCmd = program.command('source').description('Data-source connectors in the active workspace');
541
+
542
+ srcCmd
543
+ .command('list')
544
+ .action(async () => {
545
+ const { listConnectors } = await import('../src/sources.js');
546
+ const { workspace, connectors } = await listConnectors();
547
+ if (!workspace) {
548
+ console.log(' No active workspace — set one first (`claudenv workspace use <id>`)');
549
+ return;
550
+ }
551
+ if (connectors.length === 0) {
552
+ console.log(` [${workspace}] no connectors yet — add one via /add-source in Claude Code`);
553
+ return;
554
+ }
555
+ console.log(` [${workspace}]`);
556
+ for (const c of connectors) {
557
+ console.log(` ${c.name} (${c.type}, ${c.status})${c.host ? ` ${c.host}` : ''}`);
558
+ }
559
+ });
560
+
561
+ srcCmd
562
+ .command('show')
563
+ .argument('<name>', 'Connector name')
564
+ .action(async (name) => {
565
+ const { showConnector } = await import('../src/sources.js');
566
+ const text = await showConnector(name);
567
+ if (!text) {
568
+ console.error(` Connector "${name}" not found in active workspace`);
569
+ process.exit(2);
570
+ }
571
+ console.log(text);
572
+ });
573
+
574
+ // --- doctor ---
575
+ program
576
+ .command('doctor')
577
+ .description('Health-check the claudenv setup')
578
+ .action(async () => {
579
+ const { runDoctor } = await import('../src/doctor.js');
580
+ const { lines, hasFail } = await runDoctor();
581
+ for (const l of lines) console.log(l);
582
+ process.exit(hasFail ? 1 : 0);
583
+ });
584
+
291
585
  // =============================================
292
586
  // Install / Uninstall
293
587
  // =============================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudenv",
3
- "version": "1.2.5",
3
+ "version": "1.3.1",
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,31 @@
1
+ ---
2
+ description: Добавить коннектор к источнику данных (SQL/REST/вики/Redash) с изоляцией по workspace
3
+ allowed-tools: Bash, Read, Write, Edit, Skill
4
+ argument-hint: [<описание источника>]
5
+ ---
6
+
7
+ # /add-source - подключить источник данных
8
+
9
+ Запускает skill `source-connector`: опрашивает тебя, генерирует рабочий коннектор,
10
+ кладёт секреты в `.env.local`, кэширует знание о коннекторе (параметры + provenance)
11
+ в память активного workspace.
12
+
13
+ ## Routing
14
+
15
+ 1. Активируй skill `source-connector`.
16
+ 2. Если в `$ARGUMENTS` есть описание источника (тип/хост/система) - передай его как
17
+ стартовый контекст, остальное доспроси.
18
+ 3. Если аргументов нет - начни с вопроса, к какому источнику подключаемся.
19
+
20
+ ## Перед стартом
21
+
22
+ - Определи активный workspace (env `CLAUDENV_WORKSPACE` -> файл
23
+ `~/.claudenv/active-workspace`). Нет активного - предложи выбрать/создать,
24
+ не пиши в глобальную память.
25
+ - Напомни инвариант: секреты идут только в `.env.local` (gitignored), в память -
26
+ только имена переменных.
27
+
28
+ ## Когда НЕ создавать коннектор
29
+
30
+ Если для источника есть готовый MCP-сервер - предложи путь через `/setup-mcp`
31
+ (`.mcp.json`), коннектор нужен только для источников без MCP.
@@ -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.