mino 1.6.0

Secure AI agent sandbox using rootless containers
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
# Mino

[![Website](https://img.shields.io/badge/Website-dean0x.github.io%2Fx%2Fmino-blue?style=for-the-badge)](https://dean0x.github.io/x/mino/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge)](https://opensource.org/licenses/MIT)
[![Rust](https://img.shields.io/badge/rust-1.82%2B-orange?style=for-the-badge)](https://www.rust-lang.org)
[![Crates.io](https://img.shields.io/crates/v/mino?style=for-the-badge)](https://crates.io/crates/mino)
[![npm](https://img.shields.io/npm/v/@dean0x/mino?style=for-the-badge)](https://www.npmjs.com/package/@dean0x/mino)
[![GitHub Release](https://img.shields.io/github/v/release/dean0x/mino?style=for-the-badge)](https://github.com/dean0x/mino/releases)
[![CI](https://img.shields.io/github/actions/workflow/status/dean0x/mino/ci.yml?style=for-the-badge&label=CI)](https://github.com/dean0x/mino/actions/workflows/ci.yml)

Secure sandbox wrapper for AI coding agents using rootless Podman containers.

Wraps **any command** in isolated containers with temporary cloud credentials and SSH agent forwarding. Works with Claude Code, Aider, Cursor, or any CLI tool.

<p align="center">
  <img src=".github/assets/demo.gif" alt="Mino terminal demo" width="800">
</p>

## Why Mino?

AI coding agents are powerful but require significant system access. Mino provides defense-in-depth:

- **Filesystem Isolation**: Agent only sees your project directory, not `~/.ssh`, `~/.aws`, or system files
- **Credential Scoping**: Short-lived cloud tokens instead of permanent credentials
- **Network Boundaries**: Four network modes — bridge (default), host, none, or allowlisted egress via iptables — with built-in presets for common services

## Features

- **Rootless Containers**: Podman containers with no root required (OrbStack VM on macOS, native on Linux)
- **Temporary Credentials**: Generates short-lived AWS/GCP/Azure tokens (1-12 hours)
- **SSH Agent Forwarding**: Git authentication without exposing private keys
- **Persistent Caching**: Content-addressed dependency caches survive session crashes
- **Multi-Session**: Run multiple isolated sandboxes in parallel
- **Network Isolation**: Bridge networking by default with interactive prompt on first run. Block all traffic, allowlist specific destinations, or use built-in presets (`dev`, `registries`)
- **Zero Config**: Works out of the box with sensible defaults

## Requirements

- **macOS**: [OrbStack]https://orbstack.dev installed (manages a lightweight Linux VM with Podman)
- **Linux**: [Podman]https://podman.io installed in rootless mode (no VM needed)
- Cloud CLIs (optional): `aws`, `gcloud`, `az`, `gh`

Run `mino setup` to check and install prerequisites for your platform.

## Installation

### npm

```bash
npm install -g @dean0x/mino
```

### Homebrew

```bash
brew install dean0x/tap/mino
```

### From Source

```bash
git clone https://github.com/dean0x/mino.git
cd mino
cargo install --path .
```

### Verify Installation

```bash
mino status
```

## Quick Start

```bash
# Interactive shell in sandbox
mino run

# Run Claude Code in sandbox
mino run -- claude

# Run with AWS credentials
mino run --aws -- bash

# Run with all cloud credentials
mino run --all-clouds -- bash

# Named session with specific project
mino run -n my-feature -p ~/projects/myapp -- zsh

# Use a different container image
mino run --image ubuntu:22.04 -- bash

# Use mino development images (with Claude Code pre-installed)
mino run --image typescript -- claude    # TypeScript/Node.js
mino run --image rust -- claude          # Rust
mino run --image python -- claude        # Python
mino run --image base -- claude          # Base tools only
```

## CLI Reference

### Global Options

These options work with all commands:

| Option | Description |
|--------|-------------|
| `-v, --verbose` | Enable verbose output |
| `-c, --config <PATH>` | Configuration file path (env: `MINO_CONFIG`) |
| `--no-local` | Skip local `.mino.toml` discovery |

### Commands

#### `mino run`

Start a sandboxed session.

```bash
mino run [OPTIONS] [-- COMMAND...]
```

| Option | Description |
|--------|-------------|
| `-n, --name <NAME>` | Session name (auto-generated if omitted) |
| `-p, --project <PATH>` | Project directory to mount (default: current dir) |
| `--image <IMAGE>` | Container image (default: fedora:43). Aliases: `typescript`/`ts`/`node`, `rust`/`cargo`, `python`/`py`, `base` |
| `--aws` | Include AWS credentials |
| `--gcp` | Include GCP credentials |
| `--azure` | Include Azure credentials |
| `--all-clouds` | Include all cloud credentials |
| `--github` | Include GitHub token (default: true) |
| `--ssh-agent` | Forward SSH agent (default: true) |
| `--layers <LAYERS>` | Composable layers (comma-separated, conflicts with `--image`) |
| `-e, --env <KEY=VALUE>` | Additional environment variable |
| `--volume <HOST:CONTAINER>` | Additional volume mount |
| `-d, --detach` | Run in background |
| `--no-cache` | Disable dependency caching |
| `--cache-fresh` | Force fresh cache (ignore existing) |
| `--network <MODE>` | Network mode: `bridge` (default), `host`, `none` |
| `--network-allow <RULES>` | Allowlisted destinations (`host:port`, comma-separated). Implies bridge + iptables |
| `--network-preset <PRESET>` | Network preset: `dev`, `registries` (conflicts with `--network-allow`) |

**Layer precedence**: `--layers` flag > `--image` flag > `MINO_LAYERS` env var > config `container.layers` > interactive selection > config `container.image`.

Set `MINO_LAYERS=rust,typescript` in your environment for non-interactive layer selection (CI, IDE plugins). When no layers or image are configured and the terminal is interactive, `mino run` prompts for layer selection with an option to save to config. Selecting "Base only" persists `image = "base"` to your config, skipping the prompt on subsequent runs.

On Unix systems, Mino automatically saves and restores terminal state when a session is interrupted (e.g., Ctrl+C during a prompt or container run), preventing shell corruption.

#### `mino exec`

Execute a command in a running session.

```bash
mino exec [SESSION] [-- COMMAND...]
```

| Option | Description |
|--------|-------------|
| `SESSION` | Session name (defaults to most recent running session) |
| `COMMAND` | Command to run (defaults to `/bin/zsh`) |

Examples:

```bash
mino exec                              # Shell into most recent session
mino exec my-session                   # Shell into named session
mino exec my-session -- ls -la         # Run command in named session
```

#### `mino list`

List sessions.

```bash
mino list [OPTIONS]
```

| Option | Description |
|--------|-------------|
| `-a, --all` | Show all sessions including stopped |
| `-f, --format <FORMAT>` | Output format: `table`, `json`, `plain` (default: table) |

#### `mino stop`

Stop a running session.

```bash
mino stop [OPTIONS] <SESSION>
```

| Option | Description |
|--------|-------------|
| `-f, --force` | Force stop without graceful shutdown |

#### `mino logs`

View session logs.

```bash
mino logs [OPTIONS] <SESSION>
```

| Option | Description |
|--------|-------------|
| `-f, --follow` | Follow log output (like `tail -f`) |
| `-l, --lines <N>` | Number of lines to show (default: 100, 0 = all) |

#### `mino status`

Check system health and dependencies.

```bash
mino status
```

#### `mino setup`

Install and configure prerequisites interactively.

```bash
mino setup [OPTIONS]
```

| Option | Description |
|--------|-------------|
| `-y, --yes` | Auto-approve all installation prompts |
| `--check` | Check prerequisites only, don't install |
| `--upgrade` | Upgrade existing dependencies to latest versions |

#### `mino init`

Initialize a project-local `.mino.toml` configuration file.

```bash
mino init [OPTIONS]
```

| Option | Description |
|--------|-------------|
| `-f, --force` | Overwrite existing `.mino.toml` |
| `-p, --path <DIR>` | Target directory (default: current directory) |

#### `mino cache`

Manage dependency caches.

```bash
mino cache <SUBCOMMAND>
```

| Subcommand | Description |
|------------|-------------|
| `list [-f FORMAT]` | List all cache volumes |
| `info [-p PATH]` | Show cache info for current/specified project |
| `gc [--days N] [--dry-run]` | Remove caches older than N days |
| `clear --volumes\|--images\|--all [-y]` | Clear cache volumes, composed images, or both |

#### `mino config`

Show or edit configuration.

```bash
mino config [SUBCOMMAND]
```

| Subcommand | Description |
|------------|-------------|
| `show` | Show current configuration (default) |
| `path` | Show configuration file path |
| `init [--force]` | Initialize default configuration |
| `set <KEY> <VALUE>` | Set a configuration value (e.g., `vm.name myvm`) |

#### `mino completions`

Generate shell completion scripts.

```bash
mino completions <SHELL>
```

Supported shells: `bash`, `zsh`, `fish`, `elvish`, `powershell`.

**Installation:**

```bash
# Bash — write to completions directory
mino completions bash > ~/.local/share/bash-completion/completions/mino

# Zsh — write to fpath directory
mino completions zsh > ${fpath[1]}/_mino

# Fish — write to completions directory
mino completions fish > ~/.config/fish/completions/mino.fish
```

Alternatively, add `eval "$(mino completions bash)"` or `eval "$(mino completions zsh)"` to your shell's rc file.

## Configuration

Configuration is stored at `~/.config/mino/config.toml`:

```toml
[general]
verbose = false
log_format = "text"    # "text" or "json"
audit_log = true       # Security events written to state dir
update_check = true    # Check for new versions (once/24h)

[vm]
name = "mino"
distro = "fedora"

[container]
image = "fedora:43"
workdir = "/workspace"
network = "bridge"
# network_preset = "dev"              # Preset allowlist: dev, registries
# network_allow = ["github.com:443"]  # Implies bridge + iptables egress filtering
# env = { "MY_VAR" = "value" }       # Additional env vars
# volumes = ["/host/path:/container/path"]
# layers = ["typescript", "rust"]     # Composable language layers

[credentials.aws]
enabled = false                      # Enable via config (equivalent to --aws)
session_duration_secs = 3600         # Token lifetime (1-12 hours)
# role_arn = "arn:aws:iam::123456789012:role/MyRole"
# external_id = "my-external-id"
# profile = "default"
# region = "us-east-1"

[credentials.gcp]
enabled = false                      # Enable via config (equivalent to --gcp)
# project = "my-project"
# service_account = "sa@project.iam.gserviceaccount.com"

[credentials.azure]
enabled = false                      # Enable via config (equivalent to --azure)
# subscription = "subscription-id"
# tenant = "tenant-id"

[credentials.github]
host = "github.com"    # For GitHub Enterprise

[session]
shell = "/bin/bash"
auto_cleanup_hours = 720             # Auto-cleanup stopped sessions (0 = disabled)
# default_project_dir = "/path/to/default/project"

[cache]
enabled = true           # Enable dependency caching
gc_days = 30             # Auto-remove caches older than N days
max_total_gb = 50        # Max total cache size before GC
```

### Configuration Keys

Use `mino config set <key> <value>` to modify:

```
general.verbose
general.log_format
general.audit_log
general.update_check
vm.name
vm.distro
container.image
container.network
container.network_preset
container.workdir
container.network_allow
credentials.aws.enabled
credentials.aws.session_duration_secs
credentials.aws.role_arn
credentials.aws.profile
credentials.aws.region
credentials.gcp.enabled
credentials.gcp.project
credentials.azure.enabled
credentials.azure.subscription
credentials.azure.tenant
session.shell
session.auto_cleanup_hours
```

## Dependency Caching

Mino automatically caches package manager dependencies using content-addressed volumes. If a session crashes, the cache persists and is reused on the next run.

### How It Works

1. **Lockfile Detection**: On `mino run`, scans for lockfiles:
   - `package-lock.json` / `npm-shrinkwrap.json` -> npm
   - `yarn.lock` -> yarn
   - `pnpm-lock.yaml` -> pnpm
   - `Cargo.lock` -> cargo
   - `requirements.txt` / `Pipfile.lock` -> pip
   - `poetry.lock` -> poetry
   - `uv.lock` -> uv
   - `go.sum` -> go

2. **Cache Key**: `sha256(lockfile_contents)[:12]` - same lockfile = same cache

3. **Cache States**:
   | State | Mount | When |
   |-------|-------|------|
   | Miss | read-write | No cache exists, creating new |
   | Building | read-write | In progress or crashed (retryable) |
   | Complete | read-write | Finalized, skip re-finalization |

4. **Environment Variables**: Automatically configured:
   ```
   npm_config_cache=/cache/npm
   CARGO_HOME=/cache/cargo
   PIP_CACHE_DIR=/cache/pip
   UV_CACHE_DIR=/cache/uv
   XDG_CACHE_HOME=/cache/xdg
   ```

### Security

- **Content-addressed**: Same lockfile = same cache volume; changing dependencies = new hash = new cache
- **Isolated**: Each unique lockfile gets its own cache volume

### Cache Management

```bash
# View caches for current project
mino cache info

# List all cache volumes
mino cache list

# Remove old caches (default: 30 days)
mino cache gc

# Remove caches older than 7 days
mino cache gc --days 7

# Clear everything
mino cache clear --all
```

## Network Isolation

Mino supports four network modes for container sessions:

### Modes

| Mode | Flag | Behavior |
|------|------|----------|
| Bridge | `--network bridge` (default) | Standard bridge networking, isolated from host localhost |
| Host | `--network host` | Full host networking, no restrictions |
| None | `--network none` | No network access at all |
| Allowlist | `--network-allow host:port,...` | Bridge + iptables egress filtering |
| Preset | `--network-preset dev\|registries` | Allowlist with built-in rules for common services |

### Examples

```bash
# Default: bridge networking (isolated from host localhost)
mino run -- bash

# No network access (air-gapped)
mino run --network none -- bash

# Allow only GitHub and npm registry
mino run --network-allow github.com:443,registry.npmjs.org:443 -- claude

# Use dev preset (GitHub, npm, crates.io, PyPI, AI APIs)
mino run --network-preset dev -- claude

# Use registries preset (package repos only, most restrictive)
mino run --network-preset registries -- bash

# Full host networking (no isolation)
mino run --network host -- bash
```

### Allowlist Mode

When using `--network-allow`, Mino:

1. Sets the container to bridge networking
2. Adds `CAP_NET_ADMIN` capability
3. Wraps your command with iptables rules that:
   - DROP all outbound traffic (IPv4 + IPv6)
   - ACCEPT loopback traffic
   - ACCEPT established/related connections
   - ACCEPT DNS (port 53, UDP + TCP)
   - ACCEPT each allowlisted host:port

### Presets

| Preset | Destinations | Use case |
|--------|-------------|----------|
| `dev` | github.com (443, 22), api.github.com, registry.npmjs.org, crates.io, static.crates.io, index.crates.io, pypi.org, files.pythonhosted.org, api.anthropic.com, api.openai.com | Dev with AI agents |
| `registries` | registry.npmjs.org, crates.io, static.crates.io, index.crates.io, pypi.org, files.pythonhosted.org | Package install only |

### Configuration

Set default network allowlist in config:

```toml
[container]
network = "bridge"                                  # default mode
# network_preset = "dev"                            # preset allowlist (conflicts with network_allow)
network_allow = ["github.com:443", "npmjs.org:443"] # implies bridge + iptables
```

Or via CLI: `mino config set container.network_allow "github.com:443,npmjs.org:443"`

### Known Limitations

- **DNS resolution at rule time**: iptables resolves hostnames to IPs when rules are inserted. CDN hosts with rotating IPs may become unreachable during long sessions.
- **iptables required**: The container image must include iptables. Fedora 43 and mino-base include it by default.
- **capsh required**: `--network-allow` and `--network-preset` modes require `capsh` (from `libcap`) in the container image to drop `CAP_NET_ADMIN` after iptables setup. The mino-base image includes it.

## Container Images

Mino uses a base image (`mino-base`) with a layer composition system for language toolchains.

| Alias | Behavior | Includes |
|-------|----------|----------|
| `typescript`, `ts`, `node` | Layer composition from `mino-base` | Node.js 22 LTS, pnpm, tsx, TypeScript, biome |
| `rust`, `cargo` | Layer composition from `mino-base` | rustup, cargo, clippy, bacon, sccache |
| `python`, `py` | Layer composition from `mino-base` | Python 3.13, uv, ruff, pytest |
| `base` | Pulls `ghcr.io/dean0x/mino-base` | Claude Code, git, delta, ripgrep, zoxide |

Language aliases trigger layer composition at runtime — the toolchain is installed on top of `mino-base` using `install.sh` scripts. Layers can be composed together with `--layers typescript,rust`.

All images include: Claude Code CLI, git, gh CLI, delta (git diff), ripgrep, fd, bat, fzf, neovim, zsh, zoxide.

See [images/README.md](images/README.md) for full tool inventory and layer architecture.

## Custom Layers

You can create custom layers to extend `mino-base` with any toolchain.

### Layer Locations

| Location | Path | Scope |
|----------|------|-------|
| Project-local | `.mino/layers/{name}/` | Current project only |
| User-global | `~/.config/mino/layers/{name}/` | All projects |
| Built-in | Bundled with mino | All projects |

**Resolution order**: project-local > user-global > built-in (first match wins). This lets you override built-in layers per-project or per-user.

### Creating a Layer

Each layer needs two files: `layer.toml` (metadata) and `install.sh` (setup script).

**`layer.toml`** — declares environment variables, PATH extensions, and cache paths:

```toml
[layer]
name = "go"
description = "Go toolchain + tools"
version = "1"

[env]
GOPATH = "/cache/go"
GOMODCACHE = "/cache/go/mod"
GOCACHE = "/cache/go/build"

[env.path_prepend]
dirs = ["/usr/local/go/bin", "/cache/go/bin"]

[cache]
paths = ["/cache/go"]
```

**`install.sh`** — runs as root on `mino-base`. Must be idempotent (safe to re-run):

```bash
#!/usr/bin/env bash
set -euo pipefail

# Install Go (idempotent)
if ! command -v go &>/dev/null; then
    curl -LsSf https://go.dev/dl/go1.24.1.linux-amd64.tar.gz | tar -C /usr/local -xzf -
fi

# Install tools
export GOPATH=/opt/go-tools
export PATH="/usr/local/go/bin:${GOPATH}/bin:${PATH}"
go install golang.org/x/tools/gopls@latest
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

# Fix permissions
chown -R developer:developer /opt/go-tools
chmod -R a+rX /opt/go-tools

# Verify
go version
gopls version
```

### Using Custom Layers

```bash
# Use by name (resolved from layer locations)
mino run --layers go

# Compose multiple layers
mino run --layers go,rust

# Set via environment for CI
export MINO_LAYERS=go
mino run -- go test ./...
```

### Overriding Built-in Layers

To customize a built-in layer, create a layer with the same name in your project or user config directory. Your version takes precedence:

```
.mino/layers/typescript/layer.toml    # overrides built-in typescript
.mino/layers/typescript/install.sh
```

## Architecture

### macOS (via OrbStack)

```
macOS Host
    |
    +- mino CLI (Rust binary)
    |   - Validates environment (OrbStack, Podman)
    |   - Generates temp credentials (STS, gcloud, az)
    |   - Manages session lifecycle
    |
    +-> OrbStack VM (lightweight Linux, ~200MB)
        |
        +-> Podman rootless container
            - Mounted: /workspace (project dir only)
            - SSH agent socket forwarded
            - Temp credentials as env vars
            - NO access to: ~/.ssh, ~/, system dirs
```

### Linux (native Podman)

```
Linux Host
    |
    +- mino CLI (Rust binary)
    |   - Validates environment (rootless Podman)
    |   - Generates temp credentials (STS, gcloud, az)
    |   - Manages session lifecycle
    |
    +-> Podman rootless container (no VM layer)
        - Mounted: /workspace (project dir only)
        - SSH agent socket forwarded
        - Temp credentials as env vars
        - NO access to: ~/.ssh, ~/, system dirs
```

## Credential Strategy

| Service | Method | Lifetime |
|---------|--------|----------|
| SSH/Git | Agent forwarding via socket | Session |
| GitHub | `gh auth token` | Existing token |
| AWS | STS GetSessionToken/AssumeRole | 1-12 hours |
| GCP | `gcloud auth print-access-token` | 1 hour |
| Azure | `az account get-access-token` | 1 hour |

Credentials are cached with TTL awareness - Mino automatically refreshes expired tokens.

## State Storage

```
~/.config/mino/config.toml           # User configuration

# State directory (platform-specific):
#   Linux:  ~/.local/state/mino/
#   macOS:  ~/Library/Application Support/mino/
<state_dir>/mino/
+-- sessions/*.json                  # Session state
+-- credentials/*.json               # Cached credentials (0o700 dir, 0o600 files)
+-- audit.log                        # Security audit log
```

## Security Considerations

Mino provides defense-in-depth but is not a complete security solution:

- **Container Hardening**: All containers run with `--cap-drop ALL`, `--security-opt no-new-privileges`, and `--pids-limit 4096` by default
- **Trust Boundary**: The container can access anything mounted into it
- **Network Access**: Default `bridge` mode isolates containers from host localhost. Use `--network none` for air-gapped sessions, `--network-allow` or `--network-preset` for fine-grained egress control
- **Credential Scope**: Temporary credentials still have the permissions of the source identity
- **OrbStack Trust**: You're trusting OrbStack's VM isolation
- **Container Cleanup**: All sessions (interactive and detached) remove containers after exit to prevent credential persistence via `podman inspect`

For maximum security:
1. Use dedicated cloud roles with minimal permissions
2. Use named sessions to track activity
3. Use `--network none` or `--network-allow` for network-restricted sessions
4. Use `--network-preset registries` to limit egress to package registries only

## Audit Log

Mino writes security events to `<state_dir>/mino/audit.log` in JSON Lines format. Enabled by default; disable with `general.audit_log = false` in config.

Each line is a JSON object:
```json
{"timestamp":"2026-03-09T12:00:00Z","event":"session.created","data":{...}}
```

### Events

| Event | When | Data fields |
|-------|------|-------------|
| `session.created` | Session state initialized | `name`, `project_dir`, `image`, `command` |
| `credentials.injected` | Cloud credentials passed to container | `session_name`, `providers` |
| `session.started` | Container running | `name`, `container_id` |
| `session.stopped` | Container exited | `name`, `exit_code` |
| `session.failed` | Container failed to start | `name`, `error` |

Audit logging uses silent failure mode — IO errors are logged via `tracing::warn` but never block or crash the primary workflow.

## Development

```bash
# Build debug
cargo build

# Build release
cargo build --release

# Run tests
cargo test

# Run with debug logging
RUST_LOG=mino=debug cargo run -- status

# Format code
cargo fmt

# Lint
cargo clippy
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Acknowledgments

- [OrbStack]https://orbstack.dev - Fast, lightweight macOS virtualization
- [Podman]https://podman.io - Daemonless container engine