Otto extensions

Labs
This feature is in Labs.

Extensions are opt-in capabilities that ship inside the Otto binary and add tools, slash commands, or background behaviors to a session. Some are on by default because they catch common mistakes or add useful slash commands; others are off by default because they spawn subprocesses, consume credits, or materially change behavior.

Bundled extensions

NameDefaultWhat it does
ask-useronRegisters the ask_user tool so Otto can ask 1-4 focused questions in a single batch rather than many one-at-a-time prompts.
dag-validationonAfter any edit or write to dags/*.py, runs af dags errors and surfaces import errors so Otto self-corrects in the same turn. Only fires when a local Airflow is reachable.
memoryonRegisters /bootstrap (seed memories from git and GitHub history) and /remember (save learnings from the current conversation).
skillsonProvides the hosted-skill surface: the skill tool, the /skills picker, and /skill:<name> commands for hosted skills. Disabling removes hosted skills entirely; local skills still work. See Skills.
spinner-verbsonReplaces the default loader with space-themed verbs and an elapsed-time counter. Cosmetic only.
subagentoffRegisters a subagent tool that delegates tasks to isolated otto subprocesses. Supports single (task) or parallel (tasks: [...]) delegation, with fast and deep model tiers.

Enable or disable an extension

Four layers control whether an extension is on, merged in order (highest priority first):

LayerWhereExample
CLI flag--extension <name>, --no-extension <name> (repeatable)astro otto --no-extension dag-validation
Environment variableOTTO_EXTENSIONS, OTTO_DISABLED_EXTENSIONS (comma-separated)OTTO_DISABLED_EXTENSIONS=dag-validation astro otto
Project settings.astro/otto/extensions.json{ "dag-validation": false }
User settings~/.astro/otto/extensions.json{ "memory": false }

Within a layer, an explicit disable beats an explicit enable. For example, --extension foo --no-extension foo disables foo.

Manage extensions interactively

Run /extensions inside an Otto session to open an interactive editor.

The main picker shows each bundled extension with its current state and a * marker when a CLI flag or environment variable is overriding the settings files. Select an extension to open a per-extension editor with two rows: a User scope row and a Project scope row. Each row has a three-state checkbox:

  • [x] on — writes enabled: true to that settings file.
  • [ ] off — writes enabled: false to that settings file.
  • [~] unset — removes the enabled field so lower layers win.

Press Enter or Space to cycle the focused row. The title bar updates to show the predicted next-session state and which layer is winning. Press Escape to save and close.

To apply the change:

  • Run /reload to re-run the extension list against the fresh settings while keeping your conversation history.
  • Run /new to start a fresh session.
  • Restart Otto for a full reset.

Configure an extension

The settings file accepts either a boolean shorthand or an object with enabled plus any extension-specific config. Both forms can coexist in the same file:

1{
2 "memory": false,
3 "dag-validation": {
4 "enabled": true,
5 "timeout": 60000
6 },
7 "subagent": {
8 "enabled": true,
9 "tiers": { "fast": "gpt-5.4-nano", "deep": "gpt-5.4" }
10 }
11}

Project settings shadow user settings per extension (whole-entry replace, not a deep merge).

Configurable fields

ExtensionFieldTypeDefaultDescription
dag-validationtimeoutnumber30000Timeout in milliseconds for af dags errors.
subagenttiers.faststringgpt-5.4-nanoModel used when a subagent call uses tier: "fast".
subagenttiers.deepstringparent’s modelModel used when a subagent call uses tier: "deep". Omit to inherit the main conversation’s model.

Extensions that don’t appear in the table take no configuration — they’re either on or off.