Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RepoPilot

A local-first coding agent harness. It points a language model at a real repository and lets it answer questions, make a described change, or work through an open-ended task across multiple turns — while keeping every write on an isolated git branch, gated behind verification, and reversible.

RepoPilot is designed around models that don't have reliable native tool-calling (small local models served through Ollama), not just frontier APIs. Its retry/verification machinery exists specifically to make that work.

What it does

RepoPilot has three separate execution engines, each suited to a different kind of task:

Engine Entry point Behavior
Chat src/agents/orchestrator.py Read-only Q&A over a repo, grounded in retrieved context, with citations. No tool use.
Code task src/agents/code_orchestrator.py + src/agents/graph_orchestrator.py A described change is planned into steps up front, then each step runs through an explore → generate → verify → self-correct pipeline. The harness drives execution, not the model.
Agent src/agents/loop_orchestrator.py A persistent, model-driven tool-calling loop: the model picks its own next action, turn after turn, until it calls finish or hits a turn limit.

Supporting infrastructure, all shared across the three engines above:

  • Multi-language repository graph (src/graph/) — tree-sitter-based call graph covering Python, JavaScript/TypeScript, Go, Java, and Rust. Deterministic, no LLM involved: definitions, imports, inheritance, and call resolution.
  • Git-based safety — every write happens on an isolated branch, never on main/master. A separate git-shadow-repo snapshot store (src/snapshot/) takes a snapshot after every turn, independent of the real repo's own history, with restore/undo and fork support.
  • Checkpoint/resume (src/agents/checkpoint.py) — a crashed or interrupted Agent run can resume from its last completed turn instead of restarting.
  • Permission model (src/tools/bash_tool.py, src/tools/permission_store.py) — shell commands are classified deny/safe/confirm; a "confirm" decision can be persisted as an exact-match "always allow" rule, never a wildcard pattern.
  • Roles — the Agent loop can run as build (full access), plan (research only, no writes), or explore (read-only), enforced at the point each action is dispatched.
  • Hooks (src/tools/hooks.py) — user-authored shell commands can run before/after an action, or at the end of a task. Configured only by a human editing a JSON file directly; the model itself can never write its own hooks.
  • MCP support — external tools (browser automation, documentation search, a persistent terminal session, etc.) are reachable through the Model Context Protocol, configured in data/mcp_servers.json.

Interfaces

  • CLIpython -m src.cli <subcommand>
  • TUIpython -m src.tui.app (Textual-based terminal UI)
  • Web dashboardpython -m src.web.app (Flask, http://127.0.0.1:5000)

All three call the same underlying engines; none of them have their own logic.

Installation

python -m venv venv
venv\Scripts\activate        # or: source venv/bin/activate
pip install -r requirements.txt

By default RepoPilot talks to a local Ollama instance — see OLLAMA_SETUP.md. No API key is required for that path.

To use a hosted provider instead, uncomment the matching package in requirements.txt (openai, anthropic, or google-genai) and set the corresponding environment variables below.

Configuration

Copy .env.example if present, or create .env in the repo root:

# Provider selection — one of: ollama (default), openai, anthropic, gemini, gemini-local
REPOPILOT_LLM_PROVIDER=ollama

# Required only for REPOPILOT_LLM_PROVIDER=openai (also covers OpenRouter and any other
# OpenAI-compatible endpoint via OPENAI_BASE_URL)
OPENAI_API_KEY=
OPENAI_BASE_URL=
OPENAI_MODEL=

# Required only for REPOPILOT_LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=

# Required only for REPOPILOT_LLM_PROVIDER=gemini
GEMINI_API_KEY=

.env is gitignored — never commit real keys.

MCP servers are configured in data/mcp_servers.json (empty list by default; opt-in). Hooks are configured per-repo in data/hooks/<repo_name>.json (absent by default).

Usage

Onboard a repo first:

python -m src.cli ingest --repo-url https://github.com/owner/name

Ask questions about it:

python -m src.cli chat --repo-name name

Run one described change through the Planner → Coder → Verification pipeline:

python -m src.cli code --repo-name name --task "add input validation to the signup form"

Run the persistent Agent loop instead, for open-ended or exploratory tasks:

python -m src.cli agent --repo-name name --task "investigate why the login test is flaky and fix it" \
    --allow-bash --confirm-writes --role build

Relevant agent flags: --max-turns (default 30), --role {build,plan,explore}, --resume (continue a crashed run of the same repo+task), --plan-mode (require one approved plan before any action dispatches), --delegate (split into isolated subtasks).

Build a new project from scratch, with no existing repo:

python -m src.cli scaffold --repo-name my-new-project --task "a FastAPI todo app with SQLite storage"

Query the repository graph directly:

python -m src.cli graph --repo-name name --callers-of some_function_id
python -m src.cli graph --repo-name name --dead-code
python -m src.cli graph --repo-name name --call-chain <source_id> <target_id>

Run python -m src.cli <subcommand> --help for the full flag list of any subcommand.

Known limitations

  • Every turn of the Agent loop parses one JSON action out of the model's free-text response, rather than using a provider's native structured tool-calling — a deliberate trade-off for compatibility with models that don't support native tool-calling at all, not an oversight.
  • Import resolution for JavaScript/TypeScript/Go/Java/Rust is a heuristic (path/name matching), not a real module resolver for each language (no go.mod/package.json/build-file parsing).
  • The Agent loop dispatches one action per turn, except for a narrow batch of read-only actions (read/grep/glob/webfetch) which can run concurrently in one turn; writes are never batched.
  • No production usage history. This has been exercised through targeted live testing during development, not by external users over time.

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages