#16625

Overlap third-party harness preparation with workspace setup

Draftkevinyang372wants to merge intofrom

Description

Part of the Oz cloud-agent startup latency work (workstream C2). On a self-hosted K8s worker, Claude runs spend ~21s median between shared_session_started and agent_started versus 0.7s for the Warp harness, and all of that is third-party harness preparation that today runs strictly after repo clone + setup commands. This PR moves the parts of that preparation that have no workspace dependency off the critical path so they overlap workspace preparation.

What now overlaps, and why it is safe

Right after setup_terminal_bootstrap + setup_cloud_provider_setup, a third-party run spawns an "early preparation" future on the background executor (AgentDriver::spawn_early_harness_preparation) and keeps a RemoteHandle to it. The handle is awaited at the start of setup_third_party_harness_preparation, immediately before prepare_harness. Dropping run_internal (SIGINT/SIGTERM, sandbox deadline, an earlier setup failure) drops the handle, which cancels the remote future; the plugin manager's LocalCommandExecutor kills its process group on drop.

The early group runs three things with join! and reports their errors in today's precedence order (plugins, then prompt, then conversation), so error classification and user-facing messages are unchanged:

  1. Plugin install/update (setup_harness_plugins, PTY-transport harnesses only; ACP returns drives_cli_agent_session() == false and skips it). Dependencies: active_shell_launch_data (available once terminal bootstrap finishes), HOME/CLAUDE_CONFIG_DIR/CODEX_HOME and the sidecar on PATH (process env). It runs through LocalCommandExecutor, a separate shell process, so it does not contend with clone/setup commands on the PTY. Platform-plugin failure is still fatal (HarnessSetupFailed); notification-plugin failure is still a warning.
  2. create_external_conversation (all four runners). Dependency: HTTP only. The format slug moved onto the ThirdPartyHarness trait (external_conversation_format), and HarnessRunner::start takes the pre-created Option<ServerConversationToken>. Resumed runs (resume_payload or restored_conversation_id set) skip pre-creation and the runner resolves the conversation exactly as before, so no server conversation is created that a resume would then ignore.
  3. resolve_prompt_for_task (split out of prepare_harness into resolve_harness_prompt). Dependency: HTTP only; the attachments dir is a string already known at task creation.

Still on the critical path after workspace preparation, because they need harness_working_dir: subscribe_to_harness_exit (unchanged timing), build_runner (writes .claude.json / settings.json / config.toml and publishes skills under the harness working dir), the auth preflight, and start().

Auth preflight stays on the PTY

I did not move the auth preflight to LocalCommandExecutor. The environment is not provably identical: (a) setup commands run in the PTY shell and can export auth variables that a fresh login shell would not see; (b) claude auth status honors repo-local .claude/settings.json (apiKeyHelper), which only exists after the clone and requires cwd inside the repo; (c) prepare_claude_config writes onboarding/trust state before the preflight today. Moving it would turn those cases into false HarnessAuthCheckFailed failures. It is ~1 Node cold start, so the remaining exposure is small. A follow-up could run it optimistically off the PTY and fall back to the PTY check only on failure, at the cost of losing the visible auth-check block in the shared session.

Marketplace registration dedupe

ClaudeCodePluginManager ran claude plugin marketplace add once in install() and again in install_platform_plugin() (and update_platform_plugin()); CodexPluginManager ran marketplace upgrade once per plugin the same way. Each plugin manager instance now registers/refreshes its marketplace once (AtomicBool per instance). The dedupe is scoped to the instance deliberately: on a developer machine where the notification plugin is already installed and install() is skipped, install_platform_plugin() still runs marketplace add as before, so a stale local marketplace clone behaves exactly as it does today.

Setup events

Events already carry their own start/finish timestamps, and SetupClientEventReporter posts each one independently, so overlapping steps are representable without changes. No event names were renamed. One event was added: setup_third_party_harness_early_preparation wraps the overlapped group so its wall time can be compared against setup_third_party_harness_preparation (which now covers join + config write + preflight). The plugin sub-step events now fire inside the early group rather than inside setup_third_party_harness_preparation; the server does not allowlist setup-metric event names (timeline.go IngestClientEvent), so nothing server-side needs to land first.

Linked Issue

  • The linked issue is labeled ready-to-spec or ready-to-implement.
  • Where appropriate, screenshots or a short video of the implementation are included below (especially for user-visible or UI changes).

Testing

  • cargo check -p warp --tests — clean, no warnings
  • cargo nextest run -p warp -E 'test(/agent_sdk::(driver|setup_observability)/) | test(/plugin_manager/)' — 836 passed, 0 failed
  • cargo clippy -p warp --all-targets --tests -- -D warnings — clean
  • ./script/format equivalent (cargo fmt -p warp with the repo's import config)

Existing tests updated for the new signatures: deferred_repository_semantic_acp_consumes_server_resolved_text_once now resolves the prompt through resolve_harness_prompt (still asserts exactly one resolve-prompt call), the ACP attachment test and RecordingRunner pass None for the pre-created conversation, and setup_observability_tests::EXPECTED includes the new step.

Not done: an end-to-end smoke test of one Claude PTY run and one ACP run against a local Oz stack (oz-local). That needs a local warp-server + Temporal + session-sharing-server + oz-agent-worker, a built agent binary from this branch, and live Claude credentials; that was not feasible in the time available. Recommend validating on staging and comparing setup_third_party_harness_early_preparation / setup_third_party_harness_preparation against the A1 baseline before merge.

  • I have manually tested my changes locally with ./script/run

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-OZ: Third-party harness runs install plugins and resolve the prompt while the environment is still being set up, so Claude and Codex runs start sooner.

Activity

2
warp-agent-staging[bot]8d ago

@kevinyang372, may @warp-staging-factory diagnose this CI failure, commit fixes, and push to this PR’s existing branch? A yes also opts this PR into automatic handling of future CI failures. Please reply here with @warp-staging-factory and an explicit yes or no.

View in factory

This pull request is a draft

Merging is unavailable until it is marked ready for review.