AgentixOS
A safety-first control layer toward an agentic operating system on NixOS. The agent plans and proposes in a sandbox, and a person applies the change.
Version 0.3. Open source.
| Role | Year | Kind | Try it |
|---|---|---|---|
| Concept, safety design, engineering | 2026 | AI infrastructure | Source on GitHub |
| 0 | commands the agent can run as root |
| 6 | rungs on the safety ladder, each reversible until the next |
| 1 | audit line written for every run |
The problem
The long-term goal is an operating system where AI agents help configure, repair, maintain and evolve the machine, without being given unrestricted control of the live system.
It starts with NixOS because NixOS gives a strong foundation: declarative configuration, reproducible builds, changes that roll back, and clear system boundaries.
What I built
- Plan, sandbox, propose, verify. Every goal follows the same path. The agent works in a temporary Git worktree and saves its result as a proposal. The source workspace stays untouched.
- A hard stop. Agentix does not run sudo or rebuild the system. It does not edit the system configuration, commit or push. Applying, verifying and activating a change are for a person only.
- A controller for other agents. One command prints the safety contract. Another plans a goal and, if asked, runs it end to end with a full audit. Claude Code works against the same contract.
How it is structured
The safety ladder
controller-plan: describe what is allowed
controller-run (dry run): parse and validate, nothing runs
controller-run --execute: run the goal in a temporary worktree and save a proposal
Saved proposal patch: a person reviews the diff
A person applies the patch and verifies it
A person rebuilds and activates the new system
Each rung is reversible until the next. The agent stops after the third.
In the code
From Beach-Bum/Agentix, which is public.
ALLOWED_COMMANDS = [
"agentix agent-loop <goal> --path <repo> --dry-run",
"agentix agent-loop <goal> --path <repo>",
"agentix worktree-run <goal> --path <repo> --json",
"agentix worktree-run <goal> --path <repo> --save-proposal --json",
"agentix proposals list --path <repo> --json",
"agentix audit summary --path <repo> --json",
"agentix audit tail --path <repo> --json",
"agentix self-test",
]
FORBIDDEN_COMMANDS = [
"sudo",
"nixos-rebuild switch",
"rebuild-nixos",
"direct /etc/nixos mutation",
"apply without human approval",
"git push from generated system config changes",
"secret access",
"ssh private key access",
]
SAFETY_BOUNDARIES = [
"Controller may inspect and plan.",
"Controller may run sandboxed worktree goals.",
"Controller may save proposal patches.",
"Controller must leave the source workspace files untouched unless using approved proposal workflows.",
"Controller must stop before apply, rebuild, sudo, or live system activation.",
"Human reviews proposals.",
"Human runs apply-verify if approved.",
"Human runs rebuild-nixos if final activation is desired.",
]
What keeps it safe
- Source untouched, checked. Every run records the state of the workspace before and after, including a hash of every untracked file. Any unexpected change fails the run.
- A time limit. Runs stop after 1,800 seconds by default and report a timeout.
- An audit log. One line per run, appended to a log a person can review.
- Safe to publish. A check flags private material, and an export strips it.
How "source untouched" is checked
Before a run, Agentix records three things about the real workspace: the commit it is on, the full difference from that commit, and a SHA-256 hash of every file git does not track. After the run it records them again and compares. Any difference fails the run and is named in the result.
def compare_source(before: dict, after: dict, allowed_new_paths: set[str] | None = None) -> list[str]:
allowed = set(allowed_new_paths or set())
mutations: list[str] = []
if before.get("head") != after.get("head"):
mutations.append(f"head changed: {before.get('head')} -> {after.get('head')}")
if before.get("tracked_diff") != after.get("tracked_diff"):
mutations.append("tracked files changed in source workspace")
before_untracked = before.get("untracked", {}) or {}
after_untracked = after.get("untracked", {}) or {}
for rel, hash_ in sorted(after_untracked.items()):
if rel not in before_untracked:
if rel in allowed:
continue
mutations.append(f"new untracked file: {rel}")
elif before_untracked[rel] != hash_:
mutations.append(f"untracked file content changed: {rel}")
for rel in sorted(before_untracked):
if rel not in after_untracked:
mutations.append(f"untracked file removed: {rel}")
return mutationsThe audit log
Every run appends one line of JSON to .agentix/audit.jsonl in the workspace: a UTC timestamp and what happened, with the keys sorted so two logs can be compared line by line.
def audit(path: Path, event: dict) -> None:
audit_dir = path / ".agentix"
audit_dir.mkdir(exist_ok=True)
event = {
"timestamp": datetime.now(timezone.utc).isoformat(),
**event,
}
with (audit_dir / "audit.jsonl").open("a", encoding="utf-8") as f:
f.write(json.dumps(event, sort_keys=True) + "
")How it is tested
82 automated tests, run on every push together with a syntax check of every Python file. They test the refusals as much as the features: a stale patch is refused before the person is even asked, a package change is refused on a dirty tree, and the public export leaves private files out.
What it does not do
The policy check is a list of eight text patterns (sudo, rm -rf, SSH keys, /etc/nixos, and network fetches as a warning). It catches the obvious request; it is not a sandbox, and a determined command could be written to slip past it. The actual boundary is elsewhere: the agent works in a temporary copy, the real workspace is checked before and after, and only a person applies a patch or rebuilds the system.
It is about 3,900 lines of Python 3.12 at version 0.3, with no third-party dependencies: only the standard library, git and Nix. It has been used on my own machines, not at scale.
In use
λ OS, which manages the lifecycle of Logos workspace modules (snapshot, verify, self-heal, propose, govern, audit), is built on Agentix.