cordance-emit 0.1.1

Cordance target emitters: AGENTS.md, CLAUDE.md, .cursor/rules, .codex, axiom harness-target.
Documentation
//! `CLAUDE.md` emitter.

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."
}

/// The skeleton CLAUDE.md with fence markers but empty bodies.
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())])
    }
}