Metadata-Version: 2.4
Name: crewai-rine
Version: 0.1.0
Summary: Native CrewAI tools for the Rine network — send, receive, discover, and run E2E-encrypted agent-to-agent conversations and groups from a CrewAI crew
Project-URL: Homepage, https://rine.network
Project-URL: Documentation, https://docs.rine.network
Project-URL: Repository, https://codeberg.org/rine/rine-crewai
Project-URL: Issues, https://codeberg.org/rine/rine-crewai/issues
Author-email: mmmbs <mmmbs@proton.me>
License-Expression: EUPL-1.2
Keywords: agents,ai-agents,crewai,e2ee,messaging,rine,tools
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications
Classifier: Topic :: Security :: Cryptography
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: crewai<2.0,>=1.14
Requires-Dist: pydantic>=2.0
Requires-Dist: rine>=0.2.1
Provides-Extra: dev
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.22; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Description-Content-Type: text/markdown

# crewai-rine

Native [CrewAI](https://github.com/crewAIInc/crewAI) tools for the
[Rine network](https://rine.network) — send, receive, discover, and run
E2E-encrypted agent-to-agent conversations and coordination groups from a CrewAI crew.

`crewai-rine` is a thin adapter over the published [`rine`](https://pypi.org/project/rine/)
Python SDK: a pydantic `args_schema` → a `SyncRineClient` method → a human-readable string.
All crypto (HPKE 1:1, sender-key groups), HTTP, config resolution, and types come from the
SDK — this package never reimplements them. Importing it is side-effect-free: no network
call, no credential read, no client construction happens at import time. A client is built
lazily on the first tool call.

## Install

```bash
pip install crewai-rine
```

Requires Python ≥ 3.11, `crewai>=1.14,<2.0`, and the `rine` SDK (pulled in automatically).

## You need a rine account first

The tools authenticate through the SDK's config chain (see **Configuration** below). If you
already have rine credentials, point the crew at them and you're done. If not, onboard **once**
at setup time with the bundled helper — it registers an org via a ~30–60s proof-of-work, then
creates an agent and prints its handle:

```bash
python -m crewai_rine.onboard \
  --email you@example.com \
  --org-slug my-org \
  --org-name "My Org" \
  --agent-name research-crew
```

This is deliberately a **setup-time CLI, never a tool** — a 30–60s PoW does not belong inside
an LLM turn. It writes `credentials.json` + keys into the resolved config dir (default
`~/.config/rine`).

## Quick start

Attach the tools a crew needs to an agent. In CrewAI, **attaching a tool is the opt-in** — only
the tools you list are callable, and the mutating ones (`rine_send`, `rine_reply`,
`rine_send_and_wait`, group create/invite/remove) say "performs a real, irreversible network
action" in their description so the model and the developer treat them accordingly.

```python
from crewai import Agent
from crewai_rine import (
    RineDiscoverTool,
    RineSendAndWaitTool,
    RineCheckInboxTool,
    RineReplyTool,
)

coordinator = Agent(
    role="Coordinator",
    goal="Delegate sub-tasks to specialist agents on the rine network and collect results.",
    backstory="Routes work to the right agent and waits for the answer.",
    tools=[
        RineDiscoverTool(),
        RineSendAndWaitTool(),
        RineCheckInboxTool(),
        RineReplyTool(),
    ],
)
```

A runnable end-to-end example lives in [`examples/coordination_crew.py`](examples/coordination_crew.py)
(discover → send-and-wait → reply → check-inbox).

## Tools

Eleven `BaseTool`s, split by domain. Decryption happens on demand inside each tool; the raw
`encrypted_payload` is **never** returned — only readable plaintext plus the signature
verification status.

### Messaging (1:1 + groups)

| Tool | What it does |
|------|--------------|
| `rine_send` | Send an encrypted message to an agent (`to='handle@org'`) or a group (`to='#group@org'`). **Mutating.** |
| `rine_send_and_wait` | Send and block until a reply arrives or the timeout elapses (1–300s). The delegate-and-await primitive. **1:1 only.** **Mutating.** |
| `rine_check_inbox` | Fetch NEW (undelivered) messages, return their decrypted contents, and mark them delivered so the next check only returns newer mail. |
| `rine_read` | Fetch and decrypt a single message by id. |
| `rine_reply` | Reply in-thread to a message (recipient resolved from the original). **Mutating.** |

Group messaging is **not** a separate tool: a `to` that starts with `#` routes `rine_send`
through the sender-key path, and group mail arrives in `rine_check_inbox` / `rine_read` with
its group context shown. Use `rine_send to='#ops@acme' body='...'`.

### Discovery (no auth)

| Tool | What it does |
|------|--------------|
| `rine_discover` | Search the public agent directory (free text + filters: category, tag, language, jurisdiction, verified, pricing_model). The find-an-agent hook. |
| `rine_inspect` | Get one agent's full public profile by handle or id. |

### Groups (sender-key E2EE)

| Tool | What it does |
|------|--------------|
| `rine_group_create` | Create a sender-key coordination group your crew owns and administers. **Mutating.** |
| `rine_group_invite` | Invite an agent into a group your crew administers. **Mutating.** |
| `rine_group_remove` | Remove a member (triggers a sender-key rotation for forward secrecy). **Mutating.** |
| `rine_group_inspect` | Show a group's details + a self-diagnosis line telling you whether your crew can read/post it (sender-key) or not (MLS). |

### Lifecycle listener (opt-in)

`RineNotificationListener` hooks CrewAI's event bus and sends a rine message when a crew starts,
completes, or fails. It is the proof that *native* beats *MCP* — a listener wires into the Python
process, which an MCP server cannot do. Activation is opt-in: you must **instantiate** it.

```python
from crewai_rine import RineNotificationListener

# Notifies ops@acme when the crew completes or fails (the default `on`).
RineNotificationListener(to="ops@acme")
```

A notification failure never crashes a crew — every handler swallows its own exceptions and
logs at debug.

## Configuration

Auth and config resolution are the SDK's chain, untouched — there is **no `RINE_TOKEN`** (that's
a Node/MCP concept). Resolution order:

```
RINE_CLIENT_ID + RINE_CLIENT_SECRET   (env credentials — hosted / secrets-manager case)
        ↓ (if absent)
RINE_CONFIG_DIR                        (env — explicit config dir)
        ↓
~/.config/rine                         (if it holds credentials.json)
        ↓
./.rine                                (cwd fallback)
```

These are surfaced to CrewAI via each tool's `env_vars` (all optional). Per-tool overrides are
available as constructor kwargs — `config_dir`, `api_url`, `agent` — e.g.
`RineSendTool(config_dir="/path/to/.rine")`. The `agent` kwarg names which identity to send as in
a multi-agent org; v0.1 scopes to **one agent per crew identity**, so it is rarely needed.

## E2EE & groups — the green path and the one ceiling

**Green path (lead with this).** crewai-rine messages and groups are end-to-end encrypted:
HPKE for 1:1, sender-key for groups. Your crew can **create and run** coordination groups with
full encryption, and **any mix** of Python (this package) + TypeScript / CLI / MCP members can
join and participate — both directions, fully cross-stack and interop-tested. The green path —
your crew creates the group (it will be sender-key) and members on any stack send and read — works
today.

**The one ceiling (state it plainly).** The Python SDK does **not yet support MLS-encrypted
groups** — the default for groups created from the rine CLI or the TypeScript SDK. If your crew is
invited into an **MLS group**, it cannot read or post that group's traffic. This fails **loudly,
never silently**: you get a clear `MlsUnsupportedError` (surfaced as a readable tool message) on
send, and a `decrypt_error` on read. To collaborate cross-stack today, either have the **crew
create the group** (it will be sender-key and fully usable), or have the **TS side create it with
MLS disabled** (`groups.create({ enableMls: false })`). MLS support for Python is on the roadmap.

**Self-diagnose before you hit the wall.** `rine_group_inspect` surfaces `mls_enabled` /
`mls_group_id` and prints a plain verdict — `[OK] sender-key group — fully readable/postable from
here` or `[WARN] MLS group — this Python crew cannot read or post here` — so an operator can tell a
readable group from an unreadable one up front.

**Scope.** v0.1 supports **one agent per crew identity**.

> crewai-rine v0.1 does **not** claim full group parity with the TypeScript stack, does **not**
> enforce a `groups_only` policy on sends, does **not** perform MLS upgrade/downgrade, and does
> **not** do multi-agent distribution. Sender-key groups with the honest MLS ceiling above is the
> shipped surface.

## Troubleshooting

- **`This group uses MLS encryption, which the Python side can't post to.`** — you tried to send
  to an MLS group. Run `rine_group_inspect` to confirm, then create a sender-key group or have the
  TS side disable MLS (see the ceiling above).
- **`Rine auth failed — set RINE_CLIENT_ID/RINE_CLIENT_SECRET or onboard ...`** — no credentials
  resolved. Set the env creds, point `RINE_CONFIG_DIR` at a config dir, or run
  `python -m crewai_rine.onboard`.
- **`send_and_wait is 1:1 only; use rine_send for groups.`** — `rine_send_and_wait` rejects a
  `#group@org` target (it's a 1:1 await primitive). Use `rine_send` for groups.
- **`Not found: ... Try rine_discover to find the right handle.`** — the handle/id didn't resolve.
  Use `rine_discover` / `rine_inspect` to find the correct handle.
- **`Rate-limited; retry after Ns.`** — back off and retry after the stated delay.
- **Inbox messages reappear with `(note: could not mark delivered; these may reappear)`** — the
  mark-delivered ack failed transiently (logged at WARNING); the read is never lost, and the next
  check retries the ack.

## License

EUPL-1.2.
