5.2 KiB
5.2 KiB
PLAN
Context
- Target implementation is confirmed as
m3ta.pi-agent(no container mode). - You want a fresh-from-scratch rewrite of
modules/nixos/pi-agent.nixand to ignore prior behavior as design baseline. - Required behavior:
- dedicated isolated Unix user/group for Pi (
pi-agentdefaults) - 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.
- dedicated isolated Unix user/group for Pi (
- Repo findings:
modules/nixos/default.nix+flake.nixalready import/exportpi-agentmodule.modules/home-manager/coding/agents/pi.nixalready renders Pi config files under a configurable relative path (coding.agents.pi.path, default.pi/agent).
Approach
- Fully replace
modules/nixos/pi-agent.nixwith a new design centered on:- Dedicated runtime identity (
user/group/createUser/stateDir). - Policy-driven wrapper flow (
pi-> privileged runner -> isolated execution). - Per-user project allowlists (cwd must be under roots assigned to invoking host user).
- 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).
- sync user HM Pi config directory (e.g.
- Hard isolation defaults with
systemd-runsandboxing and explicit bind/read-write paths only for state + allowed projects.
- Dedicated runtime identity (
- Keep wrapper command as
pi, and avoid exposing direct package binary on PATH when wrapper mode is enabled.
Files to modify
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)
Reuse
- Module/user/service patterns:
modules/nixos/mem0.nixtemplates/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)
Steps
- Define the new
m3ta.pi-agentoption 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.
- base runtime options (
- 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-rununit as isolated user.
- Apply hardening policy in execution profile:
ProtectSystem=strict,ProtectHome=yes,NoNewPrivileges=yes,- explicit
ReadWritePathslimited 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).
Verification
- 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
- runtime identity is isolated service user (
- 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.
Open questions
- None.
Resolved decisions
- Merge precedence is confirmed as:
- synced host Pi config/env,
- Nix-managed settings/env override synced values,
- wrapper/runtime shell env does not implicitly override managed values.
- Per-user host config source defaults to
.pi/agentfor all users, with optional per-user override support in the policy map.