Command Reference

Global Synopsis

inner <command> [subcommand] [flags] [-- extra-args]

inner run

Execute a command inside a sandbox defined by a profile.

inner run [flags] [-- extra-args]

Flags

FlagShortTypeDefaultDescription
--profile-pstringconfigured default (see inner config)Profile to use
--workdir-wpathprofile entrypoint.workdir, then cwdMount PATH read-write inside the sandbox (at the same path); also sets the initial working directory. Overrides entrypoint.workdir from the profile.
--networkboolprofile defaultEnable network access
--no-networkboolDisable network access
--interactive-iboolprofile defaultForce interactive mode (connect stdin/stdout directly to the sandbox)
--no-interactiveboolForce non-interactive mode
--mount-mstringAdditional mount in SRC:DEST[:MODE] format (mode: ro|rw). Repeatable.
--env-estringSet an environment variable as KEY=VAL. Repeatable.
--entrypointstringOverride the entrypoint command (resets profile args, like docker --entrypoint).
--arg-astringAppend an argument to the entrypoint command. Repeatable.
--args-filepathRead the file and append its entire content as a single entrypoint argument.
--timeoutint0Timeout in seconds (0 = no timeout)
--dry-runboolfalsePrint the resolved config and bwrap command without executing

Extra arguments

There are three ways to pass additional arguments to the entrypoint:

MethodWhen to use
-- arg1 arg2Multiple distinct arguments from the command line
--arg TEXTSingle argument; can be repeated; works well in scripts
--args-file PATHContent of a file as a single argument (e.g. an issue description)

All three methods can be combined. The order of appending is: [profile args]--arg values → -- extra-args (which includes --args-file content).

--args-file limits: files larger than 512 KB produce a warning; files larger than 2 MB are rejected. Binary files (content containing null bytes) are always rejected because they would be silently truncated by the kernel at the execve boundary.

Examples

# Start interactive shell (default profile)
inner run

# Use a specific profile
inner run -p claude-interactive

# Mount a project directory read-write
inner run -p claude-interactive -w ~/projects/myapp

# Override network for a single run
inner run --network -- curl https://example.com

# Override network off for a single run
inner run -p claude-interactive --no-network

# Mount an extra read-only directory
inner run -m ~/shared/libs:/libs:ro

# Pass environment variables
inner run -e DEBUG=true -e LOG_LEVEL=info

# Add extra arguments to the entrypoint via --
inner run -p default -- ls -la /workspace

# Send a prompt to an agent profile
inner run -p claude-one-shot -w ~/myproject --arg "write unit tests for all public functions"

# Pass a saved issue as the agent prompt
inner run -p claude-one-shot -w ~/myproject --args-file ~/issues/042-login-bug.md

# Combine profile flags with --arg and an issue file
inner run -p claude-one-shot -w ~/myproject --timeout 300 --args-file ~/issues/042-login-bug.md

# Override entrypoint: reuse a profile's sandbox config with a different binary
inner run -p claude-one-shot --entrypoint /usr/bin/gemini --arg "explain this codebase"

# Run a one-shot shell command in a sandbox
inner run -p shell-oneshot --arg "ls -la ~/project"

# Preview the resolved config and bwrap command without running
inner run -p claude-interactive --dry-run

# Use a profile from a URL (downloaded for this run only, not saved)
inner run -p https://raw.githubusercontent.com/acme/profiles/main/claude-restricted.toml

--dry-run prints the resolved profile, config file paths, effective sandbox settings, and the bwrap command that would be executed. The local config line is always shown so you can confirm whether a .inner/config.toml in the current directory is being picked up:

profile:       claude-interactive
profile path:  ~/.inner/profiles/claude-interactive.toml
global config: ~/.inner/config.toml
local config:  ~/projects/myapp/.inner/config.toml (missing)

entrypoint: /usr/bin/claude
interactive: true
network:     true
...

bwrap command:
  bwrap --ro-bind / / ...

inner profile

Manage sandbox profiles stored in ~/.inner/profiles/.

inner profile list

List all available profiles:

inner profile list

Output:

  NAME                DESCRIPTION
* shell               Bash shell, no network
  claude-interactive  Claude Code interactive, network enabled
  claude-one-shot     Claude Code non-interactive, dangerously-skip-permissions
  claude-containers   Claude Code with Podman rootless containers
  my-project          Project-specific profile  [local]
FlagShortDescription
--wide-wShow SCOPE and PATH columns; also display shadowed global profiles (marked [shadowed])

Wide output example (when a local shell profile shadows the global one):

  NAME   SCOPE   DESCRIPTION                   PATH
  shell  global  Bash shell, no network  [shadowed]  ~/.inner/profiles/shell.toml
* shell  local   Project shell variant  [local]      ~/projects/myapp/.inner/profiles/shell.toml
  claude-interactive  global  Claude Code interactive    ~/.inner/profiles/claude-interactive.toml

inner profile show

Display the TOML content of a profile:

inner profile show claude-interactive
FlagDescription
--explainAppend an explanation of each declared capability (injected mounts, pre-run actions, notes)
# Show profile content with capability details
inner profile show claude-interactive --explain

inner profile new

Create a new profile from a template, then open it in $EDITOR:

inner profile new myprofile

Creates ~/.inner/profiles/myprofile.toml.

inner profile edit

Open an existing profile in $EDITOR:

inner profile edit myprofile

inner profile validate

Validate one or all profiles for structural correctness:

# Validate a single profile
inner profile validate myprofile

# Validate all profiles
inner profile validate --all
FlagDescription
--allValidate all profiles in the profiles directory

inner profile clone

Clone a profile under a new name:

inner profile clone claude-interactive my-agent

inner profile install

Download and install a profile from an HTTP/HTTPS URL into ~/.inner/profiles/:

inner profile install URL [--name NAME] [--force]
FlagTypeDescription
--namestringOverride the profile name (default: last URL path segment, .toml stripped)
--forceboolOverwrite an existing profile with the same name
# Install under the name derived from the URL
inner profile install https://example.com/my-profile.toml

# Install under a custom name
inner profile install https://example.com/my-profile.toml --name restricted

# Overwrite an existing local profile
inner profile install https://example.com/my-profile.toml --force

The TOML is validated before being written to disk. Use inner run -p URL to try a remote profile without installing it first.


inner verify

Run security checks inside a sandbox to detect exposed sensitive resources and misconfigurations.

inner verify [flags]

How it works

inner verify is always run from the host. It:

  1. Builds a real sandbox using the given profile (same as inner run).
  2. Launches inner verify --inside inside that sandbox.
  3. The checks execute within the sandboxed environment and their output is forwarded to the terminal.

This means the checks probe what a real agent run would actually see — not the host environment.

Flags

FlagShortTypeDefaultDescription
--profile-pstringdefaultProfile to verify
--suggestboolfalsePrint TOML snippets for failed checks

What it checks

CheckSeverityDescription
user is not rootCRITICALProcess must not run as uid 0
/usr is read-onlyCRITICALBase filesystem must not be writable
git credentials not exposedCRITICAL~/.git-credentials must be absent or empty
~/.ssh not accessibleHIGHNo private key files visible in ~/.ssh/
~/.gnupg not accessibleHIGH~/.gnupg/ must be empty
no secrets in env varsHIGHNo env var names containing PASSWORD, SECRET, TOKEN, etc.
docker socket not accessibleMEDIUM/var/run/docker.sock must not be reachable
~/.netrc not accessibleMEDIUM~/.netrc must be absent or empty
shims active in PATHMEDIUMShim directory must be first in PATH
network restrictedMEDIUMTCP connection to 8.8.8.8:53 must fail

Custom checks can be added to a profile under [verify.custom] — see Profiles.

Output symbols

SymbolMeaning
[ok]Check passed
[!!]Check failed
[--]Resource explicitly allowed via [sandbox].allow — downgraded to INFO, does not count as failure

Examples

# Verify the default profile
inner verify

# Verify a specific profile
inner verify -p claude-interactive

# Show TOML snippets to fix failures
inner verify -p claude-interactive --suggest

Exit code is 1 if any check fails and is not overridden by [sandbox].allow.


inner log

Manage execution logs stored in ~/.inner/logs/ (or the path set in global config).

inner log list

Show all run logs as a table with ID, date, and size:

inner log list

inner log show

Display a log file, paginated through $PAGER (default: less):

inner log show <run-id>

inner log clean

Delete old log files:

inner log clean
FlagDefaultDescription
--older-than30Delete logs older than this many days
--dry-runfalsePreview deletions without removing files
# Preview what would be deleted (older than 7 days)
inner log clean --dry-run --older-than 7

# Actually delete logs older than 14 days
inner log clean --older-than 14

inner init

Initialize (or re-initialize) the ~/.inner directory:

inner init           # initialize ~/.inner (global, default)
inner init --local   # create .inner/ in the current directory

Global init (default)

Creates ~/.inner/ and its subdirectories, installs the built-in profiles, and writes a starter config.toml if none exists. Already-present files are never overwritten.

Example output on a fresh install:

dir: /home/alice/.inner
created dirs: /home/alice/.inner/profiles, /home/alice/.inner/logs, /home/alice/.inner/directives
config: created
profile claude-containers: installed
profile claude-interactive: installed
profile claude-one-shot: installed
profile gemini-interactive: installed
profile gemini-one-shot: installed
profile shell: installed
profile shell-containers: installed
profile shell-oneshot: installed
profile shell-with-claude: installed

Example output when everything already exists:

dir: /home/alice/.inner
config: already exists (skipped)
profile claude-containers: already exists (skipped)
profile claude-interactive: already exists (skipped)
profile claude-one-shot: already exists (skipped)
profile gemini-interactive: already exists (skipped)
profile gemini-one-shot: already exists (skipped)
profile shell: already exists (skipped)
profile shell-containers: already exists (skipped)
profile shell-oneshot: already exists (skipped)
profile shell-with-claude: already exists (skipped)

To reset to defaults (for example, to pick up updated built-in profiles after an upgrade) use inner reset.

Local init (--local)

Creates a .inner/ directory in the current directory with a starter config.toml and an empty profiles/ folder — so the directory structure is immediately visible and ready to customize:

inner init --local

Example output:

dir: /home/alice/projects/myapp
created dirs: /home/alice/projects/myapp/.inner/profiles
config: created

The created layout:

.inner/
├── config.toml   # local config template (all options commented out)
└── profiles/     # place project-specific profiles here

--local is idempotent: running it again in the same directory skips existing files.

Tip: commit .inner/ to the project repository. Team members get the directory structure and local defaults without any manual setup. To further customize, see inner config edit --local and the profiles guide.

Flags

FlagDescription
--localCreate .inner/ in the current directory instead of initializing ~/.inner

inner reset

Restore all built-in profiles to the versions embedded in the binary:

inner reset          # asks for confirmation
inner reset --force  # skips confirmation (useful in scripts)

The command overwrites every file in ~/.inner/profiles/ whose name matches a built-in profile. Files that do not match any built-in name — user-created profiles, cloned profiles under a custom name — are left completely untouched.

Use this after upgrading inner to pick up changes to the built-in profiles without losing your own customizations.

Example output:

profile claude-containers: reset
profile claude-interactive: reset
profile claude-one-shot: reset
profile gemini-interactive: reset
profile gemini-one-shot: reset
profile shell: reset
profile shell-containers: reset
profile shell-oneshot: reset
profile shell-with-claude: reset

reset complete.

What is affected

FileOutcome
Built-in profile (e.g. shell.toml)Overwritten with the embedded version
User-created profile (e.g. my-agent.toml)Left untouched
Cloned profile under a new nameLeft untouched
config.tomlLeft untouched

Preserving a customized built-in profile

If you have modified a built-in profile and want to keep your changes after a reset, clone it under a new name first:

inner profile clone shell my-shell
inner reset

my-shell.toml is not a built-in name, so it survives the reset unchanged.


inner config

Manage configuration. inner supports two levels of configuration:

LevelFileScope
Global~/.inner/config.tomlAll directories
Local.inner/config.toml (in the current directory)This directory only

Local config is merged on top of global. Fields set in the local file override the global value; unset fields fall back to global defaults.

inner config show

Print both the global and local configuration (if present):

inner config show

Example output when a local config exists:

# Global: /home/alice/.inner/config.toml
log_dir = "~/.inner/logs/"
default_profile = "shell"

# Local: /home/alice/projects/myapp/.inner/config.toml
default_profile = "claude-interactive"

When a file is absent a placeholder is shown instead of an error.

inner config edit

Open a config file in $EDITOR. By default, the global config is opened:

inner config edit           # opens ~/.inner/config.toml  (default)
inner config edit --global  # same as above (explicit)
inner config edit --local   # opens .inner/config.toml in the current directory

--local creates .inner/config.toml (and the .inner/ directory) in the current directory if they do not yet exist.

FlagDescription
--globalEdit the global config ~/.inner/config.toml (default)
--localEdit the local config .inner/config.toml in the current directory

Config options (apply to both global and local files):

KeyDefaultDescription
default_profile"default"Profile used when -p is not specified
log_dir~/.inner/logs/Directory where run logs are written
workspaces_pathHost directory where workspace mount-point directories are pre-created. Required when a profile mount uses ${workspaces_path} in its dest field. Local config overrides global.

Tip: commit .inner/config.toml to a project repository to give all contributors a consistent default profile without touching their personal ~/.inner/config.toml.


inner doctor

Check that the host environment satisfies all requirements:

inner doctor

Checks performed:


inner completion

Generate shell completion scripts. Provided automatically by Cobra.

inner completion [bash|zsh|fish|powershell]

Subcommands

SubcommandDescription
bashGenerate completion script for Bash
zshGenerate completion script for Zsh
fishGenerate completion script for Fish
powershellGenerate completion script for PowerShell

Setup

Bash:

# Load for the current session
source <(inner completion bash)

# Load permanently
inner completion bash > /etc/bash_completion.d/inner

Zsh:

# Load permanently (requires compinit)
inner completion zsh > "${fpath[1]}/_inner"

Fish:

inner completion fish > ~/.config/fish/completions/inner.fish

PowerShell:

inner completion powershell | Out-String | Invoke-Expression

inner version

Print version, build time, and git commit:

inner version

Example output:

inner v0.1.3 (built 2025-11-01T12:00:00Z, commit abc1234)