Docs Updater Workflow Design¶
Workflow and domain design for the docs-updater loop (on-loop-docs-updater.yaml).
| Layer | Document |
|---|---|
| Platform | Multi-Branch Loops Design |
| Caller shell | Loop Caller Workflows Design |
| Invariants | Loop Engineering Design |
Artifacts: on-loop-docs-updater.yaml · skill docs-updater · docs-updater/scripts/detect_changes.sh
Shared caller keys: Loop Caller Inputs Reference.
Purpose¶
Detect documentation drift from code changes on integration branches and open fix PRs after the docs-updater skill runs.
Supported use cases¶
- Cron scan of integration branches for git-diff facts (
changed_files,affected_docs, …) - Semantic review and fix of high-priority stale references or missing doc content
- Open an L2 review PR to the watch integration branch
- Coordinate with peer loops via workflow concurrency when multiple loops target the same branch
Out of scope¶
- PR head healing (
pr_enableddefault off) - Creating documentation from scratch; non-documentation file edits
- Loop state and detect script management
docs-updater dual paths¶
| Path | Trigger | Input |
|---|---|---|
| Interactive / hook | Pre-commit, user-invoked | scripts/detect_changes.sh JSON (mechanical facts) |
| Loop | on-loop-docs-updater.yaml |
Same detect script facts in prompt; skill builds findings[] in Execute |
Both paths share docs-updater/scripts/detect_changes.sh for mechanical facts only. The entry skill (Execute) builds semantic findings[] — detect and the caller do not emit semantic classifications.
Detect scope axis (normative)¶
Normative cross-skill definition: Detect scope axis and interactive discovery.
| Path | --scope |
Notes |
|---|---|---|
| Loop (state cursor) | range --since <sha> |
Unchanged — detect limits to <since>..HEAD changes |
| git hook / pre-commit | staged |
Index diff only; untracked files are not visible until added |
| Interactive free-form | all |
Breaking (2026-08-10): full candidate-doc enumeration — not git diff HEAD + untracked |
Loop callers must not rely on --scope all for worktree sync; use staged (hook) or range (automation).
Detect → findings pipeline (loop domain)¶
- Detect script emits mechanical facts:
changed_files,deleted_files,renamed_files,affected_docs,commit_range,skip. - Execute agent (docs-updater on the automation path) maps facts into
findings[]withfile,reason, andsource_commit, then classifies and patches per skill checklists. - Field semantics and
## Constraintsedit gate: common-loop-triage-format.md and skillreferences/category-input-schema.md/category-automation-envelope.md(automation path only).
Modes¶
| Mode | Default | Behavior |
|---|---|---|
integration |
on | Detect on watch branch → fix PR to same branch |
pull_request |
off | not supported for this loop |
Caller inputs¶
Keys are passed in on-loop-docs-updater.yaml via with: on ci-loop-caller.yaml (alphabetically ordered). Multiline values (agent_checker_instructions, agent_maker_instructions) are defined inline in the caller workflow.
Shared semantics: Loop Caller Inputs Reference. Platform branch/finalize caps: canonical table.
| Input / JSON key | Description | Dogfood value |
|---|---|---|
agent_maker_max_turns |
Max maker agent turns per loop attempt (one Agent→Verify cycle). | 100 |
agent_maker_model |
Maker model ID. Cursor: agent --list-models. |
claude-sonnet-5 |
agent_maker_effort |
Maker reasoning effort. Only engines with an effort flag (claude) consume it | medium |
agent_loop_max_attempts |
Max Agent→Verify retry cycles before finalize records failure. | 3 |
agent_checker_instructions |
Checker APPROVE/REJECT rubric. Doc-only edits; factual consistency; no sensitive data. | Inline in caller workflow |
agent_checker_max_turns |
Max checker agent turns per verification. | 100 |
agent_checker_model |
Checker model ID. Cursor: agent --list-models. |
claude-opus-5 |
agent_checker_effort |
Checker reasoning effort. Only engines with an effort flag (claude) consume it | medium |
allowlist |
Comma-separated globs the maker may modify. Must align with docs-updater scope. | docs/**/*.md,README.md,mkdocs.yml |
branch_match |
Comma-separated integration branch patterns to watch for doc drift. | main |
branch_state |
Branch for .loop/* persistence, state migration, and watch fallback. |
main |
budget_max_runs_per_day |
Daily run cap keyed by loop_name. Caller input; .loop/loop-budget.json overrides when present. |
1 |
budget_max_tokens_per_day |
Daily aggregated token cap across loops. | 1000000 |
detect_script |
Domain detect script path (shared with docs-updater hook path). | .agents/skills/docs-updater/scripts/detect_changes.sh |
engine |
AI engine (claude, copilot, codex, cursor). Maps AGENT_TOKEN to engine env. |
claude |
delivery |
Platform delivery after APPROVE (open_pr for dogfood). |
open_pr |
infer_files_pattern |
Extended regex to infer file paths from checker text. | See caller workflow |
level |
Autonomy level (L1, L2, L3). L2 opens review PR. |
L2 |
loop_name |
Loop identifier; state file .loop/state-docs-updater.json. |
docs-updater |
max_targets_per_schedule |
Max targets per cron tick after priority filters. | 3 |
may_edit |
Agent worktree edit gate (true for dogfood). |
true |
no_changes_verdict |
APPROVE or REJECT when maker produces no file diff. |
REJECT |
pr_body |
Optional static prefix (dogfood: ""). loop-finalize composes agent Overview/Summary + mechanical sections. See Loop PR Body Readable Design. |
"" |
pr_title |
PR title when finalize strategy is open_pr. |
chore(docs-updater): automated documentation update (loop-docs-updater) |
agent_maker_instructions |
Domain instructions: run docs-updater automation path; address documented findings. | Inline in caller workflow |
pr_enabled |
Enumerate open PR heads. docs-updater uses integration branches only. | false |
agent_maker_skill_name |
Skill package to invoke. | docs-updater |
Domain detect environment (detect_domain_env_json)¶
| JSON key | Description | Dogfood value |
|---|---|---|
DOCS_UPDATER_DOC_GLOBS |
Comma-separated doc file globs for git-diff analysis | docs/**/*.md,README.md |
DOCS_UPDATER_EXTRA_FILES |
Additional non-glob paths | mkdocs.yml |
When DOCS_UPDATER_DOC_GLOBS is unset, detect falls back to a repository-wide *.md find with standard repo_paths pruning (excludes .agents/, generated trees, etc.). Production callers should set globs explicitly; the fallback is mainly for local runs and tests.
Hook / manual (appendix)¶
Not a loop caller; configure via environment when invoking detect_changes.sh outside defaults.
| Env var | Description | Default |
|---|---|---|
DOCS_UPDATER_DOCS_ROOT |
Documentation tree root | docs |
DOCS_UPDATER_SITE_CONFIG |
Site navigation config path | mkdocs.yml |
| write_target | Agent artifact when may_edit is true (fix for dogfood). | fix |
Detect¶
Integration mode only¶
Per watch branch, loop-detect checks out the branch and invokes detect_changes.sh with targets["integration:<branch>"].last_sha.
Detect script outputs facts (not semantic findings):
| Field | Role |
|---|---|
changed_files, deleted_files, renamed_files |
Git diff summary |
affected_docs |
Candidate doc paths for agent review |
commit_range |
Passed through prompt context |
skip |
true when no doc-impacting change |
Skill (docs-updater automation path) builds findings[] with semantic reason from these facts.
loop-detect emits per-branch target_json:
from.ref= HEAD on watch branchto.branch= watch branchfinalize=open_pr
Do not use ci-sweeper workflow-run / gh run list detect.
Stable filters (detect only)¶
- Circuit breaker on
targets[key].consecutive_failures - Budget (platform)
No infra/env classification — not applicable.
State fields (per target key)¶
| Field | Role |
|---|---|
last_sha |
Scan cursor; advances when fix PR merges (on-loop-state-promote) |
pending |
Written at finalize on open_pr; promoted to last_sha on merge |
outcome |
pr-created, rejected, no-op, … |
consecutive_failures |
Circuit breaker |
No workflow_run_id / ci ledger.
Execute¶
- Worktree from
target.fromon integration branch - Checker diff baseline:
to.branch verifier_context: detect fact summary (changed files, affected docs). Platform always wires; may be brief
Finalize¶
PR body is composed by loop-finalize from agent ## Overview / ## Summary (skill-owned) plus mechanical sections. Dogfood sets pr_body: "". See Loop PR Body Skill Contract.
Always open_pr to to.branch at L2. L3 push rarely appropriate for docs-updater; if enabled, requires explicit promotion review.
No domain_persistence_script.
Merge-gated cursor: Same platform rule as all L2 open_pr loops — pending at finalize, last_sha on fix PR merge via on-loop-state-promote.yaml. See State delivery philosophy.
State delivery¶
See State delivery philosophy for platform rules.
Target (dogfood): merge-gated pending + on-loop-state-promote — same as changelog.
Persistence: state-docs-updater.json on branch_state via finalize inside ci-loop-agent.
Implementation Checklist¶
Shared platform: Multi-Branch — Shared platform checklist.
Loop-specific¶
- [x]
docs-updater/scripts/detect_changes.sh(facts output) - [x]
on-loop-docs-updater.yamldogfood caller viaci-loop-caller - [x]
verifier_contexton execute path (build_verifier_context_from_result.affected_docsbranch) - [x]
docs-updaterskill automation path + references - [x] Bats suite for detect script (TEST-00)
Cross-Loop Note¶
If ci-sweeper and docs-updater both target integration:main, workflow concurrency and separate concurrency groups apply. CI failure on main is ci-sweeper priority; doc-only drift is docs-updater.