wire/answer/harnesses.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! The harness page: each official harness, the command that starts it
7//! as an ACP agent, and whether this machine can run that command
8//! (`crates/wire/spec/Answer/Harnesses.lean` ยง8-52).
9//!
10//! Nothing here is about a credential: the person signs in inside the
11//! harness, and `docs` is where its own vendor says how.
12
13use serde::{Deserialize, Serialize};
14
15/// Every official harness, in the roster's order.
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
18pub struct HarnessesAnswer {
19 pub harnesses: Vec<HarnessLine>,
20}
21
22/// One harness as the page draws it.
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
25pub struct HarnessLine {
26 /// The roster's word for it: `claude_code`, `codex`, `grok_build`,
27 /// `kimi_code` or `pi`.
28 pub name: String,
29 /// The command that starts it as an ACP agent, word by word.
30 pub launch: Vec<String>,
31 /// Whether this machine can use it (`crates/wire/spec/Answer/Harnesses.lean` D23).
32 pub state: HarnessState,
33 /// Where its vendor says how a person signs in.
34 pub docs: String,
35}
36
37/// What a person does next about one harness: install its launcher,
38/// install or sign in to the harness, or use it.
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(rename_all = "snake_case")]
41#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
42pub enum HarnessState {
43 /// The launcher program (mostly `npx`) is not on the search path.
44 LauncherMissing { program: String },
45 /// The launcher is there, and none of the harness's install or
46 /// sign-in directories is. `looked` lists every directory checked,
47 /// expanded; empty while the harness has no directories registered.
48 NotSetUp { looked: Vec<String> },
49 /// The directory found.
50 Ready { at: String },
51}