Oneshot mode
Run one turn in-process. Loads ~/.yuke/providers.json, auth.json,
and the optional ~/.yuke/init.lua on startup. Resume a session with
--resume.
Oneshot mode, daemon mode over WebSocket, configured in Lua and JSON. Talk to any OpenAI-compatible endpoint.
$ cargo install yuke
$ yuke -p "summarize src/"
[ streams one assistant turn ]
One Rust binary. Sessions persist to ~/.yuke/workspaces/ for resume.
Run one assistant turn in-process, no server. The CLI loads ~/.yuke/providers.json
for the catalog and ~/.yuke/init.lua for tools and hooks. Sessions persist under
~/.yuke/workspaces/ so --resume picks them back up.
--resume <id>--output-format json returns a result with session_id$ yuke -p "refactor the parser to use the new Error type"
read src/parse.rs
read src/error.rs
Reading the current implementation and the new Error type.
The change touches 47 lines across 3 functions.
✓ Done. 4 rounds, 12.4k tokens.
One binary, two modes. The CLI is the client; yuke daemon runs an optional
long-lived server that any WebSocket client can talk to.
┌──────────┐ ws://127.0.0.1:7878/ws ┌──────────────┐
│ yuke CLI │ ◄──────────────────────────► │ yuke daemon │
└──────────┘ └──────┬───────┘
│
┌────────────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ TUI │ │ editor │ │ your own │
│ client │ │ plugin │ │ client │
└──────────┘ └──────────┘ └──────────┘
Start the daemon once, connect any client. Sessions persist under
~/.yuke/workspaces/ and stream events to every connected client in
real time.
Full schema at /asyncapi.json · human-readable guide →
# Terminal 1
$ yuke daemon
[daemon] listening on ws://127.0.0.1:7878/ws
# Terminal 2: any WebSocket client
$ yuke -p "explain this codebase"
# Or wire-protocol level:
← { "Hello": { "models": [...] } }
→ { "CreateSession": { "path": "...", "config": {} } }
← { "Event": { "event": { "Session": { "seq": 1,
"event": { "Agent": { "TextDelta": { "id": "...", "delta": "..." } } } } } }
Run one turn in-process. Loads ~/.yuke/providers.json, auth.json,
and the optional ~/.yuke/init.lua on startup. Resume a session with
--resume.
Long-lived session on ws://127.0.0.1:7878/ws. Any client that can hold a
WebSocket open can connect.
Model catalog is plain JSON in providers.json. Edit with any tool; the
daemon reloads it on the next session.
Session policy, tools, and hooks are Lua in init.lua. Async runtime,
sandboxed standard library, full IO primitives.
Tool handlers run on an async runtime. File IO, HTTP, subprocesses: all non-blocking, all available from Lua.
before_tool, after_tool, turn_start, done:
gate, rewrite, or audit the agent loop.
The daemon speaks a documented JSON-over-WebSocket protocol (asyncapi.json). Build your own client in any language.
An interactive terminal client that ships with yuke. Its UI is fully
Lua-scriptable: rebind keys, swap layouts, register
custom commands, paint your own widgets — all from
~/.yuke/tui/init.lua.
cargo install yuke drops one binary on your PATH. No
Electron, no background processes when not running.
No telemetry, no accounts, no hosted service. Credentials live in ~/.yuke/auth.json
(mode 0600); the keys themselves stay in your shell.
The model catalog is JSON, edited with any tool and reloaded by the daemon on demand.
Credentials live in their own JSON file (mode 0600), separate from the
catalog. Tools and hooks are Lua, optional, and run once per session.
// The model catalog. Edit with any tool;
// reloaded on the next session.
{
"providers": [
{
"name": "openai",
"base_url": "https://api.openai.com/v1",
"models": [
{ "name": "gpt-4o" },
{ "name": "o3", "protocol": "codex" }
]
}
]
} -- Session policy, tools, hooks.
-- This file is optional.
yuke.tool {
name = "read",
description = "Read a file with line numbers.",
params = { path = "string" },
handler = function(args)
return yuke.fs.read(args.path)
end,
}
yuke.on("before_tool", function(call)
if call.name == "bash"
and call.arguments.command:find("rm %-rf") then
return { deny = "refusing" }
end
end) One binary, opt-in daemon, no background processes when idle. The runtime is small enough to read in a weekend and small enough to keep in your head.
Tools and hooks are Lua, in ~/.yuke/init.lua. The TUI's UI is Lua too,
in ~/.yuke/tui/init.lua. The model catalog is plain JSON. The wire
protocol is a documented asyncapi.json.
MIT licensed. No telemetry, no accounts, no hosted service. Credentials live in
~/.yuke/auth.json (mode 0600); the keys themselves stay in your shell.
The bull has states. Use them as loading hints, status indicators, or just decoration in your own docs. PNGs are free to take.
Five of nine available. The full set lives in /bull/.
Replace a hosted coding agent with a local install. No telemetry, no vendor lock-in, no Electron app.
Connect your editor to a daemon over WebSocket. Drive sessions from keybindings, stream output in real time.
yuke-tui is the bundled reference client; build your own in any stack (Elm, Ratatui, Bubble Tea, GPUI). The wire protocol is documented and stable.
Install yuke, drop a providers.json next to init.lua, set the
API key in your shell. One prompt in.
$ cargo install yuke
$ mkdir -p ~/.yuke && cat > ~/.yuke/providers.json <<'EOF'
{
"providers": [
{
"name": "openai",
"models": [ { "name": "gpt-4o" } ]
}
]
}
EOF
$ cat > ~/.yuke/auth.json <<'EOF'
{ "providers": { "openai": { "type": "api_key_env", "env": "OPENAI_API_KEY" } } }
EOF
$ export OPENAI_API_KEY=*** yuke -p "summarize src/"