Skip to content

Commit 7091f0e

Browse files
dean0xDean Sharon
andauthored
fix(ambient): ensure skill tool invocations happen before text output (#158)
## Summary - Ambient mode skills were not loading despite correct GUIDED/ORCHESTRATED classification - Root cause: model prints "Loading: X, Y" text then skips actual `Skill()` tool calls — generating prose overrides the tool-call requirement - Fix: reverse instruction order in ambient-router SKILL.md and hook preamble so Skill tool invocations must happen **before** any text output ## Changes - `shared/skills/ambient-router/SKILL.md` — IMPORTANT block and Step 4 now require tool calls first, classification text after - `scripts/hooks/ambient-prompt` — preamble reinforces "FIRST tool calls MUST be Skill tool invocations" - `tests/integration/helpers.ts` — sync preamble string - `tests/ambient.test.ts` — sync drift detection expected value - `CHANGELOG.md` — add fix to [Unreleased] ## Test plan - [x] Build passes (`npm run build`) - [x] All 362 tests pass (`npm test`) - [x] Preamble drift detection test passes (verifies hook ↔ helpers sync) Co-authored-by: Dean Sharon <deanshrn@gmain.com>
1 parent 5d5ac50 commit 7091f0e

5 files changed

Lines changed: 11 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
- **Ambient mode**: skills not loading despite correct classification — reordered instructions so Skill tool invocations happen before any text output
12+
1013
---
1114

1215
## [1.8.1] - 2026-03-22

scripts/hooks/ambient-prompt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ fi
4040

4141
# Inject classification preamble
4242
# SYNC: must match tests/integration/helpers.ts AMBIENT_PREAMBLE
43-
PREAMBLE="AMBIENT MODE ACTIVE: Before responding, silently classify this prompt using the ambient-router skill already in your session context. If QUICK, respond normally without stating classification. If GUIDED or ORCHESTRATED, you MUST load the selected skills using the Skill tool before proceeding."
43+
PREAMBLE="AMBIENT MODE ACTIVE: Before responding, silently classify this prompt using the ambient-router skill already in your session context. If QUICK, respond normally without stating classification. If GUIDED or ORCHESTRATED, your FIRST tool calls MUST be Skill tool invocations for each selected skill — before writing ANY text about the task."
4444

4545
jq -n --arg ctx "$PREAMBLE" '{
4646
"hookSpecificOutput": {

shared/skills/ambient-router/SKILL.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,18 @@ See `references/skill-catalog.md` for the full skill-to-intent mapping with file
8787
<IMPORTANT>
8888
When classification is GUIDED or ORCHESTRATED, skill loading is NON-NEGOTIABLE.
8989
Do not rationalize skipping skills. Do not respond without loading them first.
90-
BLOCKING REQUIREMENT: Invoke each selected skill using the Skill tool before proceeding.
90+
BLOCKING REQUIREMENT: Your FIRST tool calls MUST be Skill tool invocations — before
91+
writing ANY text about the task. Invoke all selected skills, THEN state classification,
92+
THEN proceed with work. Do NOT write implementation text before all Skill tools return.
9193
For IMPLEMENT intent, enforce TDD: write the failing test before ANY production code.
9294
NOTE: Skills loaded in the main session via ambient mode are reference patterns only —
9395
their allowed-tools metadata does NOT restrict your tool access. You retain full access
9496
to all tools (Edit, Write, Bash, Agent, etc.) for implementation work.
9597
</IMPORTANT>
9698

9799
- **QUICK:** Respond directly. No preamble, no classification statement.
98-
- **GUIDED:** State classification briefly: `Ambient: IMPLEMENT/GUIDED. Loading: implementation-patterns, search-first.` Then invoke each skill using the Skill tool and work directly in main session. After code changes, spawn Simplifier on changed files.
99-
- **ORCHESTRATED:** State classification briefly: `Ambient: IMPLEMENT/ORCHESTRATED. Loading: implementation-orchestration, implementation-patterns.` Then invoke each skill using the Skill tool and follow Step 5 for agent orchestration.
100+
- **GUIDED:** First, invoke each selected skill using the Skill tool. After all Skill tools return, state classification briefly: `Ambient: IMPLEMENT/GUIDED. Loading: implementation-patterns, search-first.` Then work directly in main session. After code changes, spawn Simplifier on changed files.
101+
- **ORCHESTRATED:** First, invoke each selected skill using the Skill tool. After all Skill tools return, state classification briefly: `Ambient: IMPLEMENT/ORCHESTRATED. Loading: implementation-orchestration, implementation-patterns.` Then follow Step 5 for agent orchestration.
100102

101103
### GUIDED Behavior by Intent
102104

tests/ambient.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ describe('preamble drift detection', () => {
260260
// The helpers.ts AMBIENT_PREAMBLE is used by extractIntent/extractDepth etc.
261261
// We verify it indirectly by checking the shell script value matches expected.
262262
const expectedPreamble =
263-
'AMBIENT MODE ACTIVE: Before responding, silently classify this prompt using the ambient-router skill already in your session context. If QUICK, respond normally without stating classification. If GUIDED or ORCHESTRATED, you MUST load the selected skills using the Skill tool before proceeding.';
263+
'AMBIENT MODE ACTIVE: Before responding, silently classify this prompt using the ambient-router skill already in your session context. If QUICK, respond normally without stating classification. If GUIDED or ORCHESTRATED, your FIRST tool calls MUST be Skill tool invocations for each selected skill — before writing ANY text about the task.';
264264

265265
expect(shellPreamble).toBe(expectedPreamble);
266266
});

tests/integration/helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function isClaudeAvailable(): boolean {
1717

1818
// SYNC: must match scripts/hooks/ambient-prompt line 43
1919
const AMBIENT_PREAMBLE =
20-
'AMBIENT MODE ACTIVE: Before responding, silently classify this prompt using the ambient-router skill already in your session context. If QUICK, respond normally without stating classification. If GUIDED or ORCHESTRATED, you MUST load the selected skills using the Skill tool before proceeding.';
20+
'AMBIENT MODE ACTIVE: Before responding, silently classify this prompt using the ambient-router skill already in your session context. If QUICK, respond normally without stating classification. If GUIDED or ORCHESTRATED, your FIRST tool calls MUST be Skill tool invocations for each selected skill — before writing ANY text about the task.';
2121

2222
/**
2323
* Run a prompt through claude CLI in non-interactive mode.

0 commit comments

Comments
 (0)