Skip to content

kortiene/mx-agent

Repository files navigation

mx-agent

Matrix-backed CLI + daemon for decentralized orchestration between autonomous coding agents — Pi, Claude Code, and other terminal-based LLM runners.

CI Status: public alpha License: Apache-2.0 MSRV: 1.74 Platform: Unix

mx-agent turns Matrix rooms into federated workspaces where agents discover peers, share execution context (diffs, plans, env snapshots), invoke named tools, stream terminal I/O, and coordinate a distributed task graph — without a central orchestration server and without any inbound firewall port.

📖 Wiki · Getting Started · AI Agent Orchestration · Architecture


Why mx-agent?

Traditional remote-execution tooling assumes a box you can reach inbound — an SSH port, an RPC listener, a VPN or bastion. That breaks the moment your agents live behind NAT, corporate firewalls, or a home router, and it tends to hand long-lived secrets to the very LLM you'd rather not trust with them.

mx-agent inverts that:

Traditional remote execution mx-agent
Needs an inbound port (SSH/RPC/agent listener) Outbound-only — daemons connect out to a homeserver; nothing listens inbound
NAT/firewall traversal needs a VPN/bastion/tunnel Works anywhere an HTTPS connection to a homeserver works
A central coordinator is a single point of failure Federated — state lives in Matrix room history; no central mx-agent server
"Can reach the box" ≈ "can run anything" Room membership ≠ execution rights — every privileged request is Ed25519-signed and checked against deny-by-default local policy
Long-lived secrets handed to the agent The coding agent never sees Matrix tokens or device keys

If a box can sync with a homeserver, it can participate — even one that accepts no inbound connections at all.


Project status

Public alpha (v0.1.0). The architecture, protocol schema, IPC layer, policy engine, Ed25519 signing, and sandbox abstraction are in place. Most CLI subcommands currently parse their arguments and report "not implemented yet" while daemon behavior is filled in across the roadmap. Each capability below is tagged so you always know what runs today.

Area Status
Daemon lifecycle (start / status / stop), background + foreground ✅ Implemented
Local IPC: Unix-socket JSON-RPC 2.0 with 0600 perms + SO_PEERCRED peer check ✅ Implemented
Structured logging, secret redaction, dev Matrix homeserver (Tuwunel) ✅ Implemented
Protocol event schema, Ed25519 signing, policy parser, none sandbox backend ✅ Implemented
auth, workspace, agent, exec, call, task, trust, approval commands 🟡 Argument-parsing placeholders; behavior landing (issue #4)
E2EE in production, bubblewrap/container sandboxes, interactive PTY, large artifacts 🔮 Planned

Platform: Unix only (Linux and macOS). Windows was intentionally dropped — the project relies on Unix-domain-socket IPC and Unix process semantics.


Quickstart

Everything here runs today. (For the full conceptual walkthrough, see the Getting Started wiki page.)

Prerequisites

  • A Unix host (Linux or macOS)
  • Rust stable toolchain, 1.74+ (install via rustup)

Build

git clone https://github.com/kortiene/mx-agent.git
cd mx-agent
cargo build --all --release

Explore the command surface

cargo run -p mx-agent-cli -- --help        # or ./target/release/mx-agent --help

Run the daemon

mx-agent daemon start                 # start detached in the background
mx-agent daemon status                # human-readable status (exit 3 if not running)
mx-agent daemon status --json         # pid, uptime, socket path, version as JSON
mx-agent daemon stop                  # graceful shutdown (SIGTERM, then SIGKILL)

The daemon owns all long-lived state (Matrix session, keys, policy). The CLI is stateless and talks to it over $XDG_RUNTIME_DIR/mx-agent/daemon.sock. The remaining auth / workspace / agent / exec commands accept their final argument shape now but report "not implemented yet" — see Project status.


How it works

 coding agent / shell  ──spawns──▶  mx-agent (CLI, stateless)
                                          │  JSON-RPC over Unix socket (0600, SO_PEERCRED)
                                          ▼
                                   mx-agent daemon  ──signs──▶  com.mxagent.exec.request.v1 (Ed25519)
                                          │  Matrix Client-Server API (+ E2EE)
                                          ▼
                          Matrix homeserver + federation  ◀──▶  remote daemon ──▶ verify → policy → process

A local exec follows the same path as a remote one: the daemon signs an event, publishes it, and its own /sync loop receives it back through the full verify → policy → runner pipeline. See Core Concepts and Architecture.

Security posture

mx-agent is zero-trust and deny-by-default: room membership grants nothing on its own.

  • Every privileged request is Ed25519-signed; the target verifies the signature, nonce, and expiry, then checks local policy before running anything.
  • The coding agent never sees Matrix tokens or device keys — they stay inside the daemon (0600, user-owned).
  • Child processes start from an environment allowlist with secret scrubbing (GITHUB_TOKEN, OPENAI_API_KEY, AWS_*, …).
  • The local IPC socket enforces a SO_PEERCRED UID check and refuses cross-user or world-accessible runtime dirs.
  • The workspace forbids unsafe Rust (unsafe_code = "forbid").

Full details and a complete policy.toml: Security & Sandboxing · Security hardening guide.


Documentation

Doc What it covers
Wiki Conceptual guides: getting started, core concepts, protocol spec, security, AI-agent orchestration
Alpha user guide Install, log in, create a workspace, register agents, run the two-agent demo
Architecture Full system design, protocol, state model, security boundaries
Security hardening guide Safe defaults and unsafe options for tokens, trust, policy, sandboxing, audit
Alpha release checklist The alpha gate, known limitations, rollback/revocation guidance
Rust implementation roadmap Implementation phases
GitHub management · Issue backlog Project process

Development

mx-agent is a Rust Cargo workspace.

Workspace layout

Crate Purpose
mx-agent-cli The mx-agent binary and command surface
mx-agent-daemon Long-running daemon: Matrix sync, crypto, policy, supervision
mx-agent-protocol Event schemas, IDs, and protocol versioning
mx-agent-ipc Local CLI/daemon IPC transport
mx-agent-policy Local authorization policy engine
mx-agent-sandbox Process sandboxing backends

Common commands

cargo build --all       # build every crate
cargo test --all        # run all tests
cargo fmt --check       # verify formatting
cargo clippy --all-targets --all-features -- -D warnings
cargo run -p mx-agent-cli -- --help   # run the placeholder CLI

The same checks run in CI (.github/workflows/ci.yml) and must pass on every PR.

Lint and format configuration

  • Formatting is pinned by rustfmt.toml (stable options only); run cargo fmt to apply.
  • Clippy honors the MSRV in clippy.toml.
  • Shared lints are declared once in [workspace.lints] in the root Cargo.toml and inherited by each crate via [lints] workspace = true. Notably, unsafe_code is forbidden and missing_docs is a warning (treated as an error in CI via -D warnings).
  • Minimum supported Rust version (MSRV): 1.74.

Logging

All mx-agent processes emit structured logs via tracing (to stderr, so --json command output on stdout is never corrupted). Configure logging with:

Variable Values Default Purpose
MX_AGENT_LOG RUST_LOG-style directive unset Log filter (preferred)
RUST_LOG RUST_LOG-style directive unset Log filter fallback
MX_AGENT_LOG_FORMAT human | json human Output format

The CLI -v/-vv/-vvv flags raise the default level (warninfodebugtrace) when no filter env var is set.

MX_AGENT_LOG_FORMAT=json mx-agent -vv agent list   # JSON logs on stderr
MX_AGENT_LOG=mx_agent_daemon=debug,info mx-agent daemon status

Credentials are wrapped in mx_agent_telemetry::Secret, which renders as ***redacted*** in Debug/Display, and mx_agent_telemetry::redact blanks values for secret-looking keys. Never log raw tokens or keys.

Daemon lifecycle

Runtime state lives under $XDG_RUNTIME_DIR/mx-agent/ (override with MX_AGENT_RUNTIME_DIR): a daemon.json status file, the daemon.sock IPC socket, and a daemon.log for background output.

The IPC socket is created with mode 0600; the daemon refuses to run if its runtime directory is group- or world-accessible or owned by another user, and verifies the peer UID via SO_PEERCRED. Stale sockets from a previous run are cleaned up automatically when no daemon is listening. The CLI and daemon communicate over this socket using length-delimited (4-byte big-endian prefix) JSON-RPC 2.0 frames; malformed input yields a controlled JSON-RPC error rather than a dropped connection.

Local Matrix homeserver (dev / e2e)

A throwaway Tuwunel homeserver in Docker is provided for development and the integration/e2e tests:

scripts/matrix_dev.sh up             # start (loopback-only); auto-creates dev/matrix/.env
scripts/matrix_dev.sh register alice # register a test user, print an access token
scripts/matrix_dev.sh reset          # wipe all homeserver data

Then point the daemon at it (homeserver_url = "http://127.0.0.1:8008"). See dev/matrix/README.md for details.

Wiki sync

The wiki/ folder is mirrored to the GitHub wiki on pushes to main via a local pre-push hook. Install it once per clone:

sh scripts/install-wiki-hook.sh

Contributing

Issues and pull requests are welcome. Before opening a PR, run the CI checks locally (cargo fmt --check, cargo clippy --all-targets --all-features -- -D warnings, cargo test --all). See GitHub management for process and the issue backlog for where help is needed.

License

Licensed under the Apache License, Version 2.0.

About

Decentralized Matrix-backed CLI for autonomous coding agents to discover peers, share context, stream terminal I/O, and orchestrate distributed workflows across machines without central servers or exposed firewalls.

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors