# @mono-agent/agent-app

Config-first mono-agent host. Reads one `mono-agent.config.json` in a folder,
builds the configured responder, and starts every configured communication
channel plus traceability. Ships the
`mono-agent` CLI (`init`, `auth`, `sandbox`, `validate`, `memory`, `tui`, `web`, `start`) so an agent folder works without
hand-written composition code.

Setup has two deliberate wall-clock paths: flags or non-TTY input use the fast scaffold-only path (unless explicit `--auth` adds provider setup) and never claim readiness. Bare `mono-agent init` on a TTY makes one real no-tool model call per selected route before committing the scaffold, with timeouts of 90s for each cloud route and 240s for each local route.

## Category

<!-- package-metadata:start -->
<!-- Generated by scripts/generate-package-docs.mjs. Do not edit by hand. -->

Category: `app`
Tier: `core`
Catalog responsibility: Runs a config-first agent host: loads mono-agent.config.json, owns configured responder/harness/runtime/memory composition, and starts every configured channel and traceability.

<!-- package-metadata:end -->

## Responsibility

Turn a folder's `mono-agent.config.json` into a running agent host:

- Aggregate the adapter-neutral core config and every channel section
  (`telegram`, `slack`, `webhook`, `openaiApi`, `cron`) plus configured
  external channel plugins from `channels.plugins[]`.
- Build the shared runtime/responder/memory stack through app-owned configured
  composition
  (including canonical `runtime.fallbacks` routes and legacy
  `runtime.fallbackModels` compatibility).
- Preserve bounded answered/expired `AskUser` evidence in the assistant history
  copy so cold/stateless provider replay does not lose the out-of-band exchange;
  cancelled asks are not journaled.
- Expose the request-scoped read-only `RunHistory` tool for safe normalized
  search and paged evidence from completed prior runs in the logical
  conversation, independent of daily rollover buckets.
- Expose the sibling request-scoped read-only `SessionHistory` tool over the
  harness's canonical retained managed-tool lifecycle sidecar.
- Opt in to Pi-native Exec/Bash process jobs through `processJobs.*`: keep the
  owner-private queue/store/process-group lifecycle, adapter-neutral opted-in
  Slack/Telegram/web/WhatsApp wake routing with exact active-run steering and a
  reserved visible normal-turn fallback,
  wake with age-bounded busy deferrals, bounded pending/store materialization,
  stable secret-free safety errors, native same-message lifecycle surfaces,
  fail-closed live store health, a bounded monotonic registry that seals every
  retained state root even after disable or reconfiguration, bounded locked
  recovery through a fixed-name owner-private sibling directory while request
  loading stays read-only and fail-closed, cooperative
  official-process ownership, true-settlement generation barriers, provider-zero
  for configured routes and direct memory LLM/embedding calls, plus the explicit
  JSON-only `unsafeAllowUnprotectedState` trusted-host posture that suppresses
  ProcessJobs and clear-sessions SRT only under explicit sandbox-off and all-Pi
  routing while retaining registry/lease/private-root invariants, restart interruption,
  all-root separation from every clear-sessions purge, doctor section, operator
  routes, and `mono-agent jobs` CLI at the app boundary. This
  local contract does not resist a hostile same-UID provider; use OS privilege
  separation when that is in the threat model.
- Drive each channel through a uniform driver contract with per-channel
  `disabled` / `waiting_for_config` / `running` / `degraded` / `failed` status.
  `degraded` means a temporarily unavailable transport owns its recovery while
  the responder remains alive; `failed` is terminal until the host restarts or
  reloads that channel.
- Own cron control truth in owner-private `.mono-agent/cron-control-v1/`:
  durable per-job admission order, bounded run/event history, runtime enable
  overrides, idempotency receipts, and audit. An absent store is initialized;
  a present corrupt, insecure, or lease-conflicted store arms no cron jobs and
  surfaces a degraded lifecycle/discovery reason plus an error log. Operator
  actions are config-opt-in, API-key-protected, and explicitly confirmed; they
  never rewrite config, environment, or Markdown job sources.
- Register the host as a traceability source. Config edits are made directly in
  `mono-agent.config.json`, or proposed through the OS-owner-managed macOS
  configuration TUI; direct edits take effect on the next `mono-agent restart`.
- Check managed launchd logs with bounded metadata reads every five minutes,
  reconcile installed macOS LaunchAgents at login and hourly, and make `status`
  require agreement between the cached trace and launchd's live PID.
- Resolve and surface any configured `observability.exporters` (the Phoenix
  preset): `start`/`status` report the configured endpoint and a note that JSONL
  artifacts remain local; `validate` performs the live reachability probe. Export
  is best-effort and never changes a run outcome.
- Preview, strictly audit, and safely maintain the configured memory backend
  from the same config/env resolution path via `mono-agent memory` (including
  provider-free strict health and payload-free intake inspect/retry/resolve).
- Scaffold (`mono-agent init`) and validate (`mono-agent validate`) agent
  folders non-destructively.
- Resolve local-first WebSearch/WebFetch settings into every runtime run and
  report a separate bounded readiness section for loopback SearXNG plus the
  optional `agent-browser` renderer; the app never owns either companion's
  lifecycle.
- Operate the machine-wide `@mono-agent/web` assistant-ui console through
  `mono-agent web`, including persisted curated host themes and hostname
  identity; on macOS pair its worker with one helper-only, stopped-writer log
  controller while the worker remains wake-only; publish a bounded, refreshable
  skill registry through each running operator endpoint so the web composer can
  discover valid `$skill-name` references; use `mono-agent tui` for bounded
  recorded-run replay.
- Discover and expose one exact running agent through the ACP core-session
  profile with `mono-agent bridge acp`, including durable session resume, while
  preserving agent-owned configuration, workspace, sandbox, tools, MCP servers,
  and credentials.

## Install / Usage

```bash
# Install the scoped CLI host directly:
npm install --global @mono-agent/agent-app

# Create an agent folder through the guided, readiness-proven path:
cd /path/to/agent-folder
mono-agent init
mono-agent validate
mono-agent start
```

For a one-off setup without a global install, use
`npm create mono-agent@latest init`; the `create-mono-agent` alias delegates to this
same CLI.

### Guided initialization and readiness

On an interactive terminal, bare `mono-agent init` (no flags) runs a colourful,
step-by-step wizard — powered by `@clack/prompts` — that asks for the public
agent name plus exact Role text for `IDENTITY.md` → `## Role` and composes the capability selection before writing anything. An existing `IDENTITY.md` is preserved and the review says the entered Role will not be written. Escape
moves back one logical step; Ctrl-C asks for exit confirmation. The final
**Creation review** names the agent, routes/efforts, route safety, provider/SRT
actions, exact files, secret destinations, and number of real model calls before
offering **Run setup and readiness checks, then create agent** when setup is
needed, or **Run readiness checks, then create agent** when credentials are
already detected, alongside **Edit choices** and **Cancel without writing**.
Status, sandbox, and route preflights accept Escape or Ctrl-C and enter the same
resume/restart recovery flow without writing agent files. Interactive provider
authentication uses Ctrl-C only so the parent never competes with the provider
child for terminal input. This is the readiness-proven path;
any flag or non-TTY invocation is scaffold-only and never claims the agent is
ready. Presets seed the same model, channel,
tool, and sandbox decisions as the custom path; they do not silently bypass
safety choices. Journal and BuJo open a dedicated local embeddings step: choose
Ollama or LM Studio, service root, exact model, actual dimension, and optional
`apiKeyEnv`. Ollama discovery filters `/api/tags` models through `/api/show`
`embedding` capabilities; LM Studio filters exact `type: "embedding"` entries
from `/api/v1/models` and uses their `key`. One fixed non-user request to
`/api/embed` or `/v1/embeddings` must return a non-empty finite vector of the
configured dimension before readiness. Manual model/dimension entry can author
the plan when discovery is inconclusive, but cannot fake readiness. Provider
failures never fall through to the other local service. Searchable
primary/fallback pickers combine every bundled model
for the guided Pi providers (Anthropic, GitHub Copilot, OpenAI Codex, and
OpenCode-Go), Codex's live account catalog, the Claude SDK catalog, and local
discovery. The live Codex provider default leads when available; offline setup
falls back to curated `codex:gpt-5.6-terra` without guessing effort metadata, so
only **Provider default** is offered until live `model/list` succeeds. GPT-5.6 Sol is selectable as
`codex:gpt-5.6-sol` or `pi:openai-codex:gpt-5.6-sol`.
OpenCode-Go Pi refs can save `OPENCODE_API_KEY` into
the Pi auth store or remain environment-provided, and any number of fallback
models are selected from the same discovered choices one at a time. Each route
offers only its advertised effort values plus **Provider default**. Standalone
`mono-agent auth login anthropic` keeps its localhost callback active while
also reading a pasted final redirect URL through Pi's code/state-validating
OAuth implementation. `mono-agent auth login opencode-go` uses a masked TTY prompt; headless callers
must opt in to one-line redirected input with `--api-key-stdin`. Any flag (or a piped/non-TTY
invocation) takes the silent default/preset scaffold path instead; add `--auth`
to run supported provider setup in that non-interactive path. Required selected
channel secrets are masked and never enter config JSON, examples, review output,
or logs. Durable provider credentials already in `.env` are secured by the same
preflight. POSIX persistence is owner-only (`0600`), preserves existing dotenv
values/comments, and uses an external lock plus no-clobber promotion with exact
ignore rules for `.env` and transaction artifacts. The canonical agent directory
must be current-user-owned and not group/world-writable; existing `.env` and
`.gitignore` files must be current-user-owned with one link, and the ignore guard
loses group/world write access. Pathname competitors are
protected; the claimed inode is rechecked and detected open-descriptor writes are
retained in a reported recovery copy (writes after the final POSIX check remain
non-cooperative); unsafe/tracked/foreign-owned/multiply-linked
paths, stale locks, invalid dotenv, conflicts, and Windows fail closed to manual setup. Before the
interactive wizard can start the background agent it requires one disposable no-tool
response from every selected runtime route and a complete validation report with
every selected expectation ready. Cancellation, provider failure, timeout (90s
for each cloud route and 240s for each local route), empty output, or any tool
action fails the check.
Escape or Ctrl-C interrupts preflight; recovery can resume verified routes when
the non-secret plan fingerprint still matches, restart all checks, edit choices,
or cancel. Authentication repair clears every prior route proof because it can
replace credential bytes. Guided commit atomically creates the config and rechecks its exact snapshot after validation. On macOS it then creates or refreshes the canonical per-config launchd service and waits up to 60 seconds for a fresh trace whose durable `metadata.lifecycle.startupCompleted` proof is true. The worker publishes that proof only after channels, memory rituals, and final memory-health work complete; later trace refreshes change the diagnostic `metadata.reason` without revoking readiness. The controller also re-proves the live launchd PID, exact snapshot, current channel/memory health, and reachable TUI before it opens `mono-agent tui --configure` against that background responder. A readiness timeout or trace/TUI-probe error preserves the committed files and skips chat, then unloads the worker plus scheduled maintenance and removes their definitions only when stopped state is proven. If cleanup cannot be proven, the command says that a process may still be running and prints exact `start`, `status`, and `logs --follow` recovery commands plus log paths. Workers from an older release that have no durable lifecycle marker must restart once before configuration can attach. Off macOS, conversational configuration is unavailable: the wizard preserves the files and gives manual edit/validate, foreground-start, and ordinary-TUI guidance without claiming readiness. Any flag or non-TTY invocation remains scaffold-only and never starts a process.

### Managed skills and documentation companion

Every scaffold selects versioned `mono-agent-configure` and `mono-agent-memory`
skills from `./skills` with index disclosure. `ReadSkill` remains separate from
action-tool policy. `mono-agent install-skill --project --check|--update` reports
version/hash drift and refreshes only unchanged managed copies with backups; a
canonical owner-only non-symlink parent chain, per-project owner lock, and
compare-and-swap activation prevent outside or concurrent
operator edits from being overwritten, and a partial activation restores only
files that still equal the managed bytes it wrote.
The persistent SELF-CONFIG workflow guidance is managed-skill version `1.2.0`.
Existing unchanged copies are reported as stale and are never rewritten on TUI
startup; run `mono-agent install-skill --project --update` explicitly to refresh them.

Harness-mode `mono-agent install-skill` also pairs the exact matching
`@mono-agent/docs-mcp` version with available selected Codex and Claude Code
CLIs. That read-only companion gives `mono-agent-composer` offline semantic and
exact-identifier search over the public docs and its authoritative references.
Use `--no-docs-mcp` for a skill-only install. Managed MCP and skill changes are
transactional; an unrelated entry named `mono-agent-docs` is never overwritten,
including with `--force`. Project `--check` / `--update` mode does not touch
harness MCP configuration.

### Conversational self-configuration

In the separate, visibly marked **SELF-CONFIG** session only, the background app injects proposal-only
`ProposeAgentConfiguration`. The opening message shows a user-led map of identity/knowledge,
runtime/models, skills/tools/MCP/plugins, memory, channels/APIs/A2A, automation,
security, observability/operations, and acceptance criteria, then builds the chosen
workflow conversationally. It says never to enter secrets and to expect a separate
host approval before anything changes. Approval, rejection, a proposal-free turn,
`done`, and `no changes` all keep SELF-CONFIG active; only `/quit`, `/exit`, or
double `ctrl+c` exits the session, and quitting leaves the background agent running.
The host accepts only a fail-closed low-risk
allowlist: public name; effort, turn/session UX; selected project skills and
disclosure; memory size or MemoryRecall enablement; semantic tool-policy
tightening; and the separately validated Role body. Every path, memory-tier or
capture-cost change, runtime/provider route, channel/proactive/plugin, MCP,
exporter, embeddings/LLM endpoint, sandbox/network field, secret, and unknown
future field is handed to the explicit guided flow. It canonicalizes
config/Identity/state paths without following symlink parents, stages and
fsyncs replacements, then performs the final source comparison and rename as
one non-yielding commit step under an owner-only transaction lock. Separate TUI
confirmation, failure-atomic config/Role rollback compensation, rollback
evidence, a successful managed restart, and a fresh ready trace source remain mandatory. Configuration turns replace
the ordinary tool/MCP policy with `ReadSkill`, `MemoryRecall`, and the proposal
tool only. Pure direct-Codex chains use its native read-only plan posture;
mixed chains keep the finite proposal surface so a route that cannot represent
it cannot widen authority. Direct OpenCode cannot receive the host-owned MCP
proposal capability: a direct-OpenCode primary is routed through a configured
proposal-capable fallback, while a direct-OpenCode fallback makes self-configuration
unavailable with explicit remediation. The approval card shows
every full, untruncated JSON patch value and pages through the exact Role body
while keeping Reject/Approve reachable, and rejects
terminal-control or bidi-control review text before displaying it. The configuration
conversation id stays stable across incremental checkpoints and verified restarts;
each settled turn receives a fresh opaque proposal capability plus a safe host-outcome
summary. Fast follow-up text remains in the editor until settlement and is never sent
as ordinary chat or to a stale endpoint. Remote/proactive channels never receive this tool.

### Managed background runtime

Before the first macOS background launch, the CLI copies the exact package and
already-resolved dependency closure it is currently executing—including configured
channel plugins and the optional Supermemory backend—into an owner-only,
version/Node-ABI/CLI/closure-digest runtime under `~/.mono-agent/runtimes/agent-app/`.
It does not invoke npm or lifecycle scripts, so provider secrets never reach an
installer and pnpm `workspace:` links do not require registry resolution. A
relative-path/type/mode/content-hash manifest and the complete source-closure
digest are bound into the runtime marker and verified on every reuse. The LaunchAgent always points there, never at an
`npm create`/npx cache. Existing verified runtime snapshots are reused and
retained because another agent may still reference them. A loaded job is fully
booted out and bootstrapped again so rewritten arguments and environment are
adopted. During a slow install, the existing healthy worker remains loaded. An
active shared installation may take up to five minutes; concurrent consumers
wait behind its PID/incarnation-aware lock and reuse the resulting closure. An
owner-private per-instance publication barrier makes any KeepAlive respawn wait
until the replacement closure and plist are committed; dead or PID-reused
controller ownership is recovered by process incarnation. The replacement
plist carries a path-free proof of the finalized marker, and the worker
revalidates its exact canonical CLI, marker, manifest fingerprint, and launch
boundary before loading config or channels. Only that verified active closure
is automatically reopened read-only by app-owned SRT; the runtimes parent and
historical sibling closures remain outside the implicit policy. Launchd enters
Node through `/usr/bin/env -i`, so inherited variables
such as `NODE_OPTIONS` cannot execute before the worker's allowlisted environment
is established. Every foreground worker holds one owner-only lifetime lease for its
canonical config, so a managed and manual host cannot run together. A per-config
256-bit key in owner-only `~/.mono-agent/background-snapshot-keys/` commits exact
file bytes without exposing plaintext or offline-testable hashes in argv/traces.
A persisted v2 proof binds each canonical path, inode, size, nanosecond
mtime/ctime, mode, and keyed bytes, but excludes the mount's boot-local device
number. Device plus inode remain mandatory while a file is opened and read, so
a path or handle swap still fails closed; excluding only the persisted device
number lets the same unchanged file survive macOS volume renumbering across a
login or reboot. A loaded v1 proof is treated as one-time drift and republished
by the recovery controller.
A managed worker freezes the proven config, Identity, optional Soul, and MCP authority
file into private read-only copies before app/channel loading, while trace metadata continues to
name the canonical config. Readiness requires one live launchd-owned trace PID,
the exact durable snapshot, and, for configuration, a reachable TUI endpoint.
Stop succeeds only after both launchd unload and worker death are proven.

### Validation, recovery, and managed logs

`mono-agent validate` (and its `doctor` alias) reports the provenance of the CLI
producing the report in its Runtime provenance section: a private managed marker
whose freshly recomputed installed closure and coherent current manifest validate
names its full closure id plus sanitized install metadata; other executions report
`dev (unmanaged)`. With `--consumer`, this remains the validator CLI's provenance,
not an attestation of a separately running daemon.

Its **Web search & fetch** section reports the resolved SearXNG backend and
static/browser extraction mode. With liveness enabled it performs one bounded
JSON query against a configured loopback SearXNG endpoint and checks that an
enabled browser renderer reports `agent-browser` 0.33.1 or newer. Start
preflight (`liveness: false`) skips both probes without changing structural
validation.

Managed launchd stdout/stderr use a fixed automatic policy: each active file
and each of three retained generations is capped at 5 MiB. Once ready, the
managed worker performs one overlap-guarded, read-only inventory immediately and
every five minutes. The healthy below-threshold path ends there: it does not
reconstruct the durable environment, validate config, capture a snapshot, or
start another Node process. The immediate pass is observational: helper wakeups
have a five-minute startup floor. A worker may wake only for a safely inspected
per-agent active/retained log above 5 MiB or a safe owner-matching regular log
whose permissions need repair. Shared-directory repair and pending lifecycle,
journal, or preparation artifacts never wake the fleet; the scheduled helper
owns those recovery cases.

The separate controller keeps `RunAtLoad` for login recovery and runs once per
hour at a stable minute: the unsigned big-endian first four bytes of SHA-256 of
the canonical main LaunchAgent label, modulo 60. Login therefore deliberately
retains N/N `RunAtLoad` recovery coverage, while recurring runs are staggered.
The lightweight entries may start together, but each waits SHA-256(canonical
main label)[0..3] unsigned-big-endian modulo 120 seconds before PID
authentication, locking, or heavy import. This disperses the login heavy-work
boundary without an account-wide admission lock or stale-owner state; a
worker-requested wake can likewise wait at most 119 seconds. It has no `KeepAlive`
and sends output to `/dev/null`. It then authenticates its exact launchd-owned
PID and takes the per-config lifecycle lock without waiting,
before attestation or importing the controller graph. A same-agent loser exits
without expensive work. The helper plist enters through the managed closure's
attested `dist/launchd-maintenance-entry.js`; the per-agent lock winner verifies
that sibling entry against the shared path-free runtime proof and dynamically
imports the heavy controller graph. It reconstructs the durable environment, captures a fresh snapshot,
and compares the strictly parsed loaded main definition and its existing path-free
managed-runtime launch proof with the original controller CLI's inert version/digest;
it never executes mutable source bytes. A healthy pass does not run full structural
validation or traverse the immutable closure. Full validation and managed-runtime
installation/verification run only after those fast proofs identify drift, while
the per-agent lock remains held. After runtime installation and all read-only
rechecks, the helper takes the per-account shared-chain lock without waiting only
for stopped-writer/shared-directory mutation; contention defers cleanly. Healthy
log-only maintenance takes that shared lock separately. If the source
disappeared, it can repair an inactive or snapshot-drifted worker from its
private helper closure without claiming an upgrade or downgrading a healthy
worker.

The helper executes with a closed system `PATH` while carrying the worker's
non-secret durable `PATH` as a private argument. Recovery therefore preserves
the worker's toolchain lookup without letting it shadow the helper's own system
commands.

When reconciliation is needed, the existing worker stays loaded through runtime
installation. Under the shared mutation lock the helper then stops only the main
job, repairs the shared log chain, refreshes both plists, and bootstraps the main
job. It releases the shared lock before waiting for the normal 60-second readiness
proof, while retaining the per-agent lifecycle lock. A
failure preserves the helper and both definitions for the next hourly retry;
explicit stop unloads the helper and removes both definitions after PID-death
proof, so it cannot resurrect a stopped service. When log maintenance is needed,
the helper takes the
same per-config lifecycle lock, verifies the existing main plist, proves the
worker stopped, and commits owner-only bounded tails through per-agent,
fsynced deterministic stages plus a recoverable journal. A separate per-agent
lifecycle intent is atomically published as `stopping` before bootout, promoted
to `stopped` only after launchd unload and every observed PID's death, and
changed to `restoring` before bootstrap invalidates that old stop proof. It is
removed only after the exact plist is rechecked and its worker is live. An
interrupted pre-proof pass whose launchd PID is gone fails closed; durable
`stopped` rotation can resume without authorizing another agent or an intentionally
stopped service.
Recurring drift recovery and shared-only repair therefore have a worst-case
60-minute latency between logins; explicit start/restart remain synchronous.
Worker requests use a process-local monotonic 5/10/20/40/60-minute cooldown,
skip an unloaded or already-running helper, and recheck the shutdown latch
immediately before `launchctl kickstart`. A pathological worker crash loop can
still request about once per five minutes per agent after each new process.
For an 11-agent pathological simultaneous crash loop, that residual bound is
11 requests per five minutes.
Every shared log-chain mutation takes one PID/incarnation-aware owner-private
per-account lock after the per-agent lifecycle lock. Helpers defer immediately;
interactive start/restart/stop wait up to 18 seconds, then fail visibly with
the holder identity.
Start and restart perform
the same stopped-writer maintenance before loading helper then worker; stop
unloads the helper first and removes both definitions. Unsafe paths or a changed
plist fail closed without following links or resurrecting a stopped service.
`mono-agent validate` / `doctor` only inspect metadata and report exact active,
retained, and total bytes for safely inspected files; unsafe or unreadable byte
inventory is unavailable. They also render the owner-private monitor's last
inspection, cumulative wake count, last outcome, and wall-clock rendering of
the monotonic cooldown deadline. They never rotate or chmod logs.

The loaded launchd definition, not the plist bytes on disk, is authoritative
for migration. Existing agents retain their previously loaded interval until
each agent is explicitly restarted after upgrade; a fleet restart is not
performed automatically.

The machine-wide web console uses the same rotation transaction over its exact
`~/.mono-agent/web/logs/web.{out,err}.log` paths but a deliberately separate
control domain. `com.mono-agent-web-maintenance` is a no-`KeepAlive`, `/dev/null`
one-shot helper with `RunAtLoad`, a deterministic hourly minute, and the same
0–119-second pre-import dispersion. The managed worker's five-minute monitor is
wake-only and never stops or rotates the writer. The helper authenticates its
launchd PID, cached private definition, attested runtime entry, exact helper
bytes, and the main plist's composite `dev:ino:size:sha256` identity before and
after taking the web lifecycle lock. Because web logs are outside the shared
agent log directory chain, it never takes the agents' shared mutation lock.

Every main-plist publication or restoration regenerates the helper from the
fresh composite identity before either definition can be bootstrapped. Start
and restart unload helper before worker, perform proven stopped-window
maintenance, then bootstrap helper before worker. Stop unloads helper first and
removes both plists only after death proof; reset requires both jobs stopped,
both plists absent, and the same lifecycle lock. The fixed policy remains one
active file plus three 5 MiB retained generations per stream. Refused legacy
rollover artifacts are preserved while core rotation proceeds, and bounded
owner-private monitor/maintenance status lets `mono-agent web status`
distinguish active maintenance, routine `due`, durable failure, and abandoned
recovery. `mono-agent web logs` tails only active names with `tail -F`.

Guided readiness uses a worker-reproducible environment rather than the launching
shell: durable `.env` values, entered selected secrets, the resolved Pi auth path,
and operational values such as `PATH`/`HOME`. Shell-only provider credentials and
config overrides cannot create a success that launchd cannot reproduce; persisted
non-secret `MONO_AGENT_*` overrides are rejected by name.

### Provider readiness and route safety

Direct Codex discovery checks the executable, login status, and live app-server
model catalog without equating catalog availability with authentication or a
verified turn. Missing Codex setup points to the official instructions at
<https://developers.openai.com/codex/cli/>; the app never auto-installs it. The
wizard offers browser callback and headless device-code login. Detected credentials
skip redundant authentication but remain unverified until the exact route call
successfully runs. Guided Pi setup covers Anthropic, GitHub Copilot, OpenAI Codex,
and OpenCode-Go; other hand-authored Pi and local-provider configs remain compatible
without being advertised as guided cloud integrations. Supported OAuth methods and
the OpenCode-Go key flow come from the bundled upstream catalog;
stale auth locks are repaired only when the recorded process is securely proven
gone. The
wizard keeps **Allow all tools** as its default. Pi/Claude flows disclose
shell/file/web/channel effects and reconfirm an unsandboxed choice. Direct Codex
fixes policy to effective allow-all (an omitted or wildcard-containing
allowlist with no denied tools), uses its native network-off workspace sandbox,
denies unattended escalations, and fails unexpected server requests promptly.
Mixed chains are unrestricted only under explicit `runtime.routeSafety:
"per-route-native"`, which isolates provider runtimes and applies a documented
route-local contract. The default `uniform` mode keeps one common monotonic
contract and rejects/skips routes that cannot represent it. Pi keeps mono-agent
tool policy and optional SRT; Claude uses representable provider-native controls;
direct Codex/OpenCode use provider-native safety plus effective allow-all. No route
silently drops a required capability. Pi `pi:opencode-go:*` remains a Pi route.
Direct OpenCode has the same omitted-or-wildcard/empty-deny requirement; restrictive static policies fail
validation/runtime and an incompatible dynamic override is warned and ignored.

### Run history

`RunHistory` requires no config key. It is automatically available under
allow-all on MCP-capable routes; a restrictive `tools.allowedTools` must name
`RunHistory` explicitly (`run_history` remains a deprecated policy alias), and
`disallowedTools` can remove it. Direct OpenCode and other MCP-incompatible
routes suppress it. The agent-facing shorthand is `{}` to list recent runs,
`{ "query": "topic terms" }` to search safe trigger and summary metadata,
`{ "runId": "..." }` for a compact overview, and
`{ "runId": "...", "cursor": "..." }` for the next timeline page. The
`run_id` spelling and explicit `action: "list" | "search" | "inspect"` remain
compatible. List/search defaults to 5 results (maximum 10); timeline pages hold
at most 10 entries and about 16 KiB. Each result includes tool-authored
`navigation.guidance` and exact `navigation.nextActions[].arguments` for
continuing exploration.
List and search read retained summaries once; search never reads event JSONL
and matches all normalized terms only against sanitized trigger/user input,
run id, dates, status/failure kind, source/detail, model, and effort. Daily
session rollover buckets are treated as one logical conversation when rollover
is configured, while current/running runs and unrelated conversations or
threads stay unavailable. Inspect returns metadata, trigger, final visible
output, warning/failure summaries, and tool-name call/error counts before any
timeline detail is requested. Timeline continuation is cursor-paged, and nested
`RunHistory` result bodies are omitted to prevent recursive expansion.
All returned historical evidence is bounded and normalized. Structured
projected values first pass through the shared observability redactor:
non-numeric values under sensitive-looking object keys
are redacted; numeric values under matched keys are retained; free text is not
content-scanned or scrubbed. `RunHistory` then applies an additional projection
sanitizer to object keys as well as string values, with deterministic
collision-safe key disambiguation. In that second pass, numeric values under `credential`, `private_key`,
and `bearer` can remain visible; numeric values under `apiKey`, `token`,
`client_secret`, `password`, `authorization`, and `cookie` are redacted.
Assignment-shaped password or secret prose is content-scanned and replaced with
the diagnostic or tool-result omission sentinel. An optionally quoted assignment
value is exempt only when its complete value is exactly `[redacted]`; any prefix
or suffix is omitted. Ordinary filesystem spans are sanitized in place to
`[host-path]` plus a bounded non-sensitive suffix, so surrounding commands,
tool results, and assistant diagnostics remain visible; credentials and private
run-artifact content are still omitted, and absolute roots or private run paths
never survive. Results exclude the current/running run, unrelated
conversations or threads, system prompts, reasoning, recalled memory,
turn-context payloads, and raw artifact paths; historical text is marked
untrusted.

### Session tool history

`SessionHistory` requires no config key. It is available under allow-all on
request-scoped MCP-capable routes; a restrictive `tools.allowedTools` must name
`SessionHistory` (`session_history` is also accepted by policy), and deny policy
can remove it. Each request constructs a fresh stateless MCP server and transport
on a host-bound loopback capability path. Direct OpenCode and ACP routes have no
compatible host-tool seam for `SessionHistory`, so they still persist and
cold-project tool records but suppress that new tool; `validate` reports
`unsupported_route` rather than pretending coverage exists. Issue #626 does not
change `RunHistory`'s pre-existing direct-ACP route wiring.

The canonical data is not run JSONL, Pi JSONL, web SQLite, or message-history
JSON. The harness incrementally writes every managed-tool start and terminal
result to `history/tool-history/tool-lifecycles.sqlite`, independently of
successful-turn commit. A lifecycle record may therefore exist without a
canonical message-history entry. Stable conversation/run/tool-call keys and
writer-assigned per-run start/end sequences make retries idempotent; process
recovery closes dangling starts as `interrupted` without rerunning a tool.
Arguments/results are securely pre-bounded, redacted, and byte-bounded, with truncation metadata and
opaque artifact ids. Filesystem-shaped spans in object keys and string values use an opaque host-root token plus
at most two non-sensitive trailing components, so commands and results remain
inspectable without exposing an absolute root, account/home prefix, artifact
root, or private run path. Only regular files beneath the configured run-specific
`tool-output` root are accepted or checked for availability; provider-supplied
outside or symlinked paths are dropped. Isolated/proactive
runs persist but search excludes them unless explicitly requested.

`{ "action": "search" }` returns at most 10 bounded previews with text,
tool/state/run/time filters and a query-bound opaque cursor.
`{ "action": "get", "recordId": "..." }` (or `toolCallId`) returns bounded
chunks up to 8 KiB, with tombstones when retention removed known records.
Only the exact physical `(conversationId, runId)` for the active turn is
unavailable; an older rollover bucket that reused the same opaque run id remains
readable. Unrelated-conversation records stay unavailable, daily rollover
buckets remain one logical scope, nested history-tool result
bodies are omitted, and every response is labelled untrusted. Cold context
reseed receives the newest fitting chronological suffix in a neutralized UTF-8
projection capped at 64 KiB including its truncation marker; warm provider resume
continues natively and receives no replay. A zero-byte fresh sidecar is absent
for automatic projection; another corrupt/unsafe projection emits a structured
warning and continues the turn, while explicit SessionHistory reads fail closed.
Lazy writer acquisition keeps one at-most-10-second restart-handoff attempt.
After failure, writes from every already-created turn reuse that rejection and
new turns fail immediately during an initial 30-second backoff. Each failed
probe doubles that window up to five minutes, preventing ordinary consecutive
turns during a sustained outage from repeatedly paying the full acquisition
ceiling. The first later probe re-arms one full acquisition, while serialized
explicit reset may bypass only the cooldown. A cached handle is retired after
worker closure/death, one turn never reacquires mid-turn, and the recovered
handle is shared; recovery resets the backoff. The outage emits one warning plus
one later recovery warning.

Telegram `/new` clears message records and tool records across the same logical
session, including prior daily rollover buckets that canonical replay,
SessionHistory, and cold projection can expose. A custom history store used with
daily rollover must implement logical-session reset or the reset fails closed.
The durable store holds one cross-process logical-session fence across discovery
and every bucket reset, and appends take that same fence before their physical
bucket lock.
`restart --clear-sessions` purges all provider transcripts, message history, and
tool history while reporting message/tool counts and bytes separately. Doctor
audits schema, ownership, journal/integrity state, recovery, quota, and distinct
unresolved fail-soft incidents. Repeating the same failed lifecycle retry does
not inflate the count, and unrelated writes or run finalization cannot hide lost
evidence; only the matching tool phase, its durable synthetic terminal closure,
or canonical run-binding retry clears its incident while it remains retryable.
Reset and retention clear only incidents whose exact run/call/record identity
they make unretryable. A crash-stale zero-byte content database is reported as
pristine and recoverable even when its protected DELETE journal remains; a live
initialization and stale next-writer recovery are reported distinctly. A
zero-byte owner database is also a recoverable initialization window, not a
missing-table corruption report. A delayed real result supersedes that synthetic
terminal record in place. A newer tool-history schema hard-fails downgrade until
persisted conversation state is purged; an older compatible version is reported
as upgrade-pending for the next writer.

### Channel interactions and conversation history

For missing context, the agent should use active conversation history first,
`MemoryRecall` for intentionally captured durable facts, `RunHistory` for exact
prior-run evidence, and `SessionHistory` for retained managed-tool calls and
results. Answered or expired blocking `AskUser` exchanges
are written into the assistant history copy before the final response;
cancelled asks are not journaled. The copy is explicitly labelled as untrusted
historical data and bounded by newest whole interactions. If the newest valid
entry is oversized, its option descriptions may be omitted while its questions,
outcome, and answers stay whole. This does not change the outward message or
long-term memory capture. The strict tool accepts one to five structured
questions, each with two or three described options and an optional multi-select
mode. Slack and Telegram present the questions sequentially with native buttons
plus a typed custom reply; the web console renders the whole question set as one
form. The built-in Telegram `/new` command uses the configured responder's
host-owned reset surface to clear only that logical conversation and force
skill/startup-context reload on its next turn.

### Memory health and maintenance

The app publishes a cached, content-free `memoryHealth` snapshot in the primary
trace-source heartbeat and any enabled best-effort global mirror. Built-in
health is computed through a dynamic memory import so a native SQLite ABI
failure becomes sanitized `unknown` health
instead of crashing unrelated CLI startup. Concurrent refreshes coalesce; in
steady state, ordinary trace events and the completion-based timer never run a
full audit less than 30 seconds after the prior completion. Startup and reload
make one explicit post-lifecycle exception so the registered snapshot reflects
the newly started store. The timer is unreferenced and invalidated at
stop/reconfigure entry, and the same
snapshot is used for both registries. The shape is limited to backend/mode,
closed status and issue vocabularies, ISO check time, and eight whitelisted
counts—never paths, ids, content, payloads, or raw errors.

Unexpected built-in audit failures use the stable `health_check_failed` issue,
while durable work that exceeds its ownership grace uses `work_stalled`; both
are fixed metadata-only classifications.

Operator automation should use:

```bash
# One prose/ANSI-free {ok:boolean, sections, ...} object; exit 0 iff ok.
mono-agent validate --json

# Provider-free closed health; healthy/in_progress/not_configured exit 0.
mono-agent memory audit --strict --json

# Payload-free inventory; mutations require the matching agent to be stopped.
mono-agent memory inspect --json
mono-agent memory retry --json
mono-agent memory retry <64-character-id> --json
mono-agent memory resolve <64-character-id> <reason-slug> --json

# Explicit BuJo cleanup: prepare is read-only; apply/restore require stop.
mono-agent memory forget prepare --ids-file ./forget-ids.txt --reason noise_cleanup --plan ./forget-plan.json --json
mono-agent memory forget apply --plan ./forget-plan.json --json
mono-agent memory forget restore --backup /path/returned/by/apply --json
```

Journal and BuJo always require a valid managed `.index/manifest.json`; only
Lite may remain unmanaged. Missing/corrupt authority, active/configured
tier-provider-model-dimension mismatch, and native-module/ABI failure are validation
errors with stop/rebuild/revalidate remediation. Provider reachability remains
an operational `waiting` state. LM Studio is keyless when `apiKeyEnv` is omitted;
a declared but missing variable stays `waiting` and never retries keyless.
Changing provider, model, or dimension on an existing root requires a stopped,
config-aware `mono-agent memory rebuild --json`. BuJo uses the selected
embeddings service independently from its explicit capture LLM (`agent-host` in
generated configs, or an authored Ollama block). The standalone `memory-bujo`
maintenance CLI has been removed; run every memory operation config-aware through
`mono-agent memory <subcommand>` from the agent folder.
`retry` makes dead/delayed intake due for the
next store start; `resolve` explicitly abandons one item without claiming
capture succeeded, keeps permanent duplicate protection, and refuses a retained
semantic plan. `forget prepare` accepts at most 32 ids and writes an owner-only,
single-link, content-free explicit-id plan. Stopped-store `forget apply` owns the
authoritative writer lease plus a durable sibling recovery fence, creates a
fsync-verified full backup, commits each id through durable migration-forget,
and rebuilds the managed generation. Failure restores automatically; process
death blocks normal writers until recovery resumes. Explicit restore refuses to
overwrite any durable change made after cleanup and atomically consumes the
verified sibling snapshot without constructing a third full copy.

### Fleet verification

For launchd fleet verification, invoke the deployed CLI with each plist's exact
`ProgramArguments[0]` Node, `[1]` CLI, absolute `--config`/`--env-file`, and
managed `PATH`. Probe children retain only launchd-safe operational environment
values; shell-only `MONO_AGENT_*`, provider credentials, `NODE_OPTIONS`, and
proxy overrides are not fleet evidence. The current fleet contract is Node
`24.15.0`, modules ABI `137`; an ambient shell Node or environment is not
evidence that the service can load the native memory modules.

### Programmatic embedding

```ts
import { startMonoAgentApp } from "@mono-agent/agent-app";

const app = await startMonoAgentApp({ cwd: "/path/to/agent-folder" });
console.log(app.channelStatuses());
await app.stop();
```

### Reply files and MCP Apps

The configured responder adds a request-scoped `PublishReplyFile` MCP tool when
the tool policy and runtime route can carry it. The tool copies one generated
ordinary-workspace file or one file from the exact current run's outbound root
into owner-private artifact storage, hashes it, and returns only an opaque
reference. The app composition explicitly treats its configured artifact root,
the artifact-dir-derived durable conversation-history/session store,
continuation state, memory, trace registry, provider sessions/auth, config,
identity, skill, and MCP roots as private. Only the exact current run's outbound
directory is admitted as a narrow artifact-root exception. Hidden path
components, mono-agent/MCP/auth/credential/secret/token
files, npmrc, private keys, certificates, key stores, state databases, and
Unicode-disguised variants are rejected at every depth, including under the
run-output exception. Publication rejects traversal, symlinks, multiply linked
inodes, directory swaps, and source changes detected through the pinned file
descriptor. Display names are NFC-normalized, stripped of Unicode bidi
controls, and bounded at UTF-8/code-point boundaries; errors expose neither
source paths nor bytes.

Files are limited to 20 MiB, and files plus MCP Apps share one 20-part run
budget. Their durable payloads and MCP audit files stay within a fixed 256 MiB
aggregate file-byte ceiling: configured composition reserves 1 MiB for
independently admitted audit files, leaving 255 MiB to the model-fillable shared
budget.
Admission is serialized, re-inventories both payload namespaces after restart,
and fails only the new part explicitly when full; it does not evict active
staging, current-run, or authorized in-flight content. Retried identities are
deduplicated. A manifest
that cannot accept its delivery-conversation binding becomes one bounded failed
part while answer text and other valid parts survive. Terminal failure,
cancellation, or missing run metadata removes uncommitted state. The sealed
local self-configuration override excludes this publisher.

Audit storage performs one root inventory for a process/root lifecycle, then
maintains exact owner byte counts under a global append gate. Reclamation uses
rotated history first, then inactive and unprotected owners' active files as a
last resort; a live or protected owner's active `audit.jsonl` is never a
candidate. Foreign read failures receive bounded conservative accounting and
remain quarantined for the process lifetime; recovery requires a process
restart and fresh root inventory. Every append, rotation,
cleanup, and quota-reclamation mutation revalidates the audit root, owner
directory, and singly linked file identities after the operation hook and before
using the child path. Admission that cannot safely create room fails closed
without changing unrelated or out-of-root history. Unsafe target files,
symlinks, hard links, and directories fail that owner closed, while oversized
target rotations receive the same safe bounded cleanup as foreign history.
Audit records contain host identity, method,
timestamp, and phase only—not model-filled tool names, arguments, resource URIs,
URLs, or results. Tool confirmation reserves both its confirmation and bounded
completion record before execution. A failed pre-execution admission returns
`app_audit_failed` and refuses the tool call; a real completion write failure
after a successful tool call remains `app_audit_incomplete` through operator
and web transport because the side effect may have occurred and must not be
retried automatically.

Pi-native routes can retain MCP App resources negotiated at either supported
ext-apps revision. The whole primary/fallback route must support the bridge;
otherwise neither the runtime extension nor operator capability is exposed.
Stored resources follow `artifacts.retention.maxAgeDays` within that aggregate
ceiling; live connections are separately bounded by an eight-entry LRU and
ten-minute idle timeout. See
[Reply files and MCP Apps](https://mono-agent-docs.vercel.app/tools/rich-replies/)
for native channel behavior, fallbacks, browser security, and limits.

## Architecture

### Data flow

`@mono-agent/agent-app` is the composition root. A running host follows this
path:

1. Resolve built-in and configured plugin `ChannelDriver`s, then load each
   channel's config together with the shared core config.
2. Build a separate configured responder for each active channel. The responder
   composes the runtime, harness, memory, tool/MCP policy, conversation history,
   recorder, and request-scoped extensions.
3. Start every driver in parallel. Each driver normalizes transport input into
   the shared request/stream contract and returns a `RunningChannel` handle. The
   cron driver registers configured and disabled jobs but arms only their
   effective runtime-enabled subset; its operator service feeds the TUI/web
   capability lane. Process-job operator authority bypasses the generic channel
   input and enters only the exact app-owned TUI driver through a private
   composition hook. The TUI driver primes its skill registry before binding
   and refreshes changed `SKILL.md` metadata in memory while it runs.
4. Publish traceability, exporter, sandbox, process-job, continuation, and memory-health
   state while the controller tracks channel states as `disabled`,
   `waiting_for_config`, `running`, `degraded`, or `failed`.
5. On stop or reload, stop the transport first, then dispose its responder so
   queued turns and warm provider sessions cannot outlive the config snapshot.
6. For the managed macOS web console, publish the main and helper LaunchAgent
   definitions as one composite-identity pair. The worker only wakes the helper;
   the helper alone rotates after stopped-writer proof under the web lifecycle
   lock and persists bounded recovery status.

### Package structure

| Area | Modules | Purpose |
| --- | --- | --- |
| Stable host facade | `app.ts`, `app-controller.ts`, `app-controller-*.ts`, `app-controller-types.ts` | Startup state plus narrow operation ports for status, reload, channel lifecycle, traceability, and teardown. |
| Configured agent | `configured-agent.ts`, `app-controller-responder.ts` | Runtime, harness, memory, history, tools, and recorder composition. |
| Channel integration | `channels.ts`, `channel-drivers/` | Built-in drivers plus config-loaded plugin resolution. |
| Interaction and send tools | `interaction-bridge.ts`, `adapter-send-tools*.ts` | Structured `AskUser` state, channel sinks, progress, adapter-send tools, and bounded interaction-history projection. |
| Operator CLI | `cli*.ts`, `jobs-command.ts`, `init.ts`, `doctor.ts`, `doctor-observability.ts`, `background*.ts`, `launchd*.ts`, `managed-web-logs.ts`, `web-*.ts` | Setup, focused validation sections, paired managed service/log lifecycle, process-job operation, and diagnostics. |
| Host services | `run-history.ts`, `session-history.ts`, `request-scoped-mcp.ts`, `process-jobs*.ts`, `continuation*.ts`, `memory-*.ts` | Shared request-scoped guards, bounded prior-run/tool-lifecycle evidence, local process-job ownership/wake/recovery, durable continuations, and memory operations. |

## Public API

### Start here

| Need | Primary API |
| --- | --- |
| Start or stop a config-first host | `startMonoAgentApp`, `MonoAgentApp`, `MonoAgentAppOptions` |
| Build only the configured execution stack | `createConfiguredAgentResponder`, `createConfiguredAgentHarness`, `createConfiguredAgentRuntime`, `createConfiguredMemory` |
| Embed selected built-in channels | `defaultChannelDrivers`, `resolveChannelDrivers`, `createTelegramChannelDriver`, `createSlackChannelDriver`, `createWebhookChannelDriver`, `createOpenAIApiChannelDriver`, `createCronChannelDriver` |
| Scaffold or validate an agent folder | `initMonoAgentFolder`, `validateMonoAgentFolder` |
| Add bounded prior-run inspection | `createRunHistoryRuntimeExtension`, `isRunHistoryToolAllowed` |
| Add bounded retained-tool inspection | `createSessionHistoryRuntimeExtension`, `isSessionHistoryToolAllowed` |
| Operate the CLI programmatically, including process jobs and the managed web lifecycle | `runCli`, `runJobsCommand`, `parseCliArgs`, `renderHelp` |

The web maintenance controller and publication helpers remain private CLI
implementation details; this change adds no new package-level public API for
that lifecycle.

<!-- public-api-inventory:start -->
<!-- Generated by scripts/generate-public-api-docs.mjs. Do not edit by hand. -->

Every symbol exported by each public code entrypoint is listed below.

**`@mono-agent/agent-app`**

```text
AppTraceDefaults
COMPOSER_SKILL_NAME
CONTINUATION_CLAIM_TOKEN_ENV
CONTINUATION_CLAIM_TOKEN_HEADER
CONTINUATION_CLAIM_URL_ENV
CONTINUATION_CLAIM_URL_HEADER
CONTINUATION_FINGERPRINT_ENV
CONTINUATION_FINGERPRINT_HEADER
CONTINUATION_MODE_ENV
CONTINUATION_MODE_HEADER
CONTINUATION_STATES
ChannelDriver
ChannelDriverOverrides
ChannelId
ChannelStartInput
ChannelStatus
ConfigApplyResult
ConfiguredAgentHarnessOptions
ConfiguredAgentResponderOptions
ConfiguredAgentRuntimeOptions
ConsumerContractFixtureOptions
ConsumerContractFixtureResult
ConsumerContractIssue
ConsumerContractName
ConsumerContractSectionStatus
ContinuationClaimCapability
ContinuationDeliveryReceipt
ContinuationHealthSnapshot
ContinuationHistoryRecordInput
ContinuationHistoryRecordResult
ContinuationLimits
ContinuationMode
ContinuationNativeDeliveryInput
ContinuationNativeDeliveryResult
ContinuationProtocolError
ContinuationRetentionOptions
ContinuationServiceHandle
ContinuationServiceLogger
ContinuationServiceOptions
ContinuationSettings
ContinuationState
ContinuationStatusSnapshot
ContinuationStoreStats
ContinuationSynthesisAvailability
ContinuationSynthesisInput
ContinuationSynthesisResult
ContinuationSynthesisUnavailableError
ContinuationTerminalState
CronChannelOverrides
DEFAULT_CONTINUATION_LIMITS
DEFAULT_CONTINUATION_SERVICE_PORT
ExporterStatus
InitFileChange
InitFileChangeKind
InitMonoAgentFolderOptions
InitMonoAgentFolderResult
InstallSkillOptions
InstallSkillResult
InstallSkillTarget
IssueContinuationCapabilityInput
MANAGED_SRT_LOCK_SHA256
MANAGED_SRT_PACKAGE
MANAGED_SRT_VERSION
ManagedSrtSetupOptions
ManagedSrtSetupResult
MemoryRitualSchedule
MonoAgentApp
MonoAgentAppConfigInput
MonoAgentAppLogger
MonoAgentAppOptions
NamedContinuationRoute
OpenAIApiChannelOverrides
PreflightResult
RUN_HISTORY_MCP_SERVER_NAME
RUN_HISTORY_TOOL_NAME
ResolvedExporter
RunContinuationCommandOptions
RunHistoryBinding
RunHistoryRuntimeExtension
RunHistoryRuntimeExtensionOptions
RunJobsCommandOptions
RunningChannel
RunningRituals
SESSION_HISTORY_MCP_SERVER_NAME
SESSION_HISTORY_TOOL_NAME
SandboxCheckResult
SandboxCommandDependencies
SandboxFunctionalCheck
SandboxManagerOptions
SandboxRuntimeStatus
SecretEnvRefusalCode
SecretPersistenceOutcome
SecretPersistenceStatus
SessionHistoryBinding
SessionHistoryRuntimeExtensionOptions
SlackChannelOverrides
StartMemoryRitualsInput
TERMINAL_CONTINUATION_STATES
TelegramChannelOverrides
TraceabilityStatus
ValidateMonoAgentFolderOptions
ValidationReport
ValidationSection
ValidationStatus
WebhookChannelOverrides
badge
canonicalContinuationJson
channelBadge
checkSandboxRuntime
computeColorEnabled
configuredRuntimeFallbackModels
configuredRuntimeModels
consumerContractNames
consumerContractRunSummaryStatuses
continuationDigest
continuationOperatorToken
createConfiguredAgentHarness
createConfiguredAgentResponder
createConfiguredAgentRuntime
createConfiguredMemory
createCronChannelDriver
createOpenAIApiChannelDriver
createRunHistoryRuntimeExtension
createRunHistoryServer
createSessionHistoryRuntimeExtension
createSessionHistoryServer
createSlackChannelDriver
createTelegramChannelDriver
createWebhookChannelDriver
defaultChannelDrivers
ensureStartable
hasConfiguredRuntimeFallbacks
healthBadge
initMonoAgentFolder
installComposerSkill
isAppCoreConfigError
isColorEnabled
isContinuationMode
isContinuationState
isRunHistoryToolAllowed
isSessionHistoryToolAllowed
keyValue
loadAppCoreConfig
loadCliEnvFile
loadContinuationSettings
managedSrtInstallRoot
normalizeContinuationReplyTarget
parseCliArgs
phoenixAppBaseUrl
printAppStatus
renderHelp
resolveAppArtifactDir
resolveAppObservabilityExporters
resolveAppTraceHeartbeatMs
resolveAppTraceRegistryDir
resolveAppTraceSourceId
resolveAppTraceSourceLabel
resolveAppTraceStaleAfterMs
resolveChannelDrivers
rule
runCli
runContinuationCommand
runJobsCommand
runSandboxCommand
runtimeUsesFallbackRouter
sandboxRuntimeStatus
setupManagedSrt
startContinuationService
startMemoryRituals
startMonoAgentApp
style
validateConsumerContractFixture
validateMonoAgentFolder
```

<!-- public-api-inventory:end -->

## Dependency Boundary

Depends on `core`, `runtime`, `execution`, `observability`, `communication`,
and `operator-surface` packages. It is the only publishable package allowed to
compose communication adapters; adapters never depend on it.

## What This Package Does Not Own

- Adapter transports, credentials, or allowlists (owned by each
  `*-adapter` package).
- Core config schema and loading (owned by `@mono-agent/config`).
- Low-level prompt/session/tool execution internals (owned by
  `@mono-agent/agent-harness` and `@mono-agent/runtime-adapter`).
- Multi-agent orchestration (owned by `@mono-agent/agent-orchestrator`).

## Related Documentation

- [Quickstart](https://mono-agent-docs.vercel.app/getting-started/quickstart/)
- [Agent folder layout](https://mono-agent-docs.vercel.app/config/folder-layout/)
- [Configuration blueprint](https://mono-agent-docs.vercel.app/config/blueprint/)
- [CLI reference](https://mono-agent-docs.vercel.app/observability/cli-reference/)
- [Programmatic composition](https://mono-agent-docs.vercel.app/programmatic/composition/)
- [Channels](https://mono-agent-docs.vercel.app/channels/)
- [Local-first web research](https://mono-agent-docs.vercel.app/tools/web-research/)
- [Reply files and MCP Apps](https://mono-agent-docs.vercel.app/tools/rich-replies/)
- [Package source and generated API inventory](https://github.com/robertsreberski/mono-agent/tree/main/packages/agent-app)

## Verification

```bash
pnpm --filter @mono-agent/agent-app run typecheck
pnpm --filter @mono-agent/agent-app run test
pnpm run check:architecture
```

Smoke path: `mono-agent init` in a temp folder, `mono-agent validate`, then
`mono-agent start` and a `curl` POST against the printed webhook invoke URL.
