Skip to content

nahharris/vibra

Repository files navigation

Vibra

A vibe-coding-first programming language: YAML surface (strict subset), static typing, functional core, compiles to WebAssembly.

Run (MVP)

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

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

Structural code tools

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 --write

Path 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 raw

Use --arg name=value, --arg-file name=path, and --import alias=path to provide its explicit inputs.

Schemas and tooling contracts

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.

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.

Macros

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

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

Format and lint

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-warnings

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

Projects

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 workspace

vibra 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 hello

See docs/project-layout.md and schemas/project-manifest.schema.json.

Executable application packages

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

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

Type System Snapshot

  • 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 tagged stdlib/src/option.vibra enum because $option sugar and direct $void union members are rejected
  • Value patterns use the single ordered-arm $match: <expr> plus sibling when: 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 =where annotation; call sites pass type params as keys alongside value args (e.g. { $f: { t: $int64, x: 7 } })
  • $newtype creates nominal wrappers that require explicit $cast to cross to/from the inner type; transparent aliases still coerce implicitly, and other conversions use explicit $from / $into interface calls
  • =where bounds (t: [$some-iface, ...]) are checked nominally against =impl blocks at call sites and type-position instantiations (E-BOUND-001)
  • Inherent operations on a type live under its =defs annotation; explicit interface implementations live under =impl and use the reserved $self type 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 $self argument
  • 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: $str

Construct values with $option.option.some: "name" or $option.option.none.

  • io/fs APIs use nominal path, bytes, and file-mode types, with readable/writable/appendable/closeable interfaces to reject invalid file-mode operations
  • Kebab-case is recommended for every symbol; non-kebab symbols emit warnings

Examples

# 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=.

Tests

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: true
vibra 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.yaml

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

Build & test

cargo build
cargo test

License

MIT OR Apache-2.0 (see Cargo.toml).

About

Vibe-coding-first language: YAML surface, WASM target

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages