VibeVM
Contents
On this page
en
Publisher
org.vibevm.core
Version
1.0.0latest
Audiences
user, author, dev
Reading time
21 min
Rendered
Read aloud
never

PROP-000: Foundational technical decisions

  • 01This document pins the foundational technical decisions for the vibevm implementation.
  • Every subsequent PROP/FEAT may assume these are true.
  • Changing any of them requires an explicit amendment here first, then downstream updates.
  • 02Source authority: VIBEVM-SPEC.md §10 and the book in refs/book/.
  • Where this PROP and the spec disagree, the spec wins.

1. Language: Rust

03Decision: The vibevm CLI and all supporting crates are written in Rust.

04Why: Single-binary distribution, no runtime dependency, cross-platform by default, strong type system aligned with the project's discipline philosophy, excellent CLI ecosystem (clap, serde, toml, reqwest, git2, tokio, anyhow, thiserror, tracing, dialoguer, console, sha2). See VIBEVM-SPEC.md §10.1.

  • 05MSRV: Latest stable at the time of each milestone.
  • M0 pins MSRV to the latest stable at the tag.

06When to revisit: Never, in the scope of v1. If Rust proves inadequate for a future milestone, open a new PROP superseding this one.

2. Build system: Cargo workspace

07Decision: Single Cargo workspace at repo root. Crates live under crates/ per VIBEVM-SPEC.md §10.2:

  • 08vibe-cli — CLI entry point, argument parsing.
  • vibe-core — types, manifest schemas, graph model.
  • vibe-graph — graph builder and runner.
  • vibe-registry — registry fetch/cache/resolve.
  • vibe-install — install/uninstall/update logic.
  • vibe-llm — the synchronous object-safe provider abstraction and its real openai-compatible adapter: JTD-generated request/response, layered project/operator configuration, secret-safe endpoint/redirect/proxy policy, bounded blocking transport and provider-independent usage. Selected-world agent execution consumes it lazily in CLI mode; hosted/MCP execution parks without linking a paying backend. Provider presence alone activates nothing, and every core subsystem retains its algorithmic mode (PROP-054 ##LLM-IS-AN-ENHANCEMENT).
  • vibe-check — linter (M1).

09Why: Standard Rust workspace layout, enables shared dependency versions via [workspace.dependencies], supports independent testing of each crate.

10Binary name: vibe (built from vibe-cli).

3. License

  • 11Decision: vibevm ships under the Universal Permissive License 1.0 (UPL-1.0) — open source, relicensed 2026-07-12. See LICENSE.md at the repo root for the terms. The scope is this repository's shipped surface — the host tree and every packages/org.vibevm.* package; separately-developed products carry their own licences and are not governed here. The project's first phase shipped under a placeholder proprietary EULA; that phase is over.
  • Crates in this workspace set license-file = "LICENSE.md" and publish = false so none of them can be accidentally pushed to crates.io.
  • 12Why: Owner's call, taken 2026-07-12 and executed the same day: the whole shipped surface — the host tree and every packages/org.vibevm.* package — carries UPL-1.0, so a consumer of any part of vibevm gets one permissive licence and no per-package archaeology.
  • VIBEVM-SPEC.md §1 explicitly defers the produced software's license to the owner; the owner's choice is UPL-1.0.
  • Considered and rejected: the placeholder proprietary EULA of the project's first phase — superseded 2026-07-12, "that phase is over" (##LICENSE-EULA); per-package licensing across the shipped surface — rejected because a consumer of any part of vibevm would then face per-package archaeology instead of one permissive licence (##LICENSE-OWNER-CALL); any copyleft licence (GPL / AGPL / LGPL) — never in contention, for the same reason it is forbidden in dependencies: it would force the whole product to relicense, "which is exactly what UPL-1.0 exists to prevent" (##COPYLEFT-FORBIDDEN, ##PROPRIETARY-TIGHTENS).
  • 13Third-party dependencies remain permissive-only. Per VIBEVM-SPEC.md §10.3: every crate we depend on must be MIT / Apache-2.0 / BSD or equivalent.
  • GPL / AGPL / LGPL are forbidden, period.
  • The permissive license of vibevm itself does not relax that constraint — a copyleft dependency mingles with our code and would force the whole product to relicense, which is exactly what UPL-1.0 exists to prevent.

14When to revisit: the previous trigger — "when the owner decides to relicense (most likely UPL 1.0)" — fired on 2026-07-12 and is spent. Re-open when either (a) a crate is to be published to crates.io: swap license-file for the SPDX string license = "UPL-1.0" and drop publish = false; or (b) a dependency or contribution arrives under terms UPL-1.0 cannot absorb.

4. Manifest format: TOML

15Decision: All vibevm manifests use TOML 1.0 (toml crate, serde-based).

16Files:

  • 17vibe.toml — project manifest. Schema: VIBEVM-SPEC.md §7.5.
  • vibe.toml is the only manifest: one file per node, the role set by section ([project][package], optionally [workspace]). The separate vibe-package.toml of the early schema is retired (workspace fork 7e); the package schema of VIBEVM-SPEC.md §7.3 now lives in vibe.toml's [package] section.
  • vibe.lock — lockfile. Schema: VIBEVM-SPEC.md §7.4.

18Why: TOML is the Rust ecosystem default (cargo), readable, has clear escaping rules, and maps cleanly to serde structs. See VIBEVM-SPEC.md §10.1.

5. Directory layout

  • 19Decision: Per VIBEVM-SPEC.md §4.2.
  • The spec/ directory is hardcoded — never configurable in v1.
  • The .vibe/ cache directory is gitignored and per-project.
  • refs/src/ is gitignored (external reference sources, cloned by the implementer for study, not part of the vibevm repo itself).

6. Package identity

  • 20Decision: [<kind>:]<group>/<name>@<version> — identity is qualified since M1.19 (PROP-008 §2.2); the unqualified <kind>:<name>@<version> of VIBEVM-SPEC.md §7.1 is CLI sugar that resolves once, at the human boundary.
  • kind ∈ {flow, feat, stack, tool, mcp, lang, doc, app} — eight kinds; mcp shipped with PROP-027; doc and app admitted by PROP-057 through the VIBEVM-SPEC.md §4.1 amendment of 2026-09-12 (pending the owner's ratification at the merge of the docs-2026-09 branch; the code learns the two kinds in that campaign's phase 2). (§Invariants INV-VOCABULARY in this file carries the same list.)
  • name is kebab-case and (group, name) is globally unique (PROP-008 — uniqueness moved from within kind to within group). version is semver.

21Constraint forms in CLI:

  • 22flow:wal → latest stable.
  • flow:wal@0.3.0 → exact.
  • flow:wal@^0.3 → semver range.

7. Registry model (M0 vs M1)

  • 23Decision: M0: local-directory registry only. No git. Registry is a path on disk with the layout from VIBEVM-SPEC.md §8.2.
  • M1: git registry added per VIBEVM-SPEC.md §8. Configured in vibe.toml's [[registry]] array. Default public registry URL = https://github.com/vibespecs (HTTPS org root; per-package URLs are derived at fetch time via NamingConvention).
  • Backend choice, trait design, cache layout, and Windows UX for M1 are pinned in spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-001 — in brief: shell-out to the system git (not libgit2), behind a GitBackend trait that leaves the door open for a future libgit2 swap.
  • 24Default in new projects. vibe init writes the default registry URL (DEFAULT_REGISTRY_URL in vibe_core::manifest) into every new vibe.toml's [[registry]] entry unless the operator passes --no-registry or overrides with --registry-url <URL> / --registry-ref <REF>.
  • The default exists so that a plain vibe initvibe install flow:wal flow works out of the box against the public registry; overrides are there for forks, staging registries, and offline / air-gapped setups.
  • The single source of truth for the URL is the constant in vibe-core — manual-tests, smoke scripts, and docs all reference it from there.

25Source repositories — split-host posture. The vibevm project and the package registry live on separate hosts by deliberate decision (2026-04-29). Each host is chosen on its own merits:

  • 26vibevm tool source: multi-homed. GitVerse git@gitverse.ru:vibevm/vibevm.git (web https://gitverse.ru/vibevm/vibevm) and GitHub git@github.com:vibevm/vibevm.git (web https://github.com/vibevm/vibevm), both public and canonical for reading. No host is primary — mainline is the maintainer's local main, every host is a downstream read-replica, and rollout is the fast-forward-only fan-out cargo xtask mirror (PROP-016, 2026-06-14, which supersedes the single-source-of-truth reading recorded here before it).
  • Package registry: GitHub, organization vibespecs. https://github.com/vibespecs (org root) — per-package repos are https://github.com/vibespecs/<group>.<name> per PROP-008 §2.5 NamingConvention::Fqdn (dot join — owner ruling 2026-08-13; e.g. org.vibevm.wal; the live _-joined repos of the M1.19 era rename as that ruling's follow-up). The earlier <kind>-<name> repos (NamingConvention::KindName, PROP-002) are archived read-only.
  • The migration from git@gitverse.ru:vibespecs/* happened on 2026-04-29 because GitVerse's public REST API does not expose org-scoped repo creation (POST /orgs/{org}/repos returns 404 / WAF 403; documented exhaustively in PROP-002 §2.10 and crates/vibe-publish/src/gitverse.rs). Without that endpoint vibe registry publish cannot fully drive the publish loop end to end.
  • GitHub's equivalent endpoint works natively, so the registry organization moved while the vibevm project repository stays put.
  • Identity is content-hashed (PROP-002 §2.1) — the lockfile's source_url rotates but no content_hash value is invalidated by the host change.
  • Legacy registry, read-only. git@gitverse.ru:anarchic/vibespecs.git (HEAD 2203239, 2026-04-23, three v0.1.0 flows in monorepo form). Kept readable for any project still on schema-v1 lockfiles until they migrate; no new publishes happen there.
  • Decision (owner, 2026-08-01 — the current posture, refining the equal-canonical reading above): GitHub carries the leading role for both surfaces — the canonical public home of the vibevm source and of the vibespecs registry. GitVerse is supplementary: (1) a full mirror of the vibevm source — the fan-out mechanics of PROP-016 are unchanged, mainline stays the maintainer's local main, every host a fast-forward-only read-replica; (2) additional storage for the registry, used in full but published to deliberately, package by package — never blanket-mirrored.
  • Why: two grounds, one technical and one observational. The technical one is recorded above: GitVerse's public REST API exposes no org-scoped repo creation (##REG-MIGRATION-WHY), so the publish loop cannot run end-to-end there while that stands. The observational one is the owner's, 2026-08-01: which host the audience actually reads is visible from the owner's seat, not from this tree, and the observed answer is GitHub.
  • Considered and rejected: the equal-canonical dual-host posture (the reading this section carried until 2026-08-01) — superseded: kept as mirror mechanics, dropped as a role statement; GitVerse-led — impossible while ##REG-MIGRATION-WHY's endpoint gap stands; blanket-mirroring the registry to GitVerse — rejected in the ruling's own words («пакеты туда должны выкладываться специально, а не зеркалироваться всё подряд»): the supplementary store is curated by deliberate publication, never synchronised wholesale.
  • Revisit when: the halves re-open separately. The publish-loop half: GitVerse's POST /orgs/{org}/repos starts returning 2xx — observation point: one request against gitverse.ru; the probe and its failure codes are documented in PROP-002 §2.10. The leading-role half: by the owner's notice from external observation — deliberately no code-observable trigger, per the same-day B-015 precedent (BACKLOG.md).
  • 27Cache location: ~/.vibe/registries/<hash>/ for cloned registries.
  • <project>/.vibe/cache/<group>/<name>/<version>/ for per-package cache — identity-keyed, as the shipped tree already is (.vibe/cache/org.vibevm.world/wal/… on disk; the earlier <kind>/<name> spelling lagged the code). See VIBEVM-SPEC.md §8.3.

8. Task graph model

  • 28Decision: Built-in nodes only in v1 (content-only plugin contribution model per VIBEVM-SPEC.md §5.4).
  • Runner is sequential (no parallelism) in v1 per §5.2.
  • Typed value system per §5.3.
  • Why: the frozen VIBEVM-SPEC.md §5.4 states the constraint and its reason: v1's contribution model is content-only"a package materialises as a verbatim vibedeps/ subtree and contributes a boot snippet, but does not contribute executable nodes. This keeps v1 small."
  • Considered and rejected: packages contributing executable / LLM nodes (e.g. a flow adding a wal:checkpoint node bound after build:compile) — deferred, not rejected: VIBEVM-SPEC.md §5.4 targets v1.5 and directs "document the extension point but do not implement it in v1." Plugins influence the graph in v1 only by changing what content the built-in nodes operate on.
  • Revisit when: the v1.5 milestone opens — VIBEVM-SPEC.md §5.4 names it as the target for the extension point (observation point: the milestone list in vibevm/vibespecs/WAL.xml) — or earlier, when a published package needs a graph node the built-in set does not provide, observed as a [hooks].post-install doing work a node should do or a requires no built-in node can satisfy (adopted with both clauses, owner 2026-08-01).

29Workflows are graph queries (target node + transitive dependencies) per §5.5.

9. Conflict resolution

30vibevm's writer-conflict resolution — the Human > Spec > Tests > Code order (also pinned in VIBEVM-SPEC.md §2.2 and book chapter 1) — is the conflict-protocol flow: spec://org.vibevm.world/conflict-protocol/flows/conflict-protocol/CONFLICT-PROTOCOL#root.

10. Observability

  • 31Decision: Use tracing for structured logs.
  • CLI defaults to human-readable Markdown-flavored output; --json for machine-readable; --quiet for one-line summaries.
  • Exit codes per VIBEVM-SPEC.md §9.4.

11. Cross-platform target

  • 32Decision: M0 builds and runs on macOS, Linux, and Windows.
  • Path handling goes through std::path::Path — no manual separator manipulation.
  • File operations respect platform casing rules where the OS enforces them.
  • 33Test matrix: M0 dev is primarily on Windows 11 (this machine).
  • CI matrix for all three OSes lands in M2 per VIBEVM-SPEC.md §11.4.

13. Decision records live inside PROPs

34Architectural decisions are recorded as an ADR-part inside the PROP they belong to — a section (or clearly-marked facts) stating the decision, the alternatives weighed, and why — never as standalone ADR files. One document carries a contract AND the reasoning that shaped it; a reader never chases a second file to learn why. (Owner ruling 2026-08-20, closing BACKLOG B-007.)

12. Commit and push discipline

35The repository's commit-and-push discipline is the git-practices family (a host dependency), whose members carry the full text:

  • 36human-authored attributionspec://org.vibevm.world/git-attribution-policy/flows/attribution-policy/ATTRIBUTION-POLICY#root;
  • the Conventional Commits message format — spec://org.vibevm.world/git-conventional-commits/flows/conventional-commits/conventional-commits#root;
  • atomicity, one commit = one logical idea — spec://org.vibevm.world/git-atomic-commits/flows/atomic-commits/ATOMIC-COMMITS-PROTOCOL#root;
  • commit autonomy — routine proceeds, and the red lines (history rewrites, force-push, large blobs, CI / signing / secrets) stop and ask — spec://org.vibevm.world/git-autonomy/flows/autonomy/AUTONOMY-PROTOCOL#root.

37Marked exception (owner ruling, 2026-08-01): the attribution posture is enforced procedurally, not mechanically — the rules live in the boot contract and every session holds them; no commit hook, trailer scanner, or CI check exists or is planned, consistent with the standing no-CI decision. Recorded so the absence of machinery reads as a deliberate choice, not an oversight.

38Marked exception (owner ruling, 2026-08-02): the installed flow's single-place law (spec://org.vibevm.world/git-attribution-policy/flows/attribution-policy/ATTRIBUTION-POLICY#root, its boot snippet's #SCOPE-THE-ONLY-PLACES-THE-TOPIC-IS-DISCUSSED) is deliberately not kept literally by this host's boot surfaces: vibevm/vibespecs/boot/00-core.xml (Rule 1's summary), the CLAUDE.md / AGENTS.md / GEMINI.md triple (byte-identical by contract, gated by self-check step 0c), and the agent instruction files under .claude/agents/ each carry a short digest of the four rules by design — «правила обязаны доезжать до каждого агента на старте»: a session reads its boot files and does not resolve links at boot, so boot reliability wins over single-statement purity. The legal restatement set is exactly: the boot surfaces above; this §12, the host's authoritative record; and the invariant roster's one-line echo (##INV-HUMAN-AUTHORSHIP), which names its source in the same sentence. Everything else cites the flow or this section; a new restatement outside a boot surface is a defect.

13. Package layout convention

  • 39Decision: vibevm packages use a mirror layout. Every entry in a package's writes.files is simultaneously (a) the path of the file inside the package directory and (b) the path at which it will be installed in the consumer's project.
  • There is no separate target = "…" field per entry; writes.files is the single source of truth for "where does this file go?"

40Concretely, the canonical flow:org.vibevm.world/wal@1.0.0 payload under vibevm/vibepacks/org.vibevm.world/wal/v1.0.0/ contains vibevm/vibespecs/flows/wal/WAL-PROTOCOL.xml; after vibe install, the same file lives verbatim under vibevm/vibedeps/org.vibevm.world.wal/1.0.0/vibevm/vibespecs/flows/wal/WAL-PROTOCOL.xml. No mapping, no rewriting.

41Boot snippets are the one exception. The [boot_snippet] table carries an explicit source field naming the path inside the package (conventionally under boot/), while the target is always the fixed vibevm/vibespecs/boot/<filename>.

  • 42Why: a single source of truth for source-and-target paths eliminates a whole class of authoring bug where the package layout drifts from the declared writes.
  • It also makes a package directory instantly readable — a human looking at the tree knows exactly what will appear in a consumer's project without cross-referencing a separate mapping table.
  • Considered and rejected: a per-entry target = "…" field in writes.files — rejected because writes.files would stop being the single source of truth for "where does this file go?" (##NO-TARGET-FIELD), reviving the authoring-drift bug ##MIRROR-WHY-DRIFT names and costing the package directory its at-a-glance readability (##MIRROR-WHY-READABLE). [boot_snippet].source is the one retained exception, not a rejection: its target is the fixed vibevm/vibespecs/boot/<filename> (##BOOT-SNIPPET-EXCEPTION).
  • Revisit when: a second source/target exception is proposed — i.e. any manifest table beyond [boot_snippet] needing an install path that differs from its in-package path. Observation point: the manifest schema in crates/vibe-core — a per-entry target field appearing there is the fired state. One exception stands today; a second means the mirror rule is carrying less than ##MIRROR-LAYOUT claims.
  • 43Where pinned: VIBEVM-SPEC.md §13.1 shows the mirror-layout diagram and §13.2 the matching manifest. This PROP-000 entry is the decision record; the spec carries the operational definition.
  • vibe-install relies on this convention — the source path of a planned write is computed by joining cache_dir with the manifest's declared target path.

14. Manual-test protocol

  • 44Decision: human-runnable smoke-tests live in manual-tests/ at the repo root, one Markdown file per scenario, named <milestone>-<slug>.md (e.g. M1.1-git-registry-smoke.md); the directory's own README.md carries the index.
  • The tier itself — why a project keeps a second, human-run test layer alongside the automated suite, what a manual test is and is not, when to run one, and who signs it off (a human, over an agent's pre-run) — is the manual-tests flow: spec://org.vibevm.world/manual-tests/flows/manual-tests/MANUAL-TESTS-PROTOCOL#root, with the four authoring rules in its authoring-rules document and the copy-ready skeleton in test-template.
  • 45vibevm's real-world surfaces. cargo test --workspace uses fakes, tempdirs, and local bare repositories for speed and hermeticity (the flow's spec://org.vibevm.world/manual-tests/flows/manual-tests/MANUAL-TESTS-PROTOCOL#why-second-tier).
  • The manual tier is the last mile for what only the real world has here: SSH auth against GitVerse, the lockfile source_uri exactly as a downstream consumer receives it, the ~/.vibe/ layout on a user's actual filesystem, and a human confirming the CLI output says what they meant.
  • 46vibevm's bindings. Every test isolates state with mktemp -d for the project and VIBE_REGISTRY_CACHE pointing inside the scratch dir for the registry cache — the user's real ~/.vibe/ is never touched by a run.
  • Git Bash on Windows is the primary smoke-test environment (macOS and Linux must work too); where platform output differs (path separators, .exe suffix), the Windows form comes first with a portable note.

47When to run (the flow's spec://org.vibevm.world/manual-tests/flows/manual-tests/MANUAL-TESTS-PROTOCOL#when, against vibevm's surfaces):

  • 48before tagging any milestone;
  • after changes to the git backend, CLI arg parsing, or lockfile format even when cargo test stays green;
  • and as reproducers whenever a user files an integration bug.

49vibevm/vibespecs/WAL.xml names the outstanding manual runs for the current milestone — a practice that must not lapse: MT-02 and MT-03 have been awaiting owner sign-off since the TUI work landed, and a WAL that names none reads as "nothing pending".

15. Dependency weight is not a decision factor

  • 50Decision: Binary size, crate count, transitive dep weight are NOT decision factors when selecting third-party libraries.
  • Pick the strongest available library for the job — for both the Rust CLI and any future Java / frontend side.
  • 51Why: Software of comparable surface area (Chrome, modern IDEs, production package managers) routinely ships tens to hundreds of dependencies and remains fast and capable.
  • Under-specifying a load-bearing component to save megabytes creates ongoing architectural debt that is much more expensive to repay than the weight it saves. vibevm intends to be best-in-class, and best-in-class means using best-in-class primitives.

52Legitimate reasons to reject a dep:

  • 53non-permissive license (see §3 — MIT / Apache-2.0 / BSD / Unlicense only; GPL / AGPL / LGPL forbidden; MPL-2.0 allowed case by case, since its weak copyleft does not taint consumers),
  • abandoned upstream,
  • demonstrated security issues (CVE history, unpatched known exploit),
  • fundamentally bad API ergonomics that would propagate into our own interfaces.

54"Too heavy" alone is not a reason.

  • 55Concrete consequences: libraries previously rejected on footprint grounds are re-admissible. Notable: libsolv (C, with Rust bindings), git2 (wrapping libgit2), bundled native C deps, embedded interpreters when justified.
  • The size-based argument in PROP-001 §2.1 against git2 is to be pruned — the remaining arguments (Windows SSH auth, shell-out diagnostic clarity) may still carry that decision, but not the size one.
  • Considered and rejected: the predecessor policy — reject a dependency on footprint (binary size, crate count, transitive weight) — rejected, and its consequences already executed in this section: libraries previously refused on footprint grounds are re-admissible, libsolv and git2 named (##READMISSIBLE), and PROP-001 §2.1's size-based argument against git2 is marked for pruning (##PROP-001-PRUNE). Four grounds survive and are the only ones — licence, abandonment, demonstrated security issues, API ergonomics (##REJECT-LICENSE##REJECT-ERGONOMICS); "too heavy" alone is not a reason (##TOO-HEAVY-NOT-REASON).
  • Revisit when: the premise of ##WHY-PRECEDENT — that weight does not cost us — stops holding: a dependency is admitted whose weight measurably degrades a user-visible surface (install time, first-run latency, release binary size), recorded as a finding. Observation points exist today — the release artefact's size and cargo build --timings; numeric thresholds were offered and not set (owner, 2026-08-01), so the trigger is event-shaped until numbers exist.

16. JTD + codegen for wire contracts

  • 56Decision: JSON Type Definition (RFC 8927) schemas are the single source of truth for every client/server and machine-to-machine contract in this project.
  • Rust types — and types in any future non-Rust clients — are generated from JTD schemas via jtd-codegen, not hand-maintained.
  • No client/server duplication is permitted on contracts.
  • 57Why: duplication between a server contract and a hand-written client is a classic source of version-skew bugs; schema-first codegen eliminates that class of bug categorically.
  • JTD specifically (over JSON Schema / OpenAPI alone) because JTD is deliberately narrower: its schema grammar is constructed so every JTD schema maps to a clean static type in every target language, with no language-specific escape hatches.
  • Considered and rejected: JSON Schema / OpenAPI alone — rejected: JTD is "deliberately narrower: its schema grammar is constructed so every JTD schema maps to a clean static type in every target language, with no language-specific escape hatches" (##JTD-OVER-JSONSCHEMA); a hand-written client against each server contract — rejected: that duplication is "a classic source of version-skew bugs" which codegen eliminates categorically (##JTD-WHY-SKEW, ##NO-DUPLICATION). The boundary in the other direction is not a rejection: human-edited manifests stay TOML via serde"JTD is for wire, not for configs humans hand-edit" (##JTD-OUT-OF-SCOPE).
  • Revisit when: either upstream fails us — jtd-codegen ships no release for 24 months (observation point: its upstream repository, version-pinned in tools/jtd-codegen/ per ##TC-BINARY) — or a contract listed in ##JTD-IN-SCOPE proves inexpressible in JTD's grammar and would need an escape hatch, which is the property ##JTD-OVER-JSONSCHEMA bought the narrowness for. Observation point for the second: the first schema in schemas/ that cannot be written.

58In scope: LLM/provider API wrappers, external registry/public-API clients, every generated CLI --json report, MCP tool machine inputs/outputs, lifecycle/install/update/reinstall reports and their evidence members, telemetry/event logs, registered generated machine-state formats such as lifecycle/slot records, and the future hosted-registry HTTP surface. A protocol that must agree across a client/server, surface/library, process, language or release boundary starts here even when one current implementation is Rust.

59Out of scope: human-authored manifests and operator configuration — vibe.toml, vibe.lock, user/project settings — stay TOML via strict serde; tool-local decoders of an upstream protocol's own JSON-Schema arguments may also remain private typed adapters. JTD is for VibeVM-owned machine contracts, not configs humans hand-edit or a duplicate schema for someone else's protocol.

60Toolchain placement:

  • 61jtd-codegen binary in project-local tools/jtd-codegen/ (gitignored; version pinned).
  • Schemas in schemas/ at repo root, one .jtd.json file per contract, committed.
  • Generated Rust code in crates/vibe-wire/src/generated/, committed, with a // DO NOT EDIT — regenerate via cargo xtask codegen header on every file.
  • Regeneration via cargo xtask codegen. CI enforces zero drift (cargo xtask codegen && git diff --exit-code).
  • 62Toolchain install ownership: the coding agent sets up the codegen toolchain itself.
  • Machine-global changes (PATH mutation, admin-level installs, env-var additions) go through runas with an operator confirmation at the moment of the change.

17. Production architecture in the prototype phase

  • 63Decision: Load-bearing surfaces — lockfile schema, registry protocol, dep-resolver semantics, wire formats, identity model — are designed to production quality from day one.
  • The project is a prototype today; the formats and protocols it chooses today are the ones its future users will be bound to. Changing them later is orders of magnitude more expensive than designing them correctly now.
  • 64Lens: "a principal engineer at a top-tier infrastructure company, designing a format or protocol that will be used by millions" is one of the reflection lenses to reach for when a design decision lands.
  • It is not the only lens — "the simplest thing that works" remains valid for leaf features — but architecture-heavy surfaces prefer the principal-engineer lens.

65Consequences:

  • 66Prefer a recent-but-well-designed library over a tactical shortcut, even when the shortcut is cheaper in the short term.
  • Extension points, versioning markers, and forward-compatibility hooks land with the initial cut, not in a later "hardening" pass.
  • Reversibility matters: if a format or protocol decision is hard to reverse (lockfile schema, registry URL scheme, identity hash), lean heavier into design rigour before first commit.
  • "We'll fix it later" is a valid stance only for implementation quality inside a well-chosen architectural surface — not for the surface itself.

18. Complexity expectation: higher than RPM

  • 67Decision: The dependency / package model is designed to handle complexity at least matching RPM-class systems (zypper, DNF), and in several dimensions greater.
  • Manifest grammar and lockfile schema reserve fields for — and the resolver implements — capabilities, provides / requires / obsoletes / conflicts / supplements / recommends, disjunctions (A or B), boolean rich-dep syntax, capability-based resolve, and multi-kind cross-deps. Semantic (LLM-reviewed) conflicts are the one exception: the heuristic static check ships (PROP-003 CHECK-ACTIVATION-CONFLICT); the optional semantic-review feature itself is not implemented even though the provider seam is now real. When it lands it follows PROP-054 ##LLM-ENHANCEMENT-MODES, defaults off and never replaces the static resolver/check. All dependency mechanics were designed in from day one; an optional quality enhancement is not solver authority.
  • 68Why: vibevm's dependency surface is not simpler than RPM — it is wider. A feat package may require a stack providing a specific capability, flows may declare semantic compatibility with other flows, LLM-backed review adds a non-mechanical conflict dimension RPM never had.
  • Undershoot — picking a resolver that lacks virtual packages or disjunctions, or a manifest that cannot express capability-based requires — would force an incompatible schema migration after users exist.
  • 69Resolver choice (pinned in the module PROP): resolvo crate as the primary depsolver.
  • libsolv as an explicit FFI-backed fallback behind a DepSolver trait (analogous to PROP-001 §2.2's GitBackend pattern).
  • PubGrub is rejected for the primary role — its algorithm does not handle virtual packages or disjunctions — but is acceptable for explanatory rendering of conflicts in CLI output if it proves superior there.

19. Load-bearing setup documentation

70Decision: Two files at the repo root are load-bearing for the project:

  • 71DEV-GUIDE.md — contributor-facing: everything to install on a fresh machine to clone, build, test, contribute to, and (if authorized) publish from this repository.
  • RUNTIME-GUIDE.md — user-facing: everything to install and env-configure to run the shipped vibe CLI.

72vibevm's setup docs are DEV-GUIDE.md (contributor / build) and RUNTIME-GUIDE.md (runtime / user). The same-commit obligation that binds them is the dev-runtime-docs flow: spec://org.vibevm.world/dev-runtime-docs/flows/dev-runtime-docs/DEV-RUNTIME-DOCS-PROTOCOL#obligation.

20. Token secrecy and adapter scope

73req r1

  • 74Decision. Publish tokens, registry-API tokens, and any LLM-provider keys handled by vibevm are surface secrets in the sense of the secrets-hygiene flow (spec://org.vibevm.world/secrets-hygiene/flows/secrets-hygiene/SECRETS-HYGIENE-PROTOCOL#surface-secret): their value MUST NOT appear on any surface vibevm produces, though their source (env-var name, file path) may be printed.
  • vibevm's bindings of the flow's four laws (spec://org.vibevm.world/secrets-hygiene/flows/secrets-hygiene/SECRETS-HYGIENE-PROTOCOL#laws):
  • 75Never printed. Not to stdout, stderr, the CLI log, the --json event stream, error messages, panic traces, telemetry, or the lockfile. The CLI prints the source of a token (explicit / env-var name / file path) but never the value. The in-process wrapper types (vibe_publish::Token, future vibe_llm::ApiKey) MUST redact on Display and Debug — verified by unit tests (the flow's spec://org.vibevm.world/secrets-hygiene/flows/secrets-hygiene/SECRETS-HYGIENE-PROTOCOL#law-tested).
  • Never persisted. Not committed to the repository, not written into the lockfile, not embedded in cache files, not landed in the .vibe/ tree. The single sanctioned at-rest location is the operator's ~/.vibe/<host>.publish.token file (per-user, chmod-protected).
  • Sanctioned process boundaries. The token may cross a process boundary only via: (a) the host API's Authorization: Bearer … header, sent over TLS; (b) a single git remote add / git push invocation where the token is embedded in the URL as https://x-access-token:<TOKEN>@host/… (modern git ≥ 2.31 redacts URL passwords in its own log output to ***). No other path is allowed — in particular, never into a spawned third-party hook's environment (the flow's #law-boundaries).
  • Adapter scope. A RepoCreator impl MUST refuse to operate outside the organization specified in the project's [[registry]].url. A publish run targeting github.com/vibespecs may not create, modify, or even probe a repository under a different github.com org or under any user namespace. Adapter implementations carry an explicit org-prefix check and surface a PublishError on attempted scope escalation. (The general integration-scope discipline is the flow's scope-discipline document.)
  • 76Why global, not module-local. The blast radius of a leaked publish token is the entire organization it can reach (cross-repo writes, branch deletes, CI-secret reads); of an escalated adapter, the entire host account (the flow's spec://org.vibevm.world/secrets-hygiene/flows/secrets-hygiene/SECRETS-HYGIENE-PROTOCOL#blast-radius). Both are catastrophic beyond what module-local discipline can bound, so the rules are global and every code path touching a Token or a RepoCreator is audited.
  • On any suspected leak, rotate first (the flow's #leak-drill).

77Where pinned (operationally): PROP-002 §2.10 carries the publish-side mechanics; vibevm/vibespecs/boot/90-user.xml carries the operator-facing rule for this machine. Both are subordinate to this PROP-000 entry.

21. Surface floor — which channels a capability owes

78Decision: a capability lives in a library; the CLI, the TUI and the MCP server are thin surfaces over it. The rule and its vocabulary are the installed omnichannel flow: spec://org.vibevm.world/omnichannel/flows/omnichannel/OMNICHANNEL-PROTOCOL#root. This section declares only vibevm's own floor, which is what that flow asks each project to state for itself.

79vibevm's declared floor: library + CLI + MCP, plus TUI where one exists (vibe tree has one today). A new capability ships with those, or with a recorded reason why one sufficed.

80LSP and IDE extensions are deliberately NOT declared (owner, 2026-08-06: he will open that work himself). By the flow's own rule an undeclared surface is not a debt, so their absence is a choice and not a gap to be closed.

81This is a target, not a description of today. The census that motivated the decision (campaigns/packages-2026-09/harvest/g6-b047-surfaces-census.md) measured the opposite in places: of 29 top-level commands, 19 keep their substance in a separate crate and 10 keep it inside vibe-cli — the largest being the whole vibe self version manager. Of 5 MCP tools, 2 share a library function with their CLI twin, 2 have no CLI twin, and 1 reads the same data as vibe list while building its output by hand.

82The gap is not theoretical. vibe list --json and the MCP query_package printed different values for one field on Windows until 2026-08-06, because each rendered the path itself — two surfaces of one capability answering one question differently, which is exactly the failure this floor exists to prevent.

Invariants

83(These restate the most load-bearing rules from the spec and the book. If anything below seems violated in practice, stop and reconcile before proceeding.)

  1. 84Vocabulary lock, amended by the owner-approved lifecycle. lifecycle and phase are canonical VibeVM terms; their exact grammar is PROP-054 ##VOCABULARY-ADMITTED. goal remains prior-art vocabulary, and plugin is only a precise human umbrella for a package-supplied extension/mechanism implementation or an external ecosystem artifact — never a stored identity or installable kind. The machine nouns are package, extension point/mechanism, contribution, execution and handler/provider. The installable kinds are flow, feat, stack, tool, mcp, lang, doc, app; this set is exact and grows only by owner amendment to VIBEVM-SPEC.md §4.1 (doc and app entered by the amendment of 2026-09-12, PROP-057, pending the owner's ratification at the merge). Bazel/Maven internals outside the admitted set are not imported blindly.
  2. spec/ is fixed. The directory name and role cannot be configured away in v1.
  3. User-owned files are never written by vibe. vibevm/vibespecs/boot/00-core.xml and vibevm/vibespecs/boot/90-user.xml are off-limits to install/uninstall/update.
  4. One commit = one logical unit. Commit messages follow the git-practices family (§12) and reference spec://… URIs where relevant.
  5. Dogfood. vibevm is being built using the same discipline it enforces. The spec/ tree in this repo IS vibe init's reference output.
  6. Human authorship is the only attribution. The posture is the attribution-policy flow (a git-practices member, §12); everywhere else assume human authorship only.
  7. Tokens never appear in vibevm output. See §20. Audited in unit tests; any new code path touching a Token or RepoCreator is reviewed for redaction and scope-escalation safety.

For an agent

This page has a machine mirror. The citation carries the version rather than latest, so what an agent quotes does not move under it.

spec://org.vibevm.core/vibevm@1.0.0/common/PROP-000

.md.xmlllms.txt