# Runtime source agent guide
## Ownership
`lib.rs` exposes only `run_from_env()` and `run_from_env_with_exit_code()` for CLI startup. All modules and data types are internal. `bin/magi-code.rs` delegates to supported entrypoints. Extract implementations behind owning facades; keep export changes explicit.
| Launch parsing and validation | `cli.rs`, `cli/validation.rs`; subcommands: `cli/{sessions,mcp}.rs` |
| Shared settings/discovery/MCP startup snapshot | `runtime_context.rs` |
| Pipe protocol, sessions and turns | `local_agent.rs`, `local_agent/`; local guide owns wire constraints |
| Slash grammar and runtime selection | `commands.rs`, `commands/runtime.rs` |
| Turn provider selection/construction | `agent/runner/preparation.rs`, `providers/factory.rs` |
| Provider credentials, readiness, runtime resolution, login | `auth.rs`, `auth/{runtime,readiness,codex_oauth,login}.rs`; credential data: `credentials.rs`; MCP login: `mcp/oauth.rs` |
| Cargo update bounds and restart | `updates.rs`, `updates/`; idle handoff: `tui/controller/app/updates.rs` |
| Title provider work and summary observer/log | `session_titles.rs`, `summarizer.rs`; durable titles: `sessions/`; summary display: `tui/state/summary.rs` |
| Passive event-summary scheduling/provider work | `progressive_session_maintenance.rs`, `progressive_session_maintenance/generation.rs`; durable batches: `sessions/progressive_summaries.rs` |
| Compaction generation/live request snapshots/rotation | `compaction.rs`, `compaction/cached_request.rs` / `sessions/write.rs`; optional early timing: `agent/compaction_timing.rs` |
| Review snapshots/comments | `diff_review.rs`, `diff_review/`; display: `tui/diff/` |
| Hooks and post-edit diagnostics | `hooks.rs`, `hooks/`; `lsp.rs`, `lsp/` |
| Redaction/display metadata vs semantic lines | `output/` vs `rendering/`; normalization: `output/tool_display/`; shared safe tool meaning: `output/tool_card/` |
| Appearance roles/styles | `appearance.rs`, `appearance/roles.rs` |
| Checkpoint rewind planning/mutation | `checkpoints/rewind.rs`, `checkpoints/rewind/` |
| Active runtime and platform-shell spawning | `shell.rs`, `shell/runtime.rs`; bounded stdin: `shell/child_pipe_writer.rs` |
| Protected file access | `persistence.rs` |
| Shared leaf helpers (hashing, hex, paths, joins, HTTP bodies, prompt classification, credential keys) | `support.rs`, `support/`; cancellation: `cancellation.rs` |
| Jev requests/cache/evidence | `typesafe.rs`, `typesafe/evidence.rs`; feature policy: `protection/` and verifier owners |
| Startup/touched-path instructions and skills | `instructions.rs`, `instructions/subdir.rs`, `skills.rs` |
| Offline tool-output reports | `tool_output_measurement.rs`, `tool_output_measurement/{scanner,codecs}.rs` |
## Allowed dependency directions
- `provider_ids`, `credentials` and `tool_contract` have no subsystem dependencies. Use `provider_ids` directly outside providers; never import identity constants through provider execution.
- `support.rs`, `support/` and `cancellation.rs` must not import subsystem modules (`crate::config`, `crate::tools`, `crate::providers`, etc.). Reuse `support/path.rs` for lexical normalization. Single-caller helpers live with their caller.
- Bash prompt classification stays in `support/bash_mode.rs` because both agent execution and TUI submission use it. Credential-key classification stays in `support/security.rs` so process-environment filtering does not depend on output and its execution dependencies.
- Stable hashing stays in `support/hash.rs`: both summarizer event identity and transcript activity-link cache keys use it.
- `auth` → `config` for effective settings; credential data stays in `credentials`. Runtime credential resolution and provider selection belong in `auth/runtime.rs`, not config.
- `config` → `provider_ids`, `credentials`, `thinking`, `persistence` and pure validation/default/catalog helpers. Its only allowed tools import is `tools::names::canonical_disabled_key`; never import `ToolRuntime`. No config → auth or sessions edges.
- Startup (`runtime_context` and profiling startup) → config directory setup, then `sessions::prepare_session_root`. `McPaths::ensure_runtime_dirs` does not prepare session permissions.
- `sessions` → config/persistence and shared output data; its tools dependency is limited to dispatch-name equivalence in chat reconciliation. Do not pull tool execution or subagent scheduling into storage.
- `tools` and `subagents` → `output::{ToolResult, ToolResultDisplay, SubagentsOutput, SubagentStatus, MAX_SUBAGENT_TASKS}`. Result fields/serde contracts live in `output/{tool_result,subagent_result}.rs`; runtime validation/projection stays with execution owners.
- `output` → `tool_contract` for argument/metadata names. Remaining tools access is pure capability classification and read-only hash-edit operation summaries; no output → subagents edge.
- `context` → providers only for conversation/request semantics and prompt limits; provider IDs come from the leaf. Fast policy/observations live in `providers/fast.rs`, exposed through the provider facade.
### Retained mutual dependencies
These are bounded existing couplings, not permission to add unrelated reverse edges. The issue's literal `crate::<top>` scan misses grouped imports and is only a lower bound.
| agent ↔ subagents, compaction, herdr | Child execution, live compaction context, run reporting |
| auth ↔ providers | Provider-specific readiness and credential refresh |
| config ↔ appearance, thinking, model_catalog, providers | Settings defaults, reasoning protocols and cached model limits |
| config ↔ tools, subagents, mcp, typesafe | Narrow name/depth/header/service validation helpers |
| checkpoints ↔ sessions; compaction ↔ sessions; progressive_session_maintenance ↔ sessions | Rewind/retention, live request snapshots and durable maintenance observation |
| code_mode ↔ tools, output | Guarded catalog/execution and display evidence |
| context ↔ providers, output | Request budgeting and sanitized replay/display projections |
| model_catalog ↔ providers; providers ↔ thinking | Catalog transport/capabilities and reasoning protocols |
| mcp ↔ tools; providers ↔ tools; subagents ↔ tools | Schema conversion, tool advertisement/search and child tool policy |
| output ↔ providers, protection, tools | Fast observations, protected replay, capability/patch presentation |
| sessions ↔ tools | Saved-call dispatch-name equivalence only |
## Runtime contracts
- Keep title-provider work outside storage and durable/security-sensitive behavior outside display modules. Compaction summary generation uses its selected provider without a Jev check; optional Jev timing only decides whether to compact early.
- Cache-preserving compaction captures settled live requests in `Session` memory. Match provider/model and history fingerprint; preserve instructions/tools and append summary instructions. Never dispatch summary tool calls. Fallback stays tool-free, cancellation stops both paths, and each provider attempt owns separate usage accounting.
- `persistence::open_regular_file` and `read_regular_file_bounded` reject final symlinks and Unix FIFOs through held handles. Callers still own parent containment and byte bounds; lock renewal verifies ownership and updates time through the same handle.
- CLI routing must not recreate provider, auth, tool or session policy.
- Usage errors are `AppError::Usage` (exit 2); runtime failures are `AppError::Runtime` (exit 1). Clap owns parsing, `cli/validation.rs` owns cross-mode checks before side effects, configuration owns override precedence.
- `serve --stdio` routes before terminal setup; detailed lifecycle belongs in `local_agent/AGENTS.md`.
- `--update` is standalone before TTY/config/provider/session setup. TUI requests carry restart data only; execute update/restart after terminal cleanup, app drop, writer-lease release and Herdr release.
- `parse_slash_command` separates empty input, ordinary prompts, built-ins and unknown slash commands. Keep grammar/names/help in registry entries, not callers.
- `/settings` drafts belong in `tui/settings_editor.rs`; writes in `config/settings/editor.rs`. Model availability belongs in Settings → Models; retired `/models` stays out of help/autocomplete. `/model` selects cached models without catalog refresh.
- Logout distinguishes removed credentials from absent entries. Command status is local, never provider conversation content.
## Hooks, diagnostics and output
- Hook phases: `before_tool`, `after_tool`, `after_assistant`, `after_reasoning`. Policies ignore/warn/block/fail; block applies only before tools. Preserve `target_ran` on post-target failures.
- Inject hook stdout only as parsed, byte-bounded `context_items` with user role. Execute through tool cwd preflight/shared shell spawning; hook runtime owns bounded pipes and cleanup. Payload refs stay under canonical session root with protected permissions; affected paths retain count/length bounds and write-symlink rejection. Redact hook and injected-context records before storage.
- LSP uses Content-Length framing, not MCP newline JSON. Keep waits/cancellation in blocking client workers and release child processes on shutdown. Versioned diagnostics must meet requested version; unversioned diagnostics must follow synchronization start. Preserve count/byte/redaction limits, idle shutdown and repeated-failure disabling. Unavailable servers are not clean checks; diagnostics never widen editing access.
- `OutputEvent` is neither a session record nor provider request. Streaming redaction spans deltas; flush at hard boundaries before unrelated rows. Terminal-control sanitization is separate and precedes styling. Status labels belong in `output/tool_summary.rs`.
- `rendering/` returns `DisplayLine`/`DisplaySpan` with `DisplayRole`, not terminal colors. Callers own layout, limits, redaction and wrapping. Syntax loads lazily with `OnceLock`; highlighting caps at 400 lines / 64 KiB with fallback roles. Diff headers precede added/removed classification; rendering never applies patches.
- Code Mode/task facts: `output/tool_card/{execution_facts,task_telemetry}.rs`; contract: `docs/features/execution-task-card-facts.md`. Keep explicit nulls, bounded safe activity and aggregate counts independent of previews.
- Web/Image/Control public rows: `output/tool_card/public_facts.rs`; private Control input exclusion: `output/control.rs` and `output/tool_display/`. Preserve fixed labels/nulls in `docs/features/web-image-control-card-facts.md`; never reconstruct Control facts from output text.
- `ShellState` is shared runtime state, not a REPL. `spawn_platform_shell` creates piped output and a Unix process group; callers enforce cwd, limits, timeout, cancellation and cleanup. `ShellEnvPolicy::Sanitized` skips startup profiles.
- MCP/LSP share `ChildPipeWriter`: nonblocking stdin, serialized writes and deadline/cancellation checks. Reuse request deadlines; add no writer threads/queues.
## Instruction and skill discovery
- Startup instruction order: user `AGENTS.md`, explicit project-root `AGENTS.md`, then configured Markdown paths in listed order. No arbitrary ancestor scan or automatic `CLAUDE.md` loading. Configured paths are absolute `.md` files; retain indexed setting errors.
- Startup caps: 256 KiB/file, 1 MiB combined. Ignore missing optional guides; propagate other startup read failures.
- Touched-path guides load nearest-first, excluding root/already-loaded canonical paths. Allow in-root links only to in-root targets; skill/profile symlink policy differs. Cap local guides at 256 KiB and return diagnostics alongside loaded text; discovery executes nothing and writes no memory files.
- Skill collision priority: repository `.agents/skills` > configured absolute roots (later replaces earlier) > `$MC_HOME/skills` > legacy `~/.agents/skills`. Discover `SKILL.md` directly in skill directories or one grouping level below; names come from directories, not frontmatter.
- Reject non-regular/symlinked descriptors and symlink directory traversal. Cap descriptors at 1 MiB; failures remain per-path diagnostics and output uses deterministic `BTreeMap` order. Frontmatter is flat key/value, not YAML: preserve CRLF, quoting and malformed-marker diagnostics.
- Disabled-name filtering is not opt-in discovery and never relaxes reference containment. Reads of discovered skill/reference bodies belong to `tools/skill.rs`.
## Offline measurement
- Scan active primary and direct subagent sessions only, relative to held directory handles without following symlinks. Preserve open/scan signatures; newest modification time then path determines selection within file/byte/line limits.
- Results require valid identity/success and exactly one text field (`content` or legacy `output`). Compare candidates within the same Codex Responses-style item; local token estimates are not billing.
- JSON minification removes whitespace outside strings without reserialization. Select only a unique smaller candidate; helpers are neither public API nor live compression.
- Shared `profiling/profile_harness/` separates find/content/CPU/render workloads; mixed/scroll reuse render helpers. No profiling CI or correctness suite.
- Profiling hooks live in `profiling`/`profiling_support` child modules. Any `#[cfg(test)]` production struct field or hot-path block must name its consuming workload in a comment.