oma-docs · diff
git:20260823.b35d07c to git:20260912.7e4c0d1
40 added, 256 removed. Audit A to A.
---
name: oma-docs
- description: Verify documentation references against the current codebase,
- propose updates for diff-affected docs, detect i18n translation drift, and
- lint translated docs for CJK style issues. Use to check if docs still match
- reality (broken file paths, CLI commands, config keys, env vars, scripts), to
- surface docs that may need updating after code changes, or to find stale or
- style-broken translations.
+ description: Check documentation references, sync docs to code changes, and
+ detect translation drift. Use for documentation maintenance in a repository.
---
- # oma-docs - Documentation Drift Detector
+ # Documentation Maintenance
## Scheduling
### Goal
- Detect broken references in repo markdown — default glob `**/*.md` (verify mode), propose LLM-generated patch proposals for docs affected by recent code changes (sync mode), detect structural drift between English source docs and their translations (i18n mode), and lint translated docs for CJK style anti-patterns (lint mode). All modes run on-demand; sync is always interactive.
+ Keep documentation aligned with repository behavior and report verification limits.
### Intent signature
- - User asks to check if docs are up to date, find broken doc links, verify file paths referenced in docs, or detect documentation drift.
- - User asks to update docs after a code change, propose doc patches for a git diff, or sync affected docs.
- - User asks whether translations are stale, which i18n docs drifted from the English source, or to lint translated docs for style issues (em-dashes in CJK targets, etc.).
- - A workflow hook checks `docs.auto_verify: true` and runs `oma docs verify --json` at completion.
+ Check references, update docs for a code diff, identify translation drift, or lint localized prose.
### When to use
- - After a refactor, rename, or file deletion, to find stale references in docs.
- - Before a release, to confirm that CLI commands, file paths, and config keys in docs still exist.
- - After a significant git diff, to discover which docs reference the changed files and may need updating.
- - After updating English source docs (`web/docs`), to find translations (`web/i18n/{lang}/...`) that drifted or went missing.
- - Before a docs release, to lint CJK translations for content-level anti-patterns.
- - Routine drift check on any docs-heavy repo.
+ Repository documentation verification, diff-based synchronization, and translation maintenance.
### When NOT to use
- - Generating docs from scratch for undocumented features → v2 create mode.
- - Actually translating or restructuring docs → use `oma-translation` (`oma docs i18n` / `oma docs lint` only detect; they never edit translations).
- - Symbol-level semantic drift (function signature changes not reflected in prose) → v2 L3 mode.
- - CI-blocking enforcement → v2 block mode (v1 is warn-only).
- - Explaining a code change as an educational document → use `oma-explanation` (this skill detects drift; it does not author explainers).
+ - General source research -> oma-search.
+ - Application implementation -> the owning specialist.
+ - Translating known text -> oma-translation.
### Expected inputs
-
- **verify mode**: Optional glob path (default `**/*.md`), optional `--json` flag, optional `--report-file <path>`.
-
- **sync mode**: Optional git diff range (default `--cached`, fallback `HEAD~1..HEAD`).
-
- **i18n mode**: Optional `--min-severity <CRITICAL|HIGH|MEDIUM|LOW>` (default `MEDIUM`), optional `--json`.
-
- **lint mode**: Optional `--locales <list>` (comma-separated CJK locales for the `cjk-em-dash` rule, default `ko,ja,zh`), optional `--json`. The default `wrong-language` rule always scans every locale under `web/i18n/` and is not narrowed by `--locales`.
+ Mode (`verify`, `sync`, `i18n`, or `lint`), target paths or diff range, and authorized edit scope. Use `verify` when no mode is specified.
### Expected outputs
-
- **verify mode**:
- - Markdown drift report to stdout (default), or raw JSON with `--json`, or full markdown written to file with `--report-file`.
- - Exit code 0 if clean, 1 if any broken refs found.
-
- **sync mode**:
- - Per-doc patch proposals drafted by the host LLM from the CLI's candidate-doc list, confirmed per doc (`[y] apply [n] skip [d] diff [s] full proposal` style).
- - Docs modified only on explicit user approval; `doc-refs.json` regenerated after applies.
-
- **i18n mode**:
- - Per-pair structural drift signals (line count, heading count, EN-newer recency flag) with severity, as markdown summary or `--json`. Report-only: drifting pairs are handed to `oma-translation` in diff-sync mode.
-
- **lint mode**:
- - Style issues grouped by rule / language / file, as markdown summary or `--json`. Report-only: restructuring goes through `oma-translation`.
+ Findings with paths and evidence, authorized patches when requested, and unresolved checks. CLI reports remain distinct from host-authored interpretation.
### Dependencies
- - `cli/commands/docs/extract.ts`: markdown AST + L2 pattern extractor.
- - `cli/commands/docs/resolve.ts`: deterministic broken-ref checker.
- - `cli/commands/docs/reporter.ts`: deterministic markdown/JSON report renderer (no LLM call; host LLM does narrative synthesis).
- - `cli/commands/docs/sync-propose.ts`: git diff intake, reverse lookup, candidate-doc selector with secret redaction (no LLM call; host LLM drafts patches).
- - `cli/commands/docs/i18n-drift.ts`: EN↔translation structural drift detector (line/heading counts, last-commit recency; no LLM call).
- - `cli/commands/docs/lint-i18n.ts`: translated-doc linter for selected-locale CJK em-dash style and all-locale wrong-language placeholders (no LLM call, no auto-fix).
- - `docs/generated/doc-refs.json`: single-direction reference index, regenerated on every verify run. Gitignored — the CLI force-adds `docs/generated/` to `.gitignore` so generated artifacts are never committed.
- - `docs/generated/url-drift.json`: lychee-produced URL drift report (written by background lychee spawn; gitignored under the same `docs/generated/` rule).
- - `lychee`: external Rust tool for URL link checking. Detected on PATH; install via `brew install lychee` or see https://github.com/lycheeverse/lychee#installation. Optional but recommended.
- - `.agents/oma-config.yaml`: `docs.auto_verify` (workflow hook opt-in), `docs.check_urls` (URL checking on/off, default true), and `docs.exclude` (glob list of markdown trees the walker must not scan — benchmark artifacts, translation mirrors, etc.; default `[]`) toggles.
-
- ### Control-flow features
- - Mode is selected from the first argument: `verify`, `sync`, `i18n`, or `lint`.
- - verify: extract → resolve → report (fully deterministic CLI; host LLM adds narrative summary on top of the JSON/markdown output).
- - sync: git diff → reverse lookup → candidate list (CLI) → host-LLM patch proposals → interactive accept/reject.
- - i18n / lint: fully deterministic CLI reports; host LLM routes drifting pairs / style issues to `oma-translation`.
- - Branches on `--json`, `--report-file`, LLM availability, and network reachability.
- - Never blocks workflow completion in v1 (warn-only hook policy).
+ The `oma docs` CLI, Git for diff-based work, and repository docs. `lychee` is optional for URL verification. Read `resources/commands.md` for flags and output files of the selected mode.
## Structural Flow
- ### Entry
- 1. Read first argument to select mode (`verify` | `sync` | `i18n` | `lint`). If absent, print help and exit.
- 2. Load `oma-config.yaml` to check `docs.auto_verify` when invoked from a workflow hook.
- 3. Confirm required CLI dependencies (`oma docs verify`, `oma docs sync`) are on PATH.
-
- ### Scenes
- 1. **PREPARE**: Determine mode, resolve path/diff-range arguments, confirm tool availability.
- 2. **ACQUIRE**: Run extractor (`extract.ts`) to regenerate `doc-refs.json` from repo markdown (`**/*.md`, verify) or build in-memory reverse index from `doc-refs.json` (sync; a cached index newer than 5 minutes is reused, otherwise regenerated).
- 3. **REASON**: Resolve each reference deterministically (verify) or correlate changed files to candidate docs via reverse lookup (sync).
- 4. **ACT**: Render the deterministic drift report (verify) or list candidate docs with matched refs (sync). Host LLM does any natural-language synthesis or patch drafting on top of this output.
- 5. **VERIFY**: Confirm output shape is valid (JSON schema check for `--json`; structured candidate list for sync).
- 6. **FINALIZE**: Print to stdout, write report file if requested, emit exit code.
-
### Transitions
- - verify mode: PREPARE → ACQUIRE (extract) → REASON (resolve) → ACT (report) → FINALIZE.
- - sync mode: PREPARE → ACQUIRE (reverse index) → REASON (candidate matching) → ACT (LLM proposals) → VERIFY (interactive) → FINALIZE (apply approved).
- - If LLM is unavailable in verify: skip reporter summary, emit raw JSON drift report.
- - If LLM is unavailable in sync: emit candidate-list-only output (no patch proposals); user reviews manually.
- - If `doc-refs.json` is missing or older than 5 minutes in sync: regenerate via the extractor, then continue.
+ - `verify`: extract and resolve references, then summarize the report.
+ - `sync`: obtain candidates, read relevant docs and diffs, and apply only authorized corrections.
+ - `i18n` / `lint`: report drift or style issues; use oma-translation for authorized corrections.
+ - Review-only requests produce proposals. Existing scoped edit requests authorize applying those corrections without another per-file approval.
### Failure and recovery
- - Extractor parse error on a single doc: skip doc + warn, continue with remaining docs.
- - lychee unavailable or URL check incomplete: print install hint, skip URL checking, continue (core check is unaffected).
- - Host-LLM context limit exceeded while drafting patches: process candidate docs in smaller batches.
- - `oma docs` CLI not found: skip with installation hint (workflow hook: skip silently).
- - `doc-refs.json` write failure: abort and report the write error; do not emit partial index.
+ | Failure | Recovery |
+ |---|---|
+ | Missing CLI | Report unavailable automated checks; continue useful scoped inspection without presenting it as a CLI verification |
+ | Missing lychee or incomplete URL scan | Report core results and the unverified URL scope |
+ | One document cannot be parsed | Record the skipped file and continue other documents |
+ | Patch does not apply | Re-read the affected current content and make the equivalent authorized correction |
+ | Index write fails | Report the failure; do not claim the index or check is complete |
### Exit
- - Success (verify): drift report emitted; exit 0 if clean, exit 1 if broken refs found.
- - Success (sync): approved patches applied; `doc-refs.json` regenerated; session summary printed.
- - Partial success: extractor or resolver errors are explicit in the report; no silent failures.
+ Report verified findings, edits made, and remaining gaps. A clean reference scan does not establish semantic correctness or complete translation quality.
## Logical Operations
- ### Actions
- | Action | SSL primitive | Notes |
- |--------|---------------|-------|
- | Parse CLI args and mode | `READ` | First arg selects verify or sync |
- | Extract refs from docs | `CALL_TOOL` | `extract.ts`: remark AST + L2 patterns → `doc-refs.json` |
- | Check broken refs | `RESOLVE` | `resolve.ts`: file, url, cli, script, env, config checks |
- | Build reverse index | `INFER` | `sync-propose.ts`: in-memory map from `doc-refs.json` |
- | Match diff to candidate docs | `RESOLVE` | `sync-propose.ts`: git diff + reverse lookup |
- | Redact secrets from diff | `VALIDATE` | Exclude `.env*`, `*.pem`, `*.key`, `id_rsa*`; sanitize content |
- | Detect i18n drift | `RESOLVE` | `i18n-drift.ts`: EN↔translation structural signals + severity |
- | Lint translated docs | `VALIDATE` | `lint-i18n.ts`: selected-locale CJK style plus all-locale wrong-language placeholders, report-only |
- | Generate patch proposals | `INFER` | Host LLM drafts patches from `sync-propose.ts` candidate output (no CLI LLM call) |
- | Render drift report | `RENDER` | `reporter.ts`: markdown (default), JSON (`--json`), file (`--report-file`) |
- | Apply approved patches | `WRITE` | `git apply` on user-confirmed patches only |
- | Notify hook summary | `NOTIFY` | 1-3 line stdout summary for workflow hooks |
-
- ### Tools and instruments
- - `cli/commands/docs/extract.ts`: `remark` + `unified` markdown AST, L2 pattern extraction, escape hatch filter, `docs/generated/doc-refs.json` writer.
- - `cli/commands/docs/resolve.ts`: case-sensitive file existence, `which` for CLI tokens, `package.json` scripts lookup, ripgrep/git grep for env vars, `oma-config.yaml` deep-path check. URL kind is filtered out by the verify command and delegated to lychee. (Internal caching strategy: see design doc.)
- - `cli/commands/docs/reporter.ts`: deterministic markdown + JSON renderer. **No LLM call.** Friendly summary, severity tagging, fix prioritization are the host LLM's responsibility.
- - `cli/commands/docs/sync-propose.ts`: git diff intake, reverse index build, secret-pattern + gitignore file exclusion. Returns candidate docs with matched refs only. **No LLM call.** Patch synthesis is the host LLM's responsibility.
- - `cli/commands/docs/i18n-drift.ts`: pairs `web/docs` English sources with `web/i18n/{lang}/...` translations, emits line/heading/recency drift signals with severity. **No LLM call.** Translation patching is `oma-translation`'s responsibility.
- - `cli/commands/docs/lint-i18n.ts`: content-level linter with `cjk-em-dash` for selected CJK locales and `wrong-language` placeholder detection across all locales. **No LLM call, no auto-fix.** Restructuring is the host LLM's responsibility via `oma-translation`.
- - External: [`lychee`](https://github.com/lycheeverse/lychee) (background URL link checking; install via `brew install lychee`).
-
- ### Host-LLM contract
-
- This skill follows the OMA pattern (mirroring `oma-scholar`): **the CLI emits structured data; the host LLM (the agent runtime that invoked the skill) does any natural-language synthesis or judgment.**
-
- After `oma docs verify --json`:
- 1. Read the JSON drift report.
- 2. Group findings by severity / urgency (host-LLM judgment).
- 3. Suggest fixes per finding, prioritizing files most central to the project.
- 4. If the user asks for natural-language summary, host LLM produces it from the JSON, never from cached prose.
-
- After `oma docs sync <range> --json`:
- 1. Read the candidate doc list (each entry: `{ doc, changedFiles, matchedRefs }`).
- 2. For each candidate doc: read the doc itself, read `git diff` for `changedFiles`, draft a unified-diff patch reflecting the code change.
- 3. Present patches to the user for review. **Never auto-apply.**
- 4. On user approval, apply via `git apply` or by writing the doc directly.
-
- After `oma docs i18n --json`:
- 1. Read the drift pairs (severity, line/heading diff, EN-newer flag per translation).
- 2. Prioritize CRITICAL/HIGH pairs; pass each to `oma-translation` in diff-sync mode (see that skill's § Diff-Sync Mode).
- 3. Never bulk-retranslate; patch only the drifted sections, with user confirmation.
-
- After `oma docs lint --json`:
- 1. Read the style issues grouped by rule / language / file.
- 2. Restructure flagged sentences via `oma-translation` (e.g. § Stage 4-A em-dash rule); confirm edits with the user before writing.
-
### Canonical command path
-
- **verify mode** runs a drift check against the current codebase:
-
- ```bash
- # Default: scan all repo markdown (**/*.md, gitignored files excluded),
- # render markdown to stdout.
- # URL link checking is delegated to lychee in the background
- # (install: `brew install lychee`). Core check ~8s on a 1k-doc repo.
- oma docs verify
-
- # Narrow to a path or glob (uses minimatch)
- oma docs verify "docs/**/*.md"
- oma docs verify cli/README.md
-
- # Machine-readable output for CI / hooks
- oma docs verify --json
-
- # Persist full markdown report to a file (works alongside --json too)
- oma docs verify --report-file ./drift-report.md
-
- # Skip URL checking entirely (when lychee is run separately, or as a
- # one-off override of docs.check_urls=true in oma-config.yaml)
- oma docs verify --no-urls
-
- # Block until lychee finishes (CI scenarios needing complete URL data)
- oma docs verify --urls-sync
-
- # Exit code: 0 = clean, 1 = broken refs found in core check.
- # URL drift, if any, is reported separately at docs/generated/url-drift.json
- # and does NOT affect this exit code.
- ```
-
- **sync mode** proposes patches for docs affected by a git diff (always interactive, never auto-applies):
-
- ```bash
- # Default: staged changes (--cached), fallback HEAD~1..HEAD
- oma docs sync
-
- # Explicit range
- oma docs sync HEAD~5..HEAD
- oma docs sync main..feature-branch
-
- # The CLI emits the candidate-doc list; the host LLM drafts patches and
- # confirms per doc ([y] apply / [n] skip / [d] diff / [s] full proposal).
- # Sync regenerates docs/generated/doc-refs.json after applying any patches.
- ```
-
- **i18n mode** detects structural drift between English source docs (`web/docs`) and translations (`web/i18n/{lang}/...`); report-only, never edits translations:
-
- ```bash
- # Default: severity ≥ MEDIUM, markdown summary to stdout
- oma docs i18n
-
- # Machine-readable, custom threshold
- oma docs i18n --json --min-severity HIGH
-
- # Output: per-pair drift signals (line/heading diff, EN-newer flag).
- # Hand CRITICAL/HIGH pairs to `oma-translation` diff-sync mode.
- ```
-
- **lint mode** checks translated docs for content-level style anti-patterns (report-only, no auto-fix):
-
- ```bash
- # Default CJK locales: ko,ja,zh
- oma docs lint
- oma docs lint --json --locales ko,ja
- ```
-
- **Workflow hook (opt-in)** runs verify automatically at workflow completion when `docs.auto_verify: true` in `oma-config.yaml`:
-
- ```bash
- # Hook command emitted by /scm, /work, /ultrawork
- oma docs verify --json
- # Hook policy: warn-only in v1; non-zero exit does NOT block workflow completion
- ```
-
- ### Resource scope
- | Scope | Resource target |
- |-------|-----------------|
- | `LOCAL_FS` read | repo markdown `**/*.md` (extractor input), `docs/generated/doc-refs.json` (index), `web/docs` + `web/i18n/**` (i18n/lint), `.env.example`, `package.json`, `.agents/oma-config.yaml` |
- | `LOCAL_FS` write | `docs/generated/doc-refs.json` (regenerated each verify run), approved sync patches |
- | `CODEBASE` read-only | Existence checks for file/cli/script/env/config refs; git diff intake |
- | `PROCESS` | `git diff`, `git apply`, `which`, background `lychee` spawn |
- | `NETWORK` | URL checking delegated to `lychee` (no internal HEAD fallback; see Guardrail 6) |
-
- ### Preconditions
- - Markdown files exist in the repo; `docs/generated/` is created on demand for the index.
- - `cli/commands/docs/` is built and `oma` binary is on PATH (or invoked directly via `bun run`).
- - For sync mode: a git diff is available (`--cached` stage or recent commits).
- - For i18n / lint modes: `web/docs` (EN source) and `web/i18n/{lang}` trees exist.
+ 1. Select mode, paths/diff, and authorization from the request. Read only the matching section of `resources/commands.md`.
+ 2. Run `oma docs verify --json`, `oma docs sync <range> --json`, `oma docs i18n --json`, or `oma docs lint --json` as appropriate. For sync, use the requested range; otherwise staged changes, then `HEAD~1..HEAD`.
+ 3. Inspect the structured results. Verify each proposed correction against current code and document context. Exclude secret-bearing files and values from patches and reports.
+ 4. Apply corrections already authorized by the user or assigned task. Ask only about material missing decisions or new scope; continue independent work while waiting.
+ 5. Re-run affected checks after edits and record remaining failures. Regenerate the reference index once after a patch batch when needed.
- ### Effects and side effects
- - verify: regenerates `docs/generated/doc-refs.json` (always overwrites).
- - sync: modifies docs files only on user approval; regenerates `doc-refs.json` after applies.
- - i18n / lint: stdout report only; no file writes.
- - All modes: stdout output (summary or full report).
- - No `.agents/` definition files are ever modified (run outputs under `.agents/results/` and `.agents/state/` are not definitions).
+ ### Resource scope and effects
+ Verification regenerates `docs/generated/doc-refs.json`; optional URL results go to `docs/generated/url-drift.json`. Sync's CLI emits candidate data; the host drafts and applies patches. i18n/lint commands report only. A workflow hook runs only when `docs.auto_verify` is enabled and is warn-only.
### Guardrails
-
- 1. **Never modify `.agents/` definitions**: CLAUDE.md SSOT protection covers skills, workflows, rules, agents, and config, in all modes. Generated artifacts under `.agents/results/` and `.agents/state/` are not SSOT and must not be deleted to "restore" protection.
- 2. **Never auto-apply sync patches**: sync is always interactive; `[y]` confirm required per doc.
- 3. **LLM unavailable → graceful degradation**: verify falls back to raw JSON; sync falls back to candidate-list-only (no proposals). Neither mode blocks on LLM availability.
- 4. **Response language follows `oma-config.yaml` `language`**: user-facing report text is localized; code, paths, JSON keys, and CLI commands stay in English.
- 5. **Secret-bearing files excluded from sync output**: `.env*`, `*.pem`, `*.key`, `id_rsa*`, and gitignored files never appear in candidate `changedFiles` lists. Host LLM never sees secret file paths.
- 6. **URL link checking delegated to lychee**: when `docs.check_urls=true` (default), URL refs are checked by `lychee` running in the background; results land in `docs/generated/url-drift.json`. If `lychee` is missing, an install hint is printed and URL checking is skipped (no internal HEAD fallback).
- 7. **No direct LLM API calls from the CLI**: the CLI never imports vendor SDKs, never reads API keys, never makes outbound LLM requests. All synthesis, patch drafting, and natural-language framing is the host LLM's responsibility (mirrors `oma-scholar`'s pattern). This makes `oma-docs` vendor-agnostic: works identically under Claude Code / Codex / Gemini / Qwen / Antigravity.
- 8. **Hook is warn-only in v1**: broken refs never block workflow completion; `docs.auto_verify: false` by default (explicit opt-in required).
- 9. **Escape hatch respected**: `<!-- oma-docs:ignore-start -->` / `<!-- oma-docs:ignore-end -->` blocks and frontmatter `oma-docs: skip` are honored; no ref extraction from ignored regions. Use this for illustrative example paths in tutorials (hypothetical project files in inline code) that intentionally do not resolve.
- 10. **Gitignored targets are generated, not broken**: a `file` ref whose target does not exist but matches the project's gitignore rules (`git check-ignore`) is classified as `skipped` (a documented runtime/generated output such as `.agents/results/result-*.md`, `.agents/state/memories/*`, `.serena/memories/*`, `.agents/state/*.json`), never as `broken`. gitignore is the single source of truth for "produced at runtime" — gitignore an output path and it stops being flagged. The `skipped` count is surfaced (markdown summary + JSON `skippedCount`) so nothing is silently dropped.
- 11. **Non-prose trees excluded via `docs.exclude`**: committed-but-non-prose markdown (benchmark run artifacts, translation mirrors validated separately by `oma docs i18n`) is dropped from the scan by the `docs.exclude` globs rather than producing unactionable broken refs. An explicit single-file path argument bypasses `docs.exclude`.
- 12. **i18n / lint modes never write**: both emit reports only. Translation patches go through `oma-translation` with per-file user confirmation; the CLI never edits translations.
-
- ### v1 scope note
- v1 covers `verify`, `sync` (broken-only classification, L2 ref extraction), `i18n` (structural translation drift), and `lint` (CJK style anti-patterns). The following are explicitly deferred to v2: `create` mode (generate missing docs), semantic (content-level) translation drift, L3 symbol-level extraction (Tree-sitter/LSP), GitHub Action wrapper, `block` hook mode.
+ - Follow `../_shared/core/execution-policy.md` for authorization and completion.
+ - Keep review-only requests read-only and changes within the assigned diff or acceptance criteria.
+ - Do not expose secret-bearing files (`.env*`, private keys, credentials) in diff reports.
+ - The CLI produces structured data; the host performs natural-language synthesis. Do not invent CLI findings or call a vendor LLM API from the docs CLI.
+ - Honor ignore blocks, `oma-docs: skip`, and configured exclusions. Missing gitignored runtime outputs are skipped, not broken references.
+ - Preserve language, terminology, and placeholders when applying localized corrections.
## References
- - Design doc: `docs/plans/designs/008-oma-docs.md` (full architecture, schema spec, decision log, edge cases).
- - Schema spec: `doc-refs.json` v1 schema defined in design doc § doc-refs.json Schema.
- - Workflow hook integration: design doc § Workflow Hook Integration.
- - Migration: `deepinit` Step 6 retirement, design doc § Migration: deepinit Step 6.
- - Adjacent skills: `oma-translation` (v2 multilingual), `oma-skill-creation` (SSL-lite validation).
+ - Mode commands, flags, and outputs: `resources/commands.md` (selected operation only).
+ - Translation: `../oma-translation/SKILL.md` (localized correction).
+ - Authorization: `../_shared/core/execution-policy.md` (when not already provided).