# Plan: AgentFS-Backed Command Sandbox for Swival

## Objective

Enable Swival to run arbitrary shell commands while enforcing filesystem boundaries via AgentFS, so command execution can be high-autonomy without unrestricted host writes.

## Locked MVP Decisions

- Canonical integration path is **single-process re-exec** (`swival` starts once outside sandbox, then re-execs itself inside `agentfs run`).
- **No per-command sandbox wrapping** in MVP.
- `agentfs` mode is **explicit opt-in** (`--sandbox agentfs`), never auto-enabled.
- MVP enforces **write isolation**. Subprocess read restrictions remain non-strict in Phase 1.
- `--allowed-commands` remains available as **defense-in-depth** in `agentfs` mode.
- MVP runs inside AgentFS overlay semantics; Swival tools and subprocesses see the same sandbox filesystem view.

## Current State (Why This Is Needed)

- `run_command` currently executes host subprocesses directly in [`swival/tools.py`](/Users/j/src/swival/swival/tools.py) (`_run_command`, `_run_shell_command`), with no OS-level isolation.
- Swival path guards (`safe_resolve`) protect Swival's own file tools, but arbitrary subprocesses can bypass those checks.
- Existing AgentFS guidance in [`docs.md/agentfs.md`](/Users/j/src/swival/docs.md/agentfs.md) is an external wrapper workflow, not an integrated Swival sandbox mode.

## Design Goals

1. Arbitrary command execution support (equivalent to current YOLO command power).
2. Filesystem isolation at OS boundary (not just app-layer checks).
3. Clear mapping from Swival allowlists (`base_dir`, `--add-dir`, `--add-dir-ro`) to sandbox policy.
4. Persistent workspace state across agent turns.
5. Graceful fallback and explicit errors when AgentFS is unavailable.

## Non-Goals (Initial Scope)

- Replacing Swival's internal file tool sandbox.
- Full network policy redesign.
- Cross-platform strict read-deny semantics on day 1 (see "Strict Mode" phase).

## Proposed Architecture

### 1) New Sandbox Mode in Swival

Add a new execution sandbox setting:

- CLI: `--sandbox builtin|agentfs` (default: `builtin`)
- Config (`swival.toml`): `sandbox = "builtin"` or `"agentfs"`
- Optional:
  - `--sandbox-session <id>` to reuse AgentFS session state
  - `--sandbox-strict-read` (future-gated by AgentFS capability)
  - `--sandbox-allow-network` (future; default safe value)

Note: keep enum-based design even for two values; this keeps room for a future lightweight macOS-only `seatbelt` backend without flag churn.

Files to update:

- [`swival/agent.py`](/Users/j/src/swival/swival/agent.py): argparse, startup wiring, report fields
- [`swival/config.py`](/Users/j/src/swival/swival/config.py): schema/defaults/apply mapping
- [`swival/session.py`](/Users/j/src/swival/swival/session.py): programmatic API parity
- [`swival/report.py`](/Users/j/src/swival/swival/report.py): sandbox metadata in report output

### 2) Re-exec Model (Recommended)

When `--sandbox agentfs` is enabled, Swival should re-exec itself inside AgentFS before the agent loop starts.

Flow:

1. Parse args/config in outer process.
2. If `sandbox=agentfs` and not already sandboxed (`AGENTFS=1` + Swival marker env):
   - Validate `agentfs` availability (`shutil.which("agentfs")`).
   - Build AgentFS command:
     - `agentfs run`
     - `--no-default-allows`
     - `--session <id>` if provided/generated
     - `--allow <path>` for each Swival writable external root (`--add-dir`)
   - Re-exec Swival command inside AgentFS with marker env var (`SWIVAL_AGENTFS_ACTIVE=1`).
3. Inner process runs normal Swival loop.

Why re-exec:

- Keeps file tools and `run_command` seeing one consistent filesystem view.
- Preserves side-effect visibility between tool calls and shell commands.
- Avoids per-command mount/unmount complexity and state drift.

### 3) Command Policy Behavior in AgentFS Mode

In AgentFS mode, use OS sandbox as primary boundary and simplify command policy:

- Recommended default: permit YOLO command behavior for `run_command` (string + array), but only inside AgentFS.
- Keep current command timeout/output caps from [`swival/tools.py`](/Users/j/src/swival/swival/tools.py).
- Keep command execution logs/report fields unchanged, plus sandbox metadata.

Policy compatibility:

- `--allowed-commands` still works in `builtin` mode.
- In `agentfs` mode, keep `--allowed-commands` as optional defense-in-depth in MVP.

## MVP Runtime Semantics

- Swival process, file tools, and subprocess commands run in the same AgentFS sandbox view.
- Phase 1 targets write isolation and view consistency, not strict subprocess read isolation.
- Any copy-back/apply workflow for overlay changes is outside this plan's MVP scope and should be documented separately if introduced.

## Safety Interaction Matrix

| Feature | `builtin` | `agentfs` (MVP) | `agentfs` (`--sandbox-strict-read`) |
|---|---|---|---|
| `run_command` allowlist (`--allowed-commands`) | Primary control | Optional defense-in-depth | Optional defense-in-depth |
| Shell string commands | Only in YOLO | Allowed | Allowed |
| Swival file-tool `safe_resolve` checks | Enforced | Enforced | Enforced |
| Subprocess write boundary | App-layer only | OS-enforced via AgentFS sandbox | OS-enforced via AgentFS sandbox |
| Subprocess read boundary | Unrestricted | Platform-dependent (not strict) | Allowlist-only (capability-gated) |
| Read-before-write guard | Applies to file tools | Applies to file tools | Applies to file tools |
| `--add-dir` handling | Swival path checks | Swival checks + `agentfs run --allow` | Same as MVP |
| `--add-dir-ro` handling | Swival path checks | Swival file-tool enforcement only | Also enforced for subprocesses |

## Directory Access Model

### Writable

- `base_dir` becomes writable via AgentFS overlay.
- `--add-dir` paths map to `agentfs run --allow`.

### Read-only / Read scope

- `--add-dir-ro` remains enforced by Swival file tools.
- For subprocesses, strict read-deny requires extra AgentFS support on some platforms (see next phase).

## Strict Read/Write Phase (AgentFS Upstream Alignment)

Current AgentFS behavior is strong for write isolation, but strict read restriction is not uniformly enforced across platforms. Add a second phase:

1. Add AgentFS capability detection in Swival (`agentfs --version`/feature probe).
2. Use strict mode only when AgentFS supports explicit read-allow policy.
3. If `--sandbox-strict-read` is requested but unsupported, fail with `ConfigError`.

AgentFS-side work likely needed:

- Expose read-allowlist controls in `agentfs run` (or stabilized ptrace mode).
- For macOS, use explicit read allow rules instead of broad `(allow file-read*)`.
- For Linux, enforce read-deny outside allowlist (namespace-only remounting is not sufficient).

## Implementation Phases

### Phase 1: Core Integration (MVP)

1. Add sandbox config/CLI flags.
2. Implement AgentFS re-exec bootstrap module (new file, e.g. `swival/sandbox_agentfs.py`).
3. Pass through existing Swival args safely during re-exec.
4. Add report fields:
   - `sandbox_mode`
   - `sandbox_session`
   - `sandbox_backend` (agentfs/builtin)
5. Update docs:
   - [`docs.md/safety-and-sandboxing.md`](/Users/j/src/swival/docs.md/safety-and-sandboxing.md)
   - [`docs.md/usage.md`](/Users/j/src/swival/docs.md/usage.md)
   - [`docs.md/agentfs.md`](/Users/j/src/swival/docs.md/agentfs.md)

Phase 1 exit criteria:

- `--sandbox agentfs` launches one AgentFS sandboxed Swival process (no recursion, no per-command wrapping).
- Tool and command side effects are visible across turns within the same run.
- Missing/unsupported AgentFS prerequisites fail fast with actionable errors.

### Phase 2: Strict Mode + Capability Negotiation

1. Add `--sandbox-strict-read`.
2. Add AgentFS feature probing + explicit startup errors on unsupported combinations.
3. Integrate strict read policy path once AgentFS supports it.

### Phase 3: UX + Operational Hardening

1. Better diagnostics:
   - print session resume instructions in verbose mode
   - include `agentfs diff` hints in final report metadata
2. Session lifecycle controls:
   - explicit `--sandbox-session` reuse
   - optional auto-generated deterministic session IDs.
3. Optional fallback backend:
   - evaluate `--sandbox seatbelt` (macOS-only, no AgentFS dependency) as a lightweight fallback mode
   - keep this opt-in and clearly weaker than AgentFS mode for cross-platform parity

## Testing Plan

### Unit Tests (Swival)

- Config parsing:
  - new keys accepted
  - precedence CLI > project > global retained
- Bootstrap behavior:
  - no re-exec when already in AgentFS
  - correct argv generation for `agentfs run`
  - proper propagation of `--add-dir` into `--allow`

### Integration Tests

- Mock `agentfs` binary via temp script:
  - assert invocation shape and env vars.
- End-to-end (optional marker, requires AgentFS installed):
  - command can write inside `base_dir` and `--add-dir`
  - command write outside allowed roots fails
  - command output capture/truncation behavior unchanged.

### Regression Checks

- Existing `run_command` behavior unchanged in `builtin` mode.
- Existing sandbox/tool tests keep passing.

## Execution Checklist

- [ ] Finalize CLI/config surface and defaults (`builtin` remains default).
- [ ] Implement re-exec bootstrap with recursion guard.
- [ ] Thread sandbox metadata into reports.
- [ ] Add unit tests for config, argv construction, and re-exec guards.
- [ ] Add integration tests for sandbox launch and write-boundary enforcement.
- [ ] Update docs for mode selection, limitations, and expected runtime behavior.

## Risks and Mitigations

- Risk: platform differences in AgentFS read restrictions.
  - Mitigation: ship write-focused MVP, gate strict-read behind capability checks.
- Risk: recursive re-exec loops.
  - Mitigation: explicit environment marker + invariant test.
- Risk: user confusion between built-in and AgentFS modes.
  - Mitigation: startup banner and report metadata showing active sandbox mode.
- Risk: macOS `sandbox-exec` deprecation impacts AgentFS backend behavior in future macOS releases.
  - Mitigation: capability checks at startup, version-gated warnings, and keep fallback path planning (`seatbelt` backend or updated AgentFS backend) in Phase 3.

## Success Criteria

1. Swival can run arbitrary commands in `agentfs` mode without host tree mutation outside allowed roots.
2. Workspace changes from commands are visible to subsequent Swival tool calls in the same run.
3. Clear, test-covered startup behavior and failure messages when sandbox prerequisites are missing.
