Skip to main content

Add your description here

Project description

crow-cli

crow-cli is an Agent Client Protocol (ACP) native agent implementation that serves as the core execution engine for the Crow agent framework.

Installation

# Ensure you're in the correct project directory
git clone https://github.com/odellus/crow-cli.git
uv venv
# Install dependencies using uv
uv --project /path/to/crow/crow-cli sync

Or run directly

uvx crow-cli --help

if you like having it available globally, you can install it using pip

uv tool install crow-cli --python 3.14

Quick Start

uvx crow-cli init

Run Programmatically

import asyncio
from crow_acp.agent import AcpAgent, agent_run

async def main():
    await agent_run()

if __name__ == "__main__":
    asyncio.run(main())

Configuration

Features

1. ACP Protocol Native

  • Implements all ACP agent endpoints (initialize, new_session, load_session, prompt, cancel)
  • Full streaming support for token-by-token responses
  • Session persistence to SQLite database

2. MCP Tool Integration

  • Automatically discovers tools from connected MCP servers
  • Supports both MCP and ACP-native tool execution
  • Tool execution with progress updates

3. Streaming ReAct Loop

  • Real-time streaming of thinking tokens (for reasoning models)
  • Content token streaming
  • Tool call progress updates (pending → in_progress → completed/failed)

4. Cancellation Support

  • Immediate task cancellation via async events
  • Persists partial state on cancellation
  • Safe resource cleanup on cancel

5. ACP Terminal Support

When the ACP client supports terminals (clientCapabilities.terminal: true):

  • Uses ACP-native terminals instead of MCP terminal calls
  • Better terminal display in the client
  • Live output streaming
  • Proper terminal lifecycle management

Built-in Tools

The agent automatically discovers and registers tools from connected MCP servers:

  • crow-mcp_terminal - Execute shell commands in the workspace
  • crow-mcp_write - Write content to files
  • crow-mcp_read - Read files with line numbers
  • crow-mcp_edit - Fuzzy string replacement in files
  • crow-mcp_web_search - Search the web using a search engine
  • crow-mcp_web_fetch - Fetch URL content as markdown

Session Management

Creating a New Session

# When connecting via ACP, a new session is created automatically
# with the working directory and MCP servers provided by the client

Loading an Existing Session

# Sessions persist to the database and can be loaded by ID
# The load_session endpoint handles this automatically

Session Data Storage

Sessions are stored in SQLite with three main tables:

  • Prompt - System prompt templates (Jinja2)
  • Session - Session metadata (config, tools, model, cwd)
  • Event - Conversation turns (messages, tool calls, results)

Usage with ACP Clients

crow-cli is designed to work with any ACP-compatible client:

// In Zed
{
  "agent_servers": {
      "crow-cli": {
        "type": "custom",
        "command": "uvx",
        "args": ["crow-cli", "acp"],
      },
...
}

ACP Client Capabilities

The agent automatically detects and uses client capabilities:

Capability When Enabled Behavior
terminal Client supports ACP terminals Uses ACP-native terminals
fs.write_text_file Client supports file writing Uses ACP file write
fs.read_text_file Client supports file reading Uses ACP file read

Project Structure

crow-cli/
├── src/crow_cli/
│   ├── __init__.py
│   ├── agent/
│   │   ├── __init__.py
│   │   ├── compact.py        # Conversation compaction
│   │   ├── configure.py      # Agent configuration
│   │   ├── context.py        # Context providers (directory tree, file fetching)
│   │   ├── db.py             # SQLAlchemy database models
│   │   ├── llm.py            # LLM client configuration
│   │   ├── logger.py         # Logging utilities
│   │   ├── main.py           # Agent entry point
│   │   ├── mcp_client.py     # MCP client creation + tool extraction
│   │   ├── prompt.py         # Prompt building
│   │   ├── react.py          # ReAct loop implementation
│   │   ├── session.py        # Session management + persistence
│   │   ├── skills.py         # Skills handling
│   │   ├── tools.py          # Tool definitions
│   │   └── prompts/          # Jinja2 system prompt templates
│   │       ├── system_prompt.jinja2
│   │       ├── self_documentation.jinja2
│   │       ├── skill_knowledge_info.jinja2
│   │       └── system_message_suffix.jinja2
│   ├── cli/
│   │   ├── __init__.py
│   │   ├── init_cmd.py       # `crow init` command
│   │   └── main.py           # CLI entry point
│   └── client/
│       ├── __init__.py
│       └── main.py           # Programmatic client
├── config/
│   ├── compose.yaml          # Docker compose for services
│   ├── config.yaml           # Default configuration
│   ├── .env.example          # Environment variables template
│   ├── searxng/
│   │   └── settings.yml      # SearXNG search config
│   └── prompts/              # Override prompts (user customization)
│       ├── system_prompt.jinja2
│       ├── self_documentation.jinja2
│       ├── skill_knowledge_info.jinja2
│       └── system_message_suffix.jinja2
├── tests/
│   ├── __init__.py
│   ├── conftest.py
│   ├── test_agent_init.py
│   └── unit/
│       └── test_session.py
├── examples/
│   ├── mc_escher_loop.py
│   └── quick_test.py
├── pyproject.toml
├── README.md
├── TODO.md
└── run_tests.sh

Development

Running Tests

# From the project root
uv run --project /home/thomas/src/nid pytest crow-cli/tests/

Building

# Build the package
uv build --project /home/thomas/src/nid/crow-cli

# Install locally
pip install --force-reinstall ./crow-cli/dist/*.whl

ReAct Loop Logic

┌─────────────────────────────────────────────────────────────────────────┐
│                           REACT LOOP (Turn N)                           │
└─────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
                    ┌───────────────────────────────┐
                    │   cancel_event.is_set()?      │
                    └───────────────────────────────┘
                          │                  │
                         YES                 NO
                          │                  │
                          ▼                  ▼
                    ┌──────────┐    ┌────────────────────────┐
                    │  RETURN  │    │  send_request(LLM)     │
                    └──────────┘    └────────────────────────┘
                                            │
                                            ▼
                              ┌──────────────────────────────┐
                              │  process_response() stream   │
                              │  ┌────────────────────────┐  │
                              │  │ Yield: thinking/token  │  │
                              │  │ Yield: content/token   │  │
                              │  │ Yield: tool_args/token │  │
                              │  └────────────────────────┘  │
                              │           │                  │
                              │           ▼                  │
                              │    Collect in              │
                              │    state_accumulator       │
                              └──────────────────────────────┘
                                            │
                                            ▼
                              ┌──────────────────────────────┐
                              │  Cancelled during stream?    │
                              └──────────────────────────────┘
                          ┌────────┴────────┐
                         YES                NO
                          │                  │
                          ▼                  ▼
                    ┌──────────────┐  ┌────────────────────────┐
                    │ Add partial  │  │ Yield: final           │
                    │ response     │  │ (thinking, content,    │
                    │ + results    │  │  tool_call_inputs)     │
                    │ Raise        │  └────────────────────────┘
                    │ CancelledErr │                │
                    └──────────────┘                ▼
                          │                  ┌────────────────────────┐
                          │                  │ Log pre-tool usage     │
                          ▼                  └────────────────────────┘
                    ┌──────────┐                         │
                    │  RETURN  │                 ┌────────────────────────┐
                    └──────────┘                 │ tokens > threshold?    │
                          │                      └────────────────────────┘
┌──────────────────────────────┐                           │              │
│  Turn Loop: for turn in      │                          YES             NO
│    range(max_turns):         │                           │              │
└──────────────────────────────┘                           ▼              ▼
                          │                      ┌──────────────┐  ┌──────────┐
                          ▼                      │  COMPACT     │  │  SKIP  │
              ┌──────────────────────────┐      │  session()   │  │ COMPACT│
              │  process_response DONE   │      └──────────────┘  └──────────┘
              │  Extract: thinking       │           │                │
              │         content          │           └────────┬───────┘
              │         tool_call_inputs │                    │
              │         usage            │                    ▼
              └──────────────────────────┘         ┌────────────────────────┐
                          │                         │  Has tools to call?  │
                          ▼                         └────────────────────────┘
              ┌──────────────────────────┐                           │
              │  Cancelled after stream? │                      ┌────┴────┐
              └──────────────────────────┘                     YES      NO
                          │                                       │          │
                         YES                                      ▼          ▼
                          │                              ┌──────────────┐  ┌──────────────┐
                          ▼                              │  EXECUTE     │  │  NO TOOLS    │
                    ┌──────────────┐                     │  TOOLS       │  │  (final msg) │
                    │ Add partial  │                     └──────────────┘  └──────────────┘
                    │ response     │                            │              │
                    │ + tool       │                            │              │
                    │ results      │                            ▼              ▼
                    │ RETURN       │                    ┌──────────────┐  ┌──────────────┐
                    └──────────────┘                    │ Add tools    │  │ Add assistant│
                                                        │ to results   │  │ response     │
                                                        └──────────────┘  └──────────────┘
                                                        │              │              │
                                                        ▼              ▼              ▼
                              ┌──────────────────────────────────────────────────┐
                              │  Cancelled after tool execution?               │
                              └──────────────────────────────────────────────────┘
                                          │
                                 ┌────────┴────────┐
                                YES                NO
                                 │                  │
                                 ▼                  ▼
                        ┌──────────────┐  ┌────────────────────────┐
                        │ Add partial  │  │ Add assistant response │
                        │ response +   │  │ + tool results         │
                        │ tool results │  └────────────────────────┘
                        │ RETURN       │              │
                        └──────────────┘              │
                                                    │
                                                    ▼
                                        ┌────────────────────────┐
                                        │  Turn N complete       │
                                        │  ───────────────────── │
                                        │  Loop back to turn N+1 │
                                        │  (or max_turns reached)│
                                        └────────────────────────┘

Troubleshooting

Connection Issues

If the agent can't connect to MCP servers:

  1. Verify MCP server config in ~/.crow/mcp.json
  2. Check that the MCP server path is correct
  3. Ensure the server is executable

Session Loading Failures

If sessions fail to load:

  1. Check database exists: ls ~/.crow/crow.db
  2. Verify database permissions: chmod 644 ~/.crow/crow.db
  3. Check session ID exists in database

Terminal Not Working

If ACP terminals aren't working:

  1. Check client capabilities: clientCapabilities.terminal should be true
  2. Verify MCP terminal fallback is configured
  3. Check terminal command is valid in the workspace directory

License

Apache-2.0

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

crow_cli-0.1.3.tar.gz (131.4 kB view details)

Uploaded Source

Built Distribution

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

crow_cli-0.1.3-py3-none-any.whl (53.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: crow_cli-0.1.3.tar.gz
  • Upload date:
  • Size: 131.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for crow_cli-0.1.3.tar.gz
Algorithm Hash digest
SHA256 1356eb1fa3266d960400169350482574998ddc3ad12783f91a13af7a60f97a00
MD5 9ee7532917565e2c2c629248e6a555af
BLAKE2b-256 93c6d99b4a67fe8c2c65694ca1ac9f58953c51b056770b865b11370c447ec9a9

See more details on using hashes here.

File details

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

File metadata

  • Download URL: crow_cli-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 53.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for crow_cli-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 3d8cf92655dd3babb0cccc657e8873f54368a9da12e3fcfc3684e144b04862d8
MD5 4c5ed8e7fce045eb42c08fedbdd78b86
BLAKE2b-256 b4990b906b1482f4623921f7e6cfc2c0c371d342df631a747d334e2386e082c3

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