docir — design documents
Recently updated
-
check refuses to report a verdict it could not reach
Why an index holding nothing beside files on disk is an error rather than a warning: --strict was a merge gate that passed by reading nothing.
accepted -
Blocking is its own relation property, split from dependency
One flag was answering two questions — where two types sit, and whether one waits for the other — so a decision refining a superseded one read as ready to start.
accepted -
A JMESPath expression over the corpus, and no rules of docir's own
query --expr filters on an expression over each document and its resolved edges, which is the ability to state a rule without docir shipping any.
accepted -
docir doctor — one report for every way docir is subtly wrong
Why the environment checks scattered across five commands became one command, and why the corpus is deliberately not part of it.
accepted -
No type key, no body, and an unknown field is refused
The two questions store checks left open answer to 'nothing to add', and answering them found that a mistyped field matched nothing silently.
accepted
Architecture 12
-
Doc-Index CLI — the write path
What happens when a document is created, edited, archived or deleted: id allocation, schema validation, the index update, and how a diverged file is handled.
active -
Doc-Index CLI — the read path
How a query becomes results: full-text and vector rankings fused, section-level embeddings, default status visibility, and reads spanning peer stores.
active -
Doc-Index CLI — the file format on disk
What a document is as markdown: every frontmatter field, what validates it, and the tag registry the tags resolve against.
active -
Doc-Index CLI — the CLI surface
The command vocabulary agents drive docir with, the static site build, and a worked flow through them end to end.
active -
Doc-Index CLI — validation strictness tiers
The three tiers deciding what blocks a write, what a check reports and what stays advisory, plus how a schema change is detected against the index build.
active -
Keep the corpus trustworthy (maintenance, CI, staleness)
How the corpus stays consistent: reindex, check, repair, and the merge guard.
active -
Doc-Index CLI — Architecture
The shape of the system: git as the source of truth, the SQLite index as a derived projection, the layer map and the daemon — with each part of the pipeline in its own document.
active -
Architecture Rules — Modular DDD
The MUST/SHOULD module rules this codebase is held to, and how CI proves them.
active -
Capture a decision (the write path)
How a decision is captured: validate, allocate an id, write the file, project the index.
active -
Adopt docir in a repository (bootstrap, schema, agent onboarding)
How a repository gets a store and an agent learns to drive it.
active -
Maintain the tag vocabulary
How the controlled vocabulary is registered, renamed and retired.
active -
Retrieve relevant context (the read path)
How a task turns into a ranked document set: hybrid fusion plus graph expansion.
active
Decisions 49
-
check refuses to report a verdict it could not reach
Why an index holding nothing beside files on disk is an error rather than a warning: --strict was a merge gate that passed by reading nothing.
accepted -
Blocking is its own relation property, split from dependency
One flag was answering two questions — where two types sit, and whether one waits for the other — so a decision refining a superseded one read as ready to start.
accepted -
A JMESPath expression over the corpus, and no rules of docir's own
query --expr filters on an expression over each document and its resolved edges, which is the ability to state a rule without docir shipping any.
accepted -
docir doctor — one report for every way docir is subtly wrong
Why the environment checks scattered across five commands became one command, and why the corpus is deliberately not part of it.
accepted -
No type key, no body, and an unknown field is refused
The two questions store checks left open answer to 'nothing to add', and answering them found that a mistyped field matched nothing silently.
accepted -
implements carries no property, and that is the decision
Giving implements a machine meaning would warn on ordinary modelling, so it stays a word for the reader — and a kind gains a property on evidence, not on symmetry.
accepted -
A store declares its own checks; docir ships none
checks: in docs-schema.yaml runs a store's own JMESPath rules as Tier 1 warnings, which is how docir gains a validator without gaining an opinion.
accepted -
A code-coverage advisory was measured and not built
Prose naming a source path is not evidence a document governs it — the examples, the historical records and the inventories are indistinguishable from the text.
accepted -
Every change is exercised against docir's own corpus before it is done
The gates pass on defects that only a real store with history and a warm daemon exposes — 0.18.0 shipped three of them past a fully green suite.
accepted -
The deep read is batched, and its shape follows the key
Why get takes several ids and id#heading addresses in one request, why the plural payload key rather than the result count decides the reply shape, and why an address that does not resolve is data instead of an error.
accepted -
docir does not generate: the caller is already a model
Query rewriting belongs at the caller, which is a frontier model that has read the code, so docir ships no generative model and accepts several queries instead.
accepted -
Pseudo-relevance feedback, built and rejected on measurement
Rewriting a query with its top hits' own words costs 0.13 recall@5 on docir's corpus, because the first pass is already good enough that feedback only drifts.
accepted -
Several queries take turns rather than pooling their scores
Interleaving per-query rankings keeps what a correct extra phrasing finds while bounding what a wrong one costs — the only one of three fusion shapes that does both.
accepted -
A feature ships with its instructions, verified by use
A business feature is done when an agent holding only the installed package can tell what it is, when to reach for it and how to invoke it — and somebody has followed those instructions to check.
accepted -
The task is not weighted above the caller's extra phrasings
Weighting the literal task removes --also's gain along with its risk, because an extra query is powerful exactly to the degree it can outvote the task.
accepted -
A version stamp that moved is not a content change
Why docir agent update reports 'unchanged' when a release moved only the version stamp, and why the file is rewritten anyway.
accepted -
A second relation graph, derived from the prose
Why ids named in a body become mention edges, why only the orphan check reads them, why they stay out of frontmatter, and what following them cost in the benchmark.
accepted -
A rebuild is the only way to recompute vectors
Retire reindex --embeddings instead of repairing it: it recomputed exactly the vectors a rebuild recomputes anyway, for the same time, and skipped both stamps.
accepted -
A verification records what the code looked like
Why --verified fingerprints the globs a document governs, why the digests live in the file, and why the resulting check-changed finding stays a warning.
accepted -
schema validate measures the corpus, not just the file
Why the command run after a schema edit reports what that schema costs the corpus, reads files rather than the index, and never changes the exit code.
accepted -
AGENTS.md points at the skill instead of inlining it
Why the AGENTS.md block became a pointer (description + path) and now always installs the skill it names, instead of embedding a second copy of the guide.
accepted -
A second, optional skill for how to write the documents
Why documentation-writing rules ship as their own opt-in skill rather than a section of the CLI guide, and why the length rule is a section limit rather than a word count.
accepted -
docir's own prose is validated against the CLI, all four sources
Why the command-resolution guard covers CLAUDE.md and the project store as well as the shipped guide, why a retired binary name needs a separate check, why the unreal-command exemption list may only shrink, and why type/status values are checked against the shipped vocabulary.
accepted -
A document's type is mutable; its id is not
Why docir update can retype a document while its id and prefix stay put, and why a schema can subtract a type the core or a profile contributed.
accepted -
Mermaid diagrams draw from a supplied runtime, not a bundled one
Why docir build renders mermaid fences as diagrams, and why the runtime is a build input like --logo rather than a vendored asset.
accepted -
Reads federate across declared stores; writes never do
Why docir reads fan out across a committed list of peer stores, why peers are opened read-only, and why the merge sorts on similarity rather than score.
accepted -
docir self upgrade: the local half of an upgrade
One command for the steps that follow a new docir release, and why installing the new docir is not one of them.
accepted -
Upgrading the package: re-exec, and only where docir owns its environment
How docir self upgrade installs a new docir, which installs it refuses to touch, and why the release check is opt-in.
accepted -
Schema drift is reported, never enforced
Why a store records the resolved schema it was built against, why reindex is the only thing that advances it, and why the finding is a warning that must never become an error.
accepted -
Decisions are enforced by tests, not by a rule engine
Gap 6 closes as a decision: a testable decision is bound to the test that enforces it, CI prints the decisions a branch touches as a notice, and docir builds no DSL, sandbox or per-language analyzer.
accepted -
Relation-kind meaning is schema data, not three hardcoded name sets
Custom relation kinds could join none of the sets that decide cycles, layering and successor traversal, so they were silently exempt from all three; symmetric/dependency/successor become declarable properties.
accepted -
The index filter is chip-displayed state with a token grammar
Why the published index shows applied filters as removable chips, accepts tracker-style tokens (type:x, is:stale, -status:y), records each facet step in history, and dims zero-count options instead of dropping selections.
accepted -
The site publishes the relation graph as an interactive constellation page
Why docir build emits graph.html — a deterministic per-type constellation map of the corpus — plus a landing-page index, and why the graph is a domain projection (graph_payload) rather than a second data path.
accepted -
MCP as a second transport over the dispatcher
Why docir mcp serve is a third client of the dispatcher rather than a second implementation.
accepted -
Embed each section, because the model never read the rest
Why per-section vectors exist: 56% of the corpus was outside the model's token window and absent from the semantic index.
accepted -
A publishing module that takes documents as data
Why docir build renders a static site, and why the module takes JSON rather than a DocumentService.
accepted -
Cross-encoder reranking, built and rejected on measurement
Why docir has no reranker: three models and three shortlist widths all ranked worse than plain RRF fusion.
rejected -
A platform.naming leaf for shared name grammars
Why the tag-key grammar lives in platform rather than being written twice or crossing a module boundary.
accepted -
Semantic embeddings on by default
Why a real embedding model is the default and the hashing embedder only the fallback.
accepted -
A qa profile, a release_note type, and schema introspection
Why a qa profile, a release_note type and schema introspection were added.
accepted -
Per-project store discovery + docir init
Why a project-local .docir store is discovered the way git finds .git.
accepted -
Agent-instruction scaffolding as a self-contained module
Why agent-instruction scaffolding is a self-contained module that bypasses the daemon.
accepted -
A frozen core schema + swappable domain profiles
Why the schema is a frozen domain-agnostic core plus swappable domain profiles.
accepted -
Typed relation edges + per-type allowed relations
Why relation edges carry a kind, and how the on-disk form stays backward compatible.
accepted -
Staleness as data (owner + verified + review cadence)
Why staleness is owner + verified + review cadence data rather than a heuristic.
accepted -
Keep a central test tree, organized per module
Why tests live in a central tree mirroring the modules instead of beside them.
accepted -
Authorization and cross-cutting concerns are not instantiated
Why no authorization or cross-cutting machinery exists in a single-user local CLI.
accepted -
Keep the shared derived index and single unit-of-work
Why one shared SQLite schema and unit-of-work spans all contexts, and what that costs.
accepted -
Adopt Modular DDD enforced by tach
Why the codebase is vertical bounded-context modules with tach proving the boundaries in CI.
accepted
Issues 103
-
The mermaid guidance sent adopters to a version docir itself stopped using
skill and README named mermaid 10.9.3 on the false grounds that 11 is ESM-only, while docir's own pages.yml published with 11.16.1.
resolved -
CI cached a fastembed directory fastembed stopped writing to
The model cache never hit: the workflow cached ~/.cache/fastembed while fastembed 0.8 writes to $TMPDIR/fastembed_cache, so every run re-downloaded 64MB.
resolved -
CI's document-integrity gate ran over an empty index
check --strict ran on a gitignored index, so dangling edges — half the merge guard — never fired; CI now reindexes and runs doctor --strict first.
resolved -
A workflow context error took main red, and nothing local could have caught it
A job-level env used the runner context, so GitHub rejected ci.yml and zero jobs ran; actionlint now gates workflows locally and in CI.
resolved -
Embedder.dimension is declared and never read
The port declares a vector-width property nothing outside the embedding package consumes, and the fastembed adapter keeps it correct with a self-correcting field the library can answer directly.
resolved -
The embedding model is pinned, and it is English-only
bge-small-en-v1.5 is compiled in as the only real embedder, so a corpus not written in English retrieves worse than plain full-text search, with nothing to report it.
resolved -
The benchmark proves docir, not the adopter's corpus
benchmarks/ lives in the repository, so an adopter inherits docir's retrieval numbers as a claim with no way to reproduce them on their own documents.
resolved -
A ranked result cannot say why it ranked
context and search return score and similarity with none of the terms behind them, so an agent cannot tell a bad ranking from an empty corpus and ranking changes are debugged with print statements.
resolved -
context takes one query, and the caller has better ones
Both halves are answered: the model-free rewrite measured worse, and generation is closed by adr-27c63ad02695 — what remains is accepting caller-supplied queries.
resolved -
A published page executes raw HTML from a document body
docir build parses bodies with the CommonMark preset, which passes raw HTML through, so a script tag in a contributed document runs on the published site.
open -
reindex --embeddings replaces the rebuild rather than adding to it
The --embeddings flag re-embeds exactly what a plain reindex already re-embeds, for the same time, while skipping the two stamps the rebuild writes — so it is dominated by the command it modifies.
resolved -
A full rebuild on every upgrade, even when nothing changed
docir self upgrade ran an unconditional full reindex, and 96% of that is re-embedding: 58.4s of 60s on a 315-document store whose files had not moved.
resolved -
A document's type cannot be changed after it is created
docir update patches every other frontmatter field but not type, so retyping a corpus means hand-editing the markdown the CLI exists to own.
resolved -
A short section before an over-long one erases the long one's heading from the index
merge-forward keeps the first heading, then the merged block hard-splits, so the second section's heading names no chunk and matched_section can never point at it.
resolved -
Nothing reports a heading that appears twice in one document
A repeated heading makes --section resolve to the first occurrence and leaves the second unreachable by name, silently.
resolved -
The core schema cannot be subtracted, so its type names and prefixes are claimed forever
Every profiles: key merges the core unconditionally, so decision and its adr prefix exist in every store — an unused name stays addable and its prefix cannot be reused.
resolved -
Section reads and edits treat a fenced ## as a heading; the chunker does not
markdown_sections.py has no fence tracking, so --section returns a fragment ending in an unclosed fence and --replace-section silently orphans the rest of the body.
resolved -
The retrieval benchmark corpus cannot exercise any of the chunking rules
26 documents, 30 sections, none over the chunk ceiling and none quoting a fenced heading — so the splitter never runs and a chunking regression scores identically.
resolved -
Interpreter startup, not retrieval, dominates read latency
Startup still dominates after the SQLAlchemy fix: ~0.49s of a 0.53s warm-daemon read is process start and imports. What remains is pydantic-settings (~97ms) and docir's own 130 modules.
open -
No expression language over the corpus
Both halves shipped: query --expr asks a question, and checks: in docs-schema.yaml states a rule the store runs.
resolved -
A test asserts a phrase against rich-wrapped stderr, so it passes on path length
test_an_empty_store_says_so holds or fails on where rich broke the line, which depends on the tmp path inside the message.
resolved -
No way to see what a docs-schema.yaml edit will change before it lands
schema-drift reports a schema change after the fact; nothing renders the effect of an edit beforehand, and the file's meaning is not its text because the core and profiles merge into it.
resolved -
docir check has no finding for an edge whose relation kind the registry no longer knows
unknown-tag and unknown-status are reported, but an edge carrying an unregistered kind is served by get, traversed by context and flagged by nothing; only rewriting it is refused.
resolved -
A newly-required field is invisible to docir check, and surfaces one write at a time
Adding 'required:' to a live type leaves every existing document in violation with no finding of any kind; the first report is an unrelated update failing, one document at a time.
resolved -
A store cannot tell that its schema changed under it on upgrade
docs-schema.yaml has no version and the index records nothing about the schema it was built against, so a release editing the core or a profile changes what every store enforces with no local edit and no report.
resolved -
Nothing in a document names the code it governs, so a decision cannot be found from, or checked against, the codebase
No frontmatter field points at code, and the schema's 'required' hook that appears to allow one is unsatisfiable — which blocks enforcement against code and AST-anchored staleness alike.
resolved -
A ranked hit names the document but not the section that matched, so the paired section read is a guess
Chunk vectors decide the ranking and the winning ordinal is discarded before the result is built, so an agent must fetch the whole body or discover headings in a second round trip.
resolved -
--append-section accepts a heading that already carries its ##, and writes it twice
The flag takes heading text and adds the ## itself; passing '## Resolution' silently writes '## ## Resolution', which no section-edit mode can repair.
resolved -
A type may declare a required field no document can carry, and the schema loads anyway
'required:' accepts any name but is checked with getattr on the entity, so an unsatisfiable name loads fine and then rejects every add of that type, naming the write rather than the schema.
resolved -
The cycle check counts symmetric `relates_to` edges, so a mutual reference is a permanent warning
A cycle is only meaningful for relation kinds that assert direction; counting the default symmetric kind made 120 correct edges unrecordable in this store.
resolved -
The daemon keeps serving the code it started with, so a fix silently does not take effect
Nothing compares the running daemon's version against the installed one; after an upgrade or a source edit every command is answered by the old code, and the wrong answer looks normal.
resolved -
A transport failure prints a Python traceback and exits 1 instead of the error it raised
Every client-side daemon error escapes the CLI's error mapping, so the default execution mode reports failure as a stack trace.
resolved -
`--override` bypasses the transition rules and leaves no trace
Coverage checklist: "Admin: who can override a rule, and is the override audited?" — the override exists, the audit does not.
resolved -
`lint --deep` reports a duplicate for two documents that are explicitly related
On docir's own corpus all 14 duplicate findings are pairs already joined by an edge: the relation is the answer to the finding.
resolved -
Should the corrupt-state findings have a repair path, or only detection?
Every confirmed failure mode in this analysis ends in a state the product detects and cannot exit, and the documented recovery contradicts the product's second thesis.
resolved -
The default embedder path was excluded from every quality gate
A typo in `FastEmbedEmbedder.embed` would have shipped green to every default install.
resolved -
Should `tag rename` advance `updated` on every referencing document
ADR-0006 argues staleness must be honest human re-verification; a bulk administrative edit silently forges it.
resolved -
No import path: a repository with existing ADRs must re-create every document by hand
The most likely adopter is precisely a project that already keeps ADRs in markdown — the audience the product describes.
resolved -
Should `schema validate` check that transition targets name declared statuses?
The command exists to catch schema edits before they reach a write; this is the most likely schema error and it passes.
resolved -
A document may relate to itself, which manufactures the cycle warning `check` exists to report
Tier 0 accepts a self-edge; `docir check` then reports a one-node cycle that no edit but removing the edge can clear.
resolved -
`owner` is captured and only ever interpolated into a `check` message
'Knows what's stale' is one of six rows in the README comparison table. Detection works; the loop that would make it matter is absent.
resolved -
An uninitialised repository silently falls back to the global `~/.docir` store
Documents intended for a repo land in the user's home directory, ungitted and invisible to teammates, with no error at any point.
resolved -
With `--no-daemon`, concurrent `add` invocations all receive the same id
Contradicts a documented invariant.
resolved -
Linking a decision to its issue is a permanent `layering` warning in the `software` profile
The most natural thing a user will model produces a warning they cannot silence, which trains them to ignore `check` output — and compounds GAP-006.
resolved -
Four of the eight finding kinds are detected with no way to repair them
Every confirmed failure mode in this run (GAP-003, GAP-007, GAP-009) terminates in a state the product detects and cannot exit.
resolved -
No usage counts, so dead tags are invisible
The registry can only grow.
resolved -
Expansion is outgoing-only, so the document that supersedes a hit is never reached
"Is this decision still current?" is the question the relation graph most needs to answer, and it is the one direction not traversed.
resolved -
`scope-creep` uses one character threshold for every type, so a register is always too long
A glossary, a rule register and a probe log are long by definition; the check has no way to know that and advises splitting them.
resolved -
`reindex` silently skips unparseable files and reports the rebuild as a success
A user rebuilding after a hand-edit that broke frontmatter is told the rebuild succeeded.
resolved -
The markdown file is written before the transaction commits, so an interruption duplicates an id
A third route to a duplicate id, and the sharpest one.
resolved -
`docir init` ignores the global `--home` flag and creates the store under the CWD
A store is created somewhere the user did not ask for, and if the CWD happens to be a repository they now have an unrequested `.docir/` in it — which is exactly what happened to the analyst while…
resolved -
"Agents never edit markdown directly" is stated for agents and never for humans
The single most likely user action outside the CLI has no stated contract.
resolved -
How is a repository that already has ADRs supposed to adopt docir
The most likely adopter is exactly a project already keeping markdown ADRs.
resolved -
A random id is ~3x the length of a sequential one, and the cost is paid on every read
Small per document, paid on every read.
resolved -
The no-op early return skips staleness, so a no-op `update` reports a stale document as fresh
One field is wrong on one rarely-hit path.
resolved -
Dates use the writer's local date with no timezone, so teammates stamp different days
Two teammates in different timezones can stamp different dates for the same moment; staleness can differ by a day.
resolved -
The agent guide told agents to run `docir reindex --all`, a flag that does not exist
An agent following the guide after a merge gets an error instead of a rebuilt index, and the merge-safety workflow the guide exists to teach silently does not run.
resolved -
Should `reindex` restore the id counter, or is the index not fully rebuildable?
Fires on the documented happy path with no concurrency, no --force and no unusual input. It contradicts the project's first thesis, so the answer also decides whether that thesis…
resolved -
Should `--limit` bound the whole `context` response, or only the ranked seeds?
docir's headline claim is "token-cheap for agents" and `context` is the flagship command with a default limit of 5. The overrun scales with exactly the well-linked corpus the…
resolved -
The inactive-status filter is enforced on three read paths and skipped on the fourth
An agent asking for current context receives closed work items it was promised it would not see, and cannot tell which results honoured the filter.
resolved -
An edge's target key is `to` in frontmatter and `target` in JSON output
An agent that reads output and then hand-writes frontmatter will use the wrong key.
resolved -
Should graph expansion honour the inactive-status filter?
There is a defensible argument for the current behaviour — "the issue this decision resolved is worth seeing even though it is closed" — but nothing states it, and the…
resolved -
No relevance floor, and `score` carries no absolute meaning, so noise reads like a match
An agent cannot distinguish relevant context from noise, so it either always trusts the results (and is misled on unrelated tasks) or never does.
resolved -
Should `docir context` be able to return nothing?
Compounds Q-003 — the response is unbounded in size and unfiltered in quality.
resolved -
`--force-schema` alone is a silent no-op; it only takes effect together with `--force`
A user who reaches for the more specific-sounding flag gets nothing and no explanation.
resolved -
Six concurrent `--no-daemon` adds all returned `adr-0002`
"Parallel agents" is the exact scenario the invariant claims to protect, and `--no-daemon` is the mode most likely to appear in scripts and CI.
resolved -
`--limit` bounds the ranked seed set but not the response
Directly negates the product's headline claim.
resolved -
Should `--override` leave a trace of a forced illegal transition?
Coverage checklist: 'who can override a rule, and is the override audited?'
resolved -
Which findings should `check --strict` block a merge on?
A team that adopts the documented gate gets a red build on day one and will remove it — which also removes the duplicate-id detection that is the gate's stated purpose and the…
resolved -
`tag rename --merge` onto itself deletes the tag and leaves every document carrying it
Data corruption reachable from a plausible command, shipped in 0.7.0.
resolved -
`check --strict` exits 1 on any finding, so the advertised CI gate fails on a healthy corpus
The one CI integration the product advertises cannot be adopted as documented.
resolved -
`tag rename` sets `updated = today` on every referencing document, resetting the review clock
Launders the one trust signal the product offers.
resolved -
'home', 'store' and 'data root' name one concept in three places
Minor discoverability friction.
resolved -
Tags are in neither the FTS index nor the embedded text, so `search` cannot find them
Reasonable design; undocumented, and surprising given tags appear in output.
resolved -
`schema validate` does not check that transition targets are declared statuses
A command whose entire purpose is "check an edit before it reaches a write" (app.py:138) passes the most likely schema error, and the eventual message misdirects.
resolved -
Staleness is detected and never routed: `owner` reaches one `check` message and nothing else
"Knows what's stale" is one of six rows in the README's comparison table (README:44) and one of four bullets in "The model".
resolved -
`reindex` does not restore the id counter, so a fresh clone re-mints a live id
Silent loss of a decision record on the documented happy path.
resolved -
An unrecognised agent target name is silently ignored: no error, exit 0, nothing written
A once-per-repo onboarding command that reports success while doing nothing; the user proceeds believing their agent knows how to drive docir.
resolved -
Should `docir add` in an uninitialised repository succeed against the global store?
`docir init` is step 2 of the quickstart; forgetting it produces no error.
resolved -
Should `agent install --agent <unknown>` fail instead of being a silent no-op?
Once-per-repo onboarding command reporting success while doing nothing.
resolved -
Only `--replace-body` has a stale-write guard; the other four edit modes have none
The guard exists and is computed; applying it to one of five edit modes is a decision nothing records.
resolved -
Write commands report the resolved `store`; the read paths do not
Introduced by the GAP-023 fix, which reasoned about writes only.
resolved -
`reindex --changed` skips the removal sweep, so deleted documents stay in the index
The fast path silently has different semantics from the full path — deletions are invisible to it.
resolved -
Renaming a tag onto an existing key is rejected, so two tags cannot be merged
Vocabularies drift and need consolidating; the registry can only grow.
resolved -
`tag rm` reports only `removed <key>`, never how many documents it rewrote
A bulk mutation reports as a single-key operation.
resolved -
Nothing recorded which model produced a vector, so changing embedder broke every read
A dead column that turned out to be load-bearing.
resolved -
The client's connect timeout also bounded the daemon's reply, so any command slower than 5s failed
The client reported failure for work the daemon completed, then resent the request — a write slower than five seconds ran twice.
resolved -
`stale` names three unrelated concepts in one codebase
Maintenance hazard only; no user-visible defect.
resolved -
`docir init` inside an existing store's tree creates a shadowing store in silence
A nested `.docir` captures every command run beneath it, and the parent store's `check` never sees those documents.
resolved -
Nothing measures whether docir achieves its purpose
Not a defect in the code; a defect in the ability to make decisions about the code.
resolved -
`search` fetches `limit * 2` candidates then filters, so it under-returns on a closed corpus
Under-return looks like corpus scarcity rather than filtering.
resolved -
Should graph expansion follow incoming edges too?
'Is this decision still current?' is the question the relation graph most needs to answer, and it is the one direction not traversed.
resolved -
No format rule for tag keys — any non-empty string is accepted
Two agents will produce `auth`, `Auth` and `authentication` and nothing objects.
resolved -
Documented as leaving `unknown-type` documents; the recovery path is not documented
Detection is good; the exit is undocumented.
resolved -
The flag is `--include-resolved` but the concept is "inactive status"
A user querying decisions has no reason to guess that a flag named --include-resolved controls whether superseded decisions appear.
resolved -
The default embedder does not capture meaning; it is the signal FTS5 already gives
README:42 claims "Retrieval by meaning ✅ (lexical + semantic)" against RAG's ✅ and plain files' ❌.
resolved -
resolved
-
The benchmark corpus has no `supersedes` edge and no inactive document, so both go unmeasured
A harness that cannot move is read as "no regression" when it means "not measured".
resolved -
Should linking a decision to its motivating issue be a `layering` warning?
Compounds Q-004: it guarantees a finding on the most natural modelling, which trains users to ignore `check` output entirely.
resolved -
Nothing measures whether docir retrieves better or cheaper than the alternatives
This is why every gap in the register carries `frequency: unknown`, why the retrieval constants (25 FTS candidates, 0.9 similarity, 8000 chars, RRF k=60) cannot be tuned on…
resolved -
No stated corpus ceiling: `context` loads every active embedding into memory per call
Fine at the 'thousands of documents' scale the id-entropy comment assumes (identifiers.py:23-25).
resolved -
`delete --force` leaves referencing documents pointing at a document that no longer exists
The graph — the feature that distinguishes docir from a folder of files — silently accumulates unresolvable edges, in the canonical files, permanently.
resolved -
`init --force` overwrites a customised `docs-schema.yaml` along with the `.gitignore`
A user re-running init to refresh the .gitignore destroys a customised schema.
resolved
Reference 11
-
Competitive landscape — docir vs. the alternatives (2026-08-24)
Where docir stands against the retrieval, agent-memory, ADR and spec-driven markets on 2026-08-24, and the six gaps still open.
active -
How to read a ranked result
What score and similarity each mean on a context or search hit, which one --min-score filters, and the two hits it never drops.
active -
The embedding model: what it costs, and what the fallback loses
What the default embedder costs to install, what the model-free fallback loses, and how a store names a different model.
active -
Competitive landscape — docir vs. the alternatives (2026-08-03)
What the adjacent tools do, where docir is unique, and the ranked list of features it does not have.
superseded -
Discovery frame — docir at 0.8.0+, run 2026-07-30
Scope, method and budget for the second discovery pass: the surface v0.2.1 never examined, probed rather than read.
active -
Discovery probe log — PROBE-1..N and the delta pass
The executed probes behind the gap register: what was run, what came back, and what it proved.
active -
Actor catalog — who and what drives docir
The eight actors that drive docir, their goals and their authority (there is no permission model).
active -
Business rule register — 47 rules, BR-001..BR-074
47 reconstructed business rules with evidence, examples and boundaries; every one unconfirmed by a human.
active -
Discovery frame — docir at v0.2.1, run 2026-07-26
The business outcome, scope and coverage the discovery run was framed against.
superseded -
Probe log — second discovery pass, 2026-07-30
What was executed against the CLI in the 0.8.0+ pass, what it returned, and the four areas deliberately not reached.
active -
Glossary — one term, one definition, one owner
13 terms defined with owner and evidence, including the words that mean two things.
active
Release notes 2
-
0.18.0 — retrieval you can measure, see into, and steer
The release that made retrieval inspectable: a swappable model, a benchmark an adopter can run, a rank trace, and two ways to hand docir a better question.
published -
0.19.0 — state a rule, and find the question that never ran
checks: lets a store declare its own rules in docir's grammar, and the guard added alongside found that a mistyped expression had been silently matching nothing.
published
Runbooks 7
-
Connect an agent to docir
The two transports an agent can use — the installed CLI skill or the bundled MCP server — and why both answer identically.
active -
Rename a document type
How a corpus renames a type and keeps the ids it already has: disable_types frees the prefix, then documents are retyped one at a time.
active -
Read across repositories
How a store federates reads over declared peers: stores.yaml, --store, why writes and build never federate, and why ranking merges on similarity.
active -
Publish the store as a static site
How docir build renders the corpus for the people who approve decisions: the flags, publishing from CI, the --out guard, and mermaid diagrams.
active -
Upgrade docir in a project
What to run after a new docir release: the package, the derived index, and the generated files nothing refreshes for you.
active -
AI Code-Check Checklist
The staged procedure an AI agent follows when reviewing new code.
active -
Publishing to PyPI
How to publish docir to PyPI with uv and GitHub Actions trusted publishing.
active
No documents match this combination.