Install
$ agentstack add mcp-peytonnowlin-nebula ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Nebula
[](https://github.com/PeytonNowlin/Nebula/actions/workflows/ci.yml)
[](https://github.com/topics/programming-language) [](https://github.com/topics/domain-specific-language) [](https://github.com/topics/static-typing) [](https://github.com/topics/compiler) [](https://github.com/topics/rust) [](https://github.com/topics/python-transpiler) [](https://github.com/topics/ai-agents) [](https://github.com/topics/agentic) [](https://github.com/topics/llm) [](https://github.com/topics/mcp)
Nebula is a typed orchestration language for AI agents, MCP tools, and operational runbooks. Author deterministic workflows in Nebula and deploy them anywhere Python runs.
Nebula trades symbolic brevity for machine legibility: operators are keywords (plus, eq, lt), types are always explicit, and the toolchain speaks JSON — structured diagnostics, AST export, IR export, and run records with stable NEB-* error codes.
Author in Nebula, ship as Python. Agents iterate in Nebula against check --json / run --json (driven by the [scripts/nebula_agent.py](scripts/nebula_agent.py) loop harness — see [AGENTS.md](AGENTS.md)), then compile --target python produces a self-contained package you run in existing Python infrastructure — Nebula is the typed authoring layer, Python is the bytecode. Full path: [docs/author-in-nebula-ship-as-python.md](docs/author-in-nebula-ship-as-python.md).
This repository is the reference implementation: a Rust compiler and interpreter with a Python backend, probe host, and in-process embedding API.
Status: v0.1 — language and toolchain are experimental but fully tested.
Hello, Nebula
mission main {
print("Hello from Nebula");
}
cargo build --release
./target/release/nebula run examples/hello.neb
# Hello from Nebula
Requirements
Install
The nebula CLI — build from source:
git clone https://github.com/PeytonNowlin/Nebula.git
cd Nebula
cargo build --release
./target/release/nebula --help # or: cargo run -- --help
The Python runtime — nebula compile --target python vendors nebula_runtime/ into each output by default, so deployments are self-contained. To share one runtime across many compiled modules instead, install it from PyPI:
pip install nebula-runtime
The nebula CLI
Build once, then invoke subcommands directly or via cargo run --:
| Command | Purpose | |---------|---------| | check | Parse, resolve imports, typecheck | | run | Typecheck and execute | | parse --json [--load] | Export AST (optionally merged workspace) | | ir --json | Export lowered IR | | fmt [--write] | Canonical formatter | | compile --target python --out [--json] | Transpile to Python (--json emits a compile record: target, out dir, entry module, module count) | | probes list --probes [--mcp] [--json] | Inspect probe bindings and MCP tools |
Agent-oriented flags
Validation
nebula check examples/fizzbuzz.neb
nebula check examples/fizzbuzz.neb --json # success → `[]` on stdout; failure → JSON on stderr
Execution
nebula run examples/agent_counter.neb
nebula run examples/agent_counter.neb --telemetry trace.jsonl
nebula run examples/agent_counter.neb --probes probes/bundle.json
nebula run examples/runbook.neb --probes probes/runbook.json --json
Resource limits (interpreter defaults: 30s wall clock, 1M while-loop iterations, 64 MiB approximate memory)
nebula run examples/hello.neb --max-runtime-ms 5000
nebula run examples/hello.neb --max-loop-iterations 100000
nebula run examples/hello.neb --max-memory-mb 128
nebula run examples/hello.neb --no-resource-limits
Introspection and transpilation
nebula parse examples/import_demo.neb --json --load
nebula ir examples/hello.neb --json
nebula probes list --probes probes/mcp_stdio.json --mcp --json
nebula compile examples/import_demo.neb --target python --out dist/
python dist/examples/import_demo.py
JSON output
check --json emits a diagnostic array on stderr when validation fails:
[
{
"code": "NEB-T002",
"span": { "file": "example.neb", "start": 42, "end": 58, "line": 3, "column": 15 },
"message": "type mismatch: expected Int, found Str"
}
]
run --json always emits one run record on stdout (success or failure). Schema: [schemas/run-record.schema.json](schemas/run-record.schema.json).
{
"program": "examples/runbook.neb",
"exit": 0,
"diagnostics": [],
"telemetry_path": "trace.jsonl",
"probe_events": [
{ "ts": 1718380800, "probe": "log", "args": { "level": "info", "message": "ready" } }
],
"duration_ms": 42,
"printed": ["deploy ok"],
"return_value": null,
"probes_called": []
}
Other schemas live under [schemas/](schemas/): diagnostics, compile records, telemetry events, probe JSONL, probe manifests, and Nebula value encoding.
Language overview
Full specification: [nebula-spec/SPEC.md](nebula-spec/SPEC.md). Constrained-generation grammar: [grammar/nebula.gbnf](grammar/nebula.gbnf).
A program is a set of sector libraries, import statements, and exactly one mission entry point (conventionally main).
sector math {
fn double(n: Int) -> Int {
return n times 2;
}
}
mission main {
let mut i: Int = 1;
while i le 20 do
print(int_to_str(math.double(i)));
set i = i plus 1;
end
}
Design choices
| Topic | Behavior | |-------|----------| | Operators | Keywords, not symbols: plus, minus, times, div, mod, eq, lt, … | | Control flow | if / while / telemetry use end-delimited blocks; brace blocks for control flow are rejected (NEB-S005) | | Comparisons | Only lt, gt, le, ge, eq, ne; synonyms like less than are rejected (NEB-S004) | | Types | All bindings, parameters, and returns are annotated; no implicit coercion | | Namespacing | Sector symbols are qualified (math.double); same-sector calls may be unqualified inside the sector | | Numeric semantics | Matching Int/Int or Float/Float operands; checked 64-bit integer arithmetic (NEB-R007 on overflow); div/mod truncate toward zero | | Collections | List, Map, Option; empty [] / {} infer from context or default to List / Map | | Strings | UTF-8; len and string builtins operate on Unicode code points; both backends agree (parity-tested) |
Builtins
Builtins are implemented in the runtime — not loaded from source. The canonical surface is [nebula-builtins/builtins.toml](nebula-builtins/builtins.toml) (signatures stay in sync across the typechecker, interpreter, and Python shim). Human-readable notes: [std/core.neb](std/core.neb).
| Category | Functions | |----------|-----------| | I/O | print | | Collections | len, push, at, get, has, insert | | Conversions | str_to_int, int_to_str, str_to_float, float_to_str, int_to_float, float_to_int | | Strings | substr, contains, index_of, starts_with, ends_with, to_upper, to_lower, trim, replace, split, join | | Integers | abs, min, max |
push and insert mutate a variable in place; their first argument must be an identifier.
Imports
import "../std/math.neb";
mission main {
print(int_to_str(math.triple(7)));
}
Import paths are string literals, resolved relative to the importing file. Library modules may define sectors and nested imports but not a mission. Duplicate symbols across modules fail at load time (NEB-L003).
Importable standard module: [std/math.neb](std/math.neb).
Probes and telemetry
Probes declare host-provided capabilities; call dispatches them through a JSON manifest (--probes):
mission main {
probe log(level: Str, message: Str) -> Void;
telemetry
call log(level: "info", message: "starting");
end
}
| Handler kind | Role | |--------------|------| | jsonl | Structured logging (log probe) | | command | External process with stdin/stdout JSON protocol | | mcp | Model Context Protocol tool call (stdio or HTTP) | | read_file, write_file, http_get, json_parse, env_get, secret_get | Native bundle handlers |
Example manifests: [probes/host.json](probes/host.json), [probes/bundle.json](probes/bundle.json), [probes/mcp_stdio.json](probes/mcp_stdio.json), [probes/runbook.json](probes/runbook.json).
Secrets are declared in the manifest secrets map (resolved from environment variables), substituted into handler config via ${secret:name}, and read at runtime with secret_get — never embed secret values in .neb source.
With --telemetry, statements inside telemetry blocks append JSONL events ([schemas/telemetry-event.schema.json](schemas/telemetry-event.schema.json)).
Error codes
| Prefix | Category | |--------|----------| | NEB-S | Syntax / lex | | NEB-T | Type checking | | NEB-L | Module load / imports | | NEB-R | Runtime | | NEB-P | Probes / MCP |
Type checking reports multiple errors with spans in one pass.
Embedding (nebula-host)
For agent loops that should not shell out to the CLI:
use nebula_host::{Host, HostConfig, ResourceLimits};
let host = Host::with_config(HostConfig {
probe_manifest: Some("probes/bundle.json".into()),
telemetry_path: Some("trace.jsonl".into()),
resource_limits: ResourceLimits::agent_defaults(),
..HostConfig::default()
});
let check = host.check_source(r#"mission main { let x: Int = 1; }"#);
assert!(check.ok);
let run = host.run_file("examples/hello.neb");
assert!(run.ok);
assert_eq!(run.printed, vec!["Hello from Nebula"]);
// run.record is a RunRecord (same shape as `nebula run --json`)
Pipeline stages are also available directly via Host::try_parse_file, try_compile_file, try_emit_python, and list_probes.
Compiler pipeline
.neb source
→ nebula-syntax (lex + parse)
→ nebula-load (imports, workspace merge)
→ nebula-types (typecheck; builtins from nebula-builtins)
→ nebula-ir (lower)
→ nebula-runtime (interpret) | nebula-python (transpile)
| Crate | Role | |-------|------| | nebula-builtins | Canonical builtin manifest (builtins.toml) | | nebula-syntax | Lexer and parser | | nebula-ast | AST types, NebError, JSON diagnostic types | | nebula-load | Import graph and symbol merge | | nebula-types | Type checker | | nebula-ir | Intermediate representation | | nebula-runtime | Interpreter, probe host, resource limits | | nebula-mcp | MCP client transport | | nebula-host | Unified pipeline and embedding API | | nebula-diagnostics | miette::Report → JSON diagnostic extraction | | nebula-fmt | Formatter | | nebula-python | Python transpiler and runtime shim | | nebula-cli | nebula binary | | nebula-test-support | Integration tests and golden files (internal) |
Examples
| File | Demonstrates | |------|--------------| | [examples/hello.neb](examples/hello.neb) | Minimal program | | [examples/fizzbuzz.neb](examples/fizzbuzz.neb) | Sectors, conditionals, loops | | [examples/end_demo.neb](examples/enddemo.neb) | end-delimited control flow | | [examples/push_demo.neb](examples/pushdemo.neb) | Lists, push, len | | [examples/import_demo.neb](examples/importdemo.neb) | Importing std/math.neb | | [examples/agent_counter.neb](examples/agentcounter.neb) | Probes, telemetry, mutable state | | [examples/io_agent.neb](examples/ioagent.neb) | Bundle probes (read_file, http_get, …) | | [examples/runbook.neb](examples/runbook.neb) | Retry loop, command + MCP probes | | [examples/agent_lib.neb](examples/agentlib.neb) + [agent_lib_harness.py](examples/agentlibharness.py) | Compile a Nebula library, import and call it from Python |
Python backend
nebula compile --target python --out emits:
- One
.pymodule per.nebfile in the import graph - A copied
nebula_runtime/shim (builtins, probes, telemetry, checked arithmetic) - Sector namespaces as Python classes with
@staticmethodfunctions
The Rust interpreter and Python backend are kept in parity by an integration test suite.
Development
cargo test # full workspace: unit, integration, CLI e2e, parity
cargo fmt && cargo clippy
NEBULA_UPDATE_GOLDEN=1 cargo test -p nebula-test-support # refresh golden files
Roadmap
- Package manager / module registry beyond relative imports
- Additional compile targets beyond Python
- Standard library modules beyond
std/math.neb
License
MIT — see [LICENSE](LICENSE).
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: PeytonNowlin
- Source: PeytonNowlin/Nebula
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.