Skip to main content

Learning Mode

Greywall uses a deny-by-default filesystem model: reads and writes are blocked unless explicitly allowed. Rather than manually figuring out which paths a command needs, learning mode traces the command's actual filesystem access and generates a config template automatically.

How it works

  1. Run with --learning — greywall relaxes the filesystem sandbox and uses strace to trace all file operations (openat, creat, mkdir, etc.).
  2. Use the command normally — interact with it as you would outside the sandbox. The trace captures every file read and write.
  3. Template generated on exit — greywall analyzes the trace, collapses paths into minimal directory sets, filters out system defaults and sensitive files, and saves a JSONC config template.
  4. Next run auto-loads the template — when you run the same command again (without --learning), greywall automatically loads the learned template.

Quick start

# Step 1: Run in learning mode
greywall --learning -- opencode

# Step 2: Review what was generated
greywall templates show opencode

# Step 3: Run normally — template auto-loads
greywall -- opencode

The --learning flag

greywall --learning -- <command>

This runs the command inside the sandbox with:

  • Relaxed filesystem — reads and writes are allowed so strace can observe the full access pattern.
  • strace tracing — all filesystem-related syscalls are logged.
  • Network still sandboxed — network isolation remains in effect.

When the command exits, greywall:

  1. Parses the strace log for file access patterns.
  2. Filters out system paths (already allowed by default), the current working directory (auto-included), and sensitive paths (SSH keys, .env files, etc.).
  3. Collapses paths into minimal directory sets using application directory detection (e.g., multiple files under ~/.cache/opencode/ become a single ~/.cache/opencode entry).
  4. Generates a JSONC template with allowRead, allowWrite, denyWrite, and denyRead sections.
  5. Saves it to ~/.config/greywall/learned/<command>.json.

Security note: The sandbox filesystem is relaxed during learning. Do not use --learning with untrusted code.

Managing templates

List all learned templates

greywall templates list

Output:

Learned templates (~/.config/greywall/learned):

opencode
npm
cargo

Show a template: greywall templates show <name>
Use a template: greywall --template <name> -- <command>

Show a template

greywall templates show opencode

This prints the full JSONC content of the template, including the generated comments.

Use a specific template

# Auto-load: greywall looks for a template matching the command name
greywall -- opencode

# Explicit: use a specific template regardless of command name
greywall --template opencode -- ./my-custom-editor

The --template flag takes priority over auto-detection. If the specified template doesn't exist, greywall exits with an error.

Template format

A generated template looks like this:

// Learned template for "opencode"
// Generated by: greywall --learning -- opencode
// Review and adjust paths as needed
{
"filesystem": {
"allowRead": [
"~/.cache/opencode",
"~/.config/opencode"
],
"allowWrite": [
".",
"~/.cache/opencode",
"~/.local/state/opencode"
],
"denyWrite": [
"~/.bashrc",
"~/.bash_profile",
"~/.zshrc",
"~/.profile"
],
"denyRead": [
"~/.ssh/id_*",
"~/.gnupg/**",
".env",
".env.*"
]
}
}

Key features of generated templates:

  • allowRead — paths beyond system defaults and CWD that the command accessed. Only populated when deny-by-default reads are enabled.
  • allowWrite — collapsed write paths. Always includes . (current directory). Uses tilde-relative paths for home directory entries.
  • denyWrite — shell startup files and other dangerous targets are always denied.
  • denyRead — SSH keys, GPG data, and .env files are always denied.
  • Sensitive paths (SSH keys, .env, GPG) are never included in allow lists, even if the command accessed them.

Workflow

First-time setup for a new tool

# 1. Learn what the tool needs
greywall --learning -- opencode

# 2. Review the generated template
greywall templates show opencode

# 3. Edit if needed (the file path is shown by greywall)
# e.g., remove paths you don't want to allow

# 4. Run normally from now on
greywall -- opencode

Re-learning after changes

Running --learning again overwrites the existing template for that command:

# Update the template after installing new plugins
greywall --learning -- opencode

Using templates across commands

If multiple commands need the same permissions, use --template:

# Learn from one command
greywall --learning -- code

# Apply to similar commands
greywall --template code -- cursor
greywall --template code -- windsurf

Path collapsing

Learning mode intelligently collapses file paths to avoid overly verbose templates:

  • Well-known parents — paths under ~/.cache/, ~/.config/, ~/.local/share/, ~/.local/state/, ~/.local/lib/, and ~/.data/ are grouped by application directory. For example, ~/.cache/opencode/foo and ~/.cache/opencode/bar become ~/.cache/opencode.
  • Sub-path deduplication — if ~/.cache/opencode is included, ~/.cache/opencode/subfolder is removed.
  • Home directory safety — paths directly under $HOME are never collapsed to ~/ to avoid overly broad access.

Troubleshooting

"strace: attach: ptrace: Operation not permitted"

Learning mode requires ptrace support. This may fail in:

  • Docker containers without --cap-add=SYS_PTRACE
  • Environments with restrictive kernel.yama.ptrace_scope settings

Template is too broad

Review the generated template and remove paths you don't want to allow. The template is a starting point — you can edit it directly or extend it in your main config:

{
"extends": "./learned/opencode.json",
"filesystem": {
"denyRead": ["~/sensitive-project/**"]
}
}

Learning mode hangs after command exits

This can happen if the traced command spawns long-lived child processes (LSP servers, file watchers). Greywall includes a monitor that detects when the main command exits and terminates strace, but in rare cases you may need to press Ctrl+C.

See also

  • Concepts — filesystem model and deny-by-default behavior
  • ConfigurationdefaultDenyRead, allowRead, and other filesystem fields
  • Templates — built-in config templates (different from learned templates)