From 9fea97e1c05cacf65da68a73869b91091ca2584d Mon Sep 17 00:00:00 2001 From: Dean Sharon Date: Tue, 2 Jun 2026 23:00:43 +0300 Subject: [PATCH 1/2] docs(ambient): align init/CLI descriptions with keyword detection; tighten preamble directives Ambient mode gained first-word keyword detection (#235) but the init flow, ambient CLI text, plugin description, and README still described plan-only auto-detection. Update all user-facing copy to cover both detection paths (keyword + structured plan). Also tighten the two directives the preamble hook injects: symmetric structure across both paths, explicit input pass-through, and an immediately/do-not-pause instruction to preserve ambient's zero-friction intent. --- README.md | 2 +- scripts/hooks/preamble | 4 ++-- src/cli/commands/ambient.ts | 12 ++++++------ src/cli/commands/init.ts | 9 +++++---- src/cli/plugins.ts | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c3182176..223824c3 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ you: add rate limiting to the /api/upload endpoint ## What you get -**Ambient intelligence.** Devflow detects structured plans for automatic execution — normal prompts get zero overhead, no classification step. You never invoke it manually. Init and forget. +**Ambient intelligence.** Devflow detects workflow intent — start a prompt with `implement`, `explore`, `research`, `debug`, or `plan`, or paste a structured plan, and the matching workflow runs automatically. Normal prompts get zero overhead, no classification step. No slash commands needed. Init and forget. **Memory that persists.** Session context survives restarts, `/clear`, and context compaction. Your AI picks up exactly where it left off. Architectural decisions and known pitfalls accumulate in `.devflow/decisions/` and inform every future session. No manual bookkeeping. diff --git a/scripts/hooks/preamble b/scripts/hooks/preamble index c4c705bf..478e1b56 100755 --- a/scripts/hooks/preamble +++ b/scripts/hooks/preamble @@ -68,10 +68,10 @@ shopt -u nocasematch # prompts and is negligible in practice (~6ms at 200KB). No subprocess required. if [[ -n "$SKILL" && -n "$REST" ]] && ! [[ "$PROMPT" =~ [?][[:space:]]*$ ]]; then dbg "WORKFLOW_KEYWORD detected: $SKILL — injecting directive" - json_prompt_output "The user is invoking the \`$SKILL\` workflow. Briefly tell the user you are invoking \`devflow:$SKILL\`, then invoke it via the Skill tool, passing the user's request (the text after the leading \`$SKILL\` keyword) as the task input." + json_prompt_output "The user's prompt begins with the \`$SKILL\` keyword, which signals the \`devflow:$SKILL\` workflow. In one short sentence, tell the user you're invoking \`devflow:$SKILL\`. Then immediately invoke it with the Skill tool, passing the user's full request (everything after the leading \`$SKILL\` keyword) as the skill input. Do not pause to ask whether to proceed." elif [[ "$PROMPT" == *"## Goal"* ]] && [[ "$PROMPT" == *"## Steps"* ]] && [[ "$PROMPT" == *"## Files"* ]]; then dbg "EXECUTION_PLAN detected — injecting directive" - json_prompt_output "The user supplied a structured implementation plan. Briefly tell the user you are invoking \`devflow:implement\`, then invoke it via the Skill tool to execute this plan." + json_prompt_output "The user's prompt is a structured implementation plan (it contains ## Goal, ## Steps, and ## Files). In one short sentence, tell the user you're invoking \`devflow:implement\`. Then immediately invoke it with the Skill tool, passing the full plan as the skill input so it can be executed. Do not pause to ask whether to proceed." else dbg "No keyword or plan markers detected — no output" fi diff --git a/src/cli/commands/ambient.ts b/src/cli/commands/ambient.ts index 6613d2b6..de96a546 100644 --- a/src/cli/commands/ambient.ts +++ b/src/cli/commands/ambient.ts @@ -83,7 +83,7 @@ export async function addAmbientHook(settingsJson: string, devflowDir: string): const settings: Settings = JSON.parse(settingsJson); let changed = filterHookEntries(settings, 'UserPromptSubmit', isLegacy); - // --- UserPromptSubmit: preamble hook (plan detection) --- + // --- UserPromptSubmit: preamble hook (keyword + plan detection) --- const hasPreamble = settings.hooks?.UserPromptSubmit?.some((m) => m.hooks.some((h) => h.command.includes(PREAMBLE_HOOK_MARKER)), ); @@ -150,7 +150,7 @@ interface AmbientOptions { } export const ambientCommand = new Command('ambient') - .description('Enable or disable ambient mode (plan auto-detection)') + .description('Enable or disable ambient mode (keyword + plan auto-detection)') .option('--enable', 'Register ambient mode hook') .option('--disable', 'Remove ambient mode hook') .option('--status', 'Check if ambient mode is enabled') @@ -159,8 +159,8 @@ export const ambientCommand = new Command('ambient') if (!hasFlag) { p.intro(color.bgMagenta(color.white(' Ambient Mode '))); p.note( - `${color.cyan('devflow ambient --enable')} Register plan detection hook\n` + - `${color.cyan('devflow ambient --disable')} Remove plan detection hook\n` + + `${color.cyan('devflow ambient --enable')} Register detection hook\n` + + `${color.cyan('devflow ambient --disable')} Remove detection hook\n` + `${color.cyan('devflow ambient --status')} Check current state`, 'Usage', ); @@ -219,8 +219,8 @@ export const ambientCommand = new Command('ambient') return; } await fs.writeFile(settingsPath, updated, 'utf-8'); - p.log.success('Ambient mode enabled — plan detection hook registered'); - p.log.info(color.dim('Structured plans auto-execute')); + p.log.success('Ambient mode enabled — detection hook registered'); + p.log.info(color.dim('Keyword prompts and structured plans auto-run their workflow')); } if (options.disable) { diff --git a/src/cli/commands/init.ts b/src/cli/commands/init.ts index a999d987..afa09755 100644 --- a/src/cli/commands/init.ts +++ b/src/cli/commands/init.ts @@ -173,7 +173,7 @@ export const initCommand = new Command('init') .option('--plugin ', 'Install specific plugin(s), comma-separated (e.g., implement,code-review)') .option('--teams', 'Enable Agent Teams (peer debate, adversarial review)') .option('--no-teams', 'Disable Agent Teams (use parallel subagents instead)') - .option('--ambient', 'Enable ambient mode (plan auto-detection)') + .option('--ambient', 'Enable ambient mode (keyword + plan auto-detection)') .option('--no-ambient', 'Disable ambient mode') .option('--memory', 'Enable working memory (session context preservation)') .option('--no-memory', 'Disable working memory hooks') @@ -552,9 +552,10 @@ export const initCommand = new Command('init') ambientEnabled = options.ambient; } else { p.note( - 'Detects implementation plans and auto-executes them.\n' + - 'When the first message is a structured plan, automatically\n' + - 'invokes the implement workflow to execute it.\n\n' + + 'Detects workflow intent in your prompt and runs it automatically.\n' + + 'Start a prompt with implement, explore, research, debug, or plan\n' + + '(or paste a structured plan) and the matching workflow runs —\n' + + 'no slash command needed.\n\n' + 'Zero overhead for normal prompts.', 'Ambient Mode', ); diff --git a/src/cli/plugins.ts b/src/cli/plugins.ts index 1309c34a..b1cb103d 100644 --- a/src/cli/plugins.ts +++ b/src/cli/plugins.ts @@ -144,7 +144,7 @@ export const DEVFLOW_PLUGINS: PluginDefinition[] = [ }, { name: 'devflow-ambient', - description: 'Plan auto-detection', + description: 'Keyword + plan auto-detection', commands: ['/ambient'], agents: ['coder', 'validator', 'simplifier', 'scrutinizer', 'evaluator', 'tester', 'skimmer', 'reviewer', 'git', 'synthesizer', 'resolver', 'designer', 'knowledge', 'researcher'], skills: [ From a88ed0c4eddd51064622f2115fe92a7db2140300 Mon Sep 17 00:00:00 2001 From: Dean Sharon Date: Tue, 2 Jun 2026 23:04:03 +0300 Subject: [PATCH 2/2] test(ambient): update preamble directive assertions to match tightened wording --- tests/shell-hooks.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/shell-hooks.test.ts b/tests/shell-hooks.test.ts index 4a1770b3..3c7b5799 100644 --- a/tests/shell-hooks.test.ts +++ b/tests/shell-hooks.test.ts @@ -1108,9 +1108,11 @@ describe('preamble keyword detection', () => { /** Expected additionalContext message for a matched skill. */ function expectedContext(skill: string): string { return ( - `The user is invoking the \`${skill}\` workflow. Briefly tell the user you are invoking ` + - `\`devflow:${skill}\`, then invoke it via the Skill tool, passing the user's request ` + - `(the text after the leading \`${skill}\` keyword) as the task input.` + `The user's prompt begins with the \`${skill}\` keyword, which signals the ` + + `\`devflow:${skill}\` workflow. In one short sentence, tell the user you're invoking ` + + `\`devflow:${skill}\`. Then immediately invoke it with the Skill tool, passing the user's ` + + `full request (everything after the leading \`${skill}\` keyword) as the skill input. ` + + `Do not pause to ask whether to proceed.` ); } @@ -1198,7 +1200,7 @@ describe('preamble keyword detection', () => { const ctx = parsed.hookSpecificOutput.additionalContext; expect(ctx).toContain('`devflow:research`'); expect(ctx).toContain('Skill tool'); - expect(ctx).toContain('Briefly tell the user'); + expect(ctx).toContain("tell the user you're invoking"); }); });