Install
$ agentstack add skill-nodewarrior-spine-spine-update ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Spine Update — Resume and Enrich Existing Docs
Update existing Spine Architecture docs with new context from continued work sessions. Appends timestamped update sections — never overwrites or deletes existing content.
Vault Path Resolution
Resolve the vault path using this config chain:
$SPINE_VAULT_PATHenvironment variable~/.spine/config.json→ read thevaultPathfield- Default:
~/Documents/SpineVault/
If the vault doesn't exist, tell the user to run /spine-init first.
Detect Current Repo
basename "$(git remote get-url origin 2>/dev/null)" .git
Fall back to the current directory name if no git remote. If {vault}/{repo}/ doesn't exist, tell the user this repo isn't tracked by Spine yet — suggest /spine-init or /spine-capture to set it up.
Mode Selection
If $ARGUMENTS is provided (not empty and not whitespace-only): → Targeted Mode — proceed to "Targeted Mode" section below
If $ARGUMENTS is empty or not provided: → Auto-Detect Mode — proceed to "Auto-Detect Mode" section below
Targeted Mode (/spine-update )
Step 1: Resolve Target
Match $ARGUMENTS against docs in {vault}/{repo}/ using this precedence (first match wins):
- Exact filename match (case-insensitive, with or without
.mdextension) - Exact feature folder name match → resolves to the spine note in that folder (e.g.,
/spine-update authmatches{vault}/{repo}/auth/auth.md) - Substring match on doc title (from
titlefrontmatter field) - Substring match on filename
Rules:
- Case-insensitive throughout
- If exactly one match at any precedence level → auto-select that doc
- If multiple matches at the same precedence level → show a numbered pick list and let the user choose
- If no match at any level → tell user "No matching doc found for '{name}'. Did you mean to create a new doc? Try
/spine-capture."
Step 2: Read Existing Doc
Load the full content of the resolved doc. Extract:
- Staleness date: Read
last_updatedfrom frontmatter. If not present, fall back todatefield. If neither exists, treat as unknown — skip git-driven context in Step 3.
- Referenced files: Parse the
**Files changed:**section as a markdown unordered list (one file path per-line). If the section is missing or unparseable, fall back to listing all non-.mdfiles in the doc's parent feature folder:
``bash find {vault}/{repo}/{feature}/ -type f ! -name "*.md" 2>/dev/null ` Note: This fallback is rarely needed — most docs created by /spine-capture` include the section.
- Existing wikilinks: Scan for the
## See Alsosection and collect all[[...]]wikilinks already present.
Step 3: Gather Update Context
Merge two sources of context:
Git-driven context: If a staleness date was found in Step 2:
git log --oneline --since="{staleness_date}" -- {file1} {file2} ...
For commits found, read the diffs to understand what changed:
git diff {hash}~1 {hash} -- {files}
If no staleness date was available, skip git context entirely.
Session-driven context: Summarize the current conversation's context that is relevant to this doc:
- Decisions made during this session
- Trade-offs discussed
- Work completed or planned
- Changes to the approach described in the doc
If no conversation context is relevant to this doc, omit the session block from the draft.
Empty context guard: If both git context and session context are empty, inform the user: "No new commits or session context to incorporate into '{doc name}'. Nothing to update." Exit without presenting a draft. Emit output contract with status: no_candidates.
Step 4: Draft Append Section
Draft an update section to append to the existing doc:
````markdown ---
Update — {YYYY-MM-DD HH:MM}
> [!note] {One-line summary of what changed} > {2-3 sentence description combining git changes and session reasoning}
Context: {Detailed explanation of what changed and why — include code snippets where they add value}
New files: {list any files introduced since last update, or omit this line entirely if none}
````
Merge rules — follow these strictly:
- Do NOT create a new
## See Alsosection in the update block. Instead, note any new[[wikilinks]]to be inserted into the existing## See Alsosection at the bottom of the doc. If no## See Alsosection exists yet, one will be created at the very end of the doc in Step 6. - Do NOT add a
**Files changed:**block in the update section. The original**Files changed:**in the doc header is the canonical list and stays unchanged. Only include**New files:**if the work introduced source files not in the original list. - Update header includes time (
HH:MM) to disambiguate multiple updates on the same calendar day.
Step 5: Present for Review
Show the user:
- The existing doc content (first 30 lines, then
...if the doc is longer) - The proposed append section in full
- Any new wikilinks that will be added to
See Also
Ask: (S)ave, (E)dit, or S(k)ip?
- Save → proceed to Step 6
- Edit → show the full draft, let the user request specific changes, apply them, then re-present with the same Save/Edit/Skip choice
- Skip → exit without saving. Emit output contract with
status: skipped
Step 6: Save
Before writing: Record the file's mtime and size when you first read it (Step 2). Now, before writing, re-check both values. If either has changed, abort with: "File was modified by another process during this update. Please try /spine-update again." Emit output contract with status: error and recovery_hint: "File conflict — retry". This conflict guard applies to every file write in this step (doc and spine note).
After conflict guard passes:
- Append the update section to the end of the existing doc file (insert the update before any existing
## See Alsosection — the update goes between the last content section and See Also) - Merge wikilinks — insert any new
[[wikilinks]]into the existing## See Alsosection. If no## See Alsosection exists, create one at the very end of the doc after the appended update - Update frontmatter — add or update
last_updated: {YYYY-MM-DD}in the doc's YAML frontmatter. Preserve the originaldatefield unchanged - Spine note update (conditional):
- If the updated doc is NOT a spine note (i.e., it is a leaf doc inside a feature folder): check if new wikilinks were added that the spine note should reference. If so, update the spine note. Set
spine_updated: truein output contract - If the updated doc IS a spine note: skip this step entirely — no circular self-reference. Set
spine_updated: false
- Curator log — ensure
{vault}/.spine/curator-log.mdexists (create fromtemplates/curator-log.mdif missing). Prepend this entry (newest at top):
```markdown ## {YYYY-MM-DD} — Update
- Updated:
{filename}— {N} commits incorporated
```
- Confirm — tell the user the doc is updated and where to find it in Obsidian
Auto-Detect Mode (/spine-update no args)
Step 1: Scan for Stale Docs
For each .md file in {vault}/{repo}/ and its subfolders:
- Read
last_updatedfrom frontmatter. If not present, fall back todate. If neither field exists, skip this doc (cannot determine staleness) - Parse the
**Files changed:**section as a markdown unordered list (one path per-line). If missing, use all non-.mdfiles in the doc's parent folder as the file list - For each referenced file, count commits since the staleness date:
``bash git log --oneline --since="{last_updated or date}" -- {filepath} ``
- Sum the commit counts across all referenced files
- Flag docs with 3 or more total commits since the staleness date
Step 2: Rank and Cap Results
Sort flagged docs by total commit count, descending (most stale first). Cap the list at 10 results.
Step 3: Present Pick List
If stale docs were found:
Spine: {N} docs may need updating:
[1] {doc title} ({feature}/) — {N} commits since last updated
[2] {doc title} ({feature}/) — {N} commits since last updated
[3] {doc title} ({feature}/) — {N} commits since last updated
Pick a number to update, or (s)kip all:
If more than 10 stale docs exist, add: (showing top 10 of {total} stale docs)
Step 4: User Picks
If the user picks a number → load that doc and enter Targeted Mode, Step 2 (Read Existing Doc) onward. The target is already resolved from the pick list — skip Step 1.
If the user skips → emit output contract with status: skipped.
Step 5: No Stale Docs Found
If no docs meet the 3-commit threshold:
Spine: All docs up to date. Nothing to update.
Emit output contract with status: no_candidates.
Output Contract
After completing an update (or determining there is nothing to update), emit a structured observation block:
spine_update_result:
status: success | skipped | no_candidates | error
summary: "Updated 'Plan - Migration Strategy' with 7 commits of context"
updated:
- { file: "Plan - Migration Strategy.md", feature: "auth", commits_incorporated: 7, spine_updated: true }
next_actions:
- { action: "review in Obsidian", path: "{vault}/repo/auth/Plan - Migration Strategy.md" }
recovery_hint: null
Status values:
success— doc updated and savedskipped— user chose not to save (declined or skipped in review)no_candidates— auto-detect found no stale docs, or empty context guard triggered in targeted modeerror— write failure, vault missing, conflict guard triggered — includerecovery_hint
spine_updated field: true when new wikilinks were added to the corresponding spine note (hub). false when no spine note changes were needed, or when the updated doc itself is a spine note.
Cross-skill: All Spine skills use last_updated (falling back to date) for staleness queries. /spine-health stale doc findings naturally align with auto-detect mode. No handoff file needed — both skills scan fresh on demand.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Nodewarrior
- Source: Nodewarrior/spine
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.