Run when implementation is complete and documentation needs updating. Analyzes project artifacts to produce documentation update recommendations, then applies approved changes before project completion.
Read project artifacts and implementation code to identify documentation surfaces that need updating, present a delta plan for approval, and apply changes — all in a single invocation.
Required:
plan.md or implementation.mdOAT MODE: Project Document
Purpose: Analyze what a project built, identify documentation gaps, and apply approved documentation updates.
Print a phase banner once at start:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ OAT ▸ PROJECT DOCUMENT ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
For each step, announce a compact header:
OAT ▸ DOCUMENT — Step N: {step_name}Before multi-step work:
[1/N] {action}…Keep it concise; don't print a line for every shell command.
BLOCKED Activities:
oat_docs_updated in state.md)ALLOWED Activities:
oat_docs_updated in state.mdSelf-Correction Protocol: If you catch yourself:
oat_docs_updated is allowed)Recovery:
Parse $ARGUMENTS for:
--auto flag: If present, skip user approval and apply all recommendations directly.
AUTO_MODE=false
if echo "$ARGUMENTS" | grep -q '\-\-auto'; then
AUTO_MODE=true
fi
project-path: Any non-flag argument is treated as an explicit project path.
PROJECT_ARG=$(echo "$ARGUMENTS" | sed 's/--auto//g' | xargs)
OAT stores active project context in .oat/config.local.json (activeProject, local-only).
PROJECT_PATH=$(oat config get activeProject 2>/dev/null || true)
PROJECTS_ROOT="${OAT_PROJECTS_ROOT:-$(oat config get projects.root 2>/dev/null || echo ".oat/projects/shared")}"
PROJECTS_ROOT="${PROJECTS_ROOT%/}"
Resolution order:
$PROJECT_ARG is provided, use it as $PROJECT_PATHactiveProject is set in config, use thatAskUserQuestion to ask: "No active project found. Please provide the path to the project directory (e.g., .oat/projects/shared/my-project)."Validation:
$PROJECT_PATH/state.md existsplan.md or implementation.md exists (need to know what was built)Derive {project-name} as the directory name: basename "$PROJECT_PATH".
Documentation config resolution:
Read documentation config from .oat/config.json:
DOCS_ROOT=$(oat config get documentation.root 2>/dev/null || true)
DOCS_TOOLING=$(oat config get documentation.tooling 2>/dev/null || true)
DOCS_CONFIG=$(oat config get documentation.config 2>/dev/null || true)
If $DOCS_ROOT is empty, attempt auto-detection:
mkdocs.yml — if found, set DOCS_TOOLING=mkdocs and infer DOCS_ROOT from the docs_dir field (or default to docs/ relative to the mkdocs.yml location), set DOCS_CONFIG to the mkdocs.yml pathdocusaurus.config.js or docusaurus.config.ts — if found, set DOCS_TOOLING=docusaurus, infer DOCS_ROOT from configconf.py (Sphinx) — if found, set DOCS_TOOLING=sphinxdocs/ directory — if found, set DOCS_ROOT=docsDOCS_ROOT remains empty (docs directory scanning will be skipped)For auto-detection, use Glob to scan from repo root:
Glob: **/mkdocs.yml (exclude node_modules, .oat, dist)
Glob: **/docusaurus.config.{js,ts}
Store resolved values for use in later steps. Do not write auto-detected values to config.
Check whether the project-management tool pack is installed by reading config:
PJM_INSTALLED=$(oat config get tools.project-management 2>/dev/null || echo "false")
If PJM_INSTALLED is true:
oat-pjm-update-repo-reference automatically before proceeding.If PJM_INSTALLED is not true: Skip silently and proceed to Step 2.
Read all available project artifacts to build an understanding of what was built.
Read in order:
$PROJECT_PATH/discovery.md — initial requirements, key decisions, constraints$PROJECT_PATH/spec.md (if exists) — formal requirements, acceptance criteria$PROJECT_PATH/design.md (if exists) — architecture, components, data models, integration points$PROJECT_PATH/plan.md — phases, tasks, file lists, commit messages$PROJECT_PATH/implementation.md — execution log, outcomes, files changed, decisionsSynthesize a "what was built" model:
From the artifacts, extract and organize:
Note source file references:
While reading artifacts, collect all source file paths mentioned in:
**Files:** sections (Create/Modify entries)**Files changed:** entriesThese will be verified against actual code in Step 3.
Handle missing artifacts gracefully:
Read source files referenced in artifacts to confirm what actually shipped.
For each referenced source file:
Augment the model:
Scope control:
Scan the repository for all documentation and instruction surfaces.
4a. Documentation surfaces (primary — thorough analysis):
Docs directory (if $DOCS_ROOT is set):
$DOCS_CONFIG) to understand nav structure$DOCS_ROOT recursivelyRoot README.md:
Subdirectory README.md files:
**/README.md (exclude node_modules, .oat, dist, .worktrees)Reference files:
.oat/repo/reference/ directorycurrent-state.md, backlog/index.md, backlog/completed.md, roadmap.md, decision-record.md, and relevant backlog/items/*.md files as needed (whichever exist)4b. Instruction surfaces (secondary — strong signals only):
Root AGENTS.md / CLAUDE.md:
Subdirectory AGENTS.md files:
**/AGENTS.md (exclude node_modules, .oat, dist, .worktrees)Provider rules files:
.oat/sync/config.json for enabled providers.claude/rules/.cursor/rules/.github/copilot-instructions.md.gemini/rules/Store surface inventory for use in Step 5. For each surface, record:
Compare "what was built" (from Steps 2-3) against "what's documented" (from Step 4) to produce recommendations.
5a. Documentation surface assessment:
For each documentation surface relevant to the project, determine one of:
UPDATE: Existing doc needs content changes. Specify:
CREATE: No existing doc covers this area. Specify:
SPLIT: Existing doc would become too large with additions. Specify:
No change: Surface is already accurate — skip from delta plan.
5b. Instruction surface assessment (strong signals only):
Only recommend instruction changes when there is a clear trigger:
| Signal | Example | Recommendation |
|---|---|---|
| New test framework | vitest added to devDependencies | Create test rules for enabled providers |
| New styling/component library | tailwind, storybook added | Create styling rules for enabled providers |
| New build tooling | different bundler, new build step | Update AGENTS.md development commands |
| New directory with complex patterns | new package with unique conventions | Create subdirectory AGENTS.md |
| New dev commands | new CLI commands, scripts | Update root AGENTS.md |
If no strong signal is present for an instruction surface, skip it.
5c. Per recommendation, capture:
- Target: {file path — existing or proposed}
- Action: {UPDATE | CREATE | SPLIT}
- Summary: {1-2 sentences on what changes and why}
- Evidence: {artifact reference — e.g., "spec.md §3", "plan.md p02-t03", "implementation.md p01-t01 outcome"}
- Content guidance: {specific content to add or outline for new files}
Format and present the recommendations for user approval.
6a. Format output:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OAT ▸ PROJECT DOCUMENT — Delta Plan
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
## Documentation Updates ({N} recommendations)
1. {ACTION} {target file path}
{Summary of what changes and why}
Evidence: {artifact/code reference}
2. {ACTION} {target file path}
{Summary}
Evidence: {reference}
## Instruction Updates ({N} recommendations)
3. {ACTION} {target file path}
{Summary}
Evidence: {reference}
6b. Handle edge cases:
$AUTO_MODE is true: skip to Step 7 (apply all recommendations)oat_docs_updated: complete in state.md, and exit6c. Interactive approval:
Approve recommendations?
[Y]es — apply all
[I]ndividual — approve/reject each one
[S]kip — skip documentation updates
oat_docs_updated: skipped and oat_project_state_updated: "{ISO 8601 UTC timestamp}" in $PROJECT_PATH/state.md frontmatter, commit the state change, and exit without applying documentation changesTrack which recommendations were approved for Step 7.
Execute the approved documentation updates.
For each approved recommendation:
UPDATE:
CREATE:
mkdir -p)SPLIT:
Nav structure updates:
If $DOCS_CONFIG exists and new files were created in the docs directory:
Error handling:
$ALL_SUCCEEDED flag (default: true). If any file write fails, set $ALL_SUCCEEDED to false, log the error, and continue with remaining recommendations8a. Stage and commit documentation changes:
git add {list of changed/created documentation files}
git diff --cached --quiet || git commit -m "docs({project-name}): update documentation from project artifacts"
Only stage files that were actually changed or created in Step 7. Do not use git add -A.
8b. Update project state:
Update $PROJECT_PATH/state.md frontmatter based on apply outcome:
$ALL_SUCCEEDED is true: set oat_docs_updated: complete and oat_project_state_updated: "{ISO 8601 UTC timestamp}"$ALL_SUCCEEDED is false: do not set oat_docs_updated: complete — leave the field as null so the skill can be re-run. Still set oat_project_state_updated: "{ISO 8601 UTC timestamp}". Surface the failures clearly in the summary report (Step 8d) so the user knows which updates failed and why.git add "$PROJECT_PATH/state.md"
git diff --cached --quiet || git commit -m "chore({project-name}): mark docs updated"
8c. Handle edge cases:
oat_docs_updated was already set to skipped in Step 6. No further state update needed here.oat_docs_updated: complete (nothing to do is still "done").--auto mode: apply all, commit, set state — no user interaction.8d. Report summary:
If $ALL_SUCCEEDED is true:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OAT ▸ PROJECT DOCUMENT — Complete
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Documentation sync complete for {project-name}.
Updated: {N} files
Created: {N} files
Split: {N} files
Commit: {sha}
State: oat_docs_updated = complete
Next steps:
- oat-project-complete → close out the project
- Review changes before pushing
If $ALL_SUCCEEDED is false:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OAT ▸ PROJECT DOCUMENT — Partial Failure
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Documentation sync partially failed for {project-name}.
Succeeded: {N} files
Failed: {N} files
- {path}: {error reason}
Commit: {sha} (successful changes only)
State: oat_docs_updated NOT set (re-run to retry)
Next steps:
- Investigate and fix the failed writes
- Re-run oat-project-document to complete the sync
--auto mode applies all changes without user interactionoat_docs_updated state is set correctly in all pathsoat_docs_updated)