03-C-控制与接口
接口分三层:项目层接口(第 13 节新增,对应控制台的项目创建/人工交互)、Org Graph 层接口(对两个后端一视同仁,架构文档 7.2 节)、Work Graph 层接口(MVP 阶段以 Claude Code 原生动态工作流为准,架构文档 10.1 节方案 A)。所有接口默认 auth: system_internal(MVP 单用户,无外部开放 API)。
3.-1 c_pick_folder(架构文档 13.1 节决策 5)
method + path:POST /api/system/pick-folder- 语义:控制台前端是本地 Web 应用,无法直接调用 OS 原生文件夹选择对话框;此接口由本机常驻的后端进程代为拉起系统对话框(macOS
osascript、Windows/Linux 对应平台方案),返回用户选中的真实绝对路径 input_contract:{}(无需参数,对话框本身是模态的,由后端进程所在操作系统渲染)output_contract:成功{ selected_path: string };用户取消对话框{ selected_path: null }(不算错误)idempotent:否(每次调用弹出新的对话框交互)errors:DIALOG_UNAVAILABLE(不可重试):后端所在环境不支持拉起原生对话框(如无图形界面的纯服务器环境),控制台应提示改用手动路径输入作为兜底
owner_team:control-plane
3.0 c_project_create
method + path:POST /api/projectsinput_contract:{ target_folder_path: string(required), name: string(optional), init_git_if_missing: boolean(required) }output_contract:成功{ project_id, has_git_repo, graphlemon_subdir_initialized }idempotent:是——同一target_folder_path重复调用直接返回已有project记录(见 01-M 1.0 幂等约束)side_effects:若has_git_repo=false且init_git_if_missing=true,执行git init;创建<target_folder_path>/.graphlemon/子目录errors:PATH_NOT_FOUND(不可重试):文件夹不存在PATH_NOT_WRITABLE(不可重试):无写权限GIT_INIT_DECLINED(不可重试):非 Git 仓库且用户未确认初始化
owner_team:control-plane
3.0.1 c_project_get / c_project_list
GET /api/projects/:project_id、GET /api/projectsidempotent:是- 说明:MVP 控制台 UI 不强制暴露完整项目列表交互(架构文档 13.1 节决策 2),但接口按多项目设计,供未来扩展
3.1 c_task_create
method + path:POST /api/tasksinput_contract:{ project_id: string(required), goal_text: string(required), task_type: enum('goal'), created_via: enum('api','human_console', default='api') }output_contract:成功{ task_id, status: 'queued' };失败见 errorsidempotent:否(每次调用创建新任务)transaction:单表插入 + 一条execution_event(event_type=task_status_changed),需同一事务side_effects:写入task表;若org_concurrency_config.max_concurrent_goals已达上限,任务落queued但不触发调度;写入execution_event供看板实时推送errors:INVALID_PARAM(不可重试):goal_text为空或project_id不存在
audit_trace:trace_id、actor=system|human、business_id=task_idowner_team:graph-engine
3.1.1 c_bug_report_create
method + path:POST /api/bug-reports- 语义:控制台人工反馈 bug 的入口,区别于 Validator 自动生成的
c_bug_record_create(3.10 节),复用同一张bug_record表但source=human input_contract:{ description: string(required), repro_steps: string(optional), related_task_id: string(optional) }output_contract:成功{ bug_id, status: 'open' }idempotent:否side_effects:写入bug_record(source=human, status=open);写入execution_event(event_type=bug_recorded);异步触发 Validator 认领该 bug 进行 triage(复用 04-Pp_validator_root_cause_trace,见该节新增的人工接入分支)errors:INVALID_PARAM(不可重试):description为空
3.2 c_task_list / c_task_get
GET /api/tasks?status=&org_node=&keyword=、GET /api/tasks/:task_idoutput_contract:c_task_list返回分页数组;c_task_get返回单条task+ 关联artifact列表 + 关联bug_record列表idempotent:是errors:NOT_FOUND(不可重试,仅c_task_get)
3.3 c_org_node_trigger
POST /api/org-nodes/:org_node/triggerinput_contract:{ task_id: string(required) }- 语义:Org Graph 调度器将
task.assigned_org_node指向的 Org Agent 唤起,Org Agent 内部先调用c_work_graph_plan再调用c_work_graph_execute - 实现契约(架构文档 7.2 节决策,2026-07-29):底层是子进程调用
claude --agent <planner|coder|validator> -p "...",让整个会话以目标项目.claude/agents/<org_node>.md定义的 subagent 身份运行。三个 Org Agent 的身份(对应 SOUL.md)、memory、skills、tools、model 全部由这个 subagent 定义文件承载,c_org_node_trigger本身只负责拼装任务上下文 prompt 和解析返回结果,不需要额外的角色隔离逻辑 idempotent:否(每次触发可能生成新的work_graph_run)errors:TASK_NOT_READY(可重试):上游依赖 Artifact 未就绪CONCURRENCY_LIMIT_REACHED(可重试):超过max_concurrent_goalsUSAGE_LIMIT_REACHED(新增,2026-07-29):语义同 3.6 节,Org Agent 级别的调用同样可能撞到 plan 额度,处理方式一致(等待重试,不转人工介入)
owner_team:graph-engine
3.4 c_work_graph_plan
POST /api/work-graph/plan- 语义:对应 Org Agent 的 Planning Skill 调用——输入任务上下文,输出结构化
graph_manifest(节点、边、fan-out/fan-in 分组、loop 规则),不执行,只规划 input_contract:{ task_id, org_node }output_contract:{ run_id, graph_manifest }idempotent:否errors:PLANNING_FAILED(可重试,重试上限由调用方控制)- 约束(继承 10 节课程映射):
graph_manifest中每条边必须标注是否为"零 token 边"(纯代码聚合,如 flatten/dedupe)还是"需要 Agent 判断的边",规划阶段就要做这个区分,不能等执行时才发现
3.5 c_work_graph_execute
POST /api/work-graph/:run_id/execute- 语义:直接调用 Claude Code 原生动态工作流能力执行
graph_manifest对应的编排脚本(agent()/parallel()/pipeline()),编排本身不消耗模型 token(MVP 阶段唯一执行后端,见架构文档 7.2 节 2026-07-29 决策——不再考虑 Hermes CLI 后端,此前的后端不对等声明已作废) input_contract:{ run_id }output_contract:{ status, result_artifact_refs }idempotent:否errors:NODE_CONTRACT_VIOLATION(可重试,触发对应work_node_execution重试):某节点输出未通过output_schema_ref校验BUDGET_EXCEEDED(不可重试,需人工介入):执行中触发c_budget_check拦截CLASSIFIER_BLOCKED(不可重试,需人工介入):见下方权限模式说明——auto mode 分类器连续拦截 3 次或累计 20 次,-p下无人可确认,进程中止
Claude Code ACP 后端的实现契约(A-1 已通过 spike 实测确认,见 spikes/a1-dynamic-workflows/,2026-07-29):
调用是 prompt-mediated 的,不是对 Claude Code 的直接函数调用。c_work_graph_execute 的具体实现步骤:
- 将
graph_manifest对应的编排脚本写入/更新目标项目仓库的.claude/workflows/<run_id>.js(随目标项目自身 git 历史版本化,而非 graphlemon 平台仓库) - 以子进程方式调用:
claude -p 'Run /<run_id> with args {...}' \ --output-format json \ --json-schema <output_schema_ref 对应的 JSON Schema> \ --permission-mode auto不加--bare:实测--bare会跳过凭据/登录态发现(报Not logged in,与是否有 workflow 无关,是--bare本身的限制),必须用不带--bare的完整冷启动 权限模式选定为auto,而非bypassPermissions/--dangerously-skip-permissions(决策,2026-07-29):官方文档明确要求bypassPermissions只应在隔离容器/VM+无网络访问环境下使用,且"对 prompt injection 和意外操作零防护";graphlemon 当前的节点隔离手段是 git worktree(同机目录级隔离,非容器/VM 级),达不到这个前提。automode 用一个分类器对每个动作实时把关,默认拦截一批高危操作(curl|bash、密钥外泄、生产部署、force push、批量删除、IAM 变更等),同样能在-p下零 prompt 跑完,且和架构已有的预算护栏/人工升级理念一致。约束:automode 要求会话模型是 Claude Sonnet 5 / Opus 4.7+ / Fable 5(Anthropic API 上);架构文档 10 节"按节点分层选模型"给便宜/有界重复节点选模型时,需要在这个集合内选,不能选更早/更小的模型 - 解析返回 JSON 的
structured_output字段作为output_contract的result_artifact_refs来源 - 用返回 JSON 的
total_cost_usd/usage字段回填budget_guardrail_config.current_usage(对应c_budget_check) - 子进程需以无 stdin 方式启动(
< /dev/null或等效),避免任何交互式提示导致挂起;实测确认无 stdin 时不会挂起、不会插入确认提示 - 若返回结果表明本轮运行被分类器连续拦截 3 次或累计 20 次(
-p下无人可确认,官方文档称此时 auto mode 会中止会话),映射为CLASSIFIER_BLOCKED错误,对应 04-P 状态机路由到blocked_pending_human,blocked_reason='classifier_blocked',并把分类器拦截的动作摘要写入v_task_detail,供人工判断是补permissions.allow/白名单信任规则还是这确实是个危险操作
3.6 c_work_node_run
- 内部接口(不对外暴露 HTTP,供
c_work_graph_execute调用),语义对应课程"给每个节点一个契约" input_contract:{ node_exec_id, input_payload, input_schema_ref }—— 校验失败直接拒绝,不进入执行output_contract:{ output_payload }—— 必须通过output_schema_ref校验才算成功idempotent:否errors:SCHEMA_VALIDATION_FAILED(可重试,重试即重新调用 Subagent,非幂等回放)USAGE_LIMIT_REACHED(新增,2026-07-29,可重试但不是立即重试,见下方等待重试语义)
- 约束:并行写代码的节点必须先申请
git_worktree_ref(见 01-Mwork_node_execution.git_worktree_ref),执行完成后清理 worktree 并合并回主分支 - self-target 特例(新增,2026-07-30,见 05 节 §5.8):
task.project_id对应的project.target_folder_path == graphlemon 平台自身安装路径时,无论并行还是串行,一律强制申请git_worktree_ref,不适用"仅并行时才强制"的一般规则;Coder/Validator 的自测/复核全部在 worktree 副本里跑,不碰主 checkout - 新增约束(架构文档 13.1 节决策 4):节点开始执行时必须先创建对应的
execution_log_file记录(status=active),执行期间将 Claude Code ACP 的会话输出流式追加写入该文件,每次追加同时写一条execution_event(event_type=log_appended);节点执行结束(成功或失败)后将execution_log_file.status置为closed
Claude Code plan 额度耗尽的等待重试语义(架构文档 7.5 节决策,2026-07-29):
claude -p 的账号/plan 用量是一个会自然恢复的资源(5 小时滚动窗口 / 7 天窗口 / Opus 专属限额),耗尽时官方 CLI 直接终止请求并在文本里带上人类可读的恢复时间,例如 You've hit your session limit · resets 3:45pm、You've hit your weekly limit · resets Mon 12:00am。这类错误不应该路由到 blocked_pending_human(那是给需要人工判断的情况用的),而是自动等待+重试:
- 检测:
claude -p返回is_error=true且result文本匹配/hit your (session|weekly|Opus) limit/i时,判定为USAGE_LIMIT_REACHED,从匹配的关键词提取quota_limit_type(session|weekly|opus),写入work_node_execution.quota_limit_type - 状态转移:
work_node_execution.status → waiting_for_quota,记录quota_wait_started_at;不冒泡到task.status,调度器继续跑队列里其他不依赖这个节点的工作(同 04-Pbudget_exceeded的"跳过而非全局阻塞"模式) - 退避轮询:不解析"resets 3:45pm"这种脆弱的人类可读文本(没有日期/时区锚点,跨天跨周边界容易解析错),改用容量更简单可靠的退避重试——等待间隔从 5 分钟起步,每次翻倍,上限 30 分钟(5/10/20/30/30/... 分钟),每次到点直接重新发起原本要跑的那次
claude -p调用本身作为探测,成功即转入正常执行- 例外:
quota_limit_type=opus时不用等待退避——按官方建议直接把该节点这次调用降级到非 Opus 模型重试(需符合 03-C 3.5 节 auto mode 的模型约束:Sonnet 5 / Opus 4.7+ / Fable 5)
- 例外:
- 超时兜底(防止真正的账号/计费问题被无限期静默等待掩盖):
quota_limit_type=session累计等待超过 8 小时、或quota_limit_type=weekly累计等待超过 9 天仍未恢复,转blocked_pending_human,blocked_reason='usage_limit_wait_timeout' - 可见性:进入
waiting_for_quota时写一条execution_event(event_type=quota_wait_started),v_dashboard/v_graph_visualizer用信息性样式(非告警)展示,见 02-V 2.2/2.7 节——这是自愈型等待,不需要人工介入,但应该在控制台可见
3.6.1 c_execution_log_get
GET /api/work-nodes/:node_exec_id/log- 语义:获取指定 Work Node 的原始执行日志(静态模式,用于已结束节点或首次加载)
input_contract:{ path: { node_exec_id }, query: { offset: int(optional), limit: int(optional), download: boolean(optional) } }—— 支持分页避免大文件一次性传输output_contract:{ content: string, format, total_size_bytes, status };download=true时返回文件流idempotent:是errors:LOG_NOT_FOUND(不可重试):node_exec_id不存在对应日志记录LOG_PURGED(不可重试):日志已被定时清理任务删除,v_log_viewer据此展示对应异常态
3.6.2 c_ws_log_tail(实时日志订阅)
protocol:WebSocket,WS /api/ws/work-nodes/:node_exec_id/log- 语义:订阅指定 Work Node 的实时日志追加事件,用于运行中节点的滚动查看
input_contract:{ path: { node_exec_id } }output_contract(推送消息体):{ node_exec_id, appended_content: string, created_at }idempotent:不适用(长连接)errors:NODE_EXEC_NOT_FOUND(不可重试):连接建立时校验- 说明:节点执行结束后(
work_node_execution.status转为终态)服务端主动关闭该连接,前端应据此切换到c_execution_log_get的静态模式
3.7 c_artifact_write
POST /api/artifactsinput_contract:{ artifact_type, task_id, produced_by_run_id, file_path, content, depends_on_artifact_ids }output_contract:{ artifact_id, git_commit_sha }idempotent:否(artifact不可变更,见 01-M 迁移约束)side_effects:写文件 + Git commit(commit message 包含task_id与artifact_type)errors:GIT_COMMIT_FAILED(可重试)
3.8 c_skill_update
POST /api/skills/:skill_id/update- 语义:Skill 自主迭代的落地接口(架构文档 8 节决策 1)——允许 Validator 触发的自动改写立即生效,但必须产生独立 Git 提交
input_contract:{ skill_id, triggered_by_bug_id(required), new_content, change_summary(required) }output_contract:{ iteration_id, after_git_commit_sha }idempotent:否transaction:文件写入 + Git commit 需原子完成(commit 失败则整体回滚,不留半成品 Skill 文件)errors:MISSING_TRIGGER_REF(不可重试):triggered_by_bug_id缺失时直接拒绝——不允许无来源的 Skill 变更
3.9 c_skill_rollback
POST /api/skills/:skill_id/rollbackinput_contract:{ iteration_id(required) }—— 回滚到该次迭代之前的版本output_contract:{ new_iteration_id }(回滚本身也生成一条新的skill_iteration记录)idempotent:否errors:ITERATION_NOT_FOUND(不可重试)
3.10 c_bug_record_create
POST /api/bug-recordsinput_contract:{ task_id, description, repro_steps, root_cause_category(required, enum), root_cause_detail(required), related_artifact_ids, suggested_route(required) }output_contract:{ bug_id }idempotent:否errors:INVALID_ROOT_CAUSE_CATEGORY(不可重试):未落在planning|coder|skill_defect|core_engine(新增,2026-07-30,见 01-M 1.6/05 节 §5.8)四类之一- 约束:
root_cause_category=skill_defect时必须同时创建skill_iteration_suggestion,否则视为字段缺失(见 08 反模式门禁:不允许"空目标"式的归因);root_cause_category=core_engine时不要求人工评审即可提交(用户明确否决"比照org_graph_definition强制人工 PR 评审"的原提案),但c_org_loop_route会将其路由到蓝绿部署+监控流程而非常规fast_lane(见 3.11 节)
3.11 c_org_loop_route
POST /api/tasks/:task_id/route- 语义:Org-level Loop 的路由决策落地——Validator 判定结果驱动任务回到 Planner(
full_replan)或直达 Coder(fast_lane),决策本身由 Agent 判断(Validator 分类),路由本身是确定性代码(架构文档 10 节课程映射:判断用 Agent,路由用代码) input_contract:{ task_id, decided_route: enum('fast_lane','full_replan','manual_resume') }output_contract:{ task_id, new_status, new_assigned_org_node }idempotent:否errors:LOOP_LIMIT_REACHED(不可重试):task.loop_round已达上限(3 轮),强制转blocked_pending_human,不接受常规路由请求,只接受manual_resume
core_engine路由分支(新增,2026-07-30,见 05 节 §5.8):关联bug_record.root_cause_category=core_engine的任务,无论 Validator 给出的decided_route是fast_lane还是full_replan,c_org_loop_route都不直接按常规路由处理,而是在 Coder 完成修复、Validator PASS、worktree 分支 merge 回 graphlemon 自身仓库主分支之后,转交p_deploy_supervisor_blue_green流程(04-P)——即触发 Deploy Supervisor 的蓝绿部署与自动回滚机制,不是"合并即生效"
3.12 c_budget_check
- 内部接口,
c_work_graph_execute执行前/中调用 input_contract:{ scope, estimated_usage }output_contract:{ allowed: boolean, remaining_quota }idempotent:是errors:BUDGET_EXCEEDED(不可重试):触发后对应任务转blocked_pending_human,并记录blocked_reason='budget_exceeded'
3.13 c_concurrency_config_update / c_budget_config_update
PUT /api/settings/concurrency、PUT /api/settings/budgetinput_contract:对应 01-Morg_concurrency_config/budget_guardrail_config的可写字段output_contract:更新后的完整配置对象idempotent:是errors:INVALID_PARAM(不可重试):数值超出校验范围
3.13.1 c_log_retention_config_update
PUT /api/settings/log-retentioninput_contract:{ retention_days: int(required, >0), max_total_size_mb: int(optional) }output_contract:更新后的完整配置对象idempotent:是errors:INVALID_PARAM(不可重试):retention_days <= 0
3.14 c_ws_subscribe(实时事件订阅,架构文档 13.1 节决策 3)
protocol:WebSocket,WS /api/ws/projects/:project_id- 语义:控制台建立连接后订阅指定
project_id下的全部execution_event;服务端在execution_event写入的同一事务提交后立即推送给已订阅的连接 input_contract(连接建立时的订阅参数,query string):{ project_id: string(required), task_id: string(optional) }—— 传task_id时可选做服务端过滤,减少推送量output_contract(服务端推送的消息体):{ event_id, event_type, task_id, run_id, node_exec_id, payload, created_at },字段与execution_event实体一一对应idempotent:不适用(长连接)errors:PROJECT_NOT_FOUND(不可重试):连接建立时校验project_id不存在,直接拒绝连接
- 断线重连约束:客户端重连后需带上
last_event_id查询自该事件之后的遗漏事件(通过c_task_get系接口的时间线字段补齐,而非 WebSocket 层做消息重放缓冲,MVP 阶段简化处理) owner_team:control-plane
3.15 Deploy Supervisor 控制操作(PH5 新增,2026-07-30,见 docs/supervisor-auto-rollback-design.md)
以下五个操作均由 Deploy Supervisor 进程调用,不是控制台前端直接调用的 HTTP API(Deploy Supervisor 是独立于 Graph Engine 之外的确定性 Python 进程,见 01-M 1.15 节),标记为内部接口。所有决策逻辑均为确定性代码,不接入任何 LLM 判断。触发前提:task 关联的 project.target_folder_path == graphlemon 平台自身安装路径 且 Validator 判定 PASS 后,worktree 分支已 merge 回主分支(见 3.11 节 core_engine 路由分支)。
c_deploy_supervisor_stage
- 内部接口,语义:拉取合并后的主分支到全新目录(非原地
git pull),生成deployment记录 input_contract:{ git_commit_hash }output_contract:{ deployment_id, status: 'staged' }idempotent:否side_effects:复制PROD_DB_PATH到一次性candidate_db_path;用supervisor/isolation/isolated_workspace.py同款隔离原则拉起候选进程(subprocess.Popen,shell=False),监听临时candidate_porterrors:CHECKOUT_FAILED(不可重试,转blocked_pending_human):全新目录 checkout 失败(如磁盘空间不足)
c_deploy_supervisor_health_check
- 内部接口,语义:对候选实例执行
process_alive/http_health/canary_task三项 pre-cutover 检查(见supervisor-auto-rollback-design.md§6) input_contract:{ deployment_id }output_contract:{ status: 'health_check_passed' | 'health_check_failed', signals: deploy_health_signal[] }idempotent:是(可重复查询当前检查状态,但不重新触发候选进程重启)errors:HEALTH_CHECK_TIMEOUT(不可重试,直接判定该项 fail,进入回滚路径 A,不重试——重试属于"给坏版本第二次机会",不符合 fail-closed 原则)- 约束:任一检查项 fail 立即整体判定
health_check_failed,不等待其余检查项跑完
c_deploy_supervisor_cutover
- 内部接口,语义:蓝绿切换本体——仅在
c_deploy_supervisor_health_check返回health_check_passed后才允许调用 input_contract:{ deployment_id }output_contract:{ status: 'live', cutover_at }idempotent:否side_effects:Live 停止接受新的c_org_node_trigger调用(在途work_node_execution允许走到可安全中断的检查点,依赖既有持久化恢复机制,不强求优雅排空)→ Live 进程退出 → 候选进程改连PROD_DB_PATH、改绑LIVE_PORT→ 候选成为新 Live;原 Live checkout 目录保留为previous_instance_dir,不删除errors:CUTOVER_FAILED(不可重试,转blocked_pending_human):切换过程中候选进程未能正确绑定生产端口/生产库
c_deploy_supervisor_monitor
- 内部接口,语义:post-cutover 监控窗口内周期性采样四类信号(见
supervisor-auto-rollback-design.md§6),窗口时长/任务数上限见 05 节 §5.9 input_contract:{ deployment_id }(由 Deploy Supervisor 自身的调度循环周期性调用,不是一次性调用)output_contract:{ status: 'monitoring' | 'anomaly_detected' | 'monitoring_window_clean', latest_signal: deploy_health_signal }idempotent:是- 约束:
validator_approval_rate信号从execution_event/work_node_execution按滚动窗口统计 Validator 节点approved占比,与该deployment之前的历史基线做纯算术比较,偏离VALIDATOR_RATE_DEVIATION_THRESHOLD(05 节 §5.9)即判定anomaly_detected——这是"改坏了的 validator"场景的核心检测点,判断全程不需要另一个 LLM 参与
c_deploy_supervisor_rollback
- 内部接口,语义:回滚路径 A(pre-cutover,健康检查未过)与路径 B(post-cutover,监控期
anomaly_detected)的统一入口,具体步骤见supervisor-auto-rollback-design.md§7 input_contract:{ deployment_id, rollback_reason }output_contract:{ status: 'rolled_back' | 'health_check_failed' | 'rollback_failed' }idempotent:否side_effects:路径 A——终止候选进程、删除一次性 DB 副本、git revert本次合并 commit、创建bug_record(root_cause_category=core_engine);路径 B——用previous_instance_dir重新拉起旧版本、绑定LIVE_PORT+PROD_DB_PATH、对复活的旧版本重跑一遍 pre-cutover 健康检查确认无误、git revert、创建bug_recorderrors:ROLLBACK_FAILED(不可重试,转blocked_pending_human,blocked_reason='rollback_failed'):连previous_instance_dir也起不来,或git revert冲突(见supervisor-auto-rollback-design.md§10 开放问题 3)——这是本机制唯一保留的人工介入点,触发条件严格限定为"自动恢复机制本身失效",不是"代码判断谁对谁错"
owner_team:deploy-supervisor(独立于graph-engine,进程边界见 01-M 1.15 节)