Hermes-style personal AI agent powered by the Mirai cloud API
Project description
Mirai Agent
A Hermes-style personal AI agent (mirai-agent, Python 3.11+) living in the
Mirai monorepo. The model backend is the Mirai cloud API
(https://satuapps.com/v1, OpenAI-shaped with tool calling and billing);
architecture mirrors Hermes Agent:
one agent core, thin I/O shells.
Docs on the website
Install / quickstart / config / skills / gateway notes (en + id):
https://satuapps.com/agent. Desktop installers are shipped via
satuapps.com /downloads (CI artifacts uploaded by the operator — not a
public open-source GitHub Releases channel). Self-host with Docker:
see Distribution → Docker below.
Status
- Phase 1 — agent core: provider, conversation loop, tool registry with 8 built-in tools, permissions, pytest suite.
- Phase 2 — state, memory, skills:
state.db(SQLite + FTS5),SOUL.md/MEMORY.md/USER.md,SKILL.mdskills with progressive disclosure, context compression, cron scheduler. - Phase 3 — interfaces: interactive CLI (prompt_toolkit + Rich,
slash commands) +
mirai-agent serve(FastAPI WebSocket JSON-RPC with the approval flow) for the desktop app — see docs/serve-protocol.md. - Phase 4 — Electron desktop:
desktop/spawnsmirai-agent serve, safeStorage auth, approvals UI, tray/menus. - Phase 5 — packaging: PyInstaller sidecar, electron-builder dmg/nsis, electron-updater, PyPI-ready metadata, CI matrix.
- Phase 6 — messaging gateway:
mirai-agent gateway runasyncio daemon with Telegram (long-poll), Discord, Slack Socket Mode, WhatsApp Cloud API, and generic HTTP webhook adapters; allowlist auth, per-chat sessions, pid/lock/state files, graceful shutdown. - Phase 7 — website:
/agentpage (en/id) + READMEs. - Hermes bare-min parity: MCP client,
delegate_task,web_search,session_search,memorytools, thin pre/post tool hooks — see docs/hermes-parity.md. - Web control panel:
mirai-agent panelserves a localhost web UI (chat, sessions, skills, cron, gateways, MCP, config, usage) reusing the serve/wsJSON-RPC backend — see docs/panel.md.
Layout
agent/
├── pyproject.toml # uv-managed, package `mirai-agent` (PyPI-ready)
├── Dockerfile # single-user self-host image (panel default)
├── docker-compose.yml # panel + optional serve/gateway profiles
├── packaging/mirai-agent.spec
├── scripts/
│ ├── build_sidecar.sh|.ps1 # PyInstaller onedir for desktop
│ ├── install.sh|.ps1 # end-user install stubs (uv/pip)
│ └── publish.sh # build sdist/wheel (no upload)
├── docs/serve-protocol.md # the desktop WebSocket contract (v1)
├── src/mirai_agent/
│ ├── config.py # MIRAI_API_KEY env → ~/.mirai-agent/config.yaml
│ ├── home.py # $MIRAI_AGENT_HOME (~/.mirai-agent)
│ ├── permissions.py # read auto-runs; write/shell need approval
│ ├── core/
│ │ ├── aiagent.py # AIAgent facade (one core, many shells)
│ │ ├── conversation_loop.py
│ │ └── prompt_builder.py # stable/context/volatile tiers
│ ├── providers/mirai.py # httpx; JSON tool rounds + simulated SSE
│ ├── tools/ # registry + builtins (files, shell, search,
│ │ # fetch_url, web_search, memory, session_search,
│ │ # skill_view, delegate_task) + MCP client
│ ├── hooks.py # thin pre_tool / post_tool seam
│ ├── state/db.py # SQLite + FTS5 sessions/messages/usage
│ ├── skills/ # SKILL.md discovery + skill_view tool
│ ├── compression.py # summarize-oldest-turns compaction
│ ├── cron/ # jobs.json + background ticker
│ ├── cli/ # Phase 3: display / slash commands / REPL
│ ├── serve/ # Phase 3: protocol / sessions+approvals /
│ │ # FastAPI WS gateway
│ ├── panel/ # Web control panel: FastAPI REST + static UI
│ └── gateway/ # multi-platform runner (pid/lock/state)
│ └── platforms/ # telegram, discord, slack, whatsapp, webhook
└── tests/ # pytest, fully mocked — no real API calls
Parity notes vs Hermes: docs/hermes-parity.md.
Quick start (dev)
cd agent
uv venv && uv pip install -e ".[dev]" # dev = all extras + pytest
export MIRAI_API_KEY=mirai-… # or api_key: in ~/.mirai-agent/config.yaml
mirai-agent # interactive REPL
mirai-agent -p "what files are in this repo?" # one-shot
mirai-agent serve # headless WS server on :9199
pytest
End users install from PyPI:
uv tool install "mirai-agent[all]"
# or: pip install "mirai-agent[all]"
Then run mirai-agent, mirai-agent panel, or Docker Compose (see
Distribution below). The bare install stays minimal (httpx/pydantic/pyyaml —
agent core only); mirai-agent[cli] and mirai-agent[serve] are the
individual extras. Helpers: scripts/install.sh /
scripts/install.ps1.
Interactive CLI (Phase 3)
prompt_toolkit + Rich: streamed answers, tool/diff rendering, a cost line per turn, a status bar (model · permission mode · cwd · git branch), and persistent prompt history. Slash commands:
/help Show help /skills [name] List or view skills
/model [name] Show or set model /memory Show MEMORY.md
/clear Fresh session /compact Summarize old history
/cost Tokens & est. cost /exit Quit
/model persists to config.yaml; /clear starts a fresh state.db
session; write/shell approvals (yes / no / always-project / global) mirror
the Node CLI's UX.
Headless serve (Phase 3)
mirai-agent serve [--host 127.0.0.1] [--port 9199] [--yolo|--read-only]
FastAPI + uvicorn. GET /health is the readiness probe;
ws://<host>:<port>/ws speaks versioned JSON-RPC 2.0 (protocol: 1):
methods ping, server.info, chat.send (streams chat.chunk +
chat.tool_* events), tool.approval_response, sessions.list,
sessions.get; events server.hello and tool.approval_request (the
client answers with once / always-project / always-global / deny).
Sessions live in the same state.db, so a desktop session can be resumed
from the CLI and vice versa. Full contract with message shapes and
examples: docs/serve-protocol.md.
Web control panel
mirai-agent panel serves a localhost web UI on top of the same /ws
JSON-RPC backend the desktop app uses — so you can manage your local
agent from a browser without the Electron app.
mirai-agent panel # http://127.0.0.1:9200
mirai-agent panel --port 8080 # custom port
Sections: Chat (streaming + tool/approval UI over /ws), Sessions
(list / search / resume / delete), Skills (list / view), Cron (add /
run now / toggle / delete), Gateways (per-platform status, start/stop,
allowlist), MCP servers (add / remove / test), Config (edit
config.yaml safely, API key redacted), Usage/cost (from state.db).
The built UI ships inside the wheel, so mirai-agent panel works out of
the box. To rebuild from source: cd agent/panel && npm install && npm run build (writes src/mirai_agent/panel/static/). Security: binds to
127.0.0.1 only by default; a non-loopback bind requires panel.token in
config.yaml and presents that bearer on every request. Full notes:
docs/panel.md.
Key design facts
- The Mirai API replaces client system prompts with its brand prompt
server-side. Agent identity (SOUL.md), project context (MIRAI.md /
AGENTS.md), and memory therefore travel inside the first user message
of each session (
<agent_context>…</agent_context>), handled bycore/prompt_builder.py. - Tool rounds are non-stream JSON; plain assistant text comes back as simulated SSE. The provider tolerates both transparently.
- 402 means top up — surfaced as
PaymentRequiredErrorwith the subscription URL. - Permissions:
readtools run freely;write/shellask (once / always project / always global / deny), with--yolo/--autoand--read-onlymodes. Allowlists live in.mirai/permissions.json(project) and~/.mirai-agent/permissions.json(global).
Messaging gateway
mirai-agent gateway run starts an asyncio daemon that connects every
configured platform, authorizes chats against per-platform allowlists,
maps each chat to a persistent state.db session ({platform}-{chat_id}),
runs the message through the shared AIAgent core, and delivers the reply.
mirai-agent gateway run # foreground daemon (Ctrl-C to stop)
mirai-agent gateway status # pid / state / platforms / offsets
Config (~/.mirai-agent/config.yaml) — enable any subset:
gateway:
permission_mode: read-only # SAFE DEFAULT for chat surfaces
telegram:
bot_token: "123456:ABC..." # or MIRAI_TELEGRAM_BOT_TOKEN
allow_from: [123456789, "@you"]
discord:
bot_token: "…" # or MIRAI_DISCORD_BOT_TOKEN (needs websockets)
allow_from: ["1234567890"]
slack:
bot_token: "xoxb-…" # MIRAI_SLACK_BOT_TOKEN
app_token: "xapp-…" # MIRAI_SLACK_APP_TOKEN (Socket Mode)
allow_from: ["U123", "C456"]
whatsapp: # Meta Cloud API (not Baileys)
access_token: "…" # MIRAI_WHATSAPP_ACCESS_TOKEN
phone_number_id: "…" # MIRAI_WHATSAPP_PHONE_NUMBER_ID
verify_token: "mirai-verify"
webhook_port: 8787
allow_from: ["15551234567"]
webhook: # generic HTTP POST → agent → callback
host: "127.0.0.1"
port: 8788
path: "/hook"
secret: "…" # Bearer / X-Mirai-Secret
allow_from: ["*"]
Also useful agent features (Hermes bare-min):
mcp_servers:
filesystem:
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
Built-in tools added for parity: web_search, session_search, memory,
delegate_task. Thin pre_tool / post_tool hooks live in
mirai_agent.hooks.
Behavior notes:
- Authorization — only
allow_fromchats reach the agent (webhook may use"*"). Match by ID or username; empty allowlist denies everyone. - Sessions — deterministic
{platform}-{chat_id}rows instate.db. - Permissions — gateway defaults to
read-only; opt in viagateway.permission_mode: autoor allowlists inpermissions.json. - Process files under
~/.mirai-agent/:gateway.pid,gateway.lock,gateway_state.json. - Discord / Slack need the
websocketspackage (mirai-agent[serve]/[all]/[dev]). - Deferred (not bare-min): email, Baileys WhatsApp, browser/vision/TTS, ACP, full dashboard — see docs/hermes-parity.md.
Distribution (Phase 5)
Docker (single-user self-host)
Image runs the web panel by default; compose profiles add headless
serve and/or the messaging gateway. State is a volume at /data
(MIRAI_AGENT_HOME). Non-loopback panel binds need MIRAI_PANEL_TOKEN.
cd agent
export MIRAI_API_KEY=mirai-…
export MIRAI_PANEL_TOKEN=$(openssl rand -hex 16)
docker compose up --build
# Panel: http://127.0.0.1:9200/?token=$MIRAI_PANEL_TOKEN
# Optional:
docker compose --profile serve up # + :9199 JSON-RPC
docker compose --profile gateway up # messaging daemon
Files: Dockerfile, docker-compose.yml.
This is single-user self-host (your key, your volume) — not a
multi-tenant cloud control plane.
Terminal users (PyPI)
Package name: mirai-agent — live on
PyPI.
uv tool install "mirai-agent[all]"
# or:
pip install "mirai-agent[all]"
Then:
export MIRAI_API_KEY=mirai-…
mirai-agent # interactive CLI
mirai-agent panel # localhost web UI (:9200)
Docker Compose is under Docker above. Helpers:
scripts/install.sh /
scripts/install.ps1.
Maintainers — publish a new version:
cd agent
uv build # or: bash scripts/publish.sh
uv publish # wheel + sdist under dist/
Desktop sidecar (PyInstaller)
Builds a onedir binary with [cli] + [serve] extras for Electron
extraResources:
bash scripts/build_sidecar.sh # macOS / Linux → dist/mirai-agent/mirai-agent
# Windows: .\scripts\build_sidecar.ps1 → mirai-agent.exe
Architecture is native to the builder (Apple Silicon arm64 on
macos-14, x64 on windows-latest / ubuntu-latest). Spec:
packaging/mirai-agent.spec. Staged copy
lands in desktop/resources/mirai-agent/ for electron-builder.
See desktop/README.md for dmg / nsis /
AppImage / deb, satuapps.com download hosting
(tools/publish-desktop-artifacts.sh), and CI
(.github/workflows/desktop.yml).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mirai_agent-0.1.1.tar.gz.
File metadata
- Download URL: mirai_agent-0.1.1.tar.gz
- Upload date:
- Size: 189.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
93f4e0f986a8ef3c122b3e546bdb5b4f8ad9fa7918fd1a4b746007a0b07c2b9f
|
|
| MD5 |
faa65251c11110f8456553a546821665
|
|
| BLAKE2b-256 |
314ddcaecb869d0f7997e07dc842d0d218c4ee0e98236137ffce983e985f8b12
|
File details
Details for the file mirai_agent-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mirai_agent-0.1.1-py3-none-any.whl
- Upload date:
- Size: 185.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
26c9f669f5b8a1b360fbd6d0d947e48de61d87c08da3b33e59bdcb351f699d50
|
|
| MD5 |
a6f947332ee3803672a2bb315ac090dc
|
|
| BLAKE2b-256 |
cc1f963c9bf09c949644f29e8fbc7458ee378becb4bf367600ca41012ba1c576
|