轻量级 CLI Agent,基于 OpenAI 兼容 API,支持工具调用、MCP 协议、技能扩展和智能上下文管理。
- 🤖 多模型支持:OpenAI 兼容 API(默认 MiniMax-M2.5)
- 🔌 MCP 协议:连接外部工具服务器(Playwright、Fetch、Filesystem 等)
- 🛠️ 内置工具:Bash、文件读写、字符串替换、URL 抓取、Glob、Grep
- 🔒 安全沙箱:
bash工具默认在 Landlock 子进程沙箱中运行,遵循最小权限原则 - 📁 技能扩展:通过 SKILL.md 扩展专业能力
- 💬 流式响应:实时显示,支持思考内容分离
- 🧠 上下文管理:智能压缩(microcompaction)和自动摘要(autocompaction)
- 💾 会话持久化:基于 JSONL 的会话存储和恢复
- 🖥️ 双模式:TUI(推荐)和 CLI 模式
作为全局 CLI 工具安装(推荐):
uv tool install --python 3.12 git+https://github.com/selfanti/gem_code.git安装后可以在任意项目目录运行:
gem-code # TUI 模式,默认使用当前目录作为 WORKDIR
gem-code --cli # 交互式 CLI 模式
gem-code --cli --once "你的问题" # 一次性 CLI 提问安装后的第一次交互运行如果还没有 settings.json,命令行会引导输入 OPENAI_API_KEY、OPENAI_BASE_URL、OPENAI_MODEL 等信息,并把它们写入安装目录下的 settings.json。之后安装版始终读取这个文件,环境变量和 .env 都不会覆盖它。运行时的 workspace 使用当前启动目录,不再受全局 WORKDIR 影响。
如果需要启用 USE_TOOL_SEARCH=true,安装时再带上 extra:
uv tool install --python 3.12 "gem-code[tool-search] @ git+https://github.com/selfanti/gem_code.git"本地开发安装:
uv sync另外需要在embedding_model文件夹下下载一个嵌入模型,推荐使用Qwen3-Embedding-0.6B,USE_TOOL_SEARCH设置为false则不需要
源码开发时再使用项目根目录的 .env:
OPENAI_API_KEY=your-api-key
OPENAI_BASE_URL=https://api.minimaxi.com/v1
OPENAI_MODEL=MiniMax-M2.5
OPENAI_API_MODE=auto
WORKDIR=~/your-project # 可选,默认值为启动 gem-code 时的当前目录
SKILLS_DIR=~/your-project/.agents # 可选,默认值为 WORKDIR/.agents
MCP_CONFIG_PATH=~/your-project/mcp_config.json # 可选
MEMORY_COMPACTION_PATH=~/.gem_code/projects
GEM_CODE_SECURITY_ENABLED=true
GEM_CODE_SECURITY_BEST_EFFORT=true
GEM_CODE_SECURITY_ALLOW_NETWORK=false
GEM_CODE_SECURITY_ALLOW_CONNECT=443
USE_TOOL_SEARCH=falseTUI 模式(推荐):
gem-code
uv run python main.pyCLI 模式:
gem-code --cli
gem-code --cli --once "你的问题" # 一次性提问
uv run python main.py --cli
uv run python main.py "你的问题" # 一次性提问
uv run python main.py --cli --once "你的问题" # 发送一次后退出,适合自动化/评测本仓库已经接入 Harbor Installed Agent,入口在 evaluation/my_external_agent.py。评测时 Harbor 会把当前 gem-code 源码上传到任务环境,运行 evaluation/run_gem_code_once.py,并把 JSONL transcript 转成 Harbor ATIF trajectory。评测默认禁用 MCP,并强制使用非交互权限模式,避免 benchmark 过程中等待人工审批。
- 安装依赖:
uv sync- 配置
.env或 shell 环境:
OPENAI_API_KEY=your-api-key
OPENAI_BASE_URL=https://api.minimaxi.com/v1
OPENAI_MODEL=MiniMax-M2.5
OPENAI_API_MODE=auto-
确保 Docker 可用。SWE-bench Verified 和 Terminal-Bench 都是容器化任务,首次运行会拉取/构建镜像,耗时较长。
-
如果要让 Harbor 非交互评测真正执行
bash、write_file、StrReplaceFile、fetch_url等工具,需要在src/permissions.py中手动切换测试白名单:注释掉当前的DEFAULT_WHITELIST_NAMES = frozenset({"read_file", "Glob", "Grep"}),并取消注释下方的 Harbor benchmark override 全工具白名单。否则evaluation/run_gem_code_once.py会使用非交互权限模式,默认拒绝初始白名单之外的工具调用。
用于快速回归 gem-code 的 Harbor adapter、上下文管理、TUI/CLI 启动保护等本项目自身行为,不是正式公开 benchmark:
uv run python evaluation/run_harbor_matrix.py \
--job-name gem-code-smoke-10 \
--n-concurrent 1只跑某个本地任务:
uv run python evaluation/run_harbor_matrix.py \
--job-name gem-code-smoke-one \
--task-name config-defaults报告输出到:
evaluation/reports/<job-name>.md
evaluation/reports/<job-name>.json
原始 Harbor job、stdout/stderr、metadata 和 trajectory 输出到:
evaluation/jobs/<job-name>/
推荐使用仓库内封装好的 runner。SWE-bench 任务仓库在容器内挂载到 /testbed,runner 已经通过 --ak agent_workdir=/testbed 对齐 gem-code 的 WORKDIR。
先跑 1 个 smoke task:
uv run python evaluation/run_swebench_verified.py \
--job-name gem-code-swebench-smoke-1 \
--n-tasks 1 \
--n-concurrent 1跑指定任务:
uv run python evaluation/run_swebench_verified.py \
--job-name gem-code-swebench-sympy-19346 \
--task-name sympy__sympy-19346 \
--n-tasks 1扩大采样:
uv run python evaluation/run_swebench_verified.py \
--job-name gem-code-swebench-smoke-10 \
--n-tasks 10 \
--n-concurrent 1WSL2 + Windows Docker Desktop 环境下,Docker Hub token 获取和大镜像下载经常会在多任务并发构建时超时。run_swebench_verified.py 会在 --n-concurrent > 1 时先串行预拉取本次任务 Dockerfile 中的 FROM swebench/... 基础镜像,再启动 Harbor 并发任务;如果已经确认本机镜像缓存和代理都稳定,可以加 --skip-image-prepull 跳过这一步。脚本也会把当前 shell 中的 all_proxy / http_proxy / https_proxy 等常见代理变量补齐为大小写两套变量并传给 Harbor 和 agent。
只汇总已有 job,不重新运行:
uv run python evaluation/run_swebench_verified.py \
--job-name gem-code-swebench-smoke-10 \
--skip-runHarbor registry 中对应数据集为 swebench-verified@1.0,当前 registry 标注为 500 个任务。
当前仓库还没有单独的 run_terminal_bench.py wrapper,但可以直接复用同一个 Harbor Installed Agent。Terminal-Bench 2.0 在 Harbor registry 中的数据集名是 terminal-bench@2.0,当前 registry 标注为 89 个任务;也可以先用 terminal-bench-sample@2.0 跑 10 个 sample 任务。
先跑 1 个 Terminal-Bench task:
uv run harbor run \
--job-name gem-code-terminal-bench-smoke-1 \
--jobs-dir evaluation/jobs \
--agent-import-path evaluation.my_external_agent:GemCodeInstalledAgent \
--dataset terminal-bench@2.0 \
--n-tasks 1 \
--n-concurrent 1 \
--agent-setup-timeout-multiplier 4 \
--debug \
--model "$OPENAI_MODEL" \
--ae OPENAI_API_KEY="$OPENAI_API_KEY" \
--ae OPENAI_BASE_URL="$OPENAI_BASE_URL" \
--ae OPENAI_MODEL="$OPENAI_MODEL" \
--ae OPENAI_API_MODE="${OPENAI_API_MODE:-auto}"跑 sample 数据集:
uv run harbor run \
--job-name gem-code-terminal-bench-sample \
--jobs-dir evaluation/jobs \
--agent-import-path evaluation.my_external_agent:GemCodeInstalledAgent \
--dataset terminal-bench-sample@2.0 \
--n-tasks 10 \
--n-concurrent 1 \
--agent-setup-timeout-multiplier 4 \
--debug \
--model "$OPENAI_MODEL" \
--ae OPENAI_API_KEY="$OPENAI_API_KEY" \
--ae OPENAI_BASE_URL="$OPENAI_BASE_URL" \
--ae OPENAI_MODEL="$OPENAI_MODEL" \
--ae OPENAI_API_MODE="${OPENAI_API_MODE:-auto}"跑指定 Terminal-Bench 任务:
uv run harbor run \
--job-name gem-code-terminal-bench-one \
--jobs-dir evaluation/jobs \
--agent-import-path evaluation.my_external_agent:GemCodeInstalledAgent \
--dataset terminal-bench@2.0 \
--task-name <task-name> \
--n-tasks 1 \
--n-concurrent 1 \
--agent-setup-timeout-multiplier 4 \
--debug \
--model "$OPENAI_MODEL" \
--ae OPENAI_API_KEY="$OPENAI_API_KEY" \
--ae OPENAI_BASE_URL="$OPENAI_BASE_URL" \
--ae OPENAI_MODEL="$OPENAI_MODEL" \
--ae OPENAI_API_MODE="${OPENAI_API_MODE:-auto}"注意:Terminal-Bench 任务通常更偏通用终端操作。gem-code 当前评测 runner 会在非交互模式下自动拒绝默认白名单之外的工具调用;如果要把 bash 作为正式 benchmark 能力放开,需要为非交互评测设计更细的安全策略,而不是简单绕过权限门禁。
| 快捷键 | 功能 |
|---|---|
Enter |
换行 |
Ctrl+Enter / Send |
发送消息 |
Ctrl+C |
退出 |
Ctrl+L / Clear |
清空聊天记录 |
Ctrl+S |
切换侧边栏 |
? |
帮助 |
Escape |
聚焦输入框 |
侧边栏显示以下信息:
- MODEL: 当前使用的模型和 API
- WORKSPACE: 当前工作目录
- TOOLS: 可用的内置工具列表
- CONTEXT: 实时显示上下文使用量(绿色 <60%,黄色 60-80%,红色 >80%)
- FILES: 工作目录文件树
状态栏显示当前状态、模型名称和上下文使用百分比。
| 工具 | 描述 | 参数 |
|---|---|---|
bash |
执行 Shell 命令 | command, description |
read_file |
读取文件,支持渐进式披露 | path, start_line, end_line, description |
write_file |
写入文件 | path, content, description |
StrReplaceFile |
字符串替换 | path, edits |
fetch_url |
抓取 URL 内容 | url, description |
Glob |
文件搜索 | pattern, path |
Grep |
代码搜索 | pattern, path, glob, output_mode, -i, -n, -B, -A, -C |
bash不再直接在主 Agent 进程里执行,而是通过独立的 Landlock runner 启动受限子进程- 默认只允许访问工作目录、工作目录下的私有临时目录
.gem-code/tmp,以及必要的系统运行时路径(如/usr、/bin、/lib) - 出站网络默认开启;显式配置
GEM_CODE_SECURITY_ALLOW_NETWORK=true或在GEM_CODE_SECURITY_ALLOW_CONNECT中放行端口后,bash和fetch_url才允许联网 - 内核或环境不支持 Landlock 时,默认以
best-effort模式继续执行并在工具输出中标注安全降级;如需 fail-closed,可设置GEM_CODE_SECURITY_BEST_EFFORT=false
可选环境变量:
| 变量 | 默认值 | 说明 |
|---|---|---|
GEM_CODE_SECURITY_ENABLED |
true |
是否启用内置安全策略 |
GEM_CODE_SECURITY_BEST_EFFORT |
true |
Landlock 不可用时是否继续执行 |
GEM_CODE_SECURITY_ALLOW_NETWORK |
true |
是否完全放开网络 |
GEM_CODE_SECURITY_ALLOW_CONNECT |
空 | 允许出站连接的 TCP 端口,逗号分隔 |
GEM_CODE_SECURITY_ALLOW_BIND |
空 | 允许监听的 TCP 端口,逗号分隔 |
GEM_CODE_SECURITY_EXTRA_READ_PATHS |
空 | 追加只读路径,逗号分隔 |
GEM_CODE_SECURITY_EXTRA_WRITE_PATHS |
空 | 追加可写路径,逗号分隔 |
GEM_CODE_SECURITY_EXTRA_EXECUTE_PATHS |
空 | 追加可执行路径,逗号分隔 |
| 注意部分限制特性依赖Linux内核版本 |
Gem Code 实现了智能上下文管理系统,有效处理长对话:
Micro Compaction(微观压缩)
- 当上下文使用量超过 60% 时自动触发
- 将早期的工具输出内容转移到持久化存储
- 保留消息引用,释放上下文空间
Auto Compaction(自动摘要)
- 当上下文使用量超过 80% 时自动触发
- 使用 LLM 生成对话摘要,包含:
- 用户意图和关键决策
- 已探索的概念和修改的文件
- 遇到的错误和解决方案
- 待处理任务和当前状态
- 添加压缩边界,后续对话基于摘要继续
会话持久化
- 会话自动保存到
~/.gem_code/memory/{workspace}/{session_id}.jsonl - 支持会话恢复(Fork)和继续
- O(1) 时间复杂度读取任意历史消息
在 SKILLS_DIR 目录创建子文件夹,每个文件夹包含 SKILL.md:
.agent/skills/
├── python-best-practices/
│ └── SKILL.md
├── react-patterns/
│ └── SKILL.md
└── code-review-excellence/
└── SKILL.md
SKILL.md 格式:
---
name: Python Best Practices
description: 提供 Python 代码审查和最佳实践建议
---
## 代码风格
- 遵循 PEP 8
- 使用类型注解
...
## 常见模式
...Agent 会自动按需加载相关技能,无需手动选择。
创建 mcp_config.json:
{
"mcpServers": {
"filesystem": {
"type": "local",
"command": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"],
"enabled": true,
"timeout": 30000
},
"fetch": {
"type": "local",
"command": ["npx", "-y", "@modelcontextprotocol/server-fetch"],
"enabled": true
},
"playwright": {
"type": "local",
"command": ["npx", "-y", "@playwright/mcp@latest"],
"environment": {
"PLAYWRIGHT_CHROMIUM": "true"
},
"enabled": true,
"timeout": 60000
}
}
}常用 MCP 服务器:
| 服务器 | 命令 | 说明 |
|---|---|---|
| filesystem | npx -y @modelcontextprotocol/server-filesystem <path> |
文件系统访问 |
| fetch | npx -y @modelcontextprotocol/server-fetch |
HTTP 请求 |
| playwright | npx -y @playwright/mcp@latest |
浏览器自动化(需 Chrome) |
Playwright MCP 需要 Google Chrome:
# 方法 1: 系统安装
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt-get update
sudo apt-get install -y google-chrome-stable
# 方法 2: Playwright 安装
npx playwright install chromegem-code/
├── src/
│ ├── cli.py # CLI 模式
│ ├── tui.py # TUI 模式(Textual)
│ ├── session.py # 对话会话管理
│ ├── session_manager.py # 会话生命周期管理
│ ├── tool.py # 工具实现
│ ├── skill.py # 技能系统
│ ├── mcp_client.py # MCP 客户端
│ ├── mcp.py # MCP 数据模型
│ ├── context_manager.py # 上下文压缩管理
│ ├── memory.py # 会话持久化(JsonlRandomAccess)
│ ├── models.py # 数据模型(Message, ToolCall 等)
│ ├── config.py # 配置管理
│ ├── decorate.py # 终端输出装饰
│ └── agent.py # Agent 模式(实验性)
├── main.py # 程序入口
├── mcp_config.json # MCP 配置
├── pyproject.toml # 项目依赖
└── README.md # 本文档
管理对话历史、流式响应、工具调用循环:
await session.chat(
user_input,
on_reasoning=lambda chunk: ..., # 思考内容
on_content=lambda chunk: ..., # 正式输出
on_turn_end=lambda content, reasoning, has_more: ..., # 每轮结束
on_tool_start=lambda name, args: ..., # 工具开始
on_tool_result=lambda name, result: ... # 工具结果
)管理会话生命周期:
manager = SessionManager(config)
await manager.init()
# Fork 新会话(保留历史但创建新 ID)
manager.fork()
# 恢复已有会话
manager.resume(session_id)智能上下文管理:
- 阈值: 最大上下文 200K tokens
- 60% 触发 microcompaction
- 80% 触发 autocompaction
- 压缩边界: 在 JSONL 中标记压缩点
- 重新激活: 从摘要恢复完整上下文(rehydration,开发中)
基于 JSONL 的持久化存储:
# Memory_Unit 数据模型
class Memory_Unit(BaseModel):
type: "message" | "compact_boundary" | "summary"
role: "system" | "user" | "assistant" | "tool"
id: UUID
timestamp: datetime
content: Optional[str]
tool_calls: Optional[list[ToolCall]]
# JsonlRandomAccess - O(1) 读取
accessor = JsonlRandomAccess(filepath)
accessor.add_line(memory_unit.model_dump_json())
message = accessor.get_line(index)| 变量 | 必需 | 默认值 | 说明 |
|---|---|---|---|
OPENAI_API_KEY |
✅ | - | API 密钥 |
OPENAI_BASE_URL |
✅ | - | API 基础 URL |
OPENAI_MODEL |
❌ | MiniMax-M2.5 | 模型名称 |
OPENAI_API_MODE |
❌ | auto | auto / chat_completions / responses |
WORKDIR |
❌ | 当前目录 | 工作目录 |
SKILLS_DIR |
❌ | WORKDIR/.agents |
技能目录 |
MCP_CONFIG_PATH |
❌ | - | MCP 配置文件路径 |
MEMORY_COMPACTION_PATH |
❌ | ~/.gem_code/projects |
会话压缩与持久化目录 |
- Python: 3.12+
- 包管理器: uv
- API: OpenAI SDK (>=2.21.0)
- MCP: mcp (>=1.26.0)
- TUI: Textual (>=0.85.0)
- 终端: Rich (>=14.3.3)
- 数据验证: Pydantic (>=2.0)
本项目参考 Claude Code 和 Kimi CLI 设计: https://github.com/MoonshotAI/kimi-cli
- TUI 界面(基于 Textual)
- MCP (Model Context Protocol) 支持
- 分离显示大模型思考内容和输出内容
- 按需加载 Skill
- 上下文管理
- Microcompaction(工具输出转移)
- Autocompaction(自动摘要、自动读取最近的文件并重启TODO)
- 会话持久化(Session Memory)
- 使用 Pydantic 优化数据模型
- tool search支持
- OpenAI API Responses 适配(通过
OPENAI_API_MODE=responses|auto启用) - MCP Streamable HTTP 传输支持(兼容 legacy SSE)
- 基础 Harbor Installed Agent 适配骨架
- 为大模型增加预测然后思考的设置
- 多 API 支持(DeepSeek、Kimi、OpenAI 等)
- Agent Teams(多 Agent 协作)(多agent的有效性有待商榷,暂时搁置)
- 领导 Agent 任务分配
- 基于文件系统的 Agent 间通信
- 参考文献: https://decodeclaude.com/teams-and-swarms/
- 基于 Harbor 的完整 Coding Agent 测试矩阵
- 已补充 Harbor Installed Agent 适配、ATIF 轨迹落盘、结构化运行元数据采集,以及面向
swebench-verified@1.0的 runner:evaluation/run_swebench_verified.py - 本地 synthetic smoke matrix 保留在
evaluation/harbor_matrix/,用于快速回归 adapter、context 管理和 TUI/CLI 行为 - 使用方式见上文 “Benchmark / Harbor 评测”
- 参考: https://harborframework.com/docs/agents
- 已补充 Harbor Installed Agent 适配、ATIF 轨迹落盘、结构化运行元数据采集,以及面向
- 增加用户交互(human in the loop),针对开发者,主动披露下一步行动的目的和具体操作。支持agent运行时的interupt。便于开发者及时阻止错误方向
- Plan Mode
- TODO List
- 增加审查者角色的LLM
- subagent
- 基于slime框架实现Agentic RL
- 自进化能力
.env 文件提交到版本控制。
- Agent Skills 协议: https://agentskills.io/home
- MCP 协议: https://modelcontextprotocol.io/docs/getting-started/intro
- OpenCode: https://github.com/anomalyco/opencode
- Mem0 技术报告: https://arxiv.org/abs/2504.19413
- MiniMax API 文档: https://platform.minimaxi.com/docs/api-reference/text-chat
- Claude Code 博客: https://claude.com/blog
- Claude Code 上下文压缩: https://decodeclaude.com/compaction-deep-dive/
- Claude Code 会话记忆: https://decodeclaude.com/session-memory/
- Kimi API参考https://platform.moonshot.cn/docs/guide/kimi-k2-5-quickstart#%E5%8F%82%E6%95%B0%E5%8F%98%E5%8A%A8%E8%AF%B4%E6%98%8E
- Minimax API参考https://platform.minimaxi.com/docs/api-reference/text-openai-api
- Deepseek API参考https://api-docs.deepseek.com/zh-cn/
对于coding agent甚至大部分agent来说,我认为应该具有以下几点功能:
- 可观测性/便于观测性:大模型的执行过程可能需要人的介入,为了方便人类使用者,agent重点输出的应该是方便供使用者检查的 内容以及对应格式。
- 分层文件系统:对于LLM需要的任何较大的信息源,都应该进行知识的分层,顶层到底层由概括到细致。这将大大有利于AI的信息提取。目前的agent方案要么使用不包含结构信息的RAG,要么使用Glob和Grep工具针对关键词进行查找。这两种方案效率都是较低的。
- 面向Agent的工作环境:LLM的参数越来越多,能力越来越强,但是想要更好的发挥出它的潜力,一个精心设计的、面向LLM而不是面向人的的工作环境至关重要。其中工具设计、上下文工程和针对agent设计的记忆功能都是重点.
- Agent对人类的安全性:AI技术的一切发展都以人类为中心,为了防止Agent的能力范围超出人类掌握,需要有严格的安全措施,这在目前是较少谈论的。
MIT License