OMP Workbook

Read the source. Follow the evidence.

Configuration and launch precedence

A displayed setting answers a configuration question. It does not necessarily answer the wrapper’s final policy question.

Nia’s fictional settings view says always-ask, yet an exec-tier recording call proceeds without a question. Before assuming a broken gate, she checks whether the launch supplied autoApprove separately.

Keep persisted configuration and runtime overrides separate

The supplied Settings implementation merges the active profile’s persisted layer, project settings, explicit configuration overlays, and runtime overrides, in that increasing order of precedence. get() resolves a value from the merged view, falling back to the schema default when it is absent.

Settings.set() changes the persisted layer and queues saving. Settings.override() changes a non-persisted runtime layer. An ordinary session transition is not a factory reset of those settings.

For well-formed object layers, maps are deep-merged; arrays such as bash.patterns are replaced by the higher layer rather than concatenated. Therefore the effective ordered rule list must be inspected as a list, not imagined as every rule from every file in sequence.

The wrapper reads mode and user policies from its execute-time context.settings. A tool’s own classifier can also read settings bound to its tool instance—for example, BashTool.approval() reads its session’s bash.patterns. A dump from an unrelated settings instance cannot establish both inputs.

Read the isolated CLI observation

The supplied configuration report used the installed omp/18.0.7 CLI, an exclusively owned fresh named profile with no linked authentication, and an empty temporary working directory. It did not inspect or change the reader’s personal settings.

This section reproduces the observation, not an executable recipe. The report does not include a complete profile-creation preamble, so no launch or profile-creation command is invented here. The default route is to read the recorded roundtrip.

Setting tools.approvalMode to write with JSON output returned:

Configuration and launch precedence · source excerpt 1; read surrounding instructions
{"key":"tools.approvalMode","value":"write"}

Setting the tools.approval record to the JSON object {"bash":"deny"} returned:

Configuration and launch precedence · source excerpt 2; read surrounding instructions
{"key":"tools.approval","value":{"bash":"deny"}}

The saved configuration was YAML:

Configuration and launch precedence · source excerpt 3; read surrounding instructions
tools:
  approvalMode: write
  approval:
    bash: deny

Getting each setting with JSON output returned an object, not merely its value:

Configuration and launch precedence · source excerpt 4; read surrounding instructions
{
  "key": "tools.approvalMode",
  "value": "write",
  "type": "enum",
  "description": "Default approval behavior for tool calls. 'Always ask' auto-approves read-only tools only. 'Write' auto-approves read and workspace-write tools. 'Yolo' auto-approves all tiers; user policy may still prompt or block."
}
Configuration and launch precedence · source excerpt 5; read surrounding instructions
{
  "key": "tools.approval",
  "value": { "bash": "deny" },
  "type": "record",
  "description": "Per-tool approval policies. Set to 'allow' to auto-approve, 'prompt' to require confirmation, or 'deny' to block. Overrides are honored in every approval mode."
}

Those descriptions are the observed CLI copy. Their shorthand about read-only/workspace-write behavior does not establish containment or override the more precise resolver precedence. The supplied capture also contains wall-time annotations; those are not fields in either JSON setting object.

Recorded boundary: the roundtrip demonstrates configuration serialization and inspection. It does not demonstrate an approval dialog, a live session override, effective wrapper policy, or a model invocation. commands/config.ts delegates to runConfigCommand(); the full delegated CLI implementation is not in this selected pack, so the observed JSON shapes are kept attached to the report.

Launch flags add a second source of precedence

The supported built-in long forms are --approval-mode, --auto-approve, and --yolo. The latter two set autoApprove: true. There is no listed built-in -y alias in the supplied parser.

These are flag fragments to interpret, not commands to launch for this exercise:

Launch inputSettings value after root-command overrideWrapper mode when the corresponding context is supplied
No approval flagExisting resolved settingThat setting, with the wrapper’s documented fallback if absent
--approval-mode always-askalways-ask, runtime onlyalways-ask
--auto-approve or --yolo, without an explicit modeyolo, runtime onlyyolo
--approval-mode always-ask together with --auto-approve or --yoloalways-ask remains the displayed runtime settingyolo, because context.autoApprove === true wins in the wrapper

main.ts deliberately preserves the explicit mode in settings when both inputs exist. buildSessionOptions() separately forwards autoApprove, and the SDK supplies it in the tool context. The wrapper chooses yolo from that boolean before calling resolveApproval().

Changing the order of those two different flags is not a way to make the explicit mode outrank the boolean at the wrapper. They populate separate inputs.

Recorded comparison: boundary-auto-approve-mode injected configured always-ask, autoApprove: true, and no UI. It returned with zero prompts and one inert execution. boundary-auto-approve-still-denied added an effective user deny and stopped before handlers, prompts, or execution. These cases verify execute-time wrapper behavior, not CLI parsing or a full launch.

Invalid input does not create a new safe mode

The --approval-mode setter accepts exactly the three documented values. For an invalid supplied value it logs a warning and does not install that value as the parsed mode. That is not the same as a hard launch refusal, nor proof that it selected always-ask. Other parsed inputs and the resolved settings remain relevant.

Similarly, a type annotation on Settings.get() is not runtime validation of every hand-edited value. Keep the resolver’s normalization of individual policy strings separate from raw record shape, launch parsing, and other consumers.

Paper checkpoint: a settings view says always-ask, but the execute-time context has autoApprove: true. What mode does this wrapper use, and can an effective deny remain? Worked answer: yolo; yes, the resolver’s explicit deny branches still apply.

Failure boundary: no configuration change is required to finish this chapter. Do not use a personal profile to recreate the observation or treat a config getter as a diagnostic endpoint for another process’s effective policy.

Source anchors: packages/coding-agent/src/config/settings.ts — Settings.get, set, override, #rebuildMerged; packages/coding-agent/src/config/settings-schema.ts — tools.approval, tools.approvalMode, bash.patterns; packages/coding-agent/src/commands/config.ts — Config.run; packages/coding-agent/src/cli/args.ts — parseArgs; packages/coding-agent/src/cli/flag-tables.ts — STRING_SETTERS["--approval-mode"], VALUELESS_FLAGS; packages/coding-agent/src/main.ts — runRootCommand, buildSessionOptions; packages/coding-agent/src/sdk.ts — execute-time context construction. CLI observations: proof/cli-config-proof.json.

Tool permissions and approvals · Source chapter: permissions/configuration-and-launch-precedence. Original evidence remains scoped to its recorded snapshot.

Read this chapter as Markdown

Your lesson ticks

A self-reported reading checklist, not proof of real OMP behavior. Only these ticks are saved in this browser. Reading a milestone does not resume, fork, reset or export a session.

Chapters I have worked through
Start here 1
Sessions, resets, and reviewable history 19
Memory and reusable knowledge 14
Tangent work and live control 17
Tool permissions and approvals 15
Extensions inside those boundaries 23
Connections and next steps 8
0 of 97 checked

Checklist saving needs JavaScript and available browser storage.