Workspace & more
The fs, git, exec, events, workspace, theme, assets, and push namespaces.
Workspace subscription
for await (const event of client.workspace.subscribe()) {
const { projects, worktrees, tabs } = event.snapshot ?? event.delta;
}The workspace event is the full host picture — projects, worktrees, tabs — snapshot
first, then full-replacement deltas. It is how a headless client knows where to launch
an agent, and how the phone renders its launcher.
Generic events
for await (const event of client.events.subscribe("agentStatus", { worktreeId })) {
// { type: "snapshot" | "delta", subscription, payload }
}subscribe(event, { cursor?, worktreeId?, cwd?, signal? }) works for every protocol
event kind: agentStatus, worktreeChanged, kanbanChanged, tabsChanged,
fileChanged, automationPending, automationsChanged, workspace, fanouts.
fileChanged requires worktreeId and an absolute trusted cwd.
fs — filesystem in a worktree
All paths resolve inside the given worktree root (containment enforced by the host):
await client.fs.listDir({ root, path: "src" });
await client.fs.readFile({ root, path: "src/index.ts" }); // { text, binary, truncated }
await client.fs.writeFile({ root, path, contents });
await client.fs.createFile({ root, path });
await client.fs.createFolder({ root, path });
await client.fs.pathExists({ root, path });
await client.fs.rename({ root, from, to });
await client.fs.delete({ root, path });git — worktrees and branches
The worktree operations live here (there is no client.worktrees namespace):
// create / remove
await client.git.createWorktree({ parentRoot, branch, path });
await client.git.createWorktreeAt?.({}); // fanout base commits use the host's own path
await client.git.removeWorktree({ repoRoot, worktreePath, force: false });
await client.git.deleteBranch({ repoRoot, branch });
// inspect
const changes = await client.git.worktreeChanges({ root, parentBranch });
const dirty = await client.git.isDirty({ root });
// stage / commit
await client.git.stageAll({ root });
await client.git.commitStaged({ root, message });
await client.git.mergeWorktreeToParent({ root });
// remote sync
await client.git.githubFetchAndSync({ root }); // pull then push
await client.git.githubPushBranch({ root });Also here: file/pr diffs, discard helpers, githubRepoInfo, default PR titles,
ensurePragmaExcluded (writes the .pragma/ exclusions into the repo's git exclude).
exec
const results = await client.exec.run({
root,
commands: [{ command: "bun run test" }],
maxConcurrent: 2,
});
// CommandResult[] { stdout, stderr, exitCode }theme, assets, push, health
const theme = await client.theme.get({ root }); // overrides only, global ← project
const asset = await client.assets.toDataUri(hash); // plugin icon assets, authed fetch
await client.push.register({ token }); // device push token
await client.push.presence({ focused: true }); // suppress phone pushes while focused
const health = await client.health.check(); // { status, protocolVersion, gatewayVersion, apiVersion? }client.assets.fetch(hash) returns { bytes, mime } — the token rides the request
header, so asset URLs are never bare <img> links.