No description
Find a file
guochao e21c767f18 perf(statusline): build ctx once per run instead of once per script
build_context_table runs `git rev-parse` + `git status --porcelain`,
which was called on every iteration of the parts loop. In huge repos
like Chromium each call costs ~3s, so the 8-script loop took ~24s when
cwd was heavy. The static fields (stdin, env, cwd, git) don't vary
across scripts, so hoist the call to before the loop. Cuts git
subprocess invocations from 2*N to 2, total wall time from ~86ms to
~20ms in this repo, and from ~24s to ~3s in Chromium.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 07:55:29 +08:00
docs feat(models): add lua filters and update crush sync 2026-06-07 09:50:03 +00:00
scripts feat(models): add lua filters and update crush sync 2026-06-07 09:50:03 +00:00
src perf(statusline): build ctx once per run instead of once per script 2026-06-13 07:55:29 +08:00
.envrc chore: switch direnv to flake and ignore .direnv/ 2026-05-05 19:54:17 +08:00
.gitignore chore: switch direnv to flake and ignore .direnv/ 2026-05-05 19:54:17 +08:00
AGENTS.md feat(models): add lua filters and update crush sync 2026-06-07 09:50:03 +00:00
build.rs feat(models): add lua filters and update crush sync 2026-06-07 09:50:03 +00:00
Cargo.lock feat: add statusline subcommand with Lua part-based architecture 2026-05-24 00:34:22 +08:00
Cargo.toml feat: add statusline subcommand with Lua part-based architecture 2026-05-24 00:34:22 +08:00
CLAUDE.md docs: add CLAUDE.md with uv run guidance 2026-05-05 19:52:37 +08:00
config.demo.yaml feat: support isolated homes for codex and hermes 2026-05-09 14:58:52 +08:00
deepseek-pricing.json feat(models): add lua filters and update crush sync 2026-06-07 09:50:03 +00:00
default.nix feat: inject git build metadata and add version command 2026-05-03 18:11:58 +08:00
flake.lock feat: add claude, codex, and hermes launch adapters with arg forwarding 2026-04-29 23:16:15 +08:00
flake.nix feat: inject git build metadata and add version command 2026-05-03 18:11:58 +08:00
nvchecker.toml feat(models): add lua filters and update crush sync 2026-06-07 09:50:03 +00:00
README.md feat(models): add lua filters and update crush sync 2026-06-07 09:50:03 +00:00
shell.nix feat: add claude, codex, and hermes launch adapters with arg forwarding 2026-04-29 23:16:15 +08:00

agent-run

agent-run is a small launcher for coding agents.

It keeps provider settings in one place, then adapts them for each target agent instead of asking you to manually rewrite per-agent config files every time.

Current focus:

  • claude
  • codex
  • hermes
  • crush

Current protocol support:

  • anthropic
  • openai-responses
  • openai-chat-completions

Why

Different coding agents expect different configuration shapes:

  • some read environment variables
  • some want a config file or profile
  • some mix both

agent-run gives you one provider config and adapts it to the target agent at launch time.

The provider config stays generic; each agent adapter is responsible for mapping that generic config into the shape the downstream tool expects.

What It Does

  • Centralizes provider definitions in one config file
  • Resolves secrets from either key or key_command
  • Optionally loads model lists from provider APIs and caches normalized results on disk
  • Validates protocol compatibility before launch
  • Negotiates the final protocol for agents that support more than one wire API
  • Generates temporary runtime config where needed
  • Forwards extra args to the underlying agent command

Supported Agents

Claude Code

  • protocol: anthropic
  • launch mode: environment variables
  • supports both ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY
  • ensures onboarding is marked complete before launch

Codex

  • protocol: openai-responses
  • launch mode: temporary CODEX_HOME and generated config.toml
  • does not read or merge any existing Codex home/config

Hermes Agent

  • protocol: openai-chat-completions
  • launch mode: temporary HERMES_HOME and generated config.yaml
  • injects API key via environment variable
  • does not read or merge any existing Hermes home/config

Crush

  • protocol: prefers openai-chat-completions, falls back to anthropic
  • launch mode: synchronizes managed providers into global crush.json
  • injects provider keys with per-process environment variables
  • writes Crush options to rely on synced providers and disable provider auto-update

Configuration

Default config path:

~/.config/agent-run/config.yaml

Minimal example:

providers:
  deepseek:
    protocols:
      - openai-chat-completions
      - anthropic
    base_urls:
      openai: https://api.deepseek.com
      anthropic: https://api.deepseek.com/anthropic
    key_command:
      - printenv
      - DEEPSEEK_API_KEY
    default_model: deepseek-v4-pro
    models:
      - deepseek-v4-pro
    model_api_filters: []

  kimi-code:
    protocols:
      - openai-chat-completions
      - anthropic
    base_urls:
      openai: https://api.kimi.com/coding/v1
      anthropic: https://api.kimi.com/coding
    key_command:
      - printenv
      - KIMI_API_KEY
    anthropic_use_api_key: true
    default_model: kimi-for-coding
    models:
      - kimi-for-coding

isolated_homes:
  codex:
    sandbox: {}
  hermes:
    sandbox: {}

See config.demo.yaml for a fuller example.

Protocol Negotiation

protocols declares what a provider can speak.

  • claude requires anthropic
  • codex requires openai-responses
  • hermes requires openai-chat-completions
  • crush prefers openai-chat-completions and falls back to anthropic

For single-protocol agents, launch fails unless the provider supports that protocol or --force protocol is used. For crush, agent-run picks the first supported protocol from that preference order.

Usage

Open or initialize your config:

agent-run config
agent-run config --bootstrap-config

agent-run config only opens an existing config. Use --bootstrap-config to write the embedded sample config first when the file does not exist.

Launch Claude:

agent-run launch deepseek claude
agent-run launch kimi-code claude

Launch Codex:

agent-run launch ollama codex
agent-run launch openrouter --model openai/gpt-5.3-codex codex
agent-run launch sandbox codex

Launch Hermes:

agent-run launch deepseek hermes
agent-run launch ollama hermes
agent-run launch sandbox hermes

isolated_homes notes:

  • isolated_homes.codex.<name> and isolated_homes.hermes.<name> allow launching that agent with an isolated runtime home even when no provider exists.
  • Entries are empty objects today. They do not accept key, base_url, model, or custom paths.
  • When both a provider and an isolated home entry share the same name, agent-run combines them: isolated runtime home plus provider-derived runtime config.
  • Runtime homes persist across launches. agent-run reuses the existing directory and only updates the generated config file.

Launch Crush:

agent-run launch deepseek crush
agent-run launch kimi-code crush run "explain this repository"

Generate shell completion:

agent-run completion bash
agent-run completion zsh

When installed from Nix, bash and zsh completion files are installed automatically.

Manual shell setup is only needed when running the binary outside the Nix package:

source <(agent-run completion bash)
source <(agent-run completion zsh)

Model catalog:

agent-run models list openrouter
agent-run models list --refresh openrouter
agent-run models list --all

Forward extra args to the underlying agent:

agent-run launch deepseek claude resume
agent-run launch ollama codex resume --last
agent-run launch deepseek hermes -- chat -q "hello"

Both forms are supported:

  • agent-run launch provider agent arg1 arg2
  • agent-run launch provider agent -- arg1 arg2

Completion notes:

  • Bash and Zsh are supported.
  • Provider completion is loaded from local config.yaml.
  • --model completion refreshes remote model cache by default when model_api_filters is enabled.
  • Set AGENT_RUN_DISABLE_MODEL_COMPLETION_REFRESH=1 to make completion use local models plus existing cache only.
  • Default log level is WARN. Completion runs stay silent unless you explicitly set RUST_LOG.
  • Trailing agent_args are forwarded but are not completed.

Model API filter notes:

  • Omit model_api_filters to use the default catch-all rule.
  • Set model_api_filters: [] or model_api_filters: null to disable remote model loading and cache interaction for that provider.
  • Filters are applied to normalized remote models before cache write.

Secret Handling

Each provider can use either:

  • key
  • key_command

key_command is preferred when you want to fetch secrets from an external source such as a password manager, shell environment, or local secret helper.

Extra Environment Variables

Each provider may declare an extra_env map that is injected into the launched agent process. The map is applied last and may override the env vars agent-run sets by default (e.g. ANTHROPIC_API_KEY, CODEX_HOME, OPENAI_API_KEY).

Values support inline template expansion:

  • ${env:NAME} — reads env var NAME from the launcher process; errors if unset.
  • ${context:FIELD} — reads a resolved launch field. Supported fields: provider, protocol, model, key, agent, base_url.

Example:

providers:
  openrouter:
    # ...other fields...
    extra_env:
      OPENROUTER_API_KEY: "${context:key}"
      HTTPS_PROXY: "${env:CORP_PROXY}"
      AGENT_RUN_TRACE: "${context:agent}:${context:model}"

Runtime Strategy

agent-run avoids modifying long-lived agent config for single-provider agents. Crush is the intentional multi-provider exception: its global config is the place where configured providers live, while secrets are still injected at launch time.

  • claude uses temporary env plus a one-time onboarding state fix
  • codex uses generated runtime config under cache
  • hermes uses generated runtime config under cache
  • crush synchronizes all compatible providers.* entries into ~/.config/crush/crush.json and marks them as agent-run managed

Crush note:

  • Existing non-agent-run Crush providers are preserved. If a provider name conflicts, rename one side or remove the unmanaged Crush entry.
  • Managed Crush providers store API key placeholders such as ${DEEPSEEK_API_KEY:?...}; agent-run sets those env vars only for the launched process.
  • agent-run removes stale managed Crush providers only when they are no longer present in agent-run config. A provider that temporarily fails to resolve is skipped for this launch but not deleted from crush.json.
  • agent-run does not pass a launch model to Crush. Crush does not currently support a general launch-time model override, so model selection is left to Crush defaults, crush run --model, or the UI.
  • agent-run writes options.disable_default_providers = true and options.disable_provider_auto_update = true in crush.json.
  • Managed Crush providers include the known model id and name so Crush has a usable local model list even when the provider API is unreachable; Crush can still discover models from the provider API at runtime.
  • Crush may still read the current project directory and initialize project-local files such as AGENTS.md

Development

This repository uses a minimal Rust + Nix setup.

Useful commands:

cargo check
cargo clippy -- -D warnings
cargo fmt

Docs