Terminal-native AI coding assistant (Python) with ReAct loop, memory system, and extensible tool/skill/hook architecture
Project description
minicode
Terminal-native AI coding assistant, implemented in Python.
当前状态:已完成 v0(工具层)、v1(模型层)、v2(ReAct 循环 + 记忆系统 + 权限 + Hook + Goal + Chat Bridge + 斜杠命令补全 + 自定义命令 + 代码简化)。 下一版(v3)会接 Google provider、plugin system、远程 skill/agent 拉取。
Quick start
# 1. install
pip install -e .
# 2. 跑起来(首次会自动建 .minicode/)
minicode
# 一次性命令
minicode --init # 初始化项目.minicode
minicode --version
minicode --paths
minicode --print-tools # 列工具
minicode --check-config # 校验配置
Layout
minicode/
├── pyproject.toml
├── README.md
├── .minicode/ # per-project config dir
│ ├── skills/ # skill files
│ │ ├── code-review/SKILL.md
│ │ ├── refactor/SKILL.md
│ │ └── test-gen/SKILL.md
│ ├── agents/ # subagent definitions
│ │ ├── code-reviewer.md
│ │ └── explorer.md
│ ├── commands/ # custom slash commands
│ │ ├── review.md
│ │ └── fix.md
│ ├── hooks/ # python/shell hooks
│ ├── mcp.json # MCP server config (stdio / http)
│ └── config.yaml # LLM provider 配置
├── minicode/ # source
│ ├── __init__.py
│ ├── __main__.py
│ ├── _ansi.py # ANSI 颜色常量 + TTY 探测(公共模块)
│ ├── paths.py # .minicode 路径解析
│ ├── config.py # config.yaml 加载
│ ├── command.py # custom command loader
│ ├── registry.py # 全局 registry (tools/models/skills/agents/hooks)
│ ├── tool/ # 工具层
│ │ ├── base.py # Tool 抽象基类 + ToolContext + ToolResult
│ │ ├── registry.py # ToolRegistry
│ │ ├── skill.py # SkillLoader
│ │ ├── mcp.py # McpClient + McpToolAdapter
│ │ └── builtin/ # 8 个内置工具
│ │ ├── bash.py
│ │ ├── edit.py
│ │ ├── glob_tool.py
│ │ ├── grep_tool.py
│ │ ├── read.py
│ │ ├── write.py
│ │ ├── skill.py
│ │ └── subagent.py # delegate_to_subagent
│ ├── model/ # 模型层
│ │ ├── base.py # Model 抽象基类 + ModelResponse/Event
│ │ ├── message.py # Message / Part / ToolSchema
│ │ ├── openai_compat.py # OpenAI Chat Completions
│ │ ├── anthropic.py # Anthropic Messages API
│ │ ├── demo.py # 假 provider(echo)
│ │ └── registry.py # ModelRegistry
│ ├── agent/ # ReAct 循环 + subagent
│ │ ├── loader.py # SubagentLoader
│ │ └── runtime.py # run_agent / run_subagent + 预算管理
│ ├── memory/ # 记忆系统
│ │ ├── budget.py # ContextBudget + token 估算
│ │ ├── truncation.py # 分级裁剪(soft/hard trim + 滑动窗口)
│ │ ├── compact.py # /compact 手动压缩
│ │ ├── context.py # AGENTS.md + rules → system prompt
│ │ ├── context_view.py # /context 可视化
│ │ ├── history.py # 会话历史持久化
│ │ ├── loaders.py # AGENTS.md / rules 加载
│ │ └── status.py # 输入框前 ctx 状态栏
│ ├── permission/ # 工具调用权限
│ │ ├── service.py # PermissionService
│ │ └── types.py # PermissionRequest/Result
│ ├── hooks/ # Hook 系统
│ │ ├── dispatcher.py # HookDispatcher
│ │ ├── types.py # EventName / Action / HookResponse
│ │ ├── python.py # PythonHook
│ │ └── shell.py # ShellHook
│ ├── goal/ # 停止条件 + judge
│ │ ├── service.py # GoalService
│ │ ├── types.py # Goal / Verdict
│ │ └── judge.py # judge 独立 LLM 调用
│ ├── display/ # 结构化渲染
│ │ └── formatter.py # thinking / tool-call / code-change
│ ├── chatbridge/ # 多端聊天桥接
│ │ ├── adapter.py # ChatAdapter
│ │ ├── adapters/ # stdio / webhook
│ │ └── manager.py # ChatBridgeManager
│ └── cli/
│ ├── app.py # REPL + 命令处理
│ └── input.py # 斜杠命令补全
└── tests/ # 单测 + 端到端冒烟
├── test_base.py
├── test_skill_loader.py
├── test_registry.py
├── test_config.py
├── test_model_registry.py
├── test_openai_compat.py
├── test_anthropic.py
├── test_demo.py
├── test_agent_runtime.py
├── test_memory_budget.py
├── test_memory_truncation.py
├── test_memory_compact.py
├── test_permission.py
├── test_hooks.py
├── test_goal.py
├── test_command.py
├── demo_mcp_server.py
└── test_e2e_mcp.py
config.yaml 格式
.minicode/config.yaml:
# LLM provider:当前支持 openai / anthropic / demo
provider: openai
# API Key。推荐用环境变量:${OPENAI_API_KEY}
api_key: ${OPENAI_API_KEY}
# API base URL
base_url: https://api.openai.com/v1
# 模型名称
model: gpt-4o
# 上下文窗口大小(可选)。支持 128K / 1M / 128000 等写法
context_window: 128K
# 透传给 provider 的额外参数(可选)
extra:
temperature: 0.7
max_tokens: 8K
provider 可选值:
openai— 任何实现 OpenAI Chat Completions 的服务(OpenAI/DeepSeek/Moonshot/ollama/vllm/...)anthropic— Anthropic Messages APIdemo— 进程内回显,无需网络
extra 字段透传给 provider 实现(OpenAI:temperature/top_p/presence_penalty;Anthropic:max_tokens 必填/temperature/top_k)。
CLI 命令
| 命令 | 作用 |
|---|---|
/tools |
列出所有工具(builtin + skill + mcp) |
/skills |
列出 skill |
/agents |
列出 subagent |
/hooks |
列出已加载的 hook |
/mcp |
列出 MCP 服务和状态 |
/model |
显示当前 model 详情 |
/model test |
流式发 "ping" 测试当前 model 的连通性 |
/memory |
显示 AGENTS.md + rules |
/context |
显示上下文窗口占用(进度条 + 分项明细) |
/history |
列出历史会话 |
/compact |
手动压缩历史对话(调 LLM 摘要) |
/goal |
设置/查看停止条件 |
/goal judge |
调 judge 评估是否完成 |
/chat |
chat bridge 管理 |
/permission |
权限管理(always allow/deny/clear) |
/display |
渲染 demo(thinking / tool-call / code-change) |
/paths |
打印路径解析结果 |
/call <id> [json] |
手动调用一个工具 |
/reload |
重新 build registry |
/commands |
列出自定义命令 |
/help |
打印帮助 |
/exit |
退出 |
工具协议
所有工具实现同一接口(minicode/tool/base.py):
class Tool(ABC):
kind: ToolKind = ToolKind.BUILTIN
@property
def id(self) -> str: ...
@property
def description(self) -> str: ...
@property
def parameters(self) -> type[BaseModel]: ...
async def execute(self, args: Parameters, ctx: ToolContext) -> ToolResult: ...
ToolContext 携带:
session_id— 当前会话cwd/project_root— 路径tool_registry— 工具注册表(工具间互相调用)permission_service— 权限检查hook_dispatcher— hook 触发bus— 事件总线model_registry— 模型切换config— 当前配置history— 对话历史context_budget— token 预算
ToolResult:
title— 短标题output— 内容(str | list[Part])metadata— dict(error / file_path / tool_name 等)
记忆系统
Token 预算(memory/budget.py)
不引入 tiktoken,用 chars / 3 粗估。ContextBudget 跟踪 system + history 的 token,按压力等级分级:
| 等级 | 阈值 | 动作 |
|---|---|---|
| 0 | < 50% | 无 |
| 1 | 50-70% | 软裁剪旧 tool result(head+tail) |
| 2 | 70-85% | 硬裁剪旧 tool result(清空内容) |
| 3 | ≥ 85% | 自动 compact(调 LLM 压缩历史) |
分级裁剪(memory/truncation.py)
- soft_trim_tool_results:旧 tool result → head+tail(保留结构,压缩体积)
- hard_trim_tool_results:旧 tool result → 清空标记(保留 tool_call 配对)
- truncate_messages:丢弃整轮旧消息(最后的兜底)
保护最近 N 轮不动(避免裁到当前上下文)。
/compact 手动压缩(memory/compact.py)
把旧消息喂给 LLM 生成摘要,替换成一条 assistant summary message。
上下文可视化(memory/context_view.py)
/context 命令展示:
┌──────────────────────────────────────────┐
│ context window 6500/8000 81.3% │
│ [████████░░] │
│ │
│ breakdown │
│ system prompt 1200 (15.0%) │
│ tools schema 800 (10.0%) │
│ history 4500 (56.3%) │
│ user text 1200 │
│ assistant 1500 │
│ tool calls 800 │
│ tool results 1000 │
│ │
│ output reserve 4000 (50.0%) │
│ remaining 1500 (18.8%) │
│ │
│ pressure: high (level 3) │
└──────────────────────────────────────────┘
状态栏(memory/status.py)
输入框前显示:minicode> [ctx 6500/8000 ████████░░] $_
颜色:绿 (< 60%) / 黄 (60-85%) / 红 (> 85%)。
历史持久化(memory/history.py)
会话退出时保存到 .minicode/history/{session_id}.json,支持 /history 列出和恢复。
权限系统(permission/)
工具调用前询问用户:
[permission] tool 'bash' wants to run
args: {"command": "ls -la"}
[1] Yes
[2] Yes, and always (allow this tool for the rest of the session)
[3] No [default: 1]
always_allow/always_deny:per-session 状态/permission管理:allow <tool>/deny <tool>/clear
Hook 系统(hooks/)
支持 Python 和 Shell 两种 hook:
# .minicode/hooks/my_hook.py
def run(event, context):
if event.event == "tool_call_before":
if event.data["tool"] == "bash":
return HookResponse.deny("no bash allowed")
return HookResponse.allow()
# .minicode/hooks/my_hook.sh
#!/bin/bash
EVENT=$(cat)
if echo "$EVENT" | jq -e '.event == "tool_call_before" and .data.tool == "bash"' > /dev/null; then
echo '{"action":"deny","reason":"no bash"}'
exit 0
fi
echo '{"action":"allow"}'
事件:session_start, session_end, user_prompt_submit, assistant_message, tool_call_before, tool_call_after, error, stop, compact
聚合规则:并行执行,任一 deny → 整体 deny,多个 modify → 串联合并。
Goal + Judge(goal/)
设置停止条件,让 judge 独立 LLM 调用评估是否完成:
> /goal tests pass
Goal set: "tests pass"
> /goal judge
[judge] evaluating...
[goal not yet] test suite has 3 failures
Verdict:ok(满足)、impossible(不可达)、error(judge 失败,fail-open)。
Subagent(agent/)
.minicode/agents/<name>.md 定义独立 LLM 上下文:
---
name: code-reviewer
description: 严格审查代码改动并给出改进建议
---
你是 code reviewer...
delegate_to_subagent 工具让父 LLM 把任务委派给 subagent,防递归(subagent 看不到此工具)。
Chat Bridge(chatbridge/)
多端聊天桥接,支持 stdio / webhook adapter:
> /chat
> /chat register webhook https://example.com/webhook
> /chat status
自定义命令(command.py)
.minicode/commands/<name>.md:
---
description: 代码审查命令
---
请审查以下代码改动,给出改进建议。
用户输入:$ARGUMENTS
运行时 $ARGUMENTS 替换为用户输入。
斜杠命令补全(cli/input.py)
TTY 环境下输入 / 时显示命令列表,继续输入实时过滤,Tab 补全到最长公共前缀。非 TTY 降级为 input()。
架构图
┌──────────────────────────────────────────────────────────────────────┐
│ CLI (cli/app.py) │
│ REPL / 命令处理 / 斜杠补全 / 状态栏 / 渲染 │
└──────────────────────────┬───────────────────────────────────────────┘
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────────┐
│ ToolRegistry│ │ModelRegistry│ │ CommandLoader │
│ (all tools) │ │ (providers) │ │ (custom cmds) │
└──────┬─────┘ └──────┬─────┘ └────────────────┘
│ │
│ │
▼ ▼
┌──────────────────────────────────────────┐
│ ReAct 循环 (agent/runtime.py) │
│ user → LLM → tool_call → execute → result │
│ ↑ │ │
│ └──────────────────────────┘ │
│ │
│ 预算管理:soft/hard trim → compact │
│ doom loop 检测 │
│ tool 输出截断(错误感知 head+tail) │
└──────────────────────────────────────────┘
│
├──────────────┬──────────────┬──────────────┐
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ builtin │ │ skill │ │ mcp │ │subagent │
│ tools │ │ tools │ │ tools │ │ (nested) │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
┌──────────────────────────────────────────────────┐
│ 记忆系统 (memory/) │
│ budget → truncation → compact → context_view │
│ history (持久化) / status (输入框前) │
└──────────────────────────────────────────────────┘
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ permission │ │ hooks │ │ goal │
│ (per-session)│ │ (python/shell)│ │ + judge │
└──────────────┘ └──────────────┘ └──────────────┘
┌──────────────────────────────────────────────────┐
│ chatbridge (多端桥接) │
│ stdio / webhook adapter → bus → model → history │
└──────────────────────────────────────────────────┘
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyminicode-0.3.0.tar.gz.
File metadata
- Download URL: pyminicode-0.3.0.tar.gz
- Upload date:
- Size: 53.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ece2ab0a350aff43be9c4ac71422e75a7a6b2b61d1dc85e68972a555836f364
|
|
| MD5 |
21a6ac64f0ea60dff9b9a8c14801e706
|
|
| BLAKE2b-256 |
18a74419662373f802a14caf0fe3613f38c8e778a22021211f33668a1a8b11c6
|
File details
Details for the file pyminicode-0.3.0-py3-none-any.whl.
File metadata
- Download URL: pyminicode-0.3.0-py3-none-any.whl
- Upload date:
- Size: 7.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e9238670cc4c3b21fd2ebd1b1c57ad488d39fe20b55e1d00354971326e87c21
|
|
| MD5 |
6cc61f4b2e7d604912a816c363166d17
|
|
| BLAKE2b-256 |
f2f3ef1e1684a69f6c760c919983ad4cf384f093febe24d66429bbeaa2874ab8
|