Skip to main content

mdx_rust_core/
agent_runtime.rs

1//! Agent runtime manifest and pack artifacts.
2//!
3//! These records describe how external coding agents can call `mdx-rust`
4//! without scraping human output.
5
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
10pub struct AgentRuntimeManifest {
11    pub schema_version: String,
12    pub product_version: String,
13    pub transports: Vec<AgentRuntimeTransport>,
14    pub tools: Vec<AgentRuntimeTool>,
15    pub mutation_rules: Vec<String>,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
19pub struct AgentRuntimeTransport {
20    pub id: String,
21    pub command: String,
22    pub description: String,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
26pub struct AgentRuntimeTool {
27    pub name: String,
28    pub description: String,
29    pub read_only: bool,
30    pub mutation_capable: bool,
31    pub required_flags_for_mutation: Vec<String>,
32    pub request_schema: String,
33    pub response_schema: String,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
37pub struct AgentPack {
38    pub schema_version: String,
39    pub target_agent: String,
40    pub files: Vec<AgentPackFile>,
41    pub install_note: String,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
45pub struct AgentPackFile {
46    pub path: String,
47    pub purpose: String,
48    pub content: String,
49}
50
51pub fn agent_runtime_manifest() -> AgentRuntimeManifest {
52    AgentRuntimeManifest {
53        schema_version: "0.9".to_string(),
54        product_version: env!("CARGO_PKG_VERSION").to_string(),
55        transports: vec![
56            AgentRuntimeTransport {
57                id: "cli-json".to_string(),
58                command: "mdx-rust --json <command>".to_string(),
59                description: "Stable command-line JSON contract for humans, scripts, and coding agents.".to_string(),
60            },
61            AgentRuntimeTransport {
62                id: "mcp-stdio".to_string(),
63                command: "mdx-rust mcp --stdio".to_string(),
64                description: "Line-delimited JSON tool protocol over stdin/stdout for local coding agents.".to_string(),
65            },
66            AgentRuntimeTransport {
67                id: "local-http".to_string(),
68                command: "mdx-rust serve --bind 127.0.0.1:3799".to_string(),
69                description: "Localhost-only HTTP surface for read-only tool calls and explicit mutation-gated evolution calls.".to_string(),
70            },
71        ],
72        tools: runtime_tools(),
73        mutation_rules: vec![
74            "Read-only tools must never mutate source files.".to_string(),
75            "Mutation-capable tools require explicit apply=true and the same CLI safety gates.".to_string(),
76            "Runtime callers cannot bypass evidence, stale-plan, validation, behavior eval, or rollback gates.".to_string(),
77            "Runtime callers should inspect artifact_path fields instead of scraping human output.".to_string(),
78        ],
79    }
80}
81
82pub fn agent_pack(target_agent: &str) -> AgentPack {
83    let file_path = match target_agent {
84        "codex" => ".codex/skills/mdx-rust-evolution/SKILL.md",
85        "claude" => ".claude/skills/mdx-rust-evolution/SKILL.md",
86        _ => ".mdx-rust/agent-pack/mdx-rust-evolution.md",
87    };
88    AgentPack {
89        schema_version: "0.9".to_string(),
90        target_agent: target_agent.to_string(),
91        files: vec![AgentPackFile {
92            path: file_path.to_string(),
93            purpose: "Teach a coding agent how to use mdx-rust as a safe Rust evolution engine.".to_string(),
94            content: agent_pack_content(target_agent),
95        }],
96        install_note:
97            "Review the generated file before committing it. The pack is instructions only and never grants mutation permission by itself."
98                .to_string(),
99    }
100}
101
102fn runtime_tools() -> Vec<AgentRuntimeTool> {
103    vec![
104        runtime_tool(
105            "agent-contract",
106            "Discover commands, schemas, artifacts, and mutation rules.",
107            true,
108            false,
109            "agent-contract-request",
110            "agent-contract",
111        ),
112        runtime_tool(
113            "recipes",
114            "List evidence-gated recipe capabilities.",
115            true,
116            false,
117            "recipes-request",
118            "recipe-catalog",
119        ),
120        runtime_tool(
121            "scorecard",
122            "Build a single target briefing for external agents.",
123            true,
124            false,
125            "scorecard-request",
126            "evolution-scorecard",
127        ),
128        runtime_tool(
129            "evidence",
130            "Collect measured test, coverage, mutation, and semver evidence.",
131            true,
132            false,
133            "evidence-request",
134            "evidence-run",
135        ),
136        runtime_tool(
137            "map",
138            "Build a non-mutating codebase map.",
139            true,
140            false,
141            "map-request",
142            "codebase-map",
143        ),
144        runtime_tool(
145            "plan",
146            "Build a non-mutating refactor plan.",
147            true,
148            false,
149            "plan-request",
150            "refactor-plan",
151        ),
152        runtime_tool(
153            "explain",
154            "Explain a saved mdx-rust artifact.",
155            true,
156            false,
157            "explain-request",
158            "artifact-explanation",
159        ),
160        runtime_tool(
161            "evolve",
162            "Run budget-bounded evolution through autopilot gates.",
163            false,
164            true,
165            "evolve-request",
166            "autopilot-run",
167        ),
168    ]
169}
170
171fn runtime_tool(
172    name: &str,
173    description: &str,
174    read_only: bool,
175    mutation_capable: bool,
176    request_schema: &str,
177    response_schema: &str,
178) -> AgentRuntimeTool {
179    AgentRuntimeTool {
180        name: name.to_string(),
181        description: description.to_string(),
182        read_only,
183        mutation_capable,
184        required_flags_for_mutation: if mutation_capable {
185            vec![
186                "apply=true".to_string(),
187                "confirm_mutation=true".to_string(),
188            ]
189        } else {
190            Vec::new()
191        },
192        request_schema: request_schema.to_string(),
193        response_schema: response_schema.to_string(),
194    }
195}
196
197fn agent_pack_content(target_agent: &str) -> String {
198    format!(
199        r#"---
200name: mdx-rust-evolution
201description: Use mdx-rust to inspect, plan, and safely evolve Rust codebases with evidence-gated autonomy.
202---
203
204# mdx-rust Evolution
205
206Use this when working on Rust repositories, especially when asked to harden,
207refactor, improve quality, or let an agent make autonomous changes.
208
209## Required Intake
210
2111. Run `mdx-rust --json agent-contract`.
2122. Run `mdx-rust --json scorecard <target>`.
2133. Inspect `readiness`, `next_commands`, `security`, and candidate autonomy decisions.
214
215## Mutation Rule
216
217Never add `--apply` unless the human explicitly asked for mutation. Plans,
218maps, recipes, explanations, evidence runs, and scorecards are read-only.
219
220## Safe Workflows
221
222- Review only: `mdx-rust --json evolve <target> --budget 10m --tier 2 --min-evidence covered`
223- Apply Tier 1: `mdx-rust --json evolve <target> --budget 10m --tier 1 --apply`
224- Apply Tier 2: `mdx-rust --json evidence <target> --include-coverage`, then `mdx-rust --json evolve <target> --budget 10m --tier 2 --min-evidence covered --apply`
225
226## Reporting
227
228Report artifact paths, evidence grade, executed candidates, validation status,
229rollback status, and remaining blocked or review-only work.
230
231Generated for: {target_agent}
232"#
233    )
234}