From ccb8b8a636c2f52ab3cd8f5771a96ab765b3dcd1 Mon Sep 17 00:00:00 2001 From: Fernando Date: Thu, 7 May 2026 18:25:00 -0300 Subject: [PATCH] add native claude remote control harness --- .claude/settings.json | 7 +- .../settings.minimax-executor.example.json | 4 +- .../settings.opusminimax-planner.example.json | 4 +- .claude/settings.opussonnet.example.json | 4 +- .claude/settings.solo-fast.example.json | 4 +- .claude/settings.sonnet-executor.example.json | 4 +- .claude/settings.team-safe.example.json | 4 +- .claude/skills/remote-control/SKILL.md | 127 +++++++ .claude/skills/workflow/SKILL.md | 3 +- .../green/valid-native-static.json | 35 ++ .../red/api-key-auth-allowed.json | 28 ++ .../red/custom-network-control-plane.json | 28 ++ .../red/shared-blocker-env.json | 30 ++ .../red/static-runtime-proof-claim.json | 28 ++ .../remote-control/red/token-in-url.json | 28 ++ AGENTS.md | 1 + CLAUDE.md | 9 + README.md | 56 ++- SPEC.md | 338 ++++++++++-------- docs/harness-capability-map.json | 99 +++-- docs/harness-capability-map.md | 13 +- .../golden/m12-remote-control-smoke.json | 12 + .../tasks/m12-remote-control-smoke.yaml | 6 + scripts/harness-capability-map.sh | 5 + scripts/harness-eval.sh | 9 + scripts/opusminimax-doctor.sh | 16 +- scripts/release-check.sh | 1 + scripts/remote-control-doctor.sh | 279 +++++++++++++++ scripts/remote-control-smoke.sh | 331 +++++++++++++++++ scripts/start-session.sh | 7 +- scripts/test-harness.sh | 104 +++++- scripts/visualize-smoke.sh | 6 +- setup.ps1 | 8 +- setup.sh | 16 +- 34 files changed, 1436 insertions(+), 218 deletions(-) create mode 100644 .claude/skills/remote-control/SKILL.md create mode 100644 .taste/fixtures/remote-control/green/valid-native-static.json create mode 100644 .taste/fixtures/remote-control/red/api-key-auth-allowed.json create mode 100644 .taste/fixtures/remote-control/red/custom-network-control-plane.json create mode 100644 .taste/fixtures/remote-control/red/shared-blocker-env.json create mode 100644 .taste/fixtures/remote-control/red/static-runtime-proof-claim.json create mode 100644 .taste/fixtures/remote-control/red/token-in-url.json create mode 100644 evals/harness/golden/m12-remote-control-smoke.json create mode 100644 evals/harness/tasks/m12-remote-control-smoke.yaml create mode 100755 scripts/remote-control-doctor.sh create mode 100755 scripts/remote-control-smoke.sh diff --git a/.claude/settings.json b/.claude/settings.json index 9a08f35..20e64cb 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -5,10 +5,13 @@ "TRUSTED-LOCAL WARNING: this workspace defaults to bypassPermissions for the operator's solo workflow.", "Use .claude/settings.team-safe.example.json for shared, reviewed, client-visible, or less trusted work.", "Do not put Anthropic, Claude subscription, MiniMax, or other provider credentials in this file.", - "Use ignored local profiles for planner/executor identity." + "Use ignored local profiles for planner/executor identity.", + "Remote Control compatible: do not set CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, DISABLE_TELEMETRY, disableRemoteControl, or provider auth variables in shared project settings." ], "env": { - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "DISABLE_AUTO_COMPACT": "0", "CLAUDE_CODE_NO_FLICKER": "1" }, diff --git a/.claude/settings.minimax-executor.example.json b/.claude/settings.minimax-executor.example.json index 1678ab0..30588dc 100644 --- a/.claude/settings.minimax-executor.example.json +++ b/.claude/settings.minimax-executor.example.json @@ -11,7 +11,9 @@ "MINIMAX_API_KEY": "YOUR_MINIMAX_API_KEY", "MINIMAX_API_HOST": "https://api.minimax.io", "API_TIMEOUT_MS": "3000000", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "ANTHROPIC_MODEL": "MiniMax-M2.7-highspeed", "ANTHROPIC_SMALL_FAST_MODEL": "MiniMax-M2.7-highspeed", "ANTHROPIC_DEFAULT_SONNET_MODEL": "MiniMax-M2.7-highspeed", diff --git a/.claude/settings.opusminimax-planner.example.json b/.claude/settings.opusminimax-planner.example.json index 45e12db..134198b 100644 --- a/.claude/settings.opusminimax-planner.example.json +++ b/.claude/settings.opusminimax-planner.example.json @@ -6,7 +6,9 @@ "Copy to .claude/settings.opusminimax-planner.local.json for local tweaks, but keep credentials outside committed files." ], "env": { - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4-7", "CLAUDE_CODE_EFFORT_LEVEL": "xhigh", "CLAUDE_CODE_SUBAGENT_MODEL": "sonnet", diff --git a/.claude/settings.opussonnet.example.json b/.claude/settings.opussonnet.example.json index a652f0d..23c3fa8 100644 --- a/.claude/settings.opussonnet.example.json +++ b/.claude/settings.opussonnet.example.json @@ -14,7 +14,9 @@ "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-6", "CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6", "CLAUDE_CODE_EFFORT_LEVEL": "xhigh", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "DISABLE_AUTO_COMPACT": "0", "CLAUDE_CODE_NO_FLICKER": "1" }, diff --git a/.claude/settings.solo-fast.example.json b/.claude/settings.solo-fast.example.json index aef2b32..06875e5 100644 --- a/.claude/settings.solo-fast.example.json +++ b/.claude/settings.solo-fast.example.json @@ -11,7 +11,9 @@ "MINIMAX_API_KEY": "YOUR_MINIMAX_API_KEY", "MINIMAX_API_HOST": "https://api.minimax.io", "API_TIMEOUT_MS": "3000000", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "ANTHROPIC_MODEL": "MiniMax-M2.7-highspeed", "ANTHROPIC_SMALL_FAST_MODEL": "MiniMax-M2.7-highspeed", "ANTHROPIC_DEFAULT_SONNET_MODEL": "MiniMax-M2.7-highspeed", diff --git a/.claude/settings.sonnet-executor.example.json b/.claude/settings.sonnet-executor.example.json index febd47a..c95c33d 100644 --- a/.claude/settings.sonnet-executor.example.json +++ b/.claude/settings.sonnet-executor.example.json @@ -13,7 +13,9 @@ "ANTHROPIC_DEFAULT_HAIKU_MODEL": "haiku", "CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6", "CLAUDE_CODE_EFFORT_LEVEL": "high", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "DISABLE_AUTO_COMPACT": "0", "CLAUDE_CODE_NO_FLICKER": "1" }, diff --git a/.claude/settings.team-safe.example.json b/.claude/settings.team-safe.example.json index 52ec5b3..cced5ad 100644 --- a/.claude/settings.team-safe.example.json +++ b/.claude/settings.team-safe.example.json @@ -11,7 +11,9 @@ "MINIMAX_API_KEY": "YOUR_MINIMAX_API_KEY", "MINIMAX_API_HOST": "https://api.minimax.io", "API_TIMEOUT_MS": "3000000", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "ANTHROPIC_MODEL": "MiniMax-M2.7-highspeed", "ANTHROPIC_SMALL_FAST_MODEL": "MiniMax-M2.7-highspeed", "ANTHROPIC_DEFAULT_SONNET_MODEL": "MiniMax-M2.7-highspeed", diff --git a/.claude/skills/remote-control/SKILL.md b/.claude/skills/remote-control/SKILL.md new file mode 100644 index 0000000..e27a918 --- /dev/null +++ b/.claude/skills/remote-control/SKILL.md @@ -0,0 +1,127 @@ +--- +name: remote-control +description: Use Claude Code native Remote Control (/remote-control, /rc, claude --remote-control, claude remote-control) safely inside the minmaxing harness without custom network control planes, API-key auth, or static runtime overclaims. +argument-hint: [name/status/troubleshoot] +disable-model-invocation: true +--- + +# /remote-control + +Use Claude Code's native Remote Control. This route exists to keep the harness +compatible with the official Claude Code and Claude Code CLI feature, not to +build a separate remote-control server. + +## Native Commands + +Claude Code exposes the same native Remote Control surface in three useful +modes: + +- Existing interactive session: `/remote-control` or `/rc` +- Interactive CLI launch with RC enabled: `claude --remote-control` or `claude --rc` +- CLI server mode waiting for browser/mobile connections: `claude remote-control` + +The remote surface is `claude.ai/code` or the Claude mobile app. The Claude Code +process keeps running locally on this machine, with the same filesystem, tools, +MCP servers, project settings, hooks, and permissions as the local session. + +## Native-Only Boundary + +Do not implement a custom remote server, websocket bridge, HTTP tunnel, or MCP control plane. +Do not add a browser automation backdoor for this route. Native Remote Control +uses outbound HTTPS through Anthropic and does not require inbound ports from +this harness. + +Do not confuse this with `claude --remote` or Claude Code on the web. Remote +Control drives a local Claude Code process from another device; cloud sessions +run elsewhere and do not automatically inherit this local harness environment. + +## Prerequisites + +- Claude Code must be current enough for Remote Control. +- Authentication must be a claude.ai subscription login from `claude auth login` + or `/login`. +- API-key and inference-only token auth do not satisfy Remote Control: + `ANTHROPIC_API_KEY`, Console/API-key auth, `claude setup-token`, and + `CLAUDE_CODE_OAUTH_TOKEN` are blockers for this feature. +- Shared project settings must not set `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`, + `DISABLE_TELEMETRY`, `CLAUDE_CODE_USE_BEDROCK`, `CLAUDE_CODE_USE_VERTEX`, + `CLAUDE_CODE_USE_FOUNDRY`, or `disableRemoteControl`. +- Team and Enterprise organizations may require an admin-side Remote Control + toggle before the feature is eligible. +- Run `claude` in the project at least once and accept workspace trust before + expecting a remote session to attach cleanly. + +## Checks + +Run the static doctor before blaming the harness: + +```bash +bash scripts/remote-control-doctor.sh --static --json +``` + +Run the no-secret contract gate before release: + +```bash +bash scripts/remote-control-smoke.sh --fixtures +``` + +These checks never start a live Remote Control session and must not claim +runtime proof. They only verify that committed project settings, docs, scripts, +fixtures, and eval metadata do not block or misrepresent native RC. + +## Runtime Use + +From inside an existing Claude Code session: + +```text +/remote-control +/rc +``` + +From a shell in the project root: + +```bash +claude --remote-control +claude remote-control +``` + +Use `claude --version` and `/status` locally when troubleshooting account, +organization, or auth state. If Claude reports API-key, Console, third-party +provider, inference-only token, stale organization, or disabled-policy status, +fix that auth state first. + +## Security Notes + +This workspace defaults to trusted-local `bypassPermissions` for the operator's +solo workflow. Remote Control exposes that same local session authority from +web/mobile, so treat an active RC session like sitting at the terminal. + +Keep the committed deny rules for: + +- `Read(./.env)` +- `Read(./.env.*)` +- `Read(./.claude/settings.local.json)` +- `Read(./.claude/*.local.json)` +- `Read(./secrets/**)` + +Never paste Remote Control URLs, QR tokens, credentials, `.env` contents, or +local profile secrets into artifacts, logs, PRs, or chats. Static harness evidence is compatibility evidence, not proof that a live browser or mobile session connected. + +## Troubleshooting + +- `Remote Control requires a claude.ai subscription`: log in with + `claude auth login` and choose the claude.ai path; unset `ANTHROPIC_API_KEY` + for the session. +- `Remote Control requires a full-scope login token`: do not use + `CLAUDE_CODE_OAUTH_TOKEN` or `claude setup-token`; refresh with full + claude.ai login. +- `Remote Control is not yet enabled for your account`: unset + `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`, `DISABLE_TELEMETRY`, + `CLAUDE_CODE_USE_BEDROCK`, `CLAUDE_CODE_USE_VERTEX`, and + `CLAUDE_CODE_USE_FOUNDRY`, then log out and back in if needed. +- `Remote Control is disabled by your organization's policy`: check `/status` + and the Team/Enterprise admin toggle. A managed `disableRemoteControl` + setting is a policy decision, not a harness bug. +- `Remote credentials fetch failed`: rerun with `claude remote-control --verbose` + after confirming claude.ai login, active subscription, and outbound HTTPS + access to Anthropic on port 443. diff --git a/.claude/skills/workflow/SKILL.md b/.claude/skills/workflow/SKILL.md index c0b09b2..87acec6 100644 --- a/.claude/skills/workflow/SKILL.md +++ b/.claude/skills/workflow/SKILL.md @@ -139,6 +139,7 @@ Choose the route from user intent: | deepretaste, retaste, detect intent, bootstrap taste and ICP, SOTA customer research for taste | route through `/opusworkflow` with `inner_contract=deepretaste` when files may change; preserve `/deepresearch` as the general research route when findings will not mutate taste | | define ICP, ideal customer profile, tailor taste to customer, update taste.md or taste.vision from ICP | route through `/opusworkflow` with `inner_contract=defineicp` when files may change; keep proposal-first unless explicit apply approval is present | | Claude product, Claude Code, Claude.ai, Anthropic API, connectors, plugins, skills, hooks, MCP, subagents, plan availability, limits, setup | route product facts through `/claudeproduct` before generic research; continue into `/workflow` only if files change | +| remote control, rc, continue Claude Code from phone, claude.ai/code local session | route to `/remote-control`; use native Claude Code RC commands only (`/remote-control`, `/rc`, `claude --remote-control`, `claude remote-control`) and never build a custom control server | | parallel, mode parallel, dense workflow, orchestrate subagents, split across instances | route through `/opusworkflow` with `inner_contract=parallel` for file-changing packet execution; run the `/parallel` eligibility audit and use packets only when capacity, ownership, and verification pass | | hive, hive mind, coordinated agents, swarm, multi-agent synthesis | route through `/opusworkflow` with `inner_contract=hiveworkflow` for file-changing hive work only when roles, blackboard, dissent, ownership, capacity, and verification pass; otherwise downgrade to `/workflow` or `/parallel` fallback | | explain | inspect and explain directly | @@ -712,7 +713,7 @@ bash scripts/spec-archive.sh closeout "$ARGUMENTS" "shipped: [short outcome]" 2> ## Specialist Skills -The project still provides specialist commands like `/autoplan`, `/digestflow`, `/deepretaste`, `/defineicp`, `/claudeproduct`, `/deepresearch`, `/webresearch`, `/browse`, `/introspect`, `/parallel`, `/hive`, `/hiveworkflow`, `/sprint`, `/verify`, `/audit`, `/visualize`, `/visualizeworkflow`, and `/ship`. +The project still provides specialist commands like `/autoplan`, `/digestflow`, `/deepretaste`, `/defineicp`, `/claudeproduct`, `/remote-control`, `/deepresearch`, `/webresearch`, `/browse`, `/introspect`, `/parallel`, `/hive`, `/hiveworkflow`, `/sprint`, `/verify`, `/audit`, `/visualize`, `/visualizeworkflow`, and `/ship`. Use them like this: - as direct user-invoked helpers diff --git a/.taste/fixtures/remote-control/green/valid-native-static.json b/.taste/fixtures/remote-control/green/valid-native-static.json new file mode 100644 index 0000000..e85154c --- /dev/null +++ b/.taste/fixtures/remote-control/green/valid-native-static.json @@ -0,0 +1,35 @@ +{ + "api_key_auth_allowed": false, + "artifact_type": "remote-control-readiness", + "auth": { + "api_keys_supported": false, + "oauth_login_required": true, + "requires_claude_ai_subscription": true + }, + "checks": [ + { + "id": "shared-env-blockers", + "status": "pass", + "summary": "Shared project settings do not set known Remote Control blocker or provider auth variables" + } + ], + "commands": [ + "/remote-control", + "/rc", + "claude --remote-control", + "claude remote-control" + ], + "custom_network_control_plane": false, + "mode": "ci-static", + "native_claude_code_remote_control": true, + "operator_stop_required": true, + "runtime_proof_status": "not_run_static_only", + "runtime_remote_control_started": false, + "secrets": { + "read_secret_files": false, + "secret_values_redacted": true, + "tokens_in_url": false + }, + "shared_project_env_blockers": [], + "status": "pass" +} diff --git a/.taste/fixtures/remote-control/red/api-key-auth-allowed.json b/.taste/fixtures/remote-control/red/api-key-auth-allowed.json new file mode 100644 index 0000000..5dda109 --- /dev/null +++ b/.taste/fixtures/remote-control/red/api-key-auth-allowed.json @@ -0,0 +1,28 @@ +{ + "api_key_auth_allowed": true, + "artifact_type": "remote-control-readiness", + "auth": { + "api_keys_supported": true, + "oauth_login_required": false, + "requires_claude_ai_subscription": false + }, + "commands": [ + "/remote-control", + "/rc", + "claude --remote-control", + "claude remote-control" + ], + "custom_network_control_plane": false, + "mode": "ci-static", + "native_claude_code_remote_control": true, + "operator_stop_required": true, + "runtime_proof_status": "not_run_static_only", + "runtime_remote_control_started": false, + "secrets": { + "read_secret_files": false, + "secret_values_redacted": true, + "tokens_in_url": false + }, + "shared_project_env_blockers": [], + "status": "fail" +} diff --git a/.taste/fixtures/remote-control/red/custom-network-control-plane.json b/.taste/fixtures/remote-control/red/custom-network-control-plane.json new file mode 100644 index 0000000..25ab85f --- /dev/null +++ b/.taste/fixtures/remote-control/red/custom-network-control-plane.json @@ -0,0 +1,28 @@ +{ + "api_key_auth_allowed": false, + "artifact_type": "remote-control-readiness", + "auth": { + "api_keys_supported": false, + "oauth_login_required": true, + "requires_claude_ai_subscription": true + }, + "commands": [ + "/remote-control", + "/rc", + "claude --remote-control", + "claude remote-control" + ], + "custom_network_control_plane": true, + "mode": "ci-static", + "native_claude_code_remote_control": true, + "operator_stop_required": true, + "runtime_proof_status": "not_run_static_only", + "runtime_remote_control_started": false, + "secrets": { + "read_secret_files": false, + "secret_values_redacted": true, + "tokens_in_url": false + }, + "shared_project_env_blockers": [], + "status": "fail" +} diff --git a/.taste/fixtures/remote-control/red/shared-blocker-env.json b/.taste/fixtures/remote-control/red/shared-blocker-env.json new file mode 100644 index 0000000..16f2985 --- /dev/null +++ b/.taste/fixtures/remote-control/red/shared-blocker-env.json @@ -0,0 +1,30 @@ +{ + "api_key_auth_allowed": false, + "artifact_type": "remote-control-readiness", + "auth": { + "api_keys_supported": false, + "oauth_login_required": true, + "requires_claude_ai_subscription": true + }, + "commands": [ + "/remote-control", + "/rc", + "claude --remote-control", + "claude remote-control" + ], + "custom_network_control_plane": false, + "mode": "ci-static", + "native_claude_code_remote_control": true, + "operator_stop_required": true, + "runtime_proof_status": "not_run_static_only", + "runtime_remote_control_started": false, + "secrets": { + "read_secret_files": false, + "secret_values_redacted": true, + "tokens_in_url": false + }, + "shared_project_env_blockers": [ + "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC" + ], + "status": "fail" +} diff --git a/.taste/fixtures/remote-control/red/static-runtime-proof-claim.json b/.taste/fixtures/remote-control/red/static-runtime-proof-claim.json new file mode 100644 index 0000000..cb832d9 --- /dev/null +++ b/.taste/fixtures/remote-control/red/static-runtime-proof-claim.json @@ -0,0 +1,28 @@ +{ + "api_key_auth_allowed": false, + "artifact_type": "remote-control-readiness", + "auth": { + "api_keys_supported": false, + "oauth_login_required": true, + "requires_claude_ai_subscription": true + }, + "commands": [ + "/remote-control", + "/rc", + "claude --remote-control", + "claude remote-control" + ], + "custom_network_control_plane": false, + "mode": "ci-static", + "native_claude_code_remote_control": true, + "operator_stop_required": true, + "runtime_proof_status": "confirmed", + "runtime_remote_control_started": false, + "secrets": { + "read_secret_files": false, + "secret_values_redacted": true, + "tokens_in_url": false + }, + "shared_project_env_blockers": [], + "status": "fail" +} diff --git a/.taste/fixtures/remote-control/red/token-in-url.json b/.taste/fixtures/remote-control/red/token-in-url.json new file mode 100644 index 0000000..14ed0bd --- /dev/null +++ b/.taste/fixtures/remote-control/red/token-in-url.json @@ -0,0 +1,28 @@ +{ + "api_key_auth_allowed": false, + "artifact_type": "remote-control-readiness", + "auth": { + "api_keys_supported": false, + "oauth_login_required": true, + "requires_claude_ai_subscription": true + }, + "commands": [ + "/remote-control", + "/rc", + "claude --remote-control", + "claude remote-control" + ], + "custom_network_control_plane": false, + "mode": "ci-static", + "native_claude_code_remote_control": true, + "operator_stop_required": true, + "runtime_proof_status": "not_run_static_only", + "runtime_remote_control_started": false, + "secrets": { + "read_secret_files": false, + "secret_values_redacted": true, + "tokens_in_url": true + }, + "shared_project_env_blockers": [], + "status": "fail" +} diff --git a/AGENTS.md b/AGENTS.md index 21b78de..ecefe01 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,6 +21,7 @@ This repo is optimized for Claude Code first, but it also ships project-scoped C - For `/parallel`, keep the main as orchestrator. Run the parallel eligibility audit, hardware capacity profile, execution substrate selector, packet DAG, ownership matrix, sync barriers, aggregation, hard introspection, and independent verification. Prefer subagents for bounded same-workspace work; use parallel-instances only when disjoint ownership and speed needs justify them; treat agent teams as opt-in experimental. AgentFactory/Hermes outputs must include `development_host_profile`, `target_runtime_profile`, `host_capacity_profile`, `capacity_binding`, `concurrency_budget`, queue/backpressure behavior, and `degrade_policy`; never let local dev hardware silently define cloud/server/fleet production capacity. - For `/metacognition`, steer before execution: classify the task, read or cite `scripts/parallel-capacity.sh --json`, compute an effective parallel budget, name required evidence, audit assumptions/scope/verification/risk/estimate, and route to the existing command. Treat `MAX_PARALLEL_AGENTS`, Codex `max_threads`, and hardware ceilings as ceilings, not quotas. Do not depend on raw hidden chain-of-thought, and do not promote model self-reports without verified outcomes. `/metacognition` is upstream steering; it never replaces or satisfies required `/introspect` hard gates. - For `/claudeproduct`, treat Claude, Claude Code, Claude.ai, Anthropic API, connector, plugin, skill, hook, MCP, subagent, availability, limit, pricing, model, or setup questions as current product questions. Use official Anthropic/Claude docs, Help Center, or docs indexes before memory; keep Claude Code, Claude.ai, Desktop, Mobile, API, and MCP connector behavior distinct; include permission/trust caveats for connectors; and do not read `.env` or secrets for product-doc answers. +- For `/remote-control`, use Claude Code native Remote Control only: `/remote-control`, `/rc`, `claude --remote-control`, or `claude remote-control`. Do not build a custom remote server, websocket bridge, MCP control plane, browser backdoor, or API-key fallback. Static checks such as `bash scripts/remote-control-doctor.sh --static --json` and `bash scripts/remote-control-smoke.sh --fixtures` prove harness compatibility only; live RC still requires claude.ai subscription login, current Claude Code CLI, workspace trust, and no blocker variables such as `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`, `DISABLE_TELEMETRY`, `ANTHROPIC_API_KEY`, or `CLAUDE_CODE_OAUTH_TOKEN`. - For harness self-lookup, use `docs/harness-capability-map.md` and `docs/harness-capability-map.json` first. They are generated from repo truth surfaces and list skills, route groups, rules, script gates, evals, hooks, and Codex surfaces. Verify freshness with `bash scripts/harness-capability-map.sh --check`; if stale, inspect live repo surfaces before answering. - For `/hive` and `/hiveworkflow`, treat the hive as governed coordination, not a novelty swarm. Require a queen/supervisor, capacity-bound role map, visible blackboard, dissent/conflict log, evidence-backed synthesis, and independent verification. Durable hive runs must write `.taste/hive/{run_id}/hive-run.json` and validate it with `scripts/artifact-lint.sh` plus `scripts/hive-aggregate.sh`. Hive reuses `/parallel` for packet execution and aggregation; consensus never replaces `/introspect`, `/verify`, `/workflow`, or command evidence. - For `/visualize`, create a taste-to-artifact comprehension package without implementing. For `/visualizeworkflow`, run the approval-first variant that drafts `SPEC.md`, creates a visualization package, stops at `WAITING_FOR_VISUAL_APPROVAL`, and continues only when invoked with `--continue`. Plain `/workflow` remains autonomous and must not gain a surprise human visual-approval pause. diff --git a/CLAUDE.md b/CLAUDE.md index 76c559a..28f5e1a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -83,6 +83,7 @@ We prioritize getting it right over getting it done fast. Parallel agents only h | /parallel | Hardware-aware whole-workflow parallel orchestration with packet DAG, ownership matrix, sync barriers, and aggregate verification | | /metacognition | Parallel-aware routing and evidence-grounded self-calibration before execution | | /claudeproduct | Official-source answers for Claude, Claude Code, Claude.ai, Anthropic API, connectors, plugins, skills, hooks, MCP, and subagents | +| /remote-control | Native Claude Code Remote Control via `/remote-control`, `/rc`, `claude --remote-control`, or `claude remote-control` without custom network control planes | | /hive | Governed multi-agent coordination with role map, blackboard, dissent, synthesis, and verified evidence | | /hiveworkflow | Full workflow mode that uses hive coordination before packet execution, aggregation, introspection, and verify | | /verify | Check output against SPEC | @@ -111,6 +112,14 @@ We prioritize getting it right over getting it done fast. Parallel agents only h Anthropic/Claude docs. It separates Claude product surfaces, includes connector permission/trust caveats, and never reads `.env` or secrets for product-doc answers. +- **Native Remote Control**: `/remote-control`, `/rc`, + `claude --remote-control`, and `claude remote-control` use Claude Code's + native Remote Control only. Do not build a custom remote server, websocket + bridge, MCP control plane, or API-key fallback. Static harness evidence is + compatibility evidence; live RC still requires claude.ai subscription login, + current Claude Code CLI, workspace trust, and no blocker variables such as + `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`, `DISABLE_TELEMETRY`, + `ANTHROPIC_API_KEY`, or `CLAUDE_CODE_OAUTH_TOKEN`. - **Harness Capability Map**: `docs/harness-capability-map.md` and `docs/harness-capability-map.json` are generated from repo truth and are the canonical self-lookup index for skills, route groups, rules, script gates, diff --git a/README.md b/README.md index 6549dc6..3457573 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ above from the project root. In `/opusworkflow` split mode, MiniMax is configure in the ignored executor profile `.claude/settings.minimax-executor.local.json`; it is not automatically added as a user-scope Claude MCP server. -That's it. Memory system, governed runtime profiles, and 35 skills are +That's it. Memory system, governed runtime profiles, and 36 skills are configured. ### Suggested Claude-Only Install @@ -198,6 +198,40 @@ Claude subscription auth is separate account auth. Run `claude auth login` once if this machine is not already logged in; the setup command does not store or fake your Claude subscription session. +### Native Claude Code Remote Control + +Claude Code has native Remote Control for continuing a local session from +`claude.ai/code` or the Claude mobile app. Use the native commands only: + +```text +/remote-control +/rc +``` + +From the CLI: + +```bash +claude --remote-control +claude remote-control +``` + +This is different from `claude --remote` or Claude Code on the web. Remote +Control keeps the Claude Code process running locally, with this repo's hooks, +tools, project settings, and trusted-local `bypassPermissions` posture. The +harness intentionally does not create a custom remote server, websocket bridge, +or API-key control path. + +Before using it, run the no-secret static doctor: + +```bash +bash scripts/remote-control-doctor.sh --static --json +``` + +Remote Control requires claude.ai subscription login. `ANTHROPIC_API_KEY`, +`CLAUDE_CODE_OAUTH_TOKEN`, third-party provider auth, `DISABLE_TELEMETRY`, and +`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` can block eligibility, so shared +project settings avoid those variables. + **Shared settings are committed on purpose, but they are provider-neutral.** `.claude/settings.json` contains governance hooks, deny rules, and the trusted-local `bypassPermissions` default. This is an explicit operator-speed choice, not a team-safety recommendation. Real credentials and provider identity belong in ignored local files such as `.claude/settings.opusminimax-planner.local.json` and `.claude/settings.minimax-executor.local.json`. **Fresh repos should start with `/tastebootstrap`.** It asks the 10 kernel questions, writes `taste.md` + `taste.vision`, and gives `/workflow` explicit taste to follow before anything is built. @@ -678,7 +712,7 @@ Now you can use any workflow pattern: --- -## The 35 Skills +## The 36 Skills | Skill | What It Does | |-------|-------------| @@ -701,6 +735,7 @@ Now you can use any workflow pattern: | `/parallel` | Run hardware-aware whole-workflow parallel orchestration with packet DAG, ownership matrix, sync barriers, and aggregate verification | | `/metacognition` | Parallel-aware control plane for task routing, evidence-grounded reflection, confidence calibration, and verified learning | | `/claudeproduct` | Official-source answers for Claude, Claude Code, Claude.ai, Anthropic API, connectors, plugins, skills, hooks, MCP, and subagents | +| `/remote-control` | Native Claude Code Remote Control route with a static doctor, no custom network control plane, and no API-key auth fallback | | `/hive` | Governed multi-agent coordination with role map, blackboard, dissent, synthesis, and verified evidence | | `/hiveworkflow` | Full workflow mode for hive-coordinated planning, execution, aggregation, introspection, and verification | | `/sprint` | Run an ownership-safe parallel execution wave | @@ -739,6 +774,8 @@ The routing ladder is: -> /parallel when independent execution packets are enough -> /claudeproduct for Claude, Claude Code, Claude.ai, API, connector, plugin, skill, hook, MCP, subagent, availability, limit, model, or setup questions +-> /remote-control when the operator wants native Claude Code RC from + claude.ai/code or mobile without building a custom control plane -> /hive for read-only coordination, or /opusworkflow with inner_contract=hiveworkflow when coordinated roles, blackboard state, dissent, synthesis, and mutation materially improve the outcome @@ -757,6 +794,7 @@ Use this rule of thumb: | `/defineicp` | You need to define the ICP or ICPs and tailor `taste.md` / `taste.vision` to that customer profile. | Deepresearch plan, primary/secondary/anti-ICPs, source and claim ledgers, taste patch proposal, explicit apply approval, backups, hashes, validation, and rollback evidence. | | `/opusminimax` | You want to squeeze a Claude subscription by using Opus only for planning, adversarial review, and final judgment while MiniMax does speed/bulk execution. | Provider split doctor, Opus planner artifact, MiniMax executor packets, quota-aware concurrency, parent verification, and no benchmark overclaims. | | `/claudeproduct` | The question is about Claude, Claude Code, Claude.ai, Anthropic API, connectors, plugins, skills, hooks, MCP, subagents, availability, limits, models, or setup. | Official Anthropic/Claude docs first, surface separation, source ledger, connector permission/trust caveats, confidence downgrade when current docs are missing. | +| `/remote-control` | You want Claude Code native Remote Control for an already trusted local harness session. | `/remote-control`, `/rc`, `claude --remote-control`, or `claude remote-control`; claude.ai subscription login; no custom server; no static runtime-proof claim. | | `/parallel` | The work splits into independent packets with clear owned files/surfaces and aggregate verification. | Packet DAG, ownership matrix, sync barriers, worker sidecars, `parallel-aggregate`. | | `/hive` | The task needs multiple perspectives but may not need a full file-changing workflow: research branches, adversarial review, planning alternatives, risk ranking, or synthesis. | Queen/supervisor, role map, blackboard, dissent/conflict log, evidence-backed synthesis. | | `/hiveworkflow` | The entire implementation lifecycle benefits from hive coordination and packet execution: broad audit plus implementation, multi-surface build, high-stakes verification, or agent/fleet design. | Use through `/opusworkflow` by default with `inner_contract=hiveworkflow`, plus hive artifact, `hive-run.json`, optional `/parallel` packets, `hive-aggregate`, `/introspect`, `/verify`. | @@ -791,6 +829,15 @@ or secrets for product-doc answers. Use `bash scripts/claudeproduct-scorecard.sh --fixtures --json` to prove stale memory answers and unsupported Claude claims are rejected. +**Native Remote Control:** `/remote-control`, `/rc`, `claude --remote-control`, +and `claude remote-control` are the supported paths for steering a local Claude +Code session from `claude.ai/code` or mobile. Use the native Claude Code feature +only; do not add a custom remote server, websocket bridge, MCP control plane, or +API-key fallback. Static harness evidence is compatibility evidence, not proof +that a live browser or mobile session connected. Use +`bash scripts/remote-control-doctor.sh --static --json` and +`bash scripts/remote-control-smoke.sh --fixtures` before blaming the harness. + **Harness capability map:** `docs/harness-capability-map.md` and `docs/harness-capability-map.json` are generated from repo truth surfaces and act as the canonical self-lookup index for minmaxing capabilities. They list @@ -1021,7 +1068,7 @@ minmaxing/ │ ├── settings.opussonnet.example.json │ ├── settings.sonnet-executor.example.json │ ├── hooks/ # Lifecycle hooks, including working-state rehydration -│ ├── skills/ # 35 skills (system calls) +│ ├── skills/ # 36 skills (system calls) │ │ ├── workflow/ # Central execution engine │ │ ├── opusworkflow/ # Cost-optimized daily Opus + MiniMax route │ │ ├── opusminimax/ # Opus planner + MiniMax executor mode @@ -1040,6 +1087,7 @@ minmaxing/ │ │ ├── agentfactory/ # Governed Hermes agent generator │ │ ├── parallel/ # Hardware-aware workflow parallelizer │ │ ├── claudeproduct/ # Official Claude product knowledge router +│ │ ├── remote-control/ # Native Claude Code Remote Control route │ │ ├── hive/ # Governed multi-agent coordination │ │ ├── hiveworkflow/ # Full hive-coordinated workflow │ │ ├── sprint/ # Ownership-safe parallel executor @@ -1065,6 +1113,8 @@ minmaxing/ │ ├── taste.sh # Taste system CLI │ ├── start-session.sh # Session initializer │ ├── harness-capability-map.sh # Generated harness capability map +│ ├── remote-control-doctor.sh # Static native RC readiness doctor +│ ├── remote-control-smoke.sh # Native RC compatibility smoke gate │ ├── parallel-capacity.sh # Hardware-aware parallel budget profile │ ├── parallel-smoke.sh # Parallel mode production-contract smoke test │ ├── agentfactory-smoke.sh # Agent Factory production-contract smoke test diff --git a/SPEC.md b/SPEC.md index 54ecae7..730aaa6 100644 --- a/SPEC.md +++ b/SPEC.md @@ -1,90 +1,122 @@ -# SPEC: Governed Claude Model Profile Flexibility +# SPEC: Claude Code Native Remote Control Harness ## Problem Statement -The harness can already represent the cost-optimized `/opusworkflow` default -and the optional `/opussonnet` route, but the current implementation makes model -choice too rigid. Operators should be able to request Claude Code models such as -`claude-opus-4-7`, `claude-sonnet-4-6`, `opus`, `sonnet`, `opusplan`, or a -custom model route without breaking artifacts, smokes, or safety gates. +Claude Code has native Remote Control (`/remote-control`, `/rc`, +`claude --remote-control`, and `claude remote-control`) for continuing a local +session from web or mobile. The minmaxing harness currently makes that path +fragile because the shared project settings set +`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`, and official Claude Code Remote +Control troubleshooting says that variable can make Remote Control eligibility +fail. -The default must remain conservative and cost-aware. Model freedom must not -weaken provider isolation, secret safety, runtime identity honesty, or -verification requirements. +The harness should support Claude Code's native Remote Control without building +a separate network control plane, weakening secret protections, or claiming +runtime proof from static checks. ## Success Criteria -- [x] `/opusworkflow` accepts a first-class `--model-profile` selector while - preserving the existing default behavior. -- [x] Supported profiles include `minimax`, `opussonnet`, `sonnet`, `opus`, - `default`, and `custom`. -- [x] Existing `--executor-provider minimax|claude-sonnet` compatibility keeps - working for current scripts and docs. -- [x] Anthropic-only profiles never inherit MiniMax base URLs, API key fields, - or MiniMax executor model IDs. -- [x] `artifact-lint` validates model route honesty without requiring every - planner to be Opus. -- [x] Static smokes prove the default MiniMax route, optional Opus+Sonnet route, - all-Sonnet route, and all-Opus route. -- [x] Docs explain exact commands for switching models and state that runtime - identity is account/session dependent until proven with `/status`, sentinel, - or run artifact. -- [x] No `.env`, `.env.*`, `.claude/*.local.json`, key files, or secrets are - read or committed. +- [x] Shared project settings no longer set Remote Control blocker variables + such as `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` or `DISABLE_TELEMETRY`. +- [x] The harness exposes an operator-facing `remote-control` route that + explains the native Claude Code commands and boundaries. +- [x] A no-secret static doctor detects local blockers for native Remote + Control and returns machine-readable JSON. +- [x] A smoke gate prevents regressions: blocker variables in shared settings, + API-key-precedence over subscription auth, missing version evidence, and + static runtime overclaims must fail. +- [x] The generated capability map discovers the route, script, and eval gate. +- [x] Docs distinguish native Remote Control from `claude --remote` cloud + sessions and from any custom network control plane. +- [x] No `.env`, `.env.*`, `.claude/*.local.json`, key files, credentials, or + private tokens are read or committed. ## Scope In Scope: -- Add governed model-profile resolution to the existing OpusWorkflow scripts. -- Extend run artifacts with explicit model profile and role route metadata. -- Update lint/doctor/static smokes for flexible Anthropic model profiles. -- Update README, AGENTS, CLAUDE, skills, fixtures, and generated capability map. +- Use official Claude Code docs to research native Remote Control behavior. +- Patch shared harness settings to avoid known Remote Control blockers. +- Add a `remote-control` skill/route, static doctor, smoke gate, fixtures, + eval metadata, and docs. +- Regenerate generated capability map artifacts. Out of Scope: -- Running live Claude model calls in this turn. -- Editing ignored local settings profiles or shell startup files. -- Changing the default `/opusworkflow` MiniMax-backed cost strategy. -- Claiming Opus/Sonnet runtime identity without authenticated runtime proof. - -## Research Brief +- Starting a live Remote Control session during static CI. +- Reading Claude local credentials, `.env`, `.claude/*.local.json`, or managed + organization settings. +- Building a custom HTTP/LAN/mobile control server. +- Claiming that the operator's account, organization, or mobile app is eligible + without live authenticated runtime evidence. + +## DeepResearch Brief + +### Investigation Mode + +Comprehensive, with a parallel research ceiling of 10 from +`bash scripts/parallel-capacity.sh --json`. Effective lanes used: 6 distinct +sidecar lanes plus local implementation, because the useful branches were repo +mapping, capability-map wiring, analogous route patterns, test/eval gates, +official docs, and adversarial review. + +### Collaborative Research Plan + +- Deliverable: a static, release-gated harness patch that makes Claude Code + native Remote Control compatible with minmaxing. +- Branches: + - official Claude Code Remote Control docs + - official Claude Code settings/env docs + - Codex project config and agent parallelism docs + - local harness capability registration + - local smoke/eval/release patterns + - security review for remote-facing authority +- Source classes: + - official Claude docs + - official OpenAI Codex docs + - repo truth surfaces + - read-only subagent audits +- Stop condition: identify a concrete blocker and implement the smallest + verified patch that removes it while preserving secret safety and release + gates. ### Local Evidence -- `scripts/opusworkflow.sh` currently accepts only - `--executor-provider minimax|claude-sonnet`. -- `scripts/opusminimax.sh` defaults the planner to `claude-opus-4-7` and rejects - executor providers outside `minimax|claude-sonnet`. -- `scripts/artifact-lint.sh` rejects any `opusminimax-run` whose planner model - does not contain `opus`. -- `scripts/opusworkflow-smoke.sh` proves the current MiniMax default and - optional `claude-sonnet` route but has no all-Sonnet or all-Opus route. +- `.claude/settings.json` currently sets + `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`. +- No `.claude/skills/remote-control/SKILL.md`, route entry, smoke script, or + eval gate currently exists. +- `scripts/harness-capability-map.sh` discovers `.claude/skills/*/SKILL.md`, + route groups, related scripts, and eval tasks. +- `scripts/release-check.sh` is the static release gate that must include new + route smokes. ### Current Product Evidence -- Claude Code model configuration docs say users can switch models with - `/model`, `claude --model`, `ANTHROPIC_MODEL`, or the `model` settings field. -- Claude Code docs define `opusplan` as Opus in plan mode and Sonnet in - execution mode. -- Claude Code docs say `ANTHROPIC_DEFAULT_OPUS_MODEL`, - `ANTHROPIC_DEFAULT_SONNET_MODEL`, and `CLAUDE_CODE_SUBAGENT_MODEL` control - alias and subagent model routing. -- Claude Code docs say command-line settings override local/project/user - settings, while managed settings remain highest priority. -- Claude Help Center lists `claude-opus-4-7` and `claude-sonnet-4-6` as - supported Claude Code model identifiers. +- Claude Code Remote Control exists as native commands: + `/remote-control`, `/rc`, `claude --remote-control`, and + `claude remote-control`. +- Remote Control runs Claude Code locally and exposes that local session to + Claude web/mobile; it is distinct from `claude --remote`, which starts a + cloud session. +- Claude Code Remote Control troubleshooting lists + `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` and `DISABLE_TELEMETRY` as + environment variables that can make eligibility checks fail. +- Remote Control requires claude.ai subscription/OAuth-style login; API-key + authentication and long-lived inference-only tokens are not sufficient. +- Claude Code settings support shared project `env` values and settings + precedence, so shared project settings can create repo-wide runtime blockers. ### Source Ledger -- Claude Code model configuration, accessed 2026-05-07: - https://code.claude.com/docs/en/model-config -- Claude Code CLI reference, accessed 2026-05-07: - https://code.claude.com/docs/en/cli-reference -- Claude Code settings, accessed 2026-05-07: +- Claude Code Remote Control, accessed 2026-05-07: + https://code.claude.com/docs/en/remote-control +- Claude Code on the web, accessed 2026-05-07: + https://code.claude.com/docs/en/claude-code-on-the-web +- Claude Code settings/configuration, accessed 2026-05-07: https://code.claude.com/docs/en/settings -- Claude Help Center model configuration, accessed 2026-05-07: - https://support.claude.com/en/articles/11940350-claude-code-model-configuration +- OpenAI Codex config reference, accessed 2026-05-07: + https://developers.openai.com/codex/config-reference ## Agent-Native Estimate @@ -92,120 +124,122 @@ Out of Scope: - Capacity evidence: `bash scripts/parallel-capacity.sh --json` reported `codex_max_threads=10`, `recommended_ceiling=10`, `hardware_class=workstation`, `cores=16`, `ram_gb=32`, and `agent_teams_available=false` on 2026-05-07. -- Effective parallel budget: 1 implementation lane. The work touches coupled - shell scripts, lint rules, fixtures, and docs, so parallel editing would - create merge friction. +- Effective parallel budget: 6 research lanes, 1 local implementation lane. - Agent wall-clock: 60-120 minutes. -- Agent-hours: 1.5-3.0. -- Human touch time: none for static implementation. Runtime model proof remains - account/session dependent. +- Agent-hours: 2-4 across research, patch, and verification. +- Human touch time: none for static implementation; live `rc` proof requires + the operator's Claude account and mobile/web connection. - Calendar blockers: none for static release. -- Confidence: medium. Static gates can prove routing and safety invariants, not - live model availability for the operator's Claude account. +- Confidence: medium-high for the blocker removal and static gate; medium for + live account eligibility because Team/Enterprise admin policy and login state + are external. ## Implementation Plan -### Task 1: Add model profile resolution +### Task 1: Remove shared Remote Control blockers Definition of Done: -- [x] `scripts/opusworkflow.sh` exposes `--model-profile`. -- [x] `scripts/opusminimax.sh` resolves model profiles to planner/executor - provider and model IDs. -- [x] Backward-compatible `--executor-provider claude-sonnet` still maps to the - Opus+Sonnet route. +- [x] `.claude/settings.json` no longer sets + `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` or `DISABLE_TELEMETRY`. +- [x] The settings still avoid secrets and keep project hooks/denies intact. -### Task 2: Relax lint while preserving honesty +### Task 2: Add native Remote Control harness route Definition of Done: -- [x] `scripts/artifact-lint.sh` accepts Anthropic model routes without MiniMax - base URLs. -- [x] Lint still rejects MiniMax leakage into Anthropic profiles. -- [x] Lint still rejects Opus runtime claims without model identity proof. +- [x] `.claude/skills/remote-control/SKILL.md` documents native `rc` commands, + prerequisites, troubleshooting, and static/runtime evidence boundaries. +- [x] README, CLAUDE, and AGENTS mention native Remote Control support. +- [x] Capability map groups `remote-control` under operations and links the + doctor/smoke script. -### Task 3: Update smokes and docs +### Task 3: Add static doctor and regression gate Definition of Done: -- [x] `scripts/opusworkflow-smoke.sh` validates default, Opus+Sonnet, all-Sonnet, - and all-Opus static artifacts. -- [x] Fixture coverage includes at least one Anthropic flexible model route. -- [x] README, AGENTS, CLAUDE, and route skills document the selector. -- [x] Capability map is regenerated. +- [x] `scripts/remote-control-doctor.sh --static --json` checks version, + shared settings blockers, API-key-precedence warnings, and runtime proof + status without reading secrets. +- [x] `scripts/remote-control-smoke.sh --fixtures` validates green/red fixture + contracts. +- [x] `scripts/harness-eval.sh`, `scripts/release-check.sh`, and + `scripts/test-harness.sh` include the route gate. +- [x] Generated capability map artifacts are regenerated. ## Verification -- `bash -n scripts/opusworkflow.sh scripts/opusminimax.sh scripts/opusminimax-doctor.sh scripts/artifact-lint.sh scripts/opusworkflow-smoke.sh` -- `python3 -m json.tool` on changed JSON fixtures and settings examples. -- `bash scripts/opusworkflow-smoke.sh` -- `bash scripts/artifact-lint.sh --fixtures` -- `bash scripts/security-smoke.sh` -- `bash scripts/harness-capability-map.sh --write` -- `bash scripts/harness-capability-map.sh --check --json` -- `bash scripts/harness-eval.sh --json` -- `env HARNESS_STATIC_CI=1 bash scripts/test-harness.sh` -- `bash scripts/release-check.sh --static-only` -- `git diff --check` +- [x] `bash -n scripts/remote-control-doctor.sh scripts/remote-control-smoke.sh scripts/harness-eval.sh scripts/release-check.sh scripts/test-harness.sh scripts/harness-capability-map.sh scripts/opusminimax-doctor.sh setup.sh` +- [x] `python3 -m json.tool` on changed settings examples, remote-control fixtures, and eval golden JSON. +- [x] `bash scripts/remote-control-doctor.sh --static --json` + - Result: pass. Claude Code CLI version detected as `2.1.118`; no shared + blocker variables; runtime proof status `not_run_static_only`. +- [x] `bash scripts/remote-control-smoke.sh --fixtures` + - Result: pass. Green fixture accepted; red fixtures for shared blocker env, + API-key auth, custom network control plane, static runtime proof claim, and + token-in-URL were rejected. +- [x] `bash scripts/harness-capability-map.sh --write` +- [x] `bash scripts/harness-capability-map.sh --check --json` + - Result: pass. Counts include 36 skills, 58 scripts, 23 eval tasks. +- [x] `bash scripts/harness-eval.sh --json` + - Result: pass. 23 tasks, 20 gates, no mismatches; `remote-control-smoke` + passed. +- [x] `env HARNESS_STATIC_CI=1 bash scripts/test-harness.sh` + - Result: pass. 145 passed, 0 failed. +- [x] `bash scripts/security-smoke.sh` + - Result: pass. +- [x] `bash scripts/visualize-smoke.sh` + - Result: pass after updating expected skill count to 36. +- [x] `bash scripts/release-check.sh --static-only` + - Result: pass, including full static harness and `git diff --check`. + +## Implementation Notes + +- Removed `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` from shared settings and + profile examples, replacing it with narrower non-RC-blocking toggles: + `DISABLE_AUTOUPDATER`, `DISABLE_FEEDBACK_COMMAND`, and + `DISABLE_ERROR_REPORTING`. +- Updated `setup.sh`, `setup.ps1`, and `scripts/opusminimax-doctor.sh` so local + profile generation/repair does not reintroduce the Remote Control blocker. +- Added `.claude/skills/remote-control/SKILL.md`, + `scripts/remote-control-doctor.sh`, `scripts/remote-control-smoke.sh`, + `.taste/fixtures/remote-control/*`, and `evals/harness/*/m12-*`. +- Registered the route in `scripts/harness-capability-map.sh`, + `scripts/harness-eval.sh`, `scripts/release-check.sh`, + `scripts/test-harness.sh`, `scripts/start-session.sh`, README, CLAUDE, and + AGENTS. ## Rollback Plan 1. Revert this commit. 2. Regenerate the capability map if needed. -3. Verify rollback with `bash scripts/opusworkflow-smoke.sh` and - `bash scripts/release-check.sh --static-only`. +3. Re-run `bash scripts/release-check.sh --static-only`. ## Introspection: Pre-Implementation -- Likely mistake: weakening the MiniMax/Anthropic boundary. Mitigation: lint - must still reject MiniMax URLs or MiniMax model IDs in Anthropic profiles. -- Likely mistake: making all-Opus look like the new default. Mitigation: - default remains `minimax`; docs label Opus-only as explicit and expensive. -- Likely mistake: treating static profile selection as runtime proof. - Mitigation: artifacts keep identity status `blocked` or `runtime-pending` - until `/status`, sentinel, or equivalent run evidence proves the model. -- Likely mistake: breaking existing `--executor-provider claude-sonnet` users. - Mitigation: keep it as a backward-compatible alias for `opussonnet`. - -## Verified 2026-05-07 - -- `bash -n scripts/opusworkflow.sh scripts/opusminimax.sh scripts/opusminimax-doctor.sh scripts/artifact-lint.sh scripts/opusworkflow-smoke.sh scripts/opussonnetworkflow.sh scripts/test-harness.sh`: pass. -- `python3 -m json.tool schemas/opusminimax-run.schema.json` and - `.taste/fixtures/artifact-lint/green/valid-sonnet-model-profile-run.json`: - pass. -- `bash scripts/opusworkflow-smoke.sh`: pass; validates default MiniMax, - backward-compatible Opus+Sonnet, all-Sonnet, and all-Opus static artifacts. -- `bash scripts/artifact-lint.sh --fixtures`: pass (`9 green`, `22 red`). -- `bash scripts/opusminimax-doctor.sh --static --model-profile minimax --executor-provider minimax --json`: pass with existing tracked test/fixture secret-string warning. -- `bash scripts/opusminimax-doctor.sh --static --model-profile opussonnet --executor-provider claude-sonnet --json`: pass with existing tracked test/fixture secret-string warning. -- `bash scripts/opusminimax-doctor.sh --static --model-profile sonnet --executor-provider anthropic --json`: pass with existing tracked test/fixture secret-string warning. -- `bash scripts/opusminimax-doctor.sh --static --model-profile opus --executor-provider anthropic --json`: pass with existing tracked test/fixture secret-string warning. -- `bash scripts/opusworkflow.sh --task "default profile smoke" --model-profile default --run-id manual-profile-default` plus artifact lint: pass; runtime not executed. -- `bash scripts/opusworkflow.sh --task "custom profile smoke" --model-profile custom --planner-model claude-sonnet-4-6 --executor-model claude-sonnet-4-6 --run-id manual-profile-custom` plus artifact lint: pass; runtime not executed. -- `bash scripts/opusworkflow.sh --task "bad profile smoke" --model-profile sonnet --executor-provider minimax --run-id manual-profile-bad`: correctly exits 2. -- `bash scripts/security-smoke.sh`: pass. -- `bash scripts/harness-capability-map.sh --write` and - `bash scripts/harness-capability-map.sh --check --json`: pass. -- `bash scripts/harness-eval.sh --json`: pass (`22 tasks`, `19 gates`, - `0 mismatches`). -- `env HARNESS_STATIC_CI=1 bash scripts/test-harness.sh`: pass (`141 passed`, - `0 failed`; workflow runtime smoke intentionally skipped). -- `bash scripts/release-check.sh --static-only`: pass. -- `git diff --check`: pass. - -## Introspection: Pre-Closeout - -- Likely mistake checked: this could make all-Opus look like the new default. - The default remains `model_profile=minimax`; `opus` is explicit and documented - as a high-cost route. -- Likely mistake checked: Anthropic profiles could leak MiniMax provider state. - `artifact-lint` rejects MiniMax base URLs and MiniMax executor model IDs in - Anthropic routes, and the smoke covers Sonnet/Opus profiles. -- Likely mistake checked: static model selection could be overclaimed as runtime - model proof. Artifacts keep `model_identity_confirmed=false`, - `planner_identity_status=blocked`, and `verification.status=runtime-pending` - until `/status`, sentinel, or equivalent runtime evidence proves identity. -- Remaining risk: live account availability and usage thresholds can still make - Claude Code fall back or block at runtime. This implementation proves the - harness no longer breaks statically when the operator requests a different - governed model route. +- Likely mistake: accidentally building a custom remote-control server. The + fix must stay on Claude Code native `rc`. +- Likely mistake: removing privacy settings too broadly. Mitigation: only + remove known Remote Control blockers from shared project settings and keep + deny rules intact. +- Likely mistake: static doctor overclaims runtime success. Mitigation: doctor + reports runtime proof as `not_run_static_only` unless the operator runs live + Remote Control. +- Likely mistake: adding a skill count without updating hardcoded truth + surfaces. Mitigation: update startup/test/visualize checks and regenerate the + capability map. + +## Introspection: Post-Implementation + +- Verified mistake avoided: no custom remote-control server or network bridge + was added. The route documents and gates only native Claude Code RC. +- Verified mistake avoided: static checks do not claim live browser/mobile + connection. Doctor artifacts report `runtime_remote_control_started=false` + and `runtime_proof_status=not_run_static_only`. +- Verified mistake avoided: secret protections remained intact. Shared and + example profiles still deny `.env`, `.env.*`, `.claude/*.local.json`, and + `secrets/**`; no secret files were read. +- Remaining live-runtime caveat: this proves harness compatibility, not the + operator account's live RC eligibility. Team/Enterprise admin policy, + claude.ai login state, mobile app state, and network access still require a + manual authenticated RC run by the operator. diff --git a/docs/harness-capability-map.json b/docs/harness-capability-map.json index f1bf7dd..a08c78e 100644 --- a/docs/harness-capability-map.json +++ b/docs/harness-capability-map.json @@ -65,10 +65,10 @@ ], "counts": { "codex_skills": 1, - "eval_tasks": 22, + "eval_tasks": 23, "rules": 15, - "scripts": 56, - "skills": 35 + "scripts": 58, + "skills": 36 }, "evals": [ { @@ -89,6 +89,15 @@ "task_path": "evals/harness/tasks/m11-deepretaste-intent-icp-bootstrap.yaml", "title": "/deepretaste intent-to-ICP-to-taste bootstrap gate" }, + { + "expected_result": "pass", + "gate": "scripts/remote-control-smoke.sh --fixtures", + "golden_exists": "true", + "golden_path": "evals/harness/golden/m12-remote-control-smoke.json", + "id": "m12-remote-control-smoke", + "task_path": "evals/harness/tasks/m12-remote-control-smoke.yaml", + "title": "Native Claude Code Remote Control compatibility smoke" + }, { "expected_result": "pass", "gate": "scripts/agentfactory-smoke.sh", @@ -486,12 +495,12 @@ "sha256": "1cf17ea423e2356079eac43da0c8db744b325302a8e88c935aa4fd0c0cb1bf2f" }, { - "line_count": 713, + "line_count": 718, "name": "harness-capability-map", "path": "scripts/harness-capability-map.sh", "purpose": "capability map freshness gate", "required_gate": true, - "sha256": "a39852ab33f338fadadc2c48098ea7a73d03cc3ee4bcac19bf0b1fa80ccbae21" + "sha256": "95994dddf6a8e676f0b08df3fad96a5a7e76c889bebe8c1005b7e5dfa02365b5" }, { "line_count": 640, @@ -510,12 +519,12 @@ "sha256": "00eae7491bb379f3ff338f854e532eabcab9053ba2f4e0dcb5fc40b2c5d1b3ab" }, { - "line_count": 802, + "line_count": 811, "name": "harness-eval", "path": "scripts/harness-eval.sh", "purpose": "static eval pack runner", "required_gate": true, - "sha256": "529a3c955709e829310d27a050aa95201f607472214ee06bfa3c41876b6ecb0f" + "sha256": "67d99afab21fd9b3f351232643551dc4bf35d689823517d900d0ac91fd56e6bb" }, { "line_count": 322, @@ -614,12 +623,12 @@ "sha256": "814fdc31e20687d24b8efbb2b44d67a3ec932aaef5be9a730d791c66bfc2ff03" }, { - "line_count": 525, + "line_count": 533, "name": "opusminimax-doctor", "path": "scripts/opusminimax-doctor.sh", "purpose": "OpusMiniMax provider split doctor", "required_gate": true, - "sha256": "1601190d4e749ffb37ddf657c62e4cdb4f6c7ac384e4ff26095bc45d3af3ba9d" + "sha256": "cb5fe25369342ebe8d517507170a5b64b01fba48e69b85f827ce38335dccbcbd" }, { "line_count": 400, @@ -694,12 +703,28 @@ "sha256": "51abd2accac23466bd68bea9876970fdfa1cdd0985d11146699db7a16ffa5302" }, { - "line_count": 92, + "line_count": 93, "name": "release-check", "path": "scripts/release-check.sh", "purpose": "public release/static gate", "required_gate": true, - "sha256": "c069956f1e882f0dd1728d930410fa2453be16188acc2ee6250a85c228498e79" + "sha256": "27ab8b97947dbf0e432a58147702b662ea0d66dab8fe8f209f8acfef2ac2f8b3" + }, + { + "line_count": 280, + "name": "remote-control-doctor", + "path": "scripts/remote-control-doctor.sh", + "purpose": "Static readiness doctor for Claude Code native Remote Control.", + "required_gate": false, + "sha256": "96df5ac58d7b078915729d3b7a86e556b6674a46ea868f3f97d4e958450fa925" + }, + { + "line_count": 331, + "name": "remote-control-smoke", + "path": "scripts/remote-control-smoke.sh", + "purpose": "native Claude Code Remote Control compatibility gate", + "required_gate": true, + "sha256": "7b2620306997b9b1111dde08d364bac0e48249dd6727db05cda19778e867ac83" }, { "line_count": 144, @@ -758,12 +783,12 @@ "sha256": "3e80abf5a2f2a5dc3532dbb294cf6f554c4acfa39189baaee2e46fcc3ff3a5f4" }, { - "line_count": 117, + "line_count": 118, "name": "start-session", "path": "scripts/start-session.sh", "purpose": "minmaxing Harness - Session Start", "required_gate": false, - "sha256": "1bfc1bb8efd603381bfbf06e5bef7e3920b79a6e4874e7de0669bd0c03431664" + "sha256": "81c6da767be4e12a0781ac6771df1aa6dae2897e83eb8a9f82870de6c6c59e89" }, { "line_count": 400, @@ -782,12 +807,12 @@ "sha256": "18c827b8746916ccd198045f0e8c6e4cd30ca714ca2b1c0dc05f6f47b6f3d263" }, { - "line_count": 1912, + "line_count": 2000, "name": "test-harness", "path": "scripts/test-harness.sh", "purpose": "full local harness regression suite", "required_gate": true, - "sha256": "d3868be503ca8e971431a7ab51755dd0fdb2f360df1add6192f284b471a11261" + "sha256": "669ee0474864ce2aede91e1b04aaf3ff3aecf4eca23c2bce177d7f3376eaa52f" }, { "line_count": 127, @@ -811,7 +836,7 @@ "path": "scripts/visualize-smoke.sh", "purpose": "Smoke the /visualize and /visualizeworkflow contracts without secrets or image providers.", "required_gate": false, - "sha256": "fc3f3ec2347d9c9b774c6013a3c68fbce6d70c6efb09dd89dbd233ba2f587827" + "sha256": "d703f1466b573a3644921c6bdcedb64c1a4bcfe106320c32e29d9ab6dd96250e" }, { "line_count": 117, @@ -849,9 +874,11 @@ }, "settings": { "env_keys": [ - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC", "CLAUDE_CODE_NO_FLICKER", - "DISABLE_AUTO_COMPACT" + "DISABLE_AUTOUPDATER", + "DISABLE_AUTO_COMPACT", + "DISABLE_ERROR_REPORTING", + "DISABLE_FEEDBACK_COMMAND" ], "exists": true, "hooks": [ @@ -1520,6 +1547,27 @@ "slash": "/qa", "user_invocable": true }, + { + "argument_hint": "[name/status/troubleshoot]", + "core_route": true, + "description": "Use Claude Code native Remote Control (/remote-control, /rc, claude --remote-control, claude remote-control) safely inside the minmaxing harness without custom network control planes, API-key auth, or static runtime overclaims.", + "group": "operations", + "line_count": 127, + "model_invocation": false, + "name": "remote-control", + "path": ".claude/skills/remote-control/SKILL.md", + "related_eval_tasks": [ + "evals/harness/tasks/m12-remote-control-smoke.yaml" + ], + "related_rules": [], + "related_scripts": [ + "scripts/remote-control-doctor.sh", + "scripts/remote-control-smoke.sh" + ], + "sha256": "30b8a3d03bf3ea8f6fc94f7ea6df6f3c133921d2242a335940e10a0bd4770cdb", + "slash": "/remote-control", + "user_invocable": true + }, { "argument_hint": "", "core_route": false, @@ -1671,7 +1719,7 @@ "core_route": true, "description": "Run the full minmaxing workflow end to end for one request. Use when the user wants planning, implementation, verification, and closeout to happen automatically in one command.", "group": "execution", - "line_count": 785, + "line_count": 786, "model_invocation": false, "name": "workflow", "path": ".claude/skills/workflow/SKILL.md", @@ -1693,7 +1741,7 @@ "scripts/test-harness.sh", "scripts/harness-capability-map.sh" ], - "sha256": "8af32a68b2cc13e5cd70f821b86aa6d3b187dc45626e61d82204bfa2464f087b", + "sha256": "4cfd883f190b08c8c2b639cb9f54fb3359be57e155696c33894cded814fa2f92", "slash": "/workflow", "user_invocable": true } @@ -1718,8 +1766,8 @@ "summary": { "codex_file_count": 4, "codex_skill_count": 1, - "core_route_count": 15, - "eval_task_count": 22, + "core_route_count": 16, + "eval_task_count": 23, "groups": { "agent-systems": [ "/agentfactory" @@ -1751,7 +1799,8 @@ "/memory" ], "operations": [ - "/overnight" + "/overnight", + "/remote-control" ], "parallelism": [ "/hive", @@ -1789,7 +1838,7 @@ }, "hook_event_count": 12, "rule_count": 15, - "script_count": 56, - "skill_count": 35 + "script_count": 58, + "skill_count": 36 } } diff --git a/docs/harness-capability-map.md b/docs/harness-capability-map.md index 8da11e8..02c8615 100644 --- a/docs/harness-capability-map.md +++ b/docs/harness-capability-map.md @@ -8,14 +8,14 @@ choose, which scripts prove a claim, or where the detailed contract lives. ## Summary -- Skills: 35 +- Skills: 36 - Rules: 15 -- Scripts: 56 -- Static eval tasks: 22 +- Scripts: 58 +- Static eval tasks: 23 - Hook entries: 12 - Codex config files: 4 - Codex repo skills: 1 -- Core routes: 15 +- Core routes: 16 - Secret policy: generated from committed repo truth only; never reads `.env`, `.env.*`, `.claude/settings.local.json`, private customer artifacts, or runtime secrets. @@ -29,7 +29,7 @@ choose, which scripts prove a claim, or where the detailed contract lives. - `kernel`: `/align`, `/deepretaste`, `/tastebootstrap` - `knowledge`: `/claudeproduct` - `memory`: `/memory` -- `operations`: `/overnight` +- `operations`: `/overnight`, `/remote-control` - `parallelism`: `/hive`, `/parallel`, `/sprint` - `planning`: `/autoplan`, `/council` - `quality`: `/audit`, `/introspect`, `/qa`, `/review`, `/verify` @@ -68,6 +68,7 @@ choose, which scripts prove a claim, or where the detailed contract lives. | `/overnight` | `operations` | yes | no | `.claude/skills/overnight/SKILL.md` | /overnight | | `/parallel` | `parallelism` | manual | yes | `.claude/skills/parallel/SKILL.md` | Run dense minmaxing work as a hardware-aware, main-orchestrated parallel workflow with bounded packets, explicit ownership, sync barriers, aggregation, and independent verification. | | `/qa` | `quality` | yes | no | `.claude/skills/qa/SKILL.md` | /qa | +| `/remote-control` | `operations` | manual | yes | `.claude/skills/remote-control/SKILL.md` | Use Claude Code native Remote Control (/remote-control, /rc, claude --remote-control, claude remote-control) safely inside the minmaxing harness without custom network control planes, API-key auth, or static runtime overclaims. | | `/review` | `quality` | yes | no | `.claude/skills/review/SKILL.md` | /review | | `/ship` | `release` | yes | no | `.claude/skills/ship/SKILL.md` | /ship | | `/sprint` | `parallelism` | yes | no | `.claude/skills/sprint/SKILL.md` | /sprint | @@ -127,6 +128,7 @@ choose, which scripts prove a claim, or where the detailed contract lives. | `parallel-capacity` | local parallel capacity profile | `scripts/parallel-capacity.sh` | | `parallel-plan-lint` | parallel plan fixture lint | `scripts/parallel-plan-lint.sh` | | `release-check` | public release/static gate | `scripts/release-check.sh` | +| `remote-control-smoke` | native Claude Code Remote Control compatibility gate | `scripts/remote-control-smoke.sh` | | `test-harness` | full local harness regression suite | `scripts/test-harness.sh` | ## Static Eval Gates @@ -135,6 +137,7 @@ choose, which scripts prove a claim, or where the detailed contract lives. | --- | --- | --- | --- | --- | | `m10-defineicp-taste-evolution` | `scripts/defineicp-smoke.sh --fixtures` | `reject` | `evals/harness/tasks/m10-defineicp-taste-evolution.yaml` | `evals/harness/golden/m10-defineicp-taste-evolution.json` | | `m11-deepretaste-intent-icp-bootstrap` | `scripts/deepretaste-smoke.sh --fixtures` | `reject` | `evals/harness/tasks/m11-deepretaste-intent-icp-bootstrap.yaml` | `evals/harness/golden/m11-deepretaste-intent-icp-bootstrap.json` | +| `m12-remote-control-smoke` | `scripts/remote-control-smoke.sh --fixtures` | `pass` | `evals/harness/tasks/m12-remote-control-smoke.yaml` | `evals/harness/golden/m12-remote-control-smoke.json` | | `m4-agentfactory-kill-switch-evidence` | `scripts/agentfactory-smoke.sh` | `pass` | `evals/harness/tasks/m4-agentfactory-kill-switch-evidence.yaml` | `evals/harness/golden/m4-agentfactory-kill-switch-evidence.json` | | `m4-artifact-sidecar-lint` | `scripts/artifact-lint.sh --fixtures` | `pass` | `evals/harness/tasks/m4-artifact-sidecar-lint.yaml` | `evals/harness/golden/m4-artifact-sidecar-lint.json` | | `m4-codex-run-artifact-proof` | `scripts/codex-run-smoke.sh` | `pass` | `evals/harness/tasks/m4-codex-run-artifact-proof.yaml` | `evals/harness/golden/m4-codex-run-artifact-proof.json` | diff --git a/evals/harness/golden/m12-remote-control-smoke.json b/evals/harness/golden/m12-remote-control-smoke.json new file mode 100644 index 0000000..d10151d --- /dev/null +++ b/evals/harness/golden/m12-remote-control-smoke.json @@ -0,0 +1,12 @@ +{ + "expected_evidence": "scripts/remote-control-smoke.sh --fixtures validates the /remote-control skill contract, static doctor, shared-settings blocker removal, no-secret fixtures, and native-only Claude Code Remote Control boundaries", + "expected_result": "pass", + "gate": "remote-control-smoke", + "id": "m12-remote-control-smoke", + "requires": [ + ".claude/skills/remote-control/SKILL.md", + "scripts/remote-control-doctor.sh", + "scripts/remote-control-smoke.sh", + ".taste/fixtures/remote-control" + ] +} diff --git a/evals/harness/tasks/m12-remote-control-smoke.yaml b/evals/harness/tasks/m12-remote-control-smoke.yaml new file mode 100644 index 0000000..5a9bd1d --- /dev/null +++ b/evals/harness/tasks/m12-remote-control-smoke.yaml @@ -0,0 +1,6 @@ +id: m12-remote-control-smoke +title: Native Claude Code Remote Control compatibility smoke +gate: scripts/remote-control-smoke.sh --fixtures +expected_result: pass +golden: evals/harness/golden/m12-remote-control-smoke.json +evidence: validates native Remote Control commands, settings blockers, static runtime-proof boundaries, fixtures, and release wiring diff --git a/scripts/harness-capability-map.sh b/scripts/harness-capability-map.sh index c291aca..6580e1a 100755 --- a/scripts/harness-capability-map.sh +++ b/scripts/harness-capability-map.sh @@ -104,6 +104,7 @@ ROUTE_GROUPS = { "ship": "release", "memory": "memory", "overnight": "operations", + "remote-control": "operations", "council": "planning", "visualize": "design", } @@ -124,6 +125,7 @@ CORE_ROUTES = { "verify", "agentfactory", "demo", + "remote-control", } REQUIRED_COMMANDS = { @@ -143,6 +145,7 @@ REQUIRED_COMMANDS = { "opusminimax-doctor": "OpusMiniMax provider split doctor", "opusworkflow-smoke": "OpusWorkflow cost-optimized route gate", "opussonnetworkflow": "optional Claude-only Opus plus Sonnet workflow wrapper", + "remote-control-smoke": "native Claude Code Remote Control compatibility gate", "parallel-capacity": "local parallel capacity profile", "parallel-aggregate": "parallel worker aggregate validator", "parallel-plan-lint": "parallel plan fixture lint", @@ -185,6 +188,8 @@ SCRIPT_OWNERS = { "opusworkflow": ["opusworkflow"], "opusworkflow-smoke": ["opusworkflow"], "opussonnetworkflow": ["opussonnet", "opusworkflow"], + "remote-control-doctor": ["remote-control"], + "remote-control-smoke": ["remote-control"], "harness-eval": ["workflow"], "release-check": ["ship", "workflow"], "test-harness": ["workflow"], diff --git a/scripts/harness-eval.sh b/scripts/harness-eval.sh index 2349da0..0a6f361 100755 --- a/scripts/harness-eval.sh +++ b/scripts/harness-eval.sh @@ -70,6 +70,7 @@ KNOWN_GATES = { "deepretaste-smoke", "opusminimax-benchmark-smoke", "opusworkflow-smoke", + "remote-control-smoke", "spec-archive-smoke", } VALID_RESULTS = {"pass", "reject", "accept", "fail", "skip", "blocked"} @@ -276,6 +277,10 @@ def normalize_gate(value: str) -> str: "opusworkflow-smoke": "opusworkflow-smoke", "scripts/opusworkflow-smoke.sh": "opusworkflow-smoke", "bash scripts/opusworkflow-smoke.sh": "opusworkflow-smoke", + "remote-control-smoke": "remote-control-smoke", + "scripts/remote-control-smoke.sh": "remote-control-smoke", + "scripts/remote-control-smoke.sh --fixtures": "remote-control-smoke", + "bash scripts/remote-control-smoke.sh --fixtures": "remote-control-smoke", "spec-archive-smoke": "spec-archive-smoke", "scripts/spec-archive.sh": "spec-archive-smoke", "scripts/test-harness.sh": "spec-archive-smoke", @@ -644,6 +649,10 @@ run_gate() { require_gate_script "scripts/opusworkflow-smoke.sh" || return $? bash "$ROOT_DIR/scripts/opusworkflow-smoke.sh" ;; + "remote-control-smoke") + require_gate_script "scripts/remote-control-smoke.sh" || return $? + bash "$ROOT_DIR/scripts/remote-control-smoke.sh" --fixtures + ;; "spec-archive-smoke") require_gate_script "scripts/spec-archive.sh" || return $? run_spec_archive_smoke diff --git a/scripts/opusminimax-doctor.sh b/scripts/opusminimax-doctor.sh index ff7b649..5fd6b1d 100755 --- a/scripts/opusminimax-doctor.sh +++ b/scripts/opusminimax-doctor.sh @@ -206,7 +206,9 @@ def repair_local_profiles( planner_env.pop(key, None) changed.append(rel(PLANNER_LOCAL)) for key, value in { - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4-7", "CLAUDE_CODE_EFFORT_LEVEL": "xhigh", "DISABLE_AUTO_COMPACT": "0", @@ -246,7 +248,9 @@ def repair_local_profiles( "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-6", "CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6", "CLAUDE_CODE_EFFORT_LEVEL": "high", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "DISABLE_AUTO_COMPACT": "0", "CLAUDE_CODE_NO_FLICKER": "1", }.items(): @@ -280,7 +284,9 @@ def repair_local_profiles( "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-6", "CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6", "CLAUDE_CODE_EFFORT_LEVEL": "xhigh", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "DISABLE_AUTO_COMPACT": "0", "CLAUDE_CODE_NO_FLICKER": "1", }.items(): @@ -312,7 +318,9 @@ def repair_local_profiles( "ANTHROPIC_BASE_URL": "https://api.minimax.io/anthropic", "MINIMAX_API_HOST": "https://api.minimax.io", "API_TIMEOUT_MS": "3000000", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "ANTHROPIC_MODEL": "MiniMax-M2.7-highspeed", "ANTHROPIC_SMALL_FAST_MODEL": "MiniMax-M2.7-highspeed", "ANTHROPIC_DEFAULT_SONNET_MODEL": "MiniMax-M2.7-highspeed", diff --git a/scripts/release-check.sh b/scripts/release-check.sh index 240593f..db405f4 100755 --- a/scripts/release-check.sh +++ b/scripts/release-check.sh @@ -66,6 +66,7 @@ run bash scripts/deepretaste-smoke.sh --fixtures run bash scripts/opusminimax-doctor.sh --static >/dev/null run bash scripts/opusminimax-benchmark-smoke.sh --fixtures run bash scripts/opusworkflow-smoke.sh +run bash scripts/remote-control-smoke.sh --fixtures run bash scripts/artifact-lint.sh --fixtures run bash scripts/harness-eval.sh --json >/dev/null run bash scripts/security-smoke.sh diff --git a/scripts/remote-control-doctor.sh b/scripts/remote-control-doctor.sh new file mode 100755 index 0000000..7799ce5 --- /dev/null +++ b/scripts/remote-control-doctor.sh @@ -0,0 +1,279 @@ +#!/bin/bash +# Static readiness doctor for Claude Code native Remote Control. + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +MODE="static" +JSON_ONLY=0 + +usage() { + cat >&2 <<'EOF' +Usage: + bash scripts/remote-control-doctor.sh [--static] [--json] + +Checks committed, no-secret harness compatibility with Claude Code native +Remote Control. This doctor never starts `claude remote-control`. +EOF +} + +while [ "$#" -gt 0 ]; do + case "$1" in + "--static") + MODE="static" + shift + ;; + "--json") + JSON_ONLY=1 + shift + ;; + "-h"|"--help") + usage + exit 0 + ;; + *) + usage + exit 2 + ;; + esac +done + +python3 - "$ROOT_DIR" "$MODE" "$JSON_ONLY" <<'PY' +import json +import os +import pathlib +import re +import shutil +import subprocess +import sys +from typing import Any + + +ROOT = pathlib.Path(sys.argv[1]).resolve() +MODE = sys.argv[2] +JSON_ONLY = sys.argv[3] == "1" +SETTINGS_PATH = ROOT / ".claude" / "settings.json" + +SHARED_BLOCKERS = [ + "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC", + "DISABLE_TELEMETRY", + "ANTHROPIC_API_KEY", + "ANTHROPIC_AUTH_TOKEN", + "CLAUDE_CODE_OAUTH_TOKEN", + "CLAUDE_CODE_USE_BEDROCK", + "CLAUDE_CODE_USE_VERTEX", + "CLAUDE_CODE_USE_FOUNDRY", +] + +PROCESS_WARNINGS = [ + "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC", + "DISABLE_TELEMETRY", + "ANTHROPIC_API_KEY", + "ANTHROPIC_AUTH_TOKEN", + "CLAUDE_CODE_OAUTH_TOKEN", + "CLAUDE_CODE_USE_BEDROCK", + "CLAUDE_CODE_USE_VERTEX", + "CLAUDE_CODE_USE_FOUNDRY", +] + +REQUIRED_DENY_RULES = [ + "Read(./.env)", + "Read(./.env.*)", + "Read(./.claude/settings.local.json)", + "Read(./.claude/*.local.json)", + "Read(./secrets/**)", +] + + +def rel(path: pathlib.Path) -> str: + return path.resolve().relative_to(ROOT).as_posix() + + +def check(check_id: str, status: str, summary: str, evidence: Any = None) -> dict[str, Any]: + item: dict[str, Any] = { + "id": check_id, + "status": status, + "summary": summary, + } + if evidence is not None: + item["evidence"] = evidence + return item + + +def parse_version(text: str) -> tuple[int, int, int] | None: + match = re.search(r"(\d+)\.(\d+)\.(\d+)", text) + if not match: + return None + return tuple(int(part) for part in match.groups()) + + +checks: list[dict[str, Any]] = [] +settings: dict[str, Any] = {} + +if not SETTINGS_PATH.is_file(): + checks.append(check("shared-settings-present", "fail", "Missing .claude/settings.json")) +else: + try: + settings = json.loads(SETTINGS_PATH.read_text(encoding="utf-8")) + except Exception as exc: + checks.append(check("shared-settings-json", "fail", f"Invalid JSON: {exc}")) + else: + checks.append(check("shared-settings-json", "pass", "Shared project settings JSON is valid", rel(SETTINGS_PATH))) + +env = settings.get("env", {}) if isinstance(settings, dict) else {} +if not isinstance(env, dict): + checks.append(check("shared-env-object", "fail", "settings.env must be an object")) + env = {} +else: + blockers = [name for name in SHARED_BLOCKERS if name in env] + if blockers: + checks.append( + check( + "shared-env-blockers", + "fail", + "Shared project settings set Remote Control blocker or auth variables", + {"variables_present": blockers}, + ) + ) + else: + checks.append( + check( + "shared-env-blockers", + "pass", + "Shared project settings do not set known Remote Control blocker or provider auth variables", + ) + ) + +disable_remote = settings.get("disableRemoteControl") if isinstance(settings, dict) else None +if disable_remote is True: + checks.append(check("disable-remote-control-setting", "fail", "disableRemoteControl=true blocks native Remote Control")) +else: + checks.append(check("disable-remote-control-setting", "pass", "Shared settings do not disable native Remote Control")) + +deny_rules = [] +try: + deny_rules = settings.get("permissions", {}).get("deny", []) if isinstance(settings, dict) else [] +except AttributeError: + deny_rules = [] +if not isinstance(deny_rules, list): + checks.append(check("secret-deny-rules", "fail", "permissions.deny must be a list")) +else: + missing = [rule for rule in REQUIRED_DENY_RULES if rule not in deny_rules] + if missing: + checks.append( + check( + "secret-deny-rules", + "fail", + "Shared settings are missing required secret-read deny rules", + {"missing": missing}, + ) + ) + else: + checks.append( + check( + "secret-deny-rules", + "pass", + "Shared settings deny .env, local Claude settings, and secrets paths", + ) + ) + +process_present = [name for name in PROCESS_WARNINGS if name in os.environ] +if process_present: + checks.append( + check( + "process-env-remote-control-warnings", + "warn", + "Current process environment contains variables that can block a live Remote Control session", + {"variables_present": process_present}, + ) + ) +else: + checks.append( + check( + "process-env-remote-control-warnings", + "pass", + "Current process environment does not expose known Remote Control blockers by name", + ) + ) + +claude_bin = shutil.which("claude") +version_text = "" +if not claude_bin: + checks.append(check("claude-cli-version", "warn", "claude command not found; runtime version not checked")) +else: + try: + proc = subprocess.run( + [claude_bin, "--version"], + text=True, + capture_output=True, + timeout=5, + check=False, + ) + version_text = (proc.stdout or proc.stderr or "").strip() + except Exception as exc: + checks.append(check("claude-cli-version", "warn", f"Could not execute claude --version: {exc}")) + else: + parsed = parse_version(version_text) + if parsed is None: + checks.append(check("claude-cli-version", "warn", "Could not parse claude --version output")) + elif parsed >= (2, 1, 51): + checks.append( + check( + "claude-cli-version", + "pass", + "Claude Code CLI version is at or above native Remote Control minimum", + {"version": ".".join(str(part) for part in parsed)}, + ) + ) + else: + checks.append( + check( + "claude-cli-version", + "warn", + "Claude Code CLI may be too old for native Remote Control", + {"version": ".".join(str(part) for part in parsed)}, + ) + ) + +statuses = {item["status"] for item in checks} +overall = "fail" if "fail" in statuses else "warn" if "warn" in statuses else "pass" +payload = { + "artifact_type": "remote-control-readiness", + "mode": MODE, + "status": overall, + "native_claude_code_remote_control": True, + "runtime_remote_control_started": False, + "runtime_proof_status": "not_run_static_only", + "custom_network_control_plane": False, + "api_key_auth_allowed": False, + "auth": { + "requires_claude_ai_subscription": True, + "api_keys_supported": False, + "oauth_login_required": True, + }, + "commands": [ + "/remote-control", + "/rc", + "claude --remote-control", + "claude remote-control", + ], + "shared_project_env_blockers": [name for name in SHARED_BLOCKERS if name in env], + "process_env_blocker_names_present": process_present, + "secrets": { + "read_secret_files": False, + "tokens_in_url": False, + "secret_values_redacted": True, + }, + "operator_stop_required": True, + "checks": checks, +} + +if JSON_ONLY: + print(json.dumps(payload, indent=2, sort_keys=True)) +else: + print(f"[remote-control-doctor] status={overall} mode={MODE}") + for item in checks: + print(f"[{item['status'].upper()}] {item['id']}: {item['summary']}") + +raise SystemExit(1 if overall == "fail" else 0) +PY diff --git a/scripts/remote-control-smoke.sh b/scripts/remote-control-smoke.sh new file mode 100755 index 0000000..cccaf65 --- /dev/null +++ b/scripts/remote-control-smoke.sh @@ -0,0 +1,331 @@ +#!/bin/bash +# Static smoke gate for Claude Code native Remote Control harness compatibility. + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +FIXTURE_DIR="$ROOT_DIR/.taste/fixtures/remote-control" +MODE="" +ARTIFACT_PATH="" + +usage() { + cat >&2 <<'EOF' +Usage: + bash scripts/remote-control-smoke.sh --fixtures + bash scripts/remote-control-smoke.sh --artifact PATH + +--fixtures validates the native Remote Control route, static doctor, docs, +eval metadata, and deterministic green/red fixtures without starting RC. +--artifact validates one sanitized remote-control-readiness JSON artifact. +EOF +} + +fail() { + echo "[FAIL] $*" >&2 + exit 1 +} + +require_file() { + [ -f "$1" ] || fail "missing required file: $1" +} + +require_executable() { + [ -x "$1" ] || fail "required script is not executable: $1" +} + +require_grep() { + local pattern="$1" + local file="$2" + grep -Fq -- "$pattern" "$file" 2>/dev/null || fail "missing pattern '$pattern' in $file" +} + +require_not_grep() { + local pattern="$1" + local file="$2" + if grep -Fq -- "$pattern" "$file" 2>/dev/null; then + fail "forbidden pattern '$pattern' found in $file" + fi +} + +while [ "$#" -gt 0 ]; do + case "$1" in + "--fixtures") + MODE="fixtures" + shift + ;; + "--artifact") + MODE="artifact" + ARTIFACT_PATH="${2:-}" + [ -n "$ARTIFACT_PATH" ] || { + usage + exit 2 + } + shift 2 + ;; + "-h"|"--help") + usage + exit 0 + ;; + *) + usage + exit 2 + ;; + esac +done + +[ -n "$MODE" ] || { + usage + exit 2 +} + +validate_artifact() { + local artifact="$1" + python3 - "$artifact" <<'PY' +import json +import pathlib +import re +import sys + + +path = pathlib.Path(sys.argv[1]) + +SECRET_RE = re.compile( + r"(sk-[A-Za-z0-9_-]{20,}|OPENAI_API_KEY\s*=|ANTHROPIC_API_KEY\s*=|" + r"MINIMAX_API_KEY\s*=|password\s*[:=]|secret\s*[:=]|token\s*[:=]|" + r"BEGIN [A-Z ]*PRIVATE KEY)", + re.IGNORECASE, +) + +REQUIRED_COMMANDS = { + "/remote-control", + "/rc", + "claude --remote-control", + "claude remote-control", +} + + +def fail(message: str) -> None: + print(f"[FAIL] {path}: {message}", file=sys.stderr) + raise SystemExit(1) + + +try: + raw = path.read_text(encoding="utf-8") +except FileNotFoundError: + fail("artifact file does not exist") + +if SECRET_RE.search(raw): + fail("artifact contains secret-like material") + +try: + data = json.loads(raw) +except json.JSONDecodeError as exc: + fail(f"invalid JSON: {exc}") + +if data.get("artifact_type") != "remote-control-readiness": + fail("artifact_type must be remote-control-readiness") +if data.get("status") not in {"pass", "warn"}: + fail("status must be pass or warn for an accepted readiness artifact") +if data.get("native_claude_code_remote_control") is not True: + fail("native_claude_code_remote_control must be true") +if data.get("custom_network_control_plane") is not False: + fail("custom_network_control_plane must be false") +if data.get("api_key_auth_allowed") is not False: + fail("api_key_auth_allowed must be false") +if data.get("runtime_remote_control_started") is not False: + fail("static artifacts must not start runtime Remote Control") + +runtime_proof = str(data.get("runtime_proof_status", "")).strip().lower() +if runtime_proof in {"confirmed", "proven", "pass", "passed", "runtime_passed"}: + fail("static artifact must not claim live Remote Control runtime proof") + +commands = set(data.get("commands") or []) +missing_commands = sorted(REQUIRED_COMMANDS - commands) +if missing_commands: + fail(f"missing native command aliases: {missing_commands}") + +auth = data.get("auth") or {} +if auth.get("requires_claude_ai_subscription") is not True: + fail("auth.requires_claude_ai_subscription must be true") +if auth.get("api_keys_supported") is not False: + fail("auth.api_keys_supported must be false") +if auth.get("oauth_login_required") is not True: + fail("auth.oauth_login_required must be true") + +if data.get("shared_project_env_blockers"): + fail("shared_project_env_blockers must be empty") + +secrets = data.get("secrets") or {} +if secrets.get("read_secret_files") is not False: + fail("secrets.read_secret_files must be false") +if secrets.get("tokens_in_url") is not False: + fail("secrets.tokens_in_url must be false") +if secrets.get("secret_values_redacted") is not True: + fail("secrets.secret_values_redacted must be true") + +if data.get("operator_stop_required") is not True: + fail("operator_stop_required must be true for live native RC sessions") + +for item in data.get("checks") or []: + if isinstance(item, dict) and item.get("status") == "fail": + fail(f"readiness check failed: {item.get('id', '')}") + +print(f"[PASS] {path}") +PY +} + +run_static_contract_checks() { + local skill="$ROOT_DIR/.claude/skills/remote-control/SKILL.md" + local doctor="$ROOT_DIR/scripts/remote-control-doctor.sh" + local smoke="$ROOT_DIR/scripts/remote-control-smoke.sh" + local task="$ROOT_DIR/evals/harness/tasks/m12-remote-control-smoke.yaml" + local golden="$ROOT_DIR/evals/harness/golden/m12-remote-control-smoke.json" + + require_file "$skill" + require_file "$doctor" + require_file "$smoke" + require_file "$task" + require_file "$golden" + require_executable "$doctor" + require_executable "$smoke" + + for pattern in \ + "name: remote-control" \ + "disable-model-invocation: true" \ + "# /remote-control" \ + "native Remote Control" \ + "/remote-control" \ + "/rc" \ + "claude --remote-control" \ + "claude remote-control" \ + "claude --remote" \ + "custom remote server" \ + "MCP control plane" \ + "claude.ai subscription" \ + "ANTHROPIC_API_KEY" \ + "CLAUDE_CODE_OAUTH_TOKEN" \ + "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC" \ + "DISABLE_TELEMETRY" \ + "disableRemoteControl" \ + "bypassPermissions" \ + "Static harness evidence is compatibility evidence"; do + require_grep "$pattern" "$skill" + done + + for pattern in \ + "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC" \ + "DISABLE_TELEMETRY" \ + "ANTHROPIC_API_KEY" \ + "CLAUDE_CODE_OAUTH_TOKEN" \ + "disableRemoteControl" \ + "shared_project_env_blockers" \ + "runtime_remote_control_started" \ + "not_run_static_only" \ + "custom_network_control_plane" \ + "api_key_auth_allowed" \ + "claude --version"; do + require_grep "$pattern" "$doctor" + done + + for pattern in \ + "custom_network_control_plane" \ + "api_key_auth_allowed" \ + "runtime_remote_control_started" \ + "shared_project_env_blockers" \ + "tokens_in_url" \ + "operator_stop_required"; do + require_grep "$pattern" "$smoke" + done + + for file in README.md CLAUDE.md AGENTS.md scripts/start-session.sh; do + require_grep "/remote-control" "$ROOT_DIR/$file" + require_grep "claude remote-control" "$ROOT_DIR/$file" + done + + require_grep "remote-control" "$ROOT_DIR/scripts/harness-capability-map.sh" + require_grep "remote-control-smoke" "$ROOT_DIR/scripts/harness-eval.sh" + require_grep "remote-control-smoke" "$ROOT_DIR/scripts/release-check.sh" + require_grep "m12-remote-control-smoke" "$task" + require_grep "m12-remote-control-smoke" "$golden" + + python3 - "$ROOT_DIR/.claude/settings.json" <<'PY' +import json +import pathlib +import sys + +settings_path = pathlib.Path(sys.argv[1]) +data = json.loads(settings_path.read_text(encoding="utf-8")) +env = data.get("env") or {} +blockers = { + "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC", + "DISABLE_TELEMETRY", + "ANTHROPIC_API_KEY", + "ANTHROPIC_AUTH_TOKEN", + "CLAUDE_CODE_OAUTH_TOKEN", + "CLAUDE_CODE_USE_BEDROCK", + "CLAUDE_CODE_USE_VERTEX", + "CLAUDE_CODE_USE_FOUNDRY", +} +present = sorted(name for name in blockers if name in env) +if present: + raise SystemExit(f"shared project env still contains Remote Control blockers: {present}") +if data.get("disableRemoteControl") is True: + raise SystemExit("shared project settings disable native Remote Control") +deny = data.get("permissions", {}).get("deny", []) +for rule in [ + "Read(./.env)", + "Read(./.env.*)", + "Read(./.claude/settings.local.json)", + "Read(./.claude/*.local.json)", + "Read(./secrets/**)", +]: + if rule not in deny: + raise SystemExit(f"missing required deny rule: {rule}") +PY + + local doctor_json + doctor_json="$(mktemp)" + trap 'rm -f "${doctor_json:-}"' RETURN + bash "$doctor" --static --json >"$doctor_json" + validate_artifact "$doctor_json" >/dev/null +} + +run_fixtures() { + run_static_contract_checks + + local green_count=0 + local red_count=0 + local path + + for path in "$FIXTURE_DIR"/green/*.json; do + [ -e "$path" ] || fail "missing green remote-control fixtures" + validate_artifact "$path" >/dev/null + green_count=$((green_count + 1)) + done + + for path in "$FIXTURE_DIR"/red/*.json; do + [ -e "$path" ] || fail "missing red remote-control fixtures" + if validate_artifact "$path" >/dev/null 2>&1; then + fail "red fixture was accepted: ${path#$ROOT_DIR/}" + fi + red_count=$((red_count + 1)) + done + + [ "$green_count" -ge 1 ] || fail "expected at least one green fixture" + [ "$red_count" -ge 5 ] || fail "expected at least five red fixtures" + + echo "[PASS] native Claude Code Remote Control contract smoke passed" +} + +case "$MODE" in + "fixtures") + run_fixtures + ;; + "artifact") + validate_artifact "$ARTIFACT_PATH" + ;; + *) + usage + exit 2 + ;; +esac diff --git a/scripts/start-session.sh b/scripts/start-session.sh index 504e954..ea14452 100755 --- a/scripts/start-session.sh +++ b/scripts/start-session.sh @@ -54,11 +54,11 @@ FAIL=0 # Check skills SKILL_COUNT=$(find .claude/skills -name "SKILL.md" 2>/dev/null | wc -l | tr -d ' ') -if [ "$SKILL_COUNT" -ge 35 ]; then +if [ "$SKILL_COUNT" -ge 36 ]; then echo " [PASS] $SKILL_COUNT skills found" PASS=$((PASS+1)) else - echo " [FAIL] Expected 35 skills, found $SKILL_COUNT" + echo " [FAIL] Expected 36 skills, found $SKILL_COUNT" FAIL=$((FAIL+1)) fi @@ -109,8 +109,9 @@ echo "Skills: /tastebootstrap, /workflow, /opusworkflow, /opusminimax, /digestfl echo " /review, /qa, /ship, /investigate, /sprint, /overnight, /council," echo " /audit, /deepresearch, /icpweek, /webresearch, /browse, /introspect, /codesearch," echo " /memory, /agentfactory, /parallel, /metacognition, /claudeproduct," -echo " /hive," +echo " /hive, /remote-control," echo " /hiveworkflow, /visualize, /visualizeworkflow, /demo" +echo "Remote Control: /remote-control inside Claude Code, or claude remote-control from the CLI after claude.ai login" echo "" echo "Start with: ./scripts/test-harness.sh to verify setup" echo "Optional runtime check: RUN_CLAUDE_INTEGRATION=1 bash scripts/test-harness.sh" diff --git a/scripts/test-harness.sh b/scripts/test-harness.sh index bffd7d1..fb47d87 100755 --- a/scripts/test-harness.sh +++ b/scripts/test-harness.sh @@ -497,7 +497,7 @@ if grep -Fq "pre-plan" .claude/skills/introspect/SKILL.md 2>/dev/null && \ grep -Fq "SPEC.md is frozen" .claude/skills/autoplan/SKILL.md 2>/dev/null && \ grep -Fq 'not a substitute for `/introspect`' .claude/skills/review/SKILL.md 2>/dev/null && \ grep -Fq "/introspect" README.md 2>/dev/null && \ - grep -Fq "35 skills" README.md 2>/dev/null && \ + grep -Fq "36 skills" README.md 2>/dev/null && \ grep -Fq "Introspection Gate" CLAUDE.md 2>/dev/null && \ grep -Fq "hard gate" AGENTS.md 2>/dev/null && \ [ ! -f ".claude/skills/instrospect/SKILL.md" ] && \ @@ -620,6 +620,94 @@ else test_fail "/claudeproduct contract, docs, fixtures, or scorecard are incomplete" fi +# Test 3g-remote: Native Claude Code Remote Control Contract +echo "[3g-remote] Native Claude Code Remote Control Contract" +REMOTE_CONTROL_OK=true +for required_file in \ + ".claude/skills/remote-control/SKILL.md" \ + "scripts/remote-control-doctor.sh" \ + "scripts/remote-control-smoke.sh" \ + "evals/harness/tasks/m12-remote-control-smoke.yaml" \ + "evals/harness/golden/m12-remote-control-smoke.json"; do + if [ ! -e "$required_file" ]; then + REMOTE_CONTROL_OK=false + fi +done +for required_script in remote-control-doctor remote-control-smoke; do + if [ ! -x "scripts/$required_script.sh" ]; then + REMOTE_CONTROL_OK=false + fi +done +for pattern in \ + "native Remote Control" \ + "/remote-control" \ + "/rc" \ + "claude --remote-control" \ + "claude remote-control" \ + "claude --remote" \ + "custom remote server" \ + "claude.ai subscription" \ + "ANTHROPIC_API_KEY" \ + "CLAUDE_CODE_OAUTH_TOKEN" \ + "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC" \ + "DISABLE_TELEMETRY" \ + "disableRemoteControl" \ + "bypassPermissions" \ + "Static harness evidence is compatibility evidence"; do + if ! grep -Fq "$pattern" .claude/skills/remote-control/SKILL.md README.md CLAUDE.md AGENTS.md 2>/dev/null; then + REMOTE_CONTROL_OK=false + fi +done +for pattern in \ + "shared_project_env_blockers" \ + "runtime_remote_control_started" \ + "not_run_static_only" \ + "custom_network_control_plane" \ + "api_key_auth_allowed" \ + "tokens_in_url"; do + if ! grep -Fq "$pattern" scripts/remote-control-doctor.sh scripts/remote-control-smoke.sh .taste/fixtures/remote-control/green/valid-native-static.json 2>/dev/null; then + REMOTE_CONTROL_OK=false + fi +done +if ! python3 - <<'PY' >/dev/null 2>&1; then +import json +import pathlib + +data = json.loads(pathlib.Path(".claude/settings.json").read_text(encoding="utf-8")) +env = data.get("env") or {} +blockers = { + "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC", + "DISABLE_TELEMETRY", + "ANTHROPIC_API_KEY", + "ANTHROPIC_AUTH_TOKEN", + "CLAUDE_CODE_OAUTH_TOKEN", + "CLAUDE_CODE_USE_BEDROCK", + "CLAUDE_CODE_USE_VERTEX", + "CLAUDE_CODE_USE_FOUNDRY", +} +assert not [name for name in blockers if name in env] +assert data.get("disableRemoteControl") is not True +for rule in [ + "Read(./.env)", + "Read(./.env.*)", + "Read(./.claude/settings.local.json)", + "Read(./.claude/*.local.json)", + "Read(./secrets/**)", +]: + assert rule in data.get("permissions", {}).get("deny", []) +PY + REMOTE_CONTROL_OK=false +fi +if [ "$REMOTE_CONTROL_OK" = true ] && \ + grep -Fq "remote-control" scripts/harness-capability-map.sh 2>/dev/null && \ + grep -Fq "remote-control-smoke" scripts/harness-eval.sh scripts/release-check.sh 2>/dev/null && \ + bash scripts/remote-control-doctor.sh --static --json >/dev/null 2>&1 && \ + bash scripts/remote-control-smoke.sh --fixtures >/dev/null 2>&1; then + test_pass "/remote-control uses native Claude Code RC without static runtime overclaims" +else + test_fail "/remote-control contract, docs, fixtures, or static checks are incomplete" +fi + # Test 3g-capmap: Generated Harness Capability Map echo "[3g-capmap] Generated Harness Capability Map" CAPMAP_OK=true @@ -685,7 +773,7 @@ if grep -Fq "Delegate execution. Keep judgment. Require evidence." README.md 2>/ grep -Fq "Independent verification pass" .claude/skills/verify/SKILL.md 2>/dev/null && \ grep -Fq "bash scripts/memory.sh health" README.md 2>/dev/null && \ grep -Fq "bash scripts/memory.sh health" CLAUDE.md 2>/dev/null && \ - grep -Fq "Expected 35 skills" scripts/start-session.sh 2>/dev/null && \ + grep -Fq "Expected 36 skills" scripts/start-session.sh 2>/dev/null && \ grep -Fq "Expected 6+ rules" scripts/start-session.sh 2>/dev/null && \ grep -Fq "settings.team-safe.example.json" README.md 2>/dev/null && \ ! grep -Fq "Expected 20 skills" scripts/start-session.sh 2>/dev/null && \ @@ -1455,25 +1543,25 @@ else fi # ======================================== -# Skills (35 Expected) +# Skills (36 Expected) # ======================================== echo "" -echo "[Skills - 35 Expected]" +echo "[Skills - 36 Expected]" echo "" # Test 4: Skills Count echo "[4] Skills Directory" SKILL_COUNT=$(find .claude/skills -name "SKILL.md" 2>/dev/null | wc -l | tr -d ' ') -if [ "$SKILL_COUNT" -ge 35 ]; then +if [ "$SKILL_COUNT" -ge 36 ]; then test_pass "$SKILL_COUNT skills found" else - test_fail "Expected 35+ skills, found $SKILL_COUNT" + test_fail "Expected 36+ skills, found $SKILL_COUNT" fi # Test 5: Critical Skills Content echo "[5] Critical Skills Content" -for skill in tastebootstrap workflow opussonnet visualize visualizeworkflow demo digestflow deepretaste defineicp icpweek align audit autoplan agentfactory parallel metacognition claudeproduct hive hiveworkflow deepresearch webresearch introspect verify review qa ship investigate; do +for skill in tastebootstrap workflow opussonnet visualize visualizeworkflow demo digestflow deepretaste defineicp icpweek align audit autoplan agentfactory parallel metacognition claudeproduct hive hiveworkflow remote-control deepresearch webresearch introspect verify review qa ship investigate; do if [ -f ".claude/skills/$skill/SKILL.md" ]; then LINES=$(wc -l < ".claude/skills/$skill/SKILL.md" | tr -d ' ') if [ "$LINES" -gt 20 ]; then @@ -1543,7 +1631,7 @@ fi # Test 9: Individual Scripts echo "[9] Individual Scripts" -for script in start-session sprint overnight-loop council test-harness state time-anchor spec-archive digestflow-smoke defineicp-smoke deepretaste-smoke agentfactory-smoke parallel-capacity parallel-smoke estimate-history estimate-smoke harness-scorecard metacognition-scorecard claudeproduct-scorecard harness-capability-map hive-scorecard hive-aggregate hook-smoke hook-mesh-smoke visualize-smoke codex-run-smoke parallel-plan-lint parallel-aggregate worktree-runner artifact-lint harness-eval harness-eval-report scenario-eval trace-ledger run-metrics session-insights learning-loop memory-eval security-smoke harness-doctor runtime-hardening-smoke opusminimax opusminimax-doctor minimax-exec opusminimax-benchmark-smoke opusworkflow opusworkflow-smoke opussonnetworkflow release-check; do +for script in start-session sprint overnight-loop council test-harness state time-anchor spec-archive digestflow-smoke defineicp-smoke deepretaste-smoke agentfactory-smoke parallel-capacity parallel-smoke estimate-history estimate-smoke harness-scorecard metacognition-scorecard claudeproduct-scorecard harness-capability-map hive-scorecard hive-aggregate hook-smoke hook-mesh-smoke visualize-smoke codex-run-smoke parallel-plan-lint parallel-aggregate worktree-runner artifact-lint harness-eval harness-eval-report scenario-eval trace-ledger run-metrics session-insights learning-loop memory-eval security-smoke harness-doctor runtime-hardening-smoke opusminimax opusminimax-doctor minimax-exec opusminimax-benchmark-smoke opusworkflow opusworkflow-smoke opussonnetworkflow remote-control-doctor remote-control-smoke release-check; do if [ -f "scripts/$script.sh" ]; then test_pass "$script.sh exists" else diff --git a/scripts/visualize-smoke.sh b/scripts/visualize-smoke.sh index 6a054a6..f48b741 100755 --- a/scripts/visualize-smoke.sh +++ b/scripts/visualize-smoke.sh @@ -40,7 +40,7 @@ require_file "$RULES" require_file "$WORKFLOW" SKILL_COUNT="$(find .claude/skills -name "SKILL.md" 2>/dev/null | wc -l | tr -d ' ')" -[ "$SKILL_COUNT" -ge 35 ] || fail "expected at least 35 skills, found $SKILL_COUNT" +[ "$SKILL_COUNT" -ge 36 ] || fail "expected at least 36 skills, found $SKILL_COUNT" for pattern in \ "taste.md" \ @@ -85,8 +85,8 @@ for file in README.md CLAUDE.md AGENTS.md scripts/start-session.sh; do require_grep "/visualizeworkflow" "$file" done -require_grep "35 skills" README.md -require_grep "Expected 35 skills" scripts/start-session.sh +require_grep "36 skills" README.md +require_grep "Expected 36 skills" scripts/start-session.sh if ! git check-ignore -q .taste/visualizations/probe/visualization.md; then fail ".taste/visualizations is not ignored by git" diff --git a/setup.ps1 b/setup.ps1 index 463f48a..79365b5 100644 --- a/setup.ps1 +++ b/setup.ps1 @@ -123,7 +123,9 @@ function Configure-OpusSonnetProfile($Path, $PlannerModel, $ExecutorModel) { "ANTHROPIC_DEFAULT_SONNET_MODEL" = $ExecutorModel "CLAUDE_CODE_SUBAGENT_MODEL" = $ExecutorModel "CLAUDE_CODE_EFFORT_LEVEL" = "xhigh" - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC" = "1" + "DISABLE_AUTOUPDATER" = "1" + "DISABLE_FEEDBACK_COMMAND" = "1" + "DISABLE_ERROR_REPORTING" = "1" "DISABLE_AUTO_COMPACT" = "0" "CLAUDE_CODE_NO_FLICKER" = "1" } @@ -158,7 +160,9 @@ function Configure-SonnetExecutorProfile($Path, $Model) { "ANTHROPIC_DEFAULT_SONNET_MODEL" = $Model "CLAUDE_CODE_SUBAGENT_MODEL" = $Model "CLAUDE_CODE_EFFORT_LEVEL" = "high" - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC" = "1" + "DISABLE_AUTOUPDATER" = "1" + "DISABLE_FEEDBACK_COMMAND" = "1" + "DISABLE_ERROR_REPORTING" = "1" "DISABLE_AUTO_COMPACT" = "0" "CLAUDE_CODE_NO_FLICKER" = "1" } diff --git a/setup.sh b/setup.sh index 0fe6f12..63648e3 100755 --- a/setup.sh +++ b/setup.sh @@ -538,7 +538,9 @@ env.update( "ANTHROPIC_DEFAULT_SONNET_MODEL": executor_model, "CLAUDE_CODE_SUBAGENT_MODEL": executor_model, "CLAUDE_CODE_EFFORT_LEVEL": "xhigh", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "DISABLE_AUTO_COMPACT": "0", "CLAUDE_CODE_NO_FLICKER": "1", } @@ -560,7 +562,9 @@ env.update( "ANTHROPIC_DEFAULT_SONNET_MODEL": executor_model, "CLAUDE_CODE_SUBAGENT_MODEL": executor_model, "CLAUDE_CODE_EFFORT_LEVEL": "high", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "DISABLE_AUTO_COMPACT": "0", "CLAUDE_CODE_NO_FLICKER": "1", } @@ -581,7 +585,9 @@ env.update( { "ANTHROPIC_DEFAULT_OPUS_MODEL": planner_model, "CLAUDE_CODE_EFFORT_LEVEL": "xhigh", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "DISABLE_AUTO_COMPACT": "0", "CLAUDE_CODE_NO_FLICKER": "1", } @@ -645,7 +651,9 @@ EOF "MINIMAX_API_KEY": "YOUR_MINIMAX_API_KEY", "MINIMAX_API_HOST": "https://api.minimax.io", "API_TIMEOUT_MS": "3000000", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", + "DISABLE_AUTOUPDATER": "1", + "DISABLE_FEEDBACK_COMMAND": "1", + "DISABLE_ERROR_REPORTING": "1", "ANTHROPIC_MODEL": "MiniMax-M2.7-highspeed", "ANTHROPIC_SMALL_FAST_MODEL": "MiniMax-M2.7-highspeed", "ANTHROPIC_DEFAULT_SONNET_MODEL": "MiniMax-M2.7-highspeed",