Llmdoc Update
Documentsllmdoc-updateLlmdoc Update is an Agent Skill for documents published in the TokenRollAI/llmdoc repository on GitHub: a SKILL.md instruction file an AI agent can load to do this task.
Codex-native entry skill for keeping tracked llmdoc docs current with the repository using commit-based change detection. Use this when you want the /llmdoc:update workflow in Codex.
How to use this skill
Bring this guide into your coding agent with a prompt tailored to the tool you use.
- Open your project in Codex.
- Copy and paste the prompt below.
- Review files and risks before approving any action.
Inspect the Agent Skill at https://github.com/TokenRollAI/llmdoc/blob/HEAD/skills/llmdoc-update/SKILL.md and all supporting files. Report provenance, permissions, scripts, dependencies, and security risks. Propose an exact installation into .agents/skills/llmdoc-update, but wait for my approval before writing files or running scripts.
Copying this prompt does not install or run the skill. Review third-party files before use.
llmdoc-update
This skill is the Codex-native equivalent of /llmdoc:update.
The update target is tracked llmdoc/, not .llmdoc-tmp/. Stable docs should stay consistent with the current repository and remain smaller than the source code or provide architectural explanation that source search does not.
Change detection is commit-based: it is anchored on a durable watermark (llmdoc/state/sync.md) recording the last source commit already reflected in llmdoc/, not on the working tree or the date. Uncommitted changes are an additional input; they never move the watermark.
Use it when:
- a task changed project knowledge, architecture understanding, or workflow guidance
- a useful mistake or missing-doc lesson should be preserved
- you want a command-like Codex entrypoint for updating llmdoc
Read the batch flags from $ARGUMENTS / the user message:
[summary] [--range A..B ...] [--commits SHA,SHA ...] [--since REF] [--from SHA] [--working-tree-only] [--include-default]
Invariants, design rationale, and verified git semantics: llmdoc/architecture/update-orchestration.md.
Before editing stable docs:
- read
llmdoc/index.md,llmdoc/startup.mdand the MUST docs it lists - proactively read relevant
llmdoc/guides/andllmdoc/memory/reflections/ - read
skills/llmdoc/references/lessons-learned.mdfor the active-memory archive threshold - check relevant
.llmdoc-tmp/investigations/reports only as local temporary evidence (validate their git revision, resolved range, scope, gaps) - align with the user before non-trivial edits
Sync State
llmdoc/state/sync.md is a tracked, machine-managed markdown file holding one load-bearing field, watermark-commit (the full commit SHA, whatever hash the repo uses — SHA-1 or SHA-256). It is not project knowledge: never index it, never add it to startup.md/must/, never count it as active memory. Read the watermark with a single anchored line:
W=$(awk -F': ' '/^- watermark-commit:/{print $2}' llmdoc/state/sync.md 2>/dev/null | tr -d '[:space:]')
recorder is the only writer of sync.md, and only advances it as the terminal step of a successful update.
Change Detection (commit range)
Run all git plumbing without set -e (capture each exit code) so a 128 degrades instead of aborting. The resolution ladder order is an invariant — never reorder:
# 1. Capability probe (gates the whole ladder — steps 2-5 assume a git work tree)
[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = true ] || {
echo "non-git: watermark inactive" # STOP HERE: use legacy working-tree + staged + summary detection;
return 0 2>/dev/null || exit 0 # do NOT run steps 2-5, do NOT read or advance the watermark
}
SHALLOW=$(git rev-parse --is-shallow-repository)
H=$(git rev-parse HEAD) # capture once
# 2. Read watermark
W=$(awk -F': ' '/^- watermark-commit:/{print $2}' llmdoc/state/sync.md 2>/dev/null | tr -d '[:space:]')
# 3-4. Resolve RANGE_BASE with EXPLICIT branching. Existence gates reachability: never run merge-base
# on an empty/missing $W — it would fatal-128, not skip. Each branch is terminal.
if [ -z "$W" ]; then
echo "watermark empty/missing → first-run: base=HEAD (no backfill unless --from/--since), force ≥ analysis, seed at HEAD on success"
RANGE_BASE=$H
elif ! git rev-parse --verify --quiet "$W^{commit}" >/dev/null; then
echo "watermark object missing (GC'd / below shallow boundary) → first-run baseline=HEAD, warn, do NOT advance"
# if $SHALLOW = true, suggest: git fetch --unshallow. (rev-parse --verify --quiet exits 1 cleanly; cat-file -e "$W^{commit}" would fatal 128 on the peel.)
RANGE_BASE=$H
elif git merge-base --is-ancestor "$W" "$H"; then
RANGE_BASE=$W # watermark valid
elif git merge-base --is-ancestor "$H" "$W"; then
echo "HEAD BEHIND watermark → REFUSE (reverse W..HEAD would list future files as deletions and strip docs); working-tree input only, do NOT advance"
RANGE_BASE=$H
else
RANGE_BASE=$(git merge-base "$W" "$H") # true divergence (rebase/squash-merge); force ≥ analysis
fi
# 5. Net change set (rename-aware, NUL-safe). In -z mode a rename/copy record is STATUS\0OLD\0NEW\0
# (3 fields; STATUS is R<score>/C<score>); a normal record is STATUS\0PATH\0.
git diff --name-status -M -C -z "$RANGE_BASE" "$H"
Batch flags (if any of --range/--commits/--since/--from is given, the default RANGE_BASE..HEAD is NOT added unless --include-default). Each batch resolves to a set of changed paths: parse the --name-status -z records — drop the status column; in -z mode a record is STATUS\0PATH\0, but a rename/copy record (status R<score>/C<score>) is STATUS\0OLD\0NEW\0, so read TWO path tokens when the status starts with R or C (take both) and one otherwise, or the parser desyncs. Union all batch path-sets with the working-tree set, deduplicated (do not sort -u raw NUL/status records):
--range A..B(repeatable):git diff --name-status -M -C -z A B.--commits SHA,…: per commitgit diff --name-status -M -C -z <sha>^ <sha>; reject merge commits (parent count > 1 → ask the user to passA..B); root commit diffs against the empty treegit hash-object -t tree /dev/null(4b825dc642cb6eb9a060e54bf8d69288fbee4904).--since REF|date: for a ref,<ref>..HEAD; for a date, resolve a boundary commitB=$(git rev-list -1 --before=<date> HEAD)and diffB..HEADwith the samegit diff --name-status -M -C -zas every other branch. IfBis empty (no commit predates<date>, so the whole history is in range), diff against the empty treegit hash-object -t tree /dev/nullinstead ofB..HEAD(which would be..HEADand fatal). Do NOTgit log --name-only, which yields a statusless, blank-line-polluted shape that will not union cleanly.--from SHA: one-off start override for this run only; does not touchsync.md.--working-tree-only: skip the committed range entirely; document only uncommitted changes; never advance the watermark.
Always fold in, as an ADDITIONAL input tagged worktree (never advances the watermark): git diff --name-only HEAD (every tracked path whose on-disk content differs from HEAD — staged and unstaged) ∪ git ls-files --others --exclude-standard (untracked). git diff --name-only HEAD already covers staged changes, so a separate --cached diff is redundant.
Empty range (already synced) — applies ONLY when the watermark was VALID (the RANGE_BASE=$W branch) and W == HEAD: if there are also no working-tree changes and no batch flags, report already up to date through <Hshort> and exit without touching docs, the index, or the watermark. The degraded branches that force RANGE_BASE=HEAD (empty/missing watermark → first-run seed; HEAD-behind → refuse) also produce an empty range but are NOT "already synced" — each is handled by its own branch outcome above, not by this terminal.
Doc-commit loop-breaker: if git diff --name-only "$RANGE_BASE".."$H" -- ':(exclude)llmdoc/**' is empty (range non-empty but doc-only), fast-forward the watermark to HEAD with zero doc work. Always exclude the sync file and .llmdoc-tmp/ from every diff.
Content selection: recorder reads committed-batch file content at the BATCH TIP (git show <tip>:<path>), never from HEAD/disk, except for the uncommitted working-tree set (read from disk, which wins for any currently-dirty path).
Mode Selection
The trigger is range size × authorship × risk (not context freshness):
fast: small range (≤ ~3 commits), self-authored, impacted docs nameable.--working-tree-onlydefaults here. Use the task summary, diff, targeted checks, and any still-valid scratch reports.analysis: ~4–15 commits, OR any non-self-authored commit, OR multiple clusters, OR a recovered/derived/first-run baseline. One focused evidence pass persisted under.llmdoc-tmp/investigations/.full: > ~15 commits, multi-batch backfill, history-rewrite recovery, disputed facts, or reflection-heavy failures — separate investigation, reflection, and recording roles.
Hard floors (force ≥ analysis): a merge-base-recovered baseline, a derived/first-run baseline, or any non-self-authored commit. Backfill blast-radius cap: a first-run/--since range beyond ~20 commits or ~50 files forces full and explicit user confirmation.
Self-authored test: a commit is self-authored when its author email (git log -1 --format=%ae <sha>) equals the current git config user.email. If the identity cannot be determined (e.g., a subagent with no git identity, or user.email unset), treat commits as non-self-authored — the conservative side that forces ≥ analysis.
Workflow
- Rebuild task context (index, startup, MUST docs, relevant guides + reflections; note any
$ARGUMENTSsummary). - Resolve sync state and compute the change set (run the ladder; parse batch flags; union with the working-tree set; apply the loop-breaker; handle degraded cases — non-git, shallow, first-run, orphaned, diverged, HEAD-behind — without fabricating a watermark advance).
- Select the mode from range size × authorship × risk; honor the hard floors and backfill cap.
- Investigate only as needed, seeded with the resolved net-diff path list; scratch reports record the resolved
RANGE_BASE..Hrange. - Reflect only when there is a workflow failure, repeated mistake, missing signal, or durable process lesson. Do not force a reflection for routine
fastupdates. - Update stable llmdoc docs against the batch-tip state: update only impacted docs, correct stale claims, split aggressively, reconcile
llmdoc/memory/doc-gaps.md. - Run the active-memory archive check (count files under
llmdoc/memory/excludinglessons-learned.md,doc-gaps.md,archive/;llmdoc/state/is not counted). If > 5, followskills/llmdoc/references/lessons-learned.md. - Synchronize
llmdoc/index.md. Do not index.llmdoc-tmp/, and do not indexllmdoc/state/sync.mdas knowledge. - Advance the watermark (recorder-owned terminal step). Safe-to-advance gate — ALL must hold: the update completed successfully and consumed a committed range; HEAD is attached (
git symbolic-ref -q HEADsucceeds); and no git operation is in progress — test by whether the resolved path EXISTS on disk (git rev-parse --git-pathalways prints a path and exits 0 regardless of existence, so check with[ -f ]/[ -d ]), none of[ -f "$(git rev-parse --git-path MERGE_HEAD)" ],CHERRY_PICK_HEAD,REVERT_HEAD,[ -d "$(git rev-parse --git-path rebase-merge)" ],rebase-applymay exist. If the gate holds, advancewatermark-committo the capturedH(or the highest unbroken-prefix tip). Rewrite ONLY these fields, keeping the exact- watermark-commit:line prefix (the reader anchors on it — do not reformat):watermark-commit(new full commit SHA),watermark-subject(git log -1 --format=%s <new-sha>),updated-at(ISO-8601 UTC,date -u +%Y-%m-%dT%H:%M:%SZ),updated-by(/llmdoc:update). NEVER advance on a--working-tree-onlyrun, a failed/partial run, a HEAD-behind-watermark run, or when the safe-to-advance gate fails. - Report the mode used, resolved range(s)/batches and commit count, old → new watermark (or why it did not move), scratch/reflection paths, the archive action, and the stable docs that changed.
At the end of a non-trivial task, proactively consider whether the user should be prompted to run this workflow.