A stack-VM scripting language and distributed workflow runtime
Project description
Nodus
Nodus is a lightweight, practical scripting language implemented in Python. It targets small scripts and automation tasks with a clean module system, a compact standard library, and predictable tooling.
Architecture:
source -> lexer -> parser -> AST -> module loader -> bytecode compiler -> optimizer -> VM -> scheduler -> orchestration/runtime services
Quick links:
docs/onboarding/GETTING_STARTED.mddocs/language/FORMAT.mddocs/tooling/EDITOR_SUPPORT.mddocs/tooling/LSP.mddocs/tooling/DEBUGGING.mddocs/governance/STABILITY.mddocs/tooling/TESTING.mddocs/runtime/TASK_GRAPHS.mddocs/runtime/WORKFLOWS.mddocs/runtime/RUNTIME_EVENTS.mddocs/runtime/PROFILER.mddocs/tooling/REPL.mddocs/tooling/PROJECTS.mddocs/tooling/PACKAGE_MANAGER.mddocs/runtime/SERVER_MODE.mddocs/governance/VERSIONING.mddocs/governance/RELEASE_NOTES_0.2.0.mddocs/governance/TECH_DEBT.mddocs/governance/DEPRECATIONS.md
Example
import { repeat } from "std:strings"
import "std:collections" as c
fn greet(name) {
return "hello " + name
}
let nums = [1, 2, 3]
print(greet("Nodus"))
print(repeat("ha", 2))
print(c.list_sum(nums))
Run it:
nodus run examples/hello.nd
Getting Started
- Install (editable):
pip install -e .
- REPL:
python -m nodus.tooling.repl - Run script:
nodus run script.nd - Profile script:
nodus profile examples/demo.nd - Check script (no execution):
nodus check script.nd - Format script:
nodus fmt script.nd - Run examples:
nodus test-examples - Service mode:
nodus serve(HTTP runtime server) - Language server:
nodus lsp - Debug adapter:
nodus dap - Session snapshots:
nodus snapshot <session>,nodus snapshots,nodus restore <snapshot> - Version:
nodus --version
Project setup and dependencies:
- Initialize project:
nodus init - Install dependencies:
nodus install - Update dependencies:
nodus update - Show module dependency graph:
nodus deps - List installed package dependencies:
nodus package-list
Project manifests:
nodus.tomldefines project metadata and dependencies.src/main.ndis the default project entrypoint created bynodus init.nodus.lockpins resolved dependency sources and hashes.
Backward compatible invocations are still supported:
python language.py script.ndpython tiny_vm_lang_functions.py script.nd
Common Commands
nodus fmt script.nd(format to canonical style)nodus fmt script.nd --check(CI-friendly formatting check)nodus fmt script.nd --keep-trailing(keep trailing comments inline when possible)nodus check script.nd(fast validation without running)nodus ast script.nd(print parsed AST)nodus ast script.nd --compact(compact AST view)nodus dis script.nd(print compiled bytecode without running)nodus dis script.nd --loc(include source locations in bytecode)nodus run script.nd(execute)python -m nodus.tooling.repl(interactive REPL):help,:ast <expr>,:dis <expr>,:type <expr>(inside the REPL)nodus run script.nd --trace --trace-limit 50(short trace)nodus run script.nd --trace-events(runtime event stream)nodus run script.nd --trace-json --trace-file trace.json(machine-readable events)nodus run script.nd --trace-scheduler(scheduler tracing)nodus run script.nd --no-opt(disable bytecode optimization)nodus run script.nd --step-limit 100000 --time-limit 5 --output-limit 20000(sandbox limits)nodus run script.nd --allow-paths <paths>(filesystem allowlist)nodus profile examples/demo.nd(runtime profiler report)nodus debug script.nd(interactive debugger)nodus dap(Debug Adapter Protocol over stdio)nodus install(install project dependencies to.nodus/modules/)nodus update(refresh dependencies and lockfile)nodus deps(print the incremental compilation dependency graph)nodus package-list(list package manifest/lockfile dependencies)nodus cache clear(remove cached compiled modules from.nodus/cache/)nodus test-examples(quick smoke test)nodus serve --port 7331(HTTP runtime server)nodus lsp(Language Server Protocol over stdio)nodus serve --allow-paths <paths>(restrict filesystem builtins in server mode)nodus serve --auth-token <token>(require Authorization header)nodus snapshot <session>(save session snapshot)nodus snapshots(list snapshots)nodus restore <snapshot>(restore snapshot to new session)nodus worker --host <host> --port <n>(register a worker with a server) Orchestration commands:nodus graph <script.nd>(plan a task graph from a script)nodus workflow-run <script.nd> [--workflow <name>]nodus workflow-plan <script.nd> [--workflow <name>]nodus workflow-resume <graph_id> [--checkpoint <label>]nodus workflow-checkpoints <graph_id>nodus workflow list [--project-root <path>]nodus workflow resume <graph_id> [--checkpoint <label>] [--project-root <path>]nodus workflow cleanup [--project-root <path> --retention-seconds N --force]nodus goal-run <script.nd> [--goal <name>]nodus goal-plan <script.nd> [--goal <name>]nodus goal-resume <graph_id> [--checkpoint <label>]
Debug example:
$ nodus debug workflow.nd
(nodusdb) break workflow.nd:12
(nodusdb) run
(nodusdb) step
(nodusdb) print user_id
Runtime service commands:
nodus tool-call <tool> --json <payload>nodus agent-call <agent> --json <payload>nodus memory-get <key>nodus memory-put <key> --json <value>nodus memory-delete <key>nodus memory-keys
Language Files
- Primary extension:
.nd - Legacy extension supported:
.tl
IDE Support
Nodus ships baseline editor support for syntax highlighting and snippets, plus a minimal Language Server Protocol implementation for diagnostics, completion, hover, and go-to-definition.
- Syntax highlighting and snippets:
docs/tooling/EDITOR_SUPPORT.md - Language server documentation:
docs/tooling/LSP.md - Debugging documentation:
docs/tooling/DEBUGGING.md - Start the language server with
nodus lsp - Start the debug adapter with
nodus dap
Debugging
Nodus exposes two debugger entrypoints:
nodus debug script.ndfor the built-in interactive debuggernodus dapfor IDE clients that speak the Debug Adapter Protocol
The DAP adapter reuses the existing runtime debugger, supports source-line breakpoints, continue/pause/step controls, stack traces, and variable inspection for arguments and locals.
Core Features
- numbers, booleans, strings, nil
- lists, maps, and records
- functions and recursion
- if / else, while, for
- imports and namespaced imports
- explicit exports and selective imports
- built-in stdlib modules (imported via
std:) - builtins including file I/O
- coroutines and channels
- workflow/goal syntax and task graphs
- REPL
- line/column errors + stack traces
- bytecode dump and trace mode for debugging
- bytecode version headers for forward compatibility
- embeddable Python runtime with host function registration
- sandbox limits for steps, time, and stdout output
- runtime module loader with per-module bytecode units
- on-disk bytecode cache for compiled modules in
.nodus/cache/ - scheduler fairness with round-robin queueing and per-task instruction budgets
- persisted dependency graph for incremental compilation in
.nodus/deps.json - per-module global namespace isolation
- project manifests (
nodus.toml) with dependency resolution andnodus.lock
REPL
Start the REPL with python -m nodus.tooling.repl.
The REPL now supports multiline editing for brace-delimited blocks, persistent history via ~/.nodus_history, and interactive inspection commands.
> fn add(a, b) {
... return a + b
... }
> :ast 1 + 2 * 3
Binary(+)
Number(1)
Binary(*)
Number(2)
Number(3)
> :dis 1 + 2
PUSH_CONST 1.0
PUSH_CONST 2.0
ADD
RETURN
> :type [1, 2, 3]
List<number>
Imports
import "lib/math.nd"import { add, sub } from "lib/math.nd"import "lib/math.nd" as mathimport "std:strings"import { repeat } from "std:strings"export { add } from "./math.nd"
Import resolution rules:
- Project dependencies resolve from
.nodus/modules/(installed bynodus install/nodus update). std:prefix resolves to the built-instd/directory (e.g.std:strings).- Relative paths start with
./or../and resolve from the importing file. - Non-relative paths resolve from the project root (the entry script directory by default).
- Project root override precedence:
--project-root <path>>NODUS_PROJECT_ROOT> entry script directory. - Extension handling: if no extension is provided,
.ndis preferred, then.tlas legacy fallback, thenindex.nd/index.tl.
Resolution order examples:
import "std:strings"->std/strings.nd(fallbackstd/strings.tl)import "./utils"fromsrc/main.nd->src/utils.nd(fallbacksrc/utils.tl)import "lib/math"fromsrc/main.nd-><project_root>/lib/math.nd(fallback.tl)import "./utils"fromsrc/main.nd->src/utils.nd, thensrc/utils.tl, thensrc/utils/index.nd, thensrc/utils/index.tl
Exports
export let pi = 3.14159export fn add(a, b) { return a + b }export { add, sub }
Notes:
- If a module uses any
exportdeclaration, only those names are visible to importers. - Legacy modules with no
exportdeclarations export all top-levellet/fn/assignment names.
Example (private names are not visible):
// math.nd
let secret = 10
export fn add(a, b) { return a + b }
// main.nd
import { add } from "math.nd"
print(add(1, 2))
print(secret) // error: not exported
Re-exports:
// api.nd
export { add } from "./math.nd"
Built-ins
Core: clock, type, str, len, print, input, keys, values
File utilities: read_file, write_file, append_file, exists, mkdir
AI/runtime adapters: tool_call, tool_available, tool_describe, memory_get, memory_put, memory_delete, memory_keys, agent_call, agent_available, agent_describe, emit, run_goal, plan_goal, resume_goal
Bytecode Versioning
Compiled bytecode includes a version header:
{
"bytecode_version": 1,
"module_name": "<module>",
"instructions": [...],
"constants": [],
"exports": [],
"metadata": {}
}
The VM validates the version when loading and raises BytecodeVersionError for unsupported versions.
Embedding In Python
Nodus can be embedded in Python applications:
from nodus.runtime.embedding import NodusRuntime
rt = NodusRuntime()
def send_email(addr, body):
return True
rt.register_function("send_email", send_email, arity=2)
rt.run_file("workflow.nd")
Host functions are callable from Nodus scripts and runtime errors propagate back to the host.
Sandbox Runtime Limits
Runtime execution can be constrained by:
- step limit (instruction count)
- time limit (seconds via CLI, milliseconds in the API)
- output limit (stdout character cap)
When a limit is exceeded, the runtime raises RuntimeLimitExceeded (surfaced as a sandbox error in CLI results).
Standard Library
Modules (import with std: prefix):
std:strings-upper,lower,trim,split,contains,repeat,is_blank,joinstd:collections- collection helpers and list mutation helpersstd:json-parse,stringifystd:math- numeric helpersstd:fs- filesystem helpersstd:path- path helpersstd:runtime- reflection, scheduler stats, runtime eventsstd:tools-execute,available,describestd:memory-get,put,delete,keys,hasstd:agent-call,available,describestd:async- coroutine and channel helpersstd:utils- small utility helpers
Notes:
- Tools currently dispatch to local adapters for
nodus_execute,nodus_check,nodus_ast, andnodus_dis. - Agents are local handler adapters in phase 1. Unregistered agents return a structured error instead of invoking an external provider.
- Memory stores JSON-safe values. Without a session it is process-local; in server sessions it is session-local.
AI-Native Workflow Pattern
Nodus keeps the language core small and adds agent, tool, and memory behavior through explicit built-ins and stdlib modules:
import "std:agent" as agent
import "std:memory" as memory
import "std:tools" as tools
workflow ai_pipeline {
state topic = "AI SEO"
step research {
let notes = tools.execute("nodus_check", {
"code": "print(1 + 1)",
"filename": "inline.nd"
})
memory.put("notes", notes)
return notes
}
step summarize after research {
return agent.call("summarize", {
"input": memory.get("notes")
})
}
}
Keep these semantics distinct:
- Workflow
stateis durable per-workflow execution state. memory.*is shared runtime memory outside workflow state.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nodus_lang-1.0.0.tar.gz.
File metadata
- Download URL: nodus_lang-1.0.0.tar.gz
- Upload date:
- Size: 220.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d7e60c545c9a02020c74c140b5bcf010e0a24a20592584bff40b0ed3b89e927e
|
|
| MD5 |
33c016ab395fcc36773d7e87f538363e
|
|
| BLAKE2b-256 |
12a943859fd379635186a7c8ecee405c9f525241d66181d3213af8798d629b22
|
File details
Details for the file nodus_lang-1.0.0-py3-none-any.whl.
File metadata
- Download URL: nodus_lang-1.0.0-py3-none-any.whl
- Upload date:
- Size: 193.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
210ce4f4475569d87640a925569e9ddea179446203cc52dca2a404d1cedc0d5a
|
|
| MD5 |
40bd1cc98c1f115e7ef346c9c5dcadb6
|
|
| BLAKE2b-256 |
ca5a3e7012657bcf59ada9e054a3e675701bd28db5bc0f159c121ff712d0c06f
|