Wiki update — how it works
This page documents the built-in wiki-update job: what it does, what it
picks up, and what it does not. It is the operational companion to
wiki-update-prompt.md (which is the procedure the agent follows; this
page is the mechanism around it).
1. Overview
The wiki is a set of hand-structured Markdown pages in docs/wiki/ with a
small YAML front matter: title, sources: (the code paths a page is
responsible for), and verified_at (last time its prose was checked against
code).
The wiki-update job is a diff-driven refresh: it diffs the git history
since the wiki's last recorded commit, works out which pages are affected,
and re-runs a single agent whose goal is the procedure in
docs/wiki/wiki-update-prompt.md. After a successful run, a mechanical
(not LLM) post-step writes a review diff to docs/wiki/history/ and advances
docs/wiki/.wiki-state.json to the current HEAD.
Short answer to "does it pick up code changes and new features":
- Code changes — yes, but only committed ones. The agent's input is
git diff <last_commit>..HEAD. It maps changed paths to wiki pages via each page'ssources:front matter and rewrites only the intersecting pages. - New features — yes, three ways: new/changed tools and routes regenerate
the AUTO tables in
tools.md/web-ui-api.md; user-facing behavior (UI tabs, endpoints, settings, shortcuts, workflows) is caught by the "help-sync" pass that editstemplates/help.html. - Uncommitted work — no. Working-tree changes are captured in the diff artifact for review only; the agent does not edit wiki/help pages for them.
- Brand-new subsystems — only if a page already lists them. The job edits
existing pages whose
sources:intersect the diff; it does not create new wiki pages.
2. Components
| File | Role |
|---|---|
model_harness/workflow/wiki_job.py |
Workflow definition + default weekly schedule + the mechanical write_update_diff() post-step. |
docs/wiki/wiki-update-prompt.md |
Source of truth for the procedure (the numbered goal the agent runs). |
docs/wiki/.wiki-state.json |
{last_commit, updated} — the diff base and refresh date. |
docs/wiki/*.md |
The wiki pages (front matter: title, sources, verified_at). |
docs/wiki/history/*.diff |
Per-run review diffs (committed drift + working-tree changes). |
scripts/wiki_tables.py |
Regenerates the AUTO tables in tools.md and web-ui-api.md. |
templates/help.html |
Hand-authored in-app help; updated by the help-sync pass. |
templates/wiki.html |
Reader shell for /wiki and /wiki/<slug>. |
model_harness/web/routes_pages.py |
/wiki routes, rendering, changed-page detection, search. |
model_harness/web/routes_scheduler.py |
Jobs page: schedules, manual runs, diff history, run-cost log. |
model_harness/workflow/scheduler.py |
Engine-side completion hook that calls write_update_diff(). |
3. Registration and scheduling
register_wiki_update_job(scheduler) runs at harness construction and is
idempotent:
- Registers a workflow
wiki-update(name "Wiki update") with a single AGENT step (agent_type = "react"), whosegoal_templateis the text ofwiki-update-prompt.mdafter its leading---marker. Step timeout 1800 s; workflow timeout 45 min. - Seeds a default INTERVAL schedule
wiki-update-weekly(7 days), withlast_run = nowso the first automatic run fires one full week after boot. Existing user state (retimed/disabled/last_run) on disk is preserved, never clobbered.
4. Triggering a run
Two ways, both via the Jobs/Workflows page (routes_scheduler.py):
- Scheduled — the engine's interval trigger fires
wiki-update-weekly. - Manual —
POST /api/schedules/<sid>/runruns the workflow immediately (the "run now" button). It records a per-run cost row (job_runs) and, onstatus == "completed", invokes the diff writer. Failed/cancelled runs leave no diff artifact.
The manual-run endpoint also special-cases profile-loop (redirects to the
cockpit button) and profile-optimize (proposal/eval post-steps), but
wiki-update only needs the diff post-step.
5. The agent procedure (the 6 steps)
From wiki-update-prompt.md (the goal the react agent executes):
- Read
docs/wiki/.wiki-state.jsonforlast_commit; rungit diff --stat <last_commit>..HEAD(fall back togit log -5 --onelineif the file/sha is missing). - For each wiki page, compare the changed paths against the page's
sources:front matter. Only edit pages whose sources intersect the diff — never rewrite unaffected pages. - For each affected page: read the current code at the changed paths, update
prose to match reality, set
verified_at:to today's date. Keep pages under ~250 lines; keep mermaid diagrams valid (≤15 nodes, no double-quoted labels). - If the diff touched
model_harness/tools/or anyroutes_*.py/app.py, runvenv\Scripts\python.exe scripts\wiki_tables.pyto regenerate the AUTO tables. - Help-sync pass: review the incoming changes for user-facing behavior or
features (new/changed UI tabs, API endpoints, settings, shortcuts,
workflows). If any exist, update
templates/help.html— it is hand-authored with a<nav class="help-toc">; match its style/structure and only touch the relevant sections (add a TOC entry when adding a section). - Finish with a summary: which pages changed and why, then a "Help impact"
heading listing every
help.htmlchange — or "Help impact: none".
The agent is explicitly told it does not need to create diff files or touch
.wiki-state.json — the harness does that itself.
6. The post-run diff writer (mechanical, not LLM)
write_update_diff(execution_id) runs after a completed wiki-update. It is
pure git plumbing and never raises (fail-open: git errors yield empty
strings):
- Read
last_commitfrom.wiki-state.json. git diff <last_commit>..HEAD→ "Committed since last wiki refresh" (truncated to 50 KB).git diff HEAD+ untracked-file listing (excludingdocs/wiki/history/) → "Working-tree changes (uncommitted, incl. this run)".- Then advance
.wiki-state.jsonto the currentHEAD— so the next run diffs against this point. (The writer owns this file, not the agent.) - If both sections are empty, skip. Otherwise write
docs/wiki/history/<YYYYMMDD-HHMMSS>-wiki-update[-exec_<id>].diff.
The result is a human-reviewable artifact, not an input to the next run. The committed section shows what the agent should have incorporated; the working-tree section shows what the run itself just edited (plus any unrelated uncommitted work in the tree at run time).
7. What the diff scope means in practice
- The agent's editing is driven only by committed changes
(
last_commit..HEAD). Work sitting uncommitted in the tree is recorded in the diff artifact but does not trigger wiki or help edits. - New tools →
scripts/wiki_tables.pyrewrites the<!-- AUTO:tools -->block intools.md(every registered builtin + ported tool). - New/changed routes → the same script rewrites
<!-- AUTO:routes -->inweb-ui-api.md(every Flask route except/static). - New user-facing features → only the help-sync pass (step 5) touches
help.html, and only if the agent judges them user-facing. - The job does not add new pages and does not notice code that no existing
page's
sources:covers.
8. Rendering and the reader
routes_pages.py serves the wiki:
GET /wiki→ rendersINDEX.md;GET /wiki/<slug>→ one page._wiki_pages()listsdocs/wiki/*.md(skippingwiki-update-prompt)._wiki_changed_pages()scanshistory/*.diff(newest-first, ≤20 files, ≤7-day window) fordiff --git a/docs/wiki/<page>.mdand?? docs/wiki/<page>.mdlines, marking pages changed within 2 days as "recent" for the sidebar.GET /api/wiki/search?q=backs the floating quick-search panel.- The Jobs page serves
GET /api/wiki/historyand/api/wiki/history/<name>to browse past diffs.
9. Gotchas and limitations
- Commit before you expect it to reflect. Only committed changes drive
edits. To capture work-in-progress, commit it (or run the job again after
committing) — the
last_commitpointer only advances on a completed run. - Failed runs advance nothing.
status != "completed"→ no diff, no state advance; the next run re-diffs the same range. - Truncation. Diff sections cap at 50 KB each; a huge change set may be
truncated in the artifact (the agent still sees the raw
git diff, so this only affects review). - Sources coverage is manual. A new subsystem needs a page (or an updated
sources:list) before the job will maintain it. - help.html is hand-authored. The help-sync pass is the only automated touch; it matches existing style and section structure and is scoped to the relevant sections. Large feature additions still benefit from a manual pass.
- AUTO tables are the only mechanical text. Everything else (prose, help.html) depends on the agent's judgment of the diff.