WeaveLang · v0.3 draft

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.

fieldthe moment it serves
preview_summaryThe decision to enter. What waits inside, before you go in.
collapsed_summaryThe decision to ignore. What a neighbour needs when this is only context.
summaryWhat 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:

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.

The two invariants #

first

Every depth is useful by itself

“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.

Written here, described there #

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.

writtendescribed
has materialyesno
occupies a positionyesyes
addressable, citableyesyes
a renderer showsthe materialthe summary, in its place
a generator mayrender itwrite 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.

Nuance is instruction #

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.

When the material lives elsewhere #

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.

Why converge anyway #

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.

Published conventions: weave.core, weave.software, weave.cloud, weave.security, weave.book, weave.document, weave.news, weave.history, weave.llm_response, weave.argument.

syntax

Plain words, few symbols.

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:

tokenjob
{ }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.

get it

Everything, in the form you want it.

/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.