6.18. Worktree Client¶
The Worktree Client talks to the sw4rm.worktree.WorktreeService service. Use it to:
- Bind agents to repository worktrees for file system access.
- Request temporary worktree switches with optional HITL approval.
- Approve or reject pending switch requests.
- Query current binding state and unbind when work is complete.
Worktree bindings follow a simple state machine:
UNBOUND->BOUND_HOMEviabind.BOUND_HOME->SWITCH_PENDINGviarequest_switch.SWITCH_PENDING->BOUND_NON_HOMEviaapprove_switch.SWITCH_PENDING->BOUND_HOMEviareject_switch.- Any state ->
UNBOUNDviaunbind.
6.18.1. Service Overview¶
The service exposes six RPCs:
Bind(BindRequest) -> BindResponseUnbind(UnbindRequest) -> UnbindResponseRequestSwitch(SwitchRequest) -> StatusResponseApproveSwitch(SwitchApprove) -> StatusResponseRejectSwitch(SwitchReject) -> StatusResponseStatus(StatusRequest) -> StatusResponse
Worktree state values¶
| Value | Description |
|---|---|
UNBOUND | Agent has no worktree binding. |
BOUND_HOME | Agent is bound to its home worktree. |
SWITCH_PENDING | Switch requested, awaiting approval. |
BOUND_NON_HOME | Agent is bound to a non-home worktree. |
BIND_FAILED | Last bind attempt failed. |
BindRequest fields¶
| Field | Type | Description |
|---|---|---|
agent_id | string | Agent identifier to bind. |
repo_id | string | Repository identifier containing the worktree. |
worktree_id | string | Worktree identifier (becomes the home worktree). |
BindResponse fields¶
| Field | Type | Description |
|---|---|---|
ok | bool | Whether the bind succeeded. |
reason | string | Optional failure reason. |
UnbindRequest fields¶
| Field | Type | Description |
|---|---|---|
agent_id | string | Agent identifier to unbind. |
UnbindResponse fields¶
| Field | Type | Description |
|---|---|---|
ok | bool | Whether the unbind succeeded. |
SwitchRequest fields¶
| Field | Type | Description |
|---|---|---|
agent_id | string | Agent identifier requesting the switch. |
target_worktree_id | string | Worktree identifier to switch to. |
requires_hitl | bool | Whether human approval is required. |
SwitchApprove fields¶
| Field | Type | Description |
|---|---|---|
agent_id | string | Agent identifier being approved. |
target_worktree_id | string | Worktree identifier to switch to. |
ttl_ms | uint64 | Time-to-live for the non-home binding. |
SwitchReject fields¶
| Field | Type | Description |
|---|---|---|
agent_id | string | Agent identifier being rejected. |
reason | string | Optional human-readable reason. |
StatusResponse fields¶
| Field | Type | Description |
|---|---|---|
repo_id | string | Repository identifier for the active binding. |
worktree_id | string | Active worktree identifier. |
state | string | Current worktree state. |
6.18.2. Constructors¶
Python¶
WorktreeClient(channel: grpc.Channel)
channel: A gRPC channel connected to the WorktreeService endpoint (default port: 50062).
JavaScript/TypeScript¶
new WorktreeClient(options: ClientOptions)
options.address:host:portfor the WorktreeService endpoint (default port: 50062).- Optional:
deadlineMs,retry,userAgent,interceptors,errorMapper.
Rust¶
WorktreeClient::new(endpoint: &str) -> Result<WorktreeClient>
endpoint: Full gRPC URL (for example,http://host:50062).
6.18.3. Key Methods¶
bind / bind_worktree¶
Python bind(agent_id: str, repo_id: str, worktree_id: str) -> BindResponse
JavaScript/TypeScript bind(agentId: string, repoId: string, worktreeId: string): Promise<{ ok: boolean; reason?: string }>
Rust bind_worktree(&mut self, agent_id: &str, repo_id: &str, worktree_id: &str) -> Result<()>
Response fields
ok(bool): Whether the bind succeeded.reason(string): Optional failure reason.
unbind / unbind_worktree¶
Python unbind(agent_id: str) -> UnbindResponse
JavaScript/TypeScript unbind(agentId: string): Promise<boolean>
Rust unbind_worktree(&mut self, agent_id: &str, worktree_id: &str) -> Result<()>
request_switch / requestSwitch / switch_worktree¶
Python request_switch(agent_id: str, target_worktree_id: str, requires_hitl: bool = False) -> StatusResponse
JavaScript/TypeScript requestSwitch(agentId: string, targetWorktreeId: string, requiresHitl: boolean): Promise<{ state: string; repo_id?: string; worktree_id?: string }>
Rust switch_worktree(&mut self, agent_id: &str, from_worktree_id: &str, to_worktree_id: &str) -> Result<()>
Response fields
state(string): Worktree state after the request.repo_id(string): Repository identifier (if available).worktree_id(string): Active worktree identifier (if available).
approve_switch / approveSwitch¶
Python approve_switch(agent_id: str, target_worktree_id: str, ttl_ms: int) -> StatusResponse
JavaScript/TypeScript approveSwitch(agentId: string, targetWorktreeId: string, ttlMs: number): Promise<string>
reject_switch / rejectSwitch¶
Python reject_switch(agent_id: str, reason: str = "") -> StatusResponse
JavaScript/TypeScript rejectSwitch(agentId: string, reason?: string): Promise<string>
status / worktree_status¶
Python status(agent_id: str) -> StatusResponse
JavaScript/TypeScript status(agentId: string): Promise<{ state: string; repo_id?: string; worktree_id?: string }>
Rust worktree_status(&mut self, agent_id: &str) -> Result<WorktreeStatusResponse>
Policy hooks (JavaScript/TypeScript)¶
JavaScript/TypeScript setPolicy(policy: WorktreePolicyHook): void
The default policy allows all binds, unbinds, and switches. Provide a custom WorktreePolicyHook to enforce allowlists or environment rules.
6.18.4. Usage Examples¶
import grpc
from sw4rm.clients import WorktreeClient
channel = grpc.insecure_channel("localhost:50062")
client = WorktreeClient(channel)
client.bind(agent_id="dev-agent-1", repo_id="repo-main", worktree_id="wt-feature-123")
status = client.status(agent_id="dev-agent-1")
print(status.state, status.worktree_id)
client.request_switch(
agent_id="dev-agent-1",
target_worktree_id="wt-hotfix-456",
requires_hitl=True,
)
client.approve_switch(
agent_id="dev-agent-1",
target_worktree_id="wt-hotfix-456",
ttl_ms=300000,
)
client.unbind(agent_id="dev-agent-1")
import { WorktreeClient } from '@sw4rm/js-sdk';
const client = new WorktreeClient({ address: 'localhost:50062' });
await client.bind('dev-agent-1', 'repo-main', 'wt-feature-123');
const status = await client.status('dev-agent-1');
console.log(status.state, status.worktree_id);
await client.requestSwitch('dev-agent-1', 'wt-hotfix-456', true);
await client.approveSwitch('dev-agent-1', 'wt-hotfix-456', 300000);
await client.unbind('dev-agent-1');
use sw4rm::clients::WorktreeClient;
let mut client = WorktreeClient::new("http://localhost:50062").await?;
client.bind_worktree("dev-agent-1", "repo-main", "wt-feature-123").await?;
let status = client.worktree_status("dev-agent-1").await?;
println!("{} {}", status.state, status.worktree_id);
client.switch_worktree("dev-agent-1", "wt-feature-123", "wt-hotfix-456").await?;
client.unbind_worktree("dev-agent-1", "wt-feature-123").await?;