021 - ai rewrite and ai index commands
Purpose: Two user-facing AI commands built on the S20 client: mdd ai rewrite and mdd ai index.
Status: Implemented (2026-05-08)
Introduction
Section titled “Introduction”mdd ai rewrite proposes tone/clarity rewrites of one or more markdown files. mdd ai index generates or refreshes a directory INDEX.md listing every page with a one-sentence summary.
Bundled in one spec because they share infrastructure (caching, output handling, frontmatter awareness) and are similarly small.
Originates from research note R03.
Subcommands
Section titled “Subcommands”mdd ai rewrite <path>... [--style <prompt-file>] [--apply] [--model MODEL]mdd ai index <dir> [--depth 1|all] [--apply] [--model MODEL]mdd ai rewrite
Section titled “mdd ai rewrite”Behaviour
- For each input file, send the body (frontmatter excluded) plus a
tone-of-voice system prompt to the model (default:
ai.models.defaultfrom S20). - Default output: a
<file>.rewrite.mdsibling alongside the source (e.g.notes.md→notes.md.rewrite.md; the full source filename is preserved so multi-dot names likeRFC.draft.mdround-trip toRFC.draft.md.rewrite.mdwithout losing information). The user reviews withgit diffor in an editor. No source file is mutated without--apply— the candidate-sibling pattern is the primary safety mechanism. --applyoverwrites in place (atomic*.tmp → rename). The prior file content is preserved in git history; no separate backup.
Tone-of-voice prompt
The rewrite system prompt has two blocks composed at call time:
- Tone block — bundled at
src/mdd/ai/prompts/tone-of-voice.md. Encodes a concise house voice (clear, professional, low-jargon).--style <file>overrides this block per run; the file is plain markdown used as the tone half of the system prompt. - Constraints block — bundled at
src/mdd/ai/prompts/rewrite-constraints.md. Carries the load-bearing rules (preserve placeholder tokens, don’t alter substance, return only the rewritten body). Never overridable.--styleswaps only the tone block; the constraints block is always appended after the user’s tone so the placeholder- preservation rule survives, regardless of how aggressive the custom style is.
Both digests participate in the cache key (body hash + tone digest
- constraints digest + model id + mdd version per S20). A bundled-prompt upgrade therefore invalidates stale rewrites correctly.
Pass-through rules (the AI is allowed to rewrite body prose only)
- Frontmatter — passed through unchanged.
- Tables, code blocks, fenced
{=confluence}blocks, fenced{=html}blocks — passed through unchanged. - Image references and links — preserved; the model is instructed not to reword link text in ways that break the document’s structure.
- The Confluence export header (S09) — passed through unchanged.
- The MDD footer (S09) — passed through unchanged.
The pass-through is enforced by extraction-and-restitch, not by trusting the model. Protected regions are replaced with placeholder tokens before the model call and substituted back afterwards. If a placeholder is missing from the response, fail loudly (model hallucinated away a protected region; output is unsafe).
Cache behaviour
- Cache key includes: file body hash, tone digest, constraints digest, model id, mdd version (per S20 default).
- Re-running on an unchanged file with the same tone is a no-op (cache hit, no API call).
Run summary
- Per file:
cached,rewritten,error. - End of run: total tokens / cost / count rewritten.
Output
- Multiple files are processed concurrently, bounded by
ai.concurrency(default 4 — see S20). Each call is small; the bound exists to honour gateway rate limits without serialising unnecessarily. - Errors per file are reported and continue; exit non-zero if any failed.
mdd ai index
Section titled “mdd ai index”Behaviour
- Walks
<dir>recursively, finding.mdfiles (ignoring already- generatedINDEX.mdfiles at any level). - For each
.md: compute body hash; if frontmatter has a matchingmdd.ai.summary_input_hash, reuse the cached summary (free). Else, summarise via the model (default:ai.models.summarise) and save the result back into the file’s frontmatter. - Generate or refresh
<dir>/INDEX.md:# Index*Auto-generated by `mdd ai index`. Re-run to refresh.*## Architecture- **[Platform Topology](Architecture/Platform-Topology.md)** —overview of the platform's main runtime components and howthey connect.- **[Deployment Pipeline](Architecture/Deployment-Pipeline.md)** —end-to-end flow from PR merge to production rollout.## Process- **[Onboarding](Process/Onboarding.md)** — checklist for new joiners. --depth 1lists files only (flat list, no grouping).--depth alllets the model cluster pages into topic groups (one extra LLM call); the cluster names become H2 headings.--applywritesINDEX.md(default) and writes summaries back into source-file frontmatter. Without--apply, prints the proposedINDEX.mdto stdout. Same safety pattern asrewrite: nothing on disk changes without explicit opt-in.- The generated
INDEX.mdcarries its own frontmatter:---ai_generated: truegenerated_by: mdd ai indexgenerated_at: 2026-05-08T10:30:00Z---
Per-file summary frontmatter
- Stored on the source
.md:mdd:ai:summary: "Overview of the platform's main runtime components and how they connect."summary_input_hash: 9f86d081...summary_model: claude-haiku-4-5summary_at: 2026-05-08T10:30:00Z - The
summary_input_hashis what makes reruns a no-op.
Topic clustering (only at --depth all)
- After per-file summaries, send the list (file + one-line summary) to the default model with a clustering prompt.
- Model returns
[{topic_title, file_paths[]}, ...]. - Render each topic as an H2 with the listed files under it.
Design Approach
Section titled “Design Approach”Default prompts are bundled in templates/prompts/ (one each
for rewrite, summarise, cluster). They are plain markdown so users
can read and override them.
Cache keys (all on top of S20’s base key):
- Rewrite:
(body_hash, style_hash, model_id, mdd_version, "rewrite") - Index per-file summary:
(body_hash, model_id, mdd_version, "summary") - Index clustering:
(joined_summaries_hash, model_id, mdd_version, "cluster")
Safety design — the --apply vs candidate-sibling distinction
is deliberate. Rewrites are suggestions; the default behaviour
must never silently mutate the user’s source. INDEX.md follows
the same rule: stdout by default, file write only with --apply.
Out of scope
Section titled “Out of scope”- Multi-file rewrite that reasons about cross-file consistency
(that’s S22’s
reviewterritory). - Translation. The default style is monolingual.
- Generating frontmatter fields beyond
mdd.ai.*. - Customising the index header / styling.
Site built 2026-07-30.