Machine

Machines: an always-on computer for agents that should never sleep.

box = noclick.Machine.from_name("support-box", create_if_missing=True, size="medium", region="eu",
                                max_monthly_usd=120)
support = noclick.Agent.from_name("support", create_if_missing=True, instructions="...",
                                  harness="claude_code", model_connection="claude", machine=box)
print(box.exec("df -h /").stdout)

An agent on a machine runs its harness there instead of in a sandbox per conversation: nothing is reaped when it goes quiet, and there's no per-minute sandbox charge, only the machine's flat monthly price. Each conversation gets its own container on the machine, so threads never see each other's files. Model and tool calls go through NoClick's credential proxy with temporary keys: your real keys are never on the machine. NoClick manages its image and updates, restarts it if it fails (rebuilding it on a new host from its last backup if it must), and attached volumes outlive it.

class Machine

Invite-only beta.

An always-on computer of a fixed size in one region, billed a flat monthly price (a thirtieth of it a day while it exists, running or stopped). Agents created with machine run their harness on it, each conversation in a container of its own; exec, files and expose reach the machine itself.

Attributes
idstring
namestring
sizeMachineSizeName

small, medium or large (Machine.sizes()).

cpunumber | null

vCPUs (hardware threads).

memoryGbnumber | null
diskGbnumber | null
regionRegionName | null

The region it runs in, fixed when it was created.

statusMachineStatus
statusReasonstring | null

Why it's stopped or failed, or why it restarted.

monthlyUsdnumber | null

What it costs a month, in US dollars, running or stopped.

maxMonthlyUsdnumber | null

The most you agreed it may cost a month.

networkboolean | string[] | null

What its own commands may reach: true (anywhere the machines usage policy allows) or the hosts.

volumesRecord<string, string>

The volumes it mounts: { path: volume id }.

agentCountnumber | null

How many agents run on it.

imagestring | null

The NoClick-managed image it runs, with its harness versions.

restartsnumber | null

How many times it restarted after failing, ever.

lastRestartAtDate | null
userIdstring | null
createdAtDate | null
filesMachineFiles
portsMachinePort[]

The ports it serves.

consoleUrlstring | null

This machine in the developer console (null off the hosted API).

sizesstatic

static sizes(options?: { client?: NoClick }): Promise<MachineSize[]>

What a machine can be, smallest first.

Parameters
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

Each size's name (what size= takes), its processors, memory and disk, its monthly_usd and about how many conversations can work on it at once.

createstatic

static create(name: string, options: MachineCreateOptions): Promise<Machine>

Start an always-on machine called name (unique to its user; a taken name throws Conflict with existingId), refused with PriceExceeded if its size costs more than maxMonthlyUsd. An account's first machine needs its company vetted by NoClick (ActionRequired until it's approved).

Parameters
namestringrequired
options.sizeMachineSizeName

One of Machine.sizes(); small by default.

(default "small")
options.regionRegionName

Where it runs (regions()), for good; omitted, your account's default region, else us-east.

options.volumesRecord<string, VolumeRef>

Volumes it attaches, by absolute path: each conversation sees a volume as it was when its turn started and saves its writes when the turn ends.

options.networkboolean | string[]

What the machine's own commands may reach: true (anywhere the machines usage policy allows: no mail ports, mining pools or private addresses) or a list of hosts (HTTPS to them, "*.github.com" for subdomains, and name lookups).

options.maxMonthlyUsdnumberrequired

The most its size may cost a month; above it nothing starts (PriceExceeded).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The machine, provisioning until it's ready (running).

fromNamestatic

static fromName(
  name: string,
  options?: CallOptions & Partial<MachineCreateOptions> & {
    createIfMissing?: boolean;
  },
): Machine

A lazy reference to the machine called name. With createIfMissing (and maxMonthlyUsd) it's started on first use, and an existing machine whose size, volumes or network differ is changed to match (a new size restarts it); its region is fixed, so one elsewhere throws Conflict naming its region.

Parameters
namestringrequired
options.createIfMissingboolean
options.sizeMachineSizeName

One of Machine.sizes(); small by default.

options.regionRegionName

Where it runs (regions()), for good; omitted, your account's default region, else us-east.

options.volumesRecord<string, VolumeRef>

Volumes it attaches, by absolute path: each conversation sees a volume as it was when its turn started and saves its writes when the turn ends.

options.networkboolean | string[]

What the machine's own commands may reach: true (anywhere the machines usage policy allows: no mail ports, mining pools or private addresses) or a list of hosts (HTTPS to them, "*.github.com" for subdomains, and name lookups).

options.maxMonthlyUsdnumber

The most its size may cost a month; above it nothing starts (PriceExceeded).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A machine that loads (or is started, or brought in step with your definition) the first time it's used. Nothing is sent yet.

fromIdstatic

static fromId(machineId: string, options?: CallOptions): Machine

A lazy reference to a machine by id.

Parameters
machineIdstringrequired
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
Returns

A machine that loads the first time you read a field. Nothing is sent yet.

getstatic

static get(machineId: string, options?: CallOptions): Promise<Machine>

Load a machine by id now; an unknown id raises noclick.NotFound.

Parameters
machineIdstringrequired
options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The machine, loaded.

liststatic

static list(options?: ReadOptions & { limit?: number }): Promise<Machine[]>

The current user's machines (the account's own outside asUser, or those userFilter covers).

Parameters
options.limitnumber

Return at most this many.

options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

Every matching machine, newest first, fetched page by page.

listPagestatic

static listPage(options?: ReadOptions & PageOptions): Promise<Page<Machine>>

One page of machines; pass nextCursor back as cursor.

Parameters
options.cursorstring | null

The next_cursor of the page before; omit it for the first page.

options.limitnumber

Return at most this many.

options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A page whose data holds the machines and whose next_cursor is None on the last page.

exec

exec(
  command: string,
  options: ExecOptions & { background: true },
): Promise<Operation<ExecResult>>

Run a shell command on the machine itself (not in a conversation's container): timeoutS is 60 by default, at most 90; { background: true } returns an Operation, for up to an hour.

Parameters
commandstringrequired
options.backgroundbooleanrequired

Return at once with an Operation whose wait() resolves to the ExecResult.

options.timeoutSnumber

Seconds before the command is stopped: 60 by default, at most 90, or 3600 with background.

Returns

What the command printed and how it exited, or with background=True an Operation whose wait() gives that result.

expose

expose(port: number, options?: { public?: boolean }): Promise<MachinePort>

Serve port at an HTTPS URL on NoClick's domain: private (an API key with the machines scope, which the app never sees) unless public.

Parameters
portnumberrequired
options.publicbooleandefault false
Returns

The port's url.

closePort

closePort(port: number): Promise<void>

Stop serving port; its URL stops answering.

Parameters
portnumberrequired

agents

agents(): Promise<JsonObject[]>

The agents that run on it, as their API rows (Agent.fromId(row.id) for the object).

Returns

Each Agent, loaded.

update

update(
  changes: {
    name?: string;
    size?: MachineSizeName;
    volumes?: Record<string, VolumeRef>;
    network?: boolean | string[];
    maxMonthlyUsd?: number;;
  },
): Promise<this>

Rename it, change its size, volumes, network or price ceiling. New volumes and network apply without a restart (each conversation's from its next turn). A larger size restarts it once running turns finish (updating); the new price applies from the next day. A smaller size moves a running machine to a new host, since no host shrinks a disk in place: its user's home is copied over and each conversation loads its files from where they're saved, a longer restart (what's on its disk must fit the smaller one; a move that fails leaves it on its old host).

Parameters
changes{ name?: string; size?: MachineSizeName; volumes?: Record<string, VolumeRef>; network?: boolean | string[]; maxMonthlyUsd?: number; }required
Returns

This machine, updated.

restart

restart(): Promise<Operation<Machine>>

Restart it now (running turns fail as interrupted); its disk and volumes are kept and a machine.restarted event follows. Resolves to the machine.

Returns

An Operation whose wait() gives the machine, running again.

stop

stop(): Promise<this>

Stop it: its agents take no turns until start(). It's still charged.

Returns

This machine, stopped.

start

start(): Promise<this>

Start a stopped machine. One stopped because the balance couldn't pay it is charged what it owes first (PaymentRequired while it can't).

Returns

This machine, provisioning until it's running.

delete

delete(): Promise<void>

Delete it with its disk (attached volumes stay); refused with Conflict while agents run on it.

MachineSizeinvite-only beta

interface MachineSize

Invite-only beta. One of Machine.sizes(): its processors, memory, disk and flat monthly price.

Attributes
nameMachineSizeName

What size= takes: small, medium or large.

cpunumber

vCPUs (hardware threads), as hosts sell them.

memoryGbnumber
diskGbnumber

The machine's own disk.

monthlyUsdnumber

Its price per month in US dollars, whatever it runs and whether it's busy.

workingConversationsnumber

About how many coding-agent conversations can work on it at the same moment.

rawJsonObject

The response JSON exactly as the API sent it.

MachinePortinvite-only beta

interface MachinePort

Invite-only beta. A port a machine serves; a private one asks for an API key with the machines scope, a public one answers anyone.

Attributes
portnumber
urlstring
publicboolean
rawJsonObject

The response JSON exactly as the API sent it.

MachineFilesinvite-only beta

class MachineFiles

Invite-only beta. machine.files: read and write files on the machine's own disk.

write

write(
  path: string,
  data: string | Uint8Array | ArrayBuffer | Blob,
): Promise<void>

Write data (bytes, or text as UTF-8) to path (relative paths are under /home/noclick).

Parameters
pathstringrequired
datastring | Uint8Array | ArrayBuffer | Blobrequired

read

read(path: string): Promise<Uint8Array>

Read the file at path; a missing file raises noclick.NotFound.

Parameters
pathstringrequired
Returns

The file's bytes, exactly as stored.