Skip to content

Repository files navigation

mikan office architecture — conversation-scoped workspaces and sandbox execution

@geminixiang/mikan

npm version License: MIT

A multi-platform AI coding agent for Slack, Telegram, Discord, and GitHub.

Warning

Pre-1.0 status — the overall framework stabilizes at 1.0.0. Until then, releases may change settings and on-disk data formats without migrations: upgrading between pre-1.0 versions can require resetting or manually adjusting existing state and workspace data.

Architecture

mikan keeps the chat record, agent session, and execution runtime separate:

mikan architecture

  • Conversation office is the unit everything else hangs off: one conversation's working area plus its own sandbox runtime. An office is identified by its platform and raw conversation id, and its directory is named by an office key (v1-<platform>-<readable-id>-<hash>), so two platforms can never collide on the same raw id.
  • Chat / conversation data is the platform-facing record: log.jsonl, attachments, and conversation files.
  • Session orchestration turns platform events into agent runs, handles top-level/thread scopes, and persists structured context under sessions/*.jsonl.
  • mikan agent harness (src/harness/, built on pi-agent-core and pi-ai) runs the model loop, session persistence, compaction, and calls mikan tools.
  • Sandbox runtime is where tool commands execute: host, Docker container/image, or the experimental Cloudflare bridge.
  • Vault provides runtime credentials as env vars and mounted secret files.

Features

  • Multi-platform — Slack, Telegram, Discord, and GitHub adapters
  • Concurrent conversations — Slack threads, Discord replies/threads, and Telegram reply chains run as independent sessions
  • Conversation offices — one office directory and one sandbox runtime per conversation, with platform-derived workspace sharing and explicit door-policy overrides
  • Sandbox execution — host, shared container, per-conversation managed container, or Cloudflare bridge (experimental)
  • Credential vaults/login stores credentials under --state-dir and injects env into sandbox runs
  • Web session viewer — read-only web view of the current session via session / /session
  • Persistent memory — workspace-level and per-office MEMORY.md
  • Skills — drop CLI tools into skills/
  • Events — schedule one-shot or recurring tasks via JSON files
  • Multi-provider — any provider/model supported by pi-ai

Requirements

  • Node.js >= 22.19.0

Installation

npm install -g @geminixiang/mikan

Or from source:

npm install && npm run build

Quick Start

Run mikan under PM2 so it stays up, restarts after failures, and starts on boot:

npm i -g @geminixiang/mikan pm2

# One-time setup: create the state directory and settings
mikan --onboard --state-dir=~/.mikan

# Secrets live in ~/.mikan/mikan.env (0600), outside any repo tree
curl -o ~/.mikan/mikan.env https://raw.githubusercontent.com/geminixiang/mikan/main/deploy/pm2/mikan.env.example
chmod 600 ~/.mikan/mikan.env   # then fill in your tokens

# Pull the sandbox image the default deployment runs tools in
docker pull ghcr.io/geminixiang/mikan-sandbox:latest

# Grab the maintained ecosystem file (supervision only), edit `args`
curl -O https://raw.githubusercontent.com/geminixiang/mikan/main/deploy/pm2/ecosystem.config.cjs

pm2 start ecosystem.config.cjs
pm2 save
pm2 startup   # run the printed command to enable boot autostart

Each file has one job: settings.json holds behavior (model, sandbox limits, reply modes — the Admin surface), ~/.mikan/mikan.env holds secrets and platform tokens, and ecosystem.config.cjs holds process supervision only. In ecosystem.config.cjs, point args at your state dir, sandbox mode, and working directory (mikan --help documents the flags):

args: "--state-dir=/srv/mikan/state --sandbox=image:ghcr.io/geminixiang/mikan-sandbox:latest /srv/mikan/workspace",

Set the platform tokens you need in ~/.mikan/mikan.env; you can run multiple platforms at once. mikan env prints the full inventory and what is currently set:

SLACK_APP_TOKEN=xapp-...
SLACK_BOT_TOKEN=xoxb-...
TELEGRAM_BOT_TOKEN=123456:ABC-...
DISCORD_BOT_TOKEN=MTI...
GITHUB_APP_ID=123456
GITHUB_INSTALLATION_ID=12345678
GITHUB_APP_PRIVATE_KEY_PATH=/srv/mikan/github-app.pem

Tail logs with pm2 logs mikan; upgrade with npm i -g @geminixiang/mikan && pm2 reload mikan. See the deployment guide for sandbox images, graceful shutdown, and the health endpoint.

For a one-off foreground run, the same CLI works directly:

mikan [--state-dir=~/.mikan] [--sandbox=<mode>] [<working-directory>]

The working directory is optional: it defaults to <state-dir>/workspace (so ~/.mikan/workspace with the default state dir) and is created on first run.

Platforms

  • Slack — create a Socket Mode app using src/content/docs/slack-bot-minimal-guide.md. The bot responds when @mentioned in channels and to all DMs.
  • Telegram — create a bot via @BotFather. The bot responds to private messages, @mention, and reply chains in groups.
  • Discord — create an application in the Discord Developer Portal, enable Message Content Intent, and invite it with message/file permissions.
  • GitHub — install a GitHub App (polling, no webhooks) and set GITHUB_APP_ID, GITHUB_INSTALLATION_ID, and a private key. One issue or PR is one conversation. See src/content/docs/platform-adapters/github.md.

Slack threads, Discord replies/threads, and Telegram reply chains are mapped to independent session scopes. See src/content/docs/sessions.mdx.

Sandbox

Mode Description
host (default) Run on host; no vault env injection
container:<name> Run in an existing shared container; everyone sharing it shares its one vault
image:<image> Auto-provision one Docker container and one vault per conversation office
cloudflare:<sandbox-id> Cloudflare Worker bridge (experimental; no auto workspace sync)

Each office's data view is set by its door policy. Without an explicit workspace setting, Slack follows the channel kind: public channels use trusted shared support and can update workspace MEMORY.md; private channels can read that shared memory but receive it read-only; DMs, external channels, unknown channel kinds, and other platforms stay isolated. The admin portal or /pi-sandbox door <default|isolated|shared|shared-private|full> can override that result. Door policy governs data access only; execution isolation is unaffected.

Only image:* can enforce isolated projections and read-only shared memory. host, container:*, and cloudflare:* therefore fail closed for isolated or private-channel projections; an admin must either use image:* or explicitly select a trusted read-write layout.

For routing, mounts, vault behavior, managed container details, and Cloudflare notes, see src/content/docs/sandbox.mdx.

Chat commands

Command Purpose
/login / /pi-login Store API keys or run built-in OAuth flows
session / /session Open a read-only web view of the current session
/new / /pi-new Reset the current session
/model / /pi-model provider/model[:thinking] Switch the LLM for the current conversation
/sandbox / /pi-sandbox [boost|door …] Show sandbox status, boost limits, or set the office door policy
/admin / /pi-admin Open the admin portal
/auto-reply / /pi-auto-reply on|off|status Control group/channel auto-reply
stop / /stop Stop the current run (works on every platform)

session is the only command accepted without a leading slash. See src/content/docs/commands.mdx for the full command reference and web session viewer setup.

Configuration

mikan reads global settings from <state-dir>/settings.json; host-only per-conversation overrides live at <state-dir>/conversations/<office-key>/settings.json. Legacy workspace settings are migrated once, then ignored.

{
  "llm": {
    "provider": "anthropic",
    "model": "claude-sonnet-4-6",
    "thinkingLevel": "off"
  }
}

See src/content/docs/configuration.md for all fields.

Data layout

<state-dir>/
├── settings.json
├── office-registry.json
├── conversations/
│   └── <office-key>/
│       └── settings.json
└── vaults/

<working-directory>/
├── MEMORY.md
├── skills/
├── events/
├── agents/
└── <office-key>/
    ├── MEMORY.md
    ├── SYSTEM.md
    ├── log.jsonl
    ├── attachments/
    ├── scratch/
    ├── skills/
    └── sessions/

Office directories are named by office key (v1-<platform>-<readable-id>-<hash>) and are not reversible to a raw platform id, so office-registry.json records each office's (platform, conversationId). mikan office list prints the registered offices; deployments created before the office layout are migrated on the next boot, and mikan office claim <conversationId> <platform> names the owner when boot cannot infer it.

More docs

Slack: Download channel history

mikan --download C0123456789

Development

npm run dev
npm test
npm run lint
npm run fmt:check
npm run build

See src/content/docs/development.md for E2E tests.

Contributing

PRs welcome — see CONTRIBUTING.md for dev setup, commit style, and the testing checklist. Bug reports and feature requests go through the GitHub issue templates.

License

MIT — see LICENSE.

About

A multi-platform AI coding agent for Slack, Telegram, and Discord.

Topics

Resources

Contributing

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages