Architecture Overview
Devlish compiles human-readable .dvl source files through a multi-stage pipeline into bytecode that runs in a lightweight VM. The entire toolchain is implemented in Rust with zero runtime dependencies.
Pipeline
Section titled “Pipeline”.dvl source -> Parser -> AST -> Compiler -> Bytecode (.dvlc.json) -> VMEach stage is independent and inspectable:
- Source: Human-readable English-like syntax
- Parser: Converts source lines into typed statements
- Compiler: Emits bytecode instructions with a constant pool and source map
- VM: Executes bytecode with host-provided effects
CLI Commands at Each Stage
Section titled “CLI Commands at Each Stage”# Validate source syntaxdevlish validate program.dvl
# Compile to bytecodedevlish compile program.dvl --output program.dvlc.json
# Inspect compiled bytecodedevlish disassemble program.dvlc.json
# Execute (from source or bytecode)devlish run program.dvl --input '{"key": "value"}'devlish run program.dvlc.json --input '{"key": "value"}'Crate Structure
Section titled “Crate Structure”The Rust workspace contains six crates:
| Crate | Purpose |
|---|---|
devlish_core |
Parser, compiler, CLI binary. Converts .dvl to bytecode JSON. |
devlish_vm |
Bytecode VM. Executes instructions via the HostEffects trait. |
devlish_wasm_runner |
WASM build of the VM for browser and Node embedding. |
devlish_wasm_compiler |
WASM build of the compiler for in-browser compilation. |
devlish_toolrun |
Command wrapper for token-saving output compression. |
devlish_geocivic |
Domain-specific Energy Community verification tool. |
No Runtime Dependencies
Section titled “No Runtime Dependencies”The design goal is that compiled Devlish programs carry no runtime beyond the VM:
- No Ruby, Python, or Node required to execute
- The WASM VM runs in any WebAssembly host
- The native VM runs as a single static binary
- Bytecode packages are self-contained JSON artifacts
Bytecode Package Format
Section titled “Bytecode Package Format”A compiled .dvlc.json file contains:
{ "format": "devlish-bytecode", "format_version": 0, "compiler_version": "0.1.0", "constant_pool": [1000000, "approved", true], "instructions": [ {"op": "CONST", "dest": "r0", "const": 0}, {"op": "STORE", "name": "threshold", "src": "r0"} ], "source_map": [ {"line": 1, "source": "threshold equals 1000000"} ], "manifest": null}Execution Targets
Section titled “Execution Targets”The same bytecode runs in three contexts:
- Native CLI:
devlish runwith full host effects (files, HTTP, services) - WASM sandbox:
devlish-runtimenpm package with restricted effects - MCP server:
devlish mcpserving tools to LLM clients
Import Resolution
Section titled “Import Resolution”When a program uses Import, the compiler searches:
- The directory containing the source file
- The project root (where
devlish.tomllives) devlish/andlib/under the project root- Paths in the
DEVLISH_PATHenvironment variable ~/.devlish/lib/standard library path
Imports are resolved and inlined at compile time. The resulting bytecode is self-contained.