Rush is a coding agent you run from the command line — but built
to be driven by other AI agents, not by a human typing into a
terminal. Point an orchestrator (Claude Code, your own LLM wrapper,
a CI pipeline, a multi-agent fleet) at rush run, and it gets a
model-agnostic, wrapper-stable JSON envelope back: one process it can
spawn any number of times in parallel against the same repository
without the instances corrupting each other's state.
- npm package:
@phpcraftdream/rush - Source: github.com/PHPCraftdream/rush
npm install -g @phpcraftdream/rush
rush run --role smart "summarize what this repo does"Most coding-agent CLIs are built for a human sitting in a terminal, reading streamed output and clicking through permission prompts. This one is built for the opposite case: something else is the operator — another LLM, a script, a CI job — and it needs a subprocess it can call over and over, unattended, and trust the output of.
Typical ways people actually use it:
- Claude Code (or any other agent) delegating sub-tasks. The
top-level agent hits a chunk of work that's cheap, mechanical, or
just doesn't need its own context window — it shells out to
rush run, gets a JSON envelope back, and keeps going. See the/rushskill shipped with this fork for the exact pattern. - Fan-out over a codebase. Five, ten, fifty
rush runinvocations against the same.rush/directory at once — each one a separate session, each one safe from the others' writes (SQLite, file locks, cost accounting are all defended for exactly this). - CI pipelines that need an LLM step. A build step that asks a model to review a diff, write a migration, or fix a failing test — and needs a predictable exit code and a parseable result, not a chat transcript to eyeball.
- Headless automation on a schedule. Cron jobs, webhooks, queue workers — anything that needs "run this prompt against this repo and tell me what happened" as a function call, not an interactive session.
- A human who still wants to look in. The React/Tailwind web UI covers that case, but it's the second-class entry point here — the CLI and its JSON contract are what this project is actually built around.
If what you actually want is a polished terminal UI for a human to
chat with an agent in, that's upstream charmbracelet/crush
— this repository started as a fork of it and has since diverged
substantially in that direction (no TUI, no upstream server model,
different provider/session engine). See CHANGELOG.fork.md for the
full list of what changed and why.
The product is rush as an agent's hands, not as a human's coding
companion. Every divergence below follows from that single repositioning:
- The TUI is gone — a human is no longer the primary user of the process. A React/Tailwind web UI stays for the cases where a human DOES want to look in, but the design centre is the CLI.
- The CLI is the contract.
rush runexposes a wrapper-stable JSON envelope with a small, frozen set of fields an orchestrator parses without surprises. New flags (--role,--session,--format,--agents,--timeout, …) all exist to give the upper LLM precise control over a delegated turn. - Multiple instances are a first-class concern. Five
rush runagainst one.rush/directory cannot corrupt each other's state — sessions, cost accounting, log writes, MCP-id files and SQLite are all defended explicitly. - Honest error reporting. When the model fails its contract (returns invalid JSON, runs out of context, stalls the stream) the envelope says so — there is no silent success because the agent on top cannot read the operator's mind.
- Bootstrap helper (
rush claude-init) installs/rush,/rush-fallbackand/wrushslash commands into the workspace so the upper LLM knows when and how to delegate torush runinstead of grepping the codebase itself./wrushis/rushwith mandatory git-worktree isolation — every delegation runs in a dedicated worktree instead of the primary checkout.
The browser UI is the second-class entry point for humans peeking in, the orchestrator-facing CLI is first-class.
| Area | Upstream | This fork |
|---|---|---|
| Primary user | Human in a terminal | Another agent (LLM, CI, orchestrator) calling the CLI |
| Front-end | Bubble Tea TUI (~495 files under internal/ui/) |
React/Tailwind SPA in web/, embedded via go:embed. Optional. |
| Transport | REST /v1/... over Unix socket / Windows named pipe |
WebSocket /ws over TCP loopback (single embedded server) |
| Auth | None (local-socket trust) | Token-based, see internal/server/auth.go |
| Sessions | One model per agent role, set globally | Per-session model overrides + per-session system prompt, all persisted in SQLite |
| Permissions | In-memory rules during a TUI run | Persistent per-session rules in SQLite; cross-process visible |
| Parallel runs | Not a target | First-class — flock per session, OS-level lock release on crash, atomic file writes, additive cost SQL, MCP-id flock |
crush run |
Single-shot quick fire | Wrapper-friendly: --role, --session get-or-create, --json/--format/--agents/--timeout/--stream, JSON-envelope validation, assistant_notes, fallback error messages |
| CLI providers | Limited bridge | npx Claude Code, Gemini CLI, Codex CLI, MCP bridge for external tools, session resume for Anthropic prompt caching; Haiku available as local-cli/cli-claude-haiku (200k ctx, @low|medium|high effort) |
| Web UI features | n/a | Slash-command + skill autocomplete, dark/light theme, pinned messages, fork-session button, LSP/MCP/provider management modals, file/image attachments |
The full per-file decision log lives in CHANGELOG.fork.md.
That document is also the survival guide for merging upstream main
into the fork — every divergence is annotated with a // Fork patch:
comment in the code so conflicts surface at the right line.
rush run (the non-interactive CLI mode this fork is built around)
auto-approves every tool call — bash, write, edit, fetch, everything.
There is no dialog, no allow/deny prompt, no toggle to turn this off:
it is how non-interactive mode works by design, because there is no
human on the keyboard to click Allow. The model has the same file and
process access as the OS user running rush.
This is not the old per-session "YOLO" toggle (that UI feature has
been removed entirely — see CHANGELOG.fork.md). It is unconditional
for every rush run invocation, with no flag to restore per-request
prompting. The interactive web UI (rush web) is different: it still
shows a permission dialog (Allow / Deny / Allow-always) for each tool
call unless the operator clicks through it manually.
Run rush run inside an isolated environment — Docker, Podman, a
VM, or at minimum an OS-level sandbox/dedicated worktree — whenever
the prompt or the repository content is not fully trusted, or when
model-written code will execute. Do not point it at a host you can't
afford to have fully modified. See --cwd and RUSH_FORBID_WRITES
below for lighter-weight mitigations when a full container isn't
practical, but they are not a substitute for real isolation — they
only block specific tool-call targets, not arbitrary shell execution.
Two complementary entry points; pick whichever fits the job.
rush web # default port + open browser
rush web --port 8080 --no-open # for a remote workstationA long-lived process. Sessions live in .rush/rush.db, the UI loads
the React bundle from inside the binary, the WebSocket is local-only +
token-authed. This replaces upstream's TUI.
The canonical pattern an orchestrator should be writing:
out=/tmp/audit-A.json
RUSH_FORBID_WRITES="$out" \
rush run --role smart --session "audit-A" \
--json --format json --timeout 10m \
< /tmp/audit-A.prompt > "$out" 2>"$out.err"
jq -r '.exit_reason' "$out" # "end_turn" on success, "invalid_json" if model broke contract, "error" otherwise
jq -r '.final_text' "$out" # the raw JSON the model produced (validated)
jq -r '.assistant_notes' "$out" # any prose preamble that was stripped
jq -r '.error' "$out" # error.message if non-success--role(required) — four slots exist:smart(the strong default; combined with a configured worker model this also triggers orchestrator mode — see below),fast(the cheap slot),worker(optional, no alias, cheap slot for delegated hands-on sub-task work — reachable directly via--role worker, or indirectly when a worker is configured and a--role smartrun dispatches a sub-agent via theagenttool), andreviewer(optional, no alias, the strongest slot, for explicit review invocations — never auto-selected).worker/reviewerare configured via the web UI orrush.json'smodels.worker/models.reviewer(rush models usemanages smart/fast; see--worker/--reviewerflags below for the other two). No silent default to the expensive model either way.--session <id>— get-or-create. Pass the same id again to continue, or a new id to start fresh. Works as a stable key for CI matrices and orchestrator wrappers.--json— emits a single wrapper-stable envelope on stdout:{session_id, exit_reason, final_text, assistant_notes, stripped_bytes, tool_calls, usage, duration_ms, error, warnings}.--format json | json-schema:<f> | @<f> | <any text>— appends a per-turn output-shape hint to the prompt AND post-validatesfinal_text. Withjsonorjson-schema:, the envelope is also post-processed: markdown fences and prose preamble are stripped;json.Validruns on what remains. If the model returns syntactically broken JSON (e.g. forgot a]somewhere),exit_reason="invalid_json"is set, the original (unstripped) text is preserved infinal_text, the failed strip attempt goes toassistant_notes, anderrorcarries ajson.SyntaxErrorwith a byte offset. Wrappers can branch onexit_reasoninstead of trusting the model's optimistic"stop".--agents single | with-agents | agent-allow— sub-agent fan-out policy. Leaving the flag unset is the default and disables fan-out — theagentandagentic_fetchtools are removed from the toolset entirely, same as passingsingleexplicitly (a non-interactive run has no UI to surface sub-agent work).with-agentsnudges the model to fan out.agent-allowopts in without a nudge, leaving the choice to the model. Automatic exception: when--agentsis left unset (not explicitlysingle) AND--role smartAND aworkermodel is configured, the ban on theagenttool specifically is lifted automatically — this is "orchestrator mode" (see below);agentic_fetchstays banned regardless, since it always runs on the fast model and isn't part of hands-on delegation. An explicit--agents singlealways overrides this and keeps both tools banned.--aggregation summary | concat | attach— how sub-agent fan-out output reaches the orchestrator.summary(default) lets the parent compose a wrap-up; detail lives in the DB only.concatadds a prompt nudge so the parent includes each sub-agent's reply verbatim infinal_text.attachcollects each sub-agent's last assistant text intoenvelope.sub_agent_outputsso the orchestrator gets the structured set;final_textbecomes a brief wrap-up. An always-on warning fires inenvelope.warningswhen parent collapses sub-agent outputs to <40% of their combined character count, regardless of which mode is in use.--timeout <duration>— hard wall-clock cap; the partial answer is preserved in the session and surfaced in the envelope.--timeout-extends-on-progress— when set, the stream watchdog resets its idle deadline every time streaming activity occurs, so long compositions (code generation, multi-section reports) are not killed prematurely. Capped by--timeout-hard-capif set.--timeout-hard-cap <duration>— maximum wall-clock time the watchdog will allow even with--timeout-extends-on-progress. Without a cap a continuously-streaming response runs forever. Typically set to 3–4× the idle timeout.--allow-peak-hours— bypasses a provider's configuredpeak_hoursrefusal window for this single invocation only. No persistent config-level equivalent exists; the override is conscious and one-off by design. Never add this flag on an orchestrating agent's own initiative — only when a human operator has explicitly asked, in that specific request, to override peak hours.--system-prompt[-file]— persists onto the session so follow-up runs inherit it.--stream— streams every token to stdout for live wrappers.
stripped_bytes— how many bytes were removed fromfinal_textby the JSON stripper (when--json+--format jsonwere active). Graph it across runs to track how often your model wraps in prose.tool_calls: [{name, count}]— post-hoc inventory of what tools the model actually used. Useful to verify--agents singleactually blocked fan-out.sub_agent_outputs[]— present only with--aggregation attach. Each entry is{session_id, title, final_text, char_count}for one sub-session the parent'sagenttool dispatched during this run.warnings[]— non-fatal observations. Includesfinal_text appears truncatedwhen the run errored mid-composition (so the operator sees the model was about to continue);final_text is empty after N sub-agent fan-out call(s)when the model dispatched sub-agents but never composed a top-level reply; andreduction-loss: final_text is X% of N combined sub-agent charswhen the parent over-summarised (re-run with--aggregation=attachorconcatto recover).error— present wheneverexit_reasonis non-success. If the provider's Finish part had no message (some providers emit a bare error finish), a fallback names the most likely causes (provider HTTP error, stream stall, OOM, context overflow). Oneexit_reasonvalue is a deliberate stop, not a failure:"awaiting_answer", set when the model calledask_question— see below.recovered_partial— present when the session had an orphaned partial assistant message from a previous interrupted run (detected byFinish{Partial: true}on an unfinished row). Shape:{message_id, chars, last_flush_at, text}. An always-on WARN inwarnings[]fires when this field is populated: "recovered N chars of partial assistant text — model run was interrupted". The text may be incomplete but is usually the bulk of what the model produced before the kill.
The model has an ask_question tool it can call when it genuinely
needs input to proceed (ambiguous scope, a destructive choice, missing
info) instead of guessing. Because rush run has no synchronous way
to block mid-turn for an answer, calling it force-finishes the turn
cleanly:
rush run --role smart --session "deploy-1" "deploy the release" > out.json
jq -r '.exit_reason' out.json # "awaiting_answer"
jq -r '.error' out.json # question + suggested options + resume commandexit_reason: "awaiting_answer"is not a failure — treat it like a normal continuation point, not something to retry.- The question, suggested options, and the exact resume command live in
.error(not.final_text). - Resume with
rush run --session <id> "<your answer>"— notrush sessions inject, since the process already exited.
Orchestrator mode: when --role smart is used and a worker model
is configured, the smart agent's system prompt gains an "Orchestrator
mode" instruction: understand the task's shape, but delegate hands-on
work (editing, writing, running commands) to the agent tool in
worker-context-sized chunks instead of implementing inline — one file
or logical change per delegation, with enough standalone context since
the worker doesn't see the parent conversation.
A worker sub-agent can itself call ask_question and pause. That
does not end the orchestrator's turn (unlike the top-level case
above) — it surfaces as a normal, non-error tool result along the
lines of SUB-AGENT QUESTION (session <id>): <question>. The
orchestrator answers by calling the agent tool again with
resume_session_id="<id>" and the answer as the prompt, continuing
the same sub-session instead of starting a fresh one.
RUSH_FORBID_WRITES— comma-separated paths thewrite/edit/multiedittools must NOT touch. Set this to the stdout-redirect target before everyrush run— otherwise the model can pick the same filename it sees in the prompt and overwrite your envelope output. Tool calls to forbidden paths fail visibly to the model; it then falls back to returning content viafinal_text.RUSH_PROVIDER_CACHE_TTL— duration (24hdefault,0sto always refresh). Caches the Catwalk/Hyper provider catalog locally sorush models showand similar read-only commands skip the ~3-second HTTP round-trip when the on-disk cache is fresher than the TTL.RUSH_COLOR_SCHEME—light|dark|auto(defaultauto). Forces the CLI help/error color palette onto a light or dark background, working around unreliable terminal light/dark auto-detection. The auto path queries the terminal's background color with an OSC 11 escape sequence and a hard 2-second timeout; if the terminal doesn't reply in time (or stdin/stdout aren't both real TTYs, e.g. when an orchestrator spawnsrushwith redirected stdin), lipgloss'sHasDarkBackgroundfalls back to assuming a dark background — so on a light-themed terminal the help renders grey-on-white with low contrast. This has been reported on WezTerm on Windows. SetRUSH_COLOR_SCHEME=light(or pass--color-scheme light, which is global and wins over the env var) to force the light palette.Windows gotcha:
setx RUSH_COLOR_SCHEME lightonly writes the variable to the registry for future processes — it does not update any terminal window that's already open. Open a new terminal tab/window (or restart the shell) before checking whether it took effect, or you'll see the old behavior and wrongly conclude the flag doesn't work.
Permissions are unconditionally auto-approved in rush run — see
"Security" above. --cwd /tmp/sandbox or a worktree narrows the blast
radius somewhat, but a container (Docker/Podman) or VM is the only
real isolation boundary; use it whenever the prompt or repo content
isn't fully trusted.
The fork explicitly supports running 5+ rush run --session X against
the same working directory concurrently (the canonical use case is
multi-section code audits). The defence layers:
- Per-session OS flock (
internal/session/lock.go) — two processes cannot share a session id. - SQLite WAL +
busy_timeout=30000+ single-writer-per-process connection pool. - Cost mutations go through additive SQL (
IncrementSessionCost) so concurrent sub-agent goroutines AND parallel processes cannot lose cost via read-modify-write. - Atomic file writes (
fsext.AtomicWriteFile) inwrite/edit/multiedittools —kill -9mid-write cannot truncate the user's file. - Per-process
pid=Nattribute in every log line — interleaved Windows log writes can be split post-hoc withjq 'select(.pid==N)'. - Permission grants ("Always allow") are DB-direct on every check, so a grant made in process A is immediately visible in process B without restart.
- MCP
qwen/gemini-mcp-idand~/.{qwen,gemini}/settings.jsonwrites are flock'd with a 30s timeout so a wedged sibling cannot freeze the fleet.
See CHANGELOG.fork.md Section 4.I for the full
parallel-process audit and the trade-offs we explicitly kept (e.g. N
processes still spawn N stdio children of every configured MCP server
— use HTTP/SSE-transport MCPs in parallel runs).
rush sessions inject <session-id> -m "also update the changelog"
rush sessions inject <session-id> -f ./notes/next-step.md
rush sessions inject <session-id> -m "stop, wrong approach" --interrupt
rush sessions inject 8a3f0c -m "continue" --jsonUse this when a rush run --session X you already launched (from an
orchestrator, another terminal, or a /rush sub-agent) is mid-turn
and you want to hand it new information without killing it. <id>
accepts a full session id or the short hash printed by sessions list.
- The message is persisted immediately as a normal user message —
Role
user, same as if it were typed — so it renders in the web UI exactly like anything the operator sends themselves. - By default (no
--interrupt) it merges into the session's next provider request without cancelling the in-flight turn — same latency as the web UI's non-stopping inject. - With
--interruptthe running turn is cancelled and immediately restarted with the new message, mirroring the web UI's interrupt-and-send. - If no process is currently running the session, the message is still persisted and picked up the next time the session runs; the command tells you so instead of failing.
Delivery costs nothing at rest: rush sessions inject writes a
signal row to a pending_injects table, and the running process only
checks it at points it already visits on every turn (next provider
step for the merge case, a lightweight 3s ticker bound to the active
turn for --interrupt) — no standing poll loop, no open port.
Every assistant message records its own token accounting, so you can ask how much a model actually cost and how well the prompt cache is working:
rush sessions cache <session-id> # one session, per model
rush sessions cache --by model # every session, per model
rush sessions cache --since 7d --by day # last week, day by day
rush sessions cache --since 30d --json # machine-readableTokens are split into three disjoint classes, so the prompt size is
their sum: INPUT (fresh, full price), READ (served from the
provider's prompt cache, much cheaper) and WRITE (written into the
cache). HIT is read / (input + read + write).
Grouping is by the model that actually produced each message, so a
session that switched models mid-conversation is split correctly. That
is the difference from rush sessions cost, which groups by the
session's current model and whose TOKENS column sums last-snapshot
session counters rather than real totals — the two read different
sources and are deliberately not merged into one table.
The output refuses to state numbers it cannot back up: HIT prints
n/a rather than 0% when a provider does not report caching (a
fabricated zero is indistinguishable from a real miss), every table
reports its coverage when some messages have no usage recorded, and
--by day omits HIT entirely because a day can span providers whose
cache visibility differs.
If you drive Rush from another LLM (e.g. Claude Code), run once:
rush claude-init # install /rush, /rush-fallback and /wrushThis installs three slash-commands into .claude/commands/, each
triggered explicitly by the operator — never auto-discovered:
-
rush.md—/rush <task>, an operator-triggered command that builds arush runinvocation with sensible defaults and launches it in the primary checkout (or, for genuinely parallel/overlapping delegations, in a git worktree the orchestrator sets up itself). -
rush-fallback.md—/rush-fallback <agent>, arms a reroute to a named local agent for the rest of the session whenrush runhits a hard rate/quota limit. -
wrush.md—/wrush <task>, identical to/rushexcept isolation is mandatory rather than situational: every delegation — solo or parallel, trivial or not — runs inside a freshly created git worktree, never the primary checkout, and the orchestrator merges the verified diff back and cleans up the worktree afterward. Reach for/wrushwhen you want a hard guarantee that a delegated task cannot disturb the primary checkout's working tree or index, even if the sub-agent misbehaves.Trust boundary, stated explicitly:
/wrushis a slash-command convention — plain text the orchestrating LLM reads and follows. There is no code-level guard in therushbinary itself that verifies arush runinvocation'scwdis actually under<repo-root>/worktrees/; the isolation guarantee holds only as long as the orchestrator (and any sub-agent it delegates to) actually follows the template. An operator who manually launches/wrushfrom the primary checkout, or an orchestrator that ignores the instruction, gets no runtime enforcement catching the mistake.
Earlier versions of this fork also wrote a long "delegate everything to
rush" block into CLAUDE.md. That block turned out to be a recursive-
delegation footgun: a sub-agent reading it on startup would try to
delegate every task back into rush run, spawning another sub-agent
which read the same block, and so on (see CHANGELOG.fork.md batch 22 for
the postmortem). claude-init now strips that legacy block on every
invocation (matching any version, v1..vN) and removes CLAUDE.md
entirely if stripping leaves it empty. Re-run claude-init at any time
— it's idempotent.
To uninstall completely: rush claude-del removes all three
slash-command files and strips any remaining legacy CLAUDE.md block.
Four model slots exist: smart/fast (the pair every
rush run uses by default) plus two optional ones, worker (cheap
slot for delegated sub-task work — see orchestrator mode above) and
reviewer (strongest slot, explicit-only). Commands covering the surface:
rush models list # show available atoms + raw provider/model ids (reads cache; no network)
rush models list --refresh # force a network refresh of provider data before listing
rush models use <smart> <fast> [--worker <atom>] [--reviewer <atom>] [--global | --local]
rush models use --fast <atom> # set just one slot — --smart/--fast/--worker/--reviewer are all independent
rush models state # what's effective + per-scope breakdown (alias: `show`)
rush models efforts [model] # explain reasoning-effort levels and how to set them
rush models bump <role> up|down # step a role's effort by one level
rush models unset [smart|fast|worker|reviewer|both|all] [--global|--local]No side effects by default:
rush models listreads the on-disk provider cache (or the embedded provider list bundled with Rush when no cache exists yet) and does NOT trigger a network fetch or write any cache files. Pass--refreshto force a fresh fetch from Catwalk and Hyper before rendering. The output shape (text and--json) is identical in both modes.
Atoms are short, friendly aliases. list prints them filtered by your
currently-enabled providers — disabled providers' atoms are hidden so the
list only shows what actually works right now:
ATOMS (combine as `rush models use <smart> <fast>`):
Anthropic:
via local `claude` CLI
opus-low, opus-medium, opus-high, opus-xhigh, opus-max Claude Opus (1M ctx)
sonnet-low, sonnet-medium, sonnet-high, sonnet-xhigh, sonnet-max Claude Sonnet (1M ctx)
haiku-low, haiku-medium, haiku-high, haiku-xhigh, haiku-max Claude Haiku (200k ctx)
Zai:
glm5_3 GLM 5.3 (1M ctx)
glm5_turbo GLM 5 turbo (200k ctx)
...
Anthropic atoms require a level suffix (opus-high, sonnet-low, etc.) —
the level list comes from parsing claude --help at first use (falls back
to a static low/medium/high/xhigh/max list if parsing fails).
Z.AI atoms are not all effort-less: GLM-5.3 (glm5_3) has 3 real
wire states (off/high/max) settable via the long-form suffix
(glm5_3-max) or raw zai/glm-5.3@max — one more
than every other Z.AI/GLM atom (5-turbo, 4.7, 4.6, ...), which
exposes only a boolean thinking toggle (off/on). Both forms are
validated against the atom's real levels; rush models efforts <model>
prints the exact list and commands for any specific model. (GLM-5.3's
context window/levels are provisional — see the comment above its entry
in internal/cmd/models_atoms.go.) The web UI's model picker also shows
GLM-5.3: since docs.z.ai and the upstream catwalk provider registry don't
list it yet, internal/config/load.go's configureProviders synthesizes
the same provisional entry into the Z.AI provider's model list (skipped
once catwalk or your own providers.zai.models config actually provides
one), so both the CLI atom and the web picker agree.
rush models use opus-high glm5_turbo # mixed Anthropic smart + Z.AI fast
rush models use --local glm5_3 glm5_turbo # workspace-only override
rush models use openai/gpt-5@high zai/glm-5-turbo # raw provider/model fallback for anything not in the atom list
# Also set worker/reviewer in the same call (independent of smart/fast)
rush models use opus-high haiku-low --worker glm5_turbo --reviewer opus-max
# Change ONE slot only, leaving the other three exactly as they are —
# --smart/--fast work just like --worker/--reviewer always have. The two
# positional args and --smart/--fast are mutually exclusive per call.
rush models use --fast glm4_7_flash
rush models use --smart opus-high
# Discover effort levels for a specific model (or run with no arg for the
# full per-provider overview, including the Z.AI graduated-vs-boolean split)
rush models efforts glm5_3
# Step a role's effort by one level instead of retyping the full atom name
rush models bump reviewer up
rush models bump worker down --localmodels state shows the currently-effective values for all four slots and
the per-scope breakdown so you always know whether your --local workspace
overrides your global default or vice versa.
The cascade has a third level: session. --global/--local (system/
workspace) both live in a rush.json file and are what models state
reports. On top of that, the web UI lets each open session pin its own
smart/fast/worker/reviewer, stored in that session's DB row, not in any
rush.json — so it's invisible to models state and to other sessions.
Resolution order is always system → folder → session: a session with no
override inherits whatever models state would show; setting one there
wins for that session only, and clearing it (the model picker's "Inherit"
entry, or the "Default models" modal's per-slot clear button) falls straight
back to the folder/system value. The web UI's header "Default models"
button opens a modal with three blocks — System, Folder, Session — each
showing all four slots: what's explicitly set at that level, or, when
unset, the inherited value and which level it's coming from.
Removed in batch 11:
rush models set --large X --small Yand the entirerush models presetsubtree (save/use/list/delete). Both commands now print a redirect notice pointing atrush models use.
To clear an override and fall back to the other scope: rush models unset [smart|fast|worker|reviewer|both|all] [--local|--global]. both (the
default when the arg is omitted) clears smart+fast only; all clears all
four slots. Missing keys are a no-op.
- You want the TUI experience. Use upstream — the fork removed it.
- You want a stable, blessed-by-Charm distribution path. This fork does not publish Homebrew/winget/AUR releases.
- You want the official REST
/v1/...protocol for wrapping. This fork speaks WebSocket only. - You're a human typing into one terminal session at a time. Upstream's TUI is genuinely nicer for that. This fork's CLI is shaped for scripts and orchestrators; the web UI is for peeking in, not for daily-driving conversational work.
- You're building a multi-agent system where one LLM delegates code
work to another.
rush runis that worker; the envelope is the protocol between them. - You run a multi-section audit / refactor / migration as 5+ parallel
rush runinvocations against one repo and need the cost accounting + lock-file + atomic-write guarantees that follow. - You wrap LLMs in CI: stable
--sessionkey per build matrix,--timeoutfor budget control,--jsonfor jq-parseable output,--format jsonfor raw JSON contracts with validation. - You want a long-running embedded coding agent reachable over a browser-served WebSocket from a thin React UI.
The original upstream README follows below, kept verbatim because most
of its content (installation, configuration, MCP/LSP setup, model
providers) applies unchanged to this fork. Where the fork diverges,
either the text above or CHANGELOG.fork.md overrides.
Logo, release badge, build-status badge and demo GIF removed — they point at upstream
charmbracelet/crushartifacts (Charm's logo, upstream's GitHub Actions status, upstream's release tag) and would misrepresent this fork's identity, release cadence and CI status. The text below is the upstream README's prose, kept verbatim because the installation / configuration / providers material applies to this fork unchanged.
- Multi-Model: choose from a wide range of LLMs or add your own via OpenAI- or Anthropic-compatible APIs
- Flexible: switch LLMs mid-session while preserving context
- Session-Based: maintain multiple work sessions and contexts per project
- LSP-Enhanced: Rush uses LSPs for additional context, just like you do
- Extensible: add capabilities via MCPs (
http,stdio, andsse) - Works Everywhere: first-class support in every terminal on macOS, Linux, Windows (PowerShell and WSL), Android, FreeBSD, OpenBSD, and NetBSD
- Industrial Grade: built on the Charm ecosystem, powering 25k+ applications, from leading open source projects to business-critical infrastructure
This fork ships as an npm package:
npm install -g @phpcraftdream/rush
rush run --role smart "your prompt here"Or build from source (requires Go 1.26+):
git clone https://github.com/PHPCraftdream/rush.git
cd rush
go build -o rush .Note
The package managers upstream charmbracelet/crush publishes through
(Homebrew, Winget, Scoop, apt/yum via repo.charm.sh, the Nix NUR
module, go install github.com/charmbracelet/crush@latest) install
the upstream project, not this fork — this fork's Go module path is
github.com/PHPCraftdream/rush, distinct from upstream. The npm package above
and building from this repository
directly are the two ways to get this fork specifically.
Warning
Productivity may increase when using Rush and you may find yourself nerd sniped when first using the application.
Prefer to call Rush from your own Go process instead of shelling out to
the CLI? See sdk/README.md for the embeddable SDK —
sdk.Open + Client.Run gets you a typed result envelope back, with
support for explicit per-call provider credentials, ephemeral in-memory
sessions, and concurrent multi-tenant use on one Client.
The quickest way to get started is to grab an API key for your preferred provider such as Anthropic, OpenAI, Groq, OpenRouter, or Vercel AI Gateway and just start Rush. You'll be prompted to enter your API key.
That said, you can also set environment variables for preferred providers.
| Environment Variable | Provider |
|---|---|
HYPER_API_KEY |
Charm Hyper |
ANTHROPIC_API_KEY |
Anthropic |
OPENAI_API_KEY |
OpenAI |
VERCEL_API_KEY |
Vercel AI Gateway |
GEMINI_API_KEY |
Google Gemini |
SYNTHETIC_API_KEY |
Synthetic |
ZAI_API_KEY |
Z.ai |
ZHIPU_API_KEY |
Z.ai (fallback when ZAI_API_KEY is unset) |
MINIMAX_API_KEY |
MiniMax |
HF_TOKEN |
Hugging Face Inference |
CEREBRAS_API_KEY |
Cerebras |
OPENROUTER_API_KEY |
OpenRouter |
IONET_API_KEY |
io.net |
ALIBABA_SINGAPORE_API_KEY |
Alibaba (Singapore) |
GROQ_API_KEY |
Groq |
AVIAN_API_KEY |
Avian |
OPENCODE_API_KEY |
OpenCode Zen & Go |
VERTEXAI_PROJECT |
Google Cloud VertexAI (Gemini) |
VERTEXAI_LOCATION |
Google Cloud VertexAI (Gemini) |
AWS_ACCESS_KEY_ID |
Amazon Bedrock (Claude) |
AWS_SECRET_ACCESS_KEY |
Amazon Bedrock (Claude) |
AWS_REGION |
Amazon Bedrock (Claude) |
AWS_PROFILE |
Amazon Bedrock (Custom Profile) |
AWS_BEARER_TOKEN_BEDROCK |
Amazon Bedrock |
AZURE_OPENAI_API_ENDPOINT |
Azure OpenAI models |
AZURE_OPENAI_API_KEY |
Azure OpenAI models (optional when using Entra ID) |
AZURE_OPENAI_API_VERSION |
Azure OpenAI models |
If you prefer subscription-based usage, here are some plans that work well in Rush:
Is there a provider you’d like to see in Rush? Is there an existing model that needs an update?
Rush’s default model listing is managed in Catwalk, a community-supported, open source repository of Rush-compatible models, and you’re welcome to contribute.
(Upstream's Catwalk badge image removed — see the project at charmbracelet/catwalk.)
This project was renamed from "Crush" to "Rush". If you have existing Crush
installations, run rush migrate to handle everything a filesystem tool can
handle automatically, then follow its final report for anything it can't.
rush migrate renames, in one pass:
.crush/directories to.rush/andcrush.jsonfiles torush.json— both workspace configs and the global config/data locations (and, on Unix, the root-owned/etc/crush/crush.jsonsystem config — this one may need elevated privileges)- Known artifact files inside a migrated directory:
crush.db→rush.dbandlogs/crush.log→logs/rush.log, so existing session history and logs stay reachable under the names the app now looks for - Legacy-named values inside a migrated
rush.json:disabled_skillsentries referencing a renamed builtin skill ID (crush-config→rush-config,crush-hooks→rush-hooks), and.crush-referencing path segments (including the~/.config/crushconvention) or the oldCRUSH.mdcontext-file name inskills_paths,global_context_paths, anddata_directory— this is a narrow, field-scoped rewrite, not a blind find-and-replace, so unrelated content (e.g. a hook command string that happens to mention "crush") is left untouched - Leftover files in an already-existing global target directory: if
~/.config/rush(or the data-dir equivalent) already existed before migrating — common, since the app itself may have created it on a prior run — any other legacy files still sitting in the old directory (skills/,auth.json, etc.) are also moved into the target directory, one item at a time, refusing only the specific items whose names already conflict there
By default it operates on the current working directory (or --cwd if set)
and always attempts the global/system locations above; --recursive walks
the entire directory tree from the given root, including the root itself.
Use --dry-run to preview changes without touching anything. Conflicting
targets are never clobbered — a conflicting item is refused and reported,
and everything else still proceeds.
At the end of every run, rush migrate prints a "Manual follow-up needed"
section for the two things a rename tool cannot fix by itself:
- Any
CRUSH_*-prefixed environment variable still set in your shell with no automatic Rush equivalent — the running app only readsRUSH_*names now (e.g.RUSH_FORBID_WRITES,RUSH_CACHE_DIR,RUSH_SKILLS_DIR), so an oldCRUSH_*variable left in.bashrc/.zshrc/your PowerShell profile is silently ignored rather than erroring. This is computed from your actual shell environment at the time you run the command, not a fixed list, so it only flags what you personally still have set. - A reminder to run the matching
*-delcommand (claude-del,codex-del,gemini-del,grok-del,qwen-del) if you still have old crush-named slash-commands/agents installed by a pre-rename*-initrun — the current*-initcommands install new rush-named files alongside them but never touch the old ones, so cleanup is a separate, explicit step.
Instead of running all 10 *-init/*-del commands by hand, rush cli-refresh runs each tool's del-then-init pair back to back for all 5
integrations at once (local dir by default, --recursive [root] for a
directory tree, or --global; supports --dry-run too).
Also update scripts that reference the old names directly: commands like
crush run → rush run, paths like .crush/ → .rush/, crush.json →
rush.json, and crush.db → rush.db.
Tip
Rush ships with a builtin rush-config skill for configuring itself. In
many cases you can simply ask Rush to configure itself.
Rush runs great with no configuration. That said, if you do need or want to customize Rush, configuration can be added either local to the project itself, or globally, with the following priority:
.rush.jsonrush.json$HOME/.config/rush/rush.json
Items 1 and 2 are searched by name in the project root, walking up the
directory tree from cwd — a file at ./.rush/rush.json (inside the
.rush/ subdirectory) is not discovered; that directory holds ephemeral
data, not config.
Configuration itself is stored as a JSON object:
{
"this-setting": { "this": "that" },
"that-setting": ["ceci", "cela"]
}As an additional note, Rush also stores ephemeral data, such as application state, in one additional location:
# Unix
$HOME/.local/share/rush/rush.json
# Windows
%LOCALAPPDATA%\rush\rush.jsonTip
You can override the user and data config locations by setting:
RUSH_GLOBAL_CONFIGRUSH_GLOBAL_DATA
Rush can use LSPs for additional context to help inform its decisions, just like you would. LSPs can be added manually like so:
{
"$schema": "https://charm.land/crush.json",
"lsp": {
"go": {
"command": "gopls",
"env": {
"GOTOOLCHAIN": "go1.24.5"
}
},
"typescript": {
"command": "typescript-language-server",
"args": ["--stdio"]
},
"nix": {
"command": "nil"
}
}
}Rush also supports Model Context Protocol (MCP) servers through three transport
types: stdio for command-line servers, http for HTTP endpoints, and sse
for Server-Sent Events.
Shell-style value expansion ($VAR, ${VAR:-default}, $(command), quoting,
nesting) works in command, args, env, headers, and url, so
file-based secrets work out of the box. You can use values like "$TOKEN"
or "$(cat /path/to/secret/token)". Expansion runs through Rush's embedded
shell, so the same syntax works on every supported system, Windows included.
Unset variables expand to the empty string by default, matching bash. For
required credentials, use ${VAR:?message} so an unset variable fails loudly
at load time with message instead of silently resolving to empty:
{ "api_key": "${CODEBERG_TOKEN:?set CODEBERG_TOKEN}" }Headers (both MCP headers and provider extra_headers) whose value
resolves to the empty string are dropped from the outgoing request rather
than sent as Header:. That keeps optional env-gated headers like
"OpenAI-Organization": "$OPENAI_ORG_ID" clean when the variable is unset.
Provider extra_body is a non-expanding JSON passthrough; put env-driven
values in extra_headers or the provider's api_key / base_url, all of
which do expand.
Security note:
rush.jsonis trusted code. Any$(...)in it runs at load time with your shell's privileges, before the UI appears. Don't launch Rush in a directory whoserush.jsonyou haven't reviewed.
{
"$schema": "https://charm.land/crush.json",
"mcp": {
"filesystem": {
"type": "stdio",
"command": "node",
"args": ["/path/to/mcp-server.js"],
"timeout": 120,
"disabled": false,
"disabled_tools": ["some-tool-name"],
"env": {
"NODE_ENV": "production"
}
},
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"timeout": 120,
"disabled": false,
"disabled_tools": ["create_issue", "create_pull_request"],
"headers": {
"Authorization": "Bearer $GH_PAT"
}
},
"streaming-service": {
"type": "sse",
"url": "https://example.com/mcp/sse",
"timeout": 120,
"disabled": false,
"headers": {
"API-Key": "$(echo $API_KEY)"
}
}
}
}Rush has preliminary support for hooks. For details, see the hook guide.
Rush automatically includes two files for cross-project instructions.
~/.config/rush/RUSH.md: Rush-specific rules that would confuse other agentic coding tools. If you only use Rush, this is the only one you need to edit.~/.config/AGENTS.md: generic instructions that other coding tools might read. Avoid referring to Rush-specific features or workflows here. You probably only care about this if you use multiple agentic coding tools and want to share instructions between them.
You can customize these paths using the global_context_paths option in your
configuration:
Rush respects .gitignore files by default, but you can also create a
.rushignore file to specify additional files and directories that Rush
should ignore. This is useful for excluding files that you want in version
control but don't want Rush to consider when providing context.
The .rushignore file uses the same syntax as .gitignore and can be placed
in the root of your project or in subdirectories.
By default, Rush will ask you for permission before running tool calls. If you'd like, you can allow tools to be executed without prompting you for permissions. Use this with care.
{
"$schema": "https://charm.land/crush.json",
"permissions": {
"allowed_tools": [
"view",
"ls",
"grep",
"edit",
"mcp_context7_get-library-doc"
]
}
}Non-interactive rush run invocations auto-approve every permission request
by default (no human is on the keyboard). The permissions.run block flips
that to deny-by-default so an unattended run can be scoped to a known-safe
allowlist. Interactive sessions (TUI / web) are never affected.
Set permissions.run.restrict to true, then list the non-bash tools
(allow_tools, same tool / tool:action syntax as allowed_tools) and
bash command patterns (allow_bash) the run may use. Anything outside those
lists is denied cleanly.
{
"$schema": "https://charm.land/crush.json",
"permissions": {
"run": {
"restrict": true,
"allow_tools": ["view", "edit:write"],
"allow_bash": [
"git diff",
"glob:ls *",
"regex:^go (test|build)"
]
}
}
}allow_bash entries take one of four forms:
cmd args— word-boundary prefix match (e.g."git diff"matches"git diff HEAD~1"but not"git difftool"). Chaining metacharacters (;,|,&&,$(,`) are refused, so"ls"can never approve"ls && rm -rf /".exact:cmd— whole-string equality after trimming whitespace; same chaining guard.glob:pat—filepath.Matchagainst the raw command string. No chaining guard (explicit user wildcard).regex:pat— regexp match against the raw command string. No chaining guard (explicit user pattern).
allow_tools entries for "bash" / "bash:execute" are intentionally
ignored by the run gate — bash is governed solely by allow_bash, so an
operator can't accidentally authorise arbitrary shell commands by listing
the tool name. To bypass the gate for bash wholesale, use the global
permissions.allowed_tools (which is checked before the gate); otherwise
leave bash out of allowed_tools and use run.allow_bash.
The same options are available as CLI flags on rush run, which merge
(union) with the config block. --restrict-run forces restrict on even
when the config has it off:
rush run --restrict-run \
--allow-bash 'git diff' \
--allow-bash 'glob:ls *' \
--allow-tool view \
--allow-tool edit:write \
"fix the failing tests"If you'd like to prevent Rush from using certain built-in tools entirely, you
can disable them via the options.disabled_tools list. Disabled tools are
completely hidden from the agent.
{
"$schema": "https://charm.land/crush.json",
"options": {
"disabled_tools": ["bash", "sourcegraph"]
}
}To disable tools from MCP servers, see the MCP config section.
If you'd like to prevent Rush from using certain skills entirely, you can
disable them via the options.disabled_skills list. Disabled skills are hidden
from the agent, including builtin skills and skills discovered from disk.
{
"$schema": "https://charm.land/crush.json",
"options": {
"disabled_skills": ["rush-config"]
}
}Rush supports the Agent Skills open standard for
extending agent capabilities with reusable skill packages. Skills are folders
containing a SKILL.md file with instructions that Rush can discover and
activate on demand.
The global paths we looks for skills are:
$RUSH_SKILLS_DIR$XDG_CONFIG_HOME/agents/skillsor~/.config/agents/skills/$XDG_CONFIG_HOME/rush/skillsor~/.config/rush/skills/~/.agents/skills/~/.claude/skills/- On Windows, we also look at
%LOCALAPPDATA%\agents\skills\or%USERPROFILE%\AppData\Local\agents\skills\%LOCALAPPDATA%\rush\skills\or%USERPROFILE%\AppData\Local\rush\skills\
- Additional paths configured via
options.skills_paths
On top of that, we also load skills in your project from the following relative paths:
.agents/skills.rush/skills.claude/skills.cursor/skills
{
"$schema": "https://charm.land/crush.json",
"options": {
"skills_paths": [
"~/.config/rush/skills", // Windows: "%LOCALAPPDATA%\\rush\\skills",
"./project-skills",
],
},
}You can get started with example skills from anthropics/skills:
# Unix
mkdir -p ~/.config/rush/skills
cd ~/.config/rush/skills
git clone https://github.com/anthropics/skills.git _temp
mv _temp/skills/* . && rm -rf _temp# Windows (PowerShell)
mkdir -Force "$env:LOCALAPPDATA\rush\skills"
cd "$env:LOCALAPPDATA\rush\skills"
git clone https://github.com/anthropics/skills.git _temp
mv _temp/skills/* . ; rm -r -force _tempSkills can be made invocable as commands from the commands palette (Ctrl+P). Add user-invocable: true to the skill's YAML frontmatter:
---
name: my-skill
description: A skill that can be invoked as a command.
user-invocable: true
---User-invocable skills appear in the commands palette with a user: or project: prefix:
- Skills from global directories show as
user:skill-name - Skills from project directories show as
project:skill-name
When invoked, the skill's instructions are loaded into the conversation context.
To prevent the model from auto-triggering a skill (while still allowing user invocation), add disable-model-invocation: true:
---
name: my-skill
description: Only invocable by users, not the model.
user-invocable: true
disable-model-invocation: true
---Skills with disable-model-invocation won't appear in the model's available skills list but can still be invoked manually by users.
Rush sends desktop notifications when a tool call requires permission and when the agent finishes its turn. They're only sent when the terminal window isn't focused and your terminal supports reporting the focus state.
{
"$schema": "https://charm.land/crush.json",
"options": {
"disable_notifications": false, // default
},
}To disable desktop notifications, set disable_notifications to true in your
configuration. On macOS, notifications currently lack icons due to platform
limitations.
When you initialize a project, Rush analyzes your codebase and creates
a context file that helps it work more effectively in future sessions.
By default, this file is named AGENTS.md, but you can customize the
name and location with the initialize_as option:
{
"$schema": "https://charm.land/crush.json",
"options": {
"initialize_as": "AGENTS.md"
}
}This is useful if you prefer a different naming convention or want to
place the file in a specific directory (e.g., RUSH.md or
docs/LLMs.md). Rush will fill the file with project-specific context
like build commands, code patterns, and conventions it discovered during
initialization.
By default, Rush adds attribution information to Git commits and pull requests
it creates. You can customize this behavior with the attribution option:
{
"$schema": "https://charm.land/crush.json",
"options": {
"attribution": {
"trailer_style": "co-authored-by",
"generated_with": true
}
}
}trailer_style: Controls the attribution trailer added to commit messages (default:assisted-by)assisted-by: AddsAssisted-by: Rush:[ModelID]as specified in the conventionco-authored-by: AddsCo-Authored-By: Rush <rush@charm.land>none: No attribution trailer
generated_with: When true (default), adds💘 Generated with Rushline to commit messages and PR descriptions
Rush supports custom provider configurations for both OpenAI-compatible and Anthropic-compatible APIs.
Note
Note that we support two "types" for OpenAI. Make sure to choose the right one to ensure the best experience!
openaishould be used when proxying or routing requests through OpenAI.openai-compatshould be used when using non-OpenAI providers that have OpenAI-compatible APIs.
Here’s an example configuration for Deepseek, which uses an OpenAI-compatible
API. Don't forget to set DEEPSEEK_API_KEY in your environment.
{
"$schema": "https://charm.land/crush.json",
"providers": {
"deepseek": {
"type": "openai-compat",
"base_url": "https://api.deepseek.com/v1",
"api_key": "$DEEPSEEK_API_KEY",
"models": [
{
"id": "deepseek-chat",
"name": "Deepseek V3",
"cost_per_1m_in": 0.27,
"cost_per_1m_out": 1.1,
"cost_per_1m_in_cached": 0.07,
"cost_per_1m_out_cached": 1.1,
"context_window": 64000,
"default_max_tokens": 5000
}
]
}
}
}Custom Anthropic-compatible providers follow this format:
{
"$schema": "https://charm.land/crush.json",
"providers": {
"custom-anthropic": {
"type": "anthropic",
"base_url": "https://api.anthropic.com/v1",
"api_key": "$ANTHROPIC_API_KEY",
"extra_headers": {
"anthropic-version": "2023-06-01"
},
"models": [
{
"id": "claude-sonnet-4-20250514",
"name": "Claude Sonnet 4",
"cost_per_1m_in": 3,
"cost_per_1m_out": 15,
"cost_per_1m_in_cached": 3.75,
"cost_per_1m_out_cached": 0.3,
"context_window": 200000,
"default_max_tokens": 50000,
"can_reason": true,
"supports_attachments": true
}
]
}
}
}Rush currently supports running Anthropic models through Bedrock, with caching disabled.
- A Bedrock provider will appear once you have AWS configured, i.e.
aws configure - Rush also expects the
AWS_REGIONorAWS_DEFAULT_REGIONto be set - To use a specific AWS profile set
AWS_PROFILEin your environment, i.e.AWS_PROFILE=myprofile rush - Alternatively to
aws configure, you can also just setAWS_BEARER_TOKEN_BEDROCK
Vertex AI will appear in the list of available providers when VERTEXAI_PROJECT and VERTEXAI_LOCATION are set. You will also need to be authenticated:
gcloud auth application-default loginTo add specific models to the configuration, configure as such:
{
"$schema": "https://charm.land/crush.json",
"providers": {
"vertexai": {
"models": [
{
"id": "claude-sonnet-4@20250514",
"name": "VertexAI Sonnet 4",
"cost_per_1m_in": 3,
"cost_per_1m_out": 15,
"cost_per_1m_in_cached": 3.75,
"cost_per_1m_out_cached": 0.3,
"context_window": 200000,
"default_max_tokens": 50000,
"can_reason": true,
"supports_attachments": true
}
]
}
}
}Local models can also be configured via OpenAI-compatible API. Here are two common examples:
{
"providers": {
"ollama": {
"name": "Ollama",
"base_url": "http://localhost:11434/v1/",
"type": "openai-compat",
"models": [
{
"name": "Qwen 3 30B",
"id": "qwen3:30b",
"context_window": 256000,
"default_max_tokens": 20000
}
]
}
}
}{
"providers": {
"lmstudio": {
"name": "LM Studio",
"base_url": "http://localhost:1234/v1/",
"type": "openai-compat",
"models": [
{
"name": "Qwen 3 30B",
"id": "qwen/qwen3-30b-a3b-2507",
"context_window": 256000,
"default_max_tokens": 20000
}
]
}
}
}Sometimes you need to look at logs. Luckily, Rush logs all sorts of
stuff. Logs are stored in ./.rush/logs/rush.log relative to the project.
The CLI also contains some helper commands to make perusing recent logs easier:
# Print the last 1000 lines
rush logs
# Print the last 500 lines
rush logs --tail 500
# Follow logs in real time
rush logs --followWant more logging? Run rush with the --debug flag, or enable it in the
config:
{
"$schema": "https://charm.land/crush.json",
"options": {
"debug": true,
"debug_lsp": true
}
}By default, Rush automatically checks for the latest and greatest list of providers and models from Catwalk, the open source Rush provider database. This means that when new providers and models are available, or when model metadata changes, Rush automatically updates your local configuration.
For those with restricted internet access, or those who prefer to work in air-gapped environments, this might not be want you want, and this feature can be disabled.
To disable automatic provider updates, set disable_provider_auto_update into
your rush.json config:
{
"$schema": "https://charm.land/crush.json",
"options": {
"disable_provider_auto_update": true
}
}Or set the RUSH_DISABLE_PROVIDER_AUTO_UPDATE environment variable:
export RUSH_DISABLE_PROVIDER_AUTO_UPDATE=1Rush provides a suite of commands to inspect and manage LLM providers:
# List all configured providers across global and workspace scopes
rush providers list
# Filter by id, name, or type (case-insensitive substring match)
rush providers list --grep zai
# Emit JSON for further processing
rush providers list --json | jq '.[] | select(.type=="openai")'Output shows ID, name, type, status (enabled/disabled), model count, and (masked) API key.
# Show full details for a provider
rush providers show openai
# Emit JSON
rush providers show openai --json# Enable a disabled provider (re-enables it and refreshes models)
rush providers enable zai
# Disable a provider (keeps credentials, sets disabled flag)
rush providers disable openai# Add a catwalk-known provider (uses default base URL from catwalk)
rush providers add zai --name "Z.AI" --type openai-compat --api-key $ZAI_API_KEY
# Add with a custom base URL
rush providers add local-llm --name "Local LLM" --type openai-compat \
--base-url http://localhost:8000/v1 --api-key none
# Add but don't enable
rush providers add myProvider --name "My Provider" --type openai \
--api-key $KEY --no-enable# Remove a provider with confirmation
rush providers remove openai
# Remove without prompting (required in non-interactive mode)
rush providers remove openai --yes# Refresh models for a single provider
rush providers update zai
# Refresh models for all enabled providers
rush providers update --allShows a diff of added/removed models. Warns if any currently-preferred model is orphaned.
# Equivalent to `providers list --grep pattern`
rush providers grep openai-compatManually updating providers is possible with the rush update-providers
command:
# Update providers remotely from Catwalk.
rush update-providers
# Update providers from a custom Catwalk base URL.
rush update-providers https://example.com/
# Update providers from a local file.
rush update-providers /path/to/local-providers.json
# Reset providers to the embedded version, embedded at rush at build time.
rush update-providers embedded
# For more info:
rush update-providers --helpRush records pseudonymous usage metrics (tied to a device-specific hash), which maintainers rely on to inform development and support priorities. The metrics include solely usage metadata; prompts and responses are NEVER collected.
Details on exactly what’s collected are in the source code (here and here).
You can opt out of metrics collection at any time by setting the environment variable by setting the following in your environment:
export RUSH_DISABLE_METRICS=1Or by setting the following in your config:
{
"options": {
"disable_metrics": true
}
}Rush also respects the DO_NOT_TRACK convention
which can be enabled via export DO_NOT_TRACK=1.
Installing an extra tool might be needed on Unix-like environments.
| Environment | Tool |
|---|---|
| Windows | Native support |
| macOS | Native support |
| Linux/BSD + Wayland | wl-copy and wl-paste |
| Linux/BSD + X11 | xclip or xsel |
Open an issue or pull request on this fork's repository.
Questions or issues specific to this fork: use GitHub Issues on this repository.
This fork is an independent project maintained by PHPCraftdream, living under the same FSL-1.1-MIT license as upstream, with no affiliation to Charm Industries beyond the shared origin codebase (see the top of this document for the link to upstream).
Charm热爱开源 • Charm loves open source
{ "$schema": "https://charm.land/crush.json", "options": { "global_context_paths": [ "~/path/to/custom/context/file.md", "/full/path/to/folder/of/files/" // recursively load all .md files in folder ] } }