Skill v1.0.1
currentAutomated scan100/100+3 new
version: "1.0.1" name: generate-user-docs description: "Synchronizes user-facing documentation with the current knowledge base through validate -> stale gate -> scan -> approval -> process orchestration." allowed-tools: Bash(echo ), Bash(rp1 ), Bash(git ), Bash(mkdir ), Read, Write, Glob metadata: category: documentation is_workflow: true workflow: run_policy: fresh identity_args: [] version: 2.1.0 tags:
- documentation
- sync
- workflow
- parallel
created: 2025-12-28 updated: 2026-04-04 author: cloud-on-prem/rp1 sub_agents:
- "rp1-base:scribe"
Generate User Docs
§ROLE: User-doc sync orchestrator. Reconcile user-facing docs against {kbRoot}/ in one scan pass and one process pass.
§OBJ
- Sync docs to current KB facts
- Keep orchestration state under
{workRoot}/ - Delegate file-level scan/process only
- Ask approval exactly once after scan
- If the KB is stale but structurally valid, require one explicit pre-scan decision gate
§DO
- Execute discovery + scan immediately
- Use
rp1-base:scribeonly for file batches - Spawn scan/process batches in parallel with background dispatch
- When the KB is stale, warn with a three-way gate: continue, rebuild first, or cancel
- Keep user-visible output terse:
- KB validation status
- Scan summary + approval gate
- Final report
- Preserve
scan_results.json; do NOT delete it automatically
§DONT
- Do NOT ask approval before scan
- Do NOT edit docs directly in the parent
- Do NOT iterate on scan or process more than once
- Do NOT silently continue with a stale KB
- Do NOT treat diffs inside the docs being reconciled as KB-staleness signals for this run
§PATHS
- Use the
RUN_IDfrom the generated Workflow Bootstrap section - Derive
RUN_NAMEas"Docs: sync user docs"(max 60 chars) - Set
DATESTAMPto the current date inYYYY-MM-DD - Set
SESSION_DIR=docs-sync/{DATESTAMP}-{RUN_ID} - Set
SCAN_RESULTS_REL={SESSION_DIR}/scan_results.json - Set
SCAN_RESULTS_PATH={workRoot}/{SCAN_RESULTS_REL}
STATE-MACHINE
stateDiagram-v2[*] --> discoverdiscover --> validate_kb : docs_readydiscover --> failed : no_docsvalidate_kb --> scan : kb_currentvalidate_kb --> stale_kb_gate : kb_stalevalidate_kb --> failed : kb_invalidstale_kb_gate --> scan : continue_with_stalestale_kb_gate --> cancelled : rebuild_requestedstale_kb_gate --> cancelled : rejectedscan --> approve : results_writtenscan --> failed : scan_failedapprove --> process : approvedapprove --> cancelled : rejectedprocess --> finalize : processing_doneprocess --> failed : process_failedfinalize --> [*] : donefailed --> [*] : stoppedcancelled --> [*] : stopped
First emit:
rp1 agent-tools emit \--workflow generate-user-docs \--type status_change \--run-id {RUN_ID} \--name "{RUN_NAME}" \--step discover \--data '{"status": "running"}'
State progression:
- Enter
discover,validate_kb,stale_kb_gate,scan,approve,process, andfinalizewith{"status": "running"} - Enter
failedwith{"status": "failed"} - Use
emit end-run --run-id {RUN_ID} --outcome cancelled --reason "..."for intentional stops fromstale_kb_gateorapprove. Do not useskippedas the run-level cancellation status. - Finish
finalizewith{"status": "completed"}
{% plan_tool "Track workflow: discover, validate_kb, stale_kb_gate, scan, approve, process, finalize. Keep exactly one step in progress." %}
§PROC
1. Discover Docs + Style
Discover candidate user docs via Glob:
README.mddocs/**/*.mddocs/**/*.mdx**/*.md**/*.mdx
Dedupe by path. Keep project-relative paths only.
Exclude common generated, dependency, build, and internal metadata paths:
.rp1/**,node_modules/**,.git/**,vendor/**,.venv/**,venv/**dist/**,**/dist/**,build/**,out/**,coverage/**,**/target/**,**/__pycache__/**.cache/**,.next/**,.nuxt/**,.svelte-kit/**,.idea/**,.vscode/**,.github/**
Exclude non-user-doc basenames:
AGENTS.mdDEVELOPMENT.mdCHANGELOG.mdLICENSELICENSE.mdCODE_OF_CONDUCT.mdSECURITY.md
CONTRIBUTING.md:
- Exclude only if it is a tiny stock template or placeholder
- Keep it if it is clearly project-specific user documentation
Set DOC_FILES to the remaining paths.
If DOC_FILES is empty:
- Output:
``` ERROR: No user-facing documentation files discovered.
Searched:
- README.md
- docs/**/*.md
- docs/**/*.mdx
- **/*.md
- **/*.mdx
```
- Transition to
failed - STOP
Log:
Discovered {DOC_FILES.length} documentation files
Pick up to 3 sample files for style inference:
- Prefer
README.mdif present - Prefer one
docs/file - Prefer one other remaining file
Read each sample and infer:
heading_style:atx | setextlist_marker:dash | asterisk | plus | numberedcode_fence:backtick | tilde | indentlink_style:inline | referencemax_line_length: p90 line length rounded to nearest 10 and clamped to80..120
Build STYLE_CONFIG:
{"heading_style": "atx","list_marker": "dash","list_style": "dash","code_fence": "backtick","link_style": "inline","max_line_length": 100}
Rules:
list_markeris canonicallist_styleis a compatibility alias; keep it equal tolist_marker- If style inference is mixed or weak, choose the dominant style or the default shown above
Log the inferred style in one short block.
2. Validate KB
Use Glob to confirm {kbRoot}/state.json exists. If missing:
- Output:
``` ERROR: Knowledge base not found.
Run /rp1-base:knowledge-build, then retry. ```
- Transition to
failed - STOP
Read {kbRoot}/state.json. Extract:
generated_atgit_commit
If git_commit missing or empty:
- Output:
``` ERROR: Invalid KB state.
state.json is missing git_commit. Run /rp1-base:knowledge-build, then retry. ```
- Transition to
failed - STOP
Verify the commit exists:
git cat-file -e {KB_GIT_COMMIT}^{commit} 2>/dev/null || echo "INVALID"
If output is INVALID:
- Output:
``` ERROR: KB references unknown git commit.
Run /rp1-base:knowledge-build, then retry. ```
- Transition to
failed - STOP
Compute:
git rev-parse HEADgit rev-list --count {KB_GIT_COMMIT}..HEAD
Store:
HEAD_COMMITCOMMITS_SINCE_KB
Compute repo changes since KB build:
git diff --name-only {KB_GIT_COMMIT} HEAD
Derive STALE_CHANGES:
- Start with the diff list above
- Drop generated or ignored paths from §1
- Drop
.rp1/work/** - Drop any path present in
DOC_FILES - Treat all remaining paths as KB-affecting changes for this workflow
Build:
{"state": "current","generated_at": "ISO-8601 timestamp","git_commit": "commit sha","head_commit": "commit sha","commits_behind": 0,"stale_paths": []}
Rules:
state = "current"whenSTALE_CHANGESis emptystate = "stale"whenSTALE_CHANGESis non-emptycommits_behind = COMMITS_SINCE_KBstale_paths = STALE_CHANGES
This filter is intentionally strict about non-doc-output changes and intentionally permissive about changes inside DOC_FILES; those docs are the workflow outputs being reconciled.
If STALE_CHANGES is empty:
- Output:
`` KB sync verified Commit: {KB_GIT_COMMIT} Built: {generated_at} ``
- Continue to scan
If STALE_CHANGES is non-empty:
- Output:
``` WARNING: Knowledge base is out of sync for this workflow.
KB Generated: {generated_at} KB Commit: {KB_GIT_COMMIT} Current HEAD: {HEAD_COMMIT} Behind by: {COMMITS_SINCE_KB} commits
KB-affecting changes since KB build (showing up to 30): {first 30 stale paths} ```
- Emit the stale-KB gate:
``bash rp1 agent-tools emit \ --workflow generate-user-docs \ --type waiting_for_user \ --run-id {RUN_ID} \ --step stale_kb_gate \ --data '{"prompt": "Knowledge base is stale. Continue with the stale KB, rebuild the KB first, or cancel?", "context": "KB is {COMMITS_SINCE_KB} commits behind HEAD with {STALE_CHANGES.length} KB-affecting changed paths"}' ``
- Present the gate using the standard Liquid prompt syntax:
KB_DECISION = {% ask_user "Knowledge base is stale. Continue with the stale KB, rebuild the KB first, or cancel?", options: "Continue with stale KB", "Rebuild KB first", "Cancel" %}
- If
KB_DECISION == "Continue with stale KB": - Output:
``` Proceeding with a stale KB by user choice.
KB is {COMMITS_SINCE_KB} commits behind HEAD. ```
- Continue to scan
- If
KB_DECISION == "Rebuild KB first": - Output:
``` Documentation update stopped before scan.
Rebuild the KB with /rp1-base:knowledge-build, then re-run this command. ```
- End the run explicitly:
``bash rp1 agent-tools emit end-run \ --run-id {RUN_ID} \ --outcome cancelled \ --reason "User chose to rebuild the KB before scanning docs" ``
- STOP
- If
KB_DECISION == "Cancel": - Output:
``` Documentation update cancelled before scan.
KB is stale by {COMMITS_SINCE_KB} commits. ```
- End the run explicitly:
``bash rp1 agent-tools emit end-run \ --run-id {RUN_ID} \ --outcome cancelled \ --reason "User cancelled docs sync at the stale KB gate" ``
- STOP
3. Scan
Create the session directory:
mkdir -p {workRoot}/{SESSION_DIR}
Batch DOC_FILES into groups of 5.
Spawn one background rp1-base:scribe per batch:
{% dispatch_agent "rp1-base:scribe", background %} MODE: scan FILES: {actual JSON array of project-relative paths for this batch} KB_ROOT: {kbRoot} KB_INDEX_PATH: {kbRoot}/index.md
Task: return JSON only with:
modeclassificationssummary- optional
errors
{% enddispatch_agent %}
Wait for all scan agents to finish.
For each response:
- Parse JSON
- Valid only if:
mode == "scan"classificationsis an arraysummaryis present- Capture top-level
errorswhen present - Append per-file scan errors from successful responses into
AGGREGATED.errors - Track
TOTAL_BATCHESandFAILED_BATCHES
Failure policy:
- If no scan batch succeeded: transition to
failed - If
failed_batches / total_batches >= 0.5: transition tofailed - Otherwise continue with successful batches only
Carry KB_STATUS into AGGREGATED.kb unchanged.
Aggregate successful results into AGGREGATED:
{"generated_at": "ISO-8601 timestamp","kb": {"state": "current","generated_at": "ISO-8601 timestamp","git_commit": "commit sha","head_commit": "commit sha","commits_behind": 0,"stale_paths": []},"style": {"heading_style": "atx","list_marker": "dash","list_style": "dash","code_fence": "backtick","link_style": "inline","max_line_length": 100},"files": {"README.md": {"sections": [{"heading": "Quick Start","line": 10,"level": 2,"scenario": "fix","kb_match": "modules.md:20"}]}},"summary": {"total_files": 1,"verify": 0,"add": 0,"fix": 1},"errors": [{"file": "README.md","error": "Could not read one heading body cleanly"}],"scan_failures": [{"batch": 2,"error": "Invalid JSON"}]}
Write SCAN_RESULTS_PATH.
Compute:
TOTAL_SECTIONS = AGGREGATED.summary.verify + AGGREGATED.summary.add + AGGREGATED.summary.fix
Show the scan summary:
Documentation Scan Complete{AGGREGATED.summary.total_files} files, {TOTAL_SECTIONS} sections: {AGGREGATED.summary.verify} verify, {AGGREGATED.summary.add} add, {AGGREGATED.summary.fix} fix
If AGGREGATED.kb.state == "stale":
- Add one short warning line:
Using stale KB by user choice: {AGGREGATED.kb.commits_behind} commits behind
If scan_failures is non-empty:
- Add one short warning line with the failure count
- Do NOT dump raw agent output unless the scan is already failing
If errors is non-empty:
- Add one short warning line with the per-file error count
- Preserve the errors in
scan_results.jsonfor process/reporting
4. Approval
Emit the approval gate:
rp1 agent-tools emit \--workflow generate-user-docs \--type waiting_for_user \--run-id {RUN_ID} \--step approve \--data '{"prompt": "Proceed with documentation updates?", "context": "Docs sync approval after scan phase"}'
APPROVAL = {% ask_user "Proceed with documentation updates?", options: "Yes", "No" %}
If APPROVAL == "No":
- Output:
``` Documentation update cancelled.
Scan results preserved at: {workRoot}/{SCAN_RESULTS_REL} ```
- End the run explicitly:
``bash rp1 agent-tools emit end-run \ --run-id {RUN_ID} \ --outcome cancelled \ --reason "User declined to apply documentation updates after the scan" ``
- STOP
If APPROVAL == "Yes", continue.
5. Process
Set PROCESS_FILES = Object.keys(AGGREGATED.files). Batch into groups of 5.
Spawn one background rp1-base:scribe per batch:
{% dispatch_agent "rp1-base:scribe", background %} MODE: process FILES: {actual JSON array of project-relative paths for this batch} KB_ROOT: {kbRoot} SCAN_RESULTS_PATH: {workRoot}/{SCAN_RESULTS_REL} STYLE: {actual JSON.stringify(STYLE_CONFIG)}
Task: return JSON only with:
moderesultssummary- optional
errors
{% enddispatch_agent %}
Wait for all process agents to finish.
For each response:
- Parse JSON
- Valid only if:
mode == "process"resultsis an array
If no process batch response is valid:
- Output
ERROR: Process phase failed before any valid result was returned. - Transition to
failed - STOP
Aggregate file outcomes:
SUCCESSFUL_FILES:status == "success"PARTIAL_FILES:status == "partial"FAILED_FILES:status == "failed"
Rules:
successandpartialboth count as processedpartialmeans useful edits landed, but some edits failed or review markers were insertedfailedmeans the file was not usefully updated
Build:
{"files_processed": 0,"files_succeeded": 0,"files_partial": 0,"files_failed": 0,"total_sections_verified": 0,"total_sections_added": 0,"total_sections_fixed": 0,"total_edits_applied": 0,"failed_files": []}
Count section and edit totals from both SUCCESSFUL_FILES and PARTIAL_FILES.
Final report:
Documentation Sync CompleteKB used: {AGGREGATED.kb.state}- Commits behind at scan start: {AGGREGATED.kb.commits_behind}Files processed: {files_processed}- Succeeded: {files_succeeded}- Partial: {files_partial}- Failed: {files_failed}Changes applied:- Sections verified: {total_sections_verified}- Sections added: {total_sections_added}- Sections fixed: {total_sections_fixed}- Total edits: {total_edits_applied}Scan results: {workRoot}/{SCAN_RESULTS_REL}Git-ready: docs: sync {files_succeeded + files_partial} files with KB ({total_edits_applied} edits)
If failed_files is non-empty:
- List up to 10 lines as
{path}: {first error or fallback message}
If files_succeeded + files_partial == 0:
- Transition to
failed - STOP after the report
Do NOT delete SCAN_RESULTS_PATH. Transition to finalize.