A modern, multi-provider terminal AI coding agent. Built in TypeScript, designed so the agent loop, tools and CLI never know which model provider is behind them.
claude · chatgpt · gemini · antigravity · openai · ollama
LuckyCLI is an interactive REPL that drives a tool-using agent from your terminal. It reads and edits files, runs shell commands, searches your codebase and fetches docs — asking for approval before anything side-effecting — and works across six model providers behind a single canonical message format. Switch provider or model mid-session without losing your conversation.
Status: working, actively used. The architecture is complete and type-safe, the build and unit suite are green, the Ink REPL is interactive, and several providers are verified against their live APIs (see Provider support).
- Six providers, one core. Claude, ChatGPT (OpenAI OAuth), Gemini, Antigravity, OpenAI (API key) and Ollama — all behind the same adapter interface.
- Real auth, not just keys. Browser OAuth for Claude, ChatGPT, Gemini and Antigravity; API keys for Claude/OpenAI/Gemini; Vertex AI for Gemini; local daemon for Ollama.
- A genuine agent loop that runs tools, streams output, and keeps going until
the task is done (no fixed step cap) or you press
Esc. - A project knowledge graph. Opt-in on first open, LuckyCLI maps your code's
files, symbols, imports and calls into
.lucky/graphso the agent navigates by querying instead of re-reading files, renders to interactive HTML, and keeps itself current automatically as the agent edits. Early real-LLM results in How much does it help?. - Skills on a second graph. Reusable instructions (cutting a release, your
commit conventions, …) live as
skill.mdfiles indexed in their own keyword graph. A deterministic matcher activates the relevant one for a message — with zero token cost when nothing matches — so installed skills never bloat the system prompt or move the prompt-cache prefix. See Skills. - Safety built in. Side-effecting tools prompt for approval, the shell tool
refuses destructive commands, file tools are sandboxed to the working
directory, and
http_fetchblocks private/SSRF targets. - Remembered approvals. Approve "always" once and LuckyCLI stops re-asking — per command for the shell, per tool for file writes — for the rest of the session.
- Automatic context compaction. Older turns are summarized as you approach the model's usable context, so long sessions don't fall over.
- Persistent sessions. Every turn is saved; resume the latest or pick from a list.
- Embeddable. The engine ships as a library (
@luckycli/core) with a small, documented API — the CLI is just one front-end.
The welcome screen — provider, model and working directory at a glance.
Type / to open the slash-command directory; arrow to navigate, Enter to complete.
/status — auth method, account, tier, context usage and per-model quota.
macOS / Linux (Intel or ARM):
curl -fsSL https://raw.githubusercontent.com/Fenix46/LuckyCLI/main/install.sh | bashWindows (PowerShell):
irm https://raw.githubusercontent.com/Fenix46/LuckyCLI/main/install.ps1 | iexThis downloads the prebuilt lucky binary for your platform — no Node.js
required — and adds it to your PATH. macOS/Linux install into ~/.local/bin;
Windows installs into %LOCALAPPDATA%\Programs\LuckyCLI. Then run:
luckyOptions: set LUCKY_INSTALL_DIR to install elsewhere, or LUCKY_VERSION to pin
a version (e.g. v0.2.2). On Windows set them first, e.g.
$env:LUCKY_VERSION = "v0.2.2". Both work the same way: the Windows installer
verifies the binary's SHA-256 checksum and updates your user PATH.
LuckyCLI keeps itself current. By default (auto) it checks for a new release on
startup, downloads and SHA-256-verifies it in the background, and applies it on
the next launch — never mid-session, so a running agent turn is never disturbed.
On Windows the previous binary is parked next to the new one and cleaned up on the
following launch.
Drive it manually any time:
lucky update # check; show current/latest + whether self-update works
lucky update --apply # download, verify, and install the latest release now
LUCKY_VERSION=v0.3.0 lucky update --apply # install a specific release
lucky update --auto off # off | notify | auto (default: auto)Inside the REPL: /update (status), /update apply (install + restart), and
/update auto <mode>. Set --auto notify to be told about updates without
auto-downloading, or --auto off to disable checks entirely;
LUCKY_DISABLE_UPDATE_CHECK=1 also turns off the startup check for one run.
Self-update only works when running the installed binary; from a dev checkout
(npm run dev) or a read-only install dir, lucky update prints the manual
curl … install.sh / irm … install.ps1 command instead.
Requires Node.js ≥ 20.
git clone https://github.com/Fenix46/LuckyCLI.git && cd LuckyCLI
npm install && npm run build
npm link --workspace @luckycli/cli # exposes `lucky` globallyOr run it straight from the repo without linking:
npm run dev # runs the REPL with tsxOn first run, LuckyCLI walks you through an interactive setup — pick a theme, a
provider, an auth method (including browser OAuth), and a model — then remembers
your choice in ~/.luckycli/config.json. No .env required.
lucky # interactive: pick provider + model
lucky -p claude -m claude-sonnet-4-6 # Claude
lucky -p openai-oauth -m gpt-5.5 # ChatGPT (browser login)
lucky -p gemini -m gemini-2.5-pro # Gemini
lucky -p ollama -m llama3.1 # local model via Ollama| Flag | Description |
|---|---|
-p, --provider |
claude · openai · openai-oauth · gemini · antigravity · ollama |
-m, --model |
Model id (provider-specific; see Models) |
-c, --continue |
Resume the most recent session |
--resume [id] |
Resume a session; with no id, pick one interactively |
--sessions |
List saved sessions and exit |
--setup |
Force the provider/auth switcher |
-h, --help |
Show help |
Each provider exposes one or more authentication methods. The methods below marked ✅ Verified have been exercised end-to-end against the live service; the others are implemented and unit-tested with mocked transports.
| Provider | Display name | Auth methods | Status |
|---|---|---|---|
openai-oauth |
ChatGPT | Browser OAuth (ChatGPT Plus/Pro) | ✅ Verified |
claude |
Anthropic Claude | Browser OAuth (Pro/Max/Team/Enterprise) | ✅ Verified |
claude |
Anthropic Claude | API key (ANTHROPIC_API_KEY) |
Implemented |
gemini |
Google Gemini | Browser OAuth (personal Google account) | ✅ Verified |
gemini |
Google Gemini | API key (Google AI Studio) | ✅ Verified |
gemini |
Google Gemini | Vertex AI (GCP project) | Implemented |
antigravity |
Google Antigravity | Browser OAuth | ✅ Verified |
openai |
OpenAI | API key (OPENAI_API_KEY, custom OPENAI_BASE_URL) |
Implemented |
ollama |
Ollama (local) | Local daemon base URL | Implemented |
OAuth logins open a browser window, complete the login on the provider's site, and capture the callback locally. Tokens are stored in
~/.luckycli/config.json(written0600) and refreshed automatically when they expire.
⚠️ Claude OAuth disclaimer. The Claude browser login works the same way as the official Claude Code login — it authenticates an Anthropic subscription account (Claude Pro / Max), not an API key. Using a subscription account this way may be against Anthropic's Terms of Service and could result in your account being rate-limited, suspended or banned. This project is an independent, unofficial client and is not affiliated with or endorsed by Anthropic. You use the Claude OAuth method entirely at your own risk — the author accepts no responsibility for any action Anthropic takes against your account. If in doubt, use anANTHROPIC_API_KEYinstead.
Defaults in bold. Use /model in the REPL or -m on the CLI to switch.
- ChatGPT (
openai-oauth): fetched live from the Codex backend once you sign in —/modellists exactly what your account can use (no hardcoded list). Picking a model also lets you choose a reasoning effort (low·medium·high·xhigh, defaultmedium), Codex-style. The choice persists;/model --refreshre-fetches the catalog. - Claude (
claude): claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5 - Gemini (
gemini): gemini-3.1-pro-preview, gemini-3.1-flash-lite, gemini-3-pro-preview, gemini-3-flash-preview, gemini-2.5-pro, gemini-2.5-flash, gemma-4-31b-it, gemma-4-26b-a4b-it - Antigravity (
antigravity): gemini-3.5-flash-low, gemini-3-flash-agent, gemini-3.1-pro-low, gemini-pro-agent, gemini-2.5-pro/flash, claude-sonnet-4-6, claude-opus-4-6-thinking, gpt-oss-120b-medium, … - OpenAI (
openai): gpt-4o, gpt-4o-mini, gpt-4.1, o4-mini - Ollama (
ollama): llama3.1, qwen2.5, mistral, gemma2 (any model you have pulled locally)
Type a message and press Enter. The agent streams its reasoning and tool calls inline, asks for approval on side-effecting tools, and saves the session after each turn.
| Key | Action |
|---|---|
Enter |
Send the message |
Option/Alt + Enter (macOS) · Ctrl + Enter (Win/Linux) |
Insert a newline (multiline input) |
Esc |
Interrupt the running turn |
Ctrl + C |
Cancel a running turn, or quit when idle |
↑ / ↓ |
Navigate menus and pickers |
Tab |
Complete the highlighted slash command |
| Command | Description |
|---|---|
/model |
Switch model for the active provider |
/provider |
Switch provider and authenticate |
/status |
Show provider auth, account, quota and context status |
/compact |
Summarize older chat history now |
/resume |
Pick a saved session to resume |
/theme |
Choose terminal UI colors |
/graph |
Build or refresh the project knowledge graph |
/mcp |
Open the MCP control panel: browse the registry, install, enable/disable servers |
/skill |
Open the skills panel: search a catalog, install, enable/disable, remove (alias: /skills) |
/update |
Check for updates; /update apply installs, /update auto <mode> sets the policy |
/exit |
Quit (alias: /quit) |
The agent is equipped with a registry of Zod-typed tools (JSON Schema is generated automatically for each provider). Read-only tools run without asking; side-effecting ones prompt for approval.
| Tool | Permission | What it does |
|---|---|---|
read_file |
allow | Read a text file (relative to the working directory) |
list_dir |
allow | List files and directories at a path |
glob |
allow | Find files by name with a glob (e.g. src/**/*.tsx) |
grep |
allow | Search file contents with a regular expression |
http_fetch |
allow | Fetch the text content of a public URL |
task_* |
allow | Create/list/get/update tasks — a structured todo list for multi-step work |
present_plan |
allow | Show a step-by-step plan for the work before doing it |
spawn_agent |
allow | Delegate a sub-task to a configured sub-agent |
project_memory |
allow | Read/write durable per-project notes the agent recalls later |
graph_query |
allow | Query the knowledge graph: find a symbol, its callers/callees, neighbors, or a file's symbols |
graph_overview |
allow | Summarize the graph: counts, most-connected symbols, most-imported modules |
skill_search |
allow | Search installed skills by name/description/keyword (metadata only, never bodies) |
skill_load |
allow | Load an installed skill's full instructions by name |
ask_user |
allow | Ask you a clarifying question and wait for the answer |
write_file |
ask | Write UTF-8 text to a file |
edit_file |
ask | Replace an exact snippet in a file (fuzzy snippet matching) |
apply_patch |
ask | Apply a unified-diff patch to text files |
exec |
ask | Run a shell command and return its combined output |
powershell |
ask | Run a PowerShell command (Windows) and return its output |
- Approval prompts. Tools resolved to
askpause forAllow once/Allow always/Reject. Choosing always is remembered for the session — per exact command forexec, per tool for file writes — so you aren't re-prompted. - Filesystem sandbox. File tools reject absolute paths and anything that escapes the working directory.
- Destructive-command guard.
execclassifies commands and refuses clearly destructive ones (rm -rf,sudo,mkfs,dd of=/dev/…,git reset --hard, force pushes, …) unless explicitly allowed. - SSRF guard.
http_fetchallows onlyhttp/httpsand blockslocalhost, cloud metadata endpoints, and private/loopback IP ranges (after DNS resolution).
By default read-only tools run freely, while write_file, edit_file,
apply_patch and exec ask for approval — and choosing always is remembered
for the session.
LuckyCLI is an MCP client: it connects to Model Context Protocol servers and exposes their tools to the agent alongside the built-in ones. Two transports are supported — local servers launched as a child process over stdio, and remote servers over Streamable HTTP (with an SSE fallback). Their tools register into the same approval flow as everything else.
Servers are connected in the background at startup, so a slow or unreachable one never blocks your session — its tools simply appear once it's up.
MCP servers live under an mcp key in ~/.luckycli/config.json, keyed by a name
you choose:
{
"mcp": {
"docs": {
"type": "local",
"command": ["npx", "-y", "@example/docs-mcp"],
"environment": { "DOCS_TOKEN": "…" }
},
"analytics": {
"type": "remote",
"url": "https://mcp.example.com/mcp",
"headers": { "Authorization": "Bearer …" }
}
}
}Common fields: enabled (set false to keep a server configured but off) and
timeout (connection timeout in ms). Local servers take command (argv array)
and optional environment; remote servers take url and optional headers.
You don't have to edit the file by hand — the in-app /mcp panel searches the
official MCP registry and installs servers for you.
lucky mcp list # show configured servers
lucky mcp status # connect to each and report status + tool count
lucky mcp login <name> # authorize a remote server via OAuth (opens a browser)
lucky mcp logout <name> # forget a remote server's stored tokens
Remote servers that require OAuth are supported via lucky mcp login <name>,
which runs the full authorization-code + PKCE flow through a loopback redirect
and stores the tokens in ~/.luckycli/mcp-auth.json (written 0600). During a
session those tokens are reused and refreshed automatically; a server that needs
a fresh login fails with a clear message rather than interrupting you with a
browser pop-up.
- Prompts and resources are available as internal APIs but are not yet surfaced in the REPL.
- Live
tools/list_changedupdates aren't watched yet — a server's tools are captured when it connects.
LuckyCLI can build a knowledge graph of your project — a precomputed map of
files, symbols, imports and calls — so the agent answers "where is X / who calls
Y / what is this codebase" by querying an index instead of re-reading source.
That's faster and far cheaper in tokens. The graph is native (no external
service): tree-sitter parses each file, and everything is stored as JSON in
.lucky/graph/.
It works in three phases:
- Create. The first time you open a folder, LuckyCLI asks to trust it and
offers to build the graph (AST-only, no API cost). You're asked only once per
folder. For projects started earlier, run
/graphin the REPL orlucky graph buildfrom the shell. - Use. With a graph present, the agent reaches for
graph_overview(to orient) andgraph_query(to find definitions, callers, callees, neighbors, or a file's symbols) before grepping or reading widely. - Maintain. After the agent edits files, the affected files are re-extracted
into the graph automatically — no rebuild needed. This now covers external
(MCP) tools too: when an MCP tool changes a file the graph already tracks, that
edit is picked up the same way. Brand-new files an MCP tool creates aren't
detected yet — they land on the next built-in edit or a rebuild.
lucky graph rebuild(or/graph rebuild) forces a full rebuild.
lucky graph view [path] renders the graph as a single self-contained,
interactive HTML page (.lucky/graph/view.html) — a force-directed map you can
zoom, pan and click, with the project's own code coloured by kind and external
dependencies dimmed and dashed. A side panel shows the overview counts, the most
connected symbols ("god nodes") and the most-used libraries. This is for humans:
the model never reads it (HTML is the least token-dense format), so it's
generated on demand for exploring or presenting a codebase.
* Alpha, early numbers. The graph is an early-stage feature; the figures below come from a single real session per mode, so treat them as directional, not as a controlled benchmark. Full write-up and transcripts in
docs/graph-benchmark.md.
We ran the same agent (GPT-5.4) on the broad prompt "Give me an overview of the project", once with the graph enabled and once without — a whole-project overview, which is the graph's least favourable case (the agent reads the README and entry files either way). What that one run showed:
- Efficiency: a modest win for the graph (~1.5×) — smaller working context (~21k vs ~32k) and fewer tool calls. On a sprawling overview the agent moves broadly regardless; the graph trims some exploration, not all of it.
- Quality: the two write-ups are essentially on par. The no-graph answer has
marginally more precise
file:linecitations (it read those files directly); the graph answer is just as accurate and adds something the no-graph run couldn't — a centrality view of the codebase: the most-connected "god nodes" (Agent,McpManager, the Gemini client) and which files drive graph density.
We'd expect a clearer efficiency gap on targeted navigation (find a definition, a
caller, a file's symbols), since there the graph returns an exact location instead
of the agent reading files to find it — but that isn't measured with a real LLM yet.
Try it yourself: build the graph with /graph, then run the same prompt against a
project with and without .lucky/graph.
Languages: TypeScript, TSX, JavaScript, Python, Go, Rust, Java, Ruby, C#, PHP, C,
C++, Kotlin, Swift and Dart (Flutter). Data/markup formats are mapped
structurally too — JSON and TOML (keys and sections) and HTML (resource imports
and id anchors). More are added behind the same extractor interface over time.
The graph engine is adapted from the
open-source graphify project, rewritten
natively in TypeScript in LuckyCLI's own style.
A skill is a reusable chunk of operative instructions — how you cut a
release, your commit conventions, how to review a diff — written as a plain
skill.md with a little frontmatter:
---
name: release-flow
description: Cut a versioned release with a changelog and a tag
keywords: [release, version bump, changelog, tag]
related: [conventional-commits]
---
1. Decide the next version from the changes since the last tag (semver)…Skills live globally under ~/.luckycli/skills/<name>/skill.md. Unlike the
flat "paste every skill's name + description into the system prompt" approach,
LuckyCLI indexes them in a second knowledge graph (skill ↔ keyword) and
activates them at runtime:
- Automatic. Before each message is sent, a deterministic matcher checks it against the keyword index and appends the matched skill's instructions to that turn (top 2 per turn, de-duplicated across the session). It costs zero tokens when nothing matches.
- On demand. When the model knows it needs help but no keyword fired, the
skill_search/skill_loadtools let it find and pull in a skill itself. - Cache-friendly. The system prompt only ever carries a short, fixed protocol blurb — identical whether you have 0 or 500 skills installed — so installing or removing a skill never moves the prompt-cache prefix.
/skill opens an interactive panel with two tabs:
- Installed — every skill with its description and keywords;
entertoggles a skill on/off (disabled skills stay on disk but drop out of the trigger index),dtheny/nremoves it from disk. - Search — live search of a remote skill catalog;
enterinstalls the selected skill into~/.luckycli/skills.
Non-interactively:
/skill list # installed skills + state
/skill search <query> # search the catalog
/skill add <name> # install from the catalog
/skill add ./path/to/skill # install from a local file or directory
/skill enable <name>
/skill disable <name>
/skill remove <name>The catalog base URL defaults to LuckyCLI's own and can be overridden with
LUCKY_SKILL_CATALOG_URL. The first time you open /skill, a small starter
pack (conventional-commits, release-flow, code-review) is seeded so you
have something to try — it never overwrites a skill you've edited.
Conversations are saved to ~/.luckycli/sessions/<id>.json after every turn.
lucky --continue # resume the most recent session
lucky --resume # pick a session to resume interactively
lucky --resume <id> # resume a specific session
lucky --sessions # list saved sessions and exitA resumed session restores the transcript and the model's context, and keeps its own provider/model unless you override them with flags.
When the conversation approaches the model's usable context (default: 75% of the
budget, reserving room for output), the agent automatically summarizes the older
turns into a compact synopsis and continues — keeping recent turns verbatim. You
can also trigger it manually with /compact. Compaction is on by default and
tunable via AgentConfig.compaction when embedding the library.
After the first run, LuckyCLI stores everything in a single folder in your home
directory: ~/.luckycli/. It holds config.json (your provider, model,
credentials, tool permissions and MCP servers — written 0600) and a sessions/
folder with your saved conversations. If you use MCP it may also hold
mcp-auth.json (OAuth tokens, written 0600) and mcp-catalog-cache.json
(cached registry metadata).
The exact location depends on your OS and account username (<you> below):
| OS | Path |
|---|---|
| macOS | /Users/<you>/.luckycli/ |
| Linux | /home/<you>/.luckycli/ |
| Windows | C:\Users\<you>\.luckycli\ |
You normally never need to touch it — the interactive setup writes it for you, and
/provider, /model and /theme update it from inside the REPL. To start fresh,
delete the folder (or just config.json) and run lucky again.
Everything speaks one canonical message format
(packages/core/src/providers/types.ts). Each provider is just an adapter that
translates that format to and from its own wire protocol. Nothing outside
packages/core/src/providers/impl/ imports a provider SDK.
┌─────────────┐ AgentEvent ┌──────────────┐
│ CLI / REPL │ ◀──────────────────│ Agent │ the loop
└─────────────┘ │ (agent/) │
canonical request / └──────┬───────┘
stream events │ ToolRegistry
┌──────▼───────┐ ┌──────────────┐
│ Provider │ │ Tools │
│ (providers/)│ │ read_file │
│ claude │ │ write_file │
│ openai │ │ edit_file │
│ openai-oauth│ │ apply_patch │
│ gemini │ │ glob / grep │
│ antigravity │ │ exec │
│ ollama │ │ http_fetch │
└──────────────┘ └──────────────┘
| Layer | Path | Responsibility |
|---|---|---|
| Core types | packages/core/src/providers |
Provider-agnostic messages, content blocks, stream events |
| Providers | packages/core/src/providers/impl |
One adapter per provider; canonical ⇄ SDK translation |
| Tools | packages/core/src/tools |
Zod-typed tools + registry (JSON Schema generation) + permissions |
| Agent | packages/core/src/agent |
The provider ⇄ tool loop; owns conversation history & compaction |
| Prompts | packages/core/src/prompts |
Composable system prompt (identity/agency/tool-use/environment) |
| Config | packages/core/src/config |
Resolves provider/model/credentials from flags, env, defaults; on-disk store |
| Sessions | packages/core/src/session |
Flat-file persistence + resume |
| CLI | packages/cli/src |
Interactive Ink REPL + terminal rendering |
- Add a provider = one adapter file + one factory line in
providers/index.ts. - Add a tool = one file with a Zod schema +
register(). - The agent loop is pure orchestration; it has no provider-specific code.
- Streaming is normalized to a tiny event vocabulary, so the CLI is trivial and a future web/TUI front-end can consume the same events.
@luckycli/core exports the agent, tools, providers, config and session APIs so
you can embed LuckyCLI in your own tool.
import { Agent, defaultToolRegistry, getProvider, resolveConfig } from "@luckycli/core";
const config = resolveConfig({ provider: "claude", model: "claude-sonnet-4-6" });
const provider = getProvider(config.provider!, config.credentials!);
const agent = new Agent({
provider,
model: config.model!,
tools: defaultToolRegistry(),
system: config.system,
permissions: config.permissions,
});
for await (const event of agent.send("List the TypeScript files in src/")) {
if (event.type === "text") process.stdout.write(event.delta);
}npm install
npm run build # tsc --build across the workspace
npm run dev # run the REPL with tsx (no build step)
npm run typecheck # type-check the whole workspace
npm test # vitest — unit suite for providers, agent and toolsThe repo is an npm-workspaces monorepo: @luckycli/core (engine) and
@luckycli/cli (the lucky binary). Release binaries are built with Bun via
scripts/build.ts.
Contributions are welcome — bug fixes, new tools, provider adapters, docs.
- Fork & branch. Create a feature branch off
main. - Keep the boundaries. Provider SDKs are only imported inside
packages/core/src/providers/impl/; everything else speaks the canonical format. Tools are self-contained files registered inpackages/core/src/tools/builtin/index.ts. - Stay green. Run
npm run typecheck && npm testbefore opening a PR. Add or update unit tests for the behavior you change (transports are mocked — no live API calls in the suite). - Match the style. Follow the surrounding code: small modules, explanatory comments where intent isn't obvious, no provider-specific code in the agent loop.
- Write a clear PR. Describe what changed and why; note anything you tested manually (e.g. against a live provider).
Good first contributions:
- A new tool — add a Zod-typed file under
tools/builtin/, register it, give it a sensible default permission. - A new provider adapter — implement
IProvider, add a catalog entry inproviders/catalog.ts, and a factory inproviders/index.ts. - Provider model lists — keep
providers/catalog.tscurrent as vendors ship models.
If you're planning something larger, open an issue first so we can align on the approach.
- Tool approval prompts for side-effecting tools (
exec,write_file,apply_patch,http_fetch) - Remembered "always" approvals (per-command for shell, per-tool for writes)
- Automatic context compaction (summarize older turns near the budget)
- Interactive model/provider switching from the REPL
- Browser OAuth for Claude, ChatGPT, Gemini and Antigravity
- Surgical file edits (
edit_file) with fuzzy snippet matching +apply_patch - Code search tools (
glob,grep) - Conversation persistence / session resume
- Filesystem sandbox, destructive-command guard, and SSRF protection
- Native project knowledge graph (build, query tools, autonomous updates)
- More graph languages (Go, Rust, Java, Ruby, C#, PHP, C, C++, Kotlin, Swift, Dart)
- Structural graph for data/markup (JSON, TOML, HTML)
- Interactive HTML graph visualization (
lucky graph view) - MCP client: local + remote (Streamable HTTP) servers, OAuth, in-app registry panel
- Proper graph benchmark suite (multiple prompts, repeated real-LLM runs, exact tokens)
- More non-code graph nodes (Markdown/text documents, shell scripts, YAML)
- Recorded fixtures / end-to-end tests against the live APIs
- Streaming markdown rendering in the CLI
- Retry/backoff + structured error taxonomy across providers
Apache-2.0.



