Skip to content

codeweiz/chances-cli

Repository files navigation

chances-cli

A Bun-first, multi-provider terminal coding agent.
Pluggable adapters · enforced boundaries · interactive TUI · scriptable headless mode.

npm license changelog TypeScript Bun Rust

11 providers · 10 built-in tools · 7 slash commands · plugin API · 4-type memory · 0 boundary violations


Install

npm / bun / pnpm

npm  i -g @chances-ai/cli   # → `chances` binary on PATH
bun  add -g @chances-ai/cli
pnpm add -g @chances-ai/cli

Standalone binary (zero dependencies — built with bun build --compile)

Pick a build from the GitHub releases page: darwin-arm64 · darwin-x64 · linux-x64 · linux-arm64 · windows-x64.exe.

From source (contributors)

git clone https://github.com/codeweiz/chances-cli && cd chances-cli
bun install
bun run dev          # interactive Ink chat (needs a TTY)

Requires Bun ≥ 1.3.14 for the dev flow; the published binary needs nothing.

Quick start

# 1. Health check — verifies runtime, config, credentials.
chances doctor

# 2. Mock provider works with no API key — useful for trying the loop offline.
chances -p "summarize package.json" --json

# 3. Real provider via env var.
export ANTHROPIC_API_KEY=sk-...
chances                               # interactive Ink chat
chances -p "explain src/engine.ts"    # one-shot
chances -p "/help"                    # slash commands work in -p too

Inside the interactive chat:

/help                # list all slash commands
/model               # picker — switch models mid-session
/provider list       # show configured providers
/provider add kimi   # masked credential entry
/mcp list            # MCP servers + status + tools
/mcp restart fs      # tear down + reconnect one MCP server
/mcp test github     # one-shot connect + list + dispose (debugging)
/resume              # picker — switch to a saved session
/compact             # summarize and shrink the conversation
/clear               # empty the current turn list
/logout <provider>   # remove a stored credential

What you get

Providers

11 providers, dispatched data-driven by ProviderEntry.api — adding a new OpenAI-compatible vendor is one entry in KNOWN_MODELS.

Native (@ai-sdk/*) OpenAI-compatible (@ai-sdk/openai-compatible)
anthropic openai google xai groq openrouter deepseek doubao minimax glm kimi

Built-in tools

read · write · edit · bash · grep · glob · diff · web_fetch · task · memory_save · memory_delete · memory_list

Plus any tool exposed by a configured MCP server, registered dynamically as mcp__<server>__<tool>. Every tool — built-in, plugin, OR MCP-bridged — goes through the same PermissionGate. The default policy auto-allows reads/search/memory and prompts on write/shell/integration. MCP tools inherit those categories via their schema annotations (readOnlyHint → file-read, destructiveHint → file-write, etc.). Per-tool overrides live in <workspace>/.chances/config.json.

MCP servers (3.1)

Configure servers in <workspace>/.chances/config.json:

{
  "mcp": {
    "servers": {
      "filesystem": {
        "type": "stdio",
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
      },
      "weather": {
        "type": "http",
        "url": "https://example.com/mcp",
        "headers": { "Authorization": "Bearer ${WEATHER_TOKEN}" }
      }
    }
  }
}

Env substitution supports ${VAR} and ${VAR:-default}. Project entries shadow user entries with the same name. Manage at runtime with /mcp list | tools | resources | prompts | restart <name> | test <name> | remove <name> | add | login | logout. The @modelcontextprotocol/sdk package is an optional peer dep — when no servers are configured, it's never loaded (no cold-start cost).

Resources + prompts (v9.0.0). Beyond tools, the agent consumes a server's resources and prompts:

  • Prompts become slash commands /<server>:<prompt> [args] — invoking one fetches the server's prompt and submits it as a turn.
  • Resources are reachable two ways: the model calls mcp_list_resources / mcp_read_resource, or you reference one inline with @<server>:<uri> (autocompleted; read and injected into your message).

The client advertises roots (the workspace path; disable with "mcp": { "advertiseRoots": false }). MCP sampling is intentionally not advertised — letting a server drive your model is a cost + prompt-injection surface, and neither claude-code nor oh-my-pi ships it.

Memory

4-type frontmatter schema (user / feedback / project / reference) across two scopes (~/.chances/memory/ cross-project, <workspace>/.chances/memory/ project-local). The model calls memory_save / memory_delete / memory_list directly; the agent's system prompt is auto-augmented with the relevant indexes and bodies subject to a 25 KiB per-scope budget.

Plugin API

import { definePlugin } from "@chances-ai/plugin-api";

export default definePlugin({
  name: "my-plugin",
  onLoad(ctx) {
    ctx.registerTool({ /* same Tool interface as built-ins */ });
    ctx.registerSlashCommand({ name: "ping", run: () => "pong" });
    ctx.registerHook("afterToolCall", ({ name, ok }) => {
      ctx.logger.info(`tool ${name} ${ok ? "ok" : "failed"}`);
    });
  },
});

Hooks: beforePrompt / beforeToolCall / afterToolCall / afterResponse. Plugin load failures roll back atomically — a buggy plugin can't leave the host in a half-initialized state.

Headless modes

chances -p "<prompt>"            # text mode (default)
chances -p "<prompt>" --json     # one JSON envelope on stdout
chances -p "<prompt>" --ndjson   # one event per line — pipe through jq
chances --yes -p "..."           # auto-approve all permission prompts

Exit codes are stable: 0 success · 1 unknown · 2 usage · 3 permission · 4 provider · 5 tool · 130 cancelled. CI scripts can branch on them.

Configuration

Three layers, later wins: global file → project file → env.

Path Purpose
~/.config/chances/config.json Cross-project defaults
<workspace>/.chances/config.json Project overrides
~/.config/chances/auth.json Provider credentials (0600 on POSIX)
Env vars One-off / CI overrides

Common env vars:

CHANCES_PROVIDER=anthropic
CHANCES_MODEL=claude-opus-4-7
CHANCES_MAX_TURNS=20         # agent loop budget (1..200)
ANTHROPIC_API_KEY=sk-...     # one per provider — see `chances doctor` for the full list

Architecture

apps/cli                 composition root — arg parsing, modes, exit codes
  ├── commands/          chat, doctor, config, session, stats, discover, version
  ├── modes/             text / json / ndjson renderers
  └── slash/             8 first-party slash commands (use the same PluginContext as external plugins)

packages/
  ├── runtime            event bus, cancellation, logger, errors, model-selection
  ├── config             load/merge/discover, AuthStore, permission policy
  ├── ai                 ProviderAdapter port, registry, router, AI-SDK + OpenAI-compatible + mock adapters
  ├── session            transcript persistence, resume, compact
  ├── memory             frontmatter-typed store, three model-callable tools
  ├── tools              ToolRegistry, PermissionGate (+ session positive-decision cache), 7 built-in tools
  ├── plugin-api         definePlugin, PluginHost, hooks, slash dispatch
  ├── mcp                MCP client (stdio + streamable HTTP), tool bridge, /mcp host, secret redactor
  ├── core               AgentEngine — the loop (only depends on type imports of peer packages)
  ├── tui                Ink chat + modal slot + 3 pickers (model/session/api-key)
  ├── telemetry          usage/cost JSONL sink on the bus
  └── native             JS facade over Rust crates (JS fallback today; native search lands when bench needs it)

crates/                  6 Rust crate skeletons (chances-{native,fs,pty,diff,ast,tokenize})

Boundaries are CI-enforced (.dependency-cruiser.cjs): app → ui → domain → infra → native, one-way only. As of 3.1.1: 314 modules, 0 violations.

Status

Major Theme Status
1.x Foundation — engine, tools, permission gate, Ink TUI, sessions, multi-provider shipped 2026-05-25
2.x Extensible dev tool — 11 providers, Memory v1, Router v1, plugin API, glob/grep/diff, stats, discover shipped 2026-05-26
3.0 Interactive UX — slash commands, mid-session /model, runtime /provider add, modal pickers, autocomplete shipped 2026-05-26
3.0.1 Pre-3.1 patch pass — diagnostic adapter errors, configurable agent.maxTurns, terminal exhaustion error, api-key redaction, codex review shipped 2026-05-26
3.1 MCP client — @chances-ai/mcp, stdio + streamable HTTP, tool bridge, /mcp slash, session-cached permission gate, secret redactor, ANSI strip, collision detection, three rounds of codex review shipped 2026-05-26
3.1.1 Release pipeline hardening — workspace-derived publish list, publint in CI verify, two shim scripts removed shipped 2026-05-27
3.2.1 web_fetch (SSRF-defended URL fetcher, new network-read category) + task Subagent v1 (child engine, anti-recursion, shared gate); engine cancellation tightened + bus pair invariant restored shipped 2026-05-27
3.2.2 PTY-backed bash via crates/chances-pty (first napi-rs crate, portable-pty + 2-wave kill + 300 ms drain budget); claude-code style 30 KB inline + persist-to-disk; ANSI passthrough at runtime, stripped at bash layer; JS spawn fallback; three rounds of codex review shipped 2026-05-27
3.2.3 Native release pipeline — single-package model (all chances-pty.<platform>-<arch>.node shipped inside @chances-ai/native); ABI version sentinel auto-generated by build.rs from CARGO_PKG_VERSION (no hand-maintained literal); Windows file-lock staging to ~/.chances/natives/<version>/ (immutable per (version, filename), race-safe); CI build_natives matrix (5 native runners) with Swatinem/rust-cache + unconditional smoke; both release_github and release_npm gate on native matrix; macOS ad-hoc codesign + --strict verify; doctor reports loaded path + sentinel; two rounds of codex review (4 design + 3 impl MUST-FIX folded in) shipped 2026-05-27
3.3 / 3.4 / 3.5 / 3.6 / 3.7 3.3 agent catalogs (.chances/agents/*.md); 3.4 parallel + background subagents (run_in_background: true, bounded concurrency); 3.5 auto-compaction (threshold + idle + tool-output pruning); 3.6 OTel exporter (@chances-ai/telemetry-otel, OpenTelemetry GenAI semconv); 3.7 OAuth for MCP servers (Keychain / Secret Service / Credential Manager primary, 0o600 JSON fallback) planned, ordered
3.x later → 5.x Shipped in order: worktree isolation (v4.1) → LSP tool (v5.0) → interactive PTY (v6.0/6.0.1) → Stable RPC / ACP host (v7.0) → approval-mode selector (v8.0) → MCP resources + prompts (v9.0). Remaining: fork-from-parent subagent, ToolContext.callId, TUI xterm.js pane, MCP sampling (deferred). See docs/STATUS.md for the full per-item rationale + codex review verdicts. shipping

See docs/STATUS.md for the version-by-version breakdown, docs/ROADMAP.md for the long-form plan, and CHANGELOG.md for release-level changes.

Documentation

Development

bun run check        # tsc project-reference typecheck across 25 packages (via Turbo)
bun test             # unit + integration tests (514 tests at 3.1.1)
bun run boundaries   # dependency-cruiser: enforce one-way layering
bun run build:native # cargo build the Rust workspace
bun run benchmark    # record performance baseline (cold start + grep/glob p95)

Acknowledgments

The architecture draws from two excellent open-source projects (both MIT, both studied clean-room):

  • badlogic/pi-mono — minimal multi-provider core, session-layer error recovery, model-resolver patterns.
  • can1357/oh-my-pi — native/extensible surface, plugin authoring shape, slash command UX.

We compare against Anthropic's Claude Code for terminal-coding-agent feature parity but ship a clean-room implementation.

License

MIT

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages