aiward 0.2.1

Local-first AI secret firewall for development environments.
Documentation
# Ward Implementation Map

## Product boundary

Ward protects against accidental local secret exposure in AI-assisted coding
workflows. It is not a malware sandbox, kernel isolation layer, enterprise vault,
or complete exfiltration prevention system.

The MVP succeeds when plaintext `.env` files are replaced by Ward locked
marker files, commands that need secrets run through `ward run`, and every
secret-bearing execution has an approval and audit trail. This is the passive
version: no shell hooks, no daemon, and no terminal-wide command scanning.

## Core modules

```txt
src/
  cli/          CLI parsing and command dispatch
  config/       Project-local .ward.json
  env_file/     Locked .env, manual unlock/export, and encrypted env edits
  vault/        .env.vault encryption and decryption
  registry/     ~/.ward project registry and active project selection
  policy/       Preset matching and scoped env decisions
  approvals/    Interactive and agent-mediated approval decisions
  approval_receipts/ Signed approval receipt keys, payloads, signing, and verification
  grants/       Persisted session, branch, and always approval grants
  pending_requests/ Non-interactive request storage for agent UI approval
  context/      Strict no-prompt agent worktree/branch/remote/commit verification
  agents/       Per-project agent identity records and request proof checks
  worktrees/    Trusted roots, known worktrees, and pending worktree approvals
  broker/       On-demand Unix-socket broker with in-memory unlock capability
  unlock/       Short-lived run/log unlock sessions
  runner/       Scoped env injection, child process execution, output redaction
  detection/    Preflight suspicious-pattern checks
  anomaly/      Passive grant-use anomaly alerts
  logs/         Encrypted hash-chained audit logging
  git_context/  Safe git identity and repository metadata
```

## Main functions

| Area | Function | Responsibility |
| --- | --- | --- |
| CLI | `cli::dispatch` | Route subcommands to domain modules. |
| Config | `ProjectConfig::default_for_dir` | Build initial project config. |
| Config | `default_profiles` | Generate exact-env `dev` and `migrate` profiles from known vault keys. |
| Config | `ensure_gitignore` | Keep plaintext env files ignored and optionally allow committed vaults. |
| Config | `write_project_config` | Persist `.ward.json`. |
| Vault | `encrypt_env` | Encrypt dotenv plaintext using Argon2id and AES-256-GCM. |
| Vault | `decrypt_env` | Decrypt `.env.vault` into in-memory dotenv text. |
| Vault | `import_env_file` | Read `.env`, encrypt it, and write `.env.vault`. |
| Env file | `lock_env_file` | Replace plaintext `.env` with a safe locked marker. |
| Env file | `unlock_env_file` | Write plaintext `.env` for explicit manual local development. |
| Registry | `register_project` | Add a canonical project and vault path to `~/.ward/registry.json`. |
| Registry | `resolve_project` | Resolve project by explicit name, local config, active project, or path ancestry. |
| Policy | `evaluate_request` | Match profiles/presets and decide whether approval is required. |
| Approvals | `prompt_for_approval` | Ask allow-once/session/branch/deny in the terminal. |
| Grants | `persist_grant` | Store approved session, branch, and always grants. |
| Approval receipts | `sign_payload` | Sign the canonical approved scope through broker-held signing capability. |
| Approval receipts | `verify_receipt_signature` | Reject edited, unsigned, or malformed approval grants before reuse. |
| Grants | `find_matching_grant` | Reuse only valid signed grants to skip approval prompts while still requiring unlock/PIN/passphrase. |
| Unlock | `create_run_unlock` | Store non-sensitive TTL-bound run unlock metadata. |
| Broker | `unlock_project` | Start or refresh the on-demand broker and load project unlock capability into broker memory. |
| Broker | `execute` | Ask the broker to run approved commands with scoped env injection and redacted output streaming. |
| Context | `verify_no_prompt_context` | Verify agent-provided worktree, branch, remote, commit, and canonical path before no-prompt execution. |
| Worktrees | `evaluate_worktree` | Auto-bind only trusted verified worktrees or create pending worktree approvals. |
| Agents | `ensure_agent` | Create or load per-project agent identity records. |
| Detection | `preflight_findings` | Flag suspicious requested env/command/action combinations, including critical secret-exfiltration patterns. |
| Anomaly | `detect_grant_anomalies` | Emit warning-only grant frequency, outside-hours, and branch-spread alerts. |
| Runner | `run_command` | Decrypt approved env vars, inject them, stream redacted output, and log execution. |
| Logs | `append_event` | Append encrypted hash-chained audit events under `~/.ward/logs`. |
| Git | `collect_git_context` | Collect safe git metadata for audit logs. |

## User flows

### 1. Small onboarding setup

```txt
User runs ward init
  -> create .ward.json
  -> generate dev and migrate profiles with vault-present exact env names
  -> import .env into .env.vault when present
  -> verify decrypt
  -> replace plaintext .env with locked marker by default
  -> register project
  -> update .gitignore
  -> create .env.example and agent instructions
  -> create approval key material and initial run unlock session unless --no-unlock is used
```

`ward setup --yes` runs the same recommended flow for scripts.

### 2. Import existing .env

```txt
User runs ward import .env
  -> prompt for vault PIN/passphrase
  -> parse dotenv file
  -> encrypt full env content into .env.vault
  -> replace source .env with locked marker
  -> log vault import
```

### 3. Signed approval grant

```txt
User runs ward unlock --ttl 8h
  -> decrypt vault to validate PIN/passphrase
  -> start or refresh the on-demand local broker
  -> load active project unlock capability into broker memory
  -> keep approval signing capability in broker memory
  -> write non-sensitive unlock metadata only

User approves request or runs ward allow
  -> build canonical approval receipt payload
  -> ask broker to sign payload
  -> persist grant plus receipt hash, signer key id, algorithm, and signature

Future ward run
  -> load candidate grant
  -> verify payload hash, public key signature, expiry, command hash, env subset, scope, branch, and agent
  -> ignore unsigned or modified grants
```

### 3b. Brokered no-prompt agent execution

```txt
Agent runs ward run --json --no-prompt with full context
  -> require agent, worktree, branch, git remote, commit, action, and command/profile/env data
  -> verify the claimed context with local Git and canonical paths
  -> verify or create an agent identity record
  -> evaluate worktree trust
  -> reuse only signed grants matching the verified context and agent identity
  -> contact the broker over ~/.ward/run/ward.sock
  -> broker decrypts only approved env vars in memory
  -> broker spawns the child command and streams redacted output
  -> execution logs include claimed and verified context plus broker session data
```

No-prompt flows never ask follow-up questions interactively. Missing or
mismatched context returns structured JSON and the command does not execute.

### 2b. Manual self-use

```txt
User runs ward env unlock
  -> prompt for vault PIN/passphrase
  -> decrypt .env.vault
  -> write plaintext .env with warning header and private permissions
User runs ward env lock
  -> parse current .env
  -> re-encrypt .env.vault
  -> restore locked .env marker
```

### 3. Register project for worktrees

```txt
User runs ward register my-app
  -> read .ward.json
  -> collect git remote and repo root
  -> write ~/.ward/registry.json
```

### 4. Run a command with scoped env

```txt
Agent/user runs ward run --env DATABASE_URL -- pnpm dev
  -> resolve project
  -> collect git context
  -> evaluate preset/policy
  -> run preflight detection
  -> bypass durable grants when critical findings are present
  -> prompt for approval when needed
  -> require active broker unlock session or prompt for PIN/passphrase
  -> no-prompt agent runs use broker memory instead of direct unlock file/keychain lookup
  -> write execution.started log before spawning
  -> decrypt vault in memory
  -> inject only DATABASE_URL
  -> spawn child process
  -> redact known secret values from stdout/stderr
  -> write execution.finished log
  -> write warning-only anomaly alerts if grant behavior crosses thresholds
```

When `--json --no-prompt` is used, Ward never opens an interactive prompt.
It either executes with an existing grant and active unlock, returns an
approval-required JSON payload, or returns an unlock-required JSON payload.

### 5. Request approval without execution

```txt
Agent runs ward request ...
  -> resolve project
  -> evaluate policy and detections
  -> reuse matching grant or prompt for approval
  -> persist session/branch/always grant when selected
  -> write request and approval logs
```

Profile-backed requests use the same flow, but the agent only names a profile:

```txt
Agent runs ward request --profile dev --json --no-prompt
  -> expand command/env/action from .ward.json
  -> create pending request without exposing vault contents
```

### 5b. Agent-mediated approval

```txt
Agent runs ward request --json --no-prompt ...
  -> create pending request id under ~/.ward/requests
  -> return JSON for the agent UI, including findings and critical confirmation text
User approves in agent UI
Agent records ward approve <request-id> --scope session --agent-mediated --json
  -> create scoped grant without exposing vault keys
```

Critical requests restrict the approval surface:

```txt
Agent sees confirmationRequired=true
  -> show warning title/body to the user
  -> deny by default unless the user explicitly permits the exact command
Agent records ward approve <request-id> --scope once --confirm-critical --agent-mediated --json
  -> create a one-use approval only
```

### 6. Diagnose project safety

```txt
User runs ward doctor
  -> check .ward.json
  -> check .env.vault
  -> check plaintext .env
  -> check .env.* variants except .env.example
  -> check .gitignore coverage
  -> check project registry resolution
  -> report encrypted alert count without decrypting alerts
  -> report actionable warnings
```

### 7. Teardown

```txt
User runs ward teardown --yes
  -> export plaintext dotenv from the vault to .env.export by default
  -> remove project-local Ward config and vault files
  -> unregister the project
  -> remove project-scoped grants, pending requests, and unlock sessions
  -> preserve encrypted audit logs
```

`ward teardown --yes --restore-env` is the explicit opt-in for restoring
plaintext `.env`.

## Next implementation priorities

1. Refine setup prompts beyond `--yes` for interactive users.
2. Add richer profile templates for common frameworks.
3. Keep the passive boundary explicit in generated agent instructions.