Skip to main content

a3s_code_core/
sdk_capabilities.rs

1//! Cross-language SDK capability contract.
2//!
3//! The Rust core has a deliberately larger implementation surface than any
4//! one FFI binding (for example, Rust hosts can provide native trait objects).
5//! This module is the single source of truth for the *product* capability
6//! surface.  Every official SDK exposes this inventory verbatim so an
7//! embedding application can discover features instead of guessing from
8//! package versions or parsing tool definitions.
9//!
10//! Capabilities are tagged with a [`CapabilityTier`]:
11//! - **baseline** — required for a governed local coding-agent harness
12//! - **advanced** — optional product surfaces (workflows, evaluation, serve,
13//!   S3, state graphs, research-adjacent contracts, and similar)
14
15use serde::{Deserialize, Serialize};
16
17/// Schema identifier for [`SdkCapability`] values (pre-tier inventory).
18pub const SDK_CAPABILITIES_SCHEMA_V1: &str = "a3s-code/sdk-capabilities/v1";
19
20/// Current schema for the tiered capability inventory.
21pub const SDK_CAPABILITIES_SCHEMA_V2: &str = "a3s-code/sdk-capabilities/v2";
22
23/// Product maturity / packaging tier for one capability.
24#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
25#[serde(rename_all = "snake_case")]
26pub enum CapabilityTier {
27    /// Default coding-agent harness surface.
28    Baseline,
29    /// Opt-in or host-specialized surface; not required for local coding loops.
30    Advanced,
31}
32
33impl CapabilityTier {
34    pub const fn as_str(self) -> &'static str {
35        match self {
36            Self::Baseline => "baseline",
37            Self::Advanced => "advanced",
38        }
39    }
40}
41
42/// A product capability exposed by the Core and its official SDKs.
43///
44/// `host_owned` means that the embedding application supplies policy,
45/// credentials, or a lifecycle owner.  It does not mean that the capability
46/// is unavailable to an SDK; the SDK exposes the same typed operation and the
47/// host remains responsible for the external resource.
48#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
49pub struct SdkCapability {
50    /// Stable snake-case identifier.
51    pub id: String,
52    /// Broad area used for UI grouping and telemetry.
53    pub category: String,
54    /// Human-readable contract summary.
55    pub description: String,
56    /// Canonical operation names. Language bindings map these to their naming
57    /// conventions (for example `web_search` becomes `webSearch` in Node).
58    pub operations: Vec<String>,
59    /// Whether the host owns policy, credentials, or an external lifecycle.
60    pub host_owned: bool,
61    /// Baseline coding harness versus advanced / optional surfaces.
62    pub tier: CapabilityTier,
63}
64
65struct CapabilitySpec {
66    id: &'static str,
67    category: &'static str,
68    description: &'static str,
69    operations: &'static [&'static str],
70    host_owned: bool,
71    tier: CapabilityTier,
72}
73
74const CAPABILITY_SPECS: &[CapabilitySpec] = &[
75    CapabilitySpec {
76        id: "agent_runtime",
77        category: "runtime",
78        description: "Create agents, bind workspaces, resume, replace, and close sessions.",
79        operations: &["agent.create", "agent.session", "agent.resume_session", "agent.close"],
80        host_owned: false,
81        tier: CapabilityTier::Baseline,
82    },
83    CapabilitySpec {
84        id: "conversation",
85        category: "runtime",
86        description: "Send, run, stream, attach content, inspect history, and cancel transcript-affecting turns.",
87        operations: &[
88            "session.send",
89            "session.run",
90            "session.stream",
91            "session.send_with_attachments",
92            "session.history",
93            "session.cancel",
94        ],
95        host_owned: false,
96        tier: CapabilityTier::Baseline,
97    },
98    CapabilitySpec {
99        id: "run_control",
100        category: "runtime",
101        description: "Steer or cooperatively interrupt an active run with idempotent receipts and optimistic turn guards.",
102        operations: &["session.steer", "session.interrupt", "session.run_control_snapshot"],
103        host_owned: true,
104        tier: CapabilityTier::Baseline,
105    },
106    CapabilitySpec {
107        id: "governed_tools",
108        category: "execution",
109        description: "Invoke built-in and MCP tools through validation, policy, confirmation, hooks, budgets, and tracing.",
110        operations: &["session.tool", "session.governed_tool", "session.tool_definitions"],
111        host_owned: true,
112        tier: CapabilityTier::Baseline,
113    },
114    CapabilitySpec {
115        id: "workspace_tools",
116        category: "workspace",
117        description: "Read, write, list, edit, patch, shell, glob, and grep through the governed workspace boundary.",
118        operations: &[
119            "session.read_file",
120            "session.write_file",
121            "session.ls",
122            "session.edit_file",
123            "session.patch_file",
124            "session.bash",
125            "session.glob",
126            "session.grep",
127            "session.git",
128            "session.tool:download",
129            "session.tool:batch",
130        ],
131        host_owned: true,
132        tier: CapabilityTier::Baseline,
133    },
134    CapabilitySpec {
135        id: "workspace_retrieval",
136        category: "workspace",
137        description: "Run exact, lexical, symbol, semantic, and hybrid retrieval with bounded session-owned state.",
138        operations: &[
139            "session.workspace_retrieval_status",
140            "session.semantic_search",
141            "session.hybrid_search",
142        ],
143        host_owned: true,
144        tier: CapabilityTier::Baseline,
145    },
146    CapabilitySpec {
147        id: "model_adapters",
148        category: "model",
149        description: "Resolve configured Anthropic, OpenAI-compatible, and custom host model adapters.",
150        operations: &["agent.create", "session.send", "session.stream"],
151        host_owned: true,
152        tier: CapabilityTier::Baseline,
153    },
154    CapabilitySpec {
155        id: "structured_output",
156        category: "model",
157        description: "Request schema-constrained model output with validation and bounded repair.",
158        operations: &["session.send", "session.run", "session.task"],
159        host_owned: true,
160        tier: CapabilityTier::Baseline,
161    },
162    CapabilitySpec {
163        id: "mcp_and_skills",
164        category: "extension",
165        description: "Discover and mutate isolated MCP servers and filesystem or inline Skills.",
166        operations: &[
167            "session.add_mcp",
168            "session.remove_mcp",
169            "session.mcps",
170            "session.add_skill",
171            "session.skill_names",
172        ],
173        host_owned: true,
174        tier: CapabilityTier::Baseline,
175    },
176    CapabilitySpec {
177        id: "planning_delegation",
178        category: "orchestration",
179        description: "Run plans, worker agents, and unified `task` delegation with bounded fan-out and cancellation. Model-visible `parallel_task` is removed (`HARNESS-CONV4`); use `session.tasks` / multi-item `task`. Host `session.parallel` / Flow workflows are Advanced `programmable_workflows`, not this baseline surface.",
180        operations: &["session.task", "session.tasks", "session.register_worker_agent"],
181        host_owned: true,
182        tier: CapabilityTier::Baseline,
183    },
184    CapabilitySpec {
185        id: "priority_scheduling",
186        category: "orchestration",
187        description: "Host capacity plumbing: share bounded priority/FIFO admission and observe scheduler occupancy, fairness, and lifecycle counters. Not required for ordinary coding-loop correctness.",
188        operations: &[
189            "session.task_scheduler_stats",
190            "session.task_scheduler_health",
191            "session.model_generation_pool_health",
192            "session.model_middleware_health",
193            "session.queue_stats",
194            "session.set_lane_handler",
195        ],
196        host_owned: false,
197        tier: CapabilityTier::Baseline,
198    },
199    CapabilitySpec {
200        id: "persistence",
201        category: "state",
202        description: "Atomically save and restore session state, runs, artifacts, traces, and verification evidence.",
203        operations: &["session.save", "agent.resume_session", "session.get_artifact"],
204        host_owned: true,
205        tier: CapabilityTier::Baseline,
206    },
207    CapabilitySpec {
208        id: "governance",
209        category: "security",
210        description: "Configure permissions, confirmations, hooks, budgets, verification, sanitization, and sandbox policy.",
211        operations: &[
212            "session.pending_confirmations",
213            "session.confirm_tool_use",
214            "session.register_hook",
215            "session.set_budget_guard",
216            "session.verify_commands",
217        ],
218        host_owned: true,
219        tier: CapabilityTier::Baseline,
220    },
221    CapabilitySpec {
222        id: "run_observability",
223        category: "observability",
224        description: "Inspect durable run snapshots, event pages, active tools, traces, and child-task state.",
225        operations: &[
226            "session.runs",
227            "session.run_snapshot",
228            "session.run_events",
229            "session.run_event_page",
230            "session.active_tools",
231            "session.subagent_tasks",
232        ],
233        host_owned: false,
234        tier: CapabilityTier::Baseline,
235    },
236    CapabilitySpec {
237        id: "context_memory",
238        category: "context",
239        description: "Use working, short-term, durable, and semantic memory with typed health and recall APIs.",
240        operations: &[
241            "session.memory",
242            "session.remember",
243            "session.recall",
244            "session.memory_stats",
245        ],
246        host_owned: true,
247        tier: CapabilityTier::Baseline,
248    },
249    CapabilitySpec {
250        id: "web_search",
251        category: "web",
252        description: "Baseline web search through a3s-search v3.1.4 over HTTP, native API, and RSS engines. JavaScript/headless engines require the Advanced `moli_runtime` / Cargo `headless-search` profile. Billed providers stay opt-in.",
253        operations: &["session.web_search", "session.tool:web_search"],
254        host_owned: true,
255        tier: CapabilityTier::Baseline,
256    },
257    CapabilitySpec {
258        id: "web_fetch",
259        category: "web",
260        description: "Fetch a public HTTP(S) URL into text or markdown through the governed `web_fetch` tool (size and redirect bounded).",
261        operations: &["session.tool:web_fetch"],
262        host_owned: true,
263        tier: CapabilityTier::Baseline,
264    },
265    CapabilitySpec {
266        id: "code_intelligence",
267        category: "workspace",
268        description: "Query saved-file symbols, navigation, and diagnostics when a language service is available.",
269        operations: &[
270            "session.tool:code_symbols",
271            "session.tool:code_navigation",
272            "session.tool:code_diagnostics",
273        ],
274        host_owned: true,
275        tier: CapabilityTier::Advanced,
276    },
277    CapabilitySpec {
278        id: "cognitive_packages",
279        category: "context",
280        description: "Bind exact cited cognitive knowledge generations supplied by an authoritative host.",
281        operations: &[
282            "session.cognitive_package_binding",
283            "session.current_cognitive_package_binding",
284        ],
285        host_owned: true,
286        tier: CapabilityTier::Advanced,
287    },
288    CapabilitySpec {
289        id: "use_runtime_tasks",
290        category: "integration",
291        description: "Project host-owned A3S Use runtime tasks as governed model and direct-tool capabilities.",
292        operations: &["session.tool:use_runtime_task"],
293        host_owned: true,
294        tier: CapabilityTier::Advanced,
295    },
296    CapabilitySpec {
297        id: "program",
298        category: "composition",
299        description: "Execute a bounded in-process QuickJS `program` tool as part of the coding harness. Prefer unified `task` for model-driven fan-out; this is an escape hatch, not a second workflow engine.",
300        operations: &["session.program", "session.tool:program"],
301        host_owned: false,
302        tier: CapabilityTier::Baseline,
303    },
304    CapabilitySpec {
305        id: "programmable_workflows",
306        category: "orchestration",
307        description: "Host-authored resumable parallel Workflow APIs and Flow-backed dynamic workflows (`advanced-harness`). Prefer unified `task` for model-driven coding fan-out. Does not include the baseline `program` tool.",
308        operations: &[
309            "session.parallel",
310            "session.parallel_resumable",
311            "session.workflow_step",
312        ],
313        host_owned: true,
314        tier: CapabilityTier::Advanced,
315    },
316    CapabilitySpec {
317        id: "state_graph",
318        category: "state",
319        description: "Maintain hash-linked state graph events, patches, forks, and deterministic diffs.",
320        operations: &[
321            "state_graph.create",
322            "state_graph.restore",
323            "state_graph.propose_patch",
324            "state_graph.diff",
325        ],
326        host_owned: true,
327        tier: CapabilityTier::Advanced,
328    },
329    CapabilitySpec {
330        id: "agent_release_contract",
331        category: "deployment",
332        description: "Validate versioned asset manifests, provenance, and compatibility before activation.",
333        operations: &["release.admit", "release.bind_publication", "release.verify"],
334        host_owned: true,
335        tier: CapabilityTier::Advanced,
336    },
337    CapabilitySpec {
338        id: "agent_protocol",
339        category: "transport",
340        description: "Serve versioned session/run start, cancellation, recovery, and event-page protocols.",
341        operations: &[
342            "agent_protocol.start",
343            "agent_protocol.cancel",
344            "agent_protocol.recover",
345            "agent_protocol.events",
346        ],
347        host_owned: true,
348        tier: CapabilityTier::Advanced,
349    },
350    CapabilitySpec {
351        id: "evaluation_substrate",
352        category: "evaluation",
353        description: "Project bounded evidence, isolated auxiliary lifecycle, restart-safe dispatch claims, and immutable evaluation records through versioned boundaries.",
354        operations: &[
355            "evaluation.evidence",
356            "evaluation.auxiliary",
357            "evaluation.dispatch_ledger",
358            "evaluation.result",
359            "evaluation.result_store",
360            "evaluation.wire_v1",
361        ],
362        host_owned: true,
363        tier: CapabilityTier::Advanced,
364    },
365    CapabilitySpec {
366        id: "typed_decisions",
367        category: "decision",
368        description: "In-process typed System-1 decisions via Apofasi (`choice` / `score` / `noul`) with host GatePolicy auto/escalate and digest-bound receipts. Requires Cargo feature `apofasi` (optional `apofasi-infer` / `apofasi-metal`). When enabled, Code refuses to replace planning pre-analysis and goal achievement: each returns more than one typed answer, and the call site refuses to skip the generation. Code does not add a keyword classifier and does not lower GatePolicy. The escalate prompt includes the task state. Not injected into the system prompt, not a generative model path, and not a Use-projected capability kind.",
369        operations: &[
370            "typed_decision.decide",
371            "typed_decision.decide_and_gate",
372            "typed_decision.receipt_v1",
373            "typed_decision.route",
374        ],
375        host_owned: true,
376        tier: CapabilityTier::Advanced,
377    },
378    CapabilitySpec {
379        id: "moli_runtime",
380        category: "web",
381        description: "Use a verified packaged or shared-cache Moli runtime with cross-process installation locking.",
382        operations: &["moli.default", "moli.ensure", "moli.packaged"],
383        host_owned: true,
384        tier: CapabilityTier::Advanced,
385    },
386    CapabilitySpec {
387        id: "s3_workspace",
388        category: "workspace",
389        description: "Use an S3-compatible workspace backend with bounded reads and search. Requires the SDK `s3` Cargo feature.",
390        operations: &[
391            "session.workspace_backend:s3",
392            "session.read_file",
393            "session.write_file",
394        ],
395        host_owned: true,
396        tier: CapabilityTier::Advanced,
397    },
398    CapabilitySpec {
399        id: "opentelemetry",
400        category: "observability",
401        description: "Export redacted runtime traces and metrics through the optional OTLP integration. Requires the Core `telemetry` Cargo feature.",
402        operations: &["telemetry.init", "session.trace_events"],
403        host_owned: true,
404        tier: CapabilityTier::Advanced,
405    },
406];
407
408/// Return the complete, ordered product capability inventory.
409pub fn sdk_capabilities() -> Vec<SdkCapability> {
410    CAPABILITY_SPECS
411        .iter()
412        .map(|spec| SdkCapability {
413            id: spec.id.to_owned(),
414            category: spec.category.to_owned(),
415            description: spec.description.to_owned(),
416            operations: spec
417                .operations
418                .iter()
419                .map(|value| (*value).to_owned())
420                .collect(),
421            host_owned: spec.host_owned,
422            tier: spec.tier,
423        })
424        .collect()
425}
426
427/// Return baseline coding-harness capabilities only.
428pub fn sdk_baseline_capabilities() -> Vec<SdkCapability> {
429    sdk_capabilities()
430        .into_iter()
431        .filter(|capability| capability.tier == CapabilityTier::Baseline)
432        .collect()
433}
434
435/// Return the schema identifier used by the inventory endpoint.
436pub const fn sdk_capabilities_schema() -> &'static str {
437    SDK_CAPABILITIES_SCHEMA_V2
438}
439
440#[cfg(test)]
441mod tests {
442    use super::*;
443    use std::collections::HashSet;
444
445    #[test]
446    fn inventory_is_stable_and_complete() {
447        let capabilities = sdk_capabilities();
448        assert!(capabilities.len() >= 20);
449        let ids = capabilities
450            .iter()
451            .map(|item| item.id.as_str())
452            .collect::<Vec<_>>();
453        assert_eq!(ids.len(), ids.iter().collect::<HashSet<_>>().len());
454        for capability in &capabilities {
455            assert!(!capability.category.is_empty());
456            assert!(!capability.description.is_empty());
457            assert!(!capability.operations.is_empty());
458        }
459        let required_baseline = [
460            "agent_runtime",
461            "conversation",
462            "governed_tools",
463            "workspace_tools",
464            "workspace_retrieval",
465            "planning_delegation",
466            "persistence",
467            "governance",
468            "run_control",
469            "web_search",
470            "web_fetch",
471            "program",
472        ];
473        for id in required_baseline {
474            let capability = capabilities
475                .iter()
476                .find(|item| item.id == id)
477                .unwrap_or_else(|| panic!("missing capability {id}"));
478            assert_eq!(
479                capability.tier,
480                CapabilityTier::Baseline,
481                "{id} must be baseline"
482            );
483        }
484        let required_advanced = [
485            "evaluation_substrate",
486            "typed_decisions",
487            "state_graph",
488            "programmable_workflows",
489            "s3_workspace",
490            "opentelemetry",
491            "moli_runtime",
492        ];
493        for id in required_advanced {
494            let capability = capabilities
495                .iter()
496                .find(|item| item.id == id)
497                .unwrap_or_else(|| panic!("missing capability {id}"));
498            assert_eq!(
499                capability.tier,
500                CapabilityTier::Advanced,
501                "{id} must be advanced"
502            );
503        }
504        let programmable = capabilities
505            .iter()
506            .find(|item| item.id == "programmable_workflows")
507            .expect("programmable_workflows");
508        assert!(
509            !programmable
510                .operations
511                .iter()
512                .any(|operation| operation.contains("program")),
513            "baseline program must not be mixed into Advanced programmable_workflows"
514        );
515        let web_search = capabilities
516            .iter()
517            .find(|item| item.id == "web_search")
518            .expect("web_search");
519        assert!(
520            !web_search
521                .description
522                .to_ascii_lowercase()
523                .contains("javascript-rendered")
524                || web_search.description.contains("headless-search"),
525            "baseline web_search must not claim JS engines without naming the Advanced gate"
526        );
527    }
528
529    #[test]
530    fn planning_delegation_omits_deprecated_parallel_task() {
531        let planning = sdk_capabilities()
532            .into_iter()
533            .find(|item| item.id == "planning_delegation")
534            .expect("planning_delegation");
535        assert!(planning
536            .operations
537            .iter()
538            .all(|operation| operation != "session.parallel_task"));
539        assert!(
540            planning.description.contains("removed")
541                || planning.description.contains("HARNESS-CONV4"),
542            "planning_delegation must document parallel_task removal"
543        );
544    }
545
546    #[test]
547    fn baseline_filter_excludes_advanced_surfaces() {
548        let baseline = sdk_baseline_capabilities();
549        assert!(baseline
550            .iter()
551            .all(|capability| capability.tier == CapabilityTier::Baseline));
552        assert!(!baseline.iter().any(|capability| {
553            matches!(
554                capability.id.as_str(),
555                "evaluation_substrate" | "state_graph" | "s3_workspace" | "programmable_workflows"
556            )
557        }));
558        assert!(baseline.len() >= 12);
559        assert!(baseline.len() < sdk_capabilities().len());
560    }
561
562    #[test]
563    fn inventory_serializes_with_schema() {
564        let value = serde_json::json!({
565            "schema": sdk_capabilities_schema(),
566            "capabilities": sdk_capabilities(),
567        });
568        assert_eq!(value["schema"], SDK_CAPABILITIES_SCHEMA_V2);
569        let first = &value["capabilities"][0];
570        assert!(first.get("tier").is_some());
571        assert!(value["capabilities"]
572            .as_array()
573            .is_some_and(|items| !items.is_empty()));
574    }
575
576    #[test]
577    fn tier_display_strings_are_stable() {
578        assert_eq!(CapabilityTier::Baseline.as_str(), "baseline");
579        assert_eq!(CapabilityTier::Advanced.as_str(), "advanced");
580    }
581}