Keel
The execution layer under AI agents.
Agents decide what to do. Keel decides what is allowed to become real — filesystem access, subprocesses, network egress, and credentials — without trusting the model’s story about what it “needs.”
┌─────────────────────────────┐
│ Agent runtime │ Grok · Codex · Zene · custom hosts
│ (plans, tools, prompts) │
└──────────────┬──────────────┘
│ policy · spawn · SpaceFs · events
┌──────────────▼──────────────┐
│ Keel │ Policy · Enforce · Record · Lifecycle
│ Secure execution space │
└─────────────────────────────┘
Named after a ship’s keel: the structural spine underneath. The agent rides on top; Keel keeps real host access from tearing things apart.
One line: Keel is the landing gate under the agent — bind reach first, execute under policy, audit what actually happened.
What Keel does
| Capability | What you get |
|---|---|
| Policy-bound commands | spawn under a Space; configure stdin/stdout/stderr (including MCP stdio pipes). |
| Process-tree lifecycle | Timeout / cancel kills the process group (Unix) so shell grandchildren are less likely to leak; collect exit code, duration, and termination reason. |
| Policy-bound file I/O | space.fs() (preferred) — read / write / create / delete / rename / metadata + audit. check_fs is advisory UI only. |
| Baseline secret denies | Every policy (unless opted out) denies ~/.ssh, ~/.aws, **/.env, **/*.pem, … even when default_read is true. |
| Egress control | Allowlists, local CONNECT proxy, and kernel ProxyOnly on children (DenyAll → seccomp block). |
| Credentials | JIT inject at spawn; redact exec args in audit logs when needed (audit_args: false). |
| Worktree isolation | Optional git worktree or directory under ~/.keel/worktrees/. |
| Task narrowing | Child policies can only shrink parent reach — the model cannot expand its own rights. |
| Optional host confine | Space::create_confined applies Landlock/Seatbelt to this process (irreversible; Grok-style). Default keeps the host clean and sandboxes children only. |
| Audit integrity | Default hash chain (prev_hash / event_hash); SpaceFs can attach content_sha256 digests. Verify with verify_chain. |
Four pillars
| Pillar | Plain language |
|---|---|
| Policy | Up front: what may be read, written, executed, dialed, and which credentials exist (plus TTL). |
| Enforce | At runtime: soft checks and/or kernel sandboxes (Landlock / Seatbelt) map policy to boundaries. |
| Record | Ground truth: events tagged with space_id / policy_id (optional events.jsonl under ~/.keel). |
| Lifecycle | A Space: create → use → destroy. |
What Keel is not
- Not a chat UI or planning framework (not a replacement for Grok / Codex / your agent host).
- Not a full desktop app.
- Soft checks alone are not VM-grade isolation — use kernel backends when you need stronger FS/net enforcement.
SpaceFsis a soft host-side API (TOCTOU still exists); hosts should keepO_NOFOLLOWand path re-checks where they already have them.
Status
v0.0.15 on crates.io as eero-keel-* (owner EeroEternal).
Windows Job Objects + AppContainer (path grants + CreateProcess); baseline denies; SpaceFs-first; hash-chain audit; Unix Landlock/Seatbelt/seccomp as before.
See CHANGELOG.md, design, and host integration.
Install
Requires Rust 1.93+.
CLI
Library
[]
= "0.0.15"
Rust imports use short crate names (keel_core, keel_policy, …), not the crates.io package prefix:
use ;
crates.io package names
| crates.io package | Rust lib / binary | Role |
|---|---|---|
eero-keel-policy |
keel_policy |
Policy, presets, IDs, serde |
eero-keel-record |
keel_record |
Events + sinks (memory, JSONL) |
eero-keel-enforce |
keel_enforce |
Backends (null, process-guard, kernel, worktree) |
eero-keel-core |
keel_core |
Space orchestration |
eero-keel-cli |
binary keel |
CLI |
Notes:
- Plain names
keel/keel-core/keel-cli/keel-enforceare taken by unrelated crates. - Historical
keel-exec-*is not maintained from this repo. - Source directories remain
crates/keel-*; use package names withcargo -p eero-keel-cli.
Quick start
From source
Library sketch
use Arc;
use Duration;
use ;
# async
Typical host flow:
open Space (bind policy)
→ space.fs() for file tools / space.spawn() for commands
→ wait with timeout or CancellationToken
→ destroy → keep audit log if needed
Backends
| Backend | Isolation | Status |
|---|---|---|
null |
Record only; accept policy | done |
process-guard |
Soft FS / exec checks | done |
local-process |
Linux: Landlock + bwrap + seccomp · macOS: Seatbelt · Windows: Job Objects + AppContainer (path grants) · children by default | done |
local-worktree |
Git worktree or directory under ~/.keel/worktrees/ |
done |
remote-microvm |
Guest microVM | future — docs |
Windows notes: Jobs kill process trees on cancel/timeout/Drop. AppContainer profiles +
icacls grants enforce OS-level FS reach for children when windows_appcontainer is enabled
(default). Capability set is minimal (internetClient when network is not DenyAll).
# Kernel FS on children; events under ~/.keel/spaces/
# Egress allowlist (CONNECT proxy + ProxyOnly where supported)
# Worktree + credential injection
On Linux, true read-deny for nested paths often needs bubblewrap (bwrap on PATH or KEEL_BWRAP).
Policy profiles
| Profile | Read | Write | Network (policy intent) |
|---|---|---|---|
workspace |
world (default) | workspace + ~/.keel + temps |
unrestricted |
read-only |
world | ~/.keel + temps |
deny-all |
strict |
system + workspace | workspace + ~/.keel + temps |
deny-all |
Custom profiles: builder API, JSON/TOML, or sandbox.toml (~/.keel/sandbox.toml and project .keel/sandbox.toml).
Links
- Repository: github.com/EeroEternal/keel
- Design · Integration · Testing · Changelog
License
Apache-2.0