{"id":50855221,"url":"https://github.com/eunomia-bpf/ActPlane","last_synced_at":"2026-06-29T05:00:51.004Z","repository":{"id":359694824,"uuid":"1247115218","full_name":"eunomia-bpf/ActPlane","owner":"eunomia-bpf","description":"eBPF-Based Information Flow Policy Engine for AI Agent Harnesses","archived":false,"fork":false,"pushed_at":"2026-06-22T23:02:40.000Z","size":125140,"stargazers_count":50,"open_issues_count":2,"forks_count":5,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-22T23:14:17.666Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eunomia-bpf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/security_model.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":["yunwei37","Officeyutong"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2026-05-22T23:19:43.000Z","updated_at":"2026-06-22T23:02:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/eunomia-bpf/ActPlane","commit_stats":null,"previous_names":["eunomia-bpf/actplane"],"tags_count":9,"template":false,"template_full_name":"eunomia-bpf/agentsight","purl":"pkg:github/eunomia-bpf/ActPlane","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eunomia-bpf%2FActPlane","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eunomia-bpf%2FActPlane/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eunomia-bpf%2FActPlane/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eunomia-bpf%2FActPlane/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eunomia-bpf","download_url":"https://codeload.github.com/eunomia-bpf/ActPlane/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eunomia-bpf%2FActPlane/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34913586,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-14T18:00:26.484Z","updated_at":"2026-06-29T05:00:50.991Z","avatar_url":"https://github.com/eunomia-bpf.png","language":"C","funding_links":["https://github.com/sponsors/yunwei37","https://github.com/sponsors/Officeyutong"],"categories":["Harnesses \u0026 orchestration","Provenance, Instrumentation \u0026 Observability"],"sub_categories":["Agent infrastructure"],"readme":"# ActPlane: eBPF-Based IFC Policy Engine for AI Agent Harnesses\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)\n\n**Runtime `enforcement` and `observability` for AI agent harnesses and sandboxing: declare information-flow policies for safety, security and compliance, and ActPlane enforces them in the kernel with eBPF.**\n\nPrompt constraints and model guardrails are probabilistic. ActPlane is deterministic. Tool call check cannot see indirect system behavior, e.g. a sh script.\n\n**What you can express:**\n\n- **\"No `codex` may run `git push` or write outside `/src`\"**: fine-grained sandboxing rules follow process lineage, no bypass via bash scripts or python.\n- **\"Never remove the build cache in makefile unless explicitly asked or debugging\"**: bypassable with a specific argument when necessary, not just sandbox.\n- **\"When changing `specs/*`, also update the server, SDK, and docs\"**: ActPlane never blocks the edit, it notifies the agent that downstream outputs are now stale.\n- **\"Run  `make check` \u0026 `npm tests` before committing\"**: causal ordering, not just per-operation checks.\n\n\n## Quickstart\n\nInstall with one command. The eBPF program ships prebuilt (CO-RE, architecture\nindependent), so there is **no clang/llvm/libbpf to install** — just a Rust\ntoolchain:\n\n```bash\ncargo install actplane\n```\n\nWrite a policy and run an agent (or any command) under the harness:\n\n```bash\nactplane init                                  # write a starter actplane.yaml\nactplane compile                               # validate rules (no privileges)\nactplane doctor                                # diagnose hooks, MCP, kernel support\n\ncodex                                         # MCP auto-attach tries passwordless sudo\nsudo -E actplane run claude -p \"review this repo\"\n```\n\nWhen a rule matches, ActPlane kills the action and tells the agent why:\n\n```\n🚫 KILLED: process 'git' (pid 4213, ppid 4210) — /usr/bin/git\n   effect: kill\n   reason: no git under the agent; use the review workflow\n```\n\nThe agent receives this reason through its hook integration, understands the\nconstraint, and takes a different path to complete the task.\n\n**Requirements:** Linux kernel 5.8+ with BTF (`/sys/kernel/btf/vmlinux`). `run`\nand `watch` load the eBPF engine, so they need root (or `CAP_BPF` +\n`CAP_SYS_ADMIN`); ActPlane drops the target command back to your user. With\nBPF-LSM enabled, rules can `block` before the action commits; otherwise they\n`notify` (report) or `kill`.\n\n## Why an OS-level harness?\n\nAgent constraints today come in three forms. Each solves a real problem but\nleaves a gap that the next layer down needs to cover.\n\n| Approach | What it does | What it can't cover |\n|----------|-------------|---------------------|\n| **Prompt constraints** (`CLAUDE.md`, `AGENTS.md`) | Tell the agent what to do and not do | Probabilistic: long-context agents forget or route around them, often non-maliciously |\n| **Tool-layer guards** (MCP gateways, AgentSpec) | Intercept and authorize at the tool API | Bypassed the moment the agent shells out, links an SDK, or spawns a subprocess |\n| **Sandboxes** (containers, VMs, E2B, Daytona) | Isolate the entire execution environment | All-or-nothing: can't express \"file A must only be accessed via script A\" or \"run tests before committing\" |\n\nActPlane sits below all three, at the OS level. Every `exec`, file open, and\nnetwork connect goes through the kernel, so a rule like *\"nothing descended from\n`codex`, however many hops, may run `git` or modify files outside `/work`\"*\nholds regardless of which tool path the agent takes.\n\nThe key differences:\n\n- **OS-level coverage**: observation and enforcement happen at the kernel, not the tool API. Bash, Python subprocess, direct SDK calls, all covered.\n- **Call-chain granularity**: rules follow process lineage, not just single operations. \"Codex's entire subprocess tree cannot touch git\" is one rule.\n- **Data-flow constraints**: rules express \"data read from A must never flow to B\", tracked across arbitrary fork/exec and file read/write edges, not just at a boundary.\n- **Causal ordering**: rules express \"run tests before committing\" via `since` clauses and gate invalidation, not just per-operation checks.\n- **Corrective feedback, not just blocking**: rule matches feed a human-readable reason back to the agent, so it can retry a different way. This is what makes it a harness, not a sandbox.\n- **Agent-maintained rules**: the rule language is designed so agents can write, validate (`actplane check`), and evolve their own policies.\n\n## Harness, not just a sandbox\n\nA sandbox draws an isolation boundary: everything inside is allowed, everything\noutside is denied. That works for untrusted code, but agents need something\nricher — the data-flow, causal-ordering, and corrective-feedback properties\nabove are things no isolation boundary can express.\n\nSandboxes answer \"can this process access this resource?\" A harness answers a\nbroader set of questions: not just security (\"secret data must not reach the\nnetwork\") but also software engineering discipline (\"run tests before\ncommitting\", \"don't mix data from independent tasks in one commit\", \"use the\nmigration tool to access prod.db\"). These are workflow constraints, not access\ncontrol, and they are exactly the kind of rules agents need to operate\nautonomously in real codebases.\n\nA harness also subsumes sandboxing when you need it. When an agent spawns a\nsub-agent or runs an untrusted command, you can write a rule that confines the\nentire subtree to read-only, no-network, or a specific directory. This is\nespecially important when agents cross vendor boundaries: Codex calling Claude\nCode, or the other way around. Framework-level guards from different vendors\ndon't compose, but OS-level rules follow process lineage regardless of which\nruntime is underneath.\n\n## How rules work\n\nRules are **labeled information-flow policies**, not static allow-lists.\nLabels propagate along fork/exec edges and file read/write edges, so\nconstraints follow derived data across processes and files.\n\n```yaml\n# actplane.yaml\nversion: 1\npolicy: |\n  source AGENT = exec \"claude\"\n\n  # Track when protocol schema files are modified\n  source SCHEMA_CHANGED = file \"src/protocol/**/*.proto\"\n\n  rule no-git-branch:\n    kill exec \"git\" \"branch\"   if AGENT\n    kill exec \"git\" \"worktree\" if AGENT\n    because \"This workspace forbids creating git branches or worktrees. Use other git commands, or ask the user to manage branches.\"\n\n  rule regenerate-after-schema:\n    notify exec \"git\" \"commit\"\n      if SCHEMA_CHANGED unless after exec \"protoc\" since write \"src/protocol/**\"\n    because \"Protocol schema changed — generated code may be stale. Run `make proto` to regenerate, then commit.\"\n\n  rule test-before-commit:\n    block exec \"git\" \"commit\"\n      if AGENT unless after exec \"pnpm\" \"test\" since write \"src/**\"\n    because \"Source files changed since last test run. Run `pnpm test:changed`, then commit.\"\n```\n\nThree rules, three effects, three patterns:\n\n- **`no-git-branch`** (kill): per-event rule — anything in the agent's\n  process tree that tries `git branch` is terminated immediately.\n- **`regenerate-after-schema`** (notify): cross-event conditional — if\n  the agent modified a `.proto` file, ActPlane reminds it to run `protoc`\n  before committing. The `since` clause re-arms the gate whenever the\n  schema changes again.\n- **`test-before-commit`** (block): cross-event temporal with staleness —\n  the agent must run tests before committing, and editing any `src/`\n  file invalidates the previous test run.\n\nSee [`docs/rule-language.md`](docs/rule-language.md) for the full rule language and\nworked examples.\n\n## Agent integration\n\nActPlane feeds rule-match reasons back to agents via their hook systems.\n\n`actplane init --with-codex` writes a ready-to-use Codex hook at\n`.codex/hooks.json`. It runs `actplane feedback-hook` after each tool call and\ninjects any new `.actplane/last-violation.txt` content into the next model turn.\n\n**Claude Code** (`.claude/settings.local.json`):\n\n```json\n{\n  \"hooks\": {\n    \"PostToolUse\": [{ \"matcher\": \"*\", \"hooks\": [{ \"type\": \"command\", \"command\": \"actplane feedback-hook\" }] }],\n    \"PostToolUseFailure\": [{ \"matcher\": \"*\", \"hooks\": [{ \"type\": \"command\", \"command\": \"actplane feedback-hook\" }] }]\n  }\n}\n```\n\n**Codex** (`.codex/hooks.json`):\n\n```json\n{\n  \"hooks\": {\n    \"PostToolUse\": [{ \"matcher\": \".*\", \"hooks\": [{ \"type\": \"command\", \"command\": \"actplane feedback-hook\" }] }]\n  }\n}\n```\n\nThe adapter forwards new rule matches as hook context. The kernel remains the sole\nauthority for observation and enforcement. See [`script/CLAUDE.snippet.md`](script/CLAUDE.snippet.md)\nfor the agent instruction snippet.\n\nActPlane also ships an MCP server:\n\n```bash\nactplane mcp --auto-attach-parent\n```\n\nIt exposes `actplane:///policy` for live policy validation and\n`actplane:///feedback` for the latest corrective feedback. When started by Codex,\n`--auto-attach-parent` tries passwordless sudo, loads the eBPF engine, and seeds\nthe parent Codex process so directly running `codex` is protected.\n\nAttach an already-started agent with a foreground engine:\n\n```bash\nsudo -E actplane attach --pid \u003cpid\u003e\n```\n\nOnce an MCP auto-attach or `actplane watch` engine is already running, bind an\nalready-started subagent into a child runtime domain with:\n\n```bash\nactplane attach --pid \u003cpid\u003e --child-domain --domain-id \u003cdomain-id\u003e\nactplane attach --pid \u003cpid\u003e --child-domain --delta child-policy.dsl\n```\n\n`attach` is post-hoc: future events from that process tree enter ActPlane, but\nActPlane does not reconstruct labels or file/network history from before the\nattach. For strict launch-time enforcement, start the process with\n`actplane run ... -- \u003ccmd\u003e` or `actplane control launch-child ... -- \u003ccmd\u003e`.\n\n`actplane init --with-mcp` also writes project `.mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"actplane\": {\n      \"type\": \"stdio\",\n      \"command\": \"actplane\",\n      \"args\": [\"mcp\", \"--auto-attach-parent\"]\n    }\n  }\n}\n```\n\nPrefer the project `.mcp.json` that `actplane init --with-mcp` writes. If your Codex build\ndoes not read project MCP config, use a global `codex mcp add actplane -- actplane\nmcp --auto-attach-parent` entry instead, but do not keep both or auto-attach can\nstart twice.\n\n## How it works\n\n```\nactplane.yaml ─▶ policy compiler ─▶ runtime/control ─▶ eBPF kernel engine\n policy: |        parse + lower DSL   load + seed       propagate labels,\n                                      domains           match rules,\n matches ◀─────── feedback/report ◀── ring buffer ◀──── emit on match only\n```\n\n- **Kernel** (`bpf/`): hooks `fork / exec / exit / open / unlink / rename / connect`,\n  keeps a per-node label set (process / file / endpoint), propagates labels,\n  evaluates compiled rules, emits only match events.\n- **Policy compiler** (`crates/actplane-ifc-compiler/`): parses the ActPlane IFC\n  policy language and lowers it to the fixed kernel config ABI.\n- **Runtime library** (`crates/actplane-runtime/`): resolves `actplane.yaml`,\n  loads the prebuilt eBPF object in-process via\n  [`ebpf-ifc-engine`](bpf/) (aya) — no libbpf/clang at runtime — seeds the target\n  process lineage, and reports rule matches with policy reasons.\n- **CLI frontend** (`crates/actplane-cli/`): provides the `actplane` command,\n  project setup, policy review, MCP, and command dispatch.\n\n## Build from source\n\n`cargo install actplane` is all most users need. To hack on ActPlane:\n\n```bash\ngit clone --recurse-submodules https://github.com/eunomia-bpf/ActPlane\ncd ActPlane\ncargo build --release -p actplane\n```\n\nEditing the kernel eBPF (`bpf/*.bpf.c`) requires the BPF toolchain\n(clang/llvm, libelf, zlib) and the `libbpf`/`bpftool` submodules. Rebuild and\nrefresh the committed object with:\n\n```bash\nACTPLANE_REBUILD_BPF=1 cargo build -p ebpf-ifc-engine   # regenerates bpf/prebuilt/process.bpf.o\n```\n\nRun the tests:\n\n```bash\nmake test                          # bpf C unit tests + Rust workspace unit tests\nsudo bash script/e2e_examples.sh   # live E1–E12 enforcement\n```\n\n## LICENSE\n\nMIT License. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feunomia-bpf%2FActPlane","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feunomia-bpf%2FActPlane","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feunomia-bpf%2FActPlane/lists"}