# lambdagentpaas — Lambda Calculus Agent Platform (monorepo)

<!-- Badges -->
[![License: BSL 1.1](https://img.shields.io/badge/License-BSL%201.1-blue.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![Repo](https://img.shields.io/badge/repo-kenny67nju%2Flambdagentpaas-181717?logo=github)](https://github.com/kenny67nju/lambdagentpaas)

**lambdagentpaas** is a full-stack platform for building, deploying, and serving AI agents defined in a Lambda-calculus DSL. The monorepo contains the language, the backend, the web UI, and ~10 example agents shipped to production.

> 📖 **New here?** Start with [`docs/INTRODUCTION.md`](docs/INTRODUCTION.md) for a project-level overview, then read this README for the DSL deep-dive.

## v1.0 scope and deliberate non-goals

This first release prioritizes **predictable, single-deployment usage over breadth**. The audit ([`docs/AUDIT_2026-06-05.md`](docs/AUDIT_2026-06-05.md)) led to a series of *subtractions* before the first tag:

- **Deleted:** the Feishu bot integration (`agentpaas/api/v1/feishu.py` + `agentpaas/services/feishu.py`) — it was an unfinished dev-stage surface that handed `process`-wide bot-rebind capability to anyone reaching port 8000. Will return in v2 with proper signing.
- **Deleted:** `agentexample/agent67/tools/shell_executor.py` — LLM-controlled shell with a substring blocklist (RCE-via-prompt-injection). Was never wired into agent67's actual tool registry; the file is gone now too.
- **Hardened:** `POST /api/v1/setup/bootstrap` only accepts loopback callers. Production deploys behind a reverse proxy should use the `agentpaas` CLI to create the initial tenant.
- **Single-tenant assumption:** while the data model carries `tenant_id` columns and the audit found the scoping mostly correct, v1.0 is **intended for single-tenant deployments**. Multi-tenant requires the full RBAC + integration-test pass deferred to v2.
- **Sample agents are samples:** `agentexample/qaagent67lambda` ships with `/home/67/knowledge/finance` paths — treat as a reference implementation requiring path customization, not a turn-key template.

Things v1.0 is **good for:** running the lambdagent DSL kernel, executing YAML-defined agents through the PaaS API, building a knowledge base, using the web UI for chat/run/inspection, deploying via Docker Compose or the native scripts.

Things v1.0 is **not yet good for:** untrusted multi-tenant SaaS, knowledge-dir-as-attack-surface (no pickle for shared dirs), Feishu integration, or anything that needs the `where = [".."]` empty-wheel pre-fix tooling.

## Repository layout

| Directory | What it is | Run / install |
|---|---|---|
| [`lambdagent/`](lambdagent/) | The core DSL — Lambda-calculus agent language, runtime, MCP/A2A/RAG/sandbox. Published as a standalone package (`pip install lambdagent`). | `pip install -e lambdagent/` |
| [`agentpaas/`](agentpaas/) | PaaS layer — REST API, CLI, agent registry, run workspace, knowledge-base management. Wraps `lambdagent` for multi-tenant serving. | `python3 -m agentpaas serve` |
| [`webui/`](webui/) | React + Vite frontend — agent editor, chat, run inspector, knowledge-base UI. | `cd webui && npm run dev` |
| [`agentexample/`](agentexample/) | Concrete agents in production: `physics67` (research pipeline), `qaagent67*` (RAG QA), `travelagent67`, `pptagent67`, `research67`, `agent67`, etc. | See each subdir's README |
| [`lambdagent_guard/`](lambdagent_guard/) | Static-analysis & runtime safety layer for compiled Lambda terms. | imported by `agentpaas` |
| [`deploy/`](deploy/) | Native install + start/stop scripts (Bash, PowerShell, batch). | `bash deploy/install-native.sh && bash deploy/start.sh` |
| [`docker-compose.yml`](docker-compose.yml) (repo root) | One-click Docker Compose deployment. | `docker compose up -d` |
| [`demo/`](demo/) | End-to-end demos (notebooks, scripts) for talks and onboarding. | — |
| [`docs/`](docs/) | Design docs, architecture, audits, comparison studies, [INTRODUCTION.md](docs/INTRODUCTION.md). | — |
| [`tests/`](tests/) | 189+ pytest suite across DSL, compiler, runtime, cost vectors, algebraic laws, AgentPack e2e. | `pytest tests/` |

## Live deployments

| Service | URL | Notes |
|---|---|---|
| maritime-qa | `http://qa.lambdagent.cn:8080` | 海事法规 RAG |
| 投标-qa | `http://qa.lambdagent.cn:8084` | 投标文件 RAG |
| clean-qa | `http://qa.lambdagent.cn:8083` | 49 docs / 1527 chunks, BM25 + Graph + Wiki |

---

## About the DSL (rest of this document)

The remainder of this README documents the `lambdagent/` subpackage — the Lambda-calculus DSL itself. For platform usage (REST API, web UI, deploying your own agent), see [`docs/INTRODUCTION.md`](docs/INTRODUCTION.md) and [`AGENT_GUIDE.md`](AGENT_GUIDE.md).

A Python DSL that models AI agents as Lambda calculus terms. Every agent is a function, every composition is function composition, every loop is a Y combinator. This is not a metaphor — it is a formal correspondence backed by a Church encoding verification.

**Key insight:** An (M, D) pair — a language model M plus a dataset/prompt D — is isomorphic to a Lambda term. `LLM + Dataset = Lambda term`.

**Stats:** ~13,500 lines of Python | 197 exported symbols | 4 patents filed

## Highlights

- **Unified LLM Provider System** -- 4 providers cover all major backends: Claude Code (via Max Plan), Anthropic API, OpenAI-compatible (DashScope / DeepSeek / Moonshot / Zhipu), and Ollama (local). Switch with one line of YAML.
- **Zero-Hallucination Conversations** -- `ConversationLam` maintains full session persistence so the model never loses context mid-conversation, eliminating the hallucination caused by truncated history.
- **Claude Code Max Plan -- No API Key** -- Set `provider: claude-code` and use your Claude Code subscription directly. No API key, no billing dashboard, no environment variables.
- **YAML-Driven Configuration** -- Define agents, tools, memory, and provider settings in a single YAML file. `from_config()` compiles it into a typed Lambda term tree.

### Quick Start (Simplest Path)

```yaml
# agent-config.yml
model:
  provider: claude-code
  name: sonnet
```

```bash
# Interactive chat
python3 -m agentpaas chat lambda

# Or run the example agent directly
python3 agentexample/agent67/run.py --claude
```

No API key required -- uses your Claude Code Max Plan subscription.

### Provider Comparison

| Provider | Config value | API Key needed | Notes |
|----------|-------------|----------------|-------|
| Claude Code (Max Plan) | `claude-code` | No | Uses local Claude Code subscription |
| Anthropic API | `anthropic` | Yes (`ANTHROPIC_API_KEY`) | Direct Claude API access |
| OpenAI-compatible | `dashscope` / `openai` / `deepseek` / `zhipu` / `moonshot` | Yes | Any OpenAI-compatible endpoint |
| Ollama (local) | `ollama` | No | Runs models locally, requires Ollama installed |

## Features

### Core Constructs (Lambda Calculus)

lambdagent maps 11 core agent constructs to Lambda calculus, giving each one a precise denotational semantics:

| #  | Lambda Calculus          | DSL Construct                 | Description                     |
|----|--------------------------|-------------------------------|---------------------------------|
| 1  | Lambda abstraction `λx.body` | `Lam(name, prompt)`         | An LLM with a system prompt     |
| 2  | Application `(f x)`     | `agent(input)`                | Run agent on input              |
| 3  | Composition `λx.g(f(x))`| `f >> g`                      | Pipeline / chain                |
| 4  | Church conditional `IF`  | `If(cond, then_, else_)`      | Conditional branching           |
| 5  | Y combinator             | `Loop(body, condition)`       | Iterative reasoning (ReAct)     |
| 6  | Church pair `PAIR`       | `Pair(f, g)`                  | Run two agents, return both     |
| 7  | Projections `FST / SND`  | `Fst() / Snd()`              | Extract from pair               |
| 8  | Primitive / Oracle       | `Tool(name, fn)`              | External tool call              |
| 9  | Generalized CASE         | `Route(classifier, routes)`   | Multi-way dispatch              |
| 10 | Dependent type `{x:T\|P(x)}` | `Guard(agent, validator)` | Output validation               |
| 11 | Environment extension    | `Memory(agent, store)`        | Persistent context              |

Plus `Par(f, g)` as syntactic sugar for parallel execution (via `|` operator).

### Multi-Agent Constructs (pi-calculus extension)

| #  | Process Calculus           | DSL Construct                 | Description                     |
|----|---------------------------|-------------------------------|---------------------------------|
| 12 | Channel `c!(v)` / `c?(x)` | `Channel` + `Send` + `Receive` | Inter-agent communication     |
| 13 | Shared environment         | `SharedMemory`               | Thread-safe shared state        |
| 14 | Y_n(Loop + Route)          | `GroupChat`                  | Multi-agent group discussion    |
| 15 | Dynamic CASE               | `Handoff`                    | Runtime dynamic delegation      |
| 16 | Concurrent beta-reduction  | `AsyncPar`                   | Thread-pool true parallelism    |

### Skill System

| Construct      | Description                                     |
|----------------|-------------------------------------------------|
| `Skill`        | Named, reusable Lambda term with metadata       |
| `SkillPack`    | Collection of related skills (like a package)   |
| `SkillRegistry`| Global singleton registry with search/discover  |
| `SkillAgent`   | Auto-discovers and executes best skill          |
| `@skill`       | Decorator to create and register skills         |

### Protocol Integrations

| Module          | Protocol       | Description                                |
|-----------------|----------------|--------------------------------------------|
| `MCPServer/Tool`| MCP 2025-11-25 | Connect to MCP servers (HTTP + stdio)      |
| `A2AServer/Client` | Google A2A v0.3 | Publish/discover/call remote agents     |
| `RAGTool`       | --             | TF-IDF or ChromaDB retrieval-augmented gen |
| `AgenticRAG`    | --             | Agent decides when to retrieve             |
| `Checkpoint`    | --             | Serialize/restore execution state to JSON  |

### Sandbox (Process Isolation)

| Construct          | Description                                        |
|--------------------|----------------------------------------------------|
| `SandboxedTool`    | Tool that runs in isolated subprocess with resource limits |
| `SandboxPolicy`    | Security policy (timeout, memory, network, etc.)   |
| `SecureExecutor`   | Auto-wraps all Tools in a term tree with sandbox   |
| `ResourceLimiter`  | Applies CPU/memory/fd limits via POSIX resource    |
| `@sandboxed`       | One-line decorator for sandboxed tool creation     |

## Architecture

```
YAML Config ──→ from_config() ──→ Lambda Term ──→ Runtime ──→ Result
                 (compiler)        (Term tree)    (beta-reduction)

                               ┌── Multi-Agent: Channel, GroupChat, Handoff, AsyncPar
                               ├── Skills: Skill, SkillPack, SkillRegistry, SkillAgent
Lambda Term ──→ Runtime ──→    ├── MCP: MCPServer, MCPTool (HTTP + stdio)
                               ├── A2A: AgentCard, A2AServer, A2AClient
                               ├── RAG: RAGTool, AgenticRAG, SimpleVectorStore
                               ├── Checkpoint: save/load execution state
                               └── Sandbox: SandboxedTool, SecureExecutor, ResourceLimiter
```

The system has five layers:

1. **Core DSL** (`lambdagent.core`, `lambdagent.primitives`, `lambdagent.extensions`) — the 11 core constructs as Python classes, each a subclass of `Term`.
2. **Multi-Agent** (`lambdagent.multiagent`) — 5 pi-calculus constructs for inter-agent communication, group chat, dynamic delegation, and true parallelism.
3. **Skill + Protocol** (`lambdagent.skills`, `lambdagent.mcp_client`, `lambdagent.a2a`, `lambdagent.rag`, `lambdagent.checkpoint`) — reusable skills, MCP/A2A protocol integration, retrieval-augmented generation, and state persistence.
4. **Compiler** (`lambdagent.fromconfig`) — parses YAML configs into Lambda term trees. Includes schema validation and lint.
5. **Runtime** (`lambdagent.agentruntime`) — executes Lambda terms via beta-reduction, handling LLM calls, MCP tool invocation, memory, and tracing. 支持双执行引擎切换 (recursive/cek/adaptive), 通过 `runtime.engine` 配置。CEK 引擎提供逐步成本监控、暂停/恢复和循环检测能力。

## Installation

```bash
pip install lambdagent
```

For LLM provider support:

```bash
pip install lambdagent[anthropic]   # Anthropic Claude
pip install lambdagent[openai]      # OpenAI-compatible (Dashscope, etc.)
```

## Quick Start

### Python DSL

```python
from lambdagent import Lam, Compose, Loop, Tool, Memory

# A single agent is a Lambda abstraction
writer = Lam("writer", "You are a technical writer. Write clear documentation.")

# Composition is function composition
reviewer = Lam("reviewer", "Review the text for clarity and correctness.")
pipeline = writer >> reviewer  # = lambda x. reviewer(writer(x))

# ReAct agent is a Y combinator
# `condition` takes (result, step_index) and returns bool;
# `max_steps` is the unfolding bound (default 10).
searcher = Tool("search", lambda q: web_search(q))
researcher = Loop(
    body=Lam("think", "Analyze the question. Use search if needed."),
    condition=lambda result, step: "DONE" in result,
    max_steps=10,
)

# Add memory for persistent context.
# `store` is an optional dict of {key: value} pre-loaded into the agent's
# environment; further entries are added via `agent.remember(k, v)`.
agent = Memory(researcher, store={"recent_topic": "LLM agents"})

# Execute = beta-reduction
result = agent("What are the latest advances in LLM agents?")
```

### YAML Configuration

```yaml
agentId: research-assistant
name: ResearchAssistant
type: react
systemPrompt: |
  You are a research assistant. Search for information,
  analyze it, and produce a comprehensive report.
model:
  provider: dashscope
  name: qwen3-max-2026-01-23
  temperature: 0.7
  maxTokens: 4096
react:
  maxSteps: 15
runtime:
  engine: recursive        # recursive | cek | adaptive
memory:
  enabled: true
  strategy: local
  size: 20
mcp:
  onlineTool:
    example-mcp-server:
      - everything_get_sum
  localTools:
    - terminate
```

```python
from lambdagent import from_config

agent = from_config("agent-config.yml")
result = agent("Summarize recent progress in AI safety research")
```

### Multi-Agent Group Chat

```python
from lambdagent import Lam, GroupChat, SharedMemory

researcher = Lam("researcher", "You are a researcher. Find evidence.")
critic = Lam("critic", "You are a critic. Challenge weak arguments.")
synthesizer = Lam("synthesizer", "You synthesize the discussion into conclusions.")

chat = GroupChat(
    agents=[researcher, critic, synthesizer],
    max_rounds=6,
    scheduler="round_robin",
)
result = chat("Should we invest in quantum computing?")
```

### MCP Tool Integration

```python
from lambdagent import mcp_tools, mcp_tool

# Get all tools from an MCP server
tools = mcp_tools("http://localhost:3000/mcp")

# Or get a single tool
search = mcp_tool("http://localhost:3000/mcp", "search")
result = search({"query": "AI agents"})
```

### RAG (Retrieval-Augmented Generation)

```python
from lambdagent import create_rag, AgenticRAG, Lam

rag = create_rag(["Python is a programming language.", "Lambda calculus is..."])
agent = Lam("qa", "Answer questions using the provided context.")
agentic = AgenticRAG(agent, rag, decider=lambda x: "?" in x)
result = agentic("What is Lambda calculus?")
```

### Checkpoint (Save/Resume)

```python
from lambdagent import Context, save_context, load_context

ctx = Context()
agent("long running task", ctx)
save_context(ctx, "checkpoint.json", last_input="long running task")

# Later, resume:
ctx = load_context("checkpoint.json")
agent("continue from here", ctx)
```

### Sandbox (Process Isolation)

```python
from lambdagent import SandboxedTool, SandboxPolicy, SecureExecutor, sandboxed

# One-line decorator
@sandboxed(timeout=10, memory_mb=128)
def risky_calc(x):
    return eval(x)

# Or explicit construction with policy presets
tool = SandboxedTool("calc", lambda x: eval(x), policy=SandboxPolicy.strict())

# Secure an entire term tree — wraps all Tools in sandboxes
secure_tree = SecureExecutor(policy=SandboxPolicy.default()).sandbox_all_tools(agent)
```

### One-Sentence Agent Builder

```bash
python experiments/nl2agent.py "Build a research assistant that can search the web and write reports, up to 20 steps, with memory"
```

Or programmatically:

```python
from experiments.nl2agent import one_sentence_to_agent

one_sentence_to_agent(
    "Build a code review pipeline: check security, then style, then performance",
    user_input="Review this Python function: def login(u, p): ...",
)
```

## CLI Usage

```bash
# Compile YAML to Lambda term (no execution)
lambdagent compile agent-config.yml

# Compile and execute
lambdagent run agent-config.yml "Write a quicksort in Python"

# Interactive REPL
lambdagent repl agent-config.yml

# Static analysis (lint)
lambdagent lint agent-config.yml

# Export pure Lambda expression
lambdagent lambda agent-config.yml

# Unix pipes work (composition = pipe)
echo "Hello world" | lambdagent run agent-config.yml -
```

## API Reference

### Core Terms (11 constructs)

- **`Term`** — Abstract base class. All constructs are Terms.
- **`Context`** — Evaluation environment with beta-reduction tracing.
- **`Lam(name, prompt)`** — Lambda abstraction. Wraps an LLM call.
- **`Compose(f, g)` / `f >> g`** — Function composition.
- **`If(cond, then_, else_)`** — Church conditional.
- **`Loop(body, condition)`** — Y combinator with termination.
- **`Pair(f, g)` / `Par(f, g)`** — Church pair / parallel execution.
- **`Fst()` / `Snd()`** — Pair projections.
- **`Tool(name, fn)`** — External oracle (MCP tool, shell command, etc.).
- **`Route(classifier, routes)`** — Generalized Church boolean (CASE).
- **`Guard(agent, validator)`** — Dependent type / output validation.
- **`Memory(agent, store)`** — Environment extension with persistent state.

### Multi-Agent (5 constructs)

- **`Channel(name, capacity)`** — pi-calculus channel for inter-agent communication.
- **`Send(agent, channel)`** — Send agent output to channel.
- **`Receive(channel, handler)`** — Receive from channel, optionally process with handler.
- **`SharedMemory(store, append_only)`** — Thread-safe shared state across agents.
- **`GroupChat(agents, scheduler, max_rounds)`** — Multi-agent group discussion (Y + Route).
- **`Handoff(selector, registry, fallback)`** — Runtime dynamic delegation.
- **`AsyncPar(*agents)`** — True parallel execution via thread pool.

### Skill System

- **`Skill(name, term, description, signature, tags)`** — Named, reusable Lambda term with metadata.
- **`SkillPack(name)`** — Collection of related skills.
- **`SkillRegistry()`** — Global singleton registry (search, discover, build_route).
- **`SkillAgent(classifier, registry)`** — Auto-discovers and executes best skill.
- **`@skill(name, description, tags)`** — Decorator to create and auto-register skills.

### MCP Client

- **`MCPServer.http(url)` / `MCPServer.stdio(command)`** — Connect to MCP servers.
- **`MCPTool(server, tool_name)`** — MCP tool wrapped as lambdagent Term.
- **`mcp_tools(url)`** — One-liner to get all tools from a server.
- **`mcp_tool(url, name)`** — One-liner to get a single tool.

### A2A Protocol

- **`AgentCard`** — A2A Agent capability description (JSON).
- **`A2AServer(agent, port)`** — Publish agent as A2A HTTP service.
- **`A2AClient(url)`** — Call remote A2A agent as local Term.
- **`skill_to_agent_card(skill)`** — Convert Skill to AgentCard.

### RAG

- **`RAGTool(store, top_k)`** — Retrieval tool (TF-IDF or ChromaDB).
- **`AgenticRAG(agent, rag, decider)`** — Agent decides when to retrieve.
- **`SimpleVectorStore()`** — Zero-dependency TF-IDF vector store.
- **`create_rag(documents, top_k)`** — One-liner to create RAG tool.

### Checkpoint

- **`Checkpoint(context, shared_data)`** — Execution state snapshot.
- **`CheckpointManager(directory)`** — Manage multiple checkpoints with auto-cleanup.
- **`save_context(ctx, path)` / `load_context(path)`** — Save/restore Context.

### Sandbox

- **`SandboxedTool(name, fn, policy)`** — Tool running in isolated subprocess with resource limits.
- **`SandboxPolicy(timeout, memory_mb, network, ...)`** — Security policy. Presets: `.strict()`, `.default()`, `.permissive()`.
- **`SecureExecutor(policy)`** — Auto-wraps all Tools in a term tree via `sandbox_all_tools()`.
- **`ResourceLimiter`** — Applies POSIX `RLIMIT_CPU`, `RLIMIT_AS`, `RLIMIT_NOFILE`, `RLIMIT_NPROC`.
- **`@sandboxed(timeout, memory_mb, ...)`** — Decorator for one-line sandboxed tool creation.
- **Exceptions:** `SandboxViolation`, `TimeoutViolation`, `MemoryViolation`, `OutputViolation`.

### Compiler

- **`from_config(path_or_dict)`** — YAML to Lambda term.
- **`lint_config(path_or_dict)`** — Static analysis.
- **`to_lambda_expr(path_or_dict)`** — Export formal Lambda expression.
- **`describe_config(path_or_dict)`** — Human-readable structure description.

### Runtime

- **`Runtime`** — Executes Lambda terms with LLM backends.
- **`ReActEngine`** — Implements the Y combinator loop for ReAct agents.
- **`MCPClient`** — Model Context Protocol tool invocation.
- **`TraceStore`** — Records beta-reduction traces for debugging.

## Theory

lambdagent is grounded in a formal correspondence between agent constructs and Lambda calculus:

- **Church encoding verification**: All 11 constructs are shown to be encodable as pure Lambda terms. The `If` construct uses Church booleans, `Pair`/`Fst`/`Snd` use Church pairs, and `Route` uses generalized Church numerals.
- **S+K completeness**: The DSL is computationally complete — `Lam` and application together can encode `S` and `K` combinators, from which all computable functions follow.
- **Y combinator semantics**: `Loop` is not ad-hoc iteration; it is the Y combinator `Y = λf.(λx.f(x x))(λx.f(x x))` with a bounded unfolding (`max_iterations`) to ensure termination.

For the full formal treatment, see [`docs/INTRODUCTION.md`](docs/INTRODUCTION.md) and the design docs under [`docs/`](docs/) (Church-encoding proofs, cost-vector semantics, algebraic laws).

## License

[Business Source License 1.1](LICENSE) — Copyright (c) 2025 kenny67nju

Non-production use (development, testing, personal projects, academic research) is always permitted. Production use is free for organizations with ≤10 individual users or employees. On **2031-04-05** (the Change Date), the license automatically converts to Apache License 2.0.

For production use beyond the 10-user limit before the Change Date, contact the licensor for a commercial license.

## Citation

If you use lambdagent in academic work, please cite:

```bibtex
@software{lambdagentpaas2025,
  title     = {lambdagentpaas: A Lambda Calculus Agent Platform},
  author    = {kenny67nju},
  year      = {2025},
  url       = {https://github.com/kenny67nju/lambdagentpaas},
}
```

To cite the DSL specifically (the `lambdagent/` subpackage, also published standalone on PyPI):

```bibtex
@software{lambdagent2025,
  title     = {lambdagent: A Lambda Calculus Agent DSL},
  author    = {kenny67nju},
  year      = {2025},
  url       = {https://github.com/kenny67nju/lambdagent},
}
```
