This is a Python-based command-line AI coding assistant. It uses system prompts to constrain the model to play the role of Project Pilot (a senior project engineer), turning vague user intent into a clear execution blueprint. It supports streaming output, interactive conversation, live in-terminal Markdown rendering, multi-provider switching, session recovery, and sub-agent domain delegation.
# Clone the repository
git clone git@gitee.com:mian-dev/rp--your-programming-co-pilot.git
cd rp--your-programming-co-pilot
# Create and activate a virtual environment
python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux/macOS
# source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# (Optional) Install as an executable command
pip install -e .
# Configure the API key
cp .env.example .env
# Edit .env and fill in non-provider settings (logging, etc.)
# Provider configuration uses JSON: run rp, enter /connect to pick a preset and enter your API key
# (see "Multi-provider and Models" below)Once installed, use the rp command (equivalent to python -m src.main).
# Single question
python -m src.main -m "Help me design a user login module"
# Enter interactive mode (type exit/quit/q to quit)
python -m src.main
# Specify a different prompt file
python -m src.main -p SYSTEM_PROMPT.md -l general
# Start in a specific working mode (plan / build / auto)
python -m src.main -M plan -m "Help me design a user login module"
# List available prompt files
python -m src.main --list-prompts| Mode | Description |
|---|---|
plan |
Planning only, no file modification (defensively disables the shell / write / edit tools) |
build |
Implement the requirements directly |
auto |
Automatically plan and implement (default) |
- In interactive mode, enter
/modeto view/switch, or pressShift+Tabto cycle; - On the command line, use
-M/--mode <mode>to specify the startup mode.
Project Pilot has 5 built-in sub-agents, automatically delegated domain-specific tasks via the delegate tool:
| Sub-Agent | Responsibility |
|---|---|
librarian |
Knowledge retrieval and material organization |
frontend_builder |
Frontend code implementation |
backend_builder |
Backend code implementation |
ui_ux_designer |
UI/UX design |
reviewer |
Code review and quality assurance |
Each sub-agent has its own prompt (src/data/agents/, with frontmatter declaring the role description and tool allowlist) and an independent LLM invocation loop. Execution is displayed live in the terminal, with mouse-click collapsible panels. Sub-agents neither ask the user questions nor delegate again.
When input starts with /, a command suggestion box appears automatically: use ↑/↓ or Tab to switch candidates, Enter to confirm, and Esc to close. You can also type the full command and press Enter to run it.
| Command | Description |
|---|---|
/help |
Show all available commands |
/variants |
View/switch thinking intensity (low / medium / high / max, passed to the API as reasoning_effort) |
/models |
List the current provider's available models; /models <name> switches |
/connect |
List configured providers; /connect <name> switches |
/mode |
View/switch working mode (plan / build / auto) |
/compact |
Compact the conversation context (keeps the last 20 messages; /compact <n> to specify) |
/usage |
View token usage and context window occupancy |
/init |
Generate AGENTS.md in the workspace root (/init -f overwrites an existing file) |
/session |
List saved sessions; /session <id> resumes the specified session and continues the conversation |
/clear |
Clear conversation history |
/exit / /quit |
Quit |
Conversations are automatically saved to .rp/sessions/ (already added to .gitignore); on next launch, use /session to restore context.
The input area has a bottom status bar showing the current mode and model on the right. When the model creates a todo list via create_todo_list, it appears in the bottom bar too, separated from the input box by a horizontal rule:
────────────────────────────────────────────────────────────
1. [ ] 分析需求
2. [~] 设计接口
3. [x] 编写测试
⏸ auto mode on · /help 查看快捷键 deepseek-v4-flash · deepseek
Status markers: [ ] pending, [~] in progress, [x] completed. The todo list is session-scoped and shared with sub-agents; use todos_update to advance items as the task progresses. The picker (/connect, /checkpoints) and command display (/help, /models, etc.) take precedence over the todo list while they are open.
When a session starts, rp automatically initializes a git repository in the workspace root (ROOT_DIR) if it is not already one, and creates a commit after each completed round of conversation so every round's changes are snapshotted.
- On first initialization, a safe
.gitignoreis written (only when none exists) to keep secrets and runtime artifacts — such as.env,.rp/,log/— out of version control, followed by an initial baseline commit. - After each round (including interrupted or errored ones), all workspace changes are staged and committed with a message like
rp: 第 N 轮对话 - <summary>. Empty commits are never created. - Commits only happen when something actually changed; if git is unavailable or a command fails, it is logged and silently skipped — the conversation is never affected.
- Set
RP_AUTO_GIT=0in.envto disable this feature.
Every commit rp creates (initial baseline, per-round, task branches, merges) is recorded with its full hash into .rp/checkpoints.json:
/checkpointsopens a visual checkpoint picker (or lists them in non-terminal mode);/checkpoints <hash>or/rollback <hash>targets a specific commit directly.- After selecting a checkpoint, rp asks for confirmation, then executes
git reset --hard <hash>to roll the workspace back to that state. Confirm withy, cancel with any other key.
Each task delegated to a sub-agent (via the delegate tool) runs on its own branch:
- rp stashes any uncommitted changes and creates a branch
task/<agent>-<timestamp>from the current HEAD. - The sub-agent executes on that branch; its work is committed there.
- When it finishes, rp shows the change statistics and asks you to review: input
yto merge the branch back to the main branch (--no-ff, then the branch is deleted), ornto discard the branch's changes. Any changes stashed before the delegation are restored afterwards.
Provider configuration is stored in JSON files rather than environment variables:
- Preset templates:
src/data/providers/preset/<name>.json, containing onlytype/api_url/models/default_model(no API key), distributed with the project. - Using a preset: run
rp, then enter/connect. The fixed bottom area shows the list of available providers; use↑ ↓to switch andEnterto confirm, then you are prompted to enter the API key. The program automatically generatessrc/data/providers/<name>.json(preset metadata +api_key) and switches to it. - Current selection: the provider/model selected via
/connectand/modelsis persisted to.rp/config.jsonand restored automatically on next launch.
type selects the transport backend:
type |
Backend | Notes |
|---|---|---|
openai |
OpenAI SDK → chat.completions |
Default for OpenAI-compatible providers (DeepSeek, GLM, Kimi, Qwen, MiniMax, etc.) |
responses |
OpenAI SDK → responses |
OpenAI Responses API; system becomes instructions, tool results become function_call_output items |
anthropic |
anthropic SDK → messages.stream |
Anthropic Claude; system is a separate parameter, max_tokens is required (default 8192) |
Missing or invalid type causes the provider file to be rejected (and Config.validate() reports it explicitly).
Example of manually creating src/data/providers/<name>.json:
{
"name": "deepseek",
"type": "openai",
"api_url": "https://api.deepseek.com/v1",
"models": ["deepseek-v4-flash", "deepseek-v4-pro"],
"default_model": "deepseek-v4-flash",
"api_key": "sk-xxx"
}For Anthropic:
{
"name": "anthropic",
"type": "anthropic",
"api_url": "https://api.anthropic.com",
"models": ["claude-opus-4-1", "claude-sonnet-4-5", "claude-haiku-4-5"],
"default_model": "claude-sonnet-4-5",
"api_key": "sk-ant-xxx"
}Other settings are still configured in .env:
| Variable | Description | Default |
|---|---|---|
RP_VARIANT |
Thinking intensity (low / medium / high / max) |
medium |
RP_MODE |
Working mode (plan / build / auto) |
auto |
SEARCH_BACKEND |
Web search backend (bing / ddg / auto; auto falls back to bing when ddg fails) |
bing |
LOG_LEVEL |
Log level | INFO |
LOG_DIR |
Log directory | log/ |
LOG_ENCODING |
Log file encoding | utf-8 |
SESSION_DIR |
Session storage directory | .rp/sessions/ |
RP_AUTO_GIT |
Auto-initialize a git repo at session start and commit after each round (1 / 0) |
1 |
RICH_COLOR_SYSTEM |
Terminal color system (auto / standard / 256 / truecolor / windows) |
auto |
RICH_THEME |
rich theme | none |
TAB_SIZE |
Tab width | 8 |
The project uses a three-layer architecture: core (infrastructure) → api (capabilities) → ui (presentation).
src/
├── main.py # Entry point: assembles the three layers and starts
├── config.py # Configuration and validation (JSON provider presets / mode / variant)
├── core/ # Infrastructure layer
│ ├── logger.py # Logging (file + console)
│ ├── event_bus.py # Event bus (inter-thread communication)
│ ├── prompt.py # Prompt loading
│ └── session.py # Session persistence (JSON save / load / restore)
├── api/ # Capability layer
│ ├── client.py # OpenAI client (background thread + tool invocation loop)
│ ├── agents.py # Sub-agent definition loading and independent run loop
│ └── tools.py # Tool definitions (schemas) and executors
├── ui/ # Presentation layer
│ ├── app.py # rich TUI (Live rendering + event consumption + session recovery)
│ ├── input.py # Input box (slash command completion / mode badge / key bindings)
│ ├── cancel_watcher.py# Background listener for double-ESC, triggers a CANCEL event to interrupt the current answer
│ ├── formatters.py # Compresses tool call arguments into readable name(args) display text
│ ├── mascot.py # Startup mascot
│ └── subagent_panel.py# Sub-agent execution panel (live display / collapsible)
├── data/general/ # System prompts
├── data/agents/ # Sub-agent prompts (frontmatter declares roles and tool permissions)
├── data/providers/preset/ # Provider preset templates (JSON, no API key)
└── data/providers/ # Provider configs generated after using presets (contains API key)
scripts/
├── build_exe.py # One-click Nuitka compilation of a single-file executable
└── launcher.py # Packaging entry point (forwards to src.main:main)
tests/ # pytest tests (core / api / ui / agents / session, etc.)
.github/workflows/ # GitHub Actions: CI / Format / Release / Snapshot / Auto Merge
pyproject.toml # Project metadata, ruff and pytest config, `rp` command entry point
cost_map.json # Reference pricing for mainstream models (CNY / 1M tokens)
| Layer | Responsibility | Dependencies |
|---|---|---|
core |
Logging, inter-thread communication (event bus), prompt loading, session persistence | Standard library + config only |
api |
OpenAI requests, streaming output, tool definition and execution, sub-agent running | core |
ui |
rich TUI: rendering messages, input interaction, sub-agent panels, consuming events | core + api |
Built-in tools: ask (ask the user a question, via the event bus), read (read a workspace file), write (write a workspace file, content previewed in a code box), edit (precise replacement in an existing file, changes shown as a git-style diff), grep (regular-expression search), shell (execute commands), web_search (web search, Bing by default, switchable via SEARCH_BACKEND), web_fetch (fetch web page content), delegate (delegate domain-specific tasks to a sub-agent), create_todo_list / todos_read / todos_update (track a multi-step task's progress). Tool call arguments are displayed in a readable form in the terminal instead of raw JSON. Read/write tools are anchored to the workspace root by default to prevent out-of-bounds access.
Communication model: the UI main thread handles rendering and input; API requests run on a background thread and publish token / tool call / sub-agent event / error events via the EventBus, which the UI consumes to update the interface in real time. The ask tool uses the bus to ask the UI a question and wait for the user's answer, forming a complete closed loop.
pip install -r requirements-dev.txt
ruff check . # Lint
ruff format . # Format
pytest # Run tests (CI covers Python 3.10 ~ 3.13)Use Nuitka to compile the project into a single-file executable (not cross-platform; build separately on each target system):
# Full build (output in dist/: Windows -> rp.exe, Linux/macOS -> rp)
python scripts/build_exe.py
# Preview the Nuitka command that would run
python scripts/build_exe.py --dry-runGitHub Actions includes Release / Snapshot workflows:
Release: triggered by pushing av*tag. It runs tests first, then builds with Nuitka on Windows / Linux / macOS, packs the three platform binaries together withsrc/dataintorp-<tag>.zip, generates aSHA256SUMSchecksum file, and finally creates a GitHub Release. Tags with-alpha/-betaonly publish a source snapshot pre-release and do not build binaries.Snapshot: automatically (or manually) creates asnapshot-YYMMDDsource pre-release every Monday.
Issues and pull requests are welcome. See CONTRIBUTING.md.
This project is licensed under the MIT License.
