This release is a pre-release and may not be stable for production use.
Carrier
Send. Reply. Acknowledge.
Carrier gives agents and programs authenticated, durable inboxes.
Exchange messages through an async Python SDK or MCP tools,
with identities and message history persisted in SQLite.
Quick start · Demos · Python SDK · MCP setup · Documentation
Contents · Capabilities · Installation · Demos · Quick start · Build with Carrier · Architecture · Delivery semantics · Documentation · Development
What you can do
- Address agents and programs directly. Send to a permanent address or a unique readable name.
- Keep inboxes across restarts. Retain identities, messages, replies, and acknowledgments in SQLite, including messages sent while a recipient is offline.
- Follow a request and its reply. Correlate responses with the original message instead of guessing from inbox order.
- Make retries explicit. Reuse a send's retry key to avoid duplicate storage, and acknowledge messages after accepting them.
- Integrate through Python or MCP. Run async consumers in your application or expose inbox tools to an agent conversation.
See Carrier in action
These recordings run against a real, isolated Carrier service. Expand a workflow to watch the GIF. The accompanying VHS tapes show the recorded commands.
Send, reply, and acknowledge — Python SDK
Send a request to another inbox, match the reply to that request, then explicitly acknowledge both messages. Reading and replying leave them pending; acknowledgment preserves their history.
Retry a send without storing a duplicate
Publish the same build event with a stable retry key. Both sends return message
ID 1. After archiving and acknowledging it, another retry returns that same
message with status acknowledged. The inbox retains one message.
Recover an inbox after consumer downtime
Store three events while the consumer is offline and the service stays running. The archiver reads two-message pages, commits each event before acknowledgment, and accepts zero events when run again. All three messages remain in history.
Exchange messages through real MCP tools
Two scripted Python clients connect to separate Carrier stdio adapters and call
send, wait, and ack. A reply is correlated with its original request. This
records real MCP tool calls and service responses; no AI model is used.
Run the quick start and SDK examples to reproduce the messaging workflows locally. Real stdio MCP exchanges are covered by the integration tests. The tapes depend on a separate recording harness; this repository does not include that harness.
Installation
These instructions describe the development branch preparing aixand-carrier-mcp==0.1.0b0.
Python 3.11+ is required. The required aixand-lib-filesystem dependency is
published on PyPI and installs automatically with python -m pip install ..
After Carrier's first PyPI publication, install the beta in a virtual environment with
python -m pip install aixand-carrier-mcp==0.1.0b0. See Python package releases
for publication and verification.
The development helpers and native packaging still require Carrier and
aixand-libraries source checkouts in sibling directories:
workspace/
carrier/
aixand-libraries/
filesystem/
Obtain the filesystem source from the same source workspace for these helper commands. See source prerequisites if the helper reports a missing dependency.
To install the standalone CLI, run from the Carrier repository root:
./dev.sh install --prod
"$HOME/.local/bin/carrier" --help
On Windows use .\dev.ps1 install --prod, then carrier --help.
On Linux/macOS, add ~/.local/bin to PATH before using bare carrier commands.
The source installer needs network access to resolve third-party dependencies.
For SDK applications, use the separate environment below.
Carrier also adopts the revision-2 product installer for locally built artifacts. Its native payload bundles CPython, Carrier, and dependency wheels. Read the installation guide for packaging, private scope, bootstraps, updates, and uninstall. The installer validation guide explains lifecycle checks and native qualification requirements. Hosted native installers are not provided by this checkout. Python package publication uses the tag-to-PyPI workflow.
Start the messaging service explicitly with carrier serve. Carrier databases
and credentials survive software removal. See development setup
for installer locations and lifecycle commands.
Python SDK setup
Applications on Unix sharing the local Carrier database can use
carrier.ensure_session(database=..., credentials=..., address=..., name=...)
to provision stable inbox identities. It preserves existing credentials and
uses a private pending credential file and filesystem lock to recover an
interrupted provisioning operation with the same token. Concurrent callers for
the same credential path share one identity. An existing address with different
credentials is rejected. This local administration helper must point at the
database actually served by Carrier; verify access through Client.open().
It does not grant remote clients provisioning privileges.
For the Python SDK, install Carrier into your application's environment.
The public CLI's private environment does not add Carrier to other Python
environments. From a local checkout, the quick start below uses a .venv:
python3 -m venv .venv
.venv/bin/python -m pip install .
source .venv/bin/activate
The package is named aixand-carrier-mcp; the Python import and CLI are both carrier.
The service, SDK, and MCP adapter ship together. On Windows, create the environment
with py -3 -m venv .venv and use .venv\Scripts\python.exe and
.venv\Scripts\carrier.exe for the examples.
Set up with mise
From the repository root:
mise trust
mise run setup
source .venv/bin/activate
Mise selects the Python version in mise.toml and installs Carrier
and its test dependencies into .venv. You can also use mise run carrier
to invoke the CLI without activating the environment.
Quick start
Exchange a request and reply between two inboxes. This walkthrough uses
.carrier/demo.db and port 8876, separate from the service's default
database and port. Run commands from the repository root.
-
Create the two identities once.
carrier session demo/requester --db .carrier/demo.db --credentials .carrier/requester.json carrier session demo/reviewer --db .carrier/demo.db --credentials .carrier/reviewer.json
Each command prints
Created ...; credentials saved to .... Keep those credential files to reuse the inboxes; provisioning refuses to overwrite them. The.carrier/directory is ignored by Git. -
Start the shared service.
carrier serve --db .carrier/demo.db --port 8876
Leave this terminal running. In a second terminal, verify the service:
carrier status --url http://127.0.0.1:8876
Expect
Carrier running at http://127.0.0.1:8876. -
Send, reply, and acknowledge.
Save the following as
.carrier/exchange.pyand run.venv/bin/python .carrier/exchange.pyfrom the repository root, using the SDK environment created during installation:import asyncio from uuid import uuid4 from carrier import Client async def main(): url = "http://127.0.0.1:8876" async with ( Client(url=url, credentials=".carrier/requester.json") as requester, Client(url=url, credentials=".carrier/reviewer.json") as reviewer, ): retry_key = uuid4().hex question = await requester.send( "Can you review this change?", to="demo/reviewer", idempotency_key=retry_key, ) page = await reviewer.receive_pending() incoming = next(m for m in page.messages if m.id == question.id) print("Reviewer received:", incoming.content) await incoming.reply("I'll review it.") await incoming.ack() answer = await requester.wait_for_reply(question, timeout=5) print("Requester received:", answer.content) await answer.ack() status = await requester.delivery_status(retry_key) print("Request delivery:", status["status"]) asyncio.run(main())
Expected output:
Reviewer received: Can you review this change? Requester received: I'll review it. Request delivery: acknowledged
The example opens both inboxes in one program; each can instead belong to a separate application or agent. Use these demo inboxes without other active consumers. Each successful run acknowledges both messages, and a new run uses a fresh retry key. Acknowledgment records acceptance of the request; the review itself is application work.
Stop the service with Ctrl+C. Restart it with the same database and reuse the
credential files to retain identities and history. For normal operation, the
defaults are http://127.0.0.1:8765 and ~/.aixand/carrier/carrier.db.
Carrier creates its per-user directory, ~/.aixand/carrier, when needed.
Override the database with --db; provisioning and serving must use the same
database. Credential files remain at the explicitly supplied --credentials path.
Existing databases at ~/.local/share/carrier/carrier.db are not moved
automatically. To migrate, stop the service and other processes accessing the
database, then move carrier.db and any SQLite sidecar files into
~/.aixand/carrier/, without overwriting an existing database. Keep your credential
files and update any explicit database paths in service units or integrations
before restarting. To continue using the previous location, pass
--db "$HOME/.local/share/carrier/carrier.db" to both provisioning and serving.
Build with Carrier
For managed Codex terminal launches, the optional agent launch adapter provides CLI and async SDK entry points, durable conversation binding, and detached cleanup. Carrier's ordinary messaging SDK and MCP setup remain independent.
Python
The quick start uses the async SDK. Applications can also send JSON, wait for
correlated replies, and register an async message handler with
@inbox.consumer(). Calling await inbox.run() runs that consumer in your
application; the handler explicitly replies and acknowledges messages.
Try the runnable SDK examples: request a CI report from a worker, publish build events safely across retries, and archive pending events after downtime. The Python SDK guide also covers the API, error handling, and compatibility requirements.
MCP
Configure a stdio MCP adapter for each agent conversation, using absolute paths. This example connects to the quick-start requester's inbox:
{
"mcpServers": {
"carrier": {
"command": "/home/you/.local/bin/carrier",
"args": [
"mcp", "--url", "http://127.0.0.1:8876",
"--credentials", "/absolute/path/to/carrier/.carrier/requester.json"
]
}
}
}
Replace the command with the absolute path to your installed carrier and the
credentials path with your own. The configuration format depends on your app.
Each independent conversation needs its own identity. The shared backend is an
HTTP service; the local adapter
provides the MCP tools. An agent can call
send(to="demo/reviewer", content="Can you review this change?"), then use
wait() to receive messages and ack() to accept them.
For the receiving conversation, use reviewer.json. Let the agents own their
inbox reads once connected. To correlate a reply, send it back to the original
sender with reply_to set to the received message's numeric id. The requester
can then call wait(reply_to=...) with its original request's ID.
wait() defaults to 45 seconds and accepts timeout_seconds up to 300. Keep
your app's MCP tool timeout above that duration. Waiting does not acknowledge
messages; call ack(message_id=...) after accepting each one. Reconnect the
adapter after upgrading Carrier to load updated tools.
The Python SDK calls the send retry key idempotency_key; MCP calls it
message_id. Acknowledgments use the stored message's numeric id.
Architecture
Python applications and per-conversation MCP adapters share the same HTTP service. The service authenticates inbox access and persists messaging state in SQLite.
flowchart LR
accTitle: Carrier runtime communication
accDescr: Python applications and per-conversation MCP adapters use the async Python SDK to access the shared HTTP service. The service authenticates inbox access and stores identities and messages in SQLite.
App[Python application] --> SDK[Async Python SDK]
Agent[Agent conversation] -->|stdio MCP| Adapter[MCP adapter]
Adapter --> SDK
SDK -->|HTTP| Service[Carrier service]
Service --> DB[(SQLite)]
Carrier owns message exchange. Applications own process launch, session lifecycle, and actions triggered by messages. An optional adapter coordinates agent launch and conversation binding.
Delivery semantics
- Stored: Carrier has persisted the message. An offline recipient can read it later.
- Acknowledged: The recipient has explicitly accepted the message. Reading or replying alone does not acknowledge it.
- Completed: Your application defines and communicates task completion, for example through a correlated reply.
Reads preserve history. Unacknowledged messages remain pending and can be returned again; retry keys prevent duplicate message storage when reused with the same request. They do not guarantee exactly-once task execution.
Use one active receiving owner per inbox. Receiving requires an SDK consumer or an explicit MCP tool call; Carrier does not wake an agent that has ended its turn. The service binds to localhost by default. Remote deployment requires HTTPS and operational hardening. The Python SDK guide explains retry rules, pagination, error handling, and consumer ownership.
Documentation
| I want to… | Guide |
|---|---|
| Exchange my first request and reply | Quick start |
| Add messaging to a Python application | Python SDK |
| Connect an agent conversation | MCP setup |
| Run a worker or publish events | Runnable examples |
| Handle retries and pending messages | Delivery semantics · Retry contract |
| Install the CLI or build a native artifact | Installation · Product installation |
| Install or update the CLI from a local checkout | Development · Linux/macOS installer · Windows installer |
| Diagnose setup or service errors | Troubleshooting |
| Find CLI options and defaults | CLI reference |
| Report an issue or read the participation policy | Issues and pull requests · Support |
| Change a local checkout and run checks | Development guide |
The documentation index records the adopted standard and reader paths.
Development
Keep the required ../aixand-libraries/filesystem checkout described under
installation. To build and install the standalone CLI, run from
the repository root on Linux/macOS with Python 3.11+:
./dev.sh install --prod
On Windows, use PowerShell 5.1+ with Python 3.11+:
.\dev.ps1 install --prod
carrier --help
The PowerShell script detects py, python, python3, or an existing
uv-managed Python. Set CARRIER_DEV_PYTHON to select a specific executable.
It works from any directory and does not require administrator access.
Install and reinstall add the command directory to your user PATH and the
current PowerShell process, without duplicating existing entries. Run
.\dev.ps1 directly to use carrier immediately. When using powershell -File
or pwsh -File, the parent terminal keeps its old PATH; run the script
directly there or reopen the terminal application.
The development installer publishes carrier (carrier.exe on Windows) in
~/.local/bin and installs its private environments in
~/.aixand/carrier/dev-install by default. On Linux/macOS, add the command
directory to your shell PATH. Virtual environment activation is not needed.
Local reinstall, uninstall, and custom paths
./dev.sh reinstall
./dev.sh uninstall
On Windows:
.\dev.ps1 reinstall
.\dev.ps1 uninstall
Reinstall builds and checks a fresh environment before switching the command.
Restart running services and MCP adapters afterward to load the new copy.
On Windows, stop them before reinstalling so carrier.exe is not in use.
Previous environments remain available to existing processes until uninstall.
Stop those processes before uninstalling; uninstall removes the command and
installed environments while preserving databases, credentials, and service
configuration. The script does not register or manage a background service.
Windows uninstall leaves the shared command directory on PATH for other tools.
Set CARRIER_DEV_PYTHON to select a Python executable,
CARRIER_DEV_INSTALL_DIR to change the command directory, or
CARRIER_DEV_ENV_DIR to change the private environment directory. Directory
overrides must be absolute paths; use the same values for reinstall and uninstall.
Choose separate local paths if you also use an artifact-based product installation.
Run ./dev.sh --help or .\dev.ps1 --help for the full command reference.
These commands manage development installations; they do not manage
public-installer releases.
For a development installation using the previous default directory, stop the service and MCP adapters, then reinstall at the new location:
CARRIER_DEV_ENV_DIR="$HOME/.local/share/carrier/dev-install" ./dev.sh uninstall
./dev.sh install --prod
This preserves database and credential files; migrate an existing database as described above before restarting. Rebuild virtual environments at the new location because their scripts contain absolute paths.
Use an editable install for work on the service, SDK, or MCP adapter:
mise run setup
mise run test
For locked development, keep the ../aixand-libraries/filesystem checkout and use:
./dev.sh develop
./dev.sh check
./dev.sh test
The tests cover authentication, inbox isolation, delivery semantics, persistence,
the SDK, and real stdio MCP exchanges. Use ./dev.sh reinstall (or
.\dev.ps1 reinstall on Windows) when you want to update the standalone CLI
from the current checkout.
Documentation · Issues and pull requests · Code of conduct · Security · Support · Changelog · Apache-2.0 license
AI-assisted development
We use AI tools to generate and revise code and documentation. Maintainers review and validate the resulting work and preserve required third-party attribution. We do not knowingly include proprietary code without permission. Report ownership or licensing concerns through the private reporting route.
Issues and pull requests
Bug reports, documentation issues, feature requests, and usage questions are welcome. We do not accept external pull requests because the team lacks capacity to review them. See the participation policy and support guide.
Metadata
Release files for aixand-carrier-mcp 0.1.0b0
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 |
|---|---|---|---|---|
| aixand_carrier_mcp-0.1.0b0.tar.gz | 2.5 MB | With provenance | Details for aixand_carrier_mcp-0.1.0b0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| aixand_carrier_mcp-0.1.0b0-py3-none-any.whl | Python 3 | none | any | Details for aixand_carrier_mcp-0.1.0b0-py3-none-any.whl |
Total release size: 2.6 MB
Release files / aixand_carrier_mcp-0.1.0b0.tar.gz
| Download URL | aixand_carrier_mcp-0.1.0b0.tar.gz |
|---|---|
| Size | 2.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bb68c5fb81d6da21c25a2778e9ec616b379714f31a63f656349138d9be1d8375
|
|
BLAKE2b-256 checksum How to use checksums |
b70061242c162a97be5ac34d9f57b9154bc0dcc8f54440724ccaf6cea037b4f2
|
| 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 Nov 11, 2026.
Transparency logRelease files / aixand_carrier_mcp-0.1.0b0-py3-none-any.whl
| Download URL | aixand_carrier_mcp-0.1.0b0-py3-none-any.whl |
|---|---|
| Size | 42.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
653c2b7aa20a31f5897877104781f2b7e6a684fe893e6c886b1bb8b72efdd2f8
|
|
BLAKE2b-256 checksum How to use checksums |
a4d9382ca2c19219e6aaa208ab307893dec7c7982a524ef9df066d888434d198
|
| 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 Nov 11, 2026.
Transparency logSecurity for aixand-carrier-mcp 0.1.0b0
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.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for aixand_carrier_mcp-0.1.0b0.tar.gz
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 Nov 11, 2026.
Transparency logA 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.