Metadata-Version: 2.4
Name: aether-kernel
Version: 0.4.0
Summary: Aether — AI-native pipeline language and kernel
License: Apache-2.0
Project-URL: Homepage, https://github.com/baiers/aether
Project-URL: Issues, https://github.com/baiers/aether/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Compilers
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Rust
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# Aether

**A deterministic orchestration language for AI agents.**

[![CI](https://github.com/baiers/aether/actions/workflows/ci.yml/badge.svg)](https://github.com/baiers/aether/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
[![Version](https://img.shields.io/badge/version-0.4.0-green.svg)](https://github.com/baiers/aether/releases)

---

LLM agents fail silently, run code with no safety model, and produce pipelines that are impossible to audit. Aether is an intermediate representation (IR) that gives AI-generated pipelines **verifiable intent, typed outputs, and compile-time safety gates** — without replacing the guest languages (Python, JS, shell) your nodes already use.

**"Intent is Compilation."**

## How it works

You write (or generate) a `.ae` program describing a pipeline as a directed acyclic graph of typed nodes. Each node declares what it does (`_intent`), what safety level it requires (`_safety`), what it reads (`::IN`), what it writes (`::OUT`), and what must be true after it runs (`::VALIDATE`). The Aether kernel executes the DAG, enforces safety gates, validates outputs, and — if a node fails — optionally calls an LLM to repair the code and retry.

```
§ROOT 0xFF_MAIN {

  §ACT 0x1A {
    ::META { _intent: "fetch active users", _safety: "read_only" }
    ::EXEC<PYTHON> {
      import urllib.request, json
      return json.loads(urllib.request.urlopen("https://api.example.com/users").read())
    }
    ::OUT { $0xUSERS: Type<JSON> }
  }

  §ACT 0x2B {
    ::META { _intent: "filter to adults only", _safety: "pure" }
    ::IN   { $0xSRC: Ref($0xUSERS) }
    ::EXEC<PYTHON> {
      return [u for u in $0xSRC if u["age"] >= 18]
    }
    ::OUT      { $0xADULTS: Type<JSON> }
    ::VALIDATE { ASSERT len($0xADULTS) >= 0 OR HALT }
  }

}
```

### Referencing ledger state in `::EXEC`

Any `$0xADDR` token in guest code resolves from the state ledger at execution
time. You can either:

- **Declare explicitly with `::IN`** (recommended) — gets you typed inputs,
  ghost aliases (`$0xSRC [users]`), and a documented dependency edge in the
  audit log.
- **Reference directly without `::IN`** — the kernel scans the code for any
  `$0x*` addresses not already bound and pulls them from the ledger. Handy
  for one-liners that read a single `::CTX` value. You lose the typed-binding
  guarantees but the pipeline still runs.

Both forms produce the same ledger reads; `::IN` just makes the contract
explicit.

Or use **Aether-Short** (`.as`) for ~60% fewer lines:

```
@pipeline 0xFF_MAIN

  $0xUSERS:  JSON = @std.io.net_get() {
    import urllib.request, json
    return json.loads(urllib.request.urlopen("https://api.example.com/users").read())
  }

  $0xADULTS: JSON = @std.proc.list.filter($0xUSERS) {
    return [u for u in $0xUSERS if u["age"] >= 18]
  } | ASSERT len($0xADULTS) >= 0 OR HALT

@end
```

## Why not just write Python?

| | Raw Python / LangGraph | Aether |
|---|---|---|
| **Safety model** | None | L0–L4 compile-time gates |
| **Typed outputs** | Runtime duck typing | Declared + validated at write time |
| **Audit trail** | Manual logging | Automatic `output.ae.json` with full node traces |
| **Self-healing** | Manual try/except | `ASSERT ... OR RETRY(3)` — LLM repairs the node |
| **LLM generation cost** | 715–1,225 tokens (LangGraph/AutoGen) | 415 tokens (3-node baseline) |
| **Runtime LLM calls** | 0 (LangGraph) — 6,200 (AutoGen) | 0 for deterministic pipelines |

See [`docs/benchmark.md`](docs/benchmark.md) for the full token-cost comparison.

## Features

**Safety — the declaration is checked, not trusted**

- **5-tier safety model** — L0 (pure math) → L4 (system root). Nodes above your threshold are blocked before execution.
- **Effect inference** — the kernel reads each node's guest code and derives the level it *actually* needs. A mismatch is reported on every run; `--verify-effects` blocks it. A node tagged `pure` that imports `requests` does not get to run.
- **Secret taint propagation** — values resolved from `ENV:` are redacted, and so is anything computed from them, in the ledger, the trace and the cache alike. `std.sec.hash.sha2` and `std.sec.mask.pii` are the sanctioned ways to release a derivative.

**Verifiability — a run you can check afterwards**

- **Execution root hash** — every node is content-addressed over its code, resolved inputs and declared contract; the per-node commitments fold into one `root_fingerprint`. Two runs sharing that hash provably ran the same code on the same inputs and got the same answers.
- **Plan validation** — `aether check <file>` (or `--dry-run`) proves every `::IN` reference resolves, no address has two writers, and the graph is acyclic. Exits non-zero, so it drops straight into a save hook or CI.
- **Typed state ledger** — outputs are written to an address space (`$0xADDR`) with type validation on every write.

**Execution**

- **Parallel DAG execution** — independent nodes run concurrently, bounded by `--max-parallel`; dependencies resolved with Kahn's topological sort.
- **`§MAP` fan-out** — `§MAP 0x2B OVER $0xITEMS AS $0xITEM { … }` runs one body per element of a runtime list. A map is *one* node in the graph, so plan checking and the root hash keep working even though N is unknown until the run.
- **`§FAIL` handlers** — a block that runs after the graph, and only if something failed, with the failure summary bound to `$0xFAILURES`. Write a partial report, notify, clean up. `::ON { 0x2B }` scopes a handler to specific nodes, and scopes what it sees, so reacting differently to different failures does not mean branching inside the guest.
- **Memoization** — `--cache` reuses results for nodes whose code and inputs are unchanged. Eligible only when pure/read-only, statically transparent, and untainted; a cached run still agrees with an uncached one on the root hash.
- **Per-node timeouts** — `--timeout` bounds any single node, and the guest process is killed rather than abandoned.

**Authoring**

- **ASL registry** — 38 canonical intents (`std.io.*`, `std.proc.*`, `std.ml.*`, `std.sec.*`, …) with safety and language defaults. Unknown `std.*` intents are hard errors; custom namespaces (`myorg.etl.*`) are accepted.
- **Self-healing RETRY** — `ASSERT expr OR RETRY(3)` sends the failing code to a registered LLM handler for repair. It remembers every rejected attempt, refuses assertions no rewrite could satisfy, and rejects candidates that do not parse before spending a call.
- **English Toggle** — `aether gen "description"` turns plain English into a `.ae` program.
- **MCP server** — `aether-mcp` exposes validate/execute/audit/inspect as tools for Claude Code and other MCP-compatible clients. `aether_validate` runs the full plan check, not just a parse, so an agent checking its own generated pipeline gets the same answer `aether check` would give.
- **REST API** — `aether-api` runs on port 3737 for LangChain, AutoGen, n8n, or any HTTP client. `GET /grammar` returns a machine-readable summary of the language for LLM consumption.
- **Aether Lens** — a standalone DAG visualizer (`lens/index.html`) that renders any `output.ae.json` execution log.

> **On isolation.** Guest code runs as an ordinary host subprocess. Everything above is *analysis* — it catches accidents and dishonest safety tags, which is the common case, but it does not contain a determined program. Real containment needs the WASM runtime tracked in [`ROADMAP.md`](ROADMAP.md). Run untrusted pipelines under an OS-level sandbox of your own until then.

## Aether Lens

Every execution writes an `output.ae.json` audit log. Open `lens/index.html` in any browser to visualize it — no build step, no npm, no server required.

![Aether Lens — DAG execution visualizer](docs/lens-screenshot.png)

Each node card shows its **intent**, **safety level**, **execution time**, and **status** — color-coded at a glance:

| Color | Meaning |
|---|---|
| Green | Completed successfully |
| Amber (`HEALED`) | Failed, repaired by LLM, re-ran successfully |
| Red (`BLOCKED`) | Skipped — upstream dependency failed or safety gate rejected |
| Orange | Failed with no recovery |

Click any node to open the detail panel: full JSON output, validation results, and the heal log if self-healing was attempted. The ledger bar at the bottom shows every live state address and its current value.

```bash
# Serve locally to auto-load output.ae.json
cd lens && python -m http.server 8080
# → open http://localhost:8080

# Or just open the file directly and drag-and-drop any output.ae.json
open lens/index.html
```

## Installation

```bash
# Option 1: pip (recommended — no Rust required)
pip install aether-kernel

# Option 2: Pre-built binary
curl -fsSL https://raw.githubusercontent.com/baiers/aether/main/install.sh | bash

# Option 3: Build from source
cargo build --release
```

## Quick Start

```bash
# Run a pipeline
aether examples/demo.ae

# Expand Aether-Short to inspect generated .ae
aether examples/pipeline.as --expand-only

# Run with a higher safety threshold (allow network calls)
aether examples/demo_showcase.ae --safety l3

# Self-healing (requires ANTHROPIC_API_KEY)
ANTHROPIC_API_KEY=sk-... aether examples/self_heal_demo.ae

# Generate a .ae program from plain English
ANTHROPIC_API_KEY=sk-... aether gen "fetch the top 10 HN stories and summarize each one"

# Start the REST API
aether-api  # → http://localhost:3737

# Start the MCP server (for Claude Code integration)
aether-mcp
```

## Claude Code / MCP Integration

Add to your MCP config (`~/.claude/mcp_config.json`):

```json
{
  "mcpServers": {
    "aether-kernel": {
      "command": "aether-mcp",
      "args": []
    }
  }
}
```

Claude can then call these directly:

| Tool | Does |
|---|---|
| `aether_validate` | Parse **and** plan-check without running: every `::IN Ref()` resolves, no address has two writers, the graph is acyclic, every `§FAIL ::ON` target exists |
| `aether_execute` | Run a program. Takes `safety_level`, `verify_effects`, `strict_registry`, `use_registry`, `timeout_seconds`, `max_parallel` |
| `aether_audit` | Send an execution log to the registered LLM handler for a natural-language report |
| `aether_inspect` | Retrieve a previous execution log by its id |

Set `verify_effects: true` when running code you did not write — it infers each
node's real effect level from its guest body and blocks any node needing more
than its `_safety` tag declares.

## Project Structure

```
src/          Rust kernel (parser, executor, ASL registry, self-healing, MCP, REST API)
asl/          ASL registry — 38 canonical intents (JSON)
examples/     Runnable .ae and .as programs
spec/         Formal EBNF grammar and type system docs
docs/         Whitepaper, benchmark paper, kernel manual
lens/         Aether Lens DAG visualizer (standalone HTML, no build step)
sdk/          LLM system prompt, MCP config, audit prompt
benchmark/    LangGraph / AutoGen equivalents + token counting scripts
python/       pip-installable wrapper (aether-kernel)
```

## What's Included (Community — Free, Apache 2.0)

| Feature | |
|---|---|
| Parser, AST, topological executor | ✓ |
| 5-tier safety model (L0–L4) | ✓ |
| ASL registry (38 canonical intents) | ✓ |
| Aether-Short (.as) notation | ✓ |
| Self-healing RETRY (your `ANTHROPIC_API_KEY`) | ✓ |
| English Toggle `aether gen` (your `ANTHROPIC_API_KEY`) | ✓ |
| MCP server for Claude Code | ✓ |
| REST API | ✓ |
| Aether Lens DAG visualizer | ✓ |

**Aether Pro** *(coming soon)* — hosted execution, managed LLM calls (no API key needed), extended ASL (200+ intents), persistent history. [Join the waitlist →](https://github.com/baiers/aether/discussions)

## License

Licensed under the [Apache License 2.0](LICENSE).

See [docs/open-core.md](docs/open-core.md) for the Community vs Pro vs Enterprise breakdown.
