Skip to main content

Standalone terminal agent for OpenRouter with tool actions and context management.

Project description

openrouter-agent-cli

Standalone terminal agent for OpenRouter models with:

  • tool actions (run_bash)
  • interactive permission gating (allow / deny / ask)
  • session persistence
  • context visibility and compaction

Install

cd openrouter-agent-cli
python3 -m venv .venv
source .venv/bin/activate
pip install -e .

Run

export OPENROUTER_API_KEY=sk-or-...
openrouter-agent

Or without installation:

export OPENROUTER_API_KEY=sk-or-...
python -m openrouter_agent_cli.cli

Non-interactive prompt

--prompt (short -p) lets another process run the CLI with a single user message, emit only the assistant reply to stdout, and exit immediately. Operation logs, tool call summaries, and permission notices are written to stderr, and tool calls are automatically denied unless you disable tools with --no-tools.

Example:

openrouter-agent --prompt "Explain tail recursion" --no-tools

Useful flags

openrouter-agent \
  --model arcee-ai/trinity-large-preview:free \
  --session-id my-session \
  --workdir ~/Projects \
  --max-turns 24 \
  --max-history-messages 60 \
  --command-timeout 30

Disable tools:

openrouter-agent --no-tools

Slash commands

  • /help
  • /exit
  • /model [id]
  • /usage
  • /context [n]
  • /compact
  • /clear
  • /tools
  • /tools on|off
  • /allow <tool|*>
  • /deny <tool|*>
  • /unallow <tool|*>
  • /undeny <tool|*>
  • /cwd [path]

Context management

  • history is saved in ~/.openrouter-agent-cli/sessions/<session_id>.json
  • /usage shows rough token estimate
  • /compact forces summarization
  • automatic compaction triggers when non-system message count exceeds --max-history-messages

Security notes

  • run_bash executes shell commands on your machine in --workdir.
  • Model outputs (tool calls) are reflected literally in run_bash, so treat every allowed tool call as untrusted input and keep the allow/deny policy enforced unless you deliberately want to run everything.
  • default policy is ask for every tool call
  • use /deny * for a fully no-tools session
  • default model is free-tier (arcee-ai/trinity-large-preview:free); override with --model or OPENROUTER_MODEL

Tool schema seen by the model

When tools are enabled, each OpenRouter request includes this tool definition:

[
  {
    "type": "function",
    "function": {
      "name": "run_bash",
      "description": "Run a shell command in the current working directory and return stdout/stderr.",
      "parameters": {
        "type": "object",
        "properties": {
          "command": {
            "type": "string",
            "description": "Shell command to execute."
          },
          "timeout_seconds": {
            "type": "integer",
            "description": "Execution timeout in seconds (1-600).",
            "default": 30
          }
        },
        "required": ["command"]
      }
    }
  }
]

Request body shape sent to OpenRouter (simplified):

{
  "model": "arcee-ai/trinity-large-preview:free",
  "messages": [...],
  "temperature": 0,
  "max_tokens": 4096,
  "tools": [...],
  "tool_choice": "auto"
}

If tools are disabled (--no-tools or /tools off), the request sets:

{
  "tool_choice": "none"
}

How run_bash is invoked

Execution flow per user turn:

  1. Model returns tool_calls in assistant message.
  2. CLI decodes function.arguments JSON into a dict.
  3. Permission policy is applied:
    • deny list blocks immediately.
    • allow list runs immediately.
    • otherwise prompt user (y/n/a/d).
  4. For run_bash, CLI executes:
    • asyncio.create_subprocess_shell(command, cwd=<workdir>, stdout=PIPE, stderr=PIPE)
    • waits with asyncio.wait_for(..., timeout_seconds)
    • kills process on timeout
  5. CLI formats stdout/stderr/exit code to text and appends a tool result message:
    • role: tool
    • tool_call_id: model-provided id
    • content: command output (capped to 8000 chars before being sent back to model)

Example tool call from model:

{
  "id": "call_123",
  "type": "function",
  "function": {
    "name": "run_bash",
    "arguments": "{\"command\":\"ls -la\",\"timeout_seconds\":30}"
  }
}

Example tool result message added by CLI:

{
  "role": "tool",
  "tool_call_id": "call_123",
  "content": "total 64\n-rw-r--r-- ..."
}

Note: despite the name run_bash, execution uses create_subprocess_shell (system shell), not an explicit bash binary unless the command itself invokes bash.

Prompt A/B testing

This repo includes a small harness for comparing system prompts:

  • script: scripts/ab_test_system_prompts.py
  • prompt variants:
    • prompts/system_prompt_control.md
    • prompts/system_prompt_agentic_v1.md
  • sample tasks: ab_tests/tasks_sample.txt

Run prompt-only comparison (no tools):

export OPENROUTER_API_KEY=sk-or-...
python scripts/ab_test_system_prompts.py \
  --tool-mode none \
  --model arcee-ai/trinity-large-preview:free

Run with tool execution enabled (use cautiously):

export OPENROUTER_API_KEY=sk-or-...
python scripts/ab_test_system_prompts.py \
  --tool-mode execute \
  --workdir "$(pwd)" \
  --model arcee-ai/trinity-large-preview:free

Artifacts are written to ab_tests/results/<timestamp>/:

  • results.json full transcripts and metadata
  • summary.csv flat comparison table
  • summary.md quick markdown summary

Run a harder repeated suite (2 prompts x 6 tasks x 3 repeats):

export OPENROUTER_API_KEY=sk-or-...
python scripts/ab_test_system_prompts.py \
  --tool-mode execute \
  --tasks-file ab_tests/tasks_hard_suite_v1.txt \
  --repeats 3 \
  --max-turns 3 \
  --max-tokens 1000 \
  --request-timeout 40 \
  --command-timeout 20 \
  --workdir "$(pwd)" \
  --model arcee-ai/trinity-large-preview:free \
  --output-dir ab_tests/results/hard_suite_v1_r3

Evaluate quality and groundedness from a run:

export OPENROUTER_API_KEY=sk-or-...
python scripts/evaluate_ab_results.py \
  --results ab_tests/results/hard_suite_v1_r3/results.json \
  --judge-model arcee-ai/trinity-large-preview:free \
  --output-dir ab_tests/results/hard_suite_v1_r3/eval

Evaluator artifacts:

  • evaluation.json per-case raw evaluation details
  • evaluation.csv tabular scores
  • leaderboard.md aggregated per-prompt ranking

Findings and release docs

  • benchmark findings: docs/AB_FINDINGS_2026-02-21.md
  • public release checklist: docs/PUBLIC_RELEASE_CHECKLIST.md
  • security policy: SECURITY.md
  • env template: .env.example

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openrouter_agent_cli-0.1.3.tar.gz (14.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openrouter_agent_cli-0.1.3-py3-none-any.whl (12.7 kB view details)

Uploaded Python 3

File details

Details for the file openrouter_agent_cli-0.1.3.tar.gz.

File metadata

  • Download URL: openrouter_agent_cli-0.1.3.tar.gz
  • Upload date:
  • Size: 14.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for openrouter_agent_cli-0.1.3.tar.gz
Algorithm Hash digest
SHA256 0aae8d5ed538ad6a417162f8b51774eba6afc76e5fcc39138823709ea3dfc80f
MD5 cde62b735ae1847d97f9ff9d1b6bc0f8
BLAKE2b-256 c607a9f564f62c9c2c7504303910dd3c7bc6f0c7d6a336e791f53547fbfdc4dc

See more details on using hashes here.

File details

Details for the file openrouter_agent_cli-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: openrouter_agent_cli-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 12.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for openrouter_agent_cli-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 ed86874cab51be387ec75aa83173de6c00b1217c28b0633df456ca00a8f8720d
MD5 1a979830029f5a6bc3acbd6b1f741b31
BLAKE2b-256 6ea44f599de25da0c683139ffee32ded6995d3548718c1155b3a133adbce7b9a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page