Connect a second computer¶
In this tutorial you connect a laptop to your Jezero server. The laptop gets its own key, the Claude Code plugin sends its sessions to the server when they end, and you watch the first one become an item you can search from either computer.
Before you start¶
You need:
- A Jezero server you administer, reachable from the laptop at
https://YOUR-JEZERO, withrequire_auth = true. Run Jezero as a service sets one up, including the address other computers use. The server is a checkout of the repository, as in Your first library; server commands run in that folder (~/jezerobelow). - An API key for the summarizer model, used in step 8.
- A laptop with
python3(3.9 or newer),curland Claude Code.
Each step says where it runs: on the server or on the laptop.
1. Build the client bundle (on the server)¶
The laptop downloads the client and the plugins from your server. Build the bundle once in the checkout:
You should see:
built /home/me/jezero/dist/client, /home/me/jezero/dist/jezero-client.tar.gz and plugins/ (version 0.5.1)
The server offers the file at /client/jezero-client.tar.gz without a key: it is the same
public code as the repository. See Serve the plugin
bundle.
2. Get the client (on the laptop)¶
Download the bundle and unpack it in ~/.jezero-src:
mkdir -p ~/.jezero-src
curl -fsSL https://YOUR-JEZERO/client/jezero-client.tar.gz | tar -xz -C ~/.jezero-src
python3 ~/.jezero-src/jezero-client/jezero_client.py --version
You should see:
jezero_client.py is the client core: one Python file with
no dependencies, shared by every plugin.
3. Create the laptop's key (on the laptop)¶
You should see:
Device key created. The key stays in /home/me/.jezero; the server only keeps its SHA-256 fingerprint.
Ask the Jezero admin to approve it with:
jezero device approve laptop SHA256
The key is in ~/.jezero/token, readable only by you, and the server address in
~/.jezero/client.json. The printed SHA256 is the key's fingerprint, not a secret:
send the whole jezero device approve line to the server's admin, which is you.
Check the key before it is approved:
You should see:
key: /home/me/.jezero
server https://YOUR-JEZERO: HTTP 401 {"ok":false,"error":"unknown token"}
queued sessions: 0
rejected uploads: 0
The first line is the folder that holds the key. The 401 is expected: the server does not know the key yet. Sessions the laptop tries to upload before the approval wait in its queue.
Note
A computer whose sessions must not reach Jezero, such as the server itself (its
connectors already read its sessions), gets a key with init ... --no-upload. The
printed line then ends in --read-only, and the plugins there only search. If init
says the computer is already set up, it already has a key (for example from the
first tutorial): add --force to replace it.
4. Approve the laptop (on the server)¶
Run the line the laptop printed, with uv run in front:
You should see:
approved laptop; the server picks up the new key within a second (backup: /home/me/jezero/jezero.toml.bak-20261022T034500Z)
The command appended to jezero.toml a client for the laptop:
[[clients]]
# Device laptop: reads Jezero and uploads its sessions to the inbox.
name = "laptop"
token_sha256 = "SHA256"
sources = ["agent-*"]
upload = true
sources = ["agent-*"] lets the laptop read every agent source, its own included.
upload = true lets it send session files to its own folder of the
inbox, data/inbox/laptop/. The command also added five
connectors, one per agent, that read that folder:
agent-claude-code-laptop, agent-codex-laptop, agent-opencode-laptop,
agent-hermes-laptop and agent-antigravity-laptop. They start with enabled = false.
The running server reads the change by itself: there is nothing to restart. uv run
jezero device list shows the laptop with its connectors.
5. Check the connection (on the laptop)¶
You should see:
key: /home/me/.jezero
server https://YOUR-JEZERO: HTTP 200 {"ok":true,"device":"laptop","version":"0.1.0.dev0"}
queued sessions: 0
rejected uploads: 0
6. Set up Claude Code (on the laptop)¶
Install the Jezero plugin. It brings the MCP server, the hooks and the jezero skill:
You should see:
...
✔ Successfully added marketplace: jezero (declared in user settings)
Installing plugin "jezero@jezero"...✔ Successfully installed plugin: jezero@jezero (scope: user)
Check that Claude Code reaches Jezero:
You should see, among your other servers:
plugin:jezero:jezero: python3 /home/me/.claude/plugins/.../core/jezero_client.py mcp --agent claude-code - ✔ Connected
The plugin's MCP server is the client core's bridge: it runs on the laptop and adds the
key from ~/.jezero to each request, so Claude Code's configuration never holds the key.
The plugin's hooks give every session a short
protocol and recent work of its project, add related past work
to the first prompt, and upload the session's transcript when it ends. A hook never
blocks Claude Code: its network calls time out after a few seconds, and errors go to
~/.jezero/client.log.
7. Work one session (on the laptop)¶
Start Claude Code in a project, for example ~/projects/atlas:
Give it a real task, let it finish, and leave with /exit. When the session ends, the
plugin queues its transcript and uploads it in the background.
Check that it left the laptop:
You should see queued sessions: 0. A session that could not be sent (offline, server
down) stays queued and goes out with the next one.
On the server, the transcript is now in the laptop's inbox, next to a .project file that
holds the project the laptop detected:
You should see:
data/inbox/laptop/claude-code/projects/-home-me-projects-atlas/SESSION-ID.jsonl.project
data/inbox/laptop/claude-code/projects/-home-me-projects-atlas/SESSION-ID.jsonl
The server's log shows the upload as a PUT /inbox/v1/claude-code/projects/... request
with 200 OK.
8. Turn the session into an item (on the server)¶
The inbox holds the raw transcript. A connector reads it, the summarizer writes the item, and the library stores it. That last part calls a language model, so it needs the summarizer.
- Ask what a run would do, without calling the model:
Right after the upload you should see "deferred_sessions": 1:
{"connector": "agent-claude-code-laptop", "docs": 0, "unchanged": 0, "stored": 0, "failed": 0, "deferred_sessions": 1, "redactions": 0, "input_chars": 0, "input_tokens": 0, "output_tokens": 0, "pruned": 0, "dry_run": true, "sample": false, "note": "nothing to summarise (1 still active, deferred)", "errors": [], "warnings": []}
A connector waits until a session has been quiet for 30 minutes (the option
settle_minutes), so it never summarises a session that is still growing. The clock
starts at the upload. Come back after 30 minutes and run the same command. You should
see the session counted as work:
{"connector": "agent-claude-code-laptop", "docs": 1, "unchanged": 0, "stored": 0, "failed": 0, "deferred_sessions": 0, "redactions": 0, "input_chars": 1208, "input_tokens": 0, "output_tokens": 0, "pruned": 0, "dry_run": true, "sample": false, "note": null, "errors": [], "warnings": []}
input_chars is the size of what would go to the model, after cleaning; yours
differs.
- Give the server a summarizer, if it has none. Add to
jezero.toml, with a small, fast model of your provider:
Put the key in a file named .env next to jezero.toml (git ignores it):
Check that Jezero sees it:
You should see, at the end:
Other providers and options are in Configuration.
- Run a pilot on the newest sessions:
You should see "stored": 1:
{"connector": "agent-claude-code-laptop", "docs": 1, "unchanged": 0, "stored": 1, "failed": 0, "deferred_sessions": 0, "redactions": 0, "input_chars": 1208, "input_tokens": ..., "output_tokens": ..., "pruned": 0, "dry_run": false, "sample": true, "note": null, "errors": [], "warnings": []}
Without a summarizer, the run stops with
"error": "SummarizerError: summarizer.model is not set in the config" as soon as a
session is ready to summarise.
- The pilot (
"sample": true) changes nothing in the connector's state: no cursor, no last run. Turn the connector on so every run reads the laptop's new sessions: injezero.toml, find the[[connectors]]block withname = "agent-claude-code-laptop"and change itsenabled = falsetoenabled = true. Then run every enabled connector once:
You should see the session reported as "unchanged": 1: the pilot already stored it,
and Jezero summarises a session again only when its content changes.
From now on, jezero run --due on a timer collects the laptop's sessions without you. See
Run Jezero as a service.
9. Search it (on both computers)¶
On the server, jezero search sees every source. Search with a few distinctive words of
your session:
You should see a line with the new source and the project:
The title, summary and atoms are what the summarizer wrote; jezero show 4 (or the app)
shows them.
On the laptop, Claude Code finds the item too. Start a new session in any folder and ask
about the work you did, for example "What did we change in atlas today? Check Jezero."
The agent calls search and cites the item id.
To search from the laptop's terminal, install the jezero command there. It reads with
the laptop's key, so it sees the same sources as its agents:
You should see:
If jezero is not found, add ~/.local/bin to your PATH. The laptop reads only
agent-* sources: if the server holds the demo items of the first tutorial, they do not
appear here.
What you built¶
- A laptop with its own key in
~/.jezero, approved on the server as the clientlaptop. - Claude Code on the laptop with the Jezero MCP server, the hooks and the skill.
- A connector,
agent-claude-code-laptop, that turns the laptop's uploaded sessions into items.
Next steps¶
- Connect an agent: Codex, OpenCode, Hermes Agent and Antigravity on
the same laptop, and older sessions with
jezero_client.py backfill. - Manage computers and keys: read-only computers, narrower sources, and removing a key.
- Troubleshooting: when a session does not arrive or a key is refused.
- Command reference: every command of the client core.