Decisions

Why lnk is installed, split and updated the way it is.

The command line is "Link", but /bin/link already exists on macOS and Linux, and package names are hard to change, so the command, its plugins (lnk-<name>) and most environment variables (LNK_*) say lnk.

Why are plugins separate programs and not Cargo features?

A Cargo feature still ships every plugin in the release build. Separate programs make what you install exactly what runs, and one plugin can't break another. The cost is a few MB per plugin, and one localhost hop for lnk tunnel open llm, where the tunnel plugin runs the models plugin's lnk model serve.

Why do the core and every plugin share one version?

The core and every first-party plugin are built and signed in the same release, one archive per program (lnk-core-<target>, lnk-<plugin>-<target>). So lnk plugin add always matches the core, and lnk upgrade updates them together. A lnk built from source has no release of its version, so its plugins are built from source too, as lnk plugin add says.

By its own key, asked about once and pinned after. A harness Link doesn't ship is released and signed by its own repository, as anyone's adapter would be: Link's key signs only what Link's release builds (its plugins, and the OpenClaw, Hermes and DeepSeek Harness adapters), so a fix to an outside adapter ships when its repository releases, without Link vouching for code it didn't build. lnk keeps no list of trusted outside keys. The first add shows the key and asks, and every upgrade must be signed by the same key, so a repository taken over later can't push a release to the machines that added it.

Because the harness contract is the one seam built for it, with a version both sides check. A plugin from outside must answer it before it's installed, so lnk plugin add <url> can't install something that takes over a group or a name of Link's.

What does lnk uninstall delete?

The programs, and only the parts you pick. Removing a tool and deleting what it kept are different wishes: an agent's memory, your files and encrypted buckets' passwords can't be made again, so each is its own answer, and none is the default.

Why does each plugin say what it keeps?

So the core knows no plugin's files: it asks each installed plugin (lnk-<plugin> uninstall --parts --json) what it keeps, by part, and has it stop its services and delete what was picked (uninstall --delete <part>) before its program goes. A plugin from outside Link is only told to stop, once you've said yes: its parts are never offered, so what it keeps in ~/.config/lnk or ~/Link is rest. Parts of one name merge (the cloud adapters each keep some of clouds), and rest is what no installed plugin claims, which the core deletes itself: a plugin removed before keeps its files there. lnk plugin remove takes what needs a plugin with it, the reverse of what lnk plugin add brings.

Why does the relay fill in its version in install.sh?

latest in the releases repo has no version to compare with, so someone with that repo could point it at an older signed release with a known hole. The relay, a signed binary, is built at the version it releases with, so it fills its version into the script it serves, and the script refuses a latest older than that. The relay can be up a few minutes before its release is; the script then says to try again.

How does lnk say a newer release is out?

lnk up and lnk agent status, the commands a person runs to see where things stand, say it once a day, on stderr; lnk tunnel open says it when the relay tells it. A notice must never cost the command it rides on: it never waits on the network, never fails, and is quiet with --json, off a terminal and with LNK_UPDATE_NOTICE=off. So it tells only what the last lnk upgrade --check found, and starts the next in the background a day after the last, for the next command to tell. The version comes from the release's signed VERSION, as lnk upgrade reads it, so nobody but Link's release key can make every lnk say "upgrade".

Why is lnk --help the groups alone?

Every command and every plugin made it 122 lines, which no one reads past the first screen. It lists the groups, each in its own help's words, and the core's commands; lnk help <group> lists a group's commands, which are its plugin's own help, and lnk plugin list the plugins and which are installed. A word that is no group gets the one it most likely meant: a plural or a plugin's name (agents), a command of one group alone (login), or a group a typo or two away (agnet).