Pre-release: not yet published to PyPI. Do not use it to upload sessions yet; use the official a4sx CLI from session-exchange.com.
a4sx
Repository · Issues · Changelog
Save your coding-agent sessions to a private library, and resume Claude Code sessions on any machine
as a new local session. a4sx is the command-line tool and Python SDK for
session-exchange.com.
- Push a session to your private library: Claude Code and Codex CLI transcripts, and Grok Build session folders. A client-side scrub (secrets and personal data, the same rules as the a4sx CLI and server) runs before anything leaves your machine, and push tells you exactly what it changed.
- Resume a saved session anywhere:
a4sx resume <name>writes it as a fresh Claude Code session in the directory you are in and startsclaude --resume. Your saved copy never changes. - Lineage: a session you resumed and push again is recorded as a child of the one it came from,
so
a4sx listshows your library as a tree. - Search published sessions and add the ones you are entitled to to your library.
- SDK: everything the command does is in
a4sx.sdk, for your own scripts, plugins or MCP servers.
Python 3.9+, no dependencies (stdlib only).
Private library: the sessions saved under your a4sx account on session-exchange.com. Its entries are not listed in the marketplace and not returned by public search; they are listed, fetched, versioned and deleted through the a4sx API with your own sign-in (or an agent key you create). Listing a session in the marketplace is a separate step in the web app, with a review. "Private" describes who can list and fetch an entry through a4sx; the server stores the bytes you upload, after scrubbing them again.
| Harness | push, list, search, fetch | resume |
|---|---|---|
| Claude Code | yes | yes |
| Codex CLI | yes | not yet |
| Grok Build | yes | not yet |
resume refuses a session recorded with another harness; it never turns one into a Claude Code
session. Such a session stays in your library, and a4sx fetch downloads its original file.
Quickstart (5 minutes)
$ pipx install a4sx # or: pip install --user a4sx
$ a4sx login # opens your browser; on SSH or headless it prints a link for your phone
signing in to https://session-exchange.com
...
signed in. your private library on https://session-exchange.com is ready.
Save the Claude Code session you worked in most recently:
$ a4sx push --latest --label my-work
a4sx push: client scrub: 2 lines changed (github_token: 1, homedir: 3) — lines 4, 212
a4sx push: local sha256 5d1c…
a4sx push: uploaded sha256 9a07…: DIFFERS from the local file (the client scrub rewrote it). …
{ "collection": "my-work-…", "status": "staged (private)", … }
Not sure what would leave your machine? a4sx push --latest --dry-run shows which lines the scrub
would change, uploads nothing and needs no sign-in.
On any machine, in the folder you want to work in:
$ a4sx list
# name created updated vers ctx title
1 my-work 2026-10-05 09:12 2026-10-05 17:40 3 84k Fix the flaky upload test
$ a4sx resume my-work
a4sx: new local session 0b6f… seeded from my-work-… (in /home/me/app)
resume starts claude --resume <new-id>. Use --no-launch to only write the session, and
pass arguments to claude after --, e.g. a4sx resume my-work -- --model opus.
When you are done, a4sx push --latest saves your continuation; it is linked to my-work in the tree.
Other harnesses push the same way; the server recognises the format:
$ a4sx push ~/.codex/sessions/2026/10/14/rollout-….jsonl --label codex-run # Codex CLI
$ a4sx push ~/.grok/sessions/<project>/<session-id>/ --label grok-run # Grok Build: the folder
For a Grok Build session folder only its updates.jsonl is uploaded. Pushing one of the folder's other
files (chat_history.jsonl, system_prompt.txt, ...) is refused.
Commands
| Command | What it does |
|---|---|
a4sx login [--no-browser] [--provider github] |
Device login in the browser. --token - stores a token you already have (read from stdin). If the account still has to confirm an e-mail address, it says so and sets up the library on the next login. |
a4sx logout |
Delete the stored token and end the session on the server. |
a4sx push FILE|FOLDER | --latest [--label L] [--into ID] [--dry-run] [--fail-on-scrub] [--keep-pii] [--no-scrub] |
Save a session (a Claude Code or Codex CLI .jsonl, or a Grok Build session folder; --latest picks the newest local Claude Code session). --into adds a new version of a saved session. --fail-on-scrub exits 3 if the scrub would change anything. If the server is busy scrubbing other uploads, push waits as long as it asks and sends the same push again. |
a4sx list [--sort updated|created|name] [--json] |
Your library, as a lineage tree. |
a4sx resume NAME [--cwd DIR] [--from-compact] [--no-launch] |
Continue a saved Claude Code session as a new local session. A marketplace listing recorded with another harness is refused before it is added to your library. |
a4sx search [WORDS…] [--library] [--tag T] |
Search published sessions (no sign-in needed), or your own library. |
a4sx acquire ID |
Add a published session you are entitled to (free, bought, granted) to your library. Never buys anything. |
a4sx fetch NAME [-o PATH] |
Download a saved transcript without resuming it (for another harness: its original file). |
a4sx tokens NAME|FILE [--window 1m] |
Token footprint against a context window. |
a4sx squash NAME |
Recipe to compact a long session into a resumable tip. |
a4sx craft SRC… --label L |
Compile one resumable base session from several sessions (pre-scrubbed like push). |
a4sx delete NAME |
Permanently delete a saved session; every stored version is erased. |
a4sx whoami, a4sx version, a4sx completion bash |
NAME is a saved session's label, its id, or a unique part of its title.
Configuration
| Setting | Default |
|---|---|
| Server | --base URL (before or after the command), else $A4SX_BASE, else the server you signed in to last, else https://session-exchange.com. Plain http:// is accepted for localhost only. |
| Session token | Stored per server by a4sx login; each server needs its own login. $A4SX_SESSION supplies one for this shell, for https://session-exchange.com only, or for $A4SX_SESSION_BASE if you set it. |
| Config dir | $A4SX_CONFIG_DIR, else %LOCALAPPDATA%\a4sx on Windows, else $XDG_CONFIG_HOME/a4sx or ~/.config/a4sx. |
| Claude Code dir | $CLAUDE_CONFIG_DIR, else ~/.claude. |
| Hints | A4SX_HINTS=0 turns off the next: hints on stderr. |
| Upload timeout | Scales with the size; A4SX_UPLOAD_TIMEOUT_S overrides it. |
| Headless login | A4SX_NO_BROWSER=1 or --no-browser. |
What leaves your machine
pushuploads the transcript after the client scrub (unless--no-scrub). It reports the changed lines, the rules that fired (never the values), and the sha256 of your file and of the upload. The server scrubs again before storing. Both are pattern-based backstops, not a guarantee: review what you push (--dry-runshows every change, with line and column).- The client scrub applies the a4sx CLI's rules, which are the server's: API keys and tokens
(Anthropic, OpenAI, xAI, Groq, Google, GitHub, Slack, AWS, Stripe, z.ai, a4sx tokens, JWTs), bearer,
basic and digest auth, AWS request signatures, credentials in URLs, private keys, secret-named
assignments, command-line passwords (
mysql -p,curl -u,--password, ...), Google Sheet ids, and personal data: e-mail addresses, IP and MAC addresses, home-directory user names (Linux, macOS, Windows, WSL, Git Bash, Claude Code project-folder names, URL-encoded paths), host names under session-exchange.com and key-file paths. Values become markers such as[REDACTED]or[REDACTED-USER]; JSON stays valid.--keep-piikeeps the personal-data group and removes the rest. The rules are vendored from the CLI bytools/vendor_scrub.py; CI checks them against the published CLI. - Your session token is stored with mode 0600, bound to the server that issued it, and is only
ever sent to that server, as an
Authorizationheader that is not forwarded on redirects. Pointing a4sx at another server (--base,$A4SX_BASE) never sends it your token; that server needs its owna4sx login. The sign-in links a server sends are only shown or opened if they are on that server's own origin. The token is never printed or logged. - Resumed sessions are written with mode 0600. A session from another author, and anything you
derive from it (a continuation you push, a
crafted base), is treated as untrusted input:resumekeeps Claude Code's permission prompts on unless you pass--trust-base. searchandversionsend no token.
SDK
from a4sx.sdk import Client, NotFound
client = Client() # same server and token resolution as the CLI
# sign in (device login); show the link and code however you like
client.login(on_pairing=lambda login, restarted: print(login.login_url, login.user_code))
res = client.push_file("session.jsonl", label="my-work") # pre-scrubbed, retried safely
print(res.response["collection"], res.scrub.summary())
rows = client.list_sessions()
hits = client.search("flaky test", scope="public")["items"]
client.acquire(hits[0]["id"]) # entitled listings only; never buys
resumed = client.resume("my-work", cwd="/home/me/app")
print(" ".join(resumed.local.resume_command)) # claude --resume <new id>
| Area | API |
|---|---|
| Auth | Client.login(), device_login(), start_device_login() / poll_device_login(), login_with_token(), logout(), me() |
| Library | list_sessions(), find(), resolve(), search(), get_listing(), fetch(), acquire(), delete() |
| Publish | push(), push_file(), push_path(), craft(); scrub_bytes() for a dry run; PushResult.harness |
| Resume | Client.resume(); offline: resume_locally(), rekey(), project_dir_name(), claude_projects_dir(), latest_local_session() |
| Transcripts | token_stats(), summarize(), trim_to_last_compact(), stitch() |
| Harnesses | harness_id(), harness_name(), FetchedSession.harness, Client.listing_harness() |
| Errors | A4sxError > ApiError (PaymentRequired, MemoryOnly), NotLoggedIn, NetworkError, NotFound, LoginExpired, LoginTimedOut, EmailVerificationPending, OtherHarness |
The SDK never prints and never calls sys.exit. Resuming without the SDK takes four steps, which
resume_locally() implements: decode the transcript, pick a fresh session id, set sessionId on
every record that has one, and write it to
${CLAUDE_CONFIG_DIR:-~/.claude}/projects/<cwd with every non-alphanumeric character replaced by "-">/<id>.jsonl.
Then run claude --resume <id>.
Compatibility
- Claude Code stores sessions in an undocumented format that can change between releases.
a4sxonly rewritessessionId(and, forcraft, theuuid/parentUuidchain), so it is robust to most changes, but a resume can still fail after a large format change. Please open an issue. - The standalone
a4sxscript from the website's installer and this package share the config dir, so a sign-in from one works in the other. This package does not include older command aliases, the launch profiles or the workspace-admin commands; keep using the installer's script if you rely on those. - The client scrub is the installer's script's own, vendored with
tools/vendor_scrub.py: a new scrub rule reaches this package with its next release.
Development
$ python -m pip install -e '.[dev]'
$ pytest -q # offline: SDK tests run against a local stub server
$ ruff check . && reuse lint
See CONTRIBUTING.md. Security issues: SECURITY.md.
About
a4sx is made by crossVault GmbH, the company behind a4sx
(session-exchange.com), a library and marketplace for coding-agent
sessions. This client is open source so you can see exactly what touches your transcripts before
anything is uploaded, and so other tools can build on the same SDK. The hosted service is not part
of this repository. Parts of this project were developed with AI assistance (Claude).
License
Apache-2.0, see LICENSE. Copyright 2026 crossVault GmbH.
Metadata
Release files for a4sx 0.11.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 | |
|---|---|---|---|
| a4sx-0.11.0.tar.gz | 119.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| a4sx-0.11.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 206.9 kB
Release files / a4sx-0.11.0.tar.gz
| Download URL | a4sx-0.11.0.tar.gz |
|---|---|
| Size | 119.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b1e5c3fccdd50551032fc469c44a163cdee8e786fe142ce7cfd6a463a4c3b1aa
|
|
BLAKE2b-256 checksum How to use checksums |
13b8b6d65d80dc4d8972a9f440f009f96fe11bcac0c0f85304b12c709f09459a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency logRelease files / a4sx-0.11.0-py3-none-any.whl
| Download URL | a4sx-0.11.0-py3-none-any.whl |
|---|---|
| Size | 87.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2dbd7378a3f2fae4bbbf5bbcb1a2c3d71241d83031c3e1130df08d6d7c2b7196
|
|
BLAKE2b-256 checksum How to use checksums |
6d954b99702e09c114256e6e75ec6145b15b040f349fc3202e8435e1cb2dbbd0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency log