Update Existing Guide
Modify an existing content.json based on a change request. The skill plans the edit, applies it, reviews it against the critical rules, and validates the result. Blocks outside the planned change are guaranteed unchanged (byte-level diff at the end).
This skill writes to content.json. It is not read-only — read safety-invariants.md before running.
Do NOT read external reference files upfront. Each phase's sub-agent loads its own references. Everything the orchestrator needs is inline below.
This skill implements the skill-memory convention. See ../skill-memory.md for the shared assets/, manifest, and frontmatter standards.
Workflow Overview
Input (guide directory + change request)
│
├─ Phase 0: Check for Prior Run ── orchestrator
│ Hash = guide content + change request
│
├─ Phase 1: Acquire & Snapshot ── orchestrator (no external reads)
│ Reads: content.json, manifest.json
│ Writes: assets/snapshots/content.json.before
│ assets/guide-structure.json (id → path map)
│
├─ Phase 2: Plan the Change ───── sub-agent loads authoring-guide.mdc
│ │ + best-practices.mdc
│ │ + ../shared/critical-rules.md
│ Writes: assets/change-plan.md
│
├─ Checkpoint: User confirms plan ── orchestrator
│
├─ Phase 3: Apply the Change ──── orchestrator + per-section sub-agents
│ │ (sub-agents load authoring-guide.mdc + best-practices.mdc)
│ Writes: updated content.json
│ assets/change-log.md (before/after per block path)
│
├─ Phase 4: Review & Fix ──────── sub-agent loads review-guide-pr.mdc
│ │ + ../shared/critical-rules.md
│ Writes: fixed content.json + assets/review-report.md
│
└─ Phase 5: Validate ──────────── orchestrator
Byte-level diff vs snapshot for unchanged paths
JSON validity, ID uniqueness, IDREF resolution
Pathfinder CLI: validate --package {guide_dir}
On failure: restore from snapshot, mark run failed
Inputs
- Required:
guide_dir— path to a directory containingcontent.json. - Required:
change_request— free-text description of the change ("add a Loki section after the Prometheus one", "swap data source X for Y", "addlazyRender: trueto the step at blocks[3].blocks[2]") OR a structured change spec (see change-request-schema.md). - Optional:
target_path— explicit block path (e.g.,blocks[3].blocks[2]) when the change_request is ambiguous about location. Phase 2 will use this if provided.
If the user gives only guide_dir, ask for the change_request. Free-text is acceptable.
Critical Rules
Read ../shared/critical-rules.md for the canonical 21 critical rules. Phase 2, Phase 3, and Phase 4 sub-agents must cite rule numbers when proposing or reviewing changes. The shared file forwards to ../../../AGENTS.md — that is the authoritative list.
Safety Invariants
Read safety-invariants.md — five inviolable rules the orchestrator and Phase 5 enforce. Violating any one fails the run and restores from snapshot.
Generated Files
The deliverable is the updated content.json. Everything in assets/ is skill-internal.
{guide_dir}/
content.json ← UPDATED (was modified by Phase 3)
manifest.json ← UPDATED only if change_request affects manifest fields
assets/
manifest.yaml ← skill memory (input hash, change request, last_update_at)
guide-structure.json ← id → path map (Phase 1)
change-plan.md ← user-approved plan (Phase 2)
change-log.md ← per-block before/after (Phase 3)
review-report.md ← review findings + fixes (Phase 4)
snapshots/
content.json.before ← pre-write snapshot (Phase 1)
Frontmatter disclaimer
Every generated markdown file in assets/ must start with:
---
disclaimer: Auto-generated by update-guide skill. Do not edit manually.
notice: To regenerate, re-run the skill with the same change request.
input_sha256: {hex digest}
guide_id: {id from content.json}
change_request: "{the change request, truncated to 100 chars}"
---
Manifest file
After Phase 5, write {guide_dir}/assets/manifest.yaml:
# Auto-generated by update-guide skill. Do not edit manually.
schema_version: 1
skill_name: "update-guide"
generated_at: "{ISO 8601 timestamp}"
input_sha256: "{hex digest — see below}"
guide:
id: "{guide id from content.json}"
change:
request: "{the full change request}"
paths_added: ["blocks[N]", ...]
paths_edited: ["blocks[M]", ...]
paths_removed: ["blocks[P]", ...]
validation:
cli_validate_passed: {true|false}
byte_level_diff_clean: {true|false}
files:
change_plan: "assets/change-plan.md"
change_log: "assets/change-log.md"
review_report: "assets/review-report.md"
snapshot: "assets/snapshots/content.json.before"
Compute input_sha256 by hashing the pair (content.json contents, change_request):
cat {guide_dir}/content.json <(printf "\n---\n%s" "{change_request}") | shasum -a 256 | awk '{print $1}'
This means re-running the same change against the same starting content.json matches the prior run and triggers warm-start. If either the content or the request differs, a fresh plan is generated.
Phase 0: Check for Prior Run (Orchestrator)
Before starting the update pipeline, check whether this update has already been applied.
- Check whether
{guide_dir}/assets/manifest.yamlexists. - If it does: read the manifest, extract
input_sha256andchange.request. - Re-hash the current pair:
cat content.json <(printf "\n---\n%s" "{change_request}") | shasum -a 256 | awk '{print $1}'. - Compare hashes:
- Match → this exact change was already applied. Tell the user (cite
change.requestandgenerated_at) and offer three options: (a) view the existingchange-log.md, (b) re-run the change against the currentcontent.json(treating it as a fresh request — drops the prior manifest), (c) abort. - Mismatch → this is a different change request or the file has been edited since. Move the prior
manifest.yaml,change-plan.md,change-log.md,review-report.mdtoassets/history/{prior_generated_at}/. Proceed with the fresh run.
- Match → this exact change was already applied. Tell the user (cite
- If
manifest.yamldoes not exist: fresh run — proceed to Phase 1.
Phase 1: Acquire & Snapshot (Orchestrator)
Verify
{guide_dir}/content.jsonexists and is valid JSON. If not, report the parse error and stop.Create
{guide_dir}/assets/snapshots/and copycontent.jsontoassets/snapshots/content.json.before(raw bytes — no parsing, no re-serialisation).Read
manifest.jsonif present (Phase 2 may reference it for context).Walk the block tree and produce
assets/guide-structure.json— a map from every block id (and section id, input variable name) to its path. Shape:{ "ids": { "open-dashboards": "blocks[2].blocks[0]", "configure-prometheus": "blocks[3]" }, "section_ids": { "navigation": "blocks[2]" }, "input_variables": { "datasourceName": "blocks[1]" }, "tree_summary": { "total_blocks": 42, "total_sections": 5, "total_interactive_steps": 18 } }Compute
input_sha256(see above) and stash it for Phase 5.
Phase 2: Plan the Change (Sub-agent)
Dispatch a sub-agent (Plan subagent type) with the following brief:
You are the **Plan the Change** phase of the update-guide skill. Read the following files in order, then produce a change plan.
**Read (in order):**
1. [.cursor/authoring-guide.mdc](../../../.cursor/authoring-guide.mdc) — block types, action types, requirements, best practices
2. [.cursor/best-practices.mdc](../../../.cursor/best-practices.mdc) — decision trees for blocks/actions/requirements/objectives; code smells
3. [../shared/critical-rules.md](../shared/critical-rules.md) — the 21 critical rules (cited by number)
4. [./change-request-schema.md](./change-request-schema.md) — structured change-request shapes (for context, even if the request is free-text)
5. {guide_dir}/assets/guide-structure.json — the id → path map
6. {guide_dir}/content.json — the original guide (for context)
**Resolve the change_request `{change_request}` to a concrete plan.**
For free-text requests, identify:
- **What** is changing (add a block / edit a block / remove a block / replace a section / add a requirement)
- **Where** it goes (use `target_path` if provided; otherwise infer from the request and from `guide-structure.json`)
- **Why** (so Phase 3 can write good prose for any new blocks)
For structured requests, validate against `change-request-schema.md` and surface any malformed fields.
**Output: a structured markdown plan at `{guide_dir}/assets/change-plan.md`** with the standard frontmatter disclaimer and these sections:
```markdown
# Change Plan
## Request
{verbatim change_request}
## Edits
For each edit:
- **Action**: add | edit | remove | replace
- **Path**: blocks[N].blocks[M] (existing path for edit/remove/replace; insertion target + position for add)
- **Block type**: markdown | interactive | section | ...
- **What it does**: one-sentence description
- **Why this location**: one-sentence rationale citing existing structure
## New Selectors To Verify
Any new `reftarget` selectors the user needs to confirm against the live Grafana UI before the change is applied. List one per line with the action context.
## New Requirements / Objectives
If the plan adds requirements or objectives, list them with their rationale. Cite the relevant requirement type from `docs/requirements-reference.md` (mentally — don't open it).
## IDREFs Affected
If any change touches:
- A section that other sections depend on via `section-completed:<id>`
- An `input` block whose variable is referenced by `var-<name>` or `{{<name>}}`
…list every referrer so Phase 3 knows what to revalidate.
## Risks
Anything the plan author is uncertain about. Examples:
- Selector stability ("this `data-testid` may have changed in recent Grafana")
- Section placement ("the new Loki section may be better after step 5 rather than at the end")
- Rule conflicts ("this addition may double the section's step count past 8")
```
**Do not modify content.json.** Stop after writing the plan. The orchestrator will present it to the user for confirmation.
After the sub-agent writes the plan, the orchestrator presents the plan to the user and asks for confirmation before proceeding to Phase 3. If the user requests revisions, re-dispatch Phase 2 with the same brief plus the user's feedback as additional context.
This is a hard checkpoint. Do not run Phase 3 until the user explicitly approves the plan.
Phase 3: Apply the Change (Orchestrator + Sub-agents)
After plan approval:
Re-read
content.json(in case the user has tweaked since Phase 1 — if so, re-snapshot and warn).For each edit in the plan:
- Add: insert the block at the specified path.
- If the block is a simple structural insertion (
markdown,noop), the orchestrator generates the JSON directly using the plan's "What it does" / "Why this location" prose. - If the block is interactive content that requires authoring expertise (a full
section, aguidedblock with multiple steps, aquiz), dispatch a per-section sub-agent (Plan subagent type) with the brief below.
- If the block is a simple structural insertion (
- Edit: apply the field-level changes from the plan.
- Remove: delete the block.
- Replace: do a paired remove + add at the same path.
- Add: insert the block at the specified path.
After every edit, write
content.jsonwith the same indentation style as the original (detect fromassets/snapshots/content.json.before— usually 2-space).Write
assets/change-log.mdwith per-block before/after blocks. Frontmatter as above. Shape:## Edit 1 — add at `blocks[5]` **Before**: (none — new block) **After**: ```json { "type": "markdown", "content": "..." }Edit 2 — edit
blocks[3].blocks[2]Before:
{ "type": "interactive", "action": "highlight", "reftarget": "..." }After:
{ "type": "interactive", "action": "highlight", "reftarget": "...", "lazyRender": true }If
manifest.jsonis affected by the change request (title, description, targeting, tier, dependencies, milestones), update it. Otherwise leave it untouched.
Per-section sub-agent brief
You are generating one section block for an in-flight update to an existing Pathfinder guide. Read these files, then produce ONE section JSON object.
**Read (in order):**
1. [.cursor/authoring-guide.mdc](../../../.cursor/authoring-guide.mdc)
2. [.cursor/best-practices.mdc](../../../.cursor/best-practices.mdc)
3. [../shared/critical-rules.md](../shared/critical-rules.md)
4. {guide_dir}/assets/change-plan.md — the approved plan (find your section's entry under Edits)
5. {guide_dir}/assets/guide-structure.json — for ID uniqueness checks
**Section brief**: {paste the plan's "Action / Path / Block type / What it does / Why this location" for this section}
**Constraints:**
- Section id MUST be unique (check against `guide-structure.json` `ids` and `section_ids`)
- Follow all 21 critical rules
- Step budget: 3-8 interactive steps for a typical section
- Include section bookends (intro markdown immediately before the section, summary immediately after) unless the section has only 1-2 blocks. Do not put “You'll …” intros inside the section.
- Cite the rule numbers you considered in a comment block above the JSON if helpful (the orchestrator will strip the comment)
**Output**: ONE valid JSON object for the section block. No prose. No markdown fences. Just the JSON.
(This sub-agent pattern mirrors autogen-guide/SKILL.md Phase 3.)
Phase 4: Review & Fix (Sub-agent)
Dispatch a sub-agent (Plan subagent type) with the following brief:
You are the **Review & Fix** phase of the update-guide skill. Read these files, then review the changed blocks AND their immediate neighbours.
**Read (in order):**
1. [.cursor/review-guide-pr.mdc](../../../.cursor/review-guide-pr.mdc) — the review protocol
2. [../shared/critical-rules.md](../shared/critical-rules.md) — the 21 critical rules
3. {guide_dir}/assets/change-log.md — what was changed
4. {guide_dir}/content.json — the current state of the guide (post-edit)
**Scope**: every block path listed in `change-log.md` AND its siblings + parent section.
**Apply** every blocking check from review-guide-pr.mdc §1, every structural check from §2.4-2.5, and the §4.6 legacy `?doc=` check. Auto-fix findings in-place (write the updated `content.json`) unless the fix would change the user-facing intent of the change.
**Output**: `{guide_dir}/assets/review-report.md` with the standard frontmatter disclaimer and these sections:
```markdown
# Review Report
## Summary
- Findings: N (auto-fixed: N, requires user attention: N)
- Scope: {list of block paths reviewed}
## Auto-fixed
For each: path, rule number, what changed.
## Requires user attention
For each: path, rule number, why it can't be auto-fixed.
```
**Do not touch blocks outside the scope. Do not regenerate prose — only fix concrete rule violations.**
Phase 5: Validate (Orchestrator)
After Phase 4:
Byte-level diff vs snapshot. Parse both
content.jsonandassets/snapshots/content.json.before. For every block path NOT inchange-log.md, the block must be byte-identical between the two. If any unchanged path differs, this is a safety invariant violation — restore from snapshot, writeassets/review-report.mdwith a## CRITICAL: safety invariant violatedsection, and stop.JSON validity. Parse
content.jsonwith strict JSON. On parse error, restore from snapshot and stop.ID uniqueness. Walk the updated tree and confirm every block id is unique. On collision, restore and stop.
IDREF resolution. For every
section-completed:<id>requirement and everyvar-<name>requirement, confirm the target still exists. For every{{<name>}}in markdown content, confirm aninputblock with that variable name exists earlier in the guide. On unresolved reference, restore and stop.Pathfinder CLI validate. Run:
node {pathfinder-app}/dist/cli/cli/index.js validate --package {guide_dir}If the CLI is not available, surface this as an incomplete-validation warning rather than a failure (skills cannot assume the user has the CLI built). If the CLI returns non-zero, restore from snapshot and stop.
If all checks pass: write/update
{guide_dir}/assets/manifest.yamlwith the schema documented above. Surface a one-paragraph summary to the user with: paths added/edited/removed, validation results, and the path toaudit-report.mdif the user wants a deeper review afterwards.
If any check fails, the orchestrator MUST:
- Restore
content.jsonfromassets/snapshots/content.json.before(byte-level copy). - Restore
manifest.jsonif it was modified. - Write
assets/review-report.mdwith a## CRITICAL: validation failedsection explaining which check failed and which snapshot was restored. - Mark the run as failed in
assets/manifest.yaml(validation.cli_validate_passed: false) and STOP.
When to use vs. skip
Use update-guide when:
- An existing guide needs a non-trivial change that touches multiple blocks or requirements.
- A change request must be reviewed and validated before merging (e.g., adding
lazyRenderretrofits). - You want a paper trail of what changed (
change-plan.md,change-log.md).
Skip update-guide and hand-edit when:
- The change is a 1-line content tweak (typo, prose clarification, tooltip rewording).
- The guide doesn't yet exist — use
autogen-guideinstead. - The change is a full rewrite — re-run
autogen-guidefrom the latest source.
See Also
- autogen-guide/SKILL.md — generate a guide from source code (for new guides)
- audit-guide/SKILL.md — audit an existing guide (run before/after this skill for a paper trail)
- migrate-guide/SKILL.md — migrate to the package format
- ../skill-memory.md — shared skill memory convention