Decisions

Why each run call gets a sandbox of its own, which programs it offers, and how a command runs in the background.

Why does run run each call in a sandbox of its own, and file a session's in one?

So code runs only in a sandbox the agent's sandbox file makes. Link Harness runs no code: it calls run and file as tools outside its sandbox, through its proxy, and their calls run under lnk sandbox run with flags made from the file. Nothing a run call starts outlives it: a program left running or a file in /tmp is gone at the next call. file runs only Link file, which starts nothing, so one sandbox with the same flags serves a session's calls: a start costs tens of milliseconds, a call in a running one about a millisecond.

Which programs does run offer?

Those of the sandbox file's [commands] this computer has, found at a start on the system's PATH. The model is offered only those, by name, in the tool's schema and in its environment section, so it never tries Python where there is none, and a program it isn't offered is refused twice, by the tool and by the sandbox itself.

No asking

There's no asking: [commands] allows or refuses. Link's list is a shell, Python, Node, git, curl, jq and the usual file tools, so a script works as it would in a terminal; ["*"] allows any program, and [] turns run off. run is granted in Link's default sandbox file on your own machine, and a deployment's own default may leave it out.

Its PATH

The PATH it looks on is the system's: /usr/local/bin, /usr/bin, /bin and the sbin folders, and on a Mac /opt/homebrew/bin first. That is what a person's terminal finds without their own ~/bin.

Why does run take a program and its arguments, not a command line?

A program's name is what [commands] checks, and what the schema can list. Arguments go as they are, with no shell reading them, so a quoted path or a $ stays itself. A pipeline or a script is sh -c, where the shell is one of the programs it may run.

What does run reach?

What the sandbox file grants the agent: the internet through a proxy of the call's own when it has [internet], only its hosts unless "*", its tcp endpoints, its per_minute, its tools, and your home folder with read = ["~"]. It reads Home and the agent's instructions, skills and conversations, and writes only the folders [files] write names, so it can't rewrite a conversation. [localhost] and [browser] aren't given to it: they're for the harness's own servers and your browser, not a script's.

Why is a command stopped before its call times out?

A command stops a tenth before [tool.run] timeout, with everything it started, so what it printed so far comes back and the harness isn't left waiting on a call that can only time out. What it printed is kept to [tool.run] output for each of its output and its errors, its start and its end, which is where a program says what it's doing and how it ended.

Where is a team's folder for run and file?

file names it teams/<team>/ in its paths, beside the agent's own folders, and keeps to what's granted of it. run reaches it by its path, ~/Link/Teams/<team>/Shared, which its sandbox opens as granted. Link Harness tells its model both.

They're defined for a harness that keeps to the files folder's layout, which writes only its conversations there itself and leaves the rest to Link's tools. OpenClaw, Hermes Agent and DeepSeek Harness have files, a shell and code of their own, in the whole folder, so Link adds none. An agent whose sandbox is off has neither: code runs only in a sandbox.

Background commands

How a command runs in the background, when the agent is told it ended, and what happens to it when the agent stops.

How does a command run in the background?

Under a supervisor of its own, lnk-link-run supervise, which run starts and which is up only while its command runs, so an agent with none costs nothing. run's server ends with its turn, so it can't own a command that outlives it. The command runs in the sandbox a run__command call gets, in a process group of its own.

Its lock

The supervisor holds a lock on the command's record for its whole life, which the system releases however it dies, so a free lock always means it's gone. They're called background commands, not jobs: each is one of the agent's run calls, on its computer, in its sandbox.

Calls of run

They are four calls of the run tool (start, list, read and stop), not a tool of their own: a second tool would repeat the program, the sandbox, [commands] and the grant, and could disagree with the first. The defaults are opinions, so they're the spec's: 4 at once (a build, a test run, a server and a download), an hour's timeout (a long test suite), and output kept a day (a morning's builds read in the evening).

When is an agent told a background command ended?

When it ends, through the agent's bridge, as a message from run:<id> to the conversation that started it, so it's never taken as yours. It says how the command ended and its output's end, half of [tool.run] output as a command's end is kept.

At most once

It's told at most once. The record is marked before the message is handed over, and unmarked only when the bridge can't be reached, as a schedule is fired at most once. A message twice is worse than one lost in a crash, and run__list still shows how it ended.

Down a chain

The message is one further down a chain than the call that started the command, and a start as far down as [tool.scheduler] hops is refused, so a command started each time one ends stops at the same cap as messages.

What happens to a background command when the agent stops?

It ends. A command lives as long as its agent runs, so nothing is ever left running with no agent to hear of it, and nothing started under grants since changed runs on. A turn ending, run's server ending or the bridge restarting leaves it running, and run__list finds it again.

What ends it

Stopping or restarting the agent, its service or the computer ends it, recorded lost and told when the agent's back.

The sweep

A sweep, as the bridge starts and at each turn, finds one whose supervisor died without a word. It kills what's left of its process group only when it's surely the command's: on the same boot, its leader the one recorded or gone, since a group's id isn't reused while any of it runs. A move or a delete stops every one, and none is carried, since a process can't move.

Why is a background command's output in the files folder?

So the agent reads it with its own tools, grep over a build's log among them, not only a call at a time. It's background/<id>.out, which the agent's sandboxes read and none writes unless [files] says so, and an ending memory doesn't index, so a build's output doesn't crowd its search. It's written outside the sandbox through descriptors, never following a link. The record, which names the process group a sweep may kill, is kept outside the files folder, in the agent's folder, where nothing the agent runs can forge it.