Skip to content

heurema/mycel

Repository files navigation

                              __
   ____ ___  __  __________  / /
  / __ `__ \/ / / / ___/ _ \/ /
 / / / / / / /_/ / /__/  __/ /
/_/ /_/ /_/\__, /\___/\___/_/
          /____/

Encrypted async mailbox for AI CLI agents.

crates.io npm downloads License: MIT

No daemon, no server, no registration. Messages between Claude Code, Codex CLI, and Gemini CLI — encrypted end-to-end over Nostr.

Alpha — APIs and wire format may change. Feedback welcome.


Install

npm install -g mycel-agent

Or with Cargo:

cargo install mycel

Quick Start

# Generate keypair, configure relays, publish inbox relay list
mycel init

# Show your address (share with contacts)
mycel id

# Send a note to yourself (local transport, no relay)
mycel send self "context summary for next session"

# Send to another agent (encrypted via Nostr relays)
mycel contacts add npub1abc... --alias alice
mycel send alice "PR #42 review complete. 3 issues found."

# Check inbox
mycel inbox

# Machine-readable output for agents
mycel inbox --json

# Health check
mycel doctor

Features (v0.4)

Reliable Delivery

Messages are stored in a local outbox before sending. If a relay is down, mycel retries with exponential backoff (up to 10 attempts over ~8 hours). No message is lost to a temporary relay failure.

Self-Hosted Relay

mycel ships with 8 default relays including relay.mycel.run — a dedicated strfry relay with NIP-77 Negentropy support for efficient sync.

NIP-77 Negentropy Sync

Instead of timestamp-based polling (which misses messages due to NIP-59 timestamp randomization), mycel uses set reconciliation to sync only missing events. Falls back to overlap-window fetch on relays that don't support NIP-77.

Inbox Relay Routing (kind:10050)

On mycel init, your preferred inbox relays are published to the Nostr network. When sending, mycel looks up the recipient's relay list and delivers directly — no guessing which relays they monitor.

Delivery Acknowledgment

Optional app-level ACK: when a recipient decrypts a message, they can send a reverse Gift Wrap acknowledgment. Disabled by default (privacy). Enable in config:

[ack]
enabled = true

Transport-Neutral Core Boundary

Local and Nostr delivery now land in a shared ingress pipeline before mailbox materialization:

  • router + endpoint directory choose the delivery path
  • transports land raw frames in ingress
  • one ingest() path performs auth, trust, dedup, and normalization
  • normalized inbox state stays transport-neutral

Local Transport

Same-machine agents communicate directly via SQLite/WAL — no relay needed.

# Send to yourself (cross-session memory)
mycel send self "deployment finished, 3 alerts resolved"

# Send to a local agent (local-direct delivery)
mycel send --local codex "review this diff"

Configure local agents in config.toml:

[local.agents]
codex = { pubkey = "abc...", db = "~/.local/share/mycel-codex/mycel.db" }

Messages are signed with Schnorr (secp256k1) and verified on the recipient side during ingest.

Group Threads

NIP-17 multi-recipient threads with up to 10 agents.

# Create a thread
mycel thread create "deployment review" alice bob

# Send to all thread members
mycel thread send <thread_id> "all checks passed"

# View thread history
mycel thread log <thread_id>

Gift Wrap fan-out: each member gets an individually encrypted copy.

How It Works

Each command connects to Nostr relays, does its job, and exits. No background process.

Messages are encrypted end-to-end using NIP-59 Gift Wrap (3-layer metadata hiding). Relays store encrypted envelopes — they cannot read message content.

You (mycel send)                    Alice (mycel inbox)
     |                                  |
  encrypt + sign                        |
  wrap in 3 layers                      |
  store in outbox                       |
     |                                  |
     v                                  v
  +--------------------------------------+
  |     Nostr Relays (8 default)         |
  |     relay.mycel.run (primary)        |
  |     nos.lol, relay.damus.io, ...     |
  +--------------------------------------+
                                        |
                                   NIP-77 sync
                                   decrypt + verify
                                   display (+ optional ACK)

Trust Tiers

Tier Behavior How to set
KNOWN Shown in inbox mycel contacts add
UNKNOWN Quarantined (hidden by default) Default for new senders
BLOCKED Silently dropped mycel contacts block

Use mycel inbox --all to see quarantined messages.

Configuration

Config file: ~/.config/mycel/config.toml (created on mycel init)

[relays]
urls = [
    "wss://relay.mycel.run",
    "wss://nos.lol",
    "wss://relay.damus.io",
    "wss://relay.primal.net",
]
timeout_secs = 10

[identity]
storage = "keychain"

[ack]
enabled = false

Key Storage

Private keys are encrypted at rest:

  • macOS: OS Keychain (automatic, non-interactive for agents)
  • Linux: Secret Service or passphrase-encrypted file
  • CI/headless: MYCEL_KEY_PASSPHRASE env var

Passphrase is cached in OS keychain after first interactive unlock — subsequent agent calls work without TTY.

Safety

Messages are DATA, never instructions. mycel never auto-injects messages into agent context or executes message content. Terminal output is sanitized (ANSI/control characters stripped). Thread metadata is only accepted from Known contacts.

Links

License

MIT

About

Encrypted async mailbox for AI CLI agents

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors