A semantic language for ideas, intent, and systems.
Express any subject at the degree of nuance you actually want — written out where the detail matters, described in one sentence where it does not, in the same file.
The Reader opens with this language's own specification, expressed in the language.
the premise
Machines now carry the noise. People should receive the meaning.
Language models have become the operating system of thinking and reasoning: they retrieve, compare, trace, and reason across more material than any person will ever read. The bottleneck has moved. It is no longer finding the material — it is receiving what the material means, at the resolution the moment deserves.
Every existing form loses part of that. Prose flattens a structure into one linear pass and hides where the certainty ends. JSON keeps the structure and throws away the meaning. A diagram fixes one altitude and discards every other. A summary is honest only until you need to check it, and then the thing it summarized is somewhere else entirely.
WeaveLang keeps the whole gradient in one document. One subject, expressed at many resolutions, where every depth is complete on its own terms — and where the bottom of the structure is not a citation pointing away, but the material itself.
for people
Read meaning, not material
Start at the one-line answer. Go deeper only where your attention actually goes. Nothing you skipped was load-bearing.
for machines
A form worth producing
Five constructs and seven symbols, with stable ids and explicit references — easy for a model to emit, validate, repair, and diff.
for trust
The thing itself is in the file
The deepest layer holds the verbatim paragraph, the exact clause, the working function. Conflicts are represented, never smoothed over.
the one-sentence version
A weave is a nested world of meanings. Each depth is a complete world at one resolution — and the deepest one is the thing being described.
the language
Five constructs. That is all of it.
The core knows nothing about software, books, law, or history. It knows only how to represent meaning. Everything domain-specific — a Kubernetes pod, a character arc, a normative MUST, a mobilization timetable — is a kind string, given meaning by a convention the core never reads.
weave the file: one bounded subject.
unit any meaningful thing. Nests to any depth. May hold material.
content the material itself, inline or named.
relation a connection between units that is not containment.
source a pinned origin, for material named rather than embedded.
weave "slug-service" kind software.system {
title "Slug service"
unit system kind software.system "Slug service" {
ref "slug-service"
summary "Turns titles into stable, collision-free URL slugs, and never
reuses a slug once it has been served."
unit cap.mint kind software.capability "Minting a slug" {
ref "src/mint.ts"
summary "A title becomes a slug; a collision appends the shortest numeric
suffix that is still free. Minting is idempotent per title."
collapsed_summary "Titles become collision-free slugs, idempotently."
preview_summary "slugify, then claim"
unit fn.mint kind software.function "mint" {
ref "src/mint.ts:mint"
summary "Return the existing slug if one was minted, otherwise take the
first free candidate. The claim decides, not the read."
content typescript
export async function mint(db: Db, title: string): Promise {
const existing = await db.slugForTitle(title)
if (existing) return existing
const base = slugify(title)
for (let n = 0; ; n++) {
const candidate = n === 0 ? base : `${base}-${n}`
if (await db.claim(candidate, title)) return candidate
}
}
end content
}
}
}
relation d1 kind software.depends_on {
from cap.serve
to policy.immutable
label "redirects are only safe because slugs are immutable"
}
}
Read the first unit and you have the answer. Read to the last and you have the code that must satisfy it.
The three summaries do three different jobs
They are not abbreviations of each other. A reader uses them at three different moments, and the difference is what makes a map navigable.
field
the moment it serves
preview_summary
The decision to enter. What waits inside, before you go in.
collapsed_summary
The decision to ignore. What a neighbour needs when this is only context.
summary
What the unit means once you are in it.
ref — the one string that cannot be wrong
A ref is the name the material already has: "9.2.2", "src/retry.ts:backoff", "Act II, sc. 3". It is copied verbatim and opaque to every tool — displayed, matched whole, put in permalinks and citations, but never parsed or sorted by.
Every summary is an interpretation and can misdescribe what it covers. A ref is a copy. A reader misled by a generated summary can still find the clause, cite it, and check it — which is the whole point.
depth
Depth is nesting. Nothing else.
A unit declares its children inside its own block. Its depth is how many units it sits inside, plus one. There is no layer index, no ladder of level names, and no annotation to keep in sync.
Three properties follow, and all three were impossible under a fixed ladder of numbered layers:
Depth is unbounded. Nothing caps the structure at five or six. A dense chapter may run nine deep while the acknowledgements stop at two.
Depth is local. Completeness belongs to a branch, not to the document. A weave is not incomplete because one branch is shallower than another; it is incomplete when a depth is not a whole world.
Depth is relative. Lift a subtree out, embed it elsewhere, render it alone — every statement inside stays true, because nothing in a unit refers to its absolute position.
why there is no ladder of level names
A global depth-to-name table asserts that depth 3 means the same thing in every branch — the exact uniformity that local depth exists to remove. Each unit's kind says what it is, and a renderer that wants to label a level reads the kinds it finds there.
“Auth module” is a table of contents. “Auth module: email/password login issues signed JWTs and protects tenant-scoped API routes” is a world. Deeper units refine; they never rescue.
second
Every depth is true of the material below it
A summary that does not describe what its subtree contains is a different claim wearing a summary's clothes. Because the material is in the file, this is checkable.
content
The material is the floor, not a footnote.
A weave does not point away from itself. Any unit may carry content: the verbatim material it is finally about. Not a summary of it, not a paraphrase, not a quotation about it — the thing.
unit passage.opening kind book.paragraph "The opening" {
ref "I.1.a"
summary "The narrator withholds the destination for a full paragraph, so the
reader arrives at the pawnbroker's door as unprepared as the
protagonist pretends to be."
content
On an exceptionally hot evening early in July a young man came out of the
garret in which he lodged in S. Place and walked slowly, as though in
hesitation, towards K. bridge.
end content
}
A content keyword alone on its line opens a verbatim block ending at end content at the same indentation. There are no escapes and no delimiters, so a block can hold quotes, braces, backticks, or any other syntax without collision — including this language's own.
content markdown
Here is how a block works:
content
material
end content
That was the example.
end content
The indentation rule is not decoration. A specification that documents its own syntax necessarily contains an example of its own terminator — and matching the opening indent is what lets it.
A unit's material is its parts, in the order they are written: the literal blocks it wrote, and the children it delegated to. That one rule is what lets a single file, a single class, or a single function carry layers inside it.
unit directives kind go.struct "RequestDirectives" {
ref "common/request.go:RequestDirectives"
summary "Every knob a caller may set for one request. The zero value is the
service default, so an unset field is never an error."
content go
type RequestDirectives struct {
end content
unit d.retry kind go.fields "Retry knobs" {
summary "Attempt count, backoff base, and whether jitter is applied. Json tags
match the config file's naming, so a directive can be set either way."
}
content go
ReadTimeout time.Duration `json:"readTimeout"`
WriteTimeout time.Duration `json:"writeTimeout"`
end content
unit d.integrity kind go.fields "Integrity knobs" {
summary "The checksum algorithm to verify with, and whether a mismatch fails
the request or only records a warning."
}
content go
}
end content
}
Read at the top, this is one sentence about what the struct is for. Read one level down, it is four ideas. Read fully, it is the struct — except that two of its four parts are described rather than written.
d.retry and d.integrity are described: they have a summary and no material of their own. They occupy a real position in the struct, they are addressable, they carry relations and citations, and a reader can see exactly where they belong. What they do not have is bytes.
written
described
has material
yes
no
occupies a position
yes
yes
addressable, citable
yes
yes
a renderer shows
the material
the summary, in its place
a generator may
render it
write it, from the summary and its surroundings
Nothing marks the difference except whether material is present. A described unit is not an omission and not an error: it is a statement that this part is conventional, uninteresting at this depth, not yet written, or deliberately left to the reader. The same mechanism covers a file whose imports are not worth reading, a function with one interesting branch, and a book read closely in one chapter and loosely everywhere else.
compression is a reading, not a format
Because material composes from parts, the same weave answers at every resolution without storing several versions of itself. A renderer picks a depth; a generator picks a depth and then writes what is still described. Neither needs a mode, and the file does not change.
Above a content block, each depth is a truer and looser statement about the same material. Below the shallowest one there is a brief; below the deepest one there is the artifact. Read downward and a weave explains. Read upward from the leaves and it justifies. Delete the leaves and what remains is a complete brief for writing them again — which is what makes an unfinished weave a buildable intent rather than a broken document.
There is deliberately no infer_below field, no compile mode, and no expansion construct. How much a tool may invent is that tool's configuration, not a fact about the subject. A weave records what is true and what is asked for; it does not carry a model's settings.
Referencing is an option, not the default. When the material already sits in a repository or an archive, the same construct names it. The semantics are identical; only the storage differs.
content typescript in pr.head {
at "auth/magic.ts"
region lines 42..78
sha256 "9f2c1a…"
}
A referenced weave is not self-contained: it needs its source to be readable. That is a deliberate trade a tool may make, never a default the language prefers.
conventions
Profiles are conventions, not rules.
A profile is a vocabulary a community converges on — kinds for units, verbs for relations, form words for material. Nothing in the language enforces it.use profile is a declaration of intent, not an import that can fail, and a weave that invents every kind it needs is completely valid.
The core validates that kind is a well-formed identifier and nothing more. Unknown terms are preserved verbatim, never dropped, never rejected. A language that refuses an unfamiliar noun has decided in advance which subjects may exist.
Agreement is what lets a tool do something specific instead of something generic. When enough people call a deployable process software.service and a data dependency software.reads, a tool can act on that without the language ever learning what a service is.
explorers
Render a known kind expressively
A cylinder for a database, a diff surface for a changed function — and a plain card for anything unrecognised.
analyzers
Ask questions that only make sense inside a convention
Which services read this table. Which requirements have no implementing unit. Which claims have no citing content.
compilers
Treat a known kind as a target
software.function with content is a file to write. document.requirement with content is a conformance test to generate.
search & merge
Compare weaves nobody coordinated
Two teams that both say software.endpoint have made their weaves comparable without ever talking.
The trade is deliberate: the core stays weak enough to describe anything, and the convention layer stays rich enough to be useful. A profile that guesses wrong costs one renderer a fallback. A core that guesses wrong costs the language a subject it can never express.
A weave is read by people at least as often as by machines, and a symbol that has to be explained is a symbol that should not exist. This is the complete non-alphanumeric vocabulary of the language:
token
job
{ }
open and close a block
[ ]
open and close a list
"
delimit a short string
,
separate list items
->
direct a shorthand edge
..
a range between two values
// /* */
comments
Everything else is a word. The rule for future additions: if a reader must be taught a character, use a word instead.
// Every statement has the same shape:
// keyword [id] [kind ] ["Title"] [{ block }]
unit api kind software.service "API" {
ref "src/api"
summary "Accepts usage events and returns an invoice preview."
confidence 0.9
cites [fn.ingest, fn.preview]
props { language "TypeScript" public true }
meta attention "the only unauthenticated route is /health"
}
edge api -> db kind software.reads "reads user records"
// A statement runs to the end of its line. What follows the head decides the
// form: a brace opens a block, a bracket opens a list, a quote starts a short
// value, and end-of-line opens a verbatim block closed by `end` plus the keyword.
detail
A longer explanation that runs over several lines, with "quotes",
{ braces }, and any other character, verbatim.
end detail
No significant whitespace beyond the dedent inside text blocks. No implicit nesting of anything but units. No context-dependent parsing. No two ways to say one core thing. A grammar that is boring for a person is trustworthy for a model — and the difference shows up as a lower repair rate, not as elegance.
the design razor
The weakest design that decides the cases.
Among designs that decide the observed cases exactly, WeaveLang takes the weakest — the one committing least beyond the data (Bennett, arXiv:2301.12987). Generality is a property of a design's extension, not its form: a short, elegant rule can be maximally overcommitted.
Three rules follow, and they govern every addition:
rule one
Weaken by deleting structure
A construct earns its place only if some real material cannot be decided without it. A layer, an option, or an enum added for an imagined future adds form and shrinks extension.
rule two
Boundedness lives at the edge
Open-ended dimensions — domain vocabulary, material formats, locators — stay strings resolved by convention. Real protocol facts, like a line range or a revision hash, are explicit and validated.
rule three
Ask what breaks
For any mechanism: what unseen-but-plausible material does this silently mishandle, and what in the observed cases forces the commitment?
This is why kind is a string rather than an enum, why depth is nesting rather than a numbered ladder, why the material is in the file rather than behind a citation, and why there are five constructs rather than twenty-five.
the reader
What the evidence says about reading this way.
The Reader is built on a review of the HCI and cognition literature on progressive disclosure, focus+context and document comprehension, with every citation adversarially checked. Four findings shape it, and each one argues against the design that looks obvious.
breadth
Every child is shown
The constraint that binds is how many things a reader must hold together, not how many are displayed. Scanning a row costs about 0.08 s, while every extra level costs a decision plus a steering term — so a narrow tree is the expensive shape, not the cheap one.
material
Material is never shrunk
A reader given documents at a quarter size loses more of what they were not looking for than a reader given flat text. The Reader demotes by substituting a shorter authored summary, never by scaling type down.
reading
Expanding is not reading
Readers open collapsed sections and then do not dwell in them. Collapse turns reading into skimming while producing a felt sense of coverage that the dwell time does not support — so the unit you came for opens whole, and folding is for material you are passing over.
scope
Extent is always visible
What a nested reader loses is not accuracy but scope: readers answer every question correctly while badly underestimating how much document exists. Every unit therefore reports its subtree size — a number the tree already knows.
Linear reading is a first-class mode rather than a fallback, because it is the arm that most often wins. And no view state derives from your behaviour, so a link you share renders for the recipient exactly as it rendered for you.
/reference.md the complete specification — constructs, syntax, grammar, canonical JSON, validation, conformance, and worked examples.
/reference.weave the same specification expressed in the language it specifies. This is what the Reader opens — read it at /reference.
/ford a whole book in the Reader: Henry Ford's My Life and Work (1922), fully woven — every passage verbatim, every level an account. /carnegie is a second, Carnegie's The Empire of Business.
/llms.txt the language in one fetch, for a model. Generated from the reference, so it cannot drift.
/llms-full.txt the whole specification, under the name a model looks for.
/research.md the review of the HCI and cognition literature the Reader is built on — every claim tiered by evidence strength, with the citations that did not survive checking named so nobody re-imports them.
/weavelang.js the parser as a browser module. Import it and read a weave in three lines.
@subweave/weavelang-parse the same parser as a TypeScript library — tokenize, parse, index. A Rust port is intended.
import { read } from "https://weavelang.org/weavelang.js"
const doc = read(await (await fetch("/reference.weave")).text())
doc.roots // top-level unit ids, in authored order
doc.units.get("s2").summary // what section 2 means at its own depth
doc.extent.get("s2") // { n, leaves, depth } — how much is in there
doc.unsummarised // units with no summary: unreachable by signage
doc.warnings // it never throws; it tells you what it skipped
Three levels, lowest to highest: tokenize() streams flat events before a tree exists, parse() builds the acyclic document, index() derives extents, order and relations.