Documents / Runbooks / run-f4a756206fe0
Upgrade docir in a project
What to run after a new docir release: the package, the derived index, and the generated files — the ones self upgrade refreshes and the ones it does not.
docir ships its schema, its agent instructions and its site templates inside the
package. A release can therefore change what a store enforces and what an agent
reads without a single file in your repository changing — there is nothing in
git diff to review. Some of that is applied for you on the next command; the
rest is this runbook.
Run it once per store. A machine has as many stores as it has .docir/
directories plus the global ~/.docir, and each carries its own index, its own
daemon and its own schema baseline.
What happens without you¶
Two pieces of derived state carry on as if nothing changed, and neither announces itself:
- The daemon. It loaded docir once and lives on, so after an upgrade it
keeps answering from the old code — and a stale answer is indistinguishable
from a correct one. The pid file records a
CodeStamp(__version__plus the newest mtime across the package sources), and a client that does not match stops and respawns it. - Embedding vectors. Each row records the model that produced it; a foreign
model_idreads as dirty rather than as a vector to compare against, so a changed model recomputes on the next write instead of raising a dimension mismatch. Force it withdocir embed --flush, or let the fulldocir reindexbelow do it — it re-saves every document and queues every one, and the drain recomputes each vector whose inputs moved, which under a changed model is all of them (issue-77dd42e3a03a).
What you have to run¶
docir self upgrade # install the new docir, then resync this store
That is the whole procedure where docir owns its environment (a uv tool, a pipx
install, a virtualenv): it runs the installer, re-executes as the build it just
installed, and then does the steps below in order, reporting each. Where
docir does not own its environment — a checkout, a project whose lockfile pins
it, an ephemeral uvx run — it says so and does the rest anyway; upgrade the
package where it is pinned. docir self status says which case you are in.
The steps are still worth understanding, because when only one of them is what you need, that one is still a command.
docir reindex # once per store
docir agent update # then commit the refreshed instruction files
docir check # last, so it describes the state you are left in
docir reindex — the only mandatory step¶
It is the only writer of the two things the index records about the code that
built it — the schema baseline and the docir version — so until it runs, check
reports neither schema-drift nor stale-index-build: absent means unknown,
not unchanged. The two answer different questions, which is why both exist: the
baseline compares schemas and stays silent for a release that changes how
documents are read rather than what they must contain (chunked embeddings
rewrote every vector without touching a type or a cadence).
It also raises the id counter to what is on disk, which is what a fresh clone
needs — the index is gitignored, so a clone has no index and every read answers
nothing until it is built. Opening a store whose index is empty rebuilds it
before anything is dispatched (Opening a store with no index builds one, deferring the vectors), and where that state still
arises check reports empty-index as an error (CI's document-integrity gate ran over an empty index).
There is deliberately no docir accept-schema verb. reindex is already the
"make the derived state agree with the sources" command, and a separate
acknowledgement would be a ritual whose only effect is to silence a report.
docir agent update — the files nothing tracks for you¶
.claude/skills/docir/SKILL.md and the docir block in AGENTS.md are generated
from a template inside the package and stamped <!-- docir:vX -->. They are
committed files, so refreshing them is a commit, and nothing detects that they
are behind: check covers the corpus, not the generated instructions. docir
0.11.0 shipped with its own skill file still claiming v0.10.0.
The store's own .gitignore is generated the same way, and self upgrade tops
it up in the same pass — there is no separate command. It is written once, by
the init that created the store, so every entry docir has added since reached
only stores created afterwards; feedback/ is the one that cost something, since
in a store predating it the first upstream draft an agent writes shows up
untracked, and that draft is the one thing in the store nobody has reviewed for
redaction (The store's generated .gitignore misses release-check.json and is never refreshed). Entries are appended, not rewritten over:
your own lines in that file are yours, and the report names what was added so
the next move is a git status.
docir check — new warnings are expected¶
missing-required, unknown-relation-kind, unknown-type and schema-drift
can all appear on a corpus that was clean yesterday. Every one is a warning,
so --strict stays green and CI does not go red on the release that moved a
rule: the documents are untouched and it is the rule that moved. Deal with
them as documents (docir update <id> ...) or as schema (docs-schema.yaml),
then reindex to re-baseline.
DOCIR_SCHEMA_NOTICE=1 prints the drift on stderr after every command, for the
change nobody will run check to discover.
If it applies to you¶
docir init --forceregenerates the store's.gitignoreoutright, which is more than the upgrade's top-up does: it also drops any line you added. Reach for it when you want the file back exactly as the package generates it. Adocs-schema.yamlyou have edited is preserved and reported, not replaced —--force-schemais what replaces it.docir build --out <dir>— the site templates ship in the package, so a published corpus is only as new as its last build.- MCP clients hold a long-lived server process: restart the client so it
re-execs the new binary. One spawned as
uvx docir mcp serveresolves from uv's cache, so name the version (uvx docir@0.11.0 mcp serve) when it matters.docir self upgradewill not touch a uvx environment — there is nothing there to upgrade, since it is resolved per run and thrown away. - CI installs docir on its own; pin the version there and bump it in the same commit, or the gate runs a different docir from the one you tested with.
Knowing an upgrade is due¶
docir self status answers it without a network call: it reports the newest
release as last checked, and an absent latest means nobody has checked, not
"up to date". --refresh asks PyPI — docir's only network call, skipped when the
answer is already from today.
A store created by docir init carries update_check: true in its committed
config.yaml, which turns it into a background fact: the daemon refreshes the
answer daily and a command mentions a newer release on stderr — over MCP, in the
server's instructions at the handshake. Creating the store is the act that opts
in, so a documentation tool still never phones home unasked, and the answer is
one the whole team inherits rather than one each person exports
(adr-bea870d0b666). DOCIR_UPDATE_CHECK=0 turns it off for one shell, =1 on;
a run with CI set never checks.
It says a release once per day per store, not once per command, and it says nothing at all to an installation that cannot act on it — a checkout, or a docir pinned by a project's lockfile, which is upgraded in that project. Those are the two reasons a notice repeating until somebody acts stops being read, answered rather than avoided.
Act on it between tasks. docir self upgrade replaces the running process,
respawns the daemon and rebuilds the index; a task that continues across that
runs its remaining steps on a build nothing verified.
docir check covers the other direction, the one that needs no network at all:
stale-index-build says the index was built by a docir that is no longer
installed.
Verify¶
docir daemon status # reports the build being served
docir query --limit 1 # a non-empty answer means the index is populated
docir check --strict # exit 0
Teammates who have not upgraded¶
The store is committed, so a teammate who has not upgraded keeps reading it — but their first command refuses. The index you migrated sits at a revision their build does not ship, and every command opens the index.
The message names both revisions. A plain docir reindex is not the way out: it opens the index
too, and refuses identically. They delete the file and rebuild, once.
rm .docir/index.db* && docir reindex # on their machine
Nothing under docs/ is touched. The index is derived and gitignored, so this costs a rebuild
and no content.
And their writes erode the store quietly¶
An older build writes back the frontmatter keys it knows and drops the rest, so a document it
edits loses whatever the newer release added — code_baseline: today, and whatever comes next.
Nothing errors; the document simply stops being watched.
Measured on a three-document store: one update --set-owner from the older build took the
baselines from three to two.
docir check --fix refiles what was dropped and names each document it touched, so the repair
is one command and reviewable in the diff.
The cost falls on whoever upgraded, because they are the only one who can see it. Upgrading
together avoids both halves; where that is not practical, run --fix after a teammate on an
older build has written.