Conversations
Every conversation of Link Harness is a folder in your agent's files,
so it moves with your agent (lnk agent move) and stays when you
switch harness. What it costs and how much of it the model sees are
here too.
Read your conversations
Each chat's folder is named by its connection and chat, and
conversation.md in it is a copy to read, added to as the agent
answers (what it
holds).
ls ~/Link/Agents/main/Agent/chats/
cat ~/Link/Agents/main/Agent/chats/telegram-123456789/conversation.md
cat ~/Link/Agents/main/Agent/chats/slack-D0123ABCDEF/conversation.mdevents.jsonl
events.jsonl holds each message as a line of JSON, in order, only
ever added to: a line is never changed once written. It holds the
message's time, model, tokens as the provider counted them, and cost.
What its events hold
A tool's call is in the message that makes it, and its answer is a line
of its own, as is a summary of what left the window, and a command you
ran (/chat:create).
lnk agent chat show
lnk agent chat show <chat> prints a chat as conversation.md
holds it, however it's kept.
lnk agent chat show telegram:123456789Open and fork a Link conversation
History shows only the owner's messages and the agent's answers, with their original event numbers and UTC times.
lnk agent chat list --json
lnk agent chat show link:main --json
lnk agent chat fork link:main --before 7The fork
The fork copies every event before the selected owner message into a
fresh link:fork-… thread and prints its history. Its source remains
unchanged. Send the edited message to the new thread with lnk agent chat send --chat <name>.
What it copies
The copied prefix includes tool calls, results, provider thinking and signatures, summaries and window marks, and keeps the source's tool restrictions.
The provider's cache
OpenAI, Anthropic, OpenRouter, Bedrock through a model service, and other providers receive their usual cacheable prompt prefix; only the edited suffix changes. Provider cache lifetimes and minimum sizes still apply.
Separate chats
lnk agent chat start opens a new chat by default, with its own folder
under Agent/chats/. Follow-ups stay in that session. Select a named
chat with --chat <name> to continue it. Discord and Slack threads have
distinct chats too; replies in one thread share its context.
Saved memory across chats
Saved memory notes are shared by the agent. A fact only mentioned in a chat is transcript history until the agent saves it with its memory tool.
Keep them smaller, or in a database
How a new chat is kept is your agent's to say, in its spec
([storage] conversations).
[storage]
conversations = "compact"log
Link's. Each chat's folder holds events.jsonl and conversation.md,
read with cat, jq or lnk agent chat show. A spec that names
file, the agent's own folder, as lnk agent show --opinions prints it, keeps
each chat this way too.
compact
Each chat's folder holds events.zst, its messages in zstd frames, and
events.jsonl, those since the last frame, read with lnk agent chat show. compact compresses the event log to reduce disk use.
It reads the whole conversation for each turn, including requests for
its latest messages, so a long compact conversation needs more read and
decompression work than a log or store driver.
sqlite
A store driver is a plugin, lnk-<name> (its
contract),
named here by its name: each chat's folder holds an empty store.sqlite,
and the driver keeps its messages. Link's is SQLite: lnk plugin add sqlite, then conversations = "sqlite", and every chat of the agent is
in one file, Agent/chats/events.sqlite.
Where the driver runs
Its program runs outside Link harness's sandbox, behind the agent's store bridge, which takes each call only as the agent's own; memory runs it in memory's sandbox.
gcs
Off the machine, so any machine reading the bucket can take your
agent's next turn, it's Google Cloud Storage: lnk plugin add gcs, then
conversations = "gcs".
Its objects
Each message is an object of its own,
<prefix>/<owner>/<agent>/<chat>/events/<number>, written only if it
isn't there, so of two machines writing one number, one does; a turn's
lease is one object beside them, replaced only if it's still the one
read.
Its settings
Its settings are its environment: the bucket (LNK_GCS_BUCKET), where
in it (LNK_GCS_PREFIX), and a token (LNK_GCS_TOKEN or
LNK_GCS_TOKEN_FILE),
each.
Link harness starts with an environment of Link's own, which doesn't
carry them, so lnk-gcs runs under a harness started with them.
Reads and clocks
Reading a chat costs a request per message, eight at a time. A lease lapses by the clocks of the machines that took and renewed it, so they keep time (NTP).
Move the old ones
Changing the key moves nothing: each chat stays where it is, read there, and a new chat starts the new way. To move the old ones too, stop your agent and run:
lnk agent stop
lnk agent chat convertWhat isn't a message
Whatever the way, a chat's folder holds what isn't a message as files
of its own: the tools it was narrowed to (tools.json), and while a
turn runs, its lease (turn.json; a driver keeps that too) and whether
it was asked to stop. Memory searches a compact or driver's chat as it
does a log's: it makes the copy itself.
Through the storage bridge
Handed the storage bridge (its settings' storage, which lnk agent start gives it on every machine), it reads and writes whatever its
machine keeps off its folder (in SQLite, a bucket, or a box's store)
only through it. What's kept at file stays in its folder as above.
Nothing on the disk
The driver of that place keeps a chat's messages, its lease and the tools it was narrowed to, and whether a turn was asked to stop is held in memory, so nothing of such a chat is on the machine's disk. A turn whose tools it can't read fails, rather than offer every tool.
Messages from its schedules and subagents
Its scheduler (Link
Scheduler)
lets it start subagents and schedule messages to itself, on a
team
message its teammates (scheduler__send), and a background command it
started tells it how it ended.
As from them
Such a message comes as from them, never from you. It's kept with who
sent it, the model is told, and each line of it is quoted, so nothing
in it reads as yours: in conversation.md too, where it's headed
"Others", not "You". Its prompt names each teammate with its agent's ID
and purpose, and what of the team's folder it may reach.
Send another message while it answers
A message you send while it answers is kept at once, and then does what
its spec says in [turns] busy.
[turns] busy
steer is Link's: the answer takes the message in at its next step,
and goes on to answer it too, the reply coming on your first message.
queue answers it after, on its own. interrupt stops the answer
where it is, keeps it marked interrupted, cancels the tools still
running, and answers your new message.
After a crash
If the harness stops mid-answer, as in a crash or a restart, it finishes the answer when it starts again, and the answer reaches your chat within a minute. If Link's bridge stops instead, the harness finishes the answer all the same, and it reaches your chat once the bridge is back.
See what it costs
After each turn the harness reports numbers only: its tokens, its cost, its tool calls and failures, and how long it took to ask the model, to send the first piece of the answer and to finish it.
lnk measure --agent main # its turns, tokens, spend and times, over the last dayWhat a turn counts
Each turn counts only the answers and tool calls it wrote itself, even
when the next turn has begun by the time they're counted. They never
include the words. The measure plugin collects them
(Measure).
A message's cost
A message's cost is the provider's when it reports one, and otherwise
its tokens at the model's price (lnk model show).
How much it remembers
The model sees as much of the conversation as the spec sends, up to 128,000 tokens in Link's, so a long conversation never runs up a surprise bill.
Its window
What Link knows of a model sets its window (lnk model show),
and your own figures win. A model on your computer gets the window its
runtime says it runs with (A Model's
Details),
and a model nobody described gets 32,768
tokens. A [window] max you set is used as you set it, whatever Link
knows.
Past three quarters
Past three quarters of it, the oldest turns leave the window half of it at a time, so the provider's cache keeps the prompt cheap. What leaves is summarized, once the turn has answered, and the window starts with the summary, so a conversation keeps going however long it gets. The files keep everything.
Notes and the summary
Where the agent has notes (Link Memory's remember, with lnk agent memory start), the model saves what matters to them before it
summarizes. The summary is kept in the conversation's events, and never
sent to you.
[window] compact_at and save_notes
When it compacts, and whether it saves first, are [window] compact_at
and save_notes in the spec; compact_at = "never" lets the oldest
turns leave unsummarized.