Пишите спецификации, которые агент может процитировать
01Текст в пакете полезен агенту, только если у каждого правила в нём есть адрес. Эта страница показывает форму такого текста: именованные разделы, одна мысль на единицу, статус на каждой и адрес, который после публикации не меняется никогда.
Зачем адрес
02Человек и агент делят один репозиторий и ничего больше: ни коридора, ни общей памяти, ни интонации. Дерево спецификаций — единственный канал между ними, а канал работает, когда на сообщение можно указать. «Поправь число повторов» отправляет агента гадать; «поправь spec://org.acme/notes-flow/flows/notes/PROTOCOL#RETRY-COUNT» отправляет его к одной строке. Второе стоит около двадцати токенов; первое стоит сотни и может попасть не в то правило.
03 spec://org.vibevm.world/addressable-specs/flows/addressable-specs/ADDRESSABLE-SPECS-PROTOCOL#THE-SPEC-TREE-IS-THE-ONLY-CHANNEL
04 spec://org.vibevm.world/addressable-specs/flows/addressable-specs/ADDRESSABLE-SPECS-PROTOCOL#FOR-POINT-CORRECTIONS-THE-URI-WINS
Адрес
05spec://<group>/<name>[@<version>]/<path>/<document>#<anchor>: координата пакета, необязательная версия, путь документа внутри vibevm/vibespecs/ без расширения и якорь. Версия — удобство, а не обязанность: без неё адрес разрешается по самой свежей установленной версии. Якоря — это идентификаторы разделов и фактов в одном адресном пространстве, так что правило цитируется одинаково, будь оно разделом или одним предложением.
06 spec://org.vibevm.world/addressable-specs/flows/addressable-specs/ADDRESSABLE-SPECS-PROTOCOL#URI-SCHEME-IS-THE-FULL-GRAMMAR
07@<version>is optional — a feature, never an obligation (owner-ruled 2026-08-04, B-028: «указание версий — опциональная фича; если версия не указана — используется самая свежая»); absent, the address resolves against the freshest installed version of the package (semver-newest among the materialisedvibedeps/slots — the one deterministic offline reading of «самая свежая»). Several coexisting slots are therefore not an ambiguity but an ordered set with a defined maximum; an explicit@<version>still picks its exact slot, including a non-newest one.
Единица
09Единица — один заголовок с якорем и текст под ним до следующего заголовка; она несёт одно решение или одно правило, понятна сама по себе и помещается на страницу. Если единице нужно «а ещё», это две единицы. Контрактные утверждения используют MUST, SHOULD и MAY; читатель никогда не должен гадать, обязывает ли предложение. Проверяемые утверждения стоят вне блоков кода, потому что у блока нет якоря, а инструкция внутри него не проверена по построению.
10 spec://org.vibevm.world/addressable-specs/flows/addressable-specs/authoring-rules#ONE-UNIT-CARRIES-ONE-DECISION
11 spec://org.vibevm.world/addressable-specs/flows/addressable-specs/authoring-rules#CONTRACT-STATEMENTS-USE-RFC-2119-VERBS
12 spec://org.vibevm.world/addressable-specs/flows/addressable-specs/authoring-rules#A-CHECKABLE-CLAIM-BELONGS-OUTSIDE-THE-FENCE
Две сериализации, одна модель
13Спецификация пишется в Markdown или на XML-диалекте проекта, и обе формы разбираются в одну модель документа. В XML раздел — элемент, названный по своему якорю, <retry-policy title="3. Повторы">. Правило — элемент, названный по своему идентификатору, с атрибутом fact="true" и статусом. В Markdown то же правило — абзац, который открывается @fact:RETRY-COUNT и закрывается @status:spec/done. Инструмент, который ничего не знает о вашем словаре, всё равно находит каждое правило одной проверкой атрибута, а конвертер переводит одну форму в другую, сообщая обо всём, что не пережило бы обратный путь.
14 Decision (ADR-part; owner ruling 2026-08-22, verbatim): «сконвертируй и факты тоже. Предлагаю такой формат<fact-name fact="true" ...>. Таким образом кастомный XML-парсер всегда может найти соответствующие элементы». A fact serialises with its ID as the element name, carrying the DISCRIMINATOR attribute —<THE-LAW fact="true" status="impl/done">body</THE-LAW>— so a reader that knows nothing of the vocabulary still finds every fact by one attribute test. The recognition law: an element IS a fact iff its name isfact(the generic form, which stays in the dialect) or it carriesfact="true". The named form is emitted whenever the id passes the same elementability predicate sections use (fact-id grammar already forbids leading digits, so the fallback tail is vocabulary collisions only); the typed-fact fence binding stays by id and does not change. The owner's second clause binds the scanners: the progress machinery must work when a fact's SOURCE — not a materialised copy — is authored XML; the host lane holds by construction (XML sources enter progress through the canonical MD projection) and is PINNED by explicit tests (an observed .xml source scans unit-for-unit equal to its MD twin), while the specmap engine's native reader learns the named form mirror-wise. The converter recipe bumps again (specdoc/2→specdoc/3); the host re-materialises once, after both shapes land. The owner's third clause (2026-08-22, same sitting) binds the boot lanes: «статические и динамические лоадеры должны хорошо работать с новым синтаксисом фактов» — pinned at the transition's landing by (a) the static-splice determinism test running over a NAMED-shape snippet whose projected facts survive into STATIC, (b) the vibe-spec normal-closure byte-equality test running over BOTH serialisations (generic and named) of one dependency, and (c) the polygon re-run at specdoc/3, whose control package auto-adopts the named shape through to_xml — INDEX targets, STATIC splice and every machine loader then exercise the final syntax end-to-end; the agent half of the dynamic router is §5a's measurement, deliberately run AFTER this transition so it measures the shape that ships. Landed: the recipe isspecdoc/3, the host's 37 slots re-materialised once with named facts live (the redbook README golden pins 45), the recognition law holds in both readers withfact="false"a loud error, progress holds full ParsedDoc parity between an XML source and its hand-pinned MD twin across two scans, and pins (a)–(c) are in the tree — the splice snippet ships<BOOT-RULE fact="true">, the normal closure compiles three lanes byte-equal, the polygon re-ran 3/3. A live lesson worth its line: XML reserves every case-insensitivexml-prefixed name, soXMLBOOTcannot be an element — the predicate refuses it and the generic form carries such ids.
15 Decision (ADR-part). The XML dialect is deliberately ISOMORPHIC to the Markdown-expressible structure — exactly the constructs the markup contract names, in XML syntax, and nothing more. A schema-foreign element or attribute is a loud parse error, never a silent skip (the same closed-vocabulary law the typed-fact grammar took). This is what makes the owner's degradation law hold by construction: XML→MD loses nothing semantic because the dialect cannot express what MD cannot; «всё невыразимое — не поддерживается» is enforced by the schema, not by a lossy converter. Reopened once, 2026-09-11, for exactly one genre — §7##DOC-VOCAB-REOPENING: the documentation vocabulary of PROP-057 is additive, gated by the package kinddoc, and one-way to Markdown by law; for the spec vocabulary this decision stands unchanged.
16 Decision (ADR-part; owner ruling 2026-08-22, verbatim): «Гораздо логичней<three-bands title=\"…\">. … Вся суть XML нотации в том, что у тебя названия тэгов несут названия сущностей, это упрощает работу нейросети». A section serialises with its ANCHOR as the element name —<three-bands title="1. The three bands">— because the dialect's first reader is an agent, and a tag that names its entity is self-describing where an endless<section>river is not. The generic form<section id="…" title="…">remains in the dialect as the REQUIRED fallback for the two cases XML itself forbids or the grammar reserves: an anchor that is not a valid XML name (leading digit) and an anchor colliding with the structural vocabulary (spec,title,status,section,p,fact,list,item,table,tr,td,fence,quote») — measured over the live corpus, that tail is 2 anchors of 1393; the emitter writes the named form everywhere else, the readers accept both. The converter recipe bumps (specdoc/1→specdoc/2), so every transformed slot re-materialises by the derived-manifest law rather than lingering in the old shape. The owner's next call arrived the same day — facts follow, see##NAMED-FACT-ELEMENTS`. Landed: the emitter writes named sections everywhere the predicate allows (the live redbook README golden carries 7 named / 0 generic), both readers accept both forms, and the engine mirrors the predicate verbatim across the separability seam.
17 Decision (ADR-part; owner ruling 2026-08-22, near-verbatim): «Не правильней ли не включать внутри list элементы item, а сразу ставить в тело list элементы типа<THE-LAW fact="true"...>? И вместо<list>использовать тэг<facts>— это новое слово для зарезервированного словарика… Если же список состоит из обычного текста (там могут даже иногда встречаться факты), то все элементы — это item и группировка — list, а факты в нём рендерятся как сейчас». The law: a list whose every item is exactly one meaningful fact materialises as the vocabulary element<facts ordered="…">with the fact elements (named or generic) directly in its body — no<item>wrappers; any other list (plain text, or mixed with occasional facts) keeps today's<list>/<item>shape with facts rendered inside items.factsjoins the reserved vocabulary (an anchor namedfactsfalls back to the generic form);orderedcarries over exactly as on<list>; the model is unchanged — both shapes parse to the sameBlock::List, so the reader accepts BOTH forms (old materialisations in the wild stay readable) and a rewrite normalises the all-fact shape to<facts>. Loud errors guard the grouping: a non-fact child inside<facts>, bare text inside<facts>, an empty<facts>. Both readers — the pivot and the specmap engine's native one — learn the form mirror-wise; the converter recipe bumpsspecdoc/3→specdoc/4and the host re-materialises once. Landed: the writer branch, thefacts_blockparser (split into the pivot's ownxml_facts.rsalong the engine's seam) and the vocabulary word sit in both readers with the four loud errors pinned; the engine proves model-identity by content hash between the two shapes; the redbook README golden re-pins with two<facts>groups and the same 45 named facts; the host's 37 slots re-materialised atspecdoc/4; and the §5a stand re-ran as the regression tool it was left as — polygons rebuilt on the new shape (121 files carry groups), the sensitive tier (gpt-5.5@low) swept 9/9 with the negative control clean.
18Статус на каждой единице говорит, где она стоит: spec/done для устоявшегося правила, impl/done, когда оно уже воплощено в коде, spec/work для черновика. Два регистра идентификаторов несут сигнал бесплатно: идентификатор в верхнем регистре помечает правило с обязывающим весом, в нижнем — вводную или заметку.
19 Decision — two anchor-id registers (owner ruling, 2026-07-24).@fact:UPPER-SLUGnames a normative fact (a law, rule, carrier, changelog entry — content with binding weight);@fact:kebab-casenames a service unit (status lines, lead-ins, connective prose).
21vibe refactor convert-source --to xml или --to markdown конвертирует файлы или целые папки, пропуская дерево зависимостей и сгенерированные файлы. Он пишет соседнюю форму и удаляет оригинал одним действием, так что дерево никогда не держит обе формы одного документа. Перед записью он конвертирует результат обратно и сравнивает: побайтно совпавший обратный путь конвертируется молча, а потеря комментариев или раскладки отвергается с описанием по каждому файлу, пока вы не подтвердите или не передадите --force. Изменение смысла отвергается всегда, потому что это дефект конвертера, а не вашего файла. --dry-run сообщает о каждом файле и ничего не пишет.
22vibe refactor convert-source --to xml|markdown [PATH…]converts spec sources between the two PROP-045 serialisations (mdaccepted as an alias ofmarkdown). Each PATH is a file or a directory; a directory walks recursively and selects spec sources (is_spec_source) currently in the OPPOSITE form; a file in the target form already is reportedalreadyand skipped. The walk always skips:vibedeps/(##VIBEDEPS-NEVER-CONVERTED), dot-directories,target/, and any file whose leading lines carry thegenerated by vibemarker (generated artifacts regenerate; they are not authored sources) — an EXPLICIT file argument overrides only the marker skip, never thevibedeps/skip.
23 A conversion writes the sibling serialisation and deletes the original in the same act, so the one-document-one-form law (PROP-045 ##TARGET-MIXED, the pair-collision check) holds at every instant — the tree never holdsX.mdandX.xmltogether, not even transiently between files. The verb assumes version control underneath it and keeps no backups of its own.
24 The destructiveness check is the owner's law, implemented by reverse reconversion through the pivot: for a sourceS, parse to IR, emit the target form, read the target form back, and project it into the SOURCE form again; compare. Three classes: (1) byte-stable — the back-projection equalsSbyte-for-byte: converts silently. (2) IR-stable loss — the back-projection re-parses to the SAME IR but differs in bytes (dropped MD/XML comments, normalised layout): the verb REFUSES with a per-file description of what is lost, and proceeds only on interactive confirmation or--force. (3) IR-divergent — the back-projection re-parses to a DIFFERENT IR: always refused,--forcedoes not apply; that class is avibe-specdocdefect to file (the pivot broke its own round-trip law), never a corpus to damage.
25 On a TTY, class-2 files prompt per file (yes / no / all); off a TTY, class-2 without--forceis an error listing every lossy file and what each loses.--forcewaives class 2 only.--dry-runclassifies and reports every file, writes nothing, and always exits 0 (an inventory, not an attempt); a real run exits 0 iff every requested conversion landed, non-zero when any file was refused or declined.
Директивы: use, embed и read
26Спецификация может подтянуть другую по адресу. #use spec://… подтягивает весь раздел верхнего уровня, содержащий адресованный узел, но не его соседей; #embed вклеивает ровно адресованный узел, не больше. Слияние по умолчанию — :add, так что текст интерфейса не нужно повторять, чтобы он попал в результат. Каждый файл, который называет директива, должен быть объявлен в манифесте пакета. Циклы законны в слое контрактов и запрещены между телами исходников, и именно это гарантирует, что сборка всегда заканчивается.
27
#use pulls the whole top-level anchored ancestor of the addressed node — reference a subsection, load its enclosing top-level section as one connected block. It does not pull that ancestor's siblings; siblings are read only when themselves needed.
28
#embed has arbitrary granularity — it splices exactly the addressed node, no more.
29 Default is:add(absent a:-suffix) — so the interface text need not be duplicated to appear in the result.
30
Every file referenced by any directive MUST be declared in the package's vibe.toml (the directive graph and the manifest cannot disagree).
31 Invariant. The contract layer is where cycles are legal; the source layer is where topological order is mandatory. This is the theoretical no-deadlock guarantee: as long as the contract hierarchy is acyclic-under-#embedand no source body participates in a#usecycle, the build always terminates.
32В прозе, которую читает агент, @spec://… с собакой обязателен: агент читает его на месте, один раз, при первой встрече, а компилятор никогда его не вклеивает. Голый spec://… остаётся на усмотрение агента.
33@spec://…(an@beforespec) is an in-place use: the agent MUST read it (mandatory), exactly as if a#usehad been declared at the top of the file. Amendment (2026-08-24, the normal-flip ruling): the obligation is the AGENT's, not the AOT compiler's — a@spectarget is never spliced into a compiled lane; the address itself is the compiled artefact, and the §2 equivalence invariant is carried by the agent's read obligation. (Splicing every@specrealised ##OPEN-CLOSURE-EXPLOSION on the first normal-format host build: the lane grew 250 KB → 2.5 MB off prose pointers.) Only an explicit#useis a compiler splice edge.
34
Read once. An @spec target is read only on first encounter, never re-read blindly — see the read-set (§below).
35 Barespec://…(no@) is at the agent's discretion — read it if useful, skip it otherwise. (A future algorithmic agent narrows this further.)
Адрес никогда не двигается
36После публикации якорь неизменяем. Переименование раздела или правила оставляет на старом якоре надгробие, указывающее на новый, так что ссылка, написанная год назад, всё ещё попадает куда надо. Перемещение файлов адреса тоже не меняет: адрес логический, путь — физика.
37 L1 — physics moves, addresses do not.spec://addresses, anchors, fact ids, specmap edges,scope!citations and recorded verdicts are LOGICAL and do not change: only the physical prefix maps differently (vibevm/vibespecs/common/PROP-000.xmlstill canonicalises to the samecommon/PROP-000document path). Any relayout step that would rename an address is a defect of the step.
38 Anchors are immutable; a rename is a tombstone — for published documentation pages as for specs, and for translations, which must match their source.
Особые случаи и правила
39Сгенерированный файл никогда не цель цитаты: цитируйте исходный документ, а не скомпилированную стартовую полосу.
40 A generatedSTATIC.mdis not a citation target — authored text never citesspec://…/boot/STATIC#…; the lane is compiler output, and source-of-truth is the package source undervibedeps/(PROP-035 §11's lint, B-011 §6.1).
41vibe facts check проверяет разметку спецификаций пакета; vibe check проверяет пакет целиком; обе запускаются перед публикацией.
42Код тоже может цитировать спецификации, атрибутом на элементе, который воплощает правило, и тогда карта отвечает, какой код стоит за каким правилом, в обе стороны; эту карту объясняют страницы об архитектуре этого руководства.