Feature matrix
A scannable projection of every mono-agent capability for non-linear readers: each feature id mapped to its coverage type, the config key(s) and env var(s) that reach it, the prose page that explains it, and any playbook that puts it to work.
docs/reference/feature-registry.md is the canonical long-form source of truth — when this matrix and the registry disagree, the registry wins. This page projects the same rows into a grid for quick lookup.
Coverage legend
Section titled “Coverage legend”| Code | Meaning |
|---|---|
config | Declarable in mono-agent.config.json; an env override exists only where one is listed (-- means JSON-only / no env form) |
cli | Reached through a mono-agent CLI flag/command |
auto | Always active when the app runs; needs no declaration |
code | Programmatic escape hatch only — see Programmatic API |
dev | Development/test-time tooling, not part of a running agent |
Env precedence everywhere: process env > mono-agent.config.json > built-in defaults.
Runtime
Section titled “Runtime”| Feature id | Coverage | Config key(s) | Env var(s) | Prose page | Playbook(s) |
|---|---|---|---|---|---|
runtime.multi-backend | config | runtime.model | MONO_AGENT_MODEL | Pi runtime | Multi-model fallback |
runtime.fallback-models | config | runtime.fallbacks[].{model,effort?}; CLI uses repeated --fallback (legacy --fallback-models flag removed) | MONO_AGENT_FALLBACKS_JSON | Fallback | Multi-model fallback |
runtime.effort | config | runtime.effort, runtime.fallbacks[].effort | MONO_AGENT_EFFORT, MONO_AGENT_FALLBACKS_JSON | Execution, effort, permissions | — |
runtime.per-trigger-model | config + code | cron.jobs[].{model,effort}; webhook.endpoints[].{model,effort} + request body {model,effort}; Telegram built-ins /model and /effort; Slack Block Kit selectors through thread-local @agent /model / @agent /effort and channel-wide workspace commands /<bot>-model / /<bot>-effort, all over configured primary/fallback models | MONO_AGENT_CRON_MODEL / MONO_AGENT_CRON_EFFORT, MONO_AGENT_WEBHOOK_MODEL / MONO_AGENT_WEBHOOK_EFFORT; Telegram/Slack controls have no env key | Cron · Webhook · Telegram · Slack | — |
runtime.permission-mode | config | runtime.permissionMode | MONO_AGENT_PERMISSION_MODE | Execution, effort, permissions | Sandboxed code agent |
runtime.max-turns | config | runtime.maxTurns | MONO_AGENT_MAX_TURNS | Pi runtime | — |
runtime.workspace | config | runtime.workspace | MONO_AGENT_WORKSPACE | Pi runtime | — |
runtime.provider-sessions | config | runtime.session.mode, runtime.session.idleTimeoutMs, runtime.session.rollover, runtime.session.rolloverTimezone, runtime.session.rolloverNotice | MONO_AGENT_SESSION_MODE, MONO_AGENT_SESSION_IDLE_TIMEOUT_MS, MONO_AGENT_SESSION_ROLLOVER, MONO_AGENT_SESSION_ROLLOVER_TIMEZONE, MONO_AGENT_SESSION_ROLLOVER_NOTICE | Sessions & concurrency | — |
runtime.concurrency | config | concurrency.maxConcurrentRuns, concurrency.maxPendingRuns | MONO_AGENT_CONCURRENCY_MAX_CONCURRENT_RUNS, MONO_AGENT_CONCURRENCY_MAX_PENDING_RUNS | Sessions & concurrency | — |
runtime.local-providers | config | providers.local[] | MONO_AGENT_LOCAL_PROVIDERS_JSON, MONO_AGENT_LOCAL_PROVIDER_* | Local providers | Local-only Ollama agent |
runtime.providers | config | providers.<providerId>, providers.local[], providers.piAuthPath, providers.piNative.* | MONO_AGENT_PROVIDERS_JSON, MONO_AGENT_PI_AUTH_PATH, MONO_AGENT_PI_* | Providers | — |
runtime.pi-credentials | config | providers.piAuthPath (OAuth/account and API-key credentials such as OpenCode-Go) | MONO_AGENT_PI_AUTH_PATH | Local providers | — |
runtime.pi-native-tuning | config | providers.piNative.transport, providers.piNative.piMaxRetries, providers.piNative.maxRetryDelayMs, providers.piNative.piSessionsRoot | MONO_AGENT_PI_TRANSPORT, MONO_AGENT_PI_MAX_RETRIES, MONO_AGENT_MAX_RETRY_DELAY_MS, MONO_AGENT_PI_SESSIONS_ROOT | Sessions & concurrency | — |
runtime.tool-parallelism | code | runtimeOptions.piToolExecutionMode | — | Tools & guards | — |
runtime.web-research | config + auto | tools.web.search.*, tools.web.fetch.* | MONO_AGENT_WEB_SEARCH_BACKEND, MONO_AGENT_WEB_SEARCH_MAX_REQUESTS_PER_RUN, MONO_AGENT_WEB_SEARCH_SEARXNG_ENDPOINT, MONO_AGENT_WEB_SEARCH_OLLAMA_*, MONO_AGENT_WEB_SEARCH_CODEX_MODEL, MONO_AGENT_WEB_FETCH_RENDER, MONO_AGENT_WEB_BROWSER_COMMAND | Local-first web research | Local-first web research agent |
runtime.webfetch-retry | auto | (built into WebFetch) | — | Tools & guards | — |
runtime.context-compaction | config + provider | runtime.compaction.* | MONO_AGENT_COMPACTION_* | Tools & guards | — |
runtime.tool-bloat-guard | auto | (artifacts land in artifacts.dir) | MONO_AGENT_ARTIFACT_DIR | Tools & guards | — |
runtime.cost-tracking | auto | (recorded in JSONL artifacts) | — | Artifacts & traces | — |
runtime.builtin-tools | config | tools.allowedTools, tools.disallowedTools | MONO_AGENT_ALLOWED_TOOLS, MONO_AGENT_DISALLOWED_TOOLS | Tools & guards | — |
runtime.structured-output | code | runtimeOptions.outputSchema (every Pi runtime route) | — | Approval & structured output | — |
runtime.live-input | auto + code | Slack/Telegram active-turn steering plus the web console’s single server-authoritative Send path, with exact host-operation ownership, separate native acceptance, exact transcript consumption, uncertainty/no automatic retry, durable UUID receipts, and confirmed safe-preview Steered activity; custom runtimeOptions.liveInput | — | Approval & structured output | — |
runtime.approval-gates | code | createMonoRuntime({ onToolApprovalRequest, ... }) (config posture: runtime.permissionMode) | MONO_AGENT_PERMISSION_MODE | Approval & structured output | — |
runtime.custom | code | startMonoAgentApp({ runtime }) | — | Composition | — |
Sandbox
Section titled “Sandbox”| Feature id | Coverage | Config key(s) | Env var(s) | Prose page | Playbook(s) |
|---|---|---|---|---|---|
sandbox.mode | config | sandbox.mode | MONO_AGENT_SANDBOX_MODE | Sandbox | Sandboxed code agent |
sandbox.network-policy | config | sandbox.network.mode, sandbox.network.allowlist | MONO_AGENT_SANDBOX_NETWORK, MONO_AGENT_SANDBOX_NETWORK_ALLOWLIST | Sandbox | Sandboxed code agent |
sandbox.filesystem-scopes | config | sandbox.readableRoots, sandbox.writableRoots, sandbox.denyWrite | MONO_AGENT_SANDBOX_READABLE_ROOTS, MONO_AGENT_SANDBOX_WRITABLE_ROOTS, MONO_AGENT_SANDBOX_DENY_WRITE | Sandbox | Sandboxed code agent |
sandbox.fallback | config | sandbox.fallback, sandbox.unsafeAllowHostProcess | MONO_AGENT_SANDBOX_FALLBACK, MONO_AGENT_SANDBOX_UNSAFE_ALLOW_HOST_PROCESS | Sandbox | Sandboxed code agent |
sandbox.monotonic-merge | auto | (harness merges configured + request policies) | — | Sandbox | — |
sandbox.managed-srt | cli + auto | mono-agent sandbox status|setup|check; automatic managed runtime resolution | — | Sandbox | Sandboxed code agent |
Memory
Section titled “Memory”| Feature id | Coverage | Config key(s) | Env var(s) | Prose page | Playbook(s) |
|---|---|---|---|---|---|
memory.lite | config | memory.mode: "lite", memory.path, memory.maxBytes, memory.writeMode | MONO_AGENT_MEMORY_MODE, MONO_AGENT_MEMORY_WRITE_MODE | Capture & recall | — |
memory.journal | config | memory.mode: "journal", memory.path, memory.embeddings.{provider,model,dim} | MONO_AGENT_MEMORY_MODE, MONO_AGENT_MEMORY_EMBEDDINGS_* | Embeddings | — |
memory.bujo | config | memory.mode: "bujo", memory.path, memory.embeddings.{provider,model,dim}, memory.llm.{provider,model,endpoint} | MONO_AGENT_MEMORY_MODE, MONO_AGENT_MEMORY_EMBEDDINGS_*, MONO_AGENT_MEMORY_LLM_* | Capture & recall | Telegram BuJo assistant |
memory.backend-supermemory | config | memory.backend: "supermemory", memory.writeMode, memory.supermemory.{baseUrl,apiKey,apiKeyEnv,container,timeoutMs,exposeMcpServer}; exact matching @mono-agent/memory-supermemory plugin required | MONO_AGENT_MEMORY_BACKEND, MONO_AGENT_MEMORY_SUPERMEMORY_* | Backends comparison | Telegram + Supermemory |
memory.bujo-consolidation | config | memory.consolidation.{enabled,cron} | MONO_AGENT_MEMORY_CONSOLIDATION_CRON, MONO_AGENT_MEMORY_CONSOLIDATION_ENABLED | Consolidation | Telegram BuJo assistant |
memory.bujo-cli | cli | Removed — use config-aware mono-agent memory <subcommand> from the agent folder | — | Validation & CLI | — |
memory.preview-cli | cli | mono-agent memory stats|today|show <date>|search <query>|top|audit|rebuild|rollback [--limit <n>] [--json]; owner-only forget prepare|apply|restore | — | Validation & CLI | — |
memory.validate | cli | mono-agent validate [--consumer] [--config] | — | Validation & CLI | — |
memory.write-mode | config | memory.writeMode | MONO_AGENT_MEMORY_WRITE_MODE | Capture & recall | — |
memory.per-turn-capture | config | memory.writeMode: "capture" (requires memory.mode: "bujo") | MONO_AGENT_MEMORY_WRITE_MODE=capture, MONO_AGENT_MEMORY_MODE=bujo | Capture & recall | Telegram BuJo assistant |
memory.recall-tool | config | memory.recallTool.enabled | MONO_AGENT_MEMORY_RECALL_TOOL_ENABLED | Capture & recall | Telegram BuJo assistant |
memory.journal-browse | config + auto | Shared memory.recallTool.enabled; local Lite/Journal/BuJo capability; policy-gated MemoryJournal; no Supermemory fallback or new key | MONO_AGENT_MEMORY_RECALL_TOOL_ENABLED, MONO_AGENT_ALLOWED_TOOLS, MONO_AGENT_DISALLOWED_TOOLS | Capture & recall | — |
memory.remember-tool | config | memory.rememberTool.enabled; allowlist-gated Remember; bujo backend only | MONO_AGENT_MEMORY_REMEMBER_TOOL_ENABLED, MONO_AGENT_ALLOWED_TOOLS | Capture & recall | — |
memory.llm-timeout | config | memory.llm.timeoutMs (in-app; 1000–600000, default 60000) | MONO_AGENT_MEMORY_LLM_TIMEOUT_MS | Validation & CLI | — |
memory.custom-store | code | createConfiguredAgentResponder({ memory }) | — | Composition | — |
Context & skills
Section titled “Context & skills”| Feature id | Coverage | Config key(s) | Env var(s) | Prose page | Playbook(s) |
|---|---|---|---|---|---|
agent.public-name | config | agent.name | MONO_AGENT_NAME | Identity & soul | — |
context.identity | config | context.identityPath | MONO_AGENT_IDENTITY_PATH | Identity & soul | — |
context.soul | config | context.soulPath | MONO_AGENT_SOUL_PATH | Identity & soul | — |
context.history | auto | (owner-only disk-backed store; 64 messages per exact conversation id independent of runtime.maxTurns; aggregate committed defaults 256 MiB / 10,000 conversations / 365 inactive days plus an independent 256 MiB live-stage cap; staged atomic publication, immediate markerless-stage recovery, fixed-shard cross-process locking, bounded pre-provider dirty-fence retirement journals, provider epoch/revision coordination, exact-id durable transcript retirement, and post-commit pruning; custom store via code; completed blocking asks retain a bounded interaction transcript) | — | Assembly | — |
skills.selected-activation | config | context.skillsRoot, context.selectedSkills | MONO_AGENT_SKILLS_ROOT, MONO_AGENT_SELECTED_SKILLS | Skills | Slack team bot + MCP tools |
skills.byte-capping | config | context.skillMaxBytes | MONO_AGENT_SKILL_MAX_BYTES | Skills | — |
Tools & MCP
Section titled “Tools & MCP”| Feature id | Coverage | Config key(s) | Env var(s) | Prose page | Playbook(s) |
|---|---|---|---|---|---|
tool-policy.allow-all | config | omitted / ["*"] = all tools (default; risk disclosed and reconfirmed unsandboxed in guided init) | MONO_AGENT_ALLOWED_TOOLS | Tool policy | — |
tool-policy.allowlist / tool-policy.denylist | config | Pi runtime reports tool_policy as projected on every route; custom structural bridges without the field should be treated conservatively | MONO_AGENT_ALLOWED_TOOLS, MONO_AGENT_DISALLOWED_TOOLS | Tool policy | — |
tool-policy.mcp-servers | config | tools.mcpConfigPath | MONO_AGENT_MCP_CONFIG_PATH | MCP | Slack team bot + MCP tools |
agent-app.rich-replies | config + auto | PublishReplyFile under allow-all, or name it in a restrictive tools.allowedTools; MCP Apps are capability-gated to an all-Pi-native route chain; retention follows artifacts.retention.maxAgeDays | MONO_AGENT_ALLOWED_TOOLS, MONO_AGENT_ARTIFACT_RETENTION_MAX_AGE_DAYS | Reply files and MCP Apps | Interactive transcription and large media |
agent-app.durable-continuations | config + code | tools.continuationServers, continuations.{enabled,host,port,stateDir,namedRoutes,detachedServices} | MONO_AGENT_CONTINUATION_SERVERS; detached bearer env names are operator-selected | Durable continuations | — |
agent-app.run-history-tool | auto | Guided settled-run recovery/list/ranked search plus compact, cursor-paged inspect over one logical conversation, including an exact SessionHistory handoff for cancelled/interrupted evidence; daily rollover-independent. RunHistory under allow-all; restrictive policy explicitly lists RunHistory (legacy policy alias run_history); no new config key | MONO_AGENT_ALLOWED_TOOLS, MONO_AGENT_DISALLOWED_TOOLS | Artifacts & traces | — |
agent-app.session-history-tool | auto | Crash-safe managed-tool invocation/result sidecar plus bounded SessionHistory search/get for the current logical conversation, with trusted navigation from invocation/result ids to exact isolated 8 KiB record reads; daily-rollover-independent. Automatic cold projection fails soft, while explicit reads fail closed. SessionHistory under allow-all; restrictive policy explicitly lists SessionHistory (legacy policy alias session_history); no new config key | MONO_AGENT_ALLOWED_TOOLS, MONO_AGENT_DISALLOWED_TOOLS | MCP | — |
agent-app.memory-journal-tool | config + auto | Request-scoped MemoryJournal over a frozen bounded local curated-memory snapshot. Shares the memory-read enablement, needs affirmative Lite/Journal/BuJo capability, and is normal-policy-gated; no config key or legacy alias | MONO_AGENT_MEMORY_RECALL_TOOL_ENABLED, MONO_AGENT_ALLOWED_TOOLS, MONO_AGENT_DISALLOWED_TOOLS | MCP | — |
agent-app.web-conversation-title | auto | Request-scoped SetConversationTitle for writable interactive web threads; names the conversation as a whole and is refined whenever a better whole-thread name emerges, never used as a status line; proposal-only result, with permanent user-rename precedence and no trigger/archive writes. Allow-all exposes it on compatible routes; restrictive policy explicitly lists it; direct OpenCode suppresses it; no new config key | MONO_AGENT_ALLOWED_TOOLS, MONO_AGENT_DISALLOWED_TOOLS | MCP | — |
agent-app.adapter-send-tools | config | auto-available under allow-all once the channel is enabled; a specific tools.allowedTools needs the exact names (SlackSendMessage, TelegramSendMessage) + valid slack.* / telegram.* config; confirmed posts are idempotently recorded in destination history | MONO_AGENT_ALLOWED_TOOLS | Delivery & send tools | Cron digest + native notify |
interaction.bridge | config + auto | interaction.bridge.{host,port}, interaction.askUser.timeoutMs (default 600000; null disables automatic expiry), interaction.progress.enabled, tools.mcpRequestContextServers; auto-starts for configured send tools, allowed structured AskUser, configured interaction JSON/env, or enabled opted project-MCP progress | MONO_AGENT_INTERACTION_BRIDGE_HOST, MONO_AGENT_INTERACTION_BRIDGE_PORT, MONO_AGENT_ASK_USER_TIMEOUT_MS (none disables automatic expiry), MONO_AGENT_PROGRESS_ENABLED, MONO_AGENT_MCP_REQUEST_CONTEXT_SERVERS | Delivery & send tools | Interactive transcription |
tool-policy.filesystem-roots | config | tools.filesystem.{readableRoots,writableRoots}; extra managed file-tool roots while sandbox.mode: "off", with write roots also readable and lexical plus realpath containment | MONO_AGENT_FILE_TOOL_READABLE_ROOTS, MONO_AGENT_FILE_TOOL_WRITABLE_ROOTS | Sandbox | — |
Channels
Section titled “Channels”Built-in channels are independent JSON sections: telegram, slack, webhook, openaiApi, cron, tui, and live. External channel packages are declared under channels.plugins[] and return the same ChannelDriver shape; the current cataloged channel extras are @mono-agent/a2a-adapter, @mono-agent/whatsapp-adapter, and @mono-agent/messenger-adapter. Most are opt-in via an enabled flag (default off); tui and live are default-on loopback operator surfaces. An off channel reports disabled; an enabled channel with incomplete config reports waiting_for_config. Adapter fields can also have MONO_AGENT_<CHANNEL>_* env vars.
| Feature id | Coverage | Config key(s) | Env var(s) | Prose page | Playbook(s) |
|---|---|---|---|---|---|
telegram.long-polling | config | telegram.enabled, telegram.botToken, telegram.allowedChatIds / telegram.allowAllChats, telegram.groupMode / telegram.stripMentionText, telegram.pollWatchdogMs, telegram.transport.ipFamily (+ built-in self-healing restart) | MONO_AGENT_TELEGRAM_BOT_TOKEN, MONO_AGENT_TELEGRAM_* | Telegram | Telegram BuJo assistant |
telegram.interactive | config + code | built-in /new, plus /model and /effort via adapter runtimeControls; telegram.commands[], telegram.reactions, telegram.quietHours; structured AskUser buttons/custom replies, non-blocking TelegramSendMessage.reply_options, and TelegramSendFile | MONO_AGENT_TELEGRAM_REACTIONS; runtime controls have no env key | Telegram | — |
slack.ask-user | auto + code | structured AskUser renders one Block Kit question at a time with option buttons, Other/custom thread reply, and multi-select Done; no Slack-specific config | — | Slack | — |
slack.socket-mode | config | slack.enabled, slack.botToken, slack.appToken, slack.allowedChannelIds / slack.allowAllChannels, slack.botUserIds, slack.mentionTextAliases, slack.stripMentionText, slack.unfurlLinks, slack.unfurlMedia. When unset, preserves one readable authenticated self-mention marker; true restores legacy full stripping and false keeps raw mention forms. Omitted unfurl settings preserve Slack’s current native-message defaults. Resilience tuning (all optional, on by default): slack.heartbeatIntervalMs, slack.heartbeatTimeoutMs, slack.reconnectInitialBackoffMs, slack.reconnectMaxBackoffMs, slack.reconnectStabilityMs, slack.reconnectStartupGraceMs, slack.drainDeadlineMs | MONO_AGENT_SLACK_* (incl. MONO_AGENT_SLACK_UNFURL_LINKS, MONO_AGENT_SLACK_UNFURL_MEDIA, MONO_AGENT_SLACK_HEARTBEAT_*, MONO_AGENT_SLACK_RECONNECT_*, MONO_AGENT_SLACK_DRAIN_DEADLINE_MS) | Slack | Slack team bot + MCP tools |
slack.speaker-names | config | slack.resolveUserNames (default true); requires the users:read bot scope | MONO_AGENT_SLACK_RESOLVE_USER_NAMES | Speaker names | — |
channels.surface-awareness | config | Always on for Slack and Telegram; slack.resolveChannelNames (default true) adds the Slack channel name and requires channels:read/groups:read | MONO_AGENT_SLACK_RESOLVE_CHANNEL_NAMES | Surface awareness | — |
slack.thread-context | config | slack.threadContext.{enabled,maxMessages,requestLimit,timeoutMs,includeBotMessages}; defaults true/15/15/4000/true; requires a *:history scope | MONO_AGENT_SLACK_THREAD_CONTEXT_* | Thread and channel context | — |
slack.shortcuts | config | slack.shortcuts[]: {callbackId, prompt, channelId?, ackText?, threadReply?} | — (JSON-only; no environment-variable form) | Slack shortcuts | — |
slack.app-home | config | slack.homeTab: {enabled?, headerText?, buttons?:[{actionId, label, prompt, channelId?, ackText?, threadReply?}]}; enabled defaults false, buttons defaults [] | — (JSON-only; no environment-variable form) | Slack App Home | — |
channel.plugins | config | channels.plugins[]: { package, id?, label?, config? } | — | Write your own channel adapter | — |
whatsapp.baileys | config | channels.plugins[].package: "@mono-agent/whatsapp-adapter" plus plugin config.{enabled,allowedChatJids,allowAllChats,groupMode,botJids,mentionTextAliases,stripMentionText}. When unset, defaults to true only when mentionTextAliases is non-empty; botJids alone does not enable stripping, so otherwise it defaults to false. | MONO_AGENT_WHATSAPP_* | — | |
messenger.graph | config | channels.plugins[].package: "@mono-agent/messenger-adapter" plus plugin config.{enabled,allowedUserIds,allowAllUsers,host,port,webhookPath,apiVersion,allowNonLoopback,proactiveMessagingType,proactiveTag}; secrets via MONO_AGENT_MESSENGER_PAGE_ACCESS_TOKEN, MONO_AGENT_MESSENGER_APP_SECRET, MONO_AGENT_MESSENGER_VERIFY_TOKEN. | MONO_AGENT_MESSENGER_* | Messenger | — |
webhook.http-invoke | config | webhook.enabled, host, port, path, prompt, notify, notifyConversationId, defaultMode, allowNonLoopback, apiKey, retentionMs, maxStoredRequests, maxRunMs, webhook.endpoints[] (incl. per-endpoint model/effort/maxRunMs; a request body may set model/effort, request winning over endpoint config; endpoint maxRunMs wins over the adapter fallback), webhook.dir; a non-loopback bind requires opt-in + bearer key | MONO_AGENT_WEBHOOK_* (incl. MONO_AGENT_WEBHOOK_API_KEY, MONO_AGENT_WEBHOOK_MODEL, MONO_AGENT_WEBHOOK_EFFORT, MONO_AGENT_WEBHOOK_MAX_RUN_MS), MONO_AGENT_WEBHOOK_ENDPOINTS_JSON, MONO_AGENT_WEBHOOK_DIR | Webhook | Webhook automation (sync/async) |
openai-api.chat-completions | config | openaiApi.enabled, host, port, basePath, allowNonLoopback, apiKey, modelId; non-loopback requires opt-in + key and wildcard binds report concrete client URLs | MONO_AGENT_OPENAI_API_{ENABLED,HOST,PORT,BASE_PATH,ALLOW_NON_LOOPBACK,KEY,MODEL_ID} | OpenAI-compatible API | OpenAI endpoint + Open WebUI |
a2a.provider | config | channels.plugins[].package: "@mono-agent/a2a-adapter" plus plugin config.provider.* (including maxRequestBytes; durable identity: provider.idempotency.{namespace,stateDir,retentionMs,maxRecords}), config.agent.*, config.skill.* | MONO_AGENT_A2A_* | A2A | A2A provider & consumer |
a2a.consumer | config + code | plugin config.consumer.{remoteAgentUrls,defaultRemoteAgentUrl,bearerToken,timeoutMs}; sendA2AMessage({idempotencyKey}) or createA2AConsumerResponder({idempotencyKeyForRequest}) | MONO_AGENT_A2A_* | A2A consumer | A2A provider & consumer |
tui.stream-endpoint | config | tui.{enabled,host,port,basePath,allowNonLoopback,apiKey} — on by default (loopback TUI/web operator surface; /v1/info separately advertises additive attachment, legacy verbatim-history, canonical v1 context import, exact structured AskUser, and agent-owned cron capabilities without a wire-schema bump) | MONO_AGENT_TUI_* | Operator stream endpoint | — |
acp.worklab-bridge | cli + code | mono-agent bridge acp --discover; mono-agent bridge acp --source-id <id>; discoverAcpBridgeAgents() | — | ACP bridge | — |
cron.scheduled-prompts | config | cron.jobs[]: {id, enabled, expression, timezone, prompt, conversationId, maxRunMs, notify, notifyConversationId, notifyFailureCooldownHours, model, effort}, cron.dir; durable agent-owned run history; opt-in confirmed/idempotent/audited operator API controls via cron.operatorActions.enabled (default off; runtime enable state never rewrites config) | MONO_AGENT_CRON_JOBS_JSON, MONO_AGENT_CRON_* (incl. MONO_AGENT_CRON_NOTIFY_FAILURE_COOLDOWN_HOURS, MONO_AGENT_CRON_MODEL, MONO_AGENT_CRON_EFFORT, MONO_AGENT_CRON_OPERATOR_ACTIONS_ENABLED), MONO_AGENT_CRON_DIR | Cron | Cron digest + native notify |
cron.run-watchdog | config + code | jobs[].maxRunMs or maxRunMs frontmatter; programmatic fallback via startCronAdapter | — | Cron | — |
channel.native-notify | config | per cron job / webhook endpoint notify; explicit notifyConversationId wins, including exact web:new for one new marked web thread per result; web is never inferred and other web:* values reject; otherwise infer only with exactly one notify-capable Telegram/Slack candidate; 0 or 2+ candidates skip with a warning; cron model-exhaustion notices require explicit notifyConversationId, never infer, and may set notifyFailureCooldownHours; Telegram/Slack stay bounded by channel allowlists, while web requires the running local console and is one-attempt/no-outbox | MONO_AGENT_CRON_NOTIFY, MONO_AGENT_CRON_NOTIFY_CONVERSATION_ID, MONO_AGENT_CRON_NOTIFY_FAILURE_COOLDOWN_HOURS (+ webhook equivalents except cooldown) | Delivery & send tools | Cron digest + native notify |
channel.final-only-delivery | code | Adapter stream.finalOnly (default true for telegram/slack; answer deltas stay hidden while a transient tool ledger may be visible) | — | Delivery & send tools | — |
channel.transient-tool-activity | code | ResilientMessageStream({ finalOnly: true, showHints: true }); terminal subagent groups remove child tool lines but retain metrics plus an optional bounded Result/Reason; proactive delivery forces showHints: false; Telegram and Slack post the answer separately then best-effort delete progress; optional transport deletion also supports /cancel cleanup | — | Delivery & send tools | — |
channel.stream-tuning | code | Adapter stream / messages options (createTelegramChannelDriver etc.) | — | Write your own channel adapter | — |
channel.custom | config + code | channels.plugins[] package loading or startMonoAgentApp({ drivers }) (implement ChannelDriver) | — | Write your own channel adapter | — |
Observability
Section titled “Observability”| Feature id | Coverage | Config key(s) | Env var(s) | Prose page | Playbook(s) |
|---|---|---|---|---|---|
observability.jsonl-artifacts | config | artifacts.dir, artifacts.retention.{maxAgeDays,maxCount,dryRun}, artifacts.memoryRetention.{maxAgeDays,maxCount,dryRun} | MONO_AGENT_ARTIFACT_* | Artifacts & traces | — |
observability.latency-attribution | auto | (emitted into run JSONL artifacts) | — | Artifacts & traces | — |
observability.trace-registry | config | traceability.{registryDir,sourceId,sourceLabel,heartbeatMs,staleAfterMs} | MONO_AGENT_TRACE_* | Artifacts & traces | — |
observability.phoenix-exporter | config | observability.exporters[]: {type:"phoenix", endpoint, projectName, includeSensitiveData, contentPatternRedaction, headers, timeoutMs} | MONO_AGENT_OBSERVABILITY_EXPORTERS | Phoenix & backfill | Phoenix-observed agent |
observability.backfill | cli | mono-agent backfill (--run <id> | --all) [--since] [--until] [--dry-run] | — | Phoenix & backfill | Backfill historical runs |
observability.artifact-audit | cli / code | auditRecordedRuns(artifactDir, { staleAfterMs }); mono-agent runs audit [--artifacts <path> | --consumer <path>] [--json] | — | Artifacts & traces | — |
observability.artifact-metrics | cli / code | summarizeRecordedRunMetrics({ artifactDir, since, until, groupBy }); mono-agent runs report [--artifacts] [--since] [--until] [--by] [--json] | — | Artifacts & traces | — |
observability.rich-traces | auto | (model / token counts / cost / duration on every span; system prompt gated by includeSensitiveData; memory runs get span.kind=memory + memory.operation) | — | Phoenix & backfill | — |
observability.stale-run-reconciliation | auto | (reconcileStaleRunArtifacts() at startup over artifacts.dir; rewrites orphaned running → interrupted) | — | Artifacts & traces | — |
tui.chat | cli | mono-agent tui [--agent <label|sourceId>] [--conversation <id>]; low-level mono-agent-tui [--responder | --url] | MONO_AGENT_TUI_API_KEY (connect key) | TUI | — |
web.console | cli | `mono-agent web [start | restart | stop | status |
Execution & composition
Section titled “Execution & composition”| Feature id | Coverage | Config key(s) | Env var(s) | Prose page | Playbook(s) |
|---|---|---|---|---|---|
app.cli-init | cli | --name, exact IDENTITY.md → ## Role prompt/outcome, managed project skills, --preset (legacy --recipe removed), canonical repeated --fallback/--fallback-effort (legacy --fallback-models removed), --auth; any flag/non-TTY remains scaffold-only | — | Quickstart | — |
app.cli-setup | cli | bare TTY mono-agent init: searchable catalogs, Escape-back, concrete review, all-route proof, interrupt resume/restart; macOS starts the background agent and prints manual edit → validate → restart → ordinary tui next steps, while unsupported platforms stay manual | — | CLI reference | — |
app.secure-secret-persistence | cli | fail-closed owner-only .env merge + external lock + pathname no-clobber/recovery checks; Windows manual only | channel/provider-native secret vars | Env vars | — |
app.provider-auth | cli | mono-agent auth login <provider> [--pi-auth-path] [--api-key-stdin]; Agent settings honest passive status, explicit bounded live checks, plus Pi-native GitHub/OpenAI device code, Anthropic paste-back, and masked provider API-key prompts; shared owner-only locked/no-clobber Pi-store write | MONO_AGENT_PI_AUTH_PATH | CLI reference, Providers | — |
app.cli-presets | cli | mono-agent presets list | show <id> (old recipes alias removed) | — | Presets & modules | — |
app.cli-no-tools-guardrail | cli | part of mono-agent validate / doctor; the tools step of mono-agent init | — | Presets & modules | — |
app.cli-validate | cli | mono-agent validate [--consumer] [--config] [--env-file] | — | Blueprint | — |
app.provider-credentials-check | cli | part of mono-agent validate; primary/fallback/memory/enabled static trigger refs; exact Pi built-in model + providers.piAuthPath, or custom model/key contract through providers.local[] | MONO_AGENT_PI_AUTH_PATH, MONO_AGENT_LOCAL_PROVIDERS_JSON | CLI reference | — |
app.cli-start | cli | mono-agent start [--config] [--env-file] [--foreground] | — | Install | — |
app.cli-stop | cli | mono-agent stop [--config] | — | Install | — |
app.cli-logs | cli | mono-agent logs [--config] [--follow|-f] [--lines <n>] | — | CLI reference | — |
app.cli-restart-clean | cli | mono-agent restart [--config] [--clear-sessions] | — | CLI reference | — |
app.managed-project-skills | cli + config | generated mono-agent-memory; retired mono-agent-configure is ignored at runtime and reported as waiting until mono-agent install-skill --project --update safely removes exact managed legacy state | MONO_AGENT_SKILLS_ROOT, MONO_AGENT_SELECTED_SKILLS, MONO_AGENT_SKILL_DISCLOSURE | Skills | — |
app.docs-mcp-companion | cli + code | mono_agent_docs({action: "search", query, limit?, scope?}); mono_agent_docs({action: "read", target}); expanded mono-agent-docs://chunk/{chunkId} resources | — | Documentation MCP companion | — |
app.cli-install-skill | cli | mono-agent install-skill [--target claude|codex|both] [--force] [--no-docs-mcp]; --project --check reports four active and four retirement states; --project --update transactionally updates active state and retires only exact managed legacy state | — | CLI reference | — |
app.cli-web | cli | bare read-only status/help; web start|restart|stop|status|logs|run|reset; --host <addr> | --loopback, --port <n>, --theme <name> on start/restart/run; restart retains the stored theme; status reports it; reset requires --all --yes | — | Web console | — |
app.env-file | cli | automatic; --env-file <path> to override | — | Env vars | — |
harness.failure-handling | auto | (built into every run) | — | Composition | — |
harness.external-summary-safety | auto | public harness/webhook summaries exclude systemPrompt; private artifacts retain it | — | Artifacts & traces | Webhook automation |
agent-app.blocking-ask-history | auto | app interaction journal + configured harness history commit; no config key | — | Assembly | Interactive long jobs |
harness.request-runtime-options | code | createConfiguredAgentResponder({ runtimeOptionsForRequest }) | — | Composition | — |
orchestrator.ask-collaborator | code | createCollaboratorToolRuntimeExtension + runtimeOptionsForRequest | — | Multi-agent | Multi-agent orchestration |
Notes on coverage types
Section titled “Notes on coverage types”A code-only feature has no mono-agent.config.json key — you reach it through startMonoAgentApp options or lower-level packages. See Programmatic API for the entry points referenced above (createConfiguredAgentResponder, createMonoRuntime, createCollaboratorToolRuntimeExtension, custom ChannelDriver/runtime/memory/historyStore injection).