A vibe-coding-first programming language: YAML surface (strict subset), static typing, functional core, compiles to WebAssembly.
- Specification: DRAFT.md
- Philosophy: PHILOSOPHY.md
- Schemas and tooling contracts: below
- Examples: examples/
- Container images
- Native toolchain archives
From the repo root (or any directory, using paths as you like—there is no required project layout):
cargo run -- run examples/hello.vibra
# After `cargo install --path .`:
vibra run examples/hello.vibraThis parses the entry .vibra file, resolves $import relative to that file’s directory (Python-style), lowers stdlib-qualified calls from $wasm declarations, and executes them through the current runtime path. Argument forwarding is explicit: call-site args are validated against stdlib signatures and forwarded into the declared $wasm.args contract.
Source execution emits and enters a deterministic WebAssembly module through the versioned vibra_v1 host boundary. See the ABI design for the entrypoint, capability, value-layout, import-validation, and compatibility contract.
vibra code queries and transactionally edits project-owned Vibra files through
typed structural paths. Pipelines can be inline, read from stdin, or loaded from
a file:
vibra code '- $code.file: src/main.vibra
- $code.at: [main, do, 0, "$io.println"]
- $code.replace: Changed'
vibra code - < refactor.vibra
vibra code --file refactor.vibra --writePath strings select mapping keys and non-negative integers select sequence
indices. Query pipelines print YAML. Editing pipelines preview a structured
report and unified diff; --write rechecks source revisions and applies every
changed file atomically.
Available stages include file/path navigation, children/parent traversal, structural find and projection, save/load, replace/delete, mapping insert/upsert/rename, sequence insert/splice, copy/move, and workspace-wide symbol or import-alias rename.
The same structural model is exposed by stdlib/src/code.vibra through forms, typed key/index paths, revision-bound nodes, structural patterns with captures, and every edit primitive. Recoverable operations return typed result enums rather than aborting execution.
vibra exec remains available for evaluating a single Vibra expression:
vibra exec '"hello"' --format rawUse --arg name=value, --arg-file name=path, and --import alias=path to
provide its explicit inputs.
The JSON Schema files in schemas/ describe the machine-readable
Vibra surface used by editors, LSP clients, structural-code tooling, and
automation. They complement the language rules in DRAFT.md; they
are not a complete specification of compiler behavior.
- Source surface:
module-surface.schema.json,function.schema.json,macro.schema.json,type-expr.schema.json,expression.schema.json, andsource-annotations.schema.json. - Projects, packages, and diagnostics:
project-manifest.schema.json,project-lock.schema.json,package-manifest.schema.json,release-metadata.schema.json,diagnostic.schema.json, and the stable code registry inlinter-codes.json. - Structural code:
code-form.schema.json,code-path.schema.json,code-query.schema.json, andcode-change-set.schema.json. - Editor queries:
query-response.schema.jsonspecifies thevibra/contextAt(andvibra query) response shape.
Each schema has a canonical $id under https://vibra.dev/schemas/. Tooling
should use the schema that matches its boundary and treat the expression and
module-surface schemas as deliberately permissive where contextual compiler
validation is required.
Function-shaped $macro declarations expand after import resolution and before
normal lowering/typechecking. $quote, $unquote, and sequence $splice
construct syntax; generated bindings are hygienic, while $capture explicitly
requests caller-scoped syntax.
identity:
$macro:
input: $code.expr-syntax
return: $code.expr-syntax
do:
- $return:
$quote:
$unquote: $args.inputMacro execution is deterministic and limited to 64 nested expansions,
1,000,000 evaluation steps, and 100,000 generated nodes per module load.
vibra expand path/to/module.vibra prints the canonical expanded module.
vibra fmt and vibra lint are YAML-first tooling commands. Their default output is structured YAML for vibe-coding workflows; JSON and SARIF are opt-in compatibility formats for external automation.
vibra fmt # check every .vibra/.vibra.yaml file under .
vibra fmt src --write # rewrite changed files in place
vibra fmt src --output json
vibra lint
vibra lint src --category style
vibra lint src --format json
vibra lint src --format sarif
vibra lint src --deny-warningsvibra fmt is check-only by default. It exits 0 when all files are canonical, exits 1 when check mode finds formatting drift, and only mutates files with --write.
vibra lint emits diagnostics with stable codes, severity, and spans matching schemas/diagnostic.schema.json. Warning-only lint runs exit 0 unless --deny-warnings is set. Errors always fail. YAML # comments are forbidden; use structural annotations:
BadName:
=comment: This external name is intentionally preserved.
=lint:
disable: [W-STYLE-001]
$literal: 1=comment is ignored by compilation. =lint applies to its mapping and
descendants and cannot suppress syntax or compiler errors.
project.vibra is the canonical project manifest. New projects can be scaffolded with:
vibra init hello
vibra init hello --template lib
vibra init hello --template workspacevibra init creates project.vibra, target source files under src/, and an offline stdlib seed under dep/std. The manifest records std as an exact-revision Git dependency on nahharris/vibra-stdlib; vibra sync can reproduce that same tree. Imports remain relative by default; imports beginning with @ resolve through project targets or dependencies and honor a dependency's declared library source root:
io:
$import: "@std/io.vibra"
core:
$import: "@core/lib.vibra"Use vibra sync to export exact Git revisions recursively into package-local dep/<name> trees and write the committed project.lock.vibra. Exported trees contain no Git metadata. The lock records identities, exact revisions, SHA-256 tree hashes, vendor paths, and alias edges. vibra check validates the lock, rejects modified vendor trees, and then validates targets, dependencies, and @ imports:
vibra sync hello
vibra check helloSee docs/project-layout.md and schemas/project-manifest.schema.json.
vibra build produces a deterministic .vapp ZIP containing the selected bin's
program.wasm, its complete project and vendored dependency source graph, and a
SHA-256 inventory in package.vibra. Timestamps, permissions, compression, and
entry ordering are fixed, so identical inputs produce identical bytes:
vibra build hello --output hello.vapp
vibra package inspect hello.vapp
vibra package verify hello.vapp
vibra run hello.vappUse --bin <name> when a project declares multiple bin targets. Verification
rejects missing, modified, duplicate, undeclared, or path-unsafe entries before
execution. The metadata contract is documented by
schemas/package-manifest.schema.json.
The compiler repository pins that same stdlib revision as the stdlib Git submodule. Clone contributors' checkouts with git clone --recurse-submodules, or initialize an existing checkout with git submodule update --init --recursive.
Functions use canonical labeled declarations: $function: $void for zero arguments, $function: $self for a method receiver, or a singleton labeled mapping for the primary argument. Additional arguments use sibling args:, and function bodies reference every argument through $args.<name>.
Policies: authority roots declare aggregate $policy arguments. The runtime
intersects those declarations with --allow-* approvals, then code explicitly
narrows the live value with $policy.narrow into a typed
$capability.<domain> argument for privileged helpers.
vibra run examples/fs-roundtrip.vibra --allow-read=. --allow-write=.Filesystem policy checks use canonical ancestry: a dir scope for path/root does not authorize a sibling such as path/root2.
Host ABI: $wasm is a checked binding to the closed vibra_v1 registry,
not an authority escape hatch. The compiler validates the module/import pair,
every argument and capability domain, and the exact return type. Run
vibra effects <path> to inspect the reachable host surface without executing it.
Current subset: entry module defines main with args: $void, return: $void, and a do: sequence of stdlib-qualified calls (including $let bindings of non-void returns and ordered $match sequence arms with explicit case: entries). Entry and imported modules may also define user functions (do: with $let / $match / $return) and generic functions ($function with the =where annotation declaring type parameters and bounds); generic calls pass explicit type arguments in the same mapping as value arguments (see DRAFT.md). io and fs functions declared in stdlib/src/io.vibra and stdlib/src/fs.vibra are executable via the runtime execution backend.
- Primitive numerics:
$int8/$int16/$int32/$int64,$uint8/$uint16/$uint32/$uint64,$float32/$float64 - Explicit annotations are required on function signatures (
args+return) - Algebraic unions are supported in lowering with direct syntax (
$union: [...],$enum: {...}, constructors,$match); optional values use the taggedstdlib/src/option.vibraenum because$optionsugar and direct$voidunion members are rejected - Value patterns use the single ordered-arm
$match: <expr>plus siblingwhen:form; pattern variables are written as{ $bind: name }, wildcard as{ $wildcard: null }, and arm bindings remain local to the arm - Generic functions and types declare type parameters via the
=whereannotation; call sites pass type params as keys alongside value args (e.g.{ $f: { t: $int64, x: 7 } }) $newtypecreates nominal wrappers that require explicit$castto cross to/from the inner type; transparent aliases still coerce implicitly, and other conversions use explicit$from/$intointerface calls=wherebounds (t: [$some-iface, ...]) are checked nominally against=implblocks at call sites and type-position instantiations (E-BOUND-001)- Inherent operations on a type live under its
=defsannotation; explicit interface implementations live under=impland use the reserved$selftype to refer to the implementing type - Interface methods can be invoked type-qualified (
$type.iface.method: { ... }) or, when the method has a$self-typed argument, interface-qualified ($iface.method: { x: $val, ... }) -- the compiler dispatches on the static type of the$selfargument - Rust-inspired tagged enums available:
Import option and instantiate its generic type explicitly:
option:
$import: ./stdlib/src/option.vibra
maybe-name:
$record:
value:
$option.option:
t: $strConstruct values with $option.option.some: "name" or $option.option.none.
io/fsAPIs use nominalpath,bytes, and file-mode types, withreadable/writable/appendable/closeableinterfaces to reject invalid file-mode operations- Kebab-case is recommended for every symbol; non-kebab symbols emit warnings
# Interactive stdin path
cargo run -- run examples/ask-name.vibra
# Filesystem roundtrip (requires explicit approval)
cargo run -- run examples/fs-roundtrip.vibra --allow-read=. --allow-write=.vibra test discovers .vibra files under tests/ and runs each top-level
$test declaration as an isolated test case. Test modules do not need main.
The $test value is a non-empty kebab-case profile; a bare vibra test runs
the capability-free core profile.
test:
$import: "@std/test.vibra"
truth:
$test: core
do:
- $test.assert: truevibra test
vibra test --filter truth
vibra test --profile core --tag language
vibra test --deny-skips --deny-warnings
vibra test --jobs 4 --timeout-ms 30000 --fail-fast
vibra test --report yaml --report-file report.yamlProfiles and tags only select tests; they never confer host permissions.
Capability tests declare sibling policy and must be run with the matching
explicit --allow-* flag. workspace: temp tests additionally need
--allow-test-workspace read, write, or read-write; without it, they are
reported as skipped. See tests/README.md for expected
errors, typed assertion helpers, profile contracts, and the complete flag
reference.
Files named foo.*.vibra are loaded as parts of the same module as
foo.vibra when foo.vibra exists. A common convention is to place unit
tests beside the module in foo.test.vibra; the suffix is only a naming
convention and does not carry special semantics.
cargo build
cargo testMIT OR Apache-2.0 (see Cargo.toml).