@humanbehavior/wizard
v1.0.15
Published
Agentic Human Behavior SDK install wizard
Downloads
702
Readme
@humanbehavior/wizard
Last updated: 2026-07-29
Agentic installer for the Human Behavior SDK (humanbehavior-js). A user runs
npx @humanbehavior/wizard, authorizes in the browser (device flow), and an LLM agent
installs and wires up Human Behavior into their project — guarded by a
defense-in-depth security model.
Pipeline
cli.ts (device-flow auth)
└─ runWizardAgent() lib/agent/agent-runner.ts (single pass — no repair loop)
├─ detectFramework() lib/detection/framework.ts → lib/frameworks/registry.ts
├─ gatherContext() per framework lib/frameworks/<framework>.ts
├─ resolveProjectChecks() lib/agent/project-checks.ts (which checks this project can run)
├─ buildInstallBrief() lib/agent/install-brief.ts + lib/frameworks/install-knowledge.ts
├─ createWizardToolsServer() lib/tools/wizard-tools.ts (in-process MCP, alwaysLoad)
├─ preinstallHostSkill() lib/agent/host-skill.ts (copies bundled skill → .claude/skills)
├─ initializeAgent() lib/agent/agent-interface.ts (LLM gateway auth)
├─ assemblePrompt() lib/agent/agent-prompt.ts + lib/programs/install-sdk/prompt.ts
├─ runAgent() — one SDK query() lib/agent/agent-interface.ts
├─ isolateAgentEnv() lib/security/agent-env-isolation.ts
├─ PreToolUse guardrail (L1) evaluateWizardToolPolicy()
├─ YARA Pre/PostToolUse hooks (L2) lib/security/yara-hooks.ts → yara-scanner.ts → yara-triage.ts
├─ init contract PostToolUse hook lib/agent/init-contract-hook.ts
├─ commandments (L0) lib/agent/commandments.ts
├─ SDK sandbox (fs + network) query({ sandbox })
├─ run_project_check (host-run) lib/agent/run-project-check.ts
│ └─ Optional stop remark hook HB_WIZARD_STOP_REMARKS=1
└─ evaluateInstallAcceptance() lib/agent/install-acceptance.ts
├─ manifest enforcement lib/agent/manifest-enforcement.ts
└─ init reachability lib/agent/init-reachability.tsThe host install brief
When the pre-scan resolves a framework the host has knowledge for, it composes
one brief (placement, the literal init snippet, env names, manifest constraints,
the verify command) and inlines it into the prompt. That replaces
read_reference_project, read_integration_manifest, read_sdk_contract, and
detect_package_manager plus the skill file reads. Those tools stay registered
as the fallback for frameworks with no knowledge entry and for ambiguous
projects. Tool search is off (ENABLE_TOOL_SEARCH=false) and the wizard-tools
server is alwaysLoad, so the schemas are pinned into turn one. TaskCreate /
TaskUpdate are in disallowedTools: the CLI runs behind
runWithQuietProgress, which no-ops stdout, so the task pane was never visible.
The init contract
init(apiKey, options?) is stated in the brief and repeated from the manifest,
and a fast model still wrote init(apiKey, urlString) on the Vue bench fixture.
Acceptance caught it, but only after the run was over, which turned a one-line
mistake into a failed install. A PostToolUse hook now runs the same
findBadInitSignature on every Write/Edit and tells the agent immediately, so
the correction costs one turn. Acceptance keeps the check as the backstop.
Verification
The agent does not shell out to tsc or eslint. It calls run_project_check,
and the host picks the command from the preflight, spawns it as argv with no
shell, and returns a verdict plus only the diagnostics naming files this install
changed. A check the project cannot run (missing binary, missing config, missing
script) is classified environment and never counts against the install. Only
failures attributable to our own edits soft-fail the run. A full production
build is never run during the install; it is listed as a user next step. There is
intentionally no outer repair or browser-verifier loop.
Acceptance additionally enforces manifests/sdk-integration.json
forbiddenPatterns, serverForbiddenGlobs, and requiresClientDirectiveGlobs
against the changed files, and proves the init module is reachable through static
imports from a framework entrypoint.
Supported project boundary
The automatic installer supports detected JavaScript browser frameworks and bundled HTML projects (for example Vite/webpack). Backend-only Python projects and unbundled static/CDN-only HTML are rejected before launching the agent.
Security (defense in depth)
- L0 commandments (
lib/agent/commandments.ts): always-appended system prompt. - L1 PreToolUse guardrail (
lib/agent/agent-interface.ts): allowlist — denies.envreads/writes (use the MCP env tools), blocks dangerous Bash operators, blocks fullbuild, blocks opaque lint/typecheck scripts with invented file-path args, and allows install/typecheck/lint/format commands. - L2 YARA (
lib/security/): regex rules scan tool inputs/outputs — block dangerous Bash pre-exec, instruct revert on violating writes, abort on prompt injection in read content, fail-closed on scanner errors. Every rule has a positive and a negative test insrc/__tests__/security.test.ts. - Scanner triage (
lib/security/yara-triage.ts): medium/high matches in thehumanbehavior_*categories are suppressed when the content proves them benign (env reference rather than literal, placeholder value, comment-only), because a false positive tells the agent to revert correct work.criticaland every adversarial category (prompt injection, exfiltration, filesystem, supply chain) are never triaged. - Env isolation (
lib/security/agent-env-isolation.ts): the entireANTHROPIC_*andCLAUDE_CODE_*namespace plusCLAUDE_CONFIG_DIRis dropped from the inherited environment before the wizard injects its own gateway values, so an inheritedCLAUDE_CODE_USE_BEDROCK,ANTHROPIC_CUSTOM_HEADERS, orANTHROPIC_MODELcannot reroute or reconfigure the run. - Secret vault (
lib/tools/secret-vault.ts): sensitive answers / env values are stored host-side and passed around as opaquesecret:<uuid>refs; the raw value never enters the LLM conversation. - Settings conflict (
lib/agent/agent-interface.ts): backs up / removes.claude/settings.jsonkeys that would hijack gateway auth, restores on exit.
Layout
src/
cli.ts arg parse + device-flow auth + kick off runWizardAgent
constants.ts Integration enum (detection order), tool prefix, timeouts
lib/
types.ts shared types
debug.ts logToFile / debug / run log file
telemetry.ts opt-out install metrics payload
agent/ agent-runner, agent-interface, agent-prompt, commandments, git-diff,
install-brief, project-checks, run-project-check,
manifest-enforcement, init-reachability, install-acceptance
tools/ wizard-tools (MCP), wizard-ask-bridge, secret-vault, safe-tools,
skill-install, integration-manifests
security/ yara-scanner, yara-hooks, yara-triage, agent-env-isolation
detection/ framework (ordered detect), package-manager, node-package-manager
frameworks/ framework-config (types), registry, install-knowledge,
one file per framework
programs/ program-step, program-registry, install-sdk/{index,prompt,steps}
ui/ wizard-ui (interface), logging-ui (headless)
skills/install-sdk/ vendored skill: SKILL.md, SDK_CONTRACT.md, description.md,
config.yaml, llm-prompts/1.0–1.3
reference-projects/ per-framework HB SDK reference guidance
manifests/ sdk-integration.json + env.json (machine-readable rules)
scripts/wizard-bench/ in-repo accuracy bench (fixtures, runner, scorer, baseline)
e2e-tests/ temporary, gitignored MSW fixture-mock E2E harnessAdding a framework
- Create
src/lib/frameworks/<name>.tsexporting aFrameworkConfig(detect,getVersion,getEnvVars,projectTypeDetection, optionalgatherContext/setupquestions). - Add it to the
Integrationenum insrc/constants.tsin the right detection order (specific before generic fallbacks) and toFRAMEWORK_REGISTRYinsrc/lib/frameworks/registry.ts. - Add
reference-projects/<name>.md, anenv.jsonentry, ansdk-integration.jsonentry, and a variant inskills/install-sdk/config.yaml.
Auth
The dashboard approval flow returns a short-lived LLM gateway URL/token. The
wizard passes those to the Claude Agent SDK via ANTHROPIC_BASE_URL and
ANTHROPIC_AUTH_TOKEN. For local wizard development only, set
HB_WIZARD_ANTHROPIC_API_KEY to bypass the gateway with a personal Anthropic
key. Override the edit/revise model with HB_WIZARD_MODEL (default claude-sonnet-4-6).
Optional: set HB_WIZARD_FAST_MODEL (e.g. claude-haiku-4-5) to start on a
cheaper model; the host upgrades to HB_WIZARD_MODEL on select_install_target
(or env write / package add) via setModel, and blocks Write/Edit until the next
model turn so the fast model cannot author init code. Gateway does not restrict
model IDs.
Override the install turn budget with HB_WIZARD_MAX_TURNS (default 75).
Override the post-wiring revise window with HB_WIZARD_REVISE_MAX_MS
(default 300000, 5 minutes).
Staging dashboard (Vercel Deployment Protection)
staging.humanbehavior.co may be locked by Vercel Authentication. The browser
can SSO past that; the CLI cannot. For HB teammates dogfooding staging:
- In Vercel → staging frontend project → Settings → Deployment Protection → Protection Bypass for Automation, create/copy the secret.
- In the shell where you run the wizard (not in the target app’s
.env):
export HB_STAGING_PROTECTION_BYPASS='the-secret'
cd /path/to/your-app
npx @humanbehavior/wizard@latest \
--dashboard-url https://staging.humanbehavior.co \
--project <staging-project-slug>VERCEL_AUTOMATION_BYPASS_SECRET is accepted as an alias. The wizard sends it
as the x-vercel-protection-bypass header on dashboard API calls and also on
Claude Agent SDK requests to the staging LLM gateway (via
ANTHROPIC_CUSTOM_HEADERS). You still Approve in the browser while logged into
staging Human Behavior.
Normal installs should use production (default dashboard URL); no bypass needed.
Content Security Policy (connect-src)
If the target app sets a CSP whose connect-src (or fallback default-src)
omits the ingestion host, the SDK can initialize while the browser still blocks
every ingest call. The wizard scans common config files (next.config.*,
middleware.ts / proxy.ts, vercel.json, HTML meta tags, etc.) and:
- Puts a Content Security Policy step in the install brief when it already
sees a block, so the agent can patch
connect-srcduring the run - Soft-fails acceptance (
needs-attention, codecsp-blocks-ingest) when the block is still present at the end
Typical fix: add https://*.humanbehavior.co to connect-src. This is a static
scan only — it does not boot the app or prove a live heartbeat.
After install (restart + verify events)
Host acceptance means wiring on disk passed — not that events are flowing. The CLI outro and install report both tell the user to:
- Restart the app/dev server so
NEXT_PUBLIC_*(and similar) env writes load - Open the app and click around
- Wait for first events on the dashboard verify step:
/projects/{slug}/get-started/sdk?step=verify
Local test mode (benchmarks / unattended)
To skip device-flow browser Approve entirely, set both:
HB_WIZARD_LOCAL_API_KEY— Human Behavior project API key for the target appHB_WIZARD_ANTHROPIC_API_KEY— personal Anthropic key for the agent
Optional: HB_WIZARD_LOCAL_PROJECT, HB_WIZARD_LOCAL_PROJECT_NAME,
HB_DASHBOARD_URL, HB_INGESTION_URL.
When either required var is unset, production device-flow is unchanged. Do not set these in CI that serves real users.
Install telemetry (opt-out)
On a terminal install status the wizard attaches run metrics to the existing
PATCH /api/wizard/sessions/[deviceCode] call: framework and variant, package
manager, host acceptance issue codes, turn count, elapsed time, token totals,
model ids, and the wizard version. The dashboard stores them in
wizard_install_runs, one row per attempt, and surfaces them at
/internal/wizard behind the same allowlist as /internal/costs.
What is never sent: source, file contents, file names, absolute paths, project names, env values, or acceptance issue messages.
Turn it off with either:
npx @humanbehavior/wizard --no-telemetry
# or
HB_WIZARD_NO_TELEMETRY=1 npx @humanbehavior/wizardWhen opted out, no payload is assembled and the status update carries only the install status it always did.
Accuracy bench
pnpm bench runs the in-repo bench in scripts/wizard-bench/: it scaffolds each
fixture app, runs the real CLI against it, and grades the resulting diff on
disk (dependency present, env keys and prefix correct, init reachable from an
entrypoint, typecheck, build) alongside turns, tokens, and elapsed time. See
scripts/wizard-bench/README.md for flags and
scoring. Run outputs and fixture trees are gitignored; baseline.json is
committed.
Scripts
pnpm build—tscpnpm test— build +node --test dist/**/*.test.jspnpm typecheck—tsc --noEmit(src + bench)pnpm dev—tsx src/cli.tspnpm bench— wizard accuracy bench (needsHB_WIZARD_LOCAL_API_KEY+HB_WIZARD_ANTHROPIC_API_KEY)
