# nebula — full machine-readable docs > A Mantle-native, policy-aware AI treasury assistant. The AI advises; deterministic code enforces the fund controls. This file inlines every documentation page plus the repo README. Sections separated by horizontal rules. Each doc body is preceded by a source pointer when frontmatter declares one. > Setup: Nebula is a Bun + Biome monorepo. Run `bun install`, set `OPENAI_API_KEY` (the brain is any OpenAI-compatible model, default `gpt-4o-mini`), then `bun run nebula init` and `bun run nebula chat`. The default identity is a plain EOA; no on-chain mint is required to start. > Safety model: every value-moving action runs through policy (pure, unit-tested) -> simulate (dry-run) -> approval (material-risk prompts a human even under YOLO) -> execute (broadcast + receipt). The fund-control policy lives in `NEBULA_POLICY_*` environment variables, not in the prompt; the model cannot override it. Binary name: `nebula` (run via `bun run nebula`). Engine: Bun. --- ## README > Source: https://github.com/rstfulzz/nebula/blob/main/README.md

Nebula

A Mantle-native, policy-aware AI treasury assistant.
The AI advises. Deterministic code enforces the fund controls.

License: MIT Built on Mantle Bun

--- Nebula is an AI agent that does real on-chain work on **Mantle** — check balances, transfer, swap, wrap, lend, and discover yield — from your **terminal**, **Telegram**, or a **web console**. What makes it more than a chatbot with a wallet is the part the AI *cannot* override: every value-moving action is checked against a deterministic policy, dry-run simulated, and (when material-risk) held for human approval before it is broadcast. The model proposes; code disposes. > **One line:** an AI treasury operator you can actually trust with a wallet, because the spending limits, allowlists, and approval gates live in auditable code — not in a prompt the model could rationalize its way around. ## Why this design LLMs are good at *deciding what to do* and bad at *being a safety boundary*. A jailbreak, a confused tool call, or a hallucinated "the user said it was fine" should never be the only thing standing between an agent and your treasury. So Nebula splits the two: - **Advisory layer (the AI):** understands intent, picks tools, explains tradeoffs, discovers opportunities. - **Control layer (deterministic code):** a pure policy engine + pre-flight simulation + an approval floor that the model has no way to bypass. This is the defensible core — unified risk analysis, RWA-eligibility awareness, transaction simulation, enforceable policy controls, approvals, and auditable execution. ## The write pipeline Every value-moving tool call (`chain.send`, `swap.execute`, `aave.supply`/`withdraw`, `chain.wrap`/`unwrap`, `chain.write`) goes through the same four gates: ``` ┌───────────┐ ┌────────────┐ ┌─────────────┐ ┌──────────┐ intent →│ POLICY │ ──▶ │ SIMULATE │ ──▶ │ APPROVAL │ ──▶ │ EXECUTE │ → receipt │ (pure fn) │ │ (dry-run) │ │ (if risky) │ │ + verify │ └───────────┘ └────────────┘ └─────────────┘ └──────────┘ hard caps, estimateGas / material-risk broadcast + allowlists, simulateContract actions prompt wait for autonomy tier aborts doomed tx EVEN IN yolo on-chain receipt ``` 1. **Policy** (`evaluatePolicy`, pure + unit-tested): hard caps on native/token amounts, recipient + token allowlists, slippage caps, and an autonomy tier. A violation **blocks** the action; an in-cap-but-material-risk action is flagged for approval. No network, no model — fully auditable. 2. **Simulate**: the tx is dry-run (`estimateGas` / `simulateContract`) before any gas is spent; a revert aborts with a decoded reason. 3. **Approval floor**: this is the part that matters. The policy verdict sits *beneath* the session permission mode — so a material-risk action prompts for human approval **even under YOLO/auto**, and is denied outright under `strict`. Fund controls in code, not in the model. 4. **Execute**: broadcast on Mantle, wait for the receipt, return a decision record (policy verdict + sim gas + tx hash). Configure the policy entirely from the environment (no code changes): ```bash NEBULA_POLICY_MAX_NATIVE_MNT=2.0 # hard cap: block sends over 2 MNT NEBULA_POLICY_AUTO_MAX_NATIVE_MNT=0.1 # auto-execute up to 0.1 MNT; above → require approval NEBULA_POLICY_MAX_SLIPPAGE_BPS=100 # block swaps over 1% slippage NEBULA_POLICY_AUTONOMY=auto # auto | confirm | readonly NEBULA_POLICY_RECIPIENT_ALLOWLIST=0xabc...,0xdef... NEBULA_POLICY_TOKEN_ALLOWLIST=0x...,0x... NEBULA_POLICY_READONLY=1 # reject all writes ``` ## Capabilities | Area | Tools | Notes | | --- | --- | --- | | Wallet / account | `account.info`, `account.balance` | identity + token snapshot (wallet + brain + recent activity, single Multicall3 round-trip) | | Balances / tokens | `chain.balance`, `tokens.info` | Transfer-event discovery; symbol/address resolution | | Transfers | `chain.send`, `chain.wrap`, `chain.unwrap` | native MNT ↔ WMNT; 0x recipients | | Trading | `swap.best`, `swap.compare`, `swap.quote`/`swap.execute`, `moe.quote`/`moe.swap` | **Agni Finance** (V3-style) + **Merchant Moe** (Liquidity Book). `swap.best` quotes both and routes to the better venue | | Controls | `policy.show` | report the active fund-control policy (caps, allowlists, autonomy, approval threshold) | | Lending | `aave.markets`, `aave.position`, `aave.supply`, `aave.withdraw`, `aave.borrow`, `aave.repay` | **Aave V3** full suite — live supply/borrow rates per reserve, supply/withdraw collateral, borrow/repay (variable rate); receipts report the resulting health factor | | Discovery | `defi.yields` | **DeFiLlama** analytics: Mantle pools ranked by APY/TVL with risk + RWA flags (read-only) | | Risk | `risk.token`, `nansen.labels` | pre-trade token vet (exit / liquidity / restricted-RWA / real-contract → low/elevated/high); **Nansen** counterparty intel (exchange/fund/smart-money + red-flags: scam/hack/sanctioned/mixer) — env `NANSEN_API_KEY` | | CEX (read-only) | `cex.balance` | **Bybit** Unified portfolio view, read-only (env keys). No CEX trading — that would bypass the on-chain safety pipeline | | Identity (ERC-8004) | `identity.resolve`, `identity.register` | **ERC-8004 Identity Registry** — register a transferable identity NFT + agent card; resolve any agent's card / owner / operational address | | Reputation (ERC-8004) | `reputation.give`, `reputation.show` | **ERC-8004 Reputation Registry** — record on-chain feedback (0–100 score + tag) about an agent; read its rating count + average | | Validation (ERC-8004) | `validation.request`, `validation.respond`, `validation.show` | **ERC-8004 Validation Registry** — open a validation request anchoring an agent's output, and publish an independent validator's pass/fail verdict | | Analysis | `chain.tx`, `chain.contract`, `chain.activity` | decode tx, introspect contracts, recent transfers | | Blockchain | `chain.block`, `chain.gas` | head, timestamp, gas price | | Generic | `chain.read`, `chain.write`, `tx.simulate` | any contract by `signature` + `args`; `tx.simulate` dry-runs any call (would-succeed + gas, or decoded revert) without broadcasting | Plus the host harness: shell / code execution (OS-sandboxed), file ops, web fetch + headless browser, and a persistent memory store. **RWA / restricted awareness:** `defi.yields` surfaces every Mantle pool but flags restricted products (USDY / MI4 / mUSD) so the agent only proposes entering them with explicit eligibility confirmation. DeFiLlama is used for *discovery and analytics only* — never execution. ### ERC-8004 (Trustless Agents) The full 3-registry spec — **Identity + Reputation + Validation** — is implemented (self-contained contracts in `contracts/`) and **deployed live on Mantle** (mainnet + Sepolia): | Registry | Mainnet (5000) | Sepolia (5003) | | --- | --- | --- | | Identity | `0x00a818451dC072d449e92a21d02d6B68fc703588` | `0x529ae7B0e8A8191c0307b918AA62f1Fc6557a621` | | Reputation | `0x56b11a8f34eCb20899BD4E1eA539E194F007F361` | `0x0DA4162BdFaFd0b5a6Da4151E0415aEaBd87B521` | | Validation | `0x4A222ec3D7e656ADFE28583219Bed3462973DECD` | `0x5eDa2Be8c2c24039952751C817a7E9C8E018628e` | An agent gets a transferable ERC-721 identity whose tokenURI is its agent card; other agents record reputation feedback and request/publish validations of its output. Drive it from the CLI (`nebula identity|reputation|validation`) or as brain tools (`identity.*`, `reputation.*`, `validation.*`). Override addresses per network with `NEBULA_{IDENTITY,REPUTATION,VALIDATION}_REGISTRY`. ## Quickstart **One-liner** — installs [bun](https://bun.sh) if needed, the `nebula` CLI, and adds it to your PATH: ```bash curl -fsSL https://raw.githubusercontent.com/rstfulzz/nebula/main/install.sh | bash ``` Open a new terminal afterwards (the installer appends bun's bin dir to your shell rc), then `nebula` works anywhere — like `claude`.
Manual install / from source `nebula` is bun-native. `bun add -g` drops the `nebula` command in `~/.bun/bin`, which must be on your `PATH`: ```bash bun add -g nebula-treasury export PATH="$HOME/.bun/bin:$PATH" # add to ~/.zshrc (or ~/.bashrc) to persist ``` Or run from a clone: `bun install`, then `bun run nebula …`.
Then point the brain at an OpenAI-compatible key and bootstrap an agent: ```bash export OPENAI_API_KEY=sk-... # optional: export NEBULA_LLM_BASE_URL=https://api.openai.com/v1 ; export NEBULA_LLM_MODEL=gpt-4o-mini nebula init # generates an agent wallet + local encrypted keystore (plain EOA, no mint) nebula # chat in the terminal ``` Fund the agent's EOA with a little MNT for gas, set your `NEBULA_POLICY_*` limits, and ask it: *"what's my balance?"*, *"best stablecoin yield on Mantle?"*, *"swap 1 MNT for USDC"*, *"supply 5 USDC to Aave"*. Material-risk actions pause for your approval. **Telegram:** set `TELEGRAM_BOT_TOKEN` (+ optional `TELEGRAM_CHAT_ID`) in your env, or run `nebula telegram setup` — then drive the same agent, with the same approval gates, from your phone via inline-keyboard. ## Mantle specifics - **Mainnet** chain id `5000` · RPC `rpc.mantle.xyz` · explorer `mantlescan.xyz` - **Sepolia testnet** chain id `5003` · RPC `rpc.sepolia.mantle.xyz` · explorer `sepolia.mantlescan.xyz` - Gas token: **MNT**. Execution + settlement happen on Mantle; official contracts/ABIs/RPC are used for all writes. ## Architecture A Bun + Biome monorepo: ``` packages/ core # brain (OpenAI-compatible), storage (SQLite, content-addressed), # permission service + approval floor, plugin host, identity, memory plugin-onchain # the Mantle limbs: policy engine, simulation, transfers, Agni + Merchant Moe swaps, # Aave lending, DeFiLlama discovery, chain read/write/analysis plugin-system # OS-sandboxed shell / code / file / web / browser tools plugin-telegram # Telegram listener + inline-keyboard approvals gateway # long-running daemon (keeps Telegram online, routes approvals) cli # `nebula` binary (init, chat, telegram, gateway, ...) apps/ web # Next.js console + docs site ``` - **Brain:** any OpenAI-compatible model (default `gpt-4o-mini`), swappable via env. - **Storage:** local SQLite, content-addressed (`0x` + sha256 CID). - **Stack:** [viem](https://viem.sh) for all chain I/O, [zod](https://zod.dev) tool schemas. ## Development ```bash bun run typecheck # tsc -b across the workspace bun test # unit tests (policy, simulation, approval floor, discovery, ...) bun run lint # biome bun run fix # biome autofix + format ``` The policy engine, approval floor, simulation guards, and the DeFiLlama discovery logic are all covered by deterministic unit tests (no network, injected fetch) so the safety boundary is verifiable in CI. For a live end-to-end check against Mantle mainnet (read a slice of every capability + the policy/simulate gates, no private key needed): ```bash bun run smoke # 11 checks against real Mantle RPC; Nansen/Bybit use .env keys if present ``` ## License MIT. --- ## For Agents > Source: https://github.com/rstfulzz/nebula/blob/main/apps/web/content/docs/11-agents.md # An honest guide for AI agents. You are an LLM. A human asked you to set up Nebula. This page tells you what you can do for them, what you must hand back, and what you should never claim. The goal is fewer hallucinated steps and fewer hung scripts. If you only read one line: **Bun is required, the brain is any OpenAI-compatible model (set `OPENAI_API_KEY`), and the fund-control policy lives in `NEBULA_POLICY_*` environment variables, not in the prompt.** ## Install Nebula is a Bun + Biome monorepo. Bun runs the install and the CLI. ```bash bun install export OPENAI_API_KEY=sk-... bun run nebula init bun run nebula chat ``` `init` generates a fresh agent wallet and a local encrypted keystore. The default identity is a plain EOA, so there is no on-chain mint and no operator signature required to get started. ## What you can do for the user - Install dependencies (`bun install`) and confirm Bun is present. - Configure the brain: set `OPENAI_API_KEY`, optionally `NEBULA_LLM_BASE_URL` and `NEBULA_LLM_MODEL` (default `gpt-4o-mini`). - Set the fund-control policy via `NEBULA_POLICY_*` (caps, allowlists, slippage, autonomy tier, read-only). See [Configuration](/docs/configuration). - Explain commands. The five the user runs most: `bun run nebula init`, `bun run nebula chat`, `bun run nebula telegram setup`, plus the gateway. See [CLI](/docs/cli). - Help them ask the agent to read or act: balances, yield discovery, transfers, Agni swaps, Aave supply/withdraw. See [Tools](/docs/tools). ## How the safety model works (so you do not fight it) Every value-moving action runs through a four-gate pipeline: policy (pure, unit-tested), simulation (dry-run before gas), an approval floor (material-risk actions prompt a human even under YOLO), and execution (broadcast plus receipt). The model proposes; deterministic code disposes. You cannot raise a limit, skip a simulation, or grant approval from the model. Those decisions live in code. Do not write scripts that try to route around them. ## Anti-patterns to avoid - **Do NOT** tell the user the model can override a policy limit. It cannot. The limits are in code. - **Do NOT** invent on-chain identity ceremonies. The default identity is a plain EOA; there is no mint, no token, no naming claim required to start. - **Do NOT** default to mainnet for exploratory work. Use the Mantle Sepolia testnet (chain id 5003) first, then move to mainnet (chain id 5000) once the policy is set. - **Do NOT** script destructive actions (large transfers, withdrawals) without having the user confirm. Material-risk actions will pause for approval anyway; respect that. ## Networks | Network | Chain ID | RPC | Explorer | |---|---|---|---| | Mantle mainnet | 5000 | `https://rpc.mantle.xyz` | `https://mantlescan.xyz` | | Mantle Sepolia testnet | 5003 | `https://rpc.sepolia.mantle.xyz` | `https://sepolia.mantlescan.xyz` | Gas token is MNT. ## Machine-readable surfaces - [/llms.txt](/llms.txt): index with one bullet per doc. Fetch this first. - [/llms-full.txt](/llms-full.txt): a single-file dump of every doc plus the repo README. - [/docs/.md](/docs/agents.md): raw markdown per page (for example `/docs/quickstart.md`, `/docs/cli.md`). Always re-fetch before relying on cached prior advice. --- ## Quickstart > Source: https://github.com/rstfulzz/nebula/blob/main/README.md # Run your first policy-gated agent. A few commands take you from install to a live chat. `init` creates a local agent (a fresh agent wallet plus a local encrypted keystore). The default identity is a plain EOA, so no on-chain mint is required. ## Prerequisites [Bun](https://bun.sh). The monorepo and CLI run on Bun. An OpenAI-compatible LLM key. The brain is any OpenAI-compatible model; the default is `gpt-4o-mini`. You can point it at any base URL and model via environment variables. A little MNT on Mantle to pay gas for the actions you ask the agent to take. ## Install and configure ```bash bun install # Configure the brain (OpenAI-compatible; any base URL / model works) export OPENAI_API_KEY=sk-... # optional overrides: # export NEBULA_LLM_BASE_URL=https://api.openai.com/v1 # export NEBULA_LLM_MODEL=gpt-4o-mini ``` ## Init ```bash bun run nebula init ``` `init` generates an agent wallet and writes a local encrypted keystore. The default identity is a plain EOA, so there is no on-chain mint and no operator signature required to get started. ## Set the policy Configure the boundary entirely from the environment. These limits live in deterministic, unit-tested code; the model cannot raise them at runtime. ```bash NEBULA_POLICY_MAX_NATIVE_MNT=2.0 # hard cap: block sends over 2 MNT NEBULA_POLICY_AUTO_MAX_NATIVE_MNT=0.1 # auto-execute up to 0.1 MNT; above this requires approval NEBULA_POLICY_MAX_SLIPPAGE_BPS=100 # block swaps over 1% slippage NEBULA_POLICY_AUTONOMY=auto # auto | confirm | readonly NEBULA_POLICY_RECIPIENT_ALLOWLIST=0xabc...,0xdef... NEBULA_POLICY_TOKEN_ALLOWLIST=0x...,0x... NEBULA_POLICY_READONLY=1 # reject all writes ``` ## Chat ```bash bun run nebula chat ``` Fund the agent's EOA with a little MNT for gas, set your `NEBULA_POLICY_*` limits, and ask it to do things: "what's my balance?", "best stablecoin yield on Mantle?", "swap 1 MNT for USDC", "supply 5 USDC to Aave". Reads run freely. Every value-moving action runs the four-gate pipeline (policy, simulate, approval, execute) before it broadcasts, and material-risk actions pause for your approval. ## Telegram Run the same agent, with the same approval gates, from your phone: ```bash bun run nebula telegram setup ``` Approval prompts arrive as inline-keyboard buttons. Read [Architecture](/docs/architecture) next to understand how the pipeline fits together. Source: [`README.md`](https://github.com/rstfulzz/nebula/blob/main/README.md). --- ## Configuration > Source: https://github.com/rstfulzz/nebula/blob/main/README.md # Configured from the environment. The brain and the entire fund-control policy are configured from environment variables. No code changes are needed to change a limit, and nothing the model outputs can override them, because the policy is enforced in deterministic, unit-tested code. ## Brain ```bash export OPENAI_API_KEY=sk-... # optional overrides: export NEBULA_LLM_BASE_URL=https://api.openai.com/v1 # any OpenAI-compatible endpoint export NEBULA_LLM_MODEL=gpt-4o-mini # default model ``` Any OpenAI-compatible model works. Swapping the model has no effect on the safety boundary. ## Policy ```bash NEBULA_POLICY_MAX_NATIVE_MNT=2.0 # hard cap: block sends over 2 MNT NEBULA_POLICY_AUTO_MAX_NATIVE_MNT=0.1 # auto-execute up to 0.1 MNT; above this requires approval NEBULA_POLICY_MAX_SLIPPAGE_BPS=100 # block swaps over 1% slippage NEBULA_POLICY_AUTONOMY=auto # auto | confirm | readonly NEBULA_POLICY_RECIPIENT_ALLOWLIST=0xabc...,0xdef... NEBULA_POLICY_TOKEN_ALLOWLIST=0x...,0x... NEBULA_POLICY_READONLY=1 # reject all writes ``` | Variable | Controls | |---|---| | `NEBULA_POLICY_MAX_NATIVE_MNT` | Hard cap on native MNT per action. A value above this blocks. | | `NEBULA_POLICY_AUTO_MAX_NATIVE_MNT` | The amount the agent may move without prompting. Above it, approval is required. | | `NEBULA_POLICY_MAX_SLIPPAGE_BPS` | Maximum allowed swap slippage, in basis points. | | `NEBULA_POLICY_AUTONOMY` | `auto` (act within tier), `confirm` (prompt on writes), `readonly` (no writes). | | `NEBULA_POLICY_RECIPIENT_ALLOWLIST` | Comma-separated recipient addresses the agent may send to. | | `NEBULA_POLICY_TOKEN_ALLOWLIST` | Comma-separated token addresses the agent may touch. | | `NEBULA_POLICY_READONLY` | When set, all writes are rejected outright. | The approval floor sits beneath the autonomy tier: a material-risk action prompts for a human even under `auto` / YOLO, and is denied under `readonly` / strict. ## Networks | Network | Chain ID | RPC | Explorer | |---|---|---|---| | Mantle mainnet | 5000 | `https://rpc.mantle.xyz` | `https://mantlescan.xyz` | | Mantle Sepolia testnet | 5003 | `https://rpc.sepolia.mantle.xyz` | `https://sepolia.mantlescan.xyz` | Gas token is MNT. Start on the Sepolia testnet for exploratory work, then move to mainnet once your policy is set. Read [Console](/docs/console) next. Source: [`README.md`](https://github.com/rstfulzz/nebula/blob/main/README.md). --- ## CLI > Source: https://github.com/rstfulzz/nebula/blob/main/packages/cli # The nebula command. The `nebula` binary owns onboarding, chat, the Telegram bridge, and the gateway daemon. Run it through Bun from the repo (`bun run nebula `). ## Init ```bash bun run nebula init ``` Generates a fresh agent wallet and writes a local encrypted keystore. The default identity is a plain EOA, so there is no on-chain mint and no operator signature required. Set your `OPENAI_API_KEY` (and any `NEBULA_LLM_*` overrides) before you start so the brain is configured. ## Chat ```bash bun run nebula chat ``` Drops into the interactive terminal session. Ask the agent to read or act: "what's my balance?", "best stablecoin yield on Mantle?", "swap 1 MNT for USDC", "supply 5 USDC to Aave". Reads return directly. Every value-moving action runs the four-gate pipeline, and material-risk actions pause for your approval inline. ## Telegram ```bash bun run nebula telegram setup ``` Pairs a Telegram bot so you can drive the same agent from your phone, with the same approval gates. Approval prompts arrive as inline-keyboard buttons. ## Gateway The gateway is a long-running daemon that keeps Telegram online and routes approval prompts even when you do not have an interactive session open. It is the process that lets the agent stay reachable between chats. ## Setting the policy The CLI reads the boundary from the environment. Set the `NEBULA_POLICY_*` variables (caps, allowlists, slippage, autonomy tier, read-only) before launching; see [Configuration](/docs/configuration) for the full list. The limits are enforced in deterministic code, so the agent cannot raise them at runtime. Read [Configuration](/docs/configuration) next. Source: [`packages/cli`](https://github.com/rstfulzz/nebula/tree/main/packages/cli). --- ## Brain > Source: https://github.com/rstfulzz/nebula/blob/main/README.md # An advisory brain you can swap. The brain is any OpenAI-compatible model. The default is `gpt-4o-mini`. Point it at a different base URL or model with environment variables and nothing else changes, because the model never gets to be the safety boundary. ```bash export OPENAI_API_KEY=sk-... # optional overrides: export NEBULA_LLM_BASE_URL=https://api.openai.com/v1 export NEBULA_LLM_MODEL=gpt-4o-mini ``` ## What the brain does The brain is the advisory layer. It reads the operator's intent, picks tools, explains tradeoffs, and discovers opportunities. It proposes actions; it does not authorize them. ## What the brain cannot do It cannot raise a policy limit, skip a simulation, or grant its own approval. Those decisions are made by deterministic code in the control layer, which sits beneath the model and is unaffected by anything the model outputs. A jailbreak or a confused tool call still hits a hard cap, a simulation, and an approval floor before any value moves. See [Architecture](/docs/architecture) for the four-gate pipeline. ## How a turn happens 1. The brain receives the operator's message plus the relevant memory index. 2. It decides whether to read (free) or to propose a value-moving action. 3. Reads return results directly. A proposed write is handed to the policy engine, simulated, and (if material-risk) held for approval before execution. 4. Cleared writes broadcast on Mantle and return a decision record the brain can report back. Because the boundary lives in code, swapping the model is a one-line change with no impact on safety. A worse model can be wrong about what to do, but it cannot get past the gates. Read [Tools](/docs/tools) next. Source: [`README.md`](https://github.com/rstfulzz/nebula/blob/main/README.md). --- ## Tools > Source: https://github.com/rstfulzz/nebula/blob/main/packages/plugin-onchain # Limbs that do, gates that decide. Tools do literal work, never safety logic. The brain decides which tool to call; the deterministic control layer decides whether a value-moving call is allowed. Reads are free. Every write (`chain.send`, `swap.execute`, `aave.supply` / `withdraw`, `chain.wrap` / `unwrap`, `chain.write`) goes through policy, simulation, and approval first. ## On-chain tools (plugin-onchain) | Area | Tools | Notes | |---|---|---| | Wallet / account | `account.info`, `account.balance` | Identity plus token snapshot plus activity; native MNT position. | | Balances / tokens | `chain.balance`, `tokens.info` | Transfer-event discovery (no curated list). | | Transfers | `chain.send`, `chain.wrap`, `chain.unwrap` | Native MNT and WMNT; 0x recipients. | | Trading | `swap.best`, `swap.compare`, `swap.quote` / `swap.execute`, `moe.quote` / `moe.swap` | Agni Finance (Uniswap-V3-style) and Merchant Moe (Liquidity Book). `swap.best` quotes both and routes to the better venue. | | Lending | `aave.markets`, `aave.position`, `aave.supply`, `aave.withdraw`, `aave.borrow`, `aave.repay` | Aave V3 full suite: live supply / borrow rates, supply / withdraw collateral, borrow / repay (variable rate); receipts report the health factor. | | Discovery | `defi.yields` | DeFiLlama analytics: Mantle pools ranked by APY / TVL with risk and RWA flags (read-only). | | Risk | `risk.token` | Pre-trade vet: can you exit it (live Agni / Moe quote), liquidity depth, restricted-RWA flag, real-contract check, into a low / elevated / high verdict. | | Controls | `policy.show`, `tx.simulate` | Report the active fund-control policy; dry-run any call (would-succeed plus gas, or decoded revert) without broadcasting. | | Analysis | `chain.tx`, `chain.contract`, `chain.activity` | Decode tx, introspect contracts, recent transfers (with optional method decode). | | Blockchain | `chain.block`, `chain.gas` | Head, timestamp, gas price plus estimated MNT cost of common ops. | | Generic | `chain.read`, `chain.write` | Any contract by `signature` plus `args`. | Source: [`packages/plugin-onchain`](https://github.com/rstfulzz/nebula/tree/main/packages/plugin-onchain). ## RWA and restricted awareness `defi.yields` surfaces every Mantle pool but flags restricted products (USDY, MI4, mUSD) so the agent only proposes entering them with explicit eligibility confirmation. DeFiLlama is used for discovery and analytics only, never execution. ## Host harness (plugin-system) The agent also has a general-purpose toolkit for the work around the chain: OS-sandboxed shell and code execution, file operations, web fetch, and a headless browser. These run on the operator's machine under the OS sandbox. Source: [`packages/plugin-system`](https://github.com/rstfulzz/nebula/tree/main/packages/plugin-system). ## Telegram (plugin-telegram) A Telegram listener turns inbound DMs into agent events. Approval prompts arrive as inline-keyboard buttons, so the same boundary applies whether you drive the agent from the terminal or your phone. Source: [`packages/plugin-telegram`](https://github.com/rstfulzz/nebula/tree/main/packages/plugin-telegram). ## Approval modes The session permission mode controls how much the agent does without prompting, but the approval floor sits beneath it. A material-risk action prompts for a human even when the session is in `auto` / YOLO, and is denied outright under `strict` and read-only. Configure it with `NEBULA_POLICY_AUTONOMY` and the rest of the `NEBULA_POLICY_*` variables. See [Configuration](/docs/configuration). Read [CLI](/docs/cli) next. Source: [`packages/plugin-onchain`](https://github.com/rstfulzz/nebula/tree/main/packages/plugin-onchain). --- ## Memory > Source: https://github.com/rstfulzz/nebula/blob/main/README.md # A local, content-addressed memory. Nebula keeps a persistent memory store on the operator's machine. It is local SQLite, content-addressed (`0x` plus sha256 CID), so the same content always resolves to the same id and nothing is duplicated. There is no remote storage layer and nothing is uploaded. ## What it stores The agent writes typed markdown notes plus an index of them. The index is the canonical entry point; the agent reads it to decide which notes to open in full. This keeps the model's working context small while still letting it recall facts it has learned across sessions. Practical examples of what lands in memory: - Operator preferences and instructions worth keeping between sessions. - Facts the agent has confirmed about your treasury or the protocols it works with. - References to external systems it has been pointed at. ## Why local Memory is observability and recall, not a safety boundary. Keeping it local keeps the data on your machine and keeps the design honest: nothing about memory can move funds. The thing that can move funds is the policy-gated write pipeline, and that is governed entirely by the deterministic control layer described in [Architecture](/docs/architecture). ## Reading it back The web console renders the same memory the agent reads, with the same typography you are reading now, so an operator can audit exactly what the agent has stored. See [Console](/docs/console). Read [Brain](/docs/brain) next. Source: [`README.md`](https://github.com/rstfulzz/nebula/blob/main/README.md). --- ## Architecture > Source: https://github.com/rstfulzz/nebula/blob/main/README.md # An advisory brain, a deterministic boundary. Nebula splits an agent into two layers that never trade places. The advisory layer (the AI) decides what to do. The control layer (deterministic code) decides whether it is allowed to happen. Every value-moving action crosses the same four gates before it touches the chain. ``` ┌───────────┐ ┌────────────┐ ┌─────────────┐ ┌──────────┐ intent →│ POLICY │ ──▶ │ SIMULATE │ ──▶ │ APPROVAL │ ──▶ │ EXECUTE │ → receipt │ (pure fn) │ │ (dry-run) │ │ (if risky) │ │ + verify │ └───────────┘ └────────────┘ └─────────────┘ └──────────┘ hard caps, estimateGas / material-risk broadcast + allowlists, simulateContract actions prompt wait for autonomy tier aborts doomed tx EVEN IN yolo on-chain receipt ``` ## The four gates Every value-moving tool call (`chain.send`, `swap.execute`, `aave.supply` / `withdraw`, `chain.wrap` / `unwrap`, `chain.write`) goes through the same pipeline: 1. **Policy** (`evaluatePolicy`, pure and unit-tested): hard caps on native and token amounts, recipient and token allowlists, slippage caps, and an autonomy tier. A violation blocks the action; an in-cap but material-risk action is flagged for approval. No network, no model, fully auditable. 2. **Simulate**: the transaction is dry-run with `estimateGas` / `simulateContract` before any gas is spent; a revert aborts with a decoded reason. 3. **Approval floor**: the policy verdict sits beneath the session permission mode, so a material-risk action prompts for human approval even under YOLO / auto, and is denied outright under `strict`. Fund controls in code, not in the model. 4. **Execute**: broadcast on Mantle, wait for the receipt, return a decision record (policy verdict plus simulated gas plus tx hash). ## The monorepo A Bun + Biome monorepo: ``` packages/ core brain (OpenAI-compatible), storage (SQLite, content-addressed), permission service + approval floor, plugin host, identity, memory plugin-onchain the Mantle limbs: policy engine, simulation, transfers, Agni swaps, Aave lending, DeFiLlama discovery, chain read/write/analysis plugin-system OS-sandboxed shell / code / file / web / browser tools plugin-telegram Telegram listener + inline-keyboard approvals gateway long-running daemon (keeps Telegram online, routes approvals) cli the `nebula` binary (init, chat, telegram, gateway, ...) apps/ web Next.js console + docs site ``` ## The runtime - **Brain**: any OpenAI-compatible model (default `gpt-4o-mini`), swappable via environment variable. - **Storage**: local SQLite, content-addressed (`0x` plus sha256 CID). - **Chain I/O**: [viem](https://viem.sh) for every read and write; [zod](https://zod.dev) tool schemas. - **Surfaces**: a terminal TUI, a Telegram bridge, and the web console. A request from any surface runs the identical pipeline. The policy engine, approval floor, simulation guards, and the DeFiLlama discovery logic are covered by deterministic unit tests (no network, injected fetch), so the safety boundary is verifiable in CI. ## Mantle specifics - **Mainnet** chain id `5000` · RPC `rpc.mantle.xyz` · explorer `mantlescan.xyz` - **Sepolia testnet** chain id `5003` · RPC `rpc.sepolia.mantle.xyz` · explorer `sepolia.mantlescan.xyz` - Gas token: MNT. Execution and settlement happen on Mantle; official contracts, ABIs, and RPC data are used for all writes. Read [Identity](/docs/identity) next. Source: [`README.md`](https://github.com/rstfulzz/nebula/blob/main/README.md). --- ## Identity > Source: https://github.com/rstfulzz/nebula/blob/main/README.md # A plain wallet, an enforced boundary. The agent's identity is a plain EOA. `nebula init` generates a fresh agent wallet and writes a local encrypted keystore. There is no on-chain mint and no operator signature required to get started; the default identity is just an address that holds MNT and signs the transactions the agent is allowed to send. ## The agent wallet The agent EOA is the address that pays gas and is the `from` of every write the agent executes. Fund it with a little MNT and the agent can transact within the limits you set. The private key is stored locally in an encrypted keystore, never sent to the model and never required to live anywhere but the operator's machine. ## What actually constrains the agent The identity is deliberately boring. The interesting part is the boundary around it: the policy engine. What the agent can do with its wallet is decided entirely by deterministic configuration, not by the address itself. | Control | Configured by | Effect | |---|---|---| | Hard caps | `NEBULA_POLICY_MAX_NATIVE_MNT`, slippage caps | Block any action over the limit. | | Allowlists | `NEBULA_POLICY_RECIPIENT_ALLOWLIST`, `NEBULA_POLICY_TOKEN_ALLOWLIST` | Restrict recipients and tokens. | | Autonomy tier | `NEBULA_POLICY_AUTONOMY` (`auto` / `confirm` / `readonly`) | How much the agent may do without a prompt. | | Read-only | `NEBULA_POLICY_READONLY` | Reject all writes outright. | These live in code and environment, so the boundary is the same whether the request arrives from the terminal, Telegram, or the web console. ## Mantle networks - Mainnet chain id `5000`, RPC `rpc.mantle.xyz`, explorer `mantlescan.xyz`. - Sepolia testnet chain id `5003`, RPC `rpc.sepolia.mantle.xyz`, explorer `sepolia.mantlescan.xyz`. Start on the Sepolia testnet for exploratory work, then move to mainnet once your policy is set the way you want it. Read [Memory](/docs/memory) next. Source: [`README.md`](https://github.com/rstfulzz/nebula/blob/main/README.md). --- ## Console > Source: https://github.com/rstfulzz/nebula/blob/main/apps/web/app/console # A browser-side operator dashboard. The console at [/console](/console) is the observability surface for your agent. Connect a wallet, sign in, and audit what the agent holds, what it remembers, and what it has done. Everything sensitive stays in the browser tab; no key material is sent to a server. ## The flow 1. **Connect wallet.** Pick any browser wallet. The console reads against Mantle. 2. **Sign in with Ethereum.** A SIWE (EIP-4361) signature proves you own the address. The server issues a session cookie that holds only your address; it performs no on-chain action. 3. **Pick an agent.** The dashboard lists the agents associated with your wallet and opens a detail view with tabs for identity, memory, activity, and wallet. 4. **Unlock when needed.** Tabs that show encrypted content prompt your wallet to unlock locally. The decryption happens in the browser; nothing leaves the tab. ## What you can see - **Identity.** The agent's address and on-chain metadata. - **Memory.** The agent's stored notes, rendered with the same typography you are reading now, so you see exactly what the agent sees. - **Activity.** A log of recent turns: what the agent did, the tool calls it issued, and the approval decisions. - **Wallet.** The agent's balance on Mantle. ## Console vs CLI The console is the audit and observability surface. The CLI is the command surface: that is where you init an agent, chat, and drive value-moving actions through the policy-gated pipeline. See [CLI](/docs/cli). Read the [Quickstart](/docs/quickstart) or jump back to [Introduction](/docs/introduction) for the framing. Source: [`apps/web/app/console`](https://github.com/rstfulzz/nebula/tree/main/apps/web/app/console). --- ## Introduction > Source: https://github.com/rstfulzz/nebula/blob/main/README.md # An AI agent you can trust with a wallet. Nebula is an AI agent that does real on-chain work on Mantle, check balances, transfer, swap, wrap, lend, and discover yield, from your terminal, Telegram, or a web console. What makes it more than a chatbot with a wallet is the part the AI cannot override: every value-moving action is checked against a deterministic policy, dry-run simulated, and (when material-risk) held for human approval before it is broadcast. The model proposes; code disposes. The pitch in one line: an AI treasury operator you can actually trust with a wallet, because the spending limits, allowlists, and approval gates live in auditable code, not in a prompt the model could rationalize its way around. ## Why this design LLMs are good at deciding what to do and bad at being a safety boundary. A jailbreak, a confused tool call, or a hallucinated "the user said it was fine" should never be the only thing standing between an agent and your treasury. So Nebula splits the two. | Layer | Who | What it owns | |---|---|---| | Advisory | The AI | Understands intent, picks tools, explains tradeoffs, discovers opportunities. | | Control | Deterministic code | A pure policy engine, pre-flight simulation, and an approval floor the model has no way to bypass. | This is the defensible core: unified risk analysis, RWA-eligibility awareness, transaction simulation, enforceable policy controls, approvals, and auditable execution. It is not a generic chatbot and not an APY-ranking bot. ## What it does today Balances and tokens, transfers (native MNT and ERC-20, wrap and unwrap MNT to WMNT), trading via Agni Finance, lending via Aave V3, yield discovery via DeFiLlama (read-only analytics with risk signals and RWA-eligibility flags for restricted products like USDY, MI4, and mUSD), and chain analysis with arbitrary contract read and write. The brain is any OpenAI-compatible model (default `gpt-4o-mini`), swappable by environment variable. Storage is a local content-addressed SQLite store. Chain I/O goes through viem. Execution and settlement happen on Mantle. ## Who this is for If you want an autonomous agent that can operate a treasury, propose and execute on-chain actions, and surface opportunities, but whose spending boundary you can read, test, and enforce in code, Nebula is the path. Read [Quickstart](/docs/quickstart) next. ## How the docs are organized Four groups. Get started covers install and a first chat. Concepts walks the four-gate write pipeline and the tool model. Reference is the CLI surface and the config shape. Operate covers the operator console at `/console`. Source for everything in this section: [`README.md`](https://github.com/rstfulzz/nebula/blob/main/README.md).