No description
  • Rust 94.6%
  • Nix 5.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
fusion 84347a5fbb FN-047: mark GitHub and GitLab forge backends as shipped in TODO.md
Update the git forge integration backlog entry to reflect that all three forge backends are now complete.

- Retitle the forge integration section from 'partial' to 'backends shipped'
- Document that Forgejo (default), GitHub, and GitLab all ship behind the shared Forge trait with identical tool names/schemas
- Note backend selection via the provider setting
- Reframe remaining work as provider-specific polish (state filters, hosted-instance edge cases)

Files changed:
 TODO.md | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-047

Fusion-Task-Lineage: ba5a2e2b-da7c-4bf8-bd75-7dda4ca8d61e

Co-authored-by: Fusion <noreply@runfusion.ai>
2026-07-03 04:34:23 -04:00
crates FN-043: expose subagents P2P peer permissions and escalation settings 2026-07-02 20:50:36 -04:00
docs FN-043: expose subagents P2P peer permissions and escalation settings 2026-07-02 20:50:36 -04:00
examples refactor: rename solus → lambda; CLI binary is lmda 2026-06-19 09:55:50 -04:00
nix FN-038: add Nix stateDir option rendering runtime state_dir setting 2026-06-20 23:01:57 -04:00
profiles refactor: rename solus → lambda; CLI binary is lmda 2026-06-19 09:55:50 -04:00
.gitignore ignore worktrees 2026-06-19 21:58:35 -04:00
AGENTS.md amend AGENTS.md 2026-06-19 10:36:00 -04:00
Cargo.lock FN-019: add host peer orchestration controller for multi-agent sessions 2026-06-20 10:29:16 -04:00
Cargo.toml FN-007: add chat-room orchestration interface extension 2026-06-20 00:29:56 -04:00
CLAUDE.md docs: add AGENTS.md + TODO.md; retire BACKLOG.md 2026-06-19 09:58:48 -04:00
flake.lock refactor(nix): flake-parts + import-tree substrate (dendritic step 1, behavior-preserving) 2026-06-17 17:48:22 -04:00
flake.nix refactor: rename solus → lambda; CLI binary is lmda 2026-06-19 09:55:50 -04:00
README.md FN-038: add Nix stateDir option rendering runtime state_dir setting 2026-06-20 23:01:57 -04:00
TODO.md FN-047: mark GitHub and GitLab forge backends as shipped in TODO.md 2026-07-03 04:34:23 -04:00

lambda

A minimal, Nix-first, self-evolving coding-agent runtime in Rust.

lambda is a framework: a small core plus extensions. The core is just the agent loop, an extension registry, and the typed contract everything registers through. Tools, hooks, commands, providers, skills, MCP clients — and the interface itself — are all extensions, written as native Rust crates or as Luau the agent can author and reload itself. The TUI is just one interface built on the core; a headless server interface ships too, and you can write your own. Configuration is 100% Nix (Nixvim-style): you write typed options, a home-manager or NixOS module generates the config.toml lambda reads.

Status: early but the foundation is complete and tested — core + contract + registry, streaming providers, a markdown-rendering TUI, Luau front-end, skill bundles, MCP client, slash commands, AGENTS.md project context, resumable session persistence, health, layered config + Nix module, and hot-reload (the agent edits a .luau, calls the reload tool, and the next turn picks it up — validate-then-swap keeps the old version on a bad reload). The TUI runs on a persistent runtime, so the registry, reloads, MCP connections, and compaction all survive across turns. Ambient timers and subagents remain as follow-ups (largely agent-buildable as extensions on the existing substrate). Live LLM use runs against OpenAI via existing Codex subscription auth (~/.codex/auth.json); Anthropic is built but needs an API key.

Quickstart (Nix)

nix build              # build the binary → ./result/bin/lmda
nix develop            # dev shell with cargo/rustc/clippy/rustfmt
nix flake check        # run the Nix module + config-generation checks

nix develop --command cargo test     # ~300 tests
./result/bin/lmda                   # launch the interactive TUI (the default)
./result/bin/lmda "your prompt"     # one-shot agent run (prints, exits)
./result/bin/lmda health            # diagnostics: what loaded, what shadowed, auth readiness
./result/bin/lmda --help            # full usage (clap)

bare lmda launches the TUI. LAMBDA_DEMO=1 lmda runs an offline mock demo (no network/credentials). Vim-style modal editing: --vim, or set it as the default with [tui] vim = true in config.toml.

Sessions (resume a conversation)

By default lambda is stateless. Opt into persistence with --session <id> (resume or create a named session) or --continue (resume the most-recently-updated one); the full transcript is saved after every turn to $XDG_STATE_HOME/lambda/sessions/<id>.json (versioned JSON; corrupt files are reported and replaced, never fatal). Works for both the TUI and one-shot runs.

./result/bin/lmda --session work "start a refactor plan"
./result/bin/lmda --session work "now implement step 1"   # continues where it left off
./result/bin/lmda --continue                              # resume the latest session in the TUI
./result/bin/lmda sessions                                # list saved sessions

First run / auth

The default provider is OpenAI via your existing Codex subscription — lambda reads ~/.codex/auth.json (so you must have the Codex CLI installed and logged in; lambda has no login flow of its own yet). No config or API key needed:

./result/bin/lmda health            # auth.openai should read "codex-auth ready"
./result/bin/lmda "say hello"       # live one-shot run (default model gpt-5.5)

This live path is verified working end-to-end (text replies and tool-use round-trips). The default model gpt-5.5 must be available to your ChatGPT account; if a model isn't, the API returns a clear error and you can pass --model <id>. Anthropic needs ANTHROPIC_API_KEY (otherwise it's listed but unusable — lmda health shows a WARN).

Architecture

lambda is a framework: the core is the product, and the interface (the TUI) is just one extension built on top — fully swappable. The dependency direction is core ← host ← extension/interface ← app/bin.

Crate Responsibility
lambda-core The contract (ToolOutput, ExtError, descriptors, hooks, Ctx, Layer, CONTRACT_VERSION), the Registry (registration, shadowing, dispatch, remove_extension, the single-active interface slot), the streaming Provider trait, the agent loop (run_agent), and the Interface trait + UI-neutral InterfaceSession.
lambda-host Generic reusable assembly: load config, run extension startup tasks, select provider, resolve sessions, build the AgentRuntime, compute neutral ContextMetadata. No first-party extension or interface deps.
lambda-app Reusable CLI runner: parses args, asks a caller-supplied register_all to install extensions/interfaces, then runs one-shot/health/sessions or the single registered interface.
lambda (bin) Thin default composition wrapper. Nix decides which ext-* Cargo features are compiled.
lambda-config Layered runtime config: defaults < config.toml < config.local.toml < env/CLI.
lambda-openai OpenAI provider (ChatGPT Codex Responses transport; reuses ~/.codex/auth.json; optional codex_auth_file).
lambda-anthropic Anthropic provider (Messages transport; API key from env or an out-of-store api_key_file).
lambda-mcp stdio MCP client — registers a server's tools as native tools.
lambda-highlight syntect-backed syntax highlighter (a registry service interfaces can render with).
lambda-luau Luau extension loader, VM actor, bridge, and hot-reload reloader.
lambda-skills Prompt-only skill bundles (manifest + SKILL.md) surfaced through context assembly.
lambda-tui terminal interface: ratatui/crossterm, markdown rendering, Vim mode, persistent runtime. Depends on lambda-core only.
lambda-headless non-terminal interface for servers: runs an optional startup prompt, then polls a queue directory for prompt files (success → done/, failure → failed/), streaming to journald. Depends on lambda-core only.

Interfaces (swap or write your own)

An interface owns the interactive loop. Exactly one is active — registering a second is an error. Interfaces are ordinary native extensions (ext-tui, ext-headless, or your own) that register into the single-active interface slot. To completely replace the UI:

  1. Write a crate implementing lambda_core::interface::Interface (one run(self, InterfaceSession) method) on top of lambda-core — see lambda-tui /lambda-headless for templates.
  2. Ship an extension.nix using lib.lambda.extensions.mkRustExtension with provides = [ "interface" ].
  3. Compose the binary through Nix (mkLambdaWith { extraExtensions = [ ... ]; }) or enable the corresponding first-party extensions.<name>.

No core changes needed. InterfaceSession carries only runtime primitives + neutral ContextMetadata — no terminal concepts — so a headless/daemon interface is as first-class as the TUI.

Layers (Store < Overlay < ProjectLocal)

Extensions register at a layer; higher layers shadow lower ones. Nix owns Store (read-only, declarative); the agent owns Overlay ($XDG_DATA_HOME/lambda/…, mutable — the self-evolution channel); ./.lambda/… is ProjectLocal. This lets the agent iterate on a Nix-installed extension without editing the store.

Configuration

lambda reads $XDG_CONFIG_HOME/lambda/config.toml (override with LAMBDA_CONFIG):

default_provider = "openai"
default_model    = "gpt-5.5"
system_prompt    = "You are lambda. Be direct and use tools when useful."

[extensions]
store_skill_dirs = ["/nix/store/…/skills"]   # Store-layer (Nix-declared)
store_luau_dirs  = ["/nix/store/…/ext"]

[[mcp.servers]]
name    = "fs"
command = "mcp-fs"
args    = ["--root", "/tmp"]

[compaction]                # auto-summarize old turns near the context limit (on by default)
enabled = true
context_window = 200000     # set to your model's real window (no per-model metadata yet)
reserve_tokens = 16384
keep_recent_tokens = 20000

[tui]
vim = true                  # Vim-style modal editing by default (--vim forces it on)

[providers.anthropic]
api_key_file = "/run/credentials/lambda.service/anthropic-api-key"   # file path, never the key
[providers.openai]
codex_auth_file = "/run/credentials/lambda.service/openai-codex-auth.json"

[headless]                  # used when the headless interface is compiled in
startup_prompt = "…"        # run once on start
queue_dir = "/var/lib/lambda/queue"
poll_interval_secs = 5
session_id = "headless"

This file is generated by the Nix module — you configure via programs.lambda/ services.lambda, not by editing it. CLI flags (--provider, --model) and LAMBDA_PROVIDER/LAMBDA_MODEL override at runtime.

Project context (AGENTS.md)

lambda follows the cross-agent AGENTS.md convention: on startup it walks from the working directory up to the project root (nearest .git ancestor), collects every AGENTS.md along the way, and appends them to the system prompt (root first, so the most specific file wins). Without a .git root only the working directory is consulted, so discovery never escapes upward. Drop an AGENTS.md in your repo to give the agent project-specific conventions.

Nix modules

Nix is the only supported configuration surface — the generated config.toml and any env vars are internal artifacts you never edit by hand. The flake exposes both homeManagerModules.lambda (desktop) and nixosModules.lambda (system service), sharing one typed option schema (nix/lambda-options.nix) plus a freeform settings escape hatch. Extensions and interfaces are ordinary Nix modules under extensions.<name>.

Home-manager (desktop, defaults to extensions.tui.enable = true):

programs.lambda = {
  enable = true;
  defaultProvider = "openai";
  stateDir = "/var/lib/lambda/state"; # optional runtime session/agent state directory
  skills = [ ./skills/writer ];
  luauExtensions = [ ./ext/linter.luau ];
  extensions.mcp.settings.servers = [
    { name = "fs"; command = "mcp-fs"; args = [ "--root" "/tmp" ]; }
  ];
  settings = { };                 # freeform config.toml escape hatch, deep-merged last
};

NixOS (headless server, hardened systemd service, defaults to the headless interface). Provider secrets stay out of the Nix store — give a path (agenix/sops-decrypted) and it's loaded via systemd LoadCredential; the rendered config points at the credential path, never the value:

services.lambda = {
  enable = true;
  defaultProvider = "anthropic";
  extensions.anthropic.settings.api_key_file = "/run/secrets/anthropic"; # NOT in /nix/store
  workspaces = [ "/srv/project" ];        # dirs the agent may read+write
  extensions.headless.settings = {
    startup_prompt = "summarize today's commits";
    queue_dir = "/var/lib/lambda/queue";   # drop prompt files here; they run then move to done/ or failed/
    poll_interval_secs = 5;
  };
  headless.sessionId = "server";
};

The home-manager module renders config to the user's XDG path; the NixOS module renders to /etc/lambda/config.toml and runs a hardened service (system user, StateDirectory, explicit ReadWritePaths workspaces). Both materialize declared skills/extensions into Store-layer dirs.

Extending

  • Skill bundle: a directory with skill.toml (name/version/description/ contract_version) and SKILL.md surfaced to the model. Drop it in a skills dir; it loads at startup.
  • Standalone Luau: a .luau file in a luau-extensions dir.
  • Native crate: a crate exposing register_extension(&mut ExtensionHost); ship an extension.nix using lib.lambda.extensions.mkRustExtension.
  • Interface: a native extension that registers into the single-active interface slot (see lambda-tui/lambda-headless) — completely replace or rewrite the UI without touching the core.
  • MCP server: declare it in extensions.mcp.settings.servers; its tools register as mcp__<server>__<tool>.
  • Hot-reload: after editing an Overlay .luau, call the reload tool (reload{ext_id}); the change applies at the next turn boundary.

Design docs

Full design specs live in docs/superpowers/specs/ — the master design, the extension contract, providers/auth, the Luau front-end, skills, the Nix config-module, and hot-reload/ambient.

Development notes

  • All cargo commands run inside nix develop.
  • The Nix flake only sees git-tracked files; git add new files before nix build.
  • This repo is developed with a two-agent workflow (Claude + Codex as co-equal peer implementers/reviewers); the local AgentBridge config is git-ignored.