1use serde::Serialize;
11use std::collections::HashMap;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
15#[serde(rename_all = "kebab-case")]
16pub enum CapabilityOutcome {
17 Native,
18 RealizeVia,
19 Degrade,
20 Fail,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
25#[serde(rename_all = "lowercase")]
26pub enum ProvidedBy {
27 Runtime,
28 Warble,
29 None,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
35#[serde(rename_all = "kebab-case")]
36pub enum Criticality {
37 SafetyCritical,
38 Required,
39 BestEffort,
40}
41
42#[derive(Debug, Clone)]
43pub struct CapabilityEntry {
44 pub outcome: CapabilityOutcome,
45 pub via: Option<&'static str>,
46 pub provided_by: ProvidedBy,
47 pub criticality: Criticality,
48 pub note: Option<&'static str>,
49}
50
51pub type CapabilityProfile = HashMap<&'static str, CapabilityEntry>;
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum TargetId {
56 Headless,
57 Interactive,
58}
59
60impl TargetId {
61 pub fn as_str(&self) -> &'static str {
62 match self {
63 TargetId::Headless => "claude-code:headless",
64 TargetId::Interactive => "claude-code:interactive",
65 }
66 }
67
68 pub fn parse(value: &str) -> Option<TargetId> {
69 match value {
70 "claude-code:headless" => Some(TargetId::Headless),
71 "claude-code:interactive" => Some(TargetId::Interactive),
72 _ => None,
73 }
74 }
75
76 pub fn profile(&self) -> CapabilityProfile {
77 match self {
78 TargetId::Headless => headless_profile(),
79 TargetId::Interactive => interactive_profile(),
80 }
81 }
82}
83
84pub const DEFAULT_TARGET: TargetId = TargetId::Headless;
86
87pub fn is_known_target(value: &str) -> bool {
88 TargetId::parse(value).is_some()
89}
90
91pub fn known_target_names() -> [&'static str; 2] {
92 [TargetId::Headless.as_str(), TargetId::Interactive.as_str()]
93}
94
95fn entry(
96 outcome: CapabilityOutcome,
97 via: Option<&'static str>,
98 provided_by: ProvidedBy,
99 criticality: Criticality,
100 note: Option<&'static str>,
101) -> CapabilityEntry {
102 CapabilityEntry {
103 outcome,
104 via,
105 provided_by,
106 criticality,
107 note,
108 }
109}
110
111fn headless_profile() -> CapabilityProfile {
112 use CapabilityOutcome::*;
113 use Criticality::*;
114 use ProvidedBy::{Runtime, Warble};
115 HashMap::from([
116 (
117 "sql_execution:read_only",
118 entry(Native, Some("bash-wren"), Runtime, Required, None),
119 ),
120 (
121 "genbi_build",
122 entry(Native, Some("bash-wren"), Runtime, Required, None),
123 ),
124 (
125 "semantic_introspection",
126 entry(RealizeVia, Some("bash-wren"), Runtime, Required, None),
127 ),
128 (
131 "schema_introspection",
132 entry(RealizeVia, Some("bash-wren"), Runtime, Required, None),
133 ),
134 ("llm:strong", entry(Native, None, Runtime, Required, None)),
135 ("llm:cheap", entry(Native, None, Runtime, Required, None)),
136 (
137 "llm:per_step_tier",
138 entry(RealizeVia, Some("subagents"), Runtime, Required, None),
139 ),
140 (
147 "llm:per_step_provider",
148 entry(
149 RealizeVia,
150 Some("bash-script|mcp-server"),
151 Warble,
152 Required,
153 Some("local step via a bash-script script or an mcp-server (warble mcp-serve); cloud steps are the driver's own wren work"),
154 ),
155 ),
156 (
157 "render_contract",
158 entry(RealizeVia, Some("html-file"), Runtime, BestEffort, None),
159 ),
160 (
161 "structured_output_capture",
162 entry(Native, Some("stream-json"), Runtime, Required, None),
163 ),
164 (
165 "human_approval",
166 entry(
167 Fail,
168 None,
169 ProvidedBy::None,
170 SafetyCritical,
171 Some("no human in the loop in headless mode"),
172 ),
173 ),
174 (
175 "write_authz",
176 entry(RealizeVia, Some("fs"), Runtime, SafetyCritical, None),
177 ),
178 (
182 "context_write_authz",
183 entry(RealizeVia, Some("scoped-fs"), Runtime, SafetyCritical, None),
184 ),
185 (
186 "artifact_write",
187 entry(RealizeVia, Some("fs"), Runtime, SafetyCritical, None),
188 ),
189 (
194 "scheduler",
195 entry(RealizeVia, Some("os-cron"), Runtime, Required, None),
196 ),
197 (
198 "event_bus",
199 entry(RealizeVia, Some("pub-sub"), Runtime, Required, None),
200 ),
201 (
202 "notify_channel",
203 entry(RealizeVia, Some("mcp-notify"), Runtime, Required, None),
204 ),
205 (
206 "blast_radius",
207 entry(
208 Fail,
209 None,
210 Warble,
211 SafetyCritical,
212 Some("requires fine_grained_binding"),
213 ),
214 ),
215 (
218 "version_control",
219 entry(RealizeVia, Some("git"), Runtime, Required, None),
220 ),
221 ])
222}
223
224fn interactive_profile() -> CapabilityProfile {
225 use CapabilityOutcome::*;
226 use Criticality::*;
227 use ProvidedBy::{Runtime, Warble};
228 HashMap::from([
229 (
230 "sql_execution:read_only",
231 entry(Native, Some("bash-wren"), Runtime, Required, None),
232 ),
233 (
234 "genbi_build",
235 entry(Native, Some("bash-wren"), Runtime, Required, None),
236 ),
237 (
238 "semantic_introspection",
239 entry(RealizeVia, Some("bash-wren"), Runtime, Required, None),
240 ),
241 (
243 "schema_introspection",
244 entry(RealizeVia, Some("bash-wren"), Runtime, Required, None),
245 ),
246 ("llm:strong", entry(Native, None, Runtime, Required, None)),
247 ("llm:cheap", entry(Native, None, Runtime, Required, None)),
248 (
249 "llm:per_step_tier",
250 entry(RealizeVia, Some("subagents"), Runtime, Required, None),
251 ),
252 (
255 "llm:per_step_provider",
256 entry(
257 RealizeVia,
258 Some("bash-script|mcp-server"),
259 Warble,
260 Required,
261 Some("local step via an emitted local-inference script (Bash); cloud steps stay native subagents"),
262 ),
263 ),
264 (
265 "render_contract",
266 entry(
267 Degrade,
268 Some("terminal-markdown"),
269 Runtime,
270 BestEffort,
271 None,
272 ),
273 ),
274 (
275 "structured_output_capture",
276 entry(
277 Degrade,
278 None,
279 ProvidedBy::None,
280 BestEffort,
281 Some("not captured in the interactive TUI"),
282 ),
283 ),
284 (
285 "human_approval",
286 entry(Native, None, Runtime, SafetyCritical, None),
287 ),
288 (
289 "write_authz",
290 entry(RealizeVia, Some("fs"), Runtime, SafetyCritical, None),
291 ),
292 (
295 "context_write_authz",
296 entry(RealizeVia, Some("scoped-fs"), Runtime, SafetyCritical, None),
297 ),
298 (
299 "artifact_write",
300 entry(RealizeVia, Some("fs"), Runtime, SafetyCritical, None),
301 ),
302 (
306 "scheduler",
307 entry(RealizeVia, Some("os-cron"), Runtime, Required, None),
308 ),
309 (
310 "event_bus",
311 entry(RealizeVia, Some("pub-sub"), Runtime, Required, None),
312 ),
313 (
314 "notify_channel",
315 entry(RealizeVia, Some("mcp-notify"), Runtime, Required, None),
316 ),
317 (
318 "blast_radius",
319 entry(
320 Fail,
321 None,
322 Warble,
323 SafetyCritical,
324 Some("requires fine_grained_binding"),
325 ),
326 ),
327 (
330 "version_control",
331 entry(RealizeVia, Some("git"), Runtime, Required, None),
332 ),
333 ])
334}