Joker is an API-first Rust coding agent. It can run as an interactive terminal UI for daily development or as a headless command for scripts, CI jobs, and automation.
- Interactive TUI with streaming assistant output, slash commands, sessions, catalog-driven provider/model switching (with live model discovery), and approval prompts.
- Headless
execmode that runs one prompt and prints the final assistant response. - Project-local
joker.tomlconfiguration with CLI overrides. - Built-in providers for scripted local runs, DeepSeek, Anthropic, Google, Alibaba/DashScope, ZhipuAI, Moonshot/Kimi, Baidu/ERNIE, and custom OpenAI-compatible endpoints.
- Workspace-scoped tools for file reads, search, edits, patching, shell commands, memory, todos, URL fetches, and MCP-discovered tools.
- Agent profiles (
plan,build,yolo) with different permission postures.
From this repository:
cargo install --path crates/joker-tuiFor development, run the binary directly:
cargo run -p joker-tui --bin jokerCreate a project config:
joker initRun the interactive TUI:
jokerStart the TUI with an initial prompt:
joker --prompt "review this repository"Run one non-interactive prompt:
joker exec "summarize this repository" --provider scriptedPrint the config path that this invocation will use:
joker config pathscripted is the default provider. It requires no network and is useful for
smoke tests:
joker exec "hello" --provider scripted --scripted-response "Joker is ready."Use a hosted provider by exporting its API key:
export DEEPSEEK_API_KEY=sk-...
joker --provider deepseek --model deepseek-chatUse a custom OpenAI-compatible endpoint from the command line:
joker --provider openai-compatible \
--base-url http://localhost:8000/v1 \
--model qwen \
--api-key-env LOCAL_LLM_API_KEYThe same endpoint can be defined once in joker.toml (see
Configuration) so every invocation picks it up.
Non-interactive exec fails early if the selected provider needs an API key
that is not present in the environment or the credential store.
Joker reads joker.toml in the current directory by default:
provider = "deepseek"
model = "deepseek-chat"
demo_tool = false
[agent.build.tools.read_file]
permission = "auto-accept"
[agent.build.tools.write_file]
permission = "ask"Custom providers are defined in [providers.<name>], following opencode's
provider.<id> shape. The wire protocol is set by kind (or protocol):
"openai-compatible", "anthropic", or "google".
provider = "local"
model = "qwen"
[providers.local]
kind = "openai-compatible" # or "anthropic" / "google"
base_url = "http://localhost:8000/v1"
model = "qwen"
api_key_env = "LOCAL_LLM_API_KEY"
[providers.local.options]
timeout = 60
headers = { "X-Custom" = "trace-123" }
[providers.local.models.qwen]
max_tokens = 4096
temperature = true
toolcall = true
reasoning = falseoptions applies provider-wide request settings; each models.<id> entry
declares per-model capabilities (temperature, tool calls, reasoning, token
limits) that drive the request clients.
CLI flags override the file for a single invocation:
joker --config ./configs/joker.toml --provider scriptedSecrets are never stored in joker.toml. Headless runs read credentials from
environment variables such as DEEPSEEK_API_KEY, ANTHROPIC_API_KEY, or a
custom --api-key-env. In the TUI, entering an API key through the provider
prompt persists it to ~/.joker/auth.json; stored keys take precedence over
environment variables.
The default build agent can inspect files automatically and asks before
mutating files or running shell commands. The plan agent is read-only for
mutating tools. The yolo agent auto-accepts more operations and should only
be used in trusted workspaces.
Headless exec is conservative: if a tool requires approval, Joker denies that
tool request instead of blocking for user input.
Run the test suite:
cargo test -qRun lint checks:
cargo clippy -q --all-targetsFormat Rust code:
cargo fmtBuild the release binary (produced at target/release/joker):
cargo build --release -p joker-tui