2026-04-13 21:27:09 +02:00
# PLAN
## Context
2026-04-14 18:36:13 +02:00
- Target implementation is confirmed as `m3ta.pi-agent` (no container mode).
- You want a **fresh-from-scratch rewrite ** of `modules/nixos/pi-agent.nix` and to ignore prior behavior as design baseline.
- Required behavior:
- dedicated isolated Unix user/group for Pi (`pi-agent` defaults)
- host UX stays `pi`
- bypass prevention (wrapper should be the canonical executable path)
- per-host-user project root policy (different roots per user)
- no writable/access scope beyond isolated Pi home/state + explicitly allowed project roots
- isolated environment must include user Pi config from HM (`modules/home-manager/coding/agents/pi.nix` ) and support Nix-managed settings/env merging.
- Repo findings:
- `modules/nixos/default.nix` + `flake.nix` already import/export `pi-agent` module.
- `modules/home-manager/coding/agents/pi.nix` already renders Pi config files under a configurable relative path (`coding.agents.pi.path` , default `.pi/agent` ).
2026-04-13 21:27:09 +02:00
## Approach
2026-04-14 18:36:13 +02:00
- Fully replace `modules/nixos/pi-agent.nix` with a new design centered on:
1. **Dedicated runtime identity ** (`user/group/createUser/stateDir` ).
2. **Policy-driven wrapper flow ** (`pi` -> privileged runner -> isolated execution).
3. **Per-user project allowlists ** (cwd must be under roots assigned to invoking host user).
4. **Config + env convergence ** :
- sync user HM Pi config directory (e.g. `~/.pi/agent` ) into isolated state,
- merge Nix-managed Pi settings into isolated `settings.json` ,
- merge Nix-managed env vars + env files into isolated runtime env source,
- make merged results visible to the isolated runtime every invocation (without container recreation semantics).
5. **Hard isolation defaults ** with `systemd-run` sandboxing and explicit bind/read-write paths only for state + allowed projects.
- Keep wrapper command as `pi` , and avoid exposing direct package binary on PATH when wrapper mode is enabled.
2026-04-13 21:27:09 +02:00
## Files to modify
2026-04-14 18:36:13 +02:00
- `modules/nixos/pi-agent.nix` (full rewrite)
- `modules/nixos/default.nix` (only if import list changes)
- `flake.nix` (only if output export attrs change)
- `docs/guides/pi-agent-isolation.md` (update option model + merge behavior)
- `docs/guides/using-modules.md` (update examples/options)
2026-04-13 21:27:09 +02:00
## Reuse
2026-04-14 18:36:13 +02:00
- Module/user/service patterns:
- `modules/nixos/mem0.nix`
- `templates/nixos-module/default.nix`
- Pi config rendering contract to consume/sync:
- `modules/home-manager/coding/agents/pi.nix` (`coding.agents.pi.path` , `settings.json` , `mcp.json` , agent docs)
2026-04-13 21:27:09 +02:00
## Steps
2026-04-14 18:36:13 +02:00
- [ ] Define the new `m3ta.pi-agent` option schema for fresh module behavior, including:
- base runtime options (`package` , `binaryName` , `user` , `group` , `createUser` , `stateDir` ),
- wrapper controls (`enable` , `commandName` , runner name, hide-direct-binary behavior),
- per-user policy map (allowed users and each user’ s allowed project roots),
- host-config sync knobs (source path relative/absolute),
- Nix-managed settings/env options for merge.
- [ ] Implement new wrapper script:
- identify invoking user,
- validate user exists in policy map,
- expand/resolve that user’ s roots,
- deny out-of-policy cwd,
- escalate only to the dedicated runner.
- [ ] Implement new privileged runner script:
- enforce root-only execution,
- resync host Pi config into isolated config dir,
- merge managed settings into isolated settings file,
- merge managed env + env files into isolated env file/export source,
- prepare deterministic project mount aliases under isolated home,
- launch Pi through hardened transient `systemd-run` unit as isolated user.
- [ ] Apply hardening policy in execution profile:
- `ProtectSystem=strict` , `ProtectHome=yes` , `NoNewPrivileges=yes` ,
- explicit `ReadWritePaths` limited to state + mounted allowed projects,
- bounded runtime PATH and writable tool/cache locations under `stateDir` .
- [ ] Add assertions for misconfiguration (e.g., empty per-user roots, wrapper enabled without authorized users).
- [ ] Add tightly scoped sudoers rule for runner command only.
- [ ] Ensure bypass prevention in packaging/PATH behavior when wrapper mode is enabled.
- [ ] Update docs with new option examples (per-user roots + settings/env merge + HM sync expectations).
2026-04-13 21:27:09 +02:00
## Verification
2026-04-14 18:36:13 +02:00
- Static/eval:
- `nix flake check`
- host config eval/build with new module options.
- Policy checks:
- authorized user in authorized root: succeeds
- authorized user outside authorized root: denied
- unauthorized user: denied
- Isolation checks:
- runtime identity is isolated service user (`pi-agent` )
- no unintended write access outside `stateDir` + allowed project binds
- direct binary bypass unavailable when wrapper mode is enabled
- Merge checks:
- HM-rendered Pi files are present in isolated config dir
- Nix-managed settings are merged into effective isolated `settings.json`
- env values from declarative attrs + env files are present in isolated runtime environment.
2026-04-13 21:27:09 +02:00
## Open questions
2026-04-14 18:36:13 +02:00
- None.
## Resolved decisions
- Merge precedence is confirmed as:
1) synced host Pi config/env,
2) Nix-managed settings/env override synced values,
3) wrapper/runtime shell env does not implicitly override managed values.
- Per-user host config source defaults to `.pi/agent` for all users, with optional per-user override support in the policy map.