Skip to content

agent-box 架构

本文档描述 已实现 行为。设计意图 / 规划见 docs/ROADMAP.mddocs/specs/

设计原则

  1. 轻依赖(CLI) — CLI 只依赖 json5(JSONC 解析)、tomli-w(TOML 写)、cmd2(上下文栈 REPL)。业务层 stdlib only(sqlite3jsonyaml 手写解析);bwrap 是系统工具。
  2. 声明式注册表,前端/CLI 零 agent 知识core/agent_types.json 定义每种 agent 的 identity(名字/颜色/logo)、runtime(config_dir / binary / data_dir / launch)、resources(provider / mcp / skills / hooks / prompt / permissions / plugins / rules / memories / instructions)。GUI 与 CLI 都不硬编码 agent 名、路径、默认值——全部 从注册表读。
  3. 模板是 package datatemplates/<agent_type>/ 在 wheel 里分发; core/library.py 解析。presets/ 提供初始 overlay。
  4. Profile = 模板拷贝 + 追加式覆盖create 拷贝模板到 ~/.agent-box/profiles/<name>/,运行时 bwrap 把 profile 目录 bind-mount 覆盖真实配置目录做隔离。Provider 等资源以追加式文件 (_providers.json)+ 写真实配置两种方式落盘(strategy dispatch)。
  5. 项目配置对 Agent 透明、对 Profile 隔离 — launch 的 cwd 由后端 解析(launch --cwd);首次启动自动建立项目 .agent-box,运行时把 Profile 私有的项目配置投影到 .claude / .codex 等原生入口。Agent 仍按自身规则发现配置,不需要理解 Agent Box。
  6. 和 ACS 的关系 — ACS(cc-switch fork)作为配置仓库: providers / mcp servers / skills / prompts 都存在 ACS 的 cc-switch.db。agent-box 通过 adapters/acs.py 只读库,再经 resources/*/apply.py 把选中项写入 profile 的真实配置。

分层架构

src/agent_box/
  config.py               — 路径 / 配置工具
                            agent_box_home(~/.agent-box)、profiles_dir、
                            default_projects_dir、acs_binary、home_dir、
                            provider_endpoints_file、profile_skills_dir
  launch.py               — 有序 mount/argv 计划 + bwrap/session 生命周期
  project_space.py        — 项目配置层发现、Profile backing 与挂载计划
  edit.py                 — $EDITOR 启动器(configure 命令使用)
  core/                   — 基础层
    agent_types.json          — agent 类型注册表(identity/runtime/resources/project)
    provider_endpoints.json   — provider base_url → /models endpoint 映射
    library.py                — 注册表读取 + template / preset 解析
    db.py                     — SQLite(profiles / sessions)
    io.py                     — 原子配置读写(JSON / JSONC / TOML / YAML)
  adapters/               — 外部数据适配
    acs.py                    — ACS 库读取(providers / mcp / skills / prompts,只读)
    models.py                 — fetch_models(provider_endpoints 驱动)
  resources/              — 资源操作(apply / CRUD / 查询)
    profile.py                — profile 生命周期(DB 行 + meta.yaml + presets)
    providers/apply.py        — provider apply(strategy dispatch:
                                json_merge / multi_file / yaml_custom / jsonc_provider)
    prompts/apply.py          — prompt apply(写入 prompt 文件 + prompt_ref)
    mcp/apply.py              — MCP server apply(写 agent 配置的 enabled_* 列)
    skills/apply.py           — skills apply(拷贝到 profile skills 目录)
    sessions.py               — session 追踪(UTC 时间、PID 存活检测、cleanup)
    hooks.py                  — hooks CRUD(JSON / YAML 双格式)
  cli/                    — cmd2 上下文栈 REPL
    shell.py                  — AgentBoxShell(repl / exec 双入口、上下文栈)
    commands/core.py          — 全局命令
    commands/profile.py       — profile 上下文命令

CLI(cmd2 上下文栈 REPL)

入口(cli/__init__.py):

  • agent-box / agent-box repl — 交互 REPL(tab 补全、历史、自动建议)。
  • agent-box exec "<script>" — 脚本执行:; 分隔命令(引号内不分割), # 注释;stdin 非 TTY 时读整段 stdin。任一命令失败返回 exit 1, 无脚本返回 exit 2。

上下文模型:全局提示符 agent-box>use <profile> 后进入 profile 上下文,提示符 [<profile>:<agent_type>]>back 返回全局。上下文栈 只有一层。

上下文命令
全局list(profiles/sessions/presets)、createdeleteshowconfigure(编辑 meta 或开 $EDITOR)、uselaunch--cwd、透传 extra)、sessions(--exit/--cleanup)
profileoptions(配置总览)、apply <provider|mcp|skill|prompt> <id>remove <provider|mcp|skill> <id>hooks(show/set/add/remove)、launch(默认当前 profile)、back

输出:人类可读对齐列;list --json / show --json / hooks show 输出 JSON(ensure_ascii=False)。数据来源:profile CRUD → SQLite + meta.yaml;apply → ACS 库查询 + strategy 写入;launch → bwrap。

launch.py 行为

launch.launch(name, extra_args=None, cwd=None):

  1. profile.load_meta(name)meta.yaml 决定 agent_type

  2. 解析路径组:

    • pdir = config.profile_agent_dir(name, agent_type) — profile 的 config 目录
    • rdir = config.real_agent_dir(agent_type) — 真实主机配置目录
    • 二次 data dir(opencode 等需要时):pdata/rdata
  3. 解析 cwd 为绝对目录,不修改 launcher 进程的全局 cwd;根据 Registry 为每个项目 surface 发现 Git 根/祖先层,首次创建 .agent-box/profiles/<profile>/root/

  4. 物化项目 Profile backing 和宿主空 mountpoint;现有宿主配置不复制、 不覆盖,在 sandbox 内由 backing 遮住。

  5. bwrap argv 模板(按顺序):

    bwrap
      --bind / /
      --bind <pdir> <rdir>                    # 隔离 agent 配置
      [--bind <pdata> <rdata>]                # 二次 data dir(opencode)
      [--bind <pjson> <rjson>]                # claude 专用:dot-claude.json
      [--bind <outer-backing> <outer-native>] # 项目父级 Profile 配置
      [--bind <cwd-backing> <cwd-native>]     # 启动目录 Profile 配置
      --dev /dev
      --proc /proc
      --tmpfs /tmp
      --unshare-ipc --unshare-pid --unshare-uts
      --share-net                              # WSL2 兼容,不破坏网络
      --chdir <resolved-cwd>
      <binary> [extra_args...]
  6. 环境默认透传,但移除 PyInstaller _MEI 注入路径。

  7. subprocess.Popen(..., start_new_session=True) 启动并记录 session;等待 Agent 退出后记录 exit code 并原样转发。

隔离完整性

--bind <pdir> <rdir> 整目录覆盖真实配置目录。对 claude 意味着 history.jsonlprojects/credentials/session-env/ 等所有 ~/.claude/ 子路径都被 profile 拷贝覆盖。claude 额外绑 dot-claude.json~/.claude.json

runtime 测试(2026-06-21)确认 --bind 整目录覆盖,无子路径泄漏。

项目 Profile 隔离

项目 backing 布局:

text
<layer>/.agent-box/profiles/<profile-name>/root/<native-relative-path>

core/agent_types.jsonproject.surfaces 为每个入口声明 pathkinddiscoverypresence。Claude/Codex 当前支持:

  • Claude:.claude.mcp.jsonCLAUDE.mdCLAUDE.local.md
  • Codex:.codex.agentsAGENTS.mdAGENTS.override.md

项目 mounts 按父层到子层排序,并晚于系统 Profile mounts。新项目 Profile 不导入宿主原生配置;同一项目中不同系统 Profile 拥有不同 backing。 Hermes/OpenCode 会初始化空项目 Profile 根,但在完成各自 inventory 前不 声明 project surfaces。

详细约束见 docs/specs/project-profile-isolation.md

数据流

core/agent_types.json + templates/<type>/ + presets/    ← package data(只读)
        ↓ create
~/.agent-box/profiles/<name>/<type>/                   ← per-profile 拷贝
        ↓ apply <resource>(strategy 写入真实配置)
profile 的 settings.json / auth.json / config.toml / opencode.jsonc ...
        ↓ launch
bwrap 子进程(覆盖真实 ~/.claude / ~/.codex / ~/.hermes / ~/.config/opencode)
        + 覆盖项目原生配置入口(.claude/.codex/根级说明文件)
        ↓ Popen + --chdir
agent binary(claude / codex / hermes / opencode)
  • ACS 库~/.agent-box/config/cc-switch.db)— providers / mcp / skills / prompts 的只读来源,apply 时查询。
  • profiles / sessions — SQLite ~/.agent-box/agent-box.db;session 时间存 UTC(datetime('now')),消费端按 UTC 解析。

config.py 行为

路径 helper(基于 AGENT_BOX_HOME_ENV~/.agent-box):

  • agent_box_home() / profiles_dir() / profile_dir(name)
  • agent_config_dir(t) / real_agent_dir(t) / profile_agent_dir(name, t)
  • agent_binary(t) / agent_data_dir(t) / real_agent_data_dir(t) / profile_agent_data_dir(name, t)
  • default_projects_dir() / projects_dir() / set_projects_dir() — GUI 项目目录(默认 ~/,持久化 gui-settings.json
  • acs_binary() — ACS 可执行文件路径(env 覆盖 → PyInstaller _MEIPASS → 仓库 submodule acs/src-tauri/target/release/cc-switch
  • home_dir() — OS home(GUI 显示 ~/... 用)
  • provider_endpoints_file() / profile_skills_dir() — 声明式数据表路径
  • project_agent_box_dir() / project_profile_root() / project_profile_path() / project_native_path() — 项目 Profile 路径
  • validate_profile_name(name) — 仅允许 [a-zA-Z0-9._-]

GUI(独立于 CLI 包)

  • 路径:gui-web/(PyWebView + React + Vite + Tailwind),不是 agent-box 包的子模块。
  • 双模式 bridgebridge.py,策略模式):
    • Windows 宿主 → WslDataAccess:经 wsl.exe python3 rpc_server.py (stdin/stdout JSON RPC)调 agent_box ,不是 agent-box CLI 二进制 —— Windows 宿主零 agent-box 依赖(bridge.py + data_wsl.py 只有 stdlib)。路径转换用确定性字符串转换 (_to_wsl_path),不经 wslpath
    • Linux/WSL → LinuxDataAccess:直接 import agent_box(懒加载, Windows 不导入)。
    • main()sys.platform == "win32" 选择;data_linux 仅在 Linux 分支懒导入。
  • RPC 运行时:exe 内置 build/runtime/(rpc_server.py + data_linux.py + agent_box 库 + 纯 Python 依赖),WSL 的 python3 经 /mnt/<drive>/... 读取 —— 无 pip / venv / CLI 安装。
  • 页面:home(仪表盘)/ profiles(列表+launch)/ detail(profile 详情, tab 由 registry resources 动态生成)/ sessions / settings / help。
  • 前端零 agent 知识:页面结构、tab、图标、默认值全部来自后端 注册表 + ACS,前端无硬编码 agent 名。
  • 关键目录:gui-web/src/pages/src/domains/src/hooks/src/api/call() 统一桥接 PyWebView)、src/i18n/(中/英)。

Future(未实现)

  • Profile import/export(tarball)。
  • CLI 库浏览list providers/skills/prompts(ACS 只读查询)目前仅 GUI 走,CLI 只有 apply <id>(需先知 id)。
  • CLI status / list models / test <endpoint>fetch_models / test_endpoint 目前只被 GUI 消费。
  • team — tmux 布局多 agent 启动。
  • plugins / permissions / rules / memories / instructions 的 CLI 命令 — 注册表已声明,CLI 无对应命令。
  • Profile rename / duplicate / 批量操作

详见 docs/ROADMAP.mddocs/specs/