For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
      • AstroFully-managed data operations, powered by Apache Airflow.
      • Astro Private CloudRun Airflow-as-a-service in your environment.
      • Professional ServicesExpert Airflow services for your enterprise's success.
    • Tools
      • Cosmos
      • Orbiter
      • CLI
      • AI SDK
      • Agents
      • Blueprint
      • UpdatesThe State of Airflow 2026See the insights from over 5,800 data practitioners in the full report. Download Now ➔
  • Customers
  • Docs
    • Insights
      • Blog
      • Webinars
      • Resource Library
      • Events
    • Education
      • Academy
      • What is Airflow?
  • Pricing
Get Started Free
    • Overview
        • Overview
        • Quickstart
        • Customize Otto
        • Upgrade Airflow with Otto
          • Tools
          • Skills
          • Memory
          • Permissions
          • Extensions
          • Settings
      • MCP servers
      • Toggle AI features
    • Book Office Hours

Product

  • Platform Overview
  • Astro
  • Astro Observe
  • Astro Private Cloud
  • Security & Trust
  • Pricing

Tools & Services

  • Cosmos
  • Docs
  • Professional Services
  • Product Updates

Use Cases

  • AI Ops
  • Data Observability
  • ETL/ELT
  • ML Ops
  • Operational Analytics
  • All Use Cases

Industries

  • Financial Services
  • Gaming
  • Retail
  • Manufacturing
  • Healthcare
  • All Industries

Resources

  • Academy
  • eBooks & Guides
  • Blog
  • Webinars
  • Events
  • The Data Flowcast Podcast
  • All Resources

Airflow

  • What is Airflow
  • Airflow on Astro
  • Airflow 3.0
  • Airflow Upgrades
  • Airflow Use Cases
  • Airflow 2.x End of Life

Company

  • Our Story
  • Customers
  • Newsroom
  • Careers
  • Contact

Support

  • Knowledge Base
  • Status
  • Contact Support
GitHubYouTubeLinkedInx
  • Legal
  • Privacy
  • Terms of Service
  • Consent Preferences

  • Do Not Sell or Share My Personal information
  • Limit the Use Of My Sensitive Personal Information

Apache Airflow®, Airflow, and the Airflow logo are trademarks of the Apache Software Foundation. Copyright © Astronomer 2026. All rights reserved.

LogoLogo
On this page
  • Permission modes
  • Where configuration lives
  • Configuration file shape
  • Rule strings
  • Path deny
  • Command patterns
  • Content patterns
  • Built-in safety checks
  • Inspect the current state
  • Disable permissions for a session
AI featuresOttoReference

Otto permissions

Edit this page
Built with
Labs
This feature is in Labs.

Otto ships a first-party permission layer that gates every tool call. Each call resolves to allow, ask (prompt the user), or deny based on the active permission mode and your configured rules.

Out of the box, Otto asks before running destructive Astro and Airflow commands, prompts before writing to sensitive files like .env or .ssh/*, and restricts writes outside your project folder. You can extend or relax these behaviors through config files and permission modes.

Permission modes

Otto runs in one of five modes. Cycle through modes interactively with Ctrl+] or the /permissions command.

ModeBehavior
defaultNormal behavior. Tools are allowed, denied, or prompted based on your rules.
acceptEditsAuto-allows edit and write inside the project. Other tools fall through to the normal rules. Safety checks still fire.
confirmEditsPrompts before edit, write, and non-read-only bash. Allow rules can’t bypass the prompt. Read tools and read-only bash fall through to the normal rules.
planBlocks edit and write entirely. Restricts bash to a read-only allowlist (ls, cat, git, rg, af, astro, etc.).
bypassPermissionsAllows everything except bypass-immune safety checks on sensitive files and out-of-project writes.

Set the starting mode with the --permission-mode <mode> flag or the OTTO_PERMISSION_MODE environment variable.

Where configuration lives

Otto reads permissions from three files, merged in order (later wins):

ScopePathPurpose
User~/.astro/otto/permissions.jsonYour personal rules across all projects
Project.astro/otto/permissions.jsonTeam-wide rules committed to Git
Local.astro/otto/permissions.local.jsonYour local-only overrides (gitignore this file)

Commit project-scope rules to your repository so every engineer on the team gets the same posture.

Configuration file shape

1{
2 "enabled": true,
3 "defaultMode": "default",
4 "restrictToProjectDir": true,
5 "rules": {
6 "allow": ["Bash(ls:*)"],
7 "deny": ["Bash(rm -rf /:*)"],
8 "ask": ["Bash(git push:*)"]
9 },
10 "pathDeny": [
11 {
12 "id": "no-root-writes",
13 "patterns": ["/etc/**", "/usr/**"],
14 "tools": ["write", "edit", "bash"],
15 "message": "Refusing to write outside user-space."
16 }
17 ],
18 "commandPatterns": [
19 {
20 "id": "my-dangerous",
21 "pattern": "\\bdrop\\s+database\\b",
22 "regex": true,
23 "behavior": "ask",
24 "description": "drop database"
25 }
26 ],
27 "contentPatterns": [
28 {
29 "id": "no-eval-in-dags",
30 "pattern": "eval\\(",
31 "regex": true,
32 "onTool": ["write", "edit"],
33 "pathGlobs": ["**/dags/**/*.py"],
34 "behavior": "deny",
35 "message": "Avoid eval() inside Dag code."
36 }
37 ]
38}

Rule strings

Rules use the format Tool or Tool(content). Content can be a command prefix, a path glob, or * to match everything.

RuleEffect
BashMatches every bash call
Bash(astro deploy:*)Matches bash commands starting with astro deploy
Write(/etc/**)Matches write calls whose path glob-matches /etc/**
Read(~/.ssh/**)Matches read calls with ~ expansion

Path deny

pathDeny blocks writes and edits against a glob list, including bash redirects. Use it to protect folders regardless of the command used to reach them.

Command patterns

Bash-only patterns that match the full command string. Use regex: true for regular expressions. commandPatterns with behavior: "ask" fire even in bypassPermissions mode.

Content patterns

Scan the body of write and edit calls against a pattern. behavior: "deny" blocks the write before it hits disk. behavior: "warn" appends an advisory without blocking.

Built-in safety checks

Otto ships compiled-in protections that fire regardless of configuration:

  • Sensitive files — prompts before any tool touches .env*, ~/.ssh/**, ~/.aws/**, shell rc files, or similar common secret locations.
  • Destructive Astro and Airflow commands — prompts before astro deploy, astro deployment delete, astro workspace delete, astro organization delete, astro dev kill, af dags delete, af runs delete, af tasks clear, af connections delete, af variables delete, and similar destructive commands.
  • Out-of-project writes — prompts before write, edit, or a bash command targets a path outside your project folder.

These checks are bypass-immune — they fire even when the mode is bypassPermissions or --skip-permissions is set.

Disable an individual destructive-command entry in your config by id:

1{
2 "commandPatterns": [
3 { "id": "astro-deploy", "enabled": false }
4 ]
5}

Inspect the current state

Run /permissions in an Otto session to see the current mode, rule counts, and the file paths for each config scope.

Disable permissions for a session

$astro otto --skip-permissions

This coerces the mode to bypassPermissions and prevents Ctrl+] from cycling out of it for the session. Bypass-immune safety checks still fire. Use it only for scripted flows you’re reviewing by hand.