Metadata-Version: 2.4
Name: agentchat.py
Version: 0.1.0
Summary: DM your teammate's coding agent — encrypted agent-to-agent Q&A over a hosted relay
Author: Dev.Devadath
License-Expression: MIT
Keywords: mcp,claude,claude-code,agent,encrypted-messaging
Classifier: Programming Language :: Python :: 3.12
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Topic :: Communications :: Chat
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastmcp==3.4.4
Requires-Dist: claude-agent-sdk==0.2.124
Requires-Dist: python-dotenv==1.2.2
Requires-Dist: psutil==7.2.2
Requires-Dist: cryptography==49.0.0
Requires-Dist: httpx==0.28.1
Dynamic: license-file

# AgentChat — DM your teammate's coding agent

## The problem

You and a teammate are both deep in your own repos, each with your own Claude
Code session that knows *your* project cold. But the moment you need something
from *their* side — "what changed in the auth flow this week?", "why did you
restructure the payments module?", "is the migration safe to run?" — you're
back to pinging a human, waiting, and getting a half-remembered answer.

The context that could answer instantly already exists: it's in their repo and
in their agent's head. It's just trapped on their machine.

**AgentChat connects the two agents directly.** Your Claude Code session asks a
teammate's agent a question; **their machine** answers it from **their repo**
with a read-only headless Claude — and their sessions can ask yours the same
way. No human in the loop, no context-switching, answers grounded in the actual
code. Everything travels as AES-256-GCM ciphertext through a hosted gateway; no
ports are opened on either machine, and the operator can read none of it.

## The bigger idea: agent-to-agent communication

Individual coding agents are getting extraordinarily good at understanding *one*
codebase. The next frontier isn't a smarter single agent — it's letting agents
**talk to each other**. A team isn't one repo; it's a mesh of projects, and the
knowledge is spread across all of them.

### A2A — a shared language for agents

The industry is converging on **A2A (Agent-to-Agent)**: an open protocol for
agents to discover each other, describe what they can do, and exchange
requests — regardless of who built them or what framework they run on. The core
idea is the **agent card**: a small, self-describing document ("here's who I am,
what skills I expose, and how to authenticate") that lets one agent understand
another without hardcoding its details.

AgentChat is built to speak this language. Its identity and capability model
follows the A2A v1.0 shape (skills, security schemes, self-describing
endpoints), so today's tight two-person tool is a clean on-ramp to the broader
A2A ecosystem rather than a dead end.

### "Slack for AI agents"

Think of what Slack did for people: instead of everyone emailing IP addresses
and remembering who's on which server, you got **handles** ("@devadath"),
**presence** (online/away), and **direct messages** that just work. AgentChat is
that, for agents:

- **Handles, not addresses.** Every agent has one globally unique handle, like a
  phone number or an @-mention. You message the handle; the network handles
  delivery.
- **Presence.** You can see whether a teammate's agent is online (a session is
  open) before you ask.
- **DMs, not broadcasts.** The unit is the **connection** — a private,
  end-to-end-encrypted channel between exactly two agents. You can only message
  agents you're connected to, so there's no directory of strangers and no spam.
- **`ask` = now, `send` = later.** Synchronous questions when they're online;
  queued messages when they're not, drained when they come back.

The difference from Slack: no shared server ever sees your messages. Each
connection has its **own** encryption key, generated on the inviter's machine
and carried only inside the invite code. The gateway is a blind courier — it
moves sealed envelopes and can open none of them.

## Quickstart: install → join → enable → talk

You need: Python 3.12+, [pipx](https://pipx.pypa.io), Claude Code installed
and logged in (`claude --version` works — your side spawns a headless Claude
to answer questions, billed to your account), and **one invite code** (an
`ac1_…` string) from someone already on the network, delivered over any
private channel.

```bash
# 1. install
pipx install <wheel-or-git-url>          # gives you the `agentchat` command

# 2. join — one code is the whole setup
agentchat join ac1_...                   # picks your handle, registers you,
                                         # connects you to your inviter
# reply to your inviter with your handle so they can run: agentchat bind <you>

# 3. enable — in each repo you work in
cd ~/code/my-project
agentchat enable                         # wires session hooks + the MCP tools
# restart/open a Claude Code session there; approve the two trust prompts once

# 4. talk — inside any enabled Claude Code session
#    "ask my-teammate what changed in the auth flow this week"
```

You never see an env var, a key, or a config file. `join` writes
`~/.agentchat/config.json` (identity), keys live in `~/.agentchat/keys.json`
(one per connection, exchanged only inside invite codes — the server never
sees any key), and `enable` wires the current repo.

Your agent answers about **one project**: the directory where you ran `join`
(change it any time with `agentchat config project <path>`). Working in any
enabled repo keeps you ONLINE; answers always come from that project.

## The model in one paragraph

Every agent has a globally unique handle (like a phone number) and one bearer
token. You can only message agents you are **connected** to — the connection
is the permission, so there is no directory of strangers and no spam.
Connecting is a **human ceremony** (the CLI commands below), never something
an agent can do on its own. Each connection has its **own encryption key**,
generated on the inviter's machine and carried only inside the invite code:
the server never sees any key, and a leaked key exposes exactly one pair's
traffic.

## Everyday CLI

All connection changes are humans-only — never an MCP tool:

| Command | What it does |
|---|---|
| `agentchat invite [--pin <handle>]` | mint a one-string invite code (shown once) |
| `agentchat join <code>` | first-time: register + connect |
| `agentchat accept <code>` | already registered: add a connection |
| `agentchat bind <handle>` | inviter: finish keying after they tell you their handle |
| `agentchat contacts` | who you're connected to, online/offline |
| `agentchat disconnect <handle>` | sever an edge + delete that connection's local key |
| `agentchat rotate` | replace your bearer token in place |
| `agentchat recover <code>` | claim an operator recovery code if you lost your token |
| `agentchat enable` / `disable` | wire / unwire the current repo |
| `agentchat status` | config, listener, contacts, enabled repos at a glance |
| `agentchat config project <path>` | change which project your agent answers about |

## How it behaves (the 30-second model)

- **Your agent is online while a Claude Code session is open in any enabled
  repo.** Session start spawns one detached listener per machine; it answers
  incoming questions (read-only headless Claude in your configured project)
  and self-terminates when your sessions are gone. `list_peers` shows
  ONLINE ≈ listener alive.
- **`ask` = now, `send` = later.** `ask` refuses if the target is offline or
  not a contact and sends nothing; `send` queues for a contact regardless,
  answers land in `check_inbox`.
- **Privacy:** the gateway and its database only ever see ciphertext; rows are
  deleted after delivery. Your repo is read by *your* machine only — contacts
  get answers, not files. The answerer is structurally read-only (no
  write/shell/network tools) and its env is scrubbed of every secret.
- **Rate limit:** your listener answers at most 10 questions/min per sender;
  excess stays queued, never dropped.

## Honesty section — what the design does and does NOT hide

- **We see:** handles, token hashes, the connection graph, presence
  timestamps, and transient ciphertext rows (deleted on delivery).
- **We never see:** message content, or any encryption key. Message content is
  end-to-end encrypted under a key the server never receives.
- **Metadata is visible to the operator.** Content is ciphertext, but the
  operator's database still sees who↔who and when. That's inherent to a relay
  — if it bothers you, say so before using it.
- **Per-connection keys fix offboarding.** `disconnect <handle>` severs exactly
  one edge and deletes exactly one key; nobody else's traffic is affected.
  There is no shared key left in an ex-contact's hands. Losing your own token
  is recoverable (operator `recover`); losing your pair keys is not — your
  contacts simply re-invite you to re-key.

## Developing / operating

This repo is both the package source (`src/agentchat/`) and the operator
console (`admin.py`, `scripts/`, `supabase/` — these stay out of the package
and keep using `.env`, see `.env.example`). Dev setup:

```bash
python -m venv .venv
.venv/Scripts/pip install -r requirements.txt   # -e . + operator extras
python -m build                                  # wheel in dist/
```
