What is refused, and before what
A path is checked before the file is read and before a brain is opened for a write. Four refusals, exit 2:max_bytes is unset by default, which is right for a person registering their own files and wrong for anything
accepting evidence from elsewhere. It is declared per brain and enforced in the runtime, so bytes assembled in
memory cannot exceed what bytes read from a file may not.
Where it came from is never guessed
--origin is recorded in provenance and is the key a later pull uses to answer “already have this?”. Omitted, it
is the path you named — which is meaningful because you named it. Nothing else invents one: the runtime is handed
bytes, a media type and an origin, and if a caller has no origin to give it says so rather than having this
machine’s directory layout written into a permanent record. See ADR-0021.
The media type is load-bearing
It is recorded in the block, it travels with the artifact, and it is what both normalization dispatch and projection read. A Markdown file filed asapplication/octet-stream is a file no text pipeline will offer to
normalise and no analyzer will read as prose.
mimetypes does not know .md, so vitruvio carries a small table of extensions a knowledge brain meets constantly
(.md, .rst, .tex, .jsonl, .yaml, .toml, .webp, .avif). Declaring --media-type is still better: an
extension is a claim, not evidence.
Normalized views
A normalized view is a deterministic, content-addressed rendering of a source, produced by a named and versioned pipeline, and recorded in provenance. It exists to be read — by a proposer, by an analyzer, by a person, and by search: a canonical block holds no prose of its own, so the view is the only text the indices and the exhaustive scan can observe. One policy decides which pipeline runs, andsource register, source replace and ingest run all follow it.
Nothing said means the pipeline that suits the media type, from the table below, and no view when none suits — a
raster image. --normalize-with NAME overrides it. --normalize-with none produces no view at all. A declared
source is the exception: it applies exactly what its declaration says, and nothing more.
Because a view is evidence, one requirement dominates every implementation choice: the same input and the same
pipeline version must produce identical bytes on every machine. Which is why:
- The HTML extractor is
html.parserfrom the standard library, not BeautifulSoup or lxml. Both are better parsers and both change their whitespace and entity handling between releases, which would move a view’s digest on a dependency bump. - Nothing reflows prose, fixes spelling or normalises quotes. Those are interpretations, and an interpretation belongs in semantic memory as a cited proposal.
- Raster images have no pipeline at all. A “normalized PNG” is a re-encode, and re-encoding is not reproducible across libpng versions. Vision embeddings read the original blob instead — the bytes that were observed are the evidence. SVG is the exception only because it is text.
Re-registering is free
Content is addressed by its hash, so registering the same bytes twice produces one block and reportsduplicate: true. This is what makes an ingestion pipeline safe to re-run.
The view is part of that identity. The same bytes registered under a different pipeline — or under none — are a
second block, not a duplicate, because a block that names a view and one that does not are different statements
about the evidence. A block registered before views were the default keeps its identity, and stays searchable by
media type only, until it is registered or replaced again.
No in-place edit
There is none, anywhere. A newer edition of a source is a new block plus a supersession edge, which is whatsource replace does. Immutability is what lets a root mean something.