devflow-kit 1.0.0 → 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 (44) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +13 -6
  3. package/dist/cli.js +5 -1
  4. package/dist/commands/ambient.d.ts +18 -0
  5. package/dist/commands/ambient.js +136 -0
  6. package/dist/commands/init.d.ts +2 -0
  7. package/dist/commands/init.js +97 -10
  8. package/dist/commands/memory.d.ts +22 -0
  9. package/dist/commands/memory.js +175 -0
  10. package/dist/commands/uninstall.js +72 -5
  11. package/dist/plugins.js +8 -1
  12. package/dist/utils/post-install.d.ts +12 -0
  13. package/dist/utils/post-install.js +82 -1
  14. package/dist/utils/safe-delete-install.d.ts +7 -0
  15. package/dist/utils/safe-delete-install.js +40 -5
  16. package/package.json +1 -1
  17. package/plugins/devflow-ambient/.claude-plugin/plugin.json +7 -0
  18. package/plugins/devflow-ambient/README.md +49 -0
  19. package/plugins/devflow-ambient/commands/ambient.md +110 -0
  20. package/plugins/devflow-ambient/skills/ambient-router/SKILL.md +89 -0
  21. package/plugins/devflow-ambient/skills/ambient-router/references/skill-catalog.md +64 -0
  22. package/plugins/devflow-audit-claude/.claude-plugin/plugin.json +1 -1
  23. package/plugins/devflow-code-review/.claude-plugin/plugin.json +1 -1
  24. package/plugins/devflow-core-skills/.claude-plugin/plugin.json +2 -1
  25. package/plugins/devflow-core-skills/skills/docs-framework/SKILL.md +10 -6
  26. package/plugins/devflow-core-skills/skills/test-driven-development/SKILL.md +139 -0
  27. package/plugins/devflow-core-skills/skills/test-driven-development/references/rationalization-prevention.md +111 -0
  28. package/plugins/devflow-debug/.claude-plugin/plugin.json +1 -1
  29. package/plugins/devflow-implement/.claude-plugin/plugin.json +1 -1
  30. package/plugins/devflow-resolve/.claude-plugin/plugin.json +1 -1
  31. package/plugins/devflow-self-review/.claude-plugin/plugin.json +1 -1
  32. package/plugins/devflow-specify/.claude-plugin/plugin.json +1 -1
  33. package/scripts/hooks/ambient-prompt.sh +48 -0
  34. package/scripts/hooks/background-memory-update.sh +49 -8
  35. package/scripts/hooks/ensure-memory-gitignore.sh +17 -0
  36. package/scripts/hooks/pre-compact-memory.sh +12 -6
  37. package/scripts/hooks/session-start-memory.sh +50 -8
  38. package/scripts/hooks/stop-update-memory.sh +10 -6
  39. package/shared/skills/ambient-router/SKILL.md +89 -0
  40. package/shared/skills/ambient-router/references/skill-catalog.md +64 -0
  41. package/shared/skills/docs-framework/SKILL.md +10 -6
  42. package/shared/skills/test-driven-development/SKILL.md +139 -0
  43. package/shared/skills/test-driven-development/references/rationalization-prevention.md +111 -0
  44. package/src/templates/managed-settings.json +14 -0
@@ -9,6 +9,8 @@ import { getInstallationPaths, getClaudeDirectory, getManagedSettingsPath } from
9
9
  import { getGitRoot } from '../utils/git.js';
10
10
  import { isClaudeCliAvailable } from '../utils/cli.js';
11
11
  import { DEVFLOW_PLUGINS, getAllSkillNames, LEGACY_SKILL_NAMES } from '../plugins.js';
12
+ import { removeAmbientHook } from './ambient.js';
13
+ import { removeMemoryHooks } from './memory.js';
12
14
  import { detectShell, getProfilePath } from '../utils/safe-delete.js';
13
15
  import { isAlreadyInstalled, removeFromProfile } from '../utils/safe-delete-install.js';
14
16
  import { removeManagedSettings } from '../utils/post-install.js';
@@ -176,6 +178,21 @@ export const uninstallCommand = new Command('uninstall')
176
178
  if (!usedCli) {
177
179
  if (isSelectiveUninstall) {
178
180
  await removeSelectedPlugins(claudeDir, selectedPlugins, verbose);
181
+ // Clean up ambient hook if ambient plugin is being removed
182
+ if (selectedPlugins.some(sp => sp.name === 'devflow-ambient')) {
183
+ const settingsPath = path.join(claudeDir, 'settings.json');
184
+ try {
185
+ const settings = await fs.readFile(settingsPath, 'utf-8');
186
+ const updated = removeAmbientHook(settings);
187
+ if (updated !== settings) {
188
+ await fs.writeFile(settingsPath, updated, 'utf-8');
189
+ if (verbose) {
190
+ p.log.success('Ambient mode hook removed from settings.json');
191
+ }
192
+ }
193
+ }
194
+ catch { /* settings.json may not exist */ }
195
+ }
179
196
  }
180
197
  else {
181
198
  await removeAllDevFlow(claudeDir, devflowScriptsDir, verbose);
@@ -221,7 +238,39 @@ export const uninstallCommand = new Command('uninstall')
221
238
  p.log.info('.docs/ preserved');
222
239
  }
223
240
  }
224
- // 2. .claudeignore
241
+ // 2. .memory/ directory
242
+ const memoryDir = path.join(process.cwd(), '.memory');
243
+ let memoryExist = false;
244
+ try {
245
+ await fs.access(memoryDir);
246
+ memoryExist = true;
247
+ }
248
+ catch { /* .memory doesn't exist */ }
249
+ if (memoryExist) {
250
+ let shouldRemoveMemory = false;
251
+ if (options.keepDocs) {
252
+ shouldRemoveMemory = false;
253
+ }
254
+ else if (process.stdin.isTTY) {
255
+ const removeMemory = await p.confirm({
256
+ message: '.memory/ directory found. Remove working memory files?',
257
+ initialValue: false,
258
+ });
259
+ if (p.isCancel(removeMemory)) {
260
+ p.cancel('Uninstall cancelled.');
261
+ process.exit(0);
262
+ }
263
+ shouldRemoveMemory = removeMemory;
264
+ }
265
+ if (shouldRemoveMemory) {
266
+ await fs.rm(memoryDir, { recursive: true, force: true });
267
+ p.log.success('.memory/ removed');
268
+ }
269
+ else {
270
+ p.log.info('.memory/ preserved');
271
+ }
272
+ }
273
+ // 4. .claudeignore
225
274
  const claudeignorePath = gitRoot
226
275
  ? path.join(gitRoot, '.claudeignore')
227
276
  : path.join(process.cwd(), '.claudeignore');
@@ -249,12 +298,30 @@ export const uninstallCommand = new Command('uninstall')
249
298
  p.log.info('.claudeignore preserved (non-interactive mode)');
250
299
  }
251
300
  }
252
- // 3. settings.json (DevFlow hooks)
301
+ // 5. settings.json (DevFlow hooks)
253
302
  for (const scope of scopesToUninstall) {
254
303
  try {
255
304
  const paths = await getInstallationPaths(scope);
256
305
  const settingsPath = path.join(paths.claudeDir, 'settings.json');
257
- const settingsContent = await fs.readFile(settingsPath, 'utf-8');
306
+ let settingsContent = await fs.readFile(settingsPath, 'utf-8');
307
+ // Always remove ambient hook on full uninstall (idempotent)
308
+ const withoutAmbient = removeAmbientHook(settingsContent);
309
+ if (withoutAmbient !== settingsContent) {
310
+ await fs.writeFile(settingsPath, withoutAmbient, 'utf-8');
311
+ settingsContent = withoutAmbient;
312
+ if (verbose) {
313
+ p.log.success(`Ambient mode hook removed from settings.json (${scope})`);
314
+ }
315
+ }
316
+ // Always remove memory hooks on full uninstall (idempotent)
317
+ const withoutMemory = removeMemoryHooks(settingsContent);
318
+ if (withoutMemory !== settingsContent) {
319
+ await fs.writeFile(settingsPath, withoutMemory, 'utf-8');
320
+ settingsContent = withoutMemory;
321
+ if (verbose) {
322
+ p.log.success(`Memory hooks removed from settings.json (${scope})`);
323
+ }
324
+ }
258
325
  const settings = JSON.parse(settingsContent);
259
326
  if (settings.hooks) {
260
327
  if (process.stdin.isTTY) {
@@ -280,7 +347,7 @@ export const uninstallCommand = new Command('uninstall')
280
347
  // settings.json doesn't exist or can't be parsed — skip
281
348
  }
282
349
  }
283
- // 4. Managed settings (security deny list)
350
+ // 6. Managed settings (security deny list)
284
351
  let managedSettingsExist = false;
285
352
  try {
286
353
  const managedPath = getManagedSettingsPath();
@@ -309,7 +376,7 @@ export const uninstallCommand = new Command('uninstall')
309
376
  p.log.info('Managed settings preserved (non-interactive mode)');
310
377
  }
311
378
  }
312
- // 5. Safe-delete shell function
379
+ // 7. Safe-delete shell function
313
380
  const shell = detectShell();
314
381
  const profilePath = getProfilePath(shell);
315
382
  if (profilePath && await isAlreadyInstalled(profilePath)) {
package/dist/plugins.js CHANGED
@@ -10,7 +10,7 @@ export const DEVFLOW_PLUGINS = [
10
10
  description: 'Auto-activating quality enforcement (foundation layer)',
11
11
  commands: [],
12
12
  agents: [],
13
- skills: ['accessibility', 'core-patterns', 'docs-framework', 'frontend-design', 'git-safety', 'git-workflow', 'github-patterns', 'input-validation', 'react', 'test-patterns', 'typescript'],
13
+ skills: ['accessibility', 'core-patterns', 'docs-framework', 'frontend-design', 'git-safety', 'git-workflow', 'github-patterns', 'input-validation', 'react', 'test-driven-development', 'test-patterns', 'typescript'],
14
14
  },
15
15
  {
16
16
  name: 'devflow-specify',
@@ -54,6 +54,13 @@ export const DEVFLOW_PLUGINS = [
54
54
  agents: ['simplifier', 'scrutinizer', 'validator'],
55
55
  skills: ['self-review', 'core-patterns'],
56
56
  },
57
+ {
58
+ name: 'devflow-ambient',
59
+ description: 'Ambient mode — auto-loads relevant skills based on each prompt',
60
+ commands: ['/ambient'],
61
+ agents: [],
62
+ skills: ['ambient-router'],
63
+ },
57
64
  {
58
65
  name: 'devflow-audit-claude',
59
66
  description: 'Audit CLAUDE.md files against Anthropic best practices',
@@ -65,4 +65,16 @@ export declare function updateGitignore(gitRoot: string, verbose: boolean): Prom
65
65
  * Create .docs/ directory structure for DevFlow artifacts.
66
66
  */
67
67
  export declare function createDocsStructure(verbose: boolean): Promise<void>;
68
+ /**
69
+ * Create .memory/ directory for working memory files.
70
+ * Separate from .docs/ which is for reviews/releases.
71
+ */
72
+ export declare function createMemoryDir(verbose: boolean, cwd?: string): Promise<void>;
73
+ /**
74
+ * Migrate memory files from .docs/ to .memory/.
75
+ * One-time migration for existing users. Skips if destination exists (no clobber).
76
+ * Also cleans up ephemeral files from .docs/.
77
+ * Returns count of migrated files.
78
+ */
79
+ export declare function migrateMemoryFiles(verbose: boolean, cwd?: string): Promise<number>;
68
80
  //# sourceMappingURL=post-install.d.ts.map
@@ -386,7 +386,7 @@ export async function installClaudeignore(gitRoot, rootDir, verbose) {
386
386
  export async function updateGitignore(gitRoot, verbose) {
387
387
  try {
388
388
  const gitignorePath = path.join(gitRoot, '.gitignore');
389
- const entriesToAdd = ['.claude/', '.devflow/'];
389
+ const entriesToAdd = ['.claude/', '.devflow/', '.memory/', '.docs/'];
390
390
  let gitignoreContent = '';
391
391
  try {
392
392
  gitignoreContent = await fs.readFile(gitignorePath, 'utf-8');
@@ -424,4 +424,85 @@ export async function createDocsStructure(verbose) {
424
424
  }
425
425
  catch { /* may already exist */ }
426
426
  }
427
+ /**
428
+ * Create .memory/ directory for working memory files.
429
+ * Separate from .docs/ which is for reviews/releases.
430
+ */
431
+ export async function createMemoryDir(verbose, cwd) {
432
+ const memoryDir = path.join(cwd ?? process.cwd(), '.memory');
433
+ try {
434
+ await fs.mkdir(memoryDir, { recursive: true });
435
+ if (verbose) {
436
+ p.log.success('.memory/ directory ready');
437
+ }
438
+ }
439
+ catch { /* may already exist */ }
440
+ }
441
+ /**
442
+ * Migrate memory files from .docs/ to .memory/.
443
+ * One-time migration for existing users. Skips if destination exists (no clobber).
444
+ * Also cleans up ephemeral files from .docs/.
445
+ * Returns count of migrated files.
446
+ */
447
+ export async function migrateMemoryFiles(verbose, cwd) {
448
+ const root = cwd ?? process.cwd();
449
+ const docsDir = path.join(root, '.docs');
450
+ const memoryDir = path.join(root, '.memory');
451
+ const migrations = [
452
+ { src: path.join(docsDir, 'WORKING-MEMORY.md'), dest: path.join(memoryDir, 'WORKING-MEMORY.md') },
453
+ { src: path.join(docsDir, 'patterns.md'), dest: path.join(memoryDir, 'PROJECT-PATTERNS.md') },
454
+ { src: path.join(docsDir, 'working-memory-backup.json'), dest: path.join(memoryDir, 'backup.json') },
455
+ ];
456
+ let migrated = 0;
457
+ for (const { src, dest } of migrations) {
458
+ try {
459
+ await fs.access(src);
460
+ }
461
+ catch {
462
+ continue; // Source doesn't exist
463
+ }
464
+ try {
465
+ await fs.access(dest);
466
+ continue; // Destination already exists — no clobber
467
+ }
468
+ catch {
469
+ // Destination doesn't exist — proceed with migration
470
+ }
471
+ try {
472
+ await fs.rename(src, dest);
473
+ migrated++;
474
+ }
475
+ catch {
476
+ // Cross-device or permission error — try copy+delete
477
+ try {
478
+ await fs.copyFile(src, dest);
479
+ await fs.rm(src, { force: true });
480
+ migrated++;
481
+ }
482
+ catch {
483
+ // Migration failed for this file — skip silently
484
+ }
485
+ }
486
+ }
487
+ // Clean up ephemeral files from .docs/
488
+ const ephemeralFiles = [
489
+ path.join(docsDir, '.working-memory-update.log'),
490
+ path.join(docsDir, '.working-memory-last-trigger'),
491
+ ];
492
+ for (const file of ephemeralFiles) {
493
+ try {
494
+ await fs.rm(file, { force: true });
495
+ }
496
+ catch { /* doesn't exist or can't remove */ }
497
+ }
498
+ // Clean up lock directory
499
+ try {
500
+ await fs.rmdir(path.join(docsDir, '.working-memory.lock'));
501
+ }
502
+ catch { /* doesn't exist or not empty */ }
503
+ if (migrated > 0 && verbose) {
504
+ p.log.success(`Migrated ${migrated} memory file(s) from .docs/ to .memory/`);
505
+ }
506
+ return migrated;
507
+ }
427
508
  //# sourceMappingURL=post-install.js.map
@@ -1,4 +1,6 @@
1
1
  import type { Shell } from './safe-delete.js';
2
+ /** Bump this when the safe-delete block changes. */
3
+ export declare const SAFE_DELETE_BLOCK_VERSION = 2;
2
4
  /**
3
5
  * Generate the safe-delete shell function block with markers.
4
6
  * Returns null for unsupported shells.
@@ -13,6 +15,11 @@ export declare function isAlreadyInstalled(profilePath: string): Promise<boolean
13
15
  * Creates parent directories and the file if they don't exist.
14
16
  */
15
17
  export declare function installToProfile(profilePath: string, block: string): Promise<void>;
18
+ /**
19
+ * Extract the installed safe-delete block version from a profile file.
20
+ * Returns 0 (not installed), 1 (legacy block without version stamp), or N (versioned block).
21
+ */
22
+ export declare function getInstalledVersion(profilePath: string): Promise<number>;
16
23
  /**
17
24
  * Remove the safe-delete block from a profile file.
18
25
  * Returns true if the block was found and removed, false otherwise.
@@ -2,6 +2,8 @@ import { promises as fs } from 'fs';
2
2
  import * as path from 'path';
3
3
  const START_MARKER = '# >>> DevFlow safe-delete >>>';
4
4
  const END_MARKER = '# <<< DevFlow safe-delete <<<';
5
+ /** Bump this when the safe-delete block changes. */
6
+ export const SAFE_DELETE_BLOCK_VERSION = 2;
5
7
  /**
6
8
  * Generate the safe-delete shell function block with markers.
7
9
  * Returns null for unsupported shells.
@@ -13,13 +15,18 @@ export function generateSafeDeleteBlock(shell, platform, trashCommand) {
13
15
  const cmd = trashCommand ?? 'trash';
14
16
  return [
15
17
  START_MARKER,
18
+ `# v${SAFE_DELETE_BLOCK_VERSION}`,
16
19
  `rm() {`,
17
20
  ` local files=()`,
18
21
  ` for arg in "$@"; do`,
19
22
  ` [[ "$arg" =~ ^- ]] || files+=("$arg")`,
20
23
  ` done`,
21
- ` if (( \${#files[@]} > 0 )); then`,
22
- ` ${cmd} "\${files[@]}"`,
24
+ ` local existing=()`,
25
+ ` for f in "\${files[@]}"; do`,
26
+ ` [ -e "$f" ] || [ -L "$f" ] && existing+=("$f")`,
27
+ ` done`,
28
+ ` if (( \${#existing[@]} > 0 )); then`,
29
+ ` ${cmd} "\${existing[@]}"`,
23
30
  ` fi`,
24
31
  `}`,
25
32
  `command() {`,
@@ -36,6 +43,7 @@ export function generateSafeDeleteBlock(shell, platform, trashCommand) {
36
43
  const cmd = trashCommand ?? 'trash';
37
44
  return [
38
45
  START_MARKER,
46
+ `# v${SAFE_DELETE_BLOCK_VERSION}`,
39
47
  `function rm --description "Safe delete via trash"`,
40
48
  ` set -l files`,
41
49
  ` for arg in $argv`,
@@ -43,8 +51,14 @@ export function generateSafeDeleteBlock(shell, platform, trashCommand) {
43
51
  ` set files $files $arg`,
44
52
  ` end`,
45
53
  ` end`,
46
- ` if test (count $files) -gt 0`,
47
- ` ${cmd} $files`,
54
+ ` set -l existing`,
55
+ ` for f in $files`,
56
+ ` if test -e $f; or test -L $f`,
57
+ ` set existing $existing $f`,
58
+ ` end`,
59
+ ` end`,
60
+ ` if test (count $existing) -gt 0`,
61
+ ` ${cmd} $existing`,
48
62
  ` end`,
49
63
  `end`,
50
64
  END_MARKER,
@@ -54,6 +68,7 @@ export function generateSafeDeleteBlock(shell, platform, trashCommand) {
54
68
  if (platform === 'win32') {
55
69
  return [
56
70
  START_MARKER,
71
+ `# v${SAFE_DELETE_BLOCK_VERSION}`,
57
72
  `if (Get-Alias rm -ErrorAction SilentlyContinue) {`,
58
73
  ` Remove-Alias rm -Force -Scope Global`,
59
74
  `}`,
@@ -82,12 +97,14 @@ export function generateSafeDeleteBlock(shell, platform, trashCommand) {
82
97
  const cmd = trashCommand ?? 'trash';
83
98
  return [
84
99
  START_MARKER,
100
+ `# v${SAFE_DELETE_BLOCK_VERSION}`,
85
101
  `if (Get-Alias rm -ErrorAction SilentlyContinue) {`,
86
102
  ` Remove-Alias rm -Force -Scope Global`,
87
103
  `}`,
88
104
  `function rm {`,
89
105
  ` $files = $args | Where-Object { $_ -notlike '-*' }`,
90
- ` if ($files) { & ${cmd} @files }`,
106
+ ` $existing = $files | Where-Object { Test-Path $_ }`,
107
+ ` if ($existing) { & ${cmd} @existing }`,
91
108
  `}`,
92
109
  END_MARKER,
93
110
  ].join('\n');
@@ -123,6 +140,24 @@ export async function installToProfile(profilePath, block) {
123
140
  const content = existing.length > 0 ? existing + separator + block + '\n' : block + '\n';
124
141
  await fs.writeFile(profilePath, content, 'utf-8');
125
142
  }
143
+ /**
144
+ * Extract the installed safe-delete block version from a profile file.
145
+ * Returns 0 (not installed), 1 (legacy block without version stamp), or N (versioned block).
146
+ */
147
+ export async function getInstalledVersion(profilePath) {
148
+ try {
149
+ const content = await fs.readFile(profilePath, 'utf-8');
150
+ const startIdx = content.indexOf(START_MARKER);
151
+ if (startIdx === -1)
152
+ return 0;
153
+ const afterMarker = content.slice(startIdx + START_MARKER.length);
154
+ const match = afterMarker.match(/^\n# v(\d+)/);
155
+ return match ? parseInt(match[1], 10) : 1;
156
+ }
157
+ catch {
158
+ return 0;
159
+ }
160
+ }
126
161
  /**
127
162
  * Remove the safe-delete block from a profile file.
128
163
  * Returns true if the block was found and removed, false otherwise.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devflow-kit",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Agentic Development Toolkit for Claude Code - Enhance AI-assisted development with intelligent commands and workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "devflow-ambient",
3
+ "description": "Ambient mode — auto-loads relevant skills for every prompt",
4
+ "version": "1.1.0",
5
+ "agents": [],
6
+ "skills": ["ambient-router"]
7
+ }
@@ -0,0 +1,49 @@
1
+ # devflow-ambient
2
+
3
+ Ambient mode — auto-loads relevant skills based on each prompt, no explicit commands needed.
4
+
5
+ ## Command
6
+
7
+ ### `/ambient`
8
+
9
+ Classify user intent and apply proportional skill enforcement to any prompt.
10
+
11
+ ```bash
12
+ /ambient add a login form # BUILD/STANDARD — loads TDD + implementation-patterns
13
+ /ambient fix the auth error # DEBUG/STANDARD — loads test-patterns + core-patterns
14
+ /ambient where is the config? # EXPLORE/QUICK — responds normally, zero overhead
15
+ /ambient refactor the auth system # BUILD/ESCALATE — suggests /implement
16
+ ```
17
+
18
+ ## Always-On Mode
19
+
20
+ Enable ambient classification on every prompt without typing `/ambient`:
21
+
22
+ ```bash
23
+ devflow ambient --enable # Register UserPromptSubmit hook
24
+ devflow ambient --disable # Remove hook
25
+ devflow ambient --status # Check if enabled
26
+ ```
27
+
28
+ When enabled, a `UserPromptSubmit` hook injects a classification preamble before every prompt. Slash commands (`/implement`, `/code-review`, etc.) and short confirmations ("yes", "ok") are skipped automatically.
29
+
30
+ ## How It Works
31
+
32
+ 1. **Classify intent** — BUILD, DEBUG, REVIEW, PLAN, EXPLORE, or CHAT
33
+ 2. **Classify depth** — QUICK (zero overhead), STANDARD (2-3 skills), or ESCALATE (workflow nudge)
34
+ 3. **Apply proportionally**:
35
+ - QUICK: respond normally
36
+ - STANDARD: load relevant skills, enforce TDD for BUILD
37
+ - ESCALATE: respond + recommend full workflow command
38
+
39
+ ## Depth Tiers
40
+
41
+ | Depth | When | Overhead |
42
+ |-------|------|----------|
43
+ | QUICK | Chat, simple exploration, git/devops ops, single-word confirmations | ~0 tokens |
44
+ | STANDARD | BUILD/DEBUG/REVIEW/PLAN, 1-5 file scope | ~500-1000 tokens (skill reads) |
45
+ | ESCALATE | Multi-file, architectural, system-wide scope | ~0 extra tokens (nudge only) |
46
+
47
+ ## Skills
48
+
49
+ - `ambient-router` — Intent + depth classification, skill selection matrix
@@ -0,0 +1,110 @@
1
+ ---
2
+ description: Ambient mode — classify intent and auto-load relevant skills for any prompt
3
+ ---
4
+
5
+ # Ambient Command
6
+
7
+ Classify user intent and auto-load relevant skills. No agents spawned — enhances the main session only.
8
+
9
+ ## Usage
10
+
11
+ ```
12
+ /ambient <prompt> Classify and respond with skill enforcement
13
+ /ambient Show usage
14
+ ```
15
+
16
+ ## Phases
17
+
18
+ ### Phase 1: Load Router
19
+
20
+ Read the `ambient-router` skill:
21
+ - `~/.claude/skills/ambient-router/SKILL.md`
22
+
23
+ ### Phase 2: Classify
24
+
25
+ Apply the ambient-router classification to `$ARGUMENTS`:
26
+
27
+ 1. **Intent:** BUILD | DEBUG | REVIEW | PLAN | EXPLORE | CHAT
28
+ 2. **Depth:** QUICK | STANDARD | ESCALATE
29
+
30
+ If no arguments provided, output:
31
+
32
+ ```
33
+ ## Ambient Mode
34
+
35
+ Classify intent and auto-load relevant skills.
36
+
37
+ Usage: /ambient <your prompt>
38
+
39
+ Examples:
40
+ /ambient add a login form → BUILD/STANDARD (loads TDD + implementation-patterns)
41
+ /ambient fix the auth error → DEBUG/STANDARD (loads test-patterns + core-patterns)
42
+ /ambient where is the config? → EXPLORE/QUICK (responds normally)
43
+ /ambient refactor the auth system → BUILD/ESCALATE (suggests /implement)
44
+
45
+ Always-on: devflow ambient --enable
46
+ ```
47
+
48
+ Then stop.
49
+
50
+ ### Phase 3: State Classification
51
+
52
+ - **QUICK:** Skip this phase entirely. Respond directly in Phase 4.
53
+ - **STANDARD:** Output one line: `Ambient: {INTENT}/{DEPTH}. Loading: {skill1}, {skill2}.`
54
+ - **ESCALATE:** Skip — recommendation happens in Phase 4.
55
+
56
+ ### Phase 4: Apply
57
+
58
+ **QUICK:**
59
+ Respond to the user's prompt normally. Zero skill loading. Zero overhead.
60
+
61
+ **STANDARD:**
62
+ Read the selected skills based on the ambient-router's skill selection matrix:
63
+
64
+ | Intent | Primary Skills | Secondary (conditional) |
65
+ |--------|---------------|------------------------|
66
+ | BUILD | test-driven-development, implementation-patterns | typescript (.ts), react (.tsx), frontend-design (CSS/UI), input-validation (forms/API), security-patterns (auth/crypto) |
67
+ | DEBUG | test-patterns, core-patterns | git-safety (if git ops) |
68
+ | REVIEW | self-review, core-patterns | test-patterns |
69
+ | PLAN | implementation-patterns | core-patterns |
70
+
71
+ Read up to 3 skills from `~/.claude/skills/{name}/SKILL.md`. Apply their patterns and constraints when responding to the user's prompt.
72
+
73
+ For BUILD intent: enforce RED-GREEN-REFACTOR from test-driven-development. Write failing tests before production code.
74
+
75
+ **ESCALATE:**
76
+ Respond to the user's prompt with your best effort, then append:
77
+
78
+ > This task spans multiple files/systems. Consider `/implement` for full lifecycle management (exploration → planning → implementation → review).
79
+
80
+ ## Architecture
81
+
82
+ ```
83
+ /ambient <prompt> (main session, no agents)
84
+
85
+ ├─ Phase 1: Load ambient-router skill
86
+ ├─ Phase 2: Classify intent + depth
87
+ ├─ Phase 3: State classification (STANDARD only)
88
+ └─ Phase 4: Apply
89
+ ├─ QUICK → respond directly
90
+ ├─ STANDARD → load 2-3 skills, apply patterns, respond
91
+ └─ ESCALATE → respond + workflow nudge
92
+ ```
93
+
94
+ ## Edge Cases
95
+
96
+ | Case | Handling |
97
+ |------|----------|
98
+ | No arguments | Show usage and stop |
99
+ | Single word ("help") | Classify — likely CHAT/QUICK |
100
+ | Prompt references `/implement` etc. | Classify as normal — user chose /ambient intentionally |
101
+ | Mixed intent ("fix and add test") | Use higher-overhead intent (BUILD > DEBUG) |
102
+ | User says "no enforcement" | Respect immediately — treat as QUICK |
103
+
104
+ ## Principles
105
+
106
+ 1. **No agents** — Ambient enhances the main session, never spawns subagents
107
+ 2. **Proportional** — QUICK gets zero overhead, STANDARD gets 2-3 skills, ESCALATE gets a nudge
108
+ 3. **Transparent** — State classification for STANDARD/ESCALATE, silent for QUICK
109
+ 4. **Respectful** — Never over-classify; when in doubt, go one tier lower
110
+ 5. **TDD for BUILD** — STANDARD depth BUILD tasks enforce test-first workflow
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: ambient-router
3
+ description: >-
4
+ Classify user intent and response depth for ambient mode. Auto-loads relevant
5
+ skills without explicit command invocation. Used by /ambient command and
6
+ always-on UserPromptSubmit hook.
7
+ user-invocable: false
8
+ allowed-tools: Read, Grep, Glob
9
+ ---
10
+
11
+ # Ambient Router
12
+
13
+ Classify user intent and auto-load relevant skills. Zero overhead for simple requests, skill injection for substantive work, workflow nudges for complex tasks.
14
+
15
+ ## Iron Law
16
+
17
+ > **PROPORTIONAL RESPONSE**
18
+ >
19
+ > Match effort to intent. Never apply heavyweight processes to lightweight requests.
20
+ > A chat question gets zero overhead. A 3-file feature gets 2-3 skills. A system
21
+ > refactor gets a nudge toward `/implement`. Misclassification in either direction
22
+ > is a failure.
23
+
24
+ ---
25
+
26
+ ## Step 1: Classify Intent
27
+
28
+ Determine what the user is trying to do from their prompt.
29
+
30
+ | Intent | Signal Words / Patterns | Examples |
31
+ |--------|------------------------|---------|
32
+ | **BUILD** | "add", "create", "implement", "build", "write", "make" | "add a login form", "create an API endpoint" |
33
+ | **DEBUG** | "fix", "bug", "broken", "failing", "error", "why does" | "fix the auth error", "why is this test failing" |
34
+ | **REVIEW** | "check", "look at", "review", "is this ok", "any issues" | "check this function", "any issues with this?" |
35
+ | **PLAN** | "how should", "design", "architecture", "approach", "strategy" | "how should I structure auth?", "what's the approach for caching?" |
36
+ | **EXPLORE** | "what is", "where is", "find", "show me", "explain", "how does" | "where is the config?", "explain this function" |
37
+ | **CHAT** | greetings, meta-questions, confirmations, short responses | "thanks", "yes", "what can you do?" |
38
+
39
+ **Ambiguous prompts:** Default to the lowest-overhead classification. "Update the README" → BUILD/STANDARD. Git operations like "commit this" → QUICK.
40
+
41
+ ## Step 2: Classify Depth
42
+
43
+ Determine how much enforcement the prompt warrants.
44
+
45
+ | Depth | Criteria | Action |
46
+ |-------|----------|--------|
47
+ | **QUICK** | CHAT intent. EXPLORE with no analytical depth ("where is X?"). Git/devops operations (commit, push, merge, branch, pr, deploy, reinstall). Single-word continuations. | Respond normally. Zero overhead. Do not state classification. |
48
+ | **STANDARD** | BUILD/DEBUG/REVIEW/PLAN intent (any word count). EXPLORE with analytical depth ("analyze our X", "discuss how Y works"). | Read and apply 2-3 relevant skills from the selection matrix below. State classification briefly. |
49
+ | **ESCALATE** | Multi-file architectural change, system-wide scope, > 5 files. Detailed implementation plan (100+ words with plan structure). | Respond at best effort + recommend: "This looks like it would benefit from `/implement` for full lifecycle management." |
50
+
51
+ ## Step 3: Select Skills (STANDARD depth only)
52
+
53
+ Based on classified intent, read the following skills to inform your response.
54
+
55
+ | Intent | Primary Skills | Secondary (if file type matches) |
56
+ |--------|---------------|----------------------------------|
57
+ | **BUILD** | test-driven-development, implementation-patterns | typescript (.ts), react (.tsx/.jsx), frontend-design (CSS/UI), input-validation (forms/API), security-patterns (auth/crypto) |
58
+ | **DEBUG** | test-patterns, core-patterns | git-safety (if git operations involved) |
59
+ | **REVIEW** | self-review, core-patterns | test-patterns |
60
+ | **PLAN** | implementation-patterns | core-patterns |
61
+
62
+ **Excluded from ambient** (review-command-only): review-methodology, complexity-patterns, consistency-patterns, database-patterns, dependencies-patterns, documentation-patterns, regression-patterns, architecture-patterns, accessibility.
63
+
64
+ See `references/skill-catalog.md` for the full skill-to-intent mapping with file pattern triggers.
65
+
66
+ ## Step 4: Apply
67
+
68
+ - **QUICK:** Respond directly. No preamble, no classification statement.
69
+ - **STANDARD:** State classification briefly: `Ambient: BUILD/STANDARD. Loading: test-driven-development, implementation-patterns.` Then read the selected skills and apply their patterns to your response. For BUILD intent, enforce RED-GREEN-REFACTOR from test-driven-development.
70
+ - **ESCALATE:** Respond with your best effort, then append: `> This task spans multiple files/systems. Consider \`/implement\` for full lifecycle (exploration → planning → implementation → review).`
71
+
72
+ ---
73
+
74
+ ## Transparency Rules
75
+
76
+ 1. **QUICK → silent.** No classification output.
77
+ 2. **STANDARD → brief statement.** One line: intent, depth, skills loaded.
78
+ 3. **ESCALATE → recommendation.** Best-effort response + workflow nudge.
79
+ 4. **Never lie about classification.** If uncertain, say so.
80
+ 5. **Never over-classify.** When in doubt, go one tier lower.
81
+
82
+ ## Edge Cases
83
+
84
+ | Case | Handling |
85
+ |------|----------|
86
+ | Mixed intent ("fix this bug and add a test") | Use the higher-overhead intent (BUILD > DEBUG) |
87
+ | Continuation of previous conversation | Inherit previous classification unless prompt clearly shifts |
88
+ | User explicitly requests no enforcement | Respect immediately — classify as QUICK |
89
+ | Prompt references specific DevFlow command | Skip ambient — the command has its own orchestration |