use camino::Utf8PathBuf;
use cordance_core::pack::CordancePack;
use crate::agents_md::forbidden_surfaces_body;
use crate::{EmitError, TargetEmitter};
pub struct ClaudeMdEmitter;
const fn operating_mode_body() -> &'static str {
"Use CONTROLLED mode for any file edits, tool use, or multi-step work.\n\
Use DIRECT only for single-step factual answers."
}
const fn cortex_boundary_body() -> &'static str {
"Cordance writes to Cortex only via `cordance-cortex-receipt-v1-candidate` receipts.\n\
Never write directly to the cortex repo or modify cortex storage.\n\
The operator hands receipts to Cortex's own acceptance flow."
}
const fn axiom_boundary_body() -> &'static str {
"Axiom is a read-only reasoning harness. Cordance emits `pai-axiom-project-harness-target.v1`\n\
JSON that axiom validators accept. Cordance does not claim runtime authority."
}
const TEMPLATE: &str = "\
# CLAUDE.md
<!-- Generated by Cordance. Regions inside fences are managed; edits outside fences are preserved. -->
## Operating Mode
<!-- cordance:begin operating-mode -->
<!-- cordance:end operating-mode -->
## Build Commands
<!-- cordance:begin build-commands -->
<!-- cordance:end build-commands -->
## Cortex Boundary
<!-- cordance:begin cortex-boundary -->
<!-- cordance:end cortex-boundary -->
## Axiom Boundary
<!-- cordance:begin axiom-boundary -->
<!-- cordance:end axiom-boundary -->
## Forbidden Imports
<!-- cordance:begin forbidden-imports -->
<!-- cordance:end forbidden-imports -->";
impl TargetEmitter for ClaudeMdEmitter {
fn name(&self) -> &'static str {
"claude-code:claude-md"
}
fn render(&self, pack: &CordancePack) -> Result<Vec<(Utf8PathBuf, Vec<u8>)>, EmitError> {
let build_commands = crate::agents_md::commands_body(pack);
let forbidden = forbidden_surfaces_body();
let content = cordance_core::fence::replace_regions(
TEMPLATE,
&[
("operating-mode", operating_mode_body()),
("build-commands", &build_commands),
("cortex-boundary", cortex_boundary_body()),
("axiom-boundary", axiom_boundary_body()),
("forbidden-imports", forbidden),
],
);
Ok(vec![("CLAUDE.md".into(), content.into_bytes())])
}
}