Security

What lnk measure reads, keeps and sends, and what it never does.

Never content

  • A measure is a number of a measure Link names, of a unit named by an ID, a kind, its parent's ID and a name: an agent's or machine's name, or a process's program. There's no field for text. A name or ID is kept only if it's letters, digits and ._:/@-, at most 64 of them.
  • A process is named only by a program on Link's list (lnk and its plugins, bwrap, sandbox-exec, node, bun, deno, python, python3, uv); any other has no name, only its ID. What a system calls a process is what it chose: a script's file name, or anything it set itself, so a name taken from it could carry a conversation's words, or a sandbox's, to wherever measures go.
  • An agent's and the machine's names are yours, and go with their measures to your endpoint.
  • What a harness reports of itself is read as the same schema, and everything else is dropped as it's read: a measure Link doesn't name, a description, an attribute, text where an ID goes. So no message, prompt, file, tool argument or answer reaches what's kept, shown or sent, even from a harness that wrote one there. A harness may report only what it counts itself (a turn's tokens, cost, calls and times); what's measured from outside, it can't say.
  • An agent's tokens are counted by its sandbox's proxy, from the usage each model's answer gives as it passes, at most 4 MiB of a stream's event and one value of each usage key of a whole answer: six counts a proxy (requests, those without usage, and input, output, cached and cache-written tokens), never a word of a prompt or an answer. It reads only the events that name usage, and a whole answer's top-level usage, and keeps their numbers; a count past a billion tokens is taken for what isn't so, and counted as an answer without usage.
  • Link Harness derives its measures from a turn's events, numbers only. A test sends a turn with a known phrase, through a tool call and its answer, and fails if its measures hold any of it; another writes the phrase everywhere a harness could, and fails if anything kept, shown or sent holds it; a third sends the phrase to a model through an agent's proxy and back, and fails if anything counted, kept, shown or sent holds it.

What it reads

  • Each agent's processes, as this user, from outside: on Linux /proc and its service's control group, on a Mac libproc. Nothing runs inside an agent's sandbox, and no harness is asked anything.
  • The agents here, their processes and where their harnesses report, from lnk agent list --json --here; what each sandbox's proxy carried, from lnk sandbox traffic --json (bytes each way, and the tokens of its model's requests, never where to).
  • The file a harness reports to, in its home, which the harness can write: it's opened without following a link, only if it's a plain file, at most 4 MiB a look, and a line longer than 64 KiB is skipped. A line longer than a look reads is skipped too, to its end however many looks that takes, so it never holds up the lines after it.

What it keeps

  • ~/.config/lnk/measure/, only yours (700, files 600): the watcher's looks, a day of them, and a summary of each minute, 30 days; old files deleted whole. counted.json there keeps what each running proxy had counted at the last look, and which agents their proxy counts, so a restarted watcher counts none of it twice. Each agent's processes are shown and sent, not kept, unless your settings keep them (lnk measure settings --processes on).
  • Your endpoint's headers (an API key) are in settings.toml there, which only you read, and never shown: lnk measure export says how many there are. An endpoint's URL can't hold a password (https://user:key@host): lnk measure export refuses it and says to use --header. Where a URL is shown, it's without a password or a query, and the watcher's log names only the endpoint's host.
  • lnk uninstall --delete measures deletes the folder.

What it sends

  • Nothing, until you name an endpoint (lnk measure export <url>). Then every look goes there as OTLP, with your headers, at most 10 seconds a request; http:// sends it in the clear, so use https:// for an endpoint off this machine. Local Link never receives it.