Skip to content

Configuration

Configure startup, global and conversation settings, platform credentials, sandbox limits, and environment variables.

mikan requires a global settings file before normal startup. Create it once, review it, then start mikan with a workspace:

Terminal window
mikan --onboard
mikan --sandbox=host /path/to/workspace

The default state directory is ~/.mikan. Use the same --state-dir for onboarding and normal startup when you choose another location:

Terminal window
mikan --onboard --state-dir=/secure/mikan-state
mikan --state-dir=/secure/mikan-state /path/to/workspace

mikan creates a missing state directory with mode 0700. An existing directory must be owned by the current user and must not be world-writable. For sandboxed modes, keep it outside the workspace so tools cannot reach credentials or administrator settings.

ScopePathPurpose
Global<state-dir>/settings.jsonRequired defaults for every conversation
Conversation<state-dir>/conversations/<officeKey>/settings.jsonPartial overrides for one conversation

Conversation settings are host-authoritative. Older <workspace>/<officeKey>/settings.json files are migrated on first access and are not read again from the sandbox-visible workspace.

Every conversation is an office, identified by its platform plus the platform’s raw conversation id. Storage paths use the office key derived from both — v1-<platform>-<readable-id>-<hash>, for example v1-slack-c0aaaaaa1-1f4b9c0d2e3a5b7c — so two platforms that happen to share a raw conversation id can never address each other’s files, settings, or credentials. The same key names the office directory in the workspace, its state directory, and its vault.

Office keys are not reversible to a raw platform id, so the host keeps a registry at <state-dir>/office-registry.json recording each office’s platform and conversation id. Use mikan office list to read it.

Upgrading from a release that stored conversations under raw platform ids migrates those directories, vaults, and state trees to the office-key layout on the next start; see Deployment.

mikan --onboard creates:

{
"llm": {
"provider": "anthropic",
"model": "claude-sonnet-4-6",
"thinkingLevel": "off",
"autoReply": {
"provider": "anthropic",
"model": "claude-haiku-4-5"
}
},
"slack": {
"replyMode": "top-level"
},
"sandbox": {
"cpus": "0.5",
"memory": "1g",
"boost": {
"cpus": "2",
"memory": "4g"
},
"workspace": {
"doorPolicy": "isolated"
},
"defaultSharedVault": ""
}
}

The values below are generated by onboarding. llm.provider, llm.model, and llm.thinkingLevel are required in the resolved global configuration; the other fields may be omitted.

FieldOnboarding valueDescription
llm.provideranthropicMain AI provider
llm.modelclaude-sonnet-4-6Main model name
llm.thinkingLeveloffoff, minimal, low, medium, high, xhigh, or max
llm.autoReply.provideranthropicOptional model provider used to evaluate auto-reply rules
llm.autoReply.modelclaude-haiku-4-5Optional model used to evaluate auto-reply rules
sentry.dsnunsetSentry DSN; sensitive prompt and tool content is redacted
sandbox.cpus0.5CPU limit for mikan-managed image/Gondolin runtimes; Gondolin rounds fractional values up to whole vCPUs
sandbox.memory1gMemory limit for mikan-managed image/Gondolin runtimes
sandbox.boost.cpus2Temporary CPU limit applied by /pi-sandbox boost
sandbox.boost.memory4gTemporary memory limit applied by /pi-sandbox boost
sandbox.workspace.doorPolicyisolatedisolated locks each conversation to its own office data; trusted explicitly permits a collaborative workspace layout
sandbox.workspace.layoutconversationEffective layout: isolated always uses conversation; trusted uses shared-support or full
sandbox.defaultSharedVaultemptyShared vault copied into eligible membership-trust image/Cloudflare conversations
slack.replyModetop-levelSlack response mode: top-level or thread

/pi-model writes a partial conversation override, and /pi-sandbox door <default|isolated|shared|full> writes the conversation’s sandbox.workspace override; the admin portal sets both the per-office and the global door policy. Auto-reply enablement and rule text are managed by /pi-auto-reply and the conversation’s auto-reply marker file, not by the JSON settings fields.

Door policy and layout resolve together. isolated always means the conversation layout: only the office’s own directory is mounted. trusted means either shared-support — the office plus the workspace-level MEMORY.md, skills/, and events/ — or full, which mounts the whole workspace root. A door policy of trusted with no layout resolves to shared-support.

Legacy sandbox.image.workspaceMount remains readable for migration: private means trusted + shared-support, while full means trusted + full. Fresh installs write the canonical backend-neutral settings and default to isolated.

At least one complete platform credential set is required for normal bot mode:

PlatformRequired environment variablesOptional variables
SlackSLACK_APP_TOKEN, SLACK_BOT_TOKEN
TelegramTELEGRAM_BOT_TOKEN
DiscordDISCORD_BOT_TOKEN
GitHubGITHUB_APP_ID, GITHUB_INSTALLATION_ID, and GITHUB_APP_PRIVATE_KEY or GITHUB_APP_PRIVATE_KEY_PATHGITHUB_REPOS, GITHUB_POLL_INTERVAL

See Platform adapters for platform-specific setup and permissions.

The formal Web adapter is enabled when the HTTP server and at least one complete account OAuth provider are configured. These OAuth clients are separate from /pi-login credential-onboarding clients and must use only account-profile scopes.

ProviderRequired environment variablesExact callback URL
GitHubWEB_GITHUB_OAUTH_CLIENT_ID, WEB_GITHUB_OAUTH_CLIENT_SECRET<LINK_URL>/auth/github/callback
GoogleWEB_GOOGLE_OAUTH_CLIENT_ID, WEB_GOOGLE_OAUTH_CLIENT_SECRET<LINK_URL>/auth/google/callback

Set LINK_URL to the canonical externally visible HTTPS origin in production and LINK_PORT to the local listen port (or omit the port to use 8181 when LINK_URL is set). Production callback URLs are never derived from forwarded request headers. Header-derived callback origins and cookies without Secure are accepted only when the request is explicitly on a loopback host for local development.

GitHub account sign-in requests read:user user:email; Google requests openid email profile. Provider tokens are discarded after the identity profile is loaded. Browser sign-in does not write credentials to a conversation vault—/pi-login remains a separate one-time capability.

Each account receives a default Personal workspace. Every Web workspace becomes an independent web office, so it does not automatically share sessions, memory, files, sandbox state, or vault state with Slack, Telegram, Discord, or GitHub-adapter conversations.

The formal React application is served at / with owned workspace routes under /w/<opaque-workspace-id>. It uses account/workspace projections only, keeps its CSRF token in memory, and receives transient run, queue, tool, and subagent state through a workspace-scoped stream. Pi session history remains the durable transcript. The older /pi-session, /pi-login, and /admin pages retain their separate capability-token boundaries for messaging-adapter support and are not Web account screens.

For source development, run the backend on port 8181 and start npm run dev:web; Vite proxies /api and /auth to the backend. npm run build emits the browser bundle to dist/web-app alongside the compiled Node server.

Command or optionPurpose
mikan --onboard [--state-dir=<dir>]Create the required global settings file
mikan [--state-dir=<dir>] [--sandbox=<mode>] [working-directory]Start configured platform bots; the working directory defaults to <state-dir>/workspace
--sandbox=host | container:<name> | image:<image> | gondolin:default | firecracker:... | cloudflare:<id>Select tool execution mode; default is host
mikan envShow the full environment-variable inventory and what is currently set
mikan --download <channel-id>Download Slack channel history; requires SLACK_BOT_TOKEN
mikan --versionPrint the installed version
mikan --helpShow CLI usage and the platform-token summary
mikan ext ...Manage harness extensions; run mikan ext for subcommands
mikan office listList registered offices, enabled platforms, and pending legacy migrations
mikan office claim <conversationId> <platform>Name the owning platform of a legacy raw-id directory boot could not attribute

mikan office accepts --state-dir <dir> and --workspace <dir>; the workspace defaults to <state-dir>/workspace. claim only records the decision — the daemon performs the move on its next start, so run it with the daemon stopped.

Environment variables read through mikan’s configuration helper also accept a MIKAN_ prefix. For example, MIKAN_SLACK_APP_TOKEN and MIKAN_LINK_URL are fallbacks for SLACK_APP_TOKEN and LINK_URL; the unprefixed value takes precedence. SENTRY_DSN is the exception: configure it directly or set sentry.dsn in settings.json.

The daemon’s full environment interface is declared as a manifest in the source tree; mikan env prints the annotated inventory grouped by platform and feature, with the current status of each variable, so you can audit a deployment without reading code.

mikan writes logs to stdout/stderr. Use PM2, systemd, Docker, or your hosting platform to route and retain them.