简要定义
Agent Workspace 把一个 Sandbox(隔离执行环境)和其中一个 Agent Runtime(例如 Pi 或 OpenCode)组合成一个可远程开发的整体。workspaceId 就是 sandboxId——两者是同一个身份,没有第二份生命周期或数据库记录。
flowchart LR
W[Agent Workspace] -->|等价于| S[Sandbox]
S --> R[Agent Runtime\nPi / OpenCode]
R --> T[Task Run\n提交并交付任务]
为什么存在这个概念
Sandbox 本身只是一个受控执行环境,不预设”应该跑什么”。Workspace 把 Sandbox 和一个具体的 Agent Runtime、仓库源码、Terminal Session 组合起来,变成一个用户可以直接远程开发、随时断线重连的环境——这是大多数”让 AI Agent 帮我改代码”场景真正需要的抽象层级。
从本地目录打开 Agent
登录后,团队已有默认 Server 时运行:
appaloft login
appaloft code默认 appaloft code 占用团队默认已注册 Server 上的 我的 Sandbox。源是远端 SHA。
缺少 Adapter/Profile 时会创建不可见的 appaloft-remote。笔记本路径不是 Workspace
真相,脏树也不会上传。位置参数若是 git remote(https://、ssh://、git@host:path),
无需本地 clone 即可占用该仓库。TTY 上默认 code 先在普通屏幕打印 Loading your project,
再打开占用 Workspace TUI。等待面板是 preparing the agent,步骤是
Using your credential / Including your skills / Waking the agent,并会显示
生成的 agent 名(adjective-noun)。不是 Checking login / Preparing disk。
occupy / copy skills / attach 作为左对齐步骤(Braille spinner,完成后 ✓)。attach
在同一全屏窗格里接上。workspace 打开同一个 TUI 作为导航。不以刷 stderr 状态行为主 UX。
HOME skill 复制限时且失败软处理,超时不会阻断 occupy。--server 与
workspace open --server 语义相同,用来钉死已登记 Server。--no-attach 和非 TTY 脚本仍用一行 stderr 进度(含进程
启动后的第一字节状态行),并打印 Remote 横幅以及 connecting 三行:
Using your {Grok|Codex|Claude} credential on the agent、Including N of your skills、
Woke agent {name}。N 是实际复制成功的 skill 数。
源码检出(appaloftdev)第一次 TTY 运行会查找或 cargo build 占用 TUI sidecar。
查找范围包括正在执行的树和常见兄弟检出(例如
appaloft-cloud/community/appaloft → appaloft),以及
APPALOFT_WORKSPACE_TUI_BINARY。
若缺少 appaloft-workspace-tui 且 Rust 低于 1.88,CLI 会点名该二进制,并打印
rustup toolchain install stable 与
cargo build --locked --manifest-path apps/workspace-control-tui/Cargo.toml。
--no-attach 不需要 TUI 二进制。
attach 之后,可选的 list/detail chrome 不得在 footer 画出
conflict at workspace-control-select 或残留的 bootstrap 冲突。
横幅是:
Remote · agent <name> · <repo@sha> · <server> · <project><name> 是 Agent 的可读名,不是 sbx_…。git 占用会生成 kebab 名,例如
resonant-silence。folder.local 可以用目录名。repo@short-sha 只出现在横幅的
git pin 上,不是把手。再次打开仍是同一个名字。Cloud Agents 列表和详情用这个名字。
JSON / --json 仍可带 workspaceId。workspace show|pause|resume|terminate
接受这个展示名。
占用成功后,CLI 会把公开的 Appaloft skill 写入 /workspace/skills/appaloft 和
/workspace/.agents/skills/appaloft。如果这台笔记本 HOME 里有匹配的 skill 目录,占用还会
只新增 复制到 /workspace/skills/<name> 和 /workspace/.agents/skills/<name>。
对齐 Railway 云 Agent 文档的根是 ~/.claude/skills、~/.codex/skills、~/.grok/skills、
~/.agents/skills。Appaloft 还会提供 ~/.cursor/skills 和 ~/.config/opencode/skills,
因为这是用户实际使用的根;这两项超出 Railway 文档范围。Railway 文档没有写 plugins、
MCP 配置、或这两个额外根。
只复制包含 SKILL.md 的目录。没有 SKILL.md 的文件夹(例如只有 references 的
use-railway)整棵跳过。已存在的沙箱文件不会被覆盖。skill 树不会复制 mcp.json、token、
cookie、.env 或编辑器插件二进制。沙箱进程看不到笔记本 HOME;复制只发生在本机 occupy
已经在写文件的那条 CLI 路径上。
在 Cloud Agents 上选择 Claude、Codex 或 Grok
appaloft code 每次只接受一个 agent 别名:
- 我们的:
--opencode、--pi、--omp - 对齐 Railway 的:
--claude、--codex、--grok
--claude、--codex、--grok 在远端 Sandbox 启动对应厂商 CLI,并把本机凭证写到会话
HOME。--opencode、--pi、--omp 选择对应 Cloud Agents harness。--harness opencode|pi|omp|claude|codex|grok 只作兼容。未传别名时,code 使用已保存的 Cloud Agents
偏好,然后跟随这台笔记本已登录或已安装的厂商。
占用会把该凭证写到会话磁盘(HOME=/workspace),而不是沙箱环境变量:
- Grok:
~/.grok/auth.json→ 会话.grok/auth.json - Codex:
~/.codex/auth.json→ 会话.codex/auth.json - Claude:setup-token(
~/.appaloft/claude-setup-token、~/.claude/setup-token,或把笔记本上的CLAUDE_CODE_OAUTH_TOKEN写成文件)。不会复制 Claude 聊天 cookie。
会话仍提供公开 Appaloft skill 和第一方 Appaloft MCP,让远端 agent 可以列出
workspace 并部署。不会复制笔记本 mcp.json 密钥。永远不会打印 token 值。
占用结束后若要删除 Codex 凭证的远端副本,运行:
appaloft sandbox file remove <sandboxId> --path .codex/auth.json删除远端文件不会撤销对应的上游登录会话。若凭证可能已经泄露,还要在 Codex / OpenAI 账号安全设置中撤销对应会话。
多个已注册 Server 时,用 --server 钉死其中一个:
appaloft code --server srv_4lifk0yrcecy若 Preparing disk 遇到暂时的 Cloud 网关失败(HTTP 502 /
503,包括 Cloudflare bad-gateway 或 origin 不完整响应),Cloud Agents 等待画面会保持,
将该磁盘步骤标为重试中,并在同一台已登记 Server
上继续重试磁盘准备,直到进入可输入的会话,或等待超时。
只有磁盘准备成功并接上会话后才算成功。短重试突发失败不会为此离开等待画面、恢复终端,或打印 folder
路径。 若截止时间到、进行中的磁盘准备被取消,或从未接上会话,CLI 会失败闭合:恢复终端一次,打印
Cloud 暂时不可达 / 磁盘准备未完成,退出非 0,不会打印 folder 路径。等待画面上的 Ctrl-C /
退出会中止进行中的打开,看起来不像成功。这是同一次 occupy 重试,不是再打开一次本地 folder。--omp
是 OpenCode harness;若你打开的是 Pi,用 --pi。CLI 会保留 HTTP 状态,不会倾倒网关页面。
未登录、没有 Server,或显式 --claude / --codex / --grok 缺少凭证,会 fail closed
并给出下一步,不会变成 Scratch。本机 Scratch 必须显式指定:
appaloft code --local--local 仍是本机 OpenCode,否则 Pi;不要求 Git、登录、Binding 或 Cloud。横幅仍是
Local scratch · this Mac · not saved remotely。
交付用的 durable open 仍是:
appaloft workspace open [path|git-remote]这条路径继续走 workspaces.open,定位参数与 code 相同:本地路径(可以不是 Git worktree)
或 git remote(https://、ssh://、git@host:path,以及不是本地目录时的 owner/repo)。
非 git 目录只能通过 git remote 占用当前目录,不会静默复用别人的会话。如果路径是 Git worktree,dirty / detached / 缺
upstream / remote tip 不一致仍会在远端创建前失败。默认 appaloft code 优先选 live 会话,同名 leftover 不能挡住第一次成功,
也不要求记住 installation id。--profile 只是显式撞名时的兜底,不同于全局
--control-plane-profile。--new 仍占用 cwd 源,不会静默 resume whoami 会话。
如果默认 code 命中的首选 Workspace 停在部分创建状态,CLI 会保留那个 Workspace 供诊断,
并自动创建一个隔离替代 Workspace;不需要退出后再手工补 --new。低层
workspace open / workspace create 仍会返回原始 partial 恢复证据,不会自动创建替代。
打开失败时会写出缺什么、正在打开哪个仓库,而不会把 Cloud 激活失败伪装成 CLI 成功。
已注册 BYOS Server 时,workspace open 和 code 放到那台 Server 上(--server <id>
可钉死),不会再索要 managed 容量。V1 不做隐式 sync 或 patch upload。
workspaces.open 会先验证来源,再读取现有 Repository Binding 和 Project 默认 Profile。如果部署方
组合了可选的 activation initializer,缺少的 Project、Binding 或默认 Profile 可以在同一次显式
activation 中幂等创建或复用,随后必须重新读取公共权威状态;没有 initializer 的 Community/local
部署继续 fail closed。initializer 必须在创建前完成授权与 admission,且不能覆盖已有、冲突、
disabled 或未授权状态。
deploy 方的 entitlement、target policy 或容量失败必须在 Sandbox/provider effect 前失败。错误可以 提示等待、重试或显式接入其他执行位置,但 Appaloft 不会把一次 managed 请求静默改成本机 Scratch。
管理正在运行的 Workspace
在受支持的 macOS/Linux 交互终端中,无子命令运行:
appaloft workspace会打开 Appaloft Workspace control TUI。进入 TUI 本身不会创建、暂停、恢复或终止任何 Workspace;它通过现有公开查询显示 Workspace、Agent Runtime、Preview port、Task 和 Promotion 摘要。选择带 attach capability 的 Runtime 后,Agent 自己的 TUI 会作为原生终端字节流嵌入右侧 窗格,Appaloft 不解析对话、tool call 或 hidden reasoning。
详情头部同时显示安全的 target class/source/reason 和 activation created/reused 状态;它与
headless sandbox show、HTTP 和 SDK 使用同一 readback,不显示主机或 provider identity。
↑/↓或j/k:选择 Workspace;Enter:attach 或重新聚焦已经连接的 Agent;a:打开所选 Workspace 的生命周期操作。ready状态可暂停或终止,paused状态可恢复或 终止;终止还需要单独按y确认;d:打开从当前 detail 推导的交付操作。可以创建默认 private、明确选择 1 小时/8 小时/24 小时 TTL 的 Preview,撤销已有 Preview,批准或交付符合状态的 Task,以及接受/重试符合状态的 Promotion;撤销、批准、Git/PR 交付和 Promotion 操作都需要单独按y确认;s:打开恢复操作。可以用filesystem或filesystem-memorycapability 创建保留 1、7 或 30 天的 Snapshot,也可以删除当前 detail 中状态允许删除的精确 Snapshot;创建和删除都需要 单独按y确认;Ctrl+]:把按键所有权从 Agent 交还给 Workspace 导航,不停止或 detach Agent;f:在同一个 Terminal Session/本地 PTY 上切换 Focus Mode,不启动第二个 Agent;r:刷新现有公开 read model;R:用同一 Session identity 手动重连;q:仅在 Workspace 导航获得焦点时退出;Agent 获得焦点时,普通按键仍发送给 Agent。
TUI 断开或退出只 detach 客户端。TUI 生命周期操作调用与显式 headless 子命令相同的公开命令;
暂停或终止前会先 detach 当前 Agent viewport,之后重新读取 Workspace 状态,而不是在本地乐观
修改状态。交付和 Snapshot 操作都不会 detach 当前 Agent Session。恢复区域还显示请求/实际隔离、
provision attempts、暂停连续性和当前 Workspace 的 Snapshot。终止/过期 Workspace 的
Workspace-owned cleanup 只根据有界 Runtime 与 Preview 查询判定 clear 或 residual;它不是
主机或 provider 零残留证明。带 deployment identity 的 Promotion 会查询
权威 Deployment Proof,并显示 verdict、mismatch 数和 unavailable evidence 数;Promotion status
不会被伪装成 proof。交付失败会保留有界表单值供修改或重试,credential 不会进入 renderer
协议。脚本、CI、无 TTY 环境或不希望加载 renderer 时使用:
appaloft workspace --no-tui
appaloft workspace --json
appaloft workspace list等价的 headless 入口仍是 workspace preview、sandbox port revoke、workspace task approve/deliver、sandbox promote accept/retry、deployment proof,以及 sandbox show、
sandbox snapshot list/create/show/delete。
这些路径不会初始化 renderer,并返回稳定的 headless 状态或继续执行现有子命令。Windows 当前仅
保证 help/headless 命令安全;嵌入模式需要独立的 release 与终端验收。Windows,或 TERM
缺失、为 dumb/unknown 的交互环境,会在 renderer 启动前返回
platform-unsupported/terminal-unsupported,避免把控制序列写入不支持的宿主终端。
使用 Profile 显式创建
需要在没有本地 Git context 的自动化中创建新 Workspace 时,使用 credential-free HTTPS repository 和显式 Profile:
appaloft workspace create \
--profile opencode-default \
--repo https://github.com/acme/web.git \
--ref refs/heads/feature/login \
--branch feature/login \
--attach--profile 接受安装 id、Profile id 或唯一显示名。Appaloft 会先编译 Profile 并解析 Sandbox
Template、隔离级别、资源/网络策略、初始化步骤、默认端口、Adapter capability 和安装时配置的
named Credential Connections,再创建 Sandbox。缺失、disabled、stale、ambiguous 或无权限的
Profile/Credential/Template/capability,以及 placement 无容量,都在 Sandbox 创建前失败。
API Key、Token 和 Secret 不允许出现在 argv。
SDK 提供等价的组合式创建:
const workspace = await appaloft.workspaces.open({
repository: "https://github.com/acme/web.git",
repositoryIdentity: "github.com/acme/web",
ref: "refs/heads/feature/login",
branch: "feature/login",
commitSha: "0123456789abcdef0123456789abcdef01234567",
profile: "opencode-default",
});
console.log(
workspace.workspaceId,
workspace.agent.runtimeId,
workspace.targetSelection,
workspace.activation,
);如果 Sandbox identity 产生后的步骤失败,错误会包含精确 phase、已有的
workspaceId/runtimeId、是否可重试以及恢复/终止入口;再次 open 会协调同一个部分创建身份,
不会静默创建重复 Sandbox。
断线重连
Terminal Session 由 Appaloft 托管的 PTY 支撑——客户端断线只是”detach”,只要 Session 的存活时间和 Sandbox 仍然有效,再次运行 appaloft code 就会重用 Session、重放有限历史输出并继续同一个 Agent 进程:
appaloft code已有脚本可以继续使用 appaloft workspace open .;它不会被弃用或改变机器可读行为。
底层排障命令仍然保留:
appaloft workspace connect <workspaceId>
appaloft workspace attach <workspaceId>native attach 只签发短期、可撤销的私有访问 capability;返回值不会包含原始服务器地址、 SSH Key 或长期凭据。
临时开发预览
appaloft workspace preview <workspaceId> \
--port 3000 \
--visibility private \
--expires-at 2026-07-24T12:00:00.000Z这是一个实时开发预览,不是不可变的候选预览(Promotion Candidate Preview)。URL、TLS、鉴权和路由由 Provider/网关适配器提供;到期、被撤销或 Sandbox 被清理后,地址必须立即失效。不同团队成员使用各自的 Sandbox 时,端口暴露、文件和进程都有独立身份,互不冲突。
生命周期
appaloft workspace list
appaloft workspace show <workspaceId>
appaloft workspace pause <workspaceId>
appaloft workspace resume <workspaceId>
appaloft workspace terminate <workspaceId>workspace list 是 Sandbox 清单的组合视图,每一项都带 agentRuntimes;如果这个数组为空,说明它是一个可以重试或清理的”部分创建”状态,而不是隐藏在另一张表里的状态。
pause / resume 保留 Sandbox 身份(详见休眠与恢复);terminate 会终止 Sandbox 及其拥有的全部 Runtime 状态,这一步不可逆。
提交一次 Task
在 Workspace 里给 Agent 布置一个任务、观察进度、批准并交付代码,使用 workspace task 子命令族:
appaloft workspace task run <workspaceId> \
--runtime-id <runtimeId> \
--task "修复 Issue #123 并运行测试" \
--check-arg bun --check-arg test
appaloft workspace task show <workspaceId> <taskRunId>
appaloft workspace task deliver <workspaceId> <taskRunId> \
--branch fix/issue-123 \
--commit-message "fix: resolve issue 123" \
--pull-request-title "Fix issue 123"Task Run 由服务端持久化——客户端断开连接不会取消 Agent 的执行。批准和交付源码必须由外部用户或可信 CLI 操作者发起,Sandbox 内的 Runtime 身份不能自我批准自己的变更。
常见误区
- 把 Workspace 当成独立于 Sandbox 的资源:
workspaceId和sandboxId是同一个 id,理解 Sandbox 的隔离和生命周期模型(见 Sandbox 模型)就理解了 Workspace 的底层行为。 - 认为客户端断线会取消正在运行的 Task:Task Run 由服务端持久化和恢复,断线只影响观察,不影响执行。
- 把开发预览当成生产访问地址:开发预览是临时、可过期的实时预览,和生成的访问地址是完全不同的机制。
- 把
.当成上传目录:它只用于解析 Git context;未提交文件从不隐式上传。 - 在 HEAD 未 push 时继续创建:Workspace 的来源必须是远端可解析的精确 SHA;先 push, 或明确选择正确的 upstream,再重试。
相关任务
进阶细节
如果第一次创建 Task Run 时 Runtime 已经在忙于处理另一个 Task,运营方可以在适配器层配置并发策略;具体行为取决于所选 Agent 适配器,详见 Agent 适配器。