# Phase 2: Adoption Readiness — Control & Credibility

> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Add control surface depth, migration guidance, and adaptive strategy switching that gives experienced users confidence to adopt the framework for production use.

**Architecture:** Group A (docs) and Group B (code) are fully parallelizable. Group C is sequential: 2.2 (Streaming Progress & Cancellation) MUST complete before 2.8 (Dynamic Strategy Switching) — both modify `kernel-runner.ts`. All code changes are additive — no refactors, no breaking changes. New stream events added to `AgentStreamEvent` union. New builder methods added to `ReactiveAgentBuilder`. New `ToolBuilder` class exported from `@reactive-agents/tools`. New `StrategyEvaluator` in reasoning package.

**Tech Stack:** TypeScript, Effect-TS, bun:test, Starlight/Astro docs

**Spec:** `docs/superpowers/specs/2026-03-11-adoption-readiness-design.md` (items 2.1–2.8)

**Key file references (from exploration):**
- Stream types: `packages/runtime/src/stream-types.ts` (lines 1–66, 9 event variants in `AgentStreamEvent` union)
- Kernel runner: `packages/reasoning/src/strategies/shared/kernel-runner.ts` (lines 1–273, loop detection at lines 128–180, main loop at lines 116–211)
- Kernel state: `packages/reasoning/src/strategies/shared/kernel-state.ts` (lines 1–262, `KernelStatus` at line 18, `KernelState` at lines 22–45, `KernelRunOptions` at lines 144–152, `KernelHooks` at lines 102–108, `noopHooks` at lines 255–261)
- Strategy registry: `packages/reasoning/src/services/strategy-registry.ts` (lines 1–151, `StrategyFn` at lines 24–46, `StrategyRegistry` service at lines 50–78, 5 built-in strategies)
- Tool types: `packages/tools/src/types.ts` (lines 1–749, `ToolDefinition` at lines 88–197, `ToolParameter` at lines 13–78)
- Tool index: `packages/tools/src/index.ts` (lines 1–136)
- Builder: `packages/runtime/src/builder.ts` (builder class at line 663, `ReasoningOptions` at lines 107–114, `ReactiveAgent` at line 2288, field declarations at lines 664–720)
- Errors: `packages/runtime/src/errors.ts` (lines 1–148, `RuntimeErrors` union at lines 60–67, `unwrapError()` at line 79)
- Reasoning config: `packages/reasoning/src/types/config.ts` (lines 1–67, `ReasoningConfig` at line 54, `defaultReasoningConfig` at line 58)
- Reasoning types index: `packages/reasoning/src/types/index.ts` (lines 1–69)
- Docs sidebar: autogenerated from directory structure (no config changes needed in `astro.config.mjs`)

**Critical patterns (from Phase 1 review):**
- `Data.TaggedError`: Takes single object arg, NOT positional. Objects are frozen — use standalone functions, not methods.
- `FiberFailure` detection: Uses `Symbol.for("effect/Runtime/FiberFailure")`, NOT `_tag`.
- Core types: Located in `packages/core/src/types/` (directory with 5 files), NOT `packages/core/src/types.ts`.
- Starlight sidebar: Uses `autogenerate` for guides/, reference/, etc. New pages auto-appear — NO sidebar config changes needed.
- Tests: `import { describe, it, expect } from "bun:test"`, NOT vitest/jest.
- Layer composition: Use `Layer.provide()` for dependencies, NOT `Layer.merge()`.

**Parallelization plan:**
- **Group A** (docs, fully independent): Chunks 1, 3, 4, 7 — can run in parallel with everything
- **Group B** (code, independent): Chunks 5, 6 — can run in parallel with Group A and each other
- **Group C** (sequential): Chunk 2 (2.2) THEN Chunk 8 (2.8) — both modify `kernel-runner.ts`

---

## Chunk 1: Migration Guide — LangChain (Item 2.1)

### Task 1: Write LangChain migration guide

**Files:**
- Create: `apps/docs/src/content/docs/guides/migrating-from-langchain.md`

- [ ] **Step 1: Create migration guide with concept mapping table**

Create `apps/docs/src/content/docs/guides/migrating-from-langchain.md` with frontmatter `title: "Migrating from LangChain.js"` and `description: "Side-by-side guide for moving agents from LangChain.js to Reactive Agents"`.

Content sections:
1. **Concept Mapping Table** — LangChain concept to Reactive Agents equivalent: `ChatOpenAI`/`ChatAnthropic` to `.withProvider()`, `AgentExecutor` to `ReactiveAgent`, `DynamicStructuredTool` to `ToolDefinition` + handler, `BufferMemory`/`ConversationSummaryMemory` to `.withMemory({ tier })`, `RunnableSequence`/`Chain` to reasoning strategies, `CallbackManager` to `.withHook()` (10-phase), `OutputParser` to `OutputFormat` on `AgentResult`.

2. **Agent Creation** — side-by-side code showing LangChain `new ChatOpenAI()` + `AgentExecutor.fromAgentAndTools()` vs Reactive Agents `ReactiveAgents.create().withProvider().withTools().build()`.

3. **Tool Registration** — LangChain `new DynamicStructuredTool({ name, description, schema, func })` vs `{ definition: { name, description, parameters, ... }, handler }`.

4. **Callbacks to Hooks** — LangChain `callbacks: [{ handleLLMStart, handleToolEnd }]` vs `.withHook({ phase, timing, handler })` for all 10 phases.

5. **Memory Setup** — LangChain `new BufferMemory()` vs `.withMemory({ tier: "standard" })` (4-layer memory: working, episodic, procedural, semantic).

6. **Key Differences** — explicit 10-phase lifecycle vs implicit chain, Effect-TS composition vs promises, 5 reasoning strategies, built-in cost/guardrails/verification, EventBus observability.

**Tests:** None (docs only).

**Verify:** `cd apps/docs && npx astro build` — check page appears at `/guides/migrating-from-langchain/`.

---

## Chunk 2: Streaming Progress & Cancellation (Item 2.2)

> **DEPENDENCY:** Must complete before Chunk 8 (Item 2.8). Both modify `kernel-runner.ts`.

### Task 2: Add `IterationProgress` stream event type (~4 tests)

**Files:**
- Modify: `packages/runtime/src/stream-types.ts` (lines 1–66)
- Test: `packages/runtime/tests/stream-types.test.ts` (new)

- [ ] **Step 1: Write failing tests for new stream event types**

Create `packages/runtime/tests/stream-types.test.ts`:
- Test that an `IterationProgress` event object with `{ _tag: "IterationProgress", iteration: 3, maxIterations: 10, toolsCalledThisStep: ["web-search"], status: "thinking" }` is a valid `AgentStreamEvent` (type discrimination works)
- Test that a `StreamCancelled` event object with `{ _tag: "StreamCancelled", reason: "User cancelled", iterationsCompleted: 5 }` is a valid `AgentStreamEvent`
- Test that `StreamCompleted` with `toolSummary` field is valid: `{ _tag: "StreamCompleted", output: "done", metadata: {}, toolSummary: [{ name: "web-search", calls: 2, avgMs: 150 }] }`
- Test type discrimination: `event._tag === "IterationProgress"` narrows to the correct shape (access `event.iteration` without type error)

Run: `cd packages/runtime && bun test tests/stream-types.test.ts`

- [ ] **Step 2: Add `IterationProgress` and `StreamCancelled` to `AgentStreamEvent` union**

In `packages/runtime/src/stream-types.ts`, add two new variants to the `AgentStreamEvent` union type after the `StreamError` variant (~line 32), in the "Always emitted" section:

`IterationProgress` variant with fields: `_tag: "IterationProgress"`, `iteration: number` (1-based), `maxIterations: number`, `toolsCalledThisStep?: readonly string[]`, `status: string`.

`StreamCancelled` variant with fields: `_tag: "StreamCancelled"`, `reason: string`, `iterationsCompleted: number`.

Update the `StreamCompleted` variant to add optional field: `toolSummary?: ReadonlyArray<{ name: string; calls: number; avgMs: number }>`.

Run: `cd packages/runtime && bun test tests/stream-types.test.ts`

### Task 3: Wire `IterationProgress` emission in kernel runner (~4 tests)

**Files:**
- Modify: `packages/reasoning/src/strategies/shared/kernel-state.ts` (`KernelHooks` at lines 102–108, `noopHooks` at lines 255–261)
- Modify: `packages/reasoning/src/strategies/shared/kernel-runner.ts` (main loop at lines 116–211)
- Test: `packages/reasoning/tests/shared/kernel-runner-progress.test.ts` (new)

- [ ] **Step 3: Write failing tests for iteration progress emission**

Create `packages/reasoning/tests/shared/kernel-runner-progress.test.ts`:
- Test that `onIterationProgress` hook is called once per iteration with correct `iteration` count matching `state.iteration`
- Test that `toolsCalledThisStep` contains only tools used in THAT iteration (not cumulative)
- Test that `status` reflects the kernel's status after the step
- Test that progress hook is NOT called after the loop exits (no extra call on "done" or "failed")

Run: `cd packages/reasoning && bun test tests/shared/kernel-runner-progress.test.ts`

- [ ] **Step 4: Add `onIterationProgress` to `KernelHooks` interface and `noopHooks`**

In `packages/reasoning/src/strategies/shared/kernel-state.ts`, add to `KernelHooks` interface (after `onError` at line 107):

```typescript
readonly onIterationProgress: (state: KernelState, toolsThisStep: readonly string[]) => Effect.Effect<void, never>;
```

Add to `noopHooks` (after `onError` at line 260):

```typescript
onIterationProgress: () => Effect.void,
```

- [ ] **Step 5: Emit `onIterationProgress` in kernel runner main loop**

In `packages/reasoning/src/strategies/shared/kernel-runner.ts`, before the while loop (line 116), add `let prevToolsUsed = new Set<string>();`. After the kernel step call at line 121 and scratchpad sync (lines 124–126), but BEFORE loop detection (line 128), add:

```typescript
const toolsThisStep = [...state.toolsUsed].filter(t => !prevToolsUsed.has(t));
yield* hooks.onIterationProgress(state, toolsThisStep);
prevToolsUsed = new Set(state.toolsUsed);
```

Run: `cd packages/reasoning && bun test tests/shared/kernel-runner-progress.test.ts`

### Task 4: Add AbortSignal support to `runStream()` (~4 tests)

**Files:**
- Modify: `packages/runtime/src/builder.ts` (ReactiveAgent.runStream method)
- Test: `packages/runtime/tests/stream-cancellation.test.ts` (new)

- [ ] **Step 6: Write failing tests for AbortSignal cancellation**

Create `packages/runtime/tests/stream-cancellation.test.ts`:
- Test that `runStream(prompt, { signal })` accepts an `AbortSignal` without type error
- Test that aborting the signal mid-stream causes the generator to yield a `StreamCancelled` event
- Test that `StreamCancelled` includes correct `iterationsCompleted` count
- Test that an already-aborted signal yields `StreamCancelled` immediately without starting execution

Run: `cd packages/runtime && bun test tests/stream-cancellation.test.ts`

- [ ] **Step 7: Add `signal` option to `runStream()` method signature**

Find the `runStream()` method on `ReactiveAgent` in `packages/runtime/src/builder.ts`. Update its signature to accept an optional options parameter: `runStream(prompt: string, options?: { signal?: AbortSignal; density?: StreamDensity }): AsyncGenerator<AgentStreamEvent>`. If the method currently accepts `density` as a second parameter, consolidate into the `options` object while keeping backward compatibility.

- [ ] **Step 8: Wire AbortSignal to kill switch and emit StreamCancelled**

In the `runStream()` method body:

1. At the start, check if `options?.signal?.aborted` is already true — if so, yield `StreamCancelled` and return.
2. Set up a cancellation flag and abort listener before the stream loop.
3. Track `IterationProgress` events to count iterations for the `StreamCancelled` event.
4. After each yielded event, check the cancellation flag. If set, invoke `KillSwitchService.stop()` via the managed runtime, yield `StreamCancelled` with the iteration count, clean up the listener, and return.
5. Clean up the listener when the stream completes normally.

Run: `cd packages/runtime && bun test tests/stream-cancellation.test.ts`

### Task 5: Enhance `StreamCompleted` with tool summary (~2 tests)

**Files:**
- Modify: `packages/runtime/src/builder.ts` (where `StreamCompleted` event is constructed)
- Test: `packages/runtime/tests/stream-completed-summary.test.ts` (new)

- [ ] **Step 9: Write failing tests for tool summary in StreamCompleted**

Create `packages/runtime/tests/stream-completed-summary.test.ts`:
- Test that `StreamCompleted` event includes `toolSummary` array when tools were called during execution
- Test that each `toolSummary` entry has `name: string`, `calls: number`, and `avgMs: number` fields

Run: `cd packages/runtime && bun test tests/stream-completed-summary.test.ts`

- [ ] **Step 10: Build tool summary from execution metadata and populate StreamCompleted**

Find where `StreamCompleted` events are constructed in the builder/stream code. Build the `toolSummary` array by grouping tool calls from execution metadata by name, counting calls, and computing average duration. Add the field to the `StreamCompleted` event object.

Run: `cd packages/runtime && bun test tests/stream-completed-summary.test.ts`

**Chunk 2 total: ~14 tests across 4 test files.**

---

## Chunk 3: Production Deployment Checklist (Item 2.3)

### Task 6: Write production checklist guide

**Files:**
- Create: `apps/docs/src/content/docs/guides/production-checklist.md`

- [ ] **Step 1: Create production deployment checklist**

Create `apps/docs/src/content/docs/guides/production-checklist.md` with frontmatter `title: "Production Deployment Checklist"` and `description: "Everything to enable before deploying Reactive Agents to production"`.

Content sections:

1. **Security** — guardrails (`.withGuardrails()`), behavioral contracts, identity/RBAC, tool approval gates (`requiresApproval: true`), `allowedTools` whitelist.

2. **Reliability** — kill switch (`.withKillSwitch()`), max iterations (`.withMaxIterations(N)`, default 10), circuit breaker, execution timeout (`.withTimeout(ms)`), retry policy (`.withRetryPolicy()`).

3. **Cost Control** — cost tracking with budget enforcement (`.withCostTracking()`), pre-flight and per-iteration budget checks, `BudgetExceededError`, complexity routing.

4. **Observability** — metrics dashboard (`.withObservability()`), EventBus auto-wiring, phase timing, tool tracking, `exportMetrics()`.

5. **Error Handling** — global error handler (`.withErrorHandler()`, Item 2.6), `RuntimeErrors` union, `unwrapError()` for clean messages.

6. **Memory** — enhanced memory (`.withMemory({ tier: "enhanced" })`), embedding provider env vars, memory consolidation, experience learning.

7. **Quick Reference Table** — Concern, Builder Method, Default, Production Recommendation.

**Tests:** None (docs only).

**Verify:** `cd apps/docs && npx astro build` — check page appears at `/guides/production-checklist/`.

---

## Chunk 4: Sub-Agent Context Forwarding Documentation (Item 2.4)

### Task 7: Write sub-agent guide

**Files:**
- Create: `apps/docs/src/content/docs/guides/sub-agents.md`

- [ ] **Step 1: Create sub-agents guide**

Create `apps/docs/src/content/docs/guides/sub-agents.md` with frontmatter `title: "Working with Sub-Agents"` and `description: "Delegate tasks to specialized sub-agents with persona control and context forwarding"`.

Content sections:

1. **Overview** — what sub-agents are, architecture (parent delegates via spawn-agent or static agent tools).

2. **Static vs Dynamic Sub-Agents** — static (`.withAgentTool()`, build-time), dynamic (`.withDynamicSubAgents()`, runtime via `spawn-agent` tool), decision tree.

3. **Context Forwarding — What IS Forwarded** — parent tool results + working memory (max 2000 chars), persona steering, `tools` whitelist on `spawn-agent`. Reference: `buildParentContextPrefix()`, `MAX_PARENT_CONTEXT_CHARS`, `ALWAYS_INCLUDE_TOOLS` in `packages/tools/src/adapters/agent-tool-adapter.ts`.

4. **Context Forwarding — Known Limitations** — 2000 char truncation, no scratchpad forwarding, no memory inheritance, sub-agent re-fetches data.

5. **Workarounds** — embed context in instructions, keep sub-agent tasks narrow, use `tools` whitelist.

6. **Persona Control** — static persona config, dynamic LLM-generated persona via `spawn-agent` parameters (`role`, `instructions`, `tone`).

7. **Performance Considerations** — delegate mode ~4x cost for simple tasks, small models struggle, lower `maxIterations` for sub-agents.

**Tests:** None (docs only).

**Verify:** `cd apps/docs && npx astro build` — check page appears at `/guides/sub-agents/`.

---

## Chunk 5: Tool Registration Builder Helper (Item 2.5)

### Task 8: Create `ToolBuilder` class (~8 tests)

**Files:**
- Create: `packages/tools/src/tool-builder.ts`
- Modify: `packages/tools/src/index.ts` (lines 1–136, add export)
- Test: `packages/tools/tests/tool-builder.test.ts` (new)

- [ ] **Step 1: Write failing tests for ToolBuilder**

Create `packages/tools/tests/tool-builder.test.ts` with `import { describe, it, expect } from "bun:test"` and `import { ToolBuilder } from "../src/tool-builder.js"`.

Tests:
1. `new ToolBuilder("my-tool").description("desc").build()` returns `{ definition, handler }` where `definition` has `name: "my-tool"`, `description: "desc"`, `parameters: []`, `riskLevel: "low"`, `timeoutMs: 30_000`, `requiresApproval: false`, `source: "function"`
2. `.param("url", "string", "Dataset URL", { required: true })` adds required parameter
3. `.param("format", "string", "Output format", { required: false, default: "json" })` adds optional parameter with default
4. `.param("type", "string", "Type", { enum: ["a", "b"] })` adds enum constraint
5. `.riskLevel("high")` overrides default risk level
6. `.timeout(60_000)` overrides default timeout
7. `.handler(fn)` stores handler — `result.handler` is the function passed in
8. Building without description throws `Error("ToolBuilder: description is required")`

Run: `cd packages/tools && bun test tests/tool-builder.test.ts`

- [ ] **Step 2: Implement `ToolBuilder` class**

Create `packages/tools/src/tool-builder.ts` importing `ToolDefinition` and `ToolParameter` from `./types.js`.

Class with private fields for all definition properties. Constructor takes `name: string`. Fluent methods: `.description()`, `.param(name, type, description, options?)` (required defaults to false), `.riskLevel()`, `.timeout()`, `.requiresApproval()`, `.returnType()`, `.category()`, `.handler()`. `.build()` validates description is set, returns `{ definition: ToolDefinition, handler?: Function }`.

Defaults: `riskLevel: "low"`, `timeoutMs: 30_000`, `requiresApproval: false`, `source: "function"`. ~60 lines total.

- [ ] **Step 3: Export `ToolBuilder` from package index**

In `packages/tools/src/index.ts`, add after the Types section (~line 24):

```typescript
// ─── Builder ───
export { ToolBuilder } from "./tool-builder.js";
```

Run: `cd packages/tools && bun test tests/tool-builder.test.ts`

**Chunk 5 total: ~8 tests in 1 test file.**

---

## Chunk 6: Global Error Handler (Item 2.6)

### Task 9: Add `.withErrorHandler()` builder method (~6 tests)

**Files:**
- Modify: `packages/runtime/src/builder.ts` (field at ~line 720, method in builder, ReactiveAgent at line 2288)
- Test: `packages/runtime/tests/error-handler.test.ts` (new)

- [ ] **Step 1: Write failing tests for global error handler**

Create `packages/runtime/tests/error-handler.test.ts` with `import { describe, it, expect } from "bun:test"` and `import { ReactiveAgents } from "../src/builder.js"`.

Tests:
1. `.withErrorHandler(handler)` — handler is called when `agent.run()` encounters an execution error
2. Handler receives error with `message` string property
3. Handler receives context with `taskId`, `phase`, `iteration` fields
4. Handler is called but error STILL propagates (run() still rejects)
5. Handler that throws does NOT replace original error
6. No handler configured — errors propagate normally (no regression)

Run: `cd packages/runtime && bun test tests/error-handler.test.ts`

- [ ] **Step 2: Add `_errorHandler` field and `withErrorHandler()` method to builder**

Add private field after `_consolidationConfig` (~line 720): `_errorHandler?` typed as `(error: RuntimeErrors, context: { taskId: string; phase: string; iteration: number; lastStep?: string }) => void`.

Add TSDoc-commented `withErrorHandler()` method that sets the field and returns `this`. Document that the handler cannot prevent error propagation — it is for logging/reporting only.

- [ ] **Step 3: Pass error handler through to ReactiveAgent and wire into run() catch path**

Add `_errorHandler` as a constructor parameter on `ReactiveAgent` (after `_setTaskDescription` at ~line 2321). In `build()`, pass `this._errorHandler` through. In `ReactiveAgent.run()`, in the error handling path, call the handler (wrapped in try/catch so handler exceptions are silently caught and never replace the original error). The handler call should include `taskId`, `phase: "execution"`, and `iteration: 0` in the context.

Run: `cd packages/runtime && bun test tests/error-handler.test.ts`

**Chunk 6 total: ~6 tests in 1 test file.**

---

## Chunk 7: Reasoning Strategy Decision Tree (Item 2.7)

### Task 10: Write strategy decision tree guide

**Files:**
- Create: `apps/docs/src/content/docs/guides/choosing-strategies.md`

- [ ] **Step 1: Create reasoning strategy decision tree guide**

Create `apps/docs/src/content/docs/guides/choosing-strategies.md` with frontmatter `title: "Choosing a Reasoning Strategy"` and `description: "Decision tree and performance characteristics for selecting the right reasoning strategy"`.

Content sections:

1. **Decision Tree** — single-step no tools: use `agent.chat()`. Multi-step with tools: ReAct (default). Structured plan: Plan-Execute-Reflect. Quality-critical: Reflexion. Creative: Tree-of-Thought. Mixed: Adaptive.

2. **Strategy Comparison Table** — columns: Strategy, Avg Tokens, Latency, Iterations, Best For, Min Model Size. Rows: ReAct (Low-Med, Fast, 3-10, tool tasks, 4B+), Plan-Execute (Med-High, Medium, 5-15, structured workflows, 14B+), Reflexion (Medium, Medium, 3-8, factual accuracy, 8B+), ToT (High, Slow, 5-20, creative, 14B+), Adaptive (Varies, Varies, Varies, mixed, 8B+).

3. **Strategy Deep Dives** — subsection per strategy with loop description, strengths, requirements.

4. **Local Model Recommendations** — 4B (ReAct only), 8B (ReAct + Reflexion), 14B (all viable), 70B+ (all, best with Plan-Execute/ToT).

5. **Configuration Examples** — `.withReasoning()`, `.withReasoning({ defaultStrategy: "plan-execute-reflect" })`, `.withReasoning({ defaultStrategy: "adaptive", adaptive: { enabled: true } })`, `.withReasoning({ enableStrategySwitching: true })`.

**Tests:** None (docs only).

**Verify:** `cd apps/docs && npx astro build` — check page appears at `/guides/choosing-strategies/`.

---

## Chunk 8: Dynamic Strategy Switching (Item 2.8)

> **DEPENDENCY:** Chunk 2 (Item 2.2) must be completed first. Both modify `kernel-runner.ts`.

### Task 11: Define `StrategyHandoff` type and evaluation function (~4 tests)

**Files:**
- Create: `packages/reasoning/src/strategies/shared/strategy-evaluator.ts`
- Test: `packages/reasoning/tests/shared/strategy-evaluator.test.ts` (new)

- [ ] **Step 1: Write failing tests for StrategyHandoff and evaluateStrategySwitch**

Create `packages/reasoning/tests/shared/strategy-evaluator.test.ts`:
1. Test `StrategyHandoff` object conforms to interface with all required fields
2. Test `evaluateStrategySwitch()` returns `StrategyEvaluation` with `{ shouldSwitch, recommendedStrategy, reasoning }` using a mock LLM
3. Test evaluator returns `{ shouldSwitch: false }` when all strategies already tried
4. Test evaluator excludes already-tried strategies from the available list

Run: `cd packages/reasoning && bun test tests/shared/strategy-evaluator.test.ts`

- [ ] **Step 2: Create `strategy-evaluator.ts` with types and evaluation function**

Create `packages/reasoning/src/strategies/shared/strategy-evaluator.ts` importing from `effect`, `@reactive-agents/llm-provider`, and `./kernel-state.js`.

Define `StrategyHandoff` interface: `originalTask`, `previousStrategy`, `stepsCompleted`, `toolsCalled` (readonly string[]), `keyObservations` (readonly string[]), `failureReason`, `switchNumber`.

Define `StrategyEvaluation` interface: `shouldSwitch` (boolean), `recommendedStrategy` (string), `reasoning` (string).

Implement `evaluateStrategySwitch(state, task, availableStrategies, triedStrategies)` returning `Effect.Effect<StrategyEvaluation, never, LLMService>`:
1. Filter out tried strategies from available. If none left, return `shouldSwitch: false`.
2. Extract last 5 observation steps from state.
3. Build concise prompt asking LLM to evaluate whether switching would help. Include task, current strategy, steps completed, failure reason, observations, and available alternatives.
4. Call `LLMService.complete()`, parse JSON response (with try/catch fallback to `shouldSwitch: false`).
5. Validate recommended strategy is in alternatives list.

Run: `cd packages/reasoning && bun test tests/shared/strategy-evaluator.test.ts`

### Task 12: Implement `buildHandoff()` helper (~3 tests)

**Files:**
- Modify: `packages/reasoning/src/strategies/shared/strategy-evaluator.ts`
- Test: `packages/reasoning/tests/shared/strategy-evaluator.test.ts` (extend)

- [ ] **Step 3: Write failing tests for buildHandoff**

Add to test file:
1. Test `buildHandoff()` extracts observation step content from `state.steps` (last 5)
2. Test `buildHandoff()` converts `state.toolsUsed` ReadonlySet to a plain array
3. Test `buildHandoff()` sets `switchNumber` to the provided value

- [ ] **Step 4: Implement `buildHandoff()` function**

Add `buildHandoff(state, task, failureReason, switchNumber): StrategyHandoff` to `strategy-evaluator.ts`. Extracts observations from state steps (filter type "observation", slice last 5, map to content). Converts `toolsUsed` Set to array via spread. Returns complete `StrategyHandoff` object. ~15 lines.

Run: `cd packages/reasoning && bun test tests/shared/strategy-evaluator.test.ts`

### Task 13: Add `"evaluating"` to `KernelStatus` and strategy switching config (~2 tests)

**Files:**
- Modify: `packages/reasoning/src/strategies/shared/kernel-state.ts` (`KernelStatus` at line 18, `KernelRunOptions` at lines 144–152)
- Test: `packages/reasoning/tests/shared/kernel-state-evaluating.test.ts` (new)

- [ ] **Step 5: Write failing tests for new KernelStatus and options**

Create `packages/reasoning/tests/shared/kernel-state-evaluating.test.ts`:
1. Test `transitionState(state, { status: "evaluating" })` produces state with `status === "evaluating"`
2. Test `KernelRunOptions` accepts `strategySwitching` field with `enabled`, `maxSwitches`, `fallbackStrategy`, `availableStrategies`

Run: `cd packages/reasoning && bun test tests/shared/kernel-state-evaluating.test.ts`

- [ ] **Step 6: Extend KernelStatus and KernelRunOptions**

Change `KernelStatus` (line 18) from `"thinking" | "acting" | "observing" | "done" | "failed"` to add `| "evaluating"`.

Add `strategySwitching?` field to `KernelRunOptions` (after `loopDetection?` at line 151): object with `enabled: boolean`, `maxSwitches?: number`, `fallbackStrategy?: string`, `availableStrategies?: readonly string[]`. Add TSDoc comments on each field.

Note: `"evaluating"` is neither `"done"` nor `"failed"`, so the kernel runner while loop naturally continues without changes.

Run: `cd packages/reasoning && bun test tests/shared/kernel-state-evaluating.test.ts`

### Task 14: Wire strategy switching into kernel runner loop detection (~8 tests)

**Files:**
- Modify: `packages/reasoning/src/strategies/shared/kernel-runner.ts` (lines 128–180 — loop detection section)
- Test: `packages/reasoning/tests/shared/kernel-runner-switching.test.ts` (new)

- [ ] **Step 7: Write failing tests for strategy switching in kernel runner**

Create `packages/reasoning/tests/shared/kernel-runner-switching.test.ts`:
1. Loop detection with `strategySwitching.enabled: true` transitions to `"evaluating"` then new strategy (not `"failed"`)
2. Evaluator `shouldSwitch: true` re-initializes kernel with new strategy and handoff context
3. Evaluator `shouldSwitch: false` transitions to `"failed"` as before
4. `maxSwitches` enforced — after N switches, loop detection goes to `"failed"`
5. `fallbackStrategy` set skips evaluator LLM call, switches directly
6. Already-tried strategies excluded from evaluator's available list
7. Handoff context injected as `priorContext` with observations
8. Switch count tracked correctly across multiple switches

Run: `cd packages/reasoning && bun test tests/shared/kernel-runner-switching.test.ts`

- [ ] **Step 8: Extract loop detection into a helper function**

Extract lines 128–180 of `kernel-runner.ts` into a pure function `detectLoop(state, config): string | null` that returns the error message if a loop is detected, or null. Moves checks (a) repeated tool calls, (b) repeated thoughts, (c) consecutive thoughts into the helper. Replace inline block with a call to `detectLoop()`. Verify all existing tests pass.

Run: `cd packages/reasoning && bun test`

- [ ] **Step 9: Add strategy switching path after loop detection**

Add tracking variables before the while loop: `let switchCount = 0`, `const triedStrategies: string[] = [options.strategy]`. Add import for `evaluateStrategySwitch` and `buildHandoff` from `./strategy-evaluator.js`.

Replace the simple `"failed"` transition after `detectLoop()` with the strategy switching path:
- If `switchCfg?.enabled` and `switchCount < maxSwitches`: check `fallbackStrategy` (direct switch) or run evaluator (LLM decides).
- If evaluator says switch: build handoff context from state, fire `onStrategySwitched` hook, re-initialize state with `initialKernelState()` using new strategy, carry forward `toolsUsed`, inject handoff as `priorContext` via cast `(input as any).priorContext = ...`, increment `switchCount`, push to `triedStrategies`, `continue`.
- If evaluator says don't switch or switching disabled: transition to `"failed"` and `break`.

Note on `input` mutation: `KernelInput` is readonly, but handoff injection requires a cast. This is acceptable for this scope; a cleaner mutable context wrapper is a future refactor.

Run: `cd packages/reasoning && bun test tests/shared/kernel-runner-switching.test.ts`

### Task 15: Add EventBus hooks for strategy switching (~3 tests)

**Files:**
- Modify: `packages/reasoning/src/strategies/shared/kernel-state.ts` (`KernelHooks`, `noopHooks`)
- Modify: `packages/reasoning/src/strategies/shared/kernel-hooks.ts` (wire EventBus events)
- Test: `packages/reasoning/tests/shared/kernel-runner-switching.test.ts` (extend)

- [ ] **Step 10: Write failing tests for strategy switch event hooks**

Add to `kernel-runner-switching.test.ts`:
1. `onStrategySwitchEvaluated` hook called when evaluator runs (receives evaluation)
2. `onStrategySwitched` hook called on switch (receives `from`, `to`, reason)
3. Neither hook called when `strategySwitching.enabled: false`

- [ ] **Step 11: Add strategy switch hooks to `KernelHooks` and `noopHooks`**

Add to `KernelHooks`: `onStrategySwitchEvaluated(state, evaluation)` and `onStrategySwitched(state, from, to, reason)`, both returning `Effect.Effect<void, never>`.

Add noop implementations to `noopHooks`.

In `kernel-hooks.ts`, wire hooks to publish EventBus events: `StrategySwitchEvaluated` (includes evaluation, strategy, taskId, timestamp) and `StrategySwitched` (from, to, reason, taskId, timestamp).

Run: `cd packages/reasoning && bun test tests/shared/kernel-runner-switching.test.ts`

### Task 16: Add builder configuration for strategy switching (~4 tests)

**Files:**
- Modify: `packages/runtime/src/builder.ts` (`ReasoningOptions` at lines 107–114, builder wiring)
- Test: `packages/runtime/tests/strategy-switching-builder.test.ts` (new)

- [ ] **Step 12: Write failing tests for builder integration**

Create `packages/runtime/tests/strategy-switching-builder.test.ts`:
1. `.withReasoning({ enableStrategySwitching: true })` accepted
2. `.withReasoning({ maxStrategySwitches: 2 })` accepted
3. `.withReasoning({ fallbackStrategy: "plan-execute-reflect" })` accepted
4. `.withReasoning()` without options — `enableStrategySwitching` defaults to `false`

Run: `cd packages/runtime && bun test tests/strategy-switching-builder.test.ts`

- [ ] **Step 13: Extend `ReasoningOptions` with strategy switching fields**

Add three new optional fields to `ReasoningOptions` (lines 107–114): `enableStrategySwitching?: boolean` (default false), `maxStrategySwitches?: number` (default 1), `fallbackStrategy?: ReasoningConfig["defaultStrategy"]`. Add TSDoc on each.

- [ ] **Step 14: Wire strategy switching config through to kernel runner**

Thread the 3 new fields from `builder._reasoningOptions` through `createRuntime()` config to `KernelRunOptions.strategySwitching`. Follow the existing pattern for how `maxIterations` and `loopDetection` flow from builder to kernel runner. In `build()`, construct `strategySwitching: { enabled, maxSwitches, fallbackStrategy }` when `enableStrategySwitching` is true.

Run: `cd packages/runtime && bun test tests/strategy-switching-builder.test.ts`

### Task 17: Export new types from package indices (~0 tests)

**Files:**
- Modify: `packages/reasoning/src/index.ts` or appropriate barrel export

- [ ] **Step 15: Add re-exports for new public types**

Export `StrategyHandoff`, `StrategyEvaluation` (as types), and `buildHandoff`, `evaluateStrategySwitch` (as values) from the reasoning package's public API. Add to `packages/reasoning/src/index.ts` under a `Strategy Switching` section.

Run: `cd packages/reasoning && bun run build` — verify build succeeds with new exports.

**Chunk 8 total: ~24 tests across 4 test files.**

---

## Summary

| Chunk | Item | Type | Tests | Group | Dependency |
|-------|------|------|-------|-------|------------|
| 1 | 2.1 Migration Guide (LangChain) | docs | 0 | A | none |
| 2 | 2.2 Streaming Progress & Cancellation | code | ~14 | C | none (must finish before Chunk 8) |
| 3 | 2.3 Production Deployment Checklist | docs | 0 | A | none |
| 4 | 2.4 Sub-Agent Context Forwarding Docs | docs | 0 | A | none |
| 5 | 2.5 Tool Registration Builder Helper | code | ~8 | B | none |
| 6 | 2.6 Global Error Handler | code | ~6 | B | none |
| 7 | 2.7 Reasoning Strategy Decision Tree | docs | 0 | A | none |
| 8 | 2.8 Dynamic Strategy Switching | code | ~24 | C | Chunk 2 (2.2) must complete first |

**Total estimated new tests: ~52**
**Total estimated new/modified files: ~20**

**Optimal execution order:**
1. Run Chunks 1, 3, 4, 5, 6, 7 in parallel (all independent)
2. Run Chunk 2 in parallel with step 1 (independent of other code chunks)
3. After Chunk 2 completes, run Chunk 8 (depends on 2.2's changes to kernel-runner.ts)
