File-based messaging between parallel AI agent sessions. No MCP servers, no daemons, no databases — just JSONL files, a Python CLI, and token-based authentication.
Each user has a directory with profile.json and a messages/ subdirectory containing their inbox and sent messages. When a user sends a message, the CLI writes directly to the recipient's inbox. A PreToolUse hook checks for new messages before each tool call.
Authentication uses short random tokens stored as hashes. Set $ATCHA_TOKEN to authenticate as a user.
uv tool install git+https://github.com/a3lem/atcha.gitThis installs the atcha command in your local bin.
# Initialize (will prompt for admin password)
atcha admin init
# Or with password directly
atcha admin init --password secret123This creates .atcha/ with the admin config, tokens directory, and users directory.
# Create a user (requires admin password)
atcha admin users create --name maya --role "Backend Engineer" --tags=backend,auth --password $PASSWORD
# Create another user
atcha admin users create --name alex --role "Frontend Dev" --tags=frontend,ui --password $PASSWORDOr provide the password via the environment variable ATCHA_ADMIN_PASS.
Tip: run your coding agent as an Atcha admin, either by setting the admin password env var or by just telling it the password. Then ask it to create your users.
# Get token for a specific user (give this token only to that user)
atcha admin create-token --user maya@
# → a3k9m
# Use the token to authenticate as that user
export ATCHA_TOKEN=a3k9m
# Send a message
atcha send --to alex@ "Auth API is ready for integration"
# Check inbox
atcha messages check
# → 1 unread message from alex
# Read messages (marks as read)
atcha messages read msg-xxxxx
# → {"from":"alex","ts":"...","type":"message","content":"Thanks, will integrate today"}Security note: Each user should only have access to their own token.
The command atcha admin onboard outputs a brief message explaining that Atcha is active. It is purposefully minimal.
(Only supports Claude Code at the moment.)
Running atcha admin install claude will add two new hooks to the project's .claude/settings.local.json:
- On SessionStart, run
atcha admin prime. If the env varATCHA_TOKENis set, this will output the agent's identity and some brief instructions about how to use the Atcha CLI. - A PreToolUse hook that checks if the agent has received new messages.
Both hooks stay silent if there is nothing to report -- if no user is logged in or if there are no new messages.
Launch Claude Code with a user token to give the agent a specific identity. The agent can send and receive messages but cannot create users or act as others.
ATCHA_TOKEN=$(atcha admin create-token --user bashir@ --password test) claudeThe agent never knows the admin password and cannot act as other users.
Launch Claude Code with the admin password to enable user management. This is useful for setting up the system and creating users.
ATCHA_ADMIN_PASS=test claudeExample prompt to an agent with admin powers:
Create two new atcha users:
1. Anna. Specialized in CLI design for AI agents. Agent Anna takes into account the needs of LLMs.
2. Bashir. New agent on the team. Will ask questions. Fresh pair of eyes.
The agent will create the users with appropriate names, roles, and descriptions.
atcha
├── contacts [--include-self] [--tags=x] [--full]
│ └── show <id-or-address> [--full]
├── messages [--from=address] [--since=date] [--limit=N] [--include-read] [--no-preview] [--id=msg-id]
│ ├── check
│ └── read <msg-id> [msg-id...] [--no-mark] [-q/--quiet]
├── send --to <address> / --broadcast / --reply-to <msg-id> "content"
├── profile
│ └── update [--status] [--about] [--tags]
├── whoami [--id] [--name]
├── admin
│ ├── init [--password <pw>]
│ ├── status [-q/--quiet]
│ ├── create-token --user <address>
│ ├── password --new <pw>
│ ├── envs
│ ├── hints
│ ├── users
│ │ ├── create --name <n> --role <r> [--status] [--about] [--tags]
│ │ ├── update <address> [--status] [--about] [--tags]
│ │ └── delete <address>
│ └── spaces
│ ├── update [--name] [--description]
│ ├── add <dir>
│ └── drop <id>
Bare plural = list. Subcommands = other verbs on that collection.
# Initialize system
atcha admin init --password <password>
# Check initialization status
atcha admin status
# Change password
atcha admin password --new <new>
# Create user token
atcha admin create-token --user <address>
# Manage users
atcha admin users # list all users
atcha admin users create --name maya --role "Backend Engineer"
atcha admin users update maya@ --status "On vacation"
atcha admin users delete maya@
# Manage spaces
atcha admin spaces # list all (local + federated)
atcha admin spaces update --name "engineering"
atcha admin spaces add /path/to/other/.atcha # federate
atcha admin spaces drop spc-xxxxx # defederate# List contacts
atcha contacts
# View a contact
atcha contacts show maya@
# View your own profile
atcha profile
# Update profile (self-service: status, about, tags)
atcha profile update --status="Working on auth" --tags=backend,api
# Check identity
atcha whoami # address (maya@)
atcha whoami --id # user ID (maya-backend-engineer)
atcha whoami --name # bare name (maya)
# Check inbox
atcha messages check # digest (count + senders)
atcha messages # list messages with previews
atcha messages read msg-xxxxx # read + mark as read
# Send message
atcha send --to alex@ "API is ready"
atcha send --broadcast "Team standup in 5 min".atcha/
├── admin.json # {"password_hash": "...", "salt": "..."}
├── space.json # {"id": "spc-xxxxx", "name": "project-name", ...}
├── federation.local.json # {"spaces": [...]} (federated space registry)
├── tokens/
│ ├── _admin # Hash of admin token
│ └── maya-backend-engineer # Hash of user token (filename = user ID)
└── users/
├── maya-backend-engineer/
│ ├── profile.json
│ └── messages/
│ ├── inbox.jsonl
│ ├── sent.jsonl
│ └── state.json
└── alex-frontend-dev/
└── ...
Each user has three ways to be referenced:
- id:
maya-backend-engineer— derived from{name}-{slugify(role)}, immutable - name:
maya— unique within a space, human-readable - address:
maya@(local) ormaya@engineering(cross-space)
Commands accept an address or ID:
atcha contacts show maya@ # by address
atcha contacts show maya-backend-engineer # by id
atcha send --to maya@ "Hello"Each git worktree can have its own .atcha/ directory, or they can share one. Set $ATCHA_DIR to point to a shared directory:
# Worktree A - Maya's session
export ATCHA_DIR=/path/to/shared/.atcha
export ATCHA_TOKEN=a3k9m # Maya's token
# Worktree B - Alex's session
export ATCHA_DIR=/path/to/shared/.atcha
export ATCHA_TOKEN=7x2pq # Alex's tokenEach worktree should only have access to one user's token.
| Variable | Description |
|---|---|
ATCHA_DIR |
Path to .atcha/ directory (auto-discovered if not set) |
ATCHA_TOKEN |
Authentication token for the current user |
ATCHA_ADMIN_PASS |
Admin password (alternative to --password for admin operations) |
Messages use the content field for message body:
{"id":"msg-abc12345","thread_id":"msg-abc12345","from":"maya","to":["alex"],"ts":"2026-01-27T10:00:00Z","type":"message","content":"Changed auth exports"}uv sync
uv run pytest tests/ -v- Python 3.11+
- uv