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

PROP-036: vibe tree — the spec-tree analyzer

01Status: IMPLEMENTED (requirements authored 2026-07-15 at the owner's request; the PACKAGE-TREE-PLAN executed against them, verified against the tree 2026-07-25 by the spec-actualization campaign — vibe tree --json validates against the shipped package-tree.schema.v1.json per its own --help, and -t is live). Governs the vibe tree command in crates/vibe-cli. Written in the post-rename link vocabulary (PROP-035): two link types, static and dynamic.

02Related: PROP-009 §2.4 (the static/dynamic link types + when), PROP-009 §2.3 (STATIC.md / INDEX.md), PROP-034 (static-transitive), PROP-035 (@spec in-place uses, STATIC.md markers), PROP-002 §lockfile (the resolved graph). Plan: PACKAGE-TREE-PLAN-v0.1.

03Non-goal (deferred): the runtime "what the agent actually loaded" skill and a GUI client — a future tool:org.vibevm.core/package-tree (§7).

1. Motivation

  • 04A project's boot is composed by vibe from a dependency closure (PROP-009): some packages are compiled verbatim into STATIC.md, others are read by reference from INDEX.md, some carry an OS when, and static-transitive edges (PROP-034) silently promote whole subtrees.
  • Today a human cannot see this at a glance — what is connected, and how does it load?
  • vibe tree answers that algorithmically: it renders the resolved package tree annotated with the effective load type and the flags that explain it, and emits the same data as JSON for downstream tools.

2. Decisions

2.1 The command

  • 05vibe tree is a read-only analyzer over the current project. It mutates nothing (REQ: never writes to the tree, manifests, lockfile, or artifacts).
  • It operates on the workspace discovered from --path (default .), reading the committed vibe.lock, the node manifests, and the generated boot artifacts.

06Three output surfaces:

  • 07interactive TUI — the default on a tty (§2.11);
  • --json — the machine surface (§2.7), the same data a GUI consumes;
  • plain — a static ASCII tree when not on a tty, or under --plain.
  • 08--json and --plain never launch the TUI.
  • The command is Tree(TreeArgs) in the CLI surface; --json/--quiet are the global flags (never redeclared).

2.2 Row semantics — the columns

09Each package is one row. Columns, left to right (REQ: this order):

  1. 10name — the tree column: group/name, drawn with indentation + branch glyphs + an expand/collapse indicator when the node has children.
  2. load — the effective load type (§2.3): static, dynamic, or none.
  3. T (transitive) — a checkbox: the effective static was forced by a static-transitive ancestor, not the package's own declaration (§2.4).
  4. C (condition) — a checkbox: the boot entry carries a when (§2.5).
  5. S (STATIC.md) — a checkbox: the package physically contributes a block to STATIC.md.
  • 11T, C, S are the "checkbox" cluster; load is a value column.
  • Detail beyond a checkbox (the full when text, the source path) is shown on demand (§2.11), never crammed into the row.

2.3 Effective load type

12The load value is the lane a package's boot snippet actually lands in, read from the committed artifacts (REQ):

  • 13static — the package appears as a <!-- vibe:static {origin} … --> contribution in STATIC.md (origin = group/name).
  • dynamic — the package's boot file appears as an [[entry]] in INDEX.md.
  • none — the package ships no [boot_snippet], so it contributes to neither lane (e.g. a content-minimal family aggregator, PROP-028).

14Decision — read the effective type from the artifacts, not a fresh recompute.

  • 15Why: the committed STATIC.md / INDEX.md are exactly what an agent reads at boot; the tool's job is to show that reality ("what is actually loaded"). A stale artifact is a fact the human needs, not one to hide.
  • Considered and rejected: recomputing EffectiveBoot fresh every run — shows what should be, masking drift the tool exists to reveal.
  • When to revisit: if the artifacts stop being committed (generated on-demand), the source of truth moves to the recompute; until then the committed lane is canonical, cross-checked by §2.10.

2.4 The transitive flag

  • 16T is set (REQ) iff the package's effective type is static and that static-ness was inherited from an ancestor edge declared static-transitive (PROP-034), rather than from the package's own consumer-declared link, its own [boot_snippet].link suggestion, or a direct static edge.
  • The static-transitive declarer itself carries T = false (its static-ness is its own declaration); every member of its closure that is not otherwise static carries T = true.

2.5 The condition flag

  • 17C is set (REQ) iff the package's boot entry carries a when condition (PROP-009 §2.4; wire form os:<name>).
  • A when forces the entry dynamic regardless of link (so C = true implies load = dynamic).
  • The full condition text is surfaced only in the detail view (§2.11) and the JSON (§2.7), never in the row.

2.6 The STATIC.md size indicator

  • 18The status line shows the size of the statically-compiled lane: the byte count and line count of STATIC.md (REQ).
  • This is the "how much am I loading verbatim every session" budget the human watches.

2.7 JSON output

  • 19vibe tree --json emits one object, the same data model the TUI renders, valid against the shipped schema (REQ: schema_version = 1).
  • The envelope follows the CLI convention ({"ok": true, "command": "tree", …}).
  • The model carries: the project context, the declared roots, the packages array (each with load {type, transitive, declared, origin, in_static_md, in_index_md, boot_path} and condition), the two boot lanes under boot (static_md/index_md, with the lane sizes), the collected in_place_specs (§2.9), and diagnostics (§2.10).
  • Display state (mode, ordering, tab, selection) is TUI-only and is not in the JSON.
  • Schema home: crates/vibe-cli/resources/package-tree.schema.v1.json.

2.8 STATIC.md decompilation

  • 20vibe tree decompiles STATIC.md into its contributions (REQ): each <!-- vibe:static {origin} — {path} --> marker opens a region running to the next marker or EOF; the region yields origin (the source group/name or host rel-path) and path (the workspace-relative source file).
  • Nested <!-- embed: {addr} --><!-- /embed: {addr} --> pairs within a region are attributed as embed spans.
  • This is a dedicated decompiler for the on-disk vibe:static open-marker format — it is not vibe_spec::decompile(), which parses the distinct vibe:begin/vibe:end compiler format and returns empty on STATIC.md.

2.9 In-place @spec collection

  • 21vibe tree collects the in-place boot-lane spec markers (REQ): @spec:// uses and #use / #embed / #source directives, via the canonical fence-aware vibe_spec::Directives::parse.
  • A bare spec:// (no @) is discretionary and is not collected.
  • (Out of scope: the #[spec(...)] code-traceability surface — that is PROP-014.)

2.10 Diagnostics

22vibe tree reports, non-fatally (REQ: never aborts rendering on these):

  • 23stale-artifacts — the committed lanes disagree with a fresh EffectiveBoot recompute (the tree needs vibe reinstall).
  • root-driftvibe.lock meta.root_dependencies disagrees with the root vibe.toml [requires.packages] (the lock is behind).

24Each diagnostic carries a severity, a stable code, a message, and an optional locator.

2.11 The interactive TUI

25On a tty (default), vibe tree is an interactive pseudographic browser (REQ). Contract:

  • 26Navigation: / move the selection (the table scrolls to keep it visible; the selected row is highlighted); / pan horizontally when the tree is wider than the viewport.
  • The key bindings sketched in this section are superseded. This §2.11 is the analyzer-era sketch; the shipped keymap is PROP-037 Spec 2's F-key scheme, and it is normative there — this section names the capabilities, never the keys.
  • Folding: the selected node folds and unfolds (shipped as the fold.toggle action, PROP-037 §13.5). The whole-tree fold sketched here was not carried into Spec 2 and does not ship — the action catalogue has fold.toggle only.
  • Detail: Enter opens a modal showing the row's full detail vertically (name, group, version, kind, load type, transitive + why, condition full text, STATIC.md membership, source, content hash, dependencies, boot file); Esc closes it. Quitting is Esc plus a confirm dialog (PROP-037 §7.4), not the bare q this sketch assumed.
  • Ordering (shown in the status line): topological (the analysis order, default) ↔ alphabetical. Chosen from the F2 sort menu (PROP-037 §7.2, which replaces any bare mode-cycle key).
  • Display mode: (a) all-together tree; (b) two stacked sub-tables static dependencies / dynamic dependencies (a header line each); (c) two tabs Static / Dynamic, with a swappable static/dynamic priority in (b) and (c). Modes are chosen from the F3 menu and tabs switch with Shift+arrows (PROP-037 §4.4 / §5.3).
  • Status line: current ordering · current display mode · the STATIC.md size indicator (§2.6).
  • Fallback: non-tty and --plain render a static ASCII tree; --json the JSON — neither enters interactive mode.

2.12 The graph is a DAG

  • 27The dependency graph has diamonds (a shared package reached by several parents).
  • vibe tree renders each package under each parent, marks a re-occurrence with a trailing (*) and does not re-expand it, and cycle-guards the walk on the package's qualified group/name (REQ).
  • The flat display modes (§2.11) collapse the DAG to one row per package.

2.13 Project resolution — VibeTree works from anywhere

28vibe tree shows a project's tree, so it needs one — but a GUI launcher (VibeTree.exe / a Start-menu shortcut) or an arbitrary shell may sit outside any project. The launchers live in the vibevm-term products repo with vibeterm and vibeframe (PROP-019 §STEP-VIBE-ONLY), and are governed there — this host contract only specifies what vibe tree does when invoked from outside a project.

29Resolution order for the human surfaces (the TUI and -t; not --json, a scripting surface resolved strictly from --path) (REQ):

  1. 30The given path--path (default: cwd, walked up for vibe.toml). On success it is recorded as the last project (vibe.tree.last-project, an L1 setting), so a later context-free launch reopens it. An explicit --path that is not a project is a hard error — never silently redirected.
  2. The remembered last project — when the cwd is not a project and no explicit --path was given, the recorded last-project opens (if it is still a project).
  3. A folder picker — a -t (VibeTree / GUI) launch with neither of the above opens a native folder chooser; the pick is recorded as the last project. Cancelling is a clean no-op (no error dialog), never a failure.

31A console launch (no -t) with neither a cwd project nor a memory keeps the original run vibe init guidance.

3. Data sources

32vibe tree joins, using the canonical parsers (REQ — no re-implemented format readers where a vibe-* crate already parses it):

  • 33graphvibe.lock (vibe_core::manifest::Lockfile): roots from meta.root_dependencies, edges from each LockedPackage.dependencies.
  • links — the node manifests (vibe_core Requires): consumer declared_link + the target's [boot_snippet] suggested link + when.
  • effective lanes + sizes — the committed vibevm/vibespecs/boot/STATIC.xml + vibevm/vibespecs/boot/INDEX.md.
  • cross-checkvibe_workspace EffectiveBoot (for the stale-artifacts diagnostic).
  • in-place specsvibe_spec::Directives::parse.

4. Non-goals

  • 34The runtime skill / prompt — inferring what the agent actually loaded at runtime (the loading spec://… convention, .vibe/ logging, multi-agency) is deferred to tool:org.vibevm.core/package-tree.
  • A GUI client — deferred to the same future package; the --json schema is its contract.
  • Spec-graph validationvibe tree attributes and reports; it does not validate spec:// targets.
  • Mutation — never; see §2.1.

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/modules/vibe-cli/PROP-036-package-tree

.md.xmlllms.txt