Skip to content
Raster
Esc
navigateopen⌘Jpreview
On this page

Take input control

Hand the keyboard from an agent to a person, and back, without the two interleaving.

At most one session may send input to a machine at a time. That is what makes human takeover safe: taking control revokes the agent’s lease rather than interleaving with it, and every input carries the lease generation, so anything from the previous holder is dropped at the gateway rather than landing late.

Reads are never leased. A viewer that cannot type can still see.

The agent side

Nothing to do. Both SDKs open a session and acquire the lease on the first call that types or clicks, and renew it at half its TTL:

await machine.keyboard.type("hello"); // acquires the lease if it does not hold one
machine.holdsInput; // true

Taking it from a person

The lease route is on the contract client, since the SDKs manage the lease themselves:

const session = await client.api.sessions.create({
  body: { machine_id: machine.id, type: "human" },
  headers: {},
});

const lease = await client.api.inputLeases.acquire({
  params: { machine_id: machine.id },
  body: { session_id: session.id, ttl_seconds: 60, force: true },
});

force: true is what takes the lease from its current holder. Without it, an agent already driving the machine causes a conflict naming the holder — which is the right answer for a program, and the wrong one for a person who has decided to intervene.

What happens to the agent

Its next renewal fails, and it stops:

machine.holdsInput; // false
await machine.keyboard.type("more");
// RasterError: conflict — someone else holds the input lease

The SDKs never re-acquire a lease they lost. A lost lease means a person took over, and silently taking it back would put an agent and a person on the same keyboard, which is the one thing single-holder input exists to prevent. Catch the conflict and decide deliberately.

Handing it back

await client.api.inputLeases.release({
  params: { machine_id: machine.id },
  body: { session_id: session.id },
});

Closing the session drops the lease with it. The agent’s next input call acquires it again normally — the lease is free, so no force is needed.

Watching without taking

A screen stream opens a session but never acquires the lease, so a viewer cannot evict whoever is driving:

const stream = await machine.screen.stream();

Terminals are outside the lease entirely. Two people holding separate ptys is normal — the lease governs the desktop, where there is one mouse and one keyboard.

Further

Sessions and input control for the fence and how enforcement works, and the realtime gateway for the input channel itself.

Was this page helpful?