tiroir
tiroir work takes an agent session that runs on a tiroir hub and gives you your own copy of it
on your laptop, in Claude Code, with the whole conversation so far. You carry on from where it
stands, under your own name, with your own tools.
It works with a tiroir hub: a server that shows shared markdown documents ("sheaves") and keeps the transcripts of the agent sessions working on them. Without such a hub this command has nothing to do.
What you need
- macOS, Linux or Windows;
- uv (or pipx), to run the command;
- Claude Code, with the
claudecommand on yourPATH; - an account on the hub's front, and a sheaf that is open to you.
Run it
Copy the command from the sheaf's page (☰ menu, Work on this, Fork to your machine), or type it with the sheaf's address:
uvx tiroir work https://hub.example.com/list/acme/site/plan.md
uvx tiroir work https://hub.example.com/list/acme/site/plan.md --cwd ~/work/acme-site
uvx tiroir work https://hub.example.com/list/acme/site/plan.md --dry-run
To keep it installed instead: uv tool install tiroir, then tiroir work <address>.
What it does, on your laptop only
- Downloads the transcript of the sheaf's live session from the hub, as you. Only a sheaf that is open to you works.
- Stores it in
~/.claude/projects/<your folder>/<session id>.jsonl, readable by you alone, or under$CLAUDE_CONFIG_DIR/projects/when you set that variable for Claude Code (a relative value is taken from the folder you work in, as Claude Code takes it). It replaces an older copy when the new transcript extends it (the session grew since your last fork). Claude Code needs exactly one copy of a session, so any other copy of it, in this folder or another one (sheaves of one project can share one session), is kept aside once the new one is written, as<session id>.jsonl.kept-<UTC time>in its own folder, and named in one line. No other copy is deleted, and a fork you made earlier keeps working: it holds its own copy of the conversation. Claude Code no longer reads a kept file; delete it yourself when you no longer want it. - Writes on the sheaf that you forked it, from which machine, with the new session's id.
- Starts
claude --resume <id> --fork-session --session-id <new id>in the folder you gave with--cwd(by default the folder you are in). That is a new session: your messages go to your copy, never back to the hub's. On macOS and Linuxtiroir workbecomes Claude Code; on Windows it starts Claude Code and waits until you leave it.
What it does not do: it never runs anything on the hub's machine, never changes the session it
copied, and never sends your messages anywhere but your own Claude Code. --dry-run downloads and
stores the transcript, records nothing on the sheaf, and prints the claude command instead of
starting it.
The transcript holds everything the session saw, including tool results: keep it as private as the sheaf itself.
Your sign-in code
tiroir work signs in to the hub with a sign-in code the hub gives you. A code works for one
sheaf, once, for 10 minutes. Three steps:
- On the sheaf's page, open ☰ > Work on this and click Get a sign-in code.
- Paste the
tiroir workcommand into your terminal and run it. - At the prompt
Sign-in code (Work on this > Get a sign-in code):, paste the code and press Enter. Nothing shows while you paste: that is on purpose.
The code never goes on the command line or into a file. To give it without the prompt (in a
script), put it in a variable without echoing it, never as TIROIR_SIGNIN_CODE=… tiroir work,
which stays in your shell history:
read -s TIROIR_SIGNIN_CODE; export TIROIR_SIGNIN_CODE
tiroir work sends the code only to a front it knows: thinkingtoo.tiroir.me, and any host you
list in ~/.config/tiroir/config.toml:
fronts = ["chat.example.com"]
For any other host it stops before anything is sent. It removes TIROIR_SIGNIN_CODE before it
starts Claude Code, and never prints the code.
A code is spent once the fork is recorded, or refused. When tiroir work says the code is no
good, get a new one from Work on this.
The session token, for now
Until the sign-in code is live on your hub, tiroir work still signs in with the session token of
your account on the front, when you have one: the file ~/.config/tiroir/front-token (mode 0600)
or the variable TIROIR_FRONT_TOKEN. It is sent as a cookie, only to the sheaf's own host, and
never printed. A TIROIR_SIGNIN_CODE that is set wins over it. While it is used, tiroir work
says so in one line and asks for no code. This path will be removed; delete
the file once your codes work.
When something is refused
tiroir work says why in one sentence and exits with code 2. The reasons:
- the sign-in code is no good (mistyped, spent, or older than 10 minutes): get a new one;
- the sheaf is not open to you with this code, or has no session on the hub;
- the host is not a front
tiroir workknows; - the address is not a sheaf's;
- the token file is readable by others (macOS and Linux);
- a link sits under the session's file name.
When the hub refuses to record the fork, tiroir work gives the hub's reason. The transcript is
then already on your laptop, and Claude Code is not started: run the same command again once the
reason is fixed, with a new code.
Development
uv run --extra dev pytest
uv run --extra dev ruff check . && uv run --extra dev ruff format --check .
The tests run the command against a fake hub on 127.0.0.1 and never touch your real
~/.claude.
License
MIT, see LICENSE.
Metadata
Release files for tiroir 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tiroir-0.2.0.tar.gz | 27.6 kB | Without provenance | Details for tiroir-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tiroir-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for tiroir-0.2.0-py3-none-any.whl |
Total release size: 41.4 kB
Release files / tiroir-0.2.0.tar.gz
| Download URL | tiroir-0.2.0.tar.gz |
|---|---|
| Size | 27.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4e93e1dba27f430195e1c13bcf5a1bb71794c838e8eba68f58463a66e550c5bf
|
|
BLAKE2b-256 checksum How to use checksums |
b35fad45d3e147c29e641b0061d6f253b6a41f13cc19e15295c9aff78882aaae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / tiroir-0.2.0-py3-none-any.whl
| Download URL | tiroir-0.2.0-py3-none-any.whl |
|---|---|
| Size | 13.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dad137e667df7e92ae0351bea96a9a594075f95a8d1f257c6e205a7b34ce9c9f
|
|
BLAKE2b-256 checksum How to use checksums |
69a510c647eaf9243c60bffc7a5b90251e98f122e835326f4a57b0d7c3a19b24
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for tiroir 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.