Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .claude/skills/wizard-development/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,11 @@ only when it gives a real owner a smaller, reusable boundary.

## Lifecycle and security

[runner/index.ts](../../../src/lib/agent/runner/index.ts) bootstraps, resolves a
binding, and dispatches to a sequence. `agent-runner.ts` is a compatibility
[runner/index.ts](../../../src/lib/agent/runner/index.ts) exports
`runAgent(config, input, options)`: it prepares the run and dispatches to the
sequence the binding names, reporting through `onProgress` and asking through
`interaction`. Gates, authentication and binding resolution live in
`src/lib/programs/run-agent-legacy.ts`. `agent-runner.ts` is a compatibility
re-export, not the implementation. Sequences own their lifecycle; harnesses own
SDK calls. `ProgramRun.postRun`, `buildOutroData`, `customPrompt`, and
`abortCases` are consumed by the linear sequence, not by the orchestrator. Put
Expand Down
50 changes: 31 additions & 19 deletions .claude/skills/wizard-development/references/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,27 @@ readiness hooks, and traverse steps and gates.
detection in `onReady`. Noninteractive execution has its own lifecycle in
[run-non-interactive.ts](../../../../src/lib/runners/run-non-interactive.ts).

[runner/index.ts](../../../../src/lib/agent/runner/index.ts) resolves a
program's `run` definition, calls shared bootstrap, selects a binding,
dispatches the sequence, and flushes the scanner report on cleanup. The old
[runner/index.ts](../../../../src/lib/agent/runner/index.ts) exports
`runAgent(config, input, options)`: it prepares the run, dispatches the sequence
the binding names, flushes the scanner report and returns a `RunResult`. It
reports through `options.onProgress` and asks through `options.interaction`; it
never calls `getUI()`, reads a session or exits.
[run-agent-legacy.ts](../../../../src/lib/programs/run-agent-legacy.ts) is the
caller today's runners use: it runs the gates, authenticates, resolves the
binding from [bindings.ts](../../../../src/lib/programs/bindings.ts), builds the
agent's inputs from the session, maps progress back onto `getUI()` and hands a
decided failure to `wizardAbort`.
[agent-runner.ts](../../../../src/lib/agent/agent-runner.ts) is a compatibility
export.
export of the agent's contracts.

| Layer | Source and responsibility |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Bootstrap | [shared/bootstrap.ts](../../../../src/lib/agent/runner/shared/bootstrap.ts): shared health/settings/auth/flag and MCP setup |
| Switchboard | [switchboard/index.ts](../../../../src/lib/agent/runner/switchboard/index.ts): resolve sequence, harness, model and effort override |
| Linear sequence | [sequence/linear.ts](../../../../src/lib/agent/runner/sequence/linear.ts): one conversation, skill/prompt assembly, post-run hooks and outro |
| Orchestrator | [orchestrator-runner.ts](../../../../src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts): seed plan, task queue, focused conversations, handoffs and completion |
| Harness | [harness/types.ts](../../../../src/lib/agent/runner/harness/types.ts): SDK boundary, implemented by Pi and Anthropic |
| Layer | Source and responsibility |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Contracts | [shared/types.ts](../../../../src/lib/agent/runner/shared/types.ts) and [progress.ts](../../../../src/lib/agent/progress.ts): `RunConfig`, `RunInput`, `RunResult`, `AgentProgress`, `AgentInteraction` |
| Prepare | [shared/bootstrap.ts](../../../../src/lib/agent/runner/shared/bootstrap.ts): logging targets, gateway mint, scan triage |
| Switchboard | [switchboard/index.ts](../../../../src/lib/agent/runner/switchboard/index.ts): resolve sequence, harness, model and effort override |
| Linear sequence | [sequence/linear.ts](../../../../src/lib/agent/runner/sequence/linear.ts): one conversation, skill/prompt assembly, post-run hooks and outro |
| Orchestrator | [orchestrator-runner.ts](../../../../src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts): seed plan, task queue, focused conversations, handoffs and completion |
| Harness | [harness/types.ts](../../../../src/lib/agent/runner/harness/types.ts): SDK boundary, implemented by Pi and Anthropic |

The contribution policy is
[Pi by default, orchestration preferred](../SKILL.md#execution-policy-and-model-admission).
Expand Down Expand Up @@ -135,16 +143,20 @@ credentials.

## UI state and agent output

Business logic uses [WizardUI](../../../../src/ui/wizard-ui.ts) through
`getUI()`. [InkUI](../../../../src/ui/tui/ink-ui.ts) updates the TUI store;
[LoggingUI](../../../../src/ui/logging-ui.ts) is available for noninteractive
callers that select it. A missing TTY does not automatically mean an arbitrary
caller uses LoggingUI; snapshot CI drives Ink in a PTY. `requestQuestion` and
task notices are supported interactions, not console prompts to invent in
business logic.
Business logic outside the agent uses
[WizardUI](../../../../src/ui/wizard-ui.ts) through `getUI()`. The agent
(`src/lib/agent`) reports through `AgentProgress` events instead, and the
reducer in
[run-agent-legacy.ts](../../../../src/lib/programs/run-agent-legacy.ts) maps
each event to one `WizardUI` call. [InkUI](../../../../src/ui/tui/ink-ui.ts)
updates the TUI store; [LoggingUI](../../../../src/ui/logging-ui.ts) is
available for noninteractive callers that select it. A missing TTY does not
automatically mean an arbitrary caller uses LoggingUI; snapshot CI drives Ink in
a PTY. `requestQuestion` and task notices are supported interactions, not
console prompts to invent in business logic.

Harness adapters translate SDK messages, status markers, task updates and tool
activity into WizardUI calls. Anthropic message processing lives in
activity into progress events. Anthropic message processing lives in
[agent-interface.ts](../../../../src/lib/agent/agent-interface.ts); Pi uses its
own session event handlers. Orchestrated tasks also have queue and handoff
state. Do not assume all harness output passes through `handleSDKMessage`.
Expand Down
13 changes: 8 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ aliases.

| Subcommand | What it audits |
| ----------------------------- | ---------------------------------------------------- |
| `wizard audit events` | event capture quality + cost |
| `wizard audit all` | comprehensive audit across every area (**default**) |
| `wizard audit events` | event capture quality + cost |
| `wizard audit all` | comprehensive audit across every area (**default**) |
| `wizard audit autocapture` | autocapture setup + cost |
| `wizard audit feature-flags` | feature flag usage + cost |
| `wizard audit identify` | `$identify` implementation |
Expand Down Expand Up @@ -170,8 +170,8 @@ nonmutating lint checks, and scope formatting fixes to edited files. Do not add
tests for prose, compiler-enforced shapes, or duplicated implementation. Keep
new code comments to one line; put longer explanations in linked docs.

Local `--ci`, smoke-test, and full headless runs require two separate secrets:
a PostHog personal API key and an already-issued gateway token supplied through
Local `--ci`, smoke-test, and full headless runs require two separate secrets: a
PostHog personal API key and an already-issued gateway token supplied through
`WIZARD_CI_GATEWAY_TOKEN_FILE`, plus the target project ID. Follow the
[credential setup](docs/local-dev.md#credentials-for-local-ci-and-headless-runs).

Expand All @@ -196,7 +196,10 @@ wizard run points. Full catalog: [`docs/local-dev.md`](docs/local-dev.md).
- TypeScript everywhere. Use `type` (not `interface`) for framework context
types so they satisfy `Record<string, unknown>`.
- All UI calls go through `getUI()` (returns `WizardUI` interface). Never import
the store directly from business logic.
the store directly from business logic. The agent (`src/lib/agent`) is the
exception: it reports through `AgentProgress` events and asks through
`AgentInteraction`, and never imports `src/ui` (the architecture test enforces
this).
- Session mutations go through explicit store setters that call `emitChange()`.
Never mutate `session` directly — nanostore holds a shallow copy.
- The router resolves the active screen from session state. No imperative
Expand Down
4 changes: 2 additions & 2 deletions scripts/tui-host.no-jest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ import type { Harness, Sequence } from '@lib/constants';
import { buildSession } from '@lib/wizard-session';
import { initLocalDev } from '@lib/local-dev';
import { configureGatewayFromCIEnvironment } from '@lib/gateway-session';
import { runAgent } from '@lib/agent/agent-runner';
import { runAgent } from '@lib/programs/run-agent-legacy';
import { TaskStreamPush, createFileDestination } from '@lib/task-stream/index';
import { getAuditChecks } from '@lib/programs/audit/types';
import { authenticate } from '@lib/agent/runner/shared/authenticate';
import { authenticate } from '@lib/programs/authenticate';
import { getOrAskForProjectData } from '@utils/setup-utils';
import { logToFile } from '@utils/debug';
import { join } from 'path';
Expand Down
5 changes: 5 additions & 0 deletions src/__tests__/architecture/import-boundaries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@ function analyze(): Analysis {

const to = classifySurface(target);
if (!allowed.includes(to)) violations.set(key, `matrix:${from}->${to}`);
// The agent reports through `onProgress` and asks through
// `AgentInteraction`; it never reaches for a renderer, not even a type.
if (from === 'agent' && target.startsWith('src/ui/')) {
violations.set(key, 'agent-imports-ui');
}
}
}

Expand Down
30 changes: 9 additions & 21 deletions src/__tests__/architecture/known-violations.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,39 @@
"violations": [
"src/commands/factories/family-picker.tsx -> src/commands/command.ts",
"src/env.ts -> src/lib/headless-mode.ts",
"src/lib/agent/mcp-prompt-streaming.ts -> src/ui/tui/services/mcp-suggested-prompts-services.ts",
"src/lib/detection/agentic.ts -> src/lib/agent/agent-interface.ts",
"src/lib/detection/project-scope.ts -> src/lib/agent/runner/shared/authenticate.ts",
"src/lib/errors/agent-map.ts -> src/lib/agent/signals.ts",
"src/lib/programs/agent-skill/index.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/agent-skill/index.ts -> src/lib/programs/agent-skill/content/index.tsx",
"src/lib/programs/ai-observability/index.ts -> src/lib/programs/agent-skill/content/index.tsx",
"src/lib/programs/audit/detect.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/audit/index.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/bindings.ts -> src/lib/agent/runner/switchboard/index.ts",
"src/lib/programs/dispatch-family.ts -> src/commands/command.ts",
"src/lib/programs/dispatch-family.ts -> src/commands/factories/shared.ts",
"src/lib/programs/error-tracking-upload-source-maps/detect.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/error-tracking-upload-source-maps/index.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/error-tracking-upload-source-maps/index.ts -> src/lib/programs/error-tracking-upload-source-maps/content/index.tsx",
"src/lib/programs/error-tracking-upload-source-maps/prompt.ts -> src/lib/agent/agent-interface.ts",
"src/lib/programs/error-tracking/index.ts -> src/lib/agent/runner/shared/types.ts",
"src/lib/programs/error-tracking/index.ts -> src/lib/programs/error-tracking/content/index.tsx",
"src/lib/programs/error-tracking/index.ts -> src/lib/programs/error-tracking/content/tips.ts",
"src/lib/programs/events-audit/index.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/mcp-analytics/index.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/metrics/index.ts -> src/lib/programs/agent-skill/content/index.tsx",
"src/lib/programs/migration/index.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/migration/index.ts -> src/lib/programs/migration/content/index.tsx",
"src/lib/programs/posthog-integration/index.ts -> src/lib/agent/agent-interface.ts",
"src/lib/programs/posthog-integration/index.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/posthog-integration/index.ts -> src/lib/agent/runner/shared/bootstrap.ts",
"src/lib/programs/posthog-integration/index.ts -> src/lib/programs/posthog-integration/content/index.tsx",
"src/lib/programs/program-registry.ts -> src/lib/programs/agent-skill/content/index.tsx",
"src/lib/programs/program-step.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/program-run.ts -> src/lib/agent/runner/shared/types.ts",
"src/lib/programs/program-step.ts -> src/ui/tui/components/TipsCard.tsx",
"src/lib/programs/program-step.ts -> src/ui/tui/primitives/index.ts",
"src/lib/programs/program-step.ts -> src/ui/tui/store.ts",
"src/lib/programs/replay-vision/index.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/revenue-analytics/detect.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/revenue-analytics/index.ts -> src/lib/programs/revenue-analytics/content/index.tsx",
"src/lib/programs/self-driving/detect.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/self-driving/index.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/run-agent-legacy.ts -> src/lib/agent/agent-interface.ts",
"src/lib/programs/run-agent-legacy.ts -> src/lib/agent/claude-settings.ts",
"src/lib/programs/run-agent-legacy.ts -> src/lib/agent/progress.ts",
"src/lib/programs/run-agent-legacy.ts -> src/lib/agent/runner/index.ts",
"src/lib/programs/run-agent-legacy.ts -> src/lib/agent/runner/switchboard/index.ts",
"src/lib/programs/run-agent-legacy.ts -> src/lib/yara-hooks.ts",
"src/lib/programs/self-driving/index.ts -> src/lib/programs/self-driving/content/index.tsx",
"src/lib/programs/self-driving/index.ts -> src/lib/programs/self-driving/content/pricing.ts",
"src/lib/programs/self-driving/index.ts -> src/lib/programs/self-driving/content/tips.ts",
"src/lib/programs/self-driving/prompt.ts -> src/lib/agent/agent-interface.ts",
"src/lib/programs/self-driving/prompt.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/warehouse-source/detect.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/warehouse-source/index.ts -> src/lib/agent/agent-runner.ts",
"src/lib/programs/warehouse-source/index.ts -> src/lib/programs/warehouse-source/content/index.tsx",
"src/lib/programs/web-analytics-doctor/detect.ts -> src/lib/agent/agent-runner.ts",
"src/lib/task-stream/event-plan-watcher.ts -> src/ui/tui/store.ts",
"src/lib/task-stream/task-stream-push.ts -> src/ui/tui/store.ts",
"src/lib/wizard-session.ts -> src/lib/agent/claude-settings.ts",
Expand All @@ -69,6 +56,7 @@
"src/ui/tui/store.ts -> src/lib/agent/claude-settings.ts",
"src/ui/tui/store.ts -> src/lib/agent/token-pricing.ts",
"src/ui/wizard-ui.ts -> src/lib/agent/claude-settings.ts",
"src/ui/wizard-ui.ts -> src/lib/agent/progress.ts",
"src/utils/package-manager.ts -> src/telemetry.ts",
"src/utils/setup-utils.ts -> src/telemetry.ts",
"src/utils/wizard-abort.ts -> src/ui/logging-ui.ts"
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ vi.mock('../utils/wizard-abort', async (importOriginal) => ({
...(await importOriginal<typeof import('../utils/wizard-abort')>()),
wizardAbort: vi.fn(),
}));
vi.mock('../lib/agent/agent-runner', () => ({
vi.mock('../lib/programs/run-agent-legacy', () => ({
runAgent: vi.fn().mockResolvedValue(undefined),
}));

Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/provision-cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ vi.mock('../utils/wizard-abort', async (importOriginal) => ({
...(await importOriginal<typeof import('../utils/wizard-abort')>()),
wizardAbort: vi.fn(),
}));
vi.mock('../lib/agent/agent-runner', () => ({
vi.mock('../lib/programs/run-agent-legacy', () => ({
runAgent: vi.fn().mockResolvedValue(undefined),
}));

Expand Down
Loading
Loading