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