cordy 0.2.0

A cross-platform TUI coding agent in Rust — workspace tabs, PTY terminals, direct-key panels, hot-swap any model/provider mid-conversation, MCP, skills, sub-agents and background jobs.
<div align="center">

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://gfx.redstone.md/strip?label=Cordy&note=a%20terminal%20coding%20agent%20in%20Rust&theme=dark">
  <img alt="Cordy — a terminal coding agent in Rust" src="https://gfx.redstone.md/strip?label=Cordy&note=a%20terminal%20coding%20agent%20in%20Rust&theme=light" width="840">
</picture>

**English** · [Русский](README.ru.md)

Hot-swap any model or provider mid-conversation. Edit files behind a permission gate.
MCP, skills, sub-agents, and background jobs — in one fast, keyboard-driven TUI.

[![CI](https://github.com/redstone-md/Cordy/actions/workflows/ci.yml/badge.svg)](https://github.com/redstone-md/Cordy/actions/workflows/ci.yml)
[![Release](https://img.shields.io/github/v/release/redstone-md/Cordy?display_name=tag&sort=semver)](https://github.com/redstone-md/Cordy/releases)
[![crates.io](https://img.shields.io/crates/v/cordy?logo=rust)](https://crates.io/crates/cordy)
[![License: MIT](https://img.shields.io/badge/license-MIT-6e9bf5)](LICENSE)
[![Rust](https://img.shields.io/badge/rust-2024-b7410e)](https://www.rust-lang.org)

</div>

Cordy is a cross-platform terminal agent that talks to every major API family — OpenAI Chat
Completions, OpenAI-compatible endpoints, Anthropic Messages, and the OpenAI Responses API —
through one canonical model, so switching provider or model never loses your conversation. It
edits files with an exact, diff-confirmed `edit`, runs a builtin toolset whose command output is
compressed by a native token optimizer, and speaks the Model Context Protocol.

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://gfx.redstone.md/strip?label=Highlights&note=what%20sets%20it%20apart&theme=dark">
  <img alt="Highlights" src="https://gfx.redstone.md/strip?label=Highlights&note=what%20sets%20it%20apart&theme=light" width="840">
</picture>

- **Hot-swap models & providers** mid-conversation — start on a local model, finish on a frontier
  one, context intact. `^P` → pick a model, or `/connect` to add a provider.
- **Every API family** — OpenAI Chat, OpenAI-compatible (Ollama / vLLM / OpenRouter / Groq / …),
  Anthropic Messages, OpenAI Responses. Wire formats never leak past the adapter.
- **Builtin tools**`read` `write` `edit` `apply_patch` `multiedit` `grep` `glob` `ls` `bash`
  `todo` `web_search` `web_fetch` `process` `rewind`, all behind a permission gate you can
  pre-approve with globs. `apply_patch` applies a multi-file, multi-hunk patch as one reviewed
  unit, matching context tolerantly so near-miss whitespace and smart quotes still land.
- **Background jobs** — run a dev server with `bash background:true`, then `process` to poll,
  wait on a regex, or kill the whole process tree.
- **MCP, skills, sub-agents** — connect MCP servers, load progressive-disclosure skills, and
  delegate work to isolated sub-agents via the `task` tool.
- **Free web search** — DuckDuckGo out of the box (no key), or Exa when `EXA_API_KEY` is set.
- **Workspace tabs** — up to five per project, each with its own session, model, mode, cost
  counters, undo checkpoints and history. Background tabs keep streaming; the strip badges what
  changed, and
  Cordy warns when two tabs write the same file.
- **Direct-key panels**`^D` mode · `^L` model · `^G` git · `^S` skills · `^K` context ·
  `^T` terminal · `^E` editor · `^B` tabs. One overlay, one look, keyboard all the way down.
- **Real terminals in the UI**`^T` opens a PTY panel beside the chat (shell, test watcher,
  or a full-screen editor via `^E`), resizable and focus-switchable without leaving Cordy.
- **Modes that actually bind**`build` `plan` `architect` `socratic` `challenge` `review`.
  Each injects its own contract into the system prompt, and the read-only ones are enforced by
  permission rules, not just asked for politely.
- **Steer a running turn**`^Alt+S` (or `/steer …`) drops a correction into the turn that is
  already in flight, so you redirect the agent instead of aborting and starting over.
- **Live cost & context HUD** — a header bar with git state, context meter and model chip; a
  context inspector that breaks the next request down by section; and a model-events log with
  per-call latency, tokens and cost.
- **42 themes, hot-reloaded** — plus custom themes as JSON in `~/.cordy/themes/`, re-read the
  moment you save them.

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://gfx.redstone.md/strip?label=Install&note=prebuilt%20binaries%20or%20from%20source&theme=dark">
  <img alt="Install" src="https://gfx.redstone.md/strip?label=Install&note=prebuilt%20binaries%20or%20from%20source&theme=light" width="840">
</picture>

**Linux / macOS**

```sh
curl -fsSL https://raw.githubusercontent.com/redstone-md/Cordy/main/install.sh | sh
```

**Windows** (PowerShell)

```powershell
irm https://raw.githubusercontent.com/redstone-md/Cordy/main/install.ps1 | iex
```

The scripts download the signed binary for your platform, verify its checksum, and drop `cordy`
on your `PATH`.

**With cargo** — `cargo install cordy`

**Prebuilt binaries** — or grab the archive for your platform from the
[latest release](https://github.com/redstone-md/Cordy/releases/latest), unpack, and run `cordy`.

**From source** (Rust 1.88+) — the default build is full-featured (MCP included):

```sh
git clone https://github.com/redstone-md/Cordy.git
cd Cordy
cargo build --release
# binary at target/release/cordy
```

Want a leaner binary without the MCP client? `cargo build --release --no-default-features`.

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://gfx.redstone.md/strip?label=Quick%20start&note=connect%20a%20provider%20and%20go&theme=dark">
  <img alt="Quick start" src="https://gfx.redstone.md/strip?label=Quick%20start&note=connect%20a%20provider%20and%20go&theme=light" width="840">
</picture>

Point Cordy at any OpenAI-compatible endpoint via environment variables, then run it:

```sh
export OPENAI_API_KEY=sk-...
export CORDY_BASE_URL=https://api.openai.com/v1   # or any compatible endpoint
export CORDY_MODEL=gpt-4o-mini
cordy
```

…or skip the env vars and press **`^P` → /connect** inside the app to add a provider through the
wizard. Providers you connect are saved to `~/.cordy/config.toml`, and the last one is restored on
launch. All user state — config, keys, sessions, cache — lives under `~/.cordy`.

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://gfx.redstone.md/strip?label=Keybinds&note=panels%20%C2%B7%20tabs%20%C2%B7%20terminals&theme=dark">
  <img alt="Keybinds" src="https://gfx.redstone.md/strip?label=Keybinds&note=panels%20%C2%B7%20tabs%20%C2%B7%20terminals&theme=light" width="840">
</picture>

**Panels**

| Key | Action |
| --- | --- |
| `^D` · `^L` | mode / persona · model picker |
| `^G` · `^S` | git menu (status, diff, log, commit, push, stash) · skills browser |
| `^K` · `^P` | context inspector · command palette |
| `^T` · `^E` | terminal panel · editor panel (`$EDITOR`) |

**Tabs**

| Key | Action |
| --- | --- |
| `^N` · `Alt+W` | new tab · close tab |
| `Alt+1``Alt+5` · `^B` | focus tab · tab list |

**Terminal panel** (while focused)

| Key | Action |
| --- | --- |
| `^Alt+T` · `^Alt+W` | back to the chat · close the panel |
| `^Alt+N` · `^Alt+↑`/`` | next panel · resize |

**Composer**

| Key | Action |
| --- | --- |
| `Enter` | send · `^J` / `Alt+Enter` newline |
| `Tab` / `Shift+Tab` | cycle agent/mode |
| `` / `` | move across lines · scroll the transcript · then prompt history |
| `^↑` / `^↓` | prompt history, always |
| `PgUp`/`PgDn` · `Home`/`End` | page the transcript · jump to top/bottom |
| `Esc` · `^Alt+S` | interrupt the turn · steer it instead |
| `^X` then … | leader: `l` sessions · `m` models · `t` theme · `s` status · `y` copy reply · `g` top · `z` redraw |
| `^R` · `^-`/`^.` | rename session · undo/redo input |

Slash commands include `/connect` `/providers` `/model` `/tabs` `/context` `/events` `/term`
`/git` `/steer` `/sessions` `/permissions` `/compact` `/goal` and more — type `/` to autocomplete.

> Two bindings differ from stock readline: `^E` opens the editor panel (line-end moved to `Alt+E`
> and `End`), and `^D` opens the mode picker (quit is `^C` on an empty line, `^X q`, or `/quit`).
>
**Clickable**

The bottom row is a menu bar, not a cheat sheet: every hint is a button, and so are the header's
model / branch / context / spend chips, the tab strip, and every picker row. Clicking a tool row
unfolds its full output. The mouse is captured for this, which costs plain drag-select —
`Shift`+drag still selects, and `^X M` (or the `⠿` indicator, `/mouse`, `mouse = false` in config)
hands the mouse back to the terminal entirely.

Pasting is your terminal's own paste; `Alt+V` pastes an *image* from the clipboard.

**Seeing the UI without running it**

```sh
cordy render list                 # scenario names
cordy render git 120x30           # draw one, in color
cordy render chat 110x30 --plain  # …or as plain text, for diffing
```

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://gfx.redstone.md/strip?label=Goals&note=long-running%20work%2C%20on%20a%20budget&theme=dark">
  <img alt="Goals" src="https://gfx.redstone.md/strip?label=Goals&note=long-running%20work%2C%20on%20a%20budget&theme=light" width="840">
</picture>

A goal is an objective the session keeps working on by itself. While it is active, each finished
turn feeds the next one, so a long task runs unattended until it is done, out of budget, or stuck.

```
/goal fix the flaky auth test --budget 200k --cost 2.50 --turns 20
/goal                 # status: objective, tokens, elapsed
/goal edit            # load the objective back into the composer
/goal pause           # stop the loop, keep the goal
/goal resume          # back to work
/goal clear           # drop it
```

Budgets are the safety rail: whichever of tokens, dollars or turns runs out first flips the goal to
*limited by budget*, and the model is told to wrap up rather than start new work. It stops on its
own too — the agent marks the goal complete only after auditing the objective against the current
worktree, or blocked after the same obstacle recurs three turns running. `Esc` or typing anything
interrupts the loop; a resumed session waits for you before spending again. Defaults live under
`[goal]` in the config, and the goal travels with the session (including forks).

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://gfx.redstone.md/strip?label=Configuration&note=hot-reloaded%20%C2%B7%20secrets%20stay%20in%20env&theme=dark">
  <img alt="Configuration" src="https://gfx.redstone.md/strip?label=Configuration&note=hot-reloaded%20%C2%B7%20secrets%20stay%20in%20env&theme=light" width="840">
</picture>

`~/.cordy/config.toml` (merged with a project-level `.cordy/config.toml`). It is **hot-reloaded**
— edits apply within a second, no restart. Secrets never live here; API keys go in the OS env or
`~/.cordy/keys.json` (written by `/connect`).

```toml
optimize = true
theme = "tokyonight"   # cordy (default) · 42 builtins, or your own JSON in ~/.cordy/themes/

# Fine-tune any role color on top of the theme
[colors]
accent  = "#7aa2f7"
surface = "#24283b"

# Autonomous goals: whichever cap is hit first ends the run
[goal]
enabled      = true
token_budget = 200000
cost_cap_usd = 5.0
max_turns    = 20

# Pre-approve commands so the agent stops asking
[permissions]
mode  = "ask"          # or "auto"
allow = ["bash:ls *", "bash:git *", "bash:cargo *"]
deny  = ["bash:rm -rf *"]

# A provider (secrets stay in env / keys.json, never here)
[[provider]]
name = "openai"
kind = "openai-chat"
base_url = "https://api.openai.com/v1"

# An MCP server (in the default build)
[[mcp]]
name = "browsermcp"
transport = "stdio"
command = "npx @browsermcp/mcp@latest"
enabled = true
```

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://gfx.redstone.md/strip?label=Project%20layout&note=one%20crate%2C%20clean%20module%20boundaries&theme=dark">
  <img alt="Project layout" src="https://gfx.redstone.md/strip?label=Project%20layout&note=one%20crate%2C%20clean%20module%20boundaries&theme=light" width="840">
</picture>

```
src/
  core/       canonical model (ContentBlock/Message/WireEvent), agent loop, prompt, context,
              sessions, permissions, goals (autonomous loop), auth
  provider/   Provider trait + one adapter per API family (+ retry decorator)
  tools/      Tool trait, builtins, native output optimizer, sub-agents, background jobs
  skills/     progressive-disclosure skill loader
  agents/     sub-agent registry
  mcp/        MCP client (on by default; opt out with --no-default-features)
  config/     TOML load/merge, model & provider profiles
  tui/        ratatui MVU app — model/update/view, chrome (header, tabs, status),
              overlay pickers, PTY terminal panels, themes, markdown
```

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://gfx.redstone.md/strip?label=Contributing&note=fmt%20%C2%B7%20clippy%20%C2%B7%20test&theme=dark">
  <img alt="Contributing" src="https://gfx.redstone.md/strip?label=Contributing&note=fmt%20%C2%B7%20clippy%20%C2%B7%20test&theme=light" width="840">
</picture>

Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). Before opening a PR:

```sh
cargo fmt
cargo clippy --all-targets
cargo test
```

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://gfx.redstone.md/strip?label=License&note=MIT&theme=dark">
  <img alt="License" src="https://gfx.redstone.md/strip?label=License&note=MIT&theme=light" width="840">
</picture>

Released under the [MIT License](LICENSE).

<div align="center">
<sub>Part of <a href="https://github.com/redstone-md">redstone.md</a></sub>
</div>