Compare commits

...

8 Commits

Author SHA1 Message Date
1692a34f6e Merge pull request 'feat: enable orchestrator + switch TTS to Edge (Katja voice)' (#8) from feature/orchestrator-edge-tts into master
Reviewed-on: #8
2026-05-01 16:15:13 +02:00
2403e54039 feat: enable orchestrator + switch TTS to Edge (Seraphina voice)
- Enable delegation.orchestrator_enabled with max_spawn_depth=2
- Switch TTS from ElevenLabs (paid) to Edge TTS (free)
- Voice: de-DE-SeraphinaMultilingualNeural — friendly, multilingual German female
- No API key required
2026-05-01 16:06:49 +02:00
m3tm3re
3e8c95944c chore: hermes update 2026-05-01 12:06:23 +02:00
fbc555feeb feat: pi guardrails 2026-04-29 20:14:07 +02:00
6a5d8f0011 feat(agents): add strict security hardening for Pi and OpenCode
Pi Guardrails:
- Enables @aliou/pi-guardrails with strict default config
- Sets onboarding.completed = true to skip onboarding prompt
- Enables pathAccess in ask mode for /nix/store and /tmp
- Adds noAccess policies for: SSH keys, GPG keys, AWS config,
  Kubernetes config, cloud CLI configs (gh/gcloud/1password/sops),
  agenix secrets, Pi auth/sessions, env files, private keys/certs
- Adds auto-deny patterns for env leakage commands:
  env, printenv, /proc/*/environ, GPG secret exports,
  ssh-add -D, password manager reads

OpenCode permissions:
- Adds permission section with global security rules
- external_directory: ask by default, allow /nix/store and /tmp
- read/edit: allow by default, deny SSH/GPG/AWS/Kube/cloud configs,
  agenix secrets, Pi auth/sessions, env files, private keys/certs
- glob: restrict sensitive path patterns
- grep: deny SSH/GPG/agenix, ask for PASSWORD/SECRET/API_KEY/PRIVATE_KEY
- bash: ask by default, allow safe git/nix commands,
  deny env/printenv/proc/GPG secret/sudo/ssh-add deletion/curl|sh
- webfetch: ask by default, allow github/nixos search
- doom_loop: ask
2026-04-29 19:48:29 +02:00
9c3d10836f Merge pull request 'fix: add uv to hermes-agent service PATH' (#7) from fix/hermes-agent-uv-path into master
Reviewed-on: #7
2026-04-29 16:24:17 +02:00
a615ab61e8 fix: add uv to hermes-agent service PATH
Add pkgs.uv to systemd.services.hermes-agent.path so that CronJobs
and terminal sessions can execute PEP 723 scripts via 'uv run'
(e.g. garmin-daily.py for Garmin Connect health data).

Also adds uv to environment.systemPackages for general availability.
2026-04-29 16:18:41 +02:00
193b8c0115 fix(git-identity): use existing gitea SSH key for agent commits
The m3ta-chiron SSH key was not accepted by Gitea.
Using the existing gitea key instead for push authentication.
2026-04-27 19:52:11 +02:00
7 changed files with 435 additions and 112 deletions

167
flake.lock generated
View File

@@ -26,11 +26,11 @@
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1777305531, "lastModified": 1777399938,
"narHash": "sha256-8GM2Aydq9i8KbvyObqyMYhWkY+e7oh3+eyMfUVnt6Oo=", "narHash": "sha256-xXPqUQezDdDtF8MbpZnwD1HkybOYwF92evx8rJ6OXCU=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "3829556188ee7a5bcdb23afa5ca5d50d6b621085", "rev": "9a91f1ee0cf011a7eaf1f16a9e17610b0457e055",
"revCount": 81, "revCount": 85,
"type": "git", "type": "git",
"url": "https://code.m3ta.dev/m3tam3re/AGENTS" "url": "https://code.m3ta.dev/m3tam3re/AGENTS"
}, },
@@ -42,11 +42,11 @@
"agents_2": { "agents_2": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1776092721, "lastModified": 1777399938,
"narHash": "sha256-avV4Snqp0K57I9s8D61+GHlg9DYZFSIvjaS4d4RYpG8=", "narHash": "sha256-xXPqUQezDdDtF8MbpZnwD1HkybOYwF92evx8rJ6OXCU=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "0ad41acb03eee0e22cba611b2171a3d3ee30cb10", "rev": "9a91f1ee0cf011a7eaf1f16a9e17610b0457e055",
"revCount": 72, "revCount": 85,
"type": "git", "type": "git",
"url": "https://code.m3ta.dev/m3tam3re/AGENTS" "url": "https://code.m3ta.dev/m3tam3re/AGENTS"
}, },
@@ -124,7 +124,6 @@
"llm-agents", "llm-agents",
"flake-parts" "flake-parts"
], ],
"import-tree": "import-tree",
"nixpkgs": [ "nixpkgs": [
"llm-agents", "llm-agents",
"nixpkgs" "nixpkgs"
@@ -139,11 +138,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1776192490, "lastModified": 1777369708,
"narHash": "sha256-5gYQNEs0/vDkHhg63aHS5g0IwG/8HNvU1Vr00cElofk=", "narHash": "sha256-1xW7cRZNsFNPQD+cE0fwnLVStnDth0HSoASEIFeT7uI=",
"owner": "nix-community", "owner": "nix-community",
"repo": "bun2nix", "repo": "bun2nix",
"rev": "6ef9f144616eedea90b364bb408ef2e1de7b310a", "rev": "e659e1cc4b8e1b21d0aa85f1c481f9db61ecfa98",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -182,11 +181,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1773889306, "lastModified": 1776613567,
"narHash": "sha256-PAqwnsBSI9SVC2QugvQ3xeYCB0otOwCacB1ueQj2tgw=", "narHash": "sha256-gC9Cp5ibBmGD5awCA9z7xy6MW6iJufhazTYJOiGlCUI=",
"owner": "nix-community", "owner": "nix-community",
"repo": "disko", "repo": "disko",
"rev": "5ad85c82cc52264f4beddc934ba57f3789f28347", "rev": "32f4236bfc141ae930b5ba2fb604f561fed5219d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -286,16 +285,16 @@
"uv2nix": "uv2nix_2" "uv2nix": "uv2nix_2"
}, },
"locked": { "locked": {
"lastModified": 1776983519, "lastModified": 1777573861,
"narHash": "sha256-cJEYjf8xV4vDw9xRBh9SHMhamj5wNjEhmMO5O3s5lag=", "narHash": "sha256-whY/1WL2fQUhPqDp7CGm3MSwOOo7FB1eADhNVnHeCRU=",
"owner": "NousResearch", "owner": "NousResearch",
"repo": "hermes-agent", "repo": "hermes-agent",
"rev": "bf196a3fc0fd1f79353369e8732051db275c6276", "rev": "73bf3ab1b22314ed9dfecbb59242c03742fe72af",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NousResearch", "owner": "NousResearch",
"ref": "v2026.4.23", "ref": "v2026.4.30",
"repo": "hermes-agent", "repo": "hermes-agent",
"type": "github" "type": "github"
} }
@@ -328,11 +327,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1775781825, "lastModified": 1777476904,
"narHash": "sha256-L5yKTpR+alrZU2XYYvIxCeCP4LBHU5jhwSj7H1VAavg=", "narHash": "sha256-EeLoE8n4+QCbteyAsYXxhfr97RFfWL1ga0xwfL6lpKw=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "e35c39fca04fee829cecdf839a50eb9b54d8a701", "rev": "8c8e5389e75a36bee53920de8ee24f017b3ae03e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -391,11 +390,11 @@
"nixpkgs": "nixpkgs_4" "nixpkgs": "nixpkgs_4"
}, },
"locked": { "locked": {
"lastModified": 1774257081, "lastModified": 1776923321,
"narHash": "sha256-92ZbaBfsEXEE7VaWJjv9aRSk3l9nyoYYyMe2AwTqSZI=", "narHash": "sha256-QowlCOrE4jGOTDCUCEx/E8gHjqSx3r25y7v4dEBpBhk=",
"owner": "Jas-SinghFSU", "owner": "Jas-SinghFSU",
"repo": "HyprPanel", "repo": "HyprPanel",
"rev": "e919b4a8a8ab5f2a0752f68576ab3eed6993cefd", "rev": "1961ba86ad5ab880beb639e5454054b2b5037e0d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -404,21 +403,6 @@
"type": "github" "type": "github"
} }
}, },
"import-tree": {
"locked": {
"lastModified": 1763762820,
"narHash": "sha256-ZvYKbFib3AEwiNMLsejb/CWs/OL/srFQ8AogkebEPF0=",
"owner": "vic",
"repo": "import-tree",
"rev": "3c23749d8013ec6daa1d7255057590e9ca726646",
"type": "github"
},
"original": {
"owner": "vic",
"repo": "import-tree",
"type": "github"
}
},
"llm-agents": { "llm-agents": {
"inputs": { "inputs": {
"blueprint": "blueprint", "blueprint": "blueprint",
@@ -429,11 +413,11 @@
"treefmt-nix": "treefmt-nix" "treefmt-nix": "treefmt-nix"
}, },
"locked": { "locked": {
"lastModified": 1777055188, "lastModified": 1777439951,
"narHash": "sha256-Cdo4+L4KTEBXCyJyZdXOjyXmnwl1m5VzHJ5uIwQTENE=", "narHash": "sha256-1Bs4ZbBayXWicrOrQQn3/BnnqhEy+tQjdFn40wHu1dw=",
"owner": "numtide", "owner": "numtide",
"repo": "llm-agents.nix", "repo": "llm-agents.nix",
"rev": "bee1f681fda054c310cd25fbc944e02a7648a0ee", "rev": "2641c18f5bb9d0b95e81beca1b0415e174d7e650",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -448,15 +432,14 @@
"basecamp": "basecamp", "basecamp": "basecamp",
"nixpkgs": "nixpkgs_6", "nixpkgs": "nixpkgs_6",
"nixpkgs-master": "nixpkgs-master", "nixpkgs-master": "nixpkgs-master",
"opencode": "opencode",
"openspec": "openspec" "openspec": "openspec"
}, },
"locked": { "locked": {
"lastModified": 1777305386, "lastModified": 1777486032,
"narHash": "sha256-crbjn8KvewFwvBKovX1r4jdmGF96XePe7U9eT9LHVFY=", "narHash": "sha256-UStORUF67vzXQ1jtORzR2cTv8GCvrxweF7HFHJgPpqw=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "95aeff28adbe251305b81584783b3e4f835670f1", "rev": "1da8c96447eb74a316861f6242421ef0309c29a8",
"revCount": 252, "revCount": 267,
"type": "git", "type": "git",
"url": "https://code.m3ta.dev/m3tam3re/nixpkgs" "url": "https://code.m3ta.dev/m3tam3re/nixpkgs"
}, },
@@ -599,11 +582,11 @@
}, },
"nixpkgs-master": { "nixpkgs-master": {
"locked": { "locked": {
"lastModified": 1775657231, "lastModified": 1777470666,
"narHash": "sha256-DP8FfybiZPp5WLB9eIk0TC2mdvuYzxLGgrBODDrwPEI=", "narHash": "sha256-uAi+pTjKLturTz3XqTwnsU0fJnqf8xx8orfPpRbdaKQ=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "4e03baaa39b7746eac5704d623461422131cd03d", "rev": "053b9fa5f0fbdac0bd9d248cea58a11223eb495d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -615,11 +598,11 @@
}, },
"nixpkgs-master_2": { "nixpkgs-master_2": {
"locked": { "locked": {
"lastModified": 1775820596, "lastModified": 1777483759,
"narHash": "sha256-DDZkqNCW97pb1WX6sDICPnDEYcnIhGMVNLyrDOA2RUQ=", "narHash": "sha256-luE+pNcTx3gz109lEC/xUxPHrx1aEZsp5X4OEBcnGaw=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "8ccce85bee20142e7d9eb7f3423c5f4fb69fa985", "rev": "b540331d6f1e343b6812b5aa1d97c707a0de0da2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -631,11 +614,11 @@
}, },
"nixpkgs-stable": { "nixpkgs-stable": {
"locked": { "locked": {
"lastModified": 1775595990, "lastModified": 1777077449,
"narHash": "sha256-OEf7YqhF9IjJFYZJyuhAypgU+VsRB5lD4DuiMws5Ltc=", "narHash": "sha256-AIiMJiqvGrN4HyLEbKAoCSRRYn0rnlW5VbKNIMIYqm4=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "4e92bbcdb030f3b4782be4751dc08e6b6cb6ccf2", "rev": "a4bf06618f0b5ee50f14ed8f0da77d34ecc19160",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -695,11 +678,11 @@
}, },
"nixpkgs_5": { "nixpkgs_5": {
"locked": { "locked": {
"lastModified": 1776329215, "lastModified": 1776949667,
"narHash": "sha256-a8BYi3mzoJ/AcJP8UldOx8emoPRLeWqALZWu4ZvjPXw=", "narHash": "sha256-GMSVw35Q+294GlrTUKlx087E31z7KurReQ1YHSKp5iw=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "b86751bc4085f48661017fa226dee99fab6c651b", "rev": "01fbdeef22b76df85ea168fbfe1bfd9e63681b30",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -711,11 +694,11 @@
}, },
"nixpkgs_6": { "nixpkgs_6": {
"locked": { "locked": {
"lastModified": 1775423009, "lastModified": 1777268161,
"narHash": "sha256-vPKLpjhIVWdDrfiUM8atW6YkIggCEKdSAlJPzzhkQlw=", "narHash": "sha256-bxrdOn8SCOv8tN4JbTF/TXq7kjo9ag4M+C8yzzIRYbE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "68d8aa3d661f0e6bd5862291b5bb263b2a6595c9", "rev": "1c3fe55ad329cbcb28471bb30f05c9827f724c76",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -743,11 +726,11 @@
}, },
"nixpkgs_8": { "nixpkgs_8": {
"locked": { "locked": {
"lastModified": 1775710090, "lastModified": 1777268161,
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=", "narHash": "sha256-bxrdOn8SCOv8tN4JbTF/TXq7kjo9ag4M+C8yzzIRYbE=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "4c1018dae018162ec878d42fec712642d214fdfa", "rev": "1c3fe55ad329cbcb28471bb30f05c9827f724c76",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -802,11 +785,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1775820600, "lastModified": 1777486007,
"narHash": "sha256-C2ffOYhqlKqKqc0KEkMQXIs6NHpM5ewEoO+o+XZCo8c=", "narHash": "sha256-5R0q8ESHux3Le76n4IuNUThkAo4o2M+Kj1Loj2J7ahI=",
"owner": "nix-community", "owner": "nix-community",
"repo": "NUR", "repo": "NUR",
"rev": "38d9344bb5323e582090d0033428a8dd7e684fde", "rev": "6f5d55cfd726ff4cd68d006bddbdf459d0dc471b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -815,28 +798,6 @@
"type": "github" "type": "github"
} }
}, },
"opencode": {
"inputs": {
"nixpkgs": [
"m3ta-nixpkgs",
"nixpkgs-master"
]
},
"locked": {
"lastModified": 1775782812,
"narHash": "sha256-m+Ue7FWiTjKMAn1QefAwOMfOb2Vybk0mJPV9zcbkOmE=",
"owner": "anomalyco",
"repo": "opencode",
"rev": "877be7e8e04142cd8fbebcb5e6c4b9617bf28cce",
"type": "github"
},
"original": {
"owner": "anomalyco",
"ref": "v1.4.3",
"repo": "opencode",
"type": "github"
}
},
"openspec": { "openspec": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -845,11 +806,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1775372219, "lastModified": 1776788052,
"narHash": "sha256-MJakKC026Sarz7nMmiFrfONWc4xgaw8ApV0Hhp4ebhM=", "narHash": "sha256-L4LBHVVtgMhSJm+IzZSYOR0UXPbvIRg4xiEV5urYxdI=",
"owner": "Fission-AI", "owner": "Fission-AI",
"repo": "OpenSpec", "repo": "OpenSpec",
"rev": "64d476f8b924bb9b74b896ea0aa784970e37da69", "rev": "3c7a05c5dc88b2397c478805890b55ed392b19e8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -996,11 +957,11 @@
"skills-anthropic": { "skills-anthropic": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1775755206, "lastModified": 1776964038,
"narHash": "sha256-H/oorOl5cch7bnziDz7gHNBv5Q0OAwFbk9w1WLku2kk=", "narHash": "sha256-xFsg66TCtKzSgRIW6Ab771FWEIhei3jPgfE4byMiB44=",
"owner": "anthropics", "owner": "anthropics",
"repo": "skills", "repo": "skills",
"rev": "12ab35c2eb5668c95810e6a6066f40f4218adc39", "rev": "5128e1865d670f5d6c9cef000e6dfc4e951fb5b9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1012,11 +973,11 @@
"skills-basecamp": { "skills-basecamp": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1775581454, "lastModified": 1777481361,
"narHash": "sha256-jDkRFNjxa+WIdpFBSPvHwGK4hbmF8bMZK5RM8ue2IGI=", "narHash": "sha256-GJ94Y1n+zR6zpOWjAGFYFWFIFpT1royFJOy2TaQXpzU=",
"owner": "basecamp", "owner": "basecamp",
"repo": "basecamp-cli", "repo": "basecamp-cli",
"rev": "5fb837c7f0d6e04c0e6c308d8b79994a49b58b2d", "rev": "59d59b66974d442190b0762129b4f1749adcedf0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1060,11 +1021,11 @@
"skills-vercel": { "skills-vercel": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1775448549, "lastModified": 1777394685,
"narHash": "sha256-P7sHiKqeThQGIOfJ1nfjiECZnhQh+U2HuLex2sg8k5E=", "narHash": "sha256-YxCMuTl+pVJ7dXhaL7l9vDw9k2orlG31j7/0pgllMJk=",
"owner": "vercel-labs", "owner": "vercel-labs",
"repo": "skills", "repo": "skills",
"rev": "df0579f85cb8a360473c921e1343359006100d3c", "rev": "7c0a9af3f8738965b71341712710ac7371089b34",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -68,7 +68,7 @@
url = "github:vercel-labs/skills"; url = "github:vercel-labs/skills";
flake = false; flake = false;
}; };
hermes-agent.url = "github:NousResearch/hermes-agent/v2026.4.23"; hermes-agent.url = "github:NousResearch/hermes-agent/v2026.4.30";
}; };
outputs = { outputs = {

View File

@@ -10,11 +10,12 @@
... ...
}: { }: {
# Agent Git Identity configuration # Agent Git Identity configuration
# Note: Uses existing gitea SSH key (m3tam3re identity) for push auth
coding.agents.gitIdentity = { coding.agents.gitIdentity = {
enable = true; enable = true;
name = "m3ta-chiron"; name = "m3ta-chiron";
email = "m3ta-chiron@agentmail.to"; email = "m3ta-chiron@agentmail.to";
sshKey = "/home/m3tam3re/.ssh/m3ta-chiron"; sshKey = "/home/m3tam3re/.ssh/gitea";
}; };
imports = [ imports = [
@@ -77,6 +78,7 @@
vulkanSupport = videoDrivers == ["amdgpu"]; vulkanSupport = videoDrivers == ["amdgpu"];
cudaSupport = videoDrivers == ["nvidia"]; cudaSupport = videoDrivers == ["nvidia"];
}) })
# opencode-desktop
openshell openshell
openspec openspec
]; ];

View File

@@ -49,6 +49,150 @@
}; };
}; };
# Security: permission hardening for OpenCode
# Last matching rule wins. Glob patterns: * = any chars, ? = single char.
# ~ and $HOME are expanded to the user's home directory.
# external_directory gates paths outside the working directory.
permission = {
# External directory access: ask by default, allow safe paths
"external_directory" = {
"*" = "ask";
"/nix/store/**" = "allow";
"/tmp/**" = "allow";
};
# Read access: allow by default, deny sensitive paths
"read" = {
"*" = "allow";
"~/.ssh/**" = "deny";
"~/.gnupg/**" = "deny";
"~/.aws/**" = "deny";
"~/.kube/**" = "deny";
"~/.config/gh/**" = "deny";
"~/.config/gcloud/**" = "deny";
"~/.config/op/**" = "deny";
"~/.config/sops/**" = "deny";
"/run/agenix/**" = "deny";
"~/.pi/agent/auth.json" = "deny";
"~/.pi/agent/sessions/**" = "deny";
"*.env" = "deny";
"*.env.*" = "deny";
"*.pem" = "deny";
"*.key" = "deny";
"*.p12" = "deny";
"*.pfx" = "deny";
"*id_rsa*" = "deny";
"*id_ed25519*" = "deny";
"*id_ecdsa*" = "deny";
"*.example.env" = "allow";
"*.sample.env" = "allow";
"*.test.env" = "allow";
".env.example" = "allow";
".env.sample" = "allow";
".env.test" = "allow";
"~/.ssh/*.pub" = "allow";
"*.pub" = "allow";
"*.csr" = "allow";
};
# Edit access: ask by default, deny sensitive paths
"edit" = {
"*" = "ask";
"~/.ssh/**" = "deny";
"~/.gnupg/**" = "deny";
"~/.aws/**" = "deny";
"~/.kube/**" = "deny";
"~/.config/gh/**" = "deny";
"~/.config/gcloud/**" = "deny";
"~/.config/op/**" = "deny";
"~/.config/sops/**" = "deny";
"/run/agenix/**" = "deny";
"~/.pi/agent/auth.json" = "deny";
"~/.pi/agent/sessions/**" = "deny";
"*.env" = "deny";
"*.env.*" = "deny";
"*.pem" = "deny";
"*.key" = "deny";
"*.p12" = "deny";
"*.pfx" = "deny";
"*id_rsa*" = "deny";
"*id_ed25519*" = "deny";
"*id_ecdsa*" = "deny";
"~/.ssh/*.pub" = "allow";
"*.pub" = "allow";
"*.csr" = "allow";
};
# Glob patterns: same rules as read for file matching
"glob" = {
"*" = "allow";
"~/.ssh/**" = "deny";
"~/.gnupg/**" = "deny";
"/run/agenix/**" = "deny";
"*.env" = "deny";
"*.env.*" = "deny";
"*.pem" = "deny";
"*.key" = "deny";
"*.p12" = "deny";
"*.pfx" = "deny";
};
# Grep: allow search, but deny searching for secrets
"grep" = {
"*" = "allow";
"~/.ssh/**" = "deny";
"~/.gnupg/**" = "deny";
"/run/agenix/**" = "deny";
"*PASSWORD*" = "ask";
"*SECRET*" = "ask";
"*API_KEY*" = "ask";
"*PRIVATE_KEY*" = "ask";
};
# Bash: ask by default, deny dangerous and env-leak commands
"bash" = {
"*" = "ask";
"git status*" = "allow";
"git diff*" = "allow";
"git log*" = "allow";
"git branch*" = "allow";
"git show*" = "allow";
"git remote*" = "allow";
"nix --version" = "allow";
"nix eval*" = "allow";
"nix build*" = "allow";
"nix develop*" = "allow";
"nix shell*" = "allow";
"nix search*" = "allow";
"alejandra*" = "allow";
"git add*" = "allow";
"git commit*" = "allow";
"git push*" = "ask";
"git pull*" = "allow";
"rm *" = "ask";
"rm -rf *" = "deny";
"sudo *" = "ask";
"env" = "deny";
"printenv" = "deny";
"cat /proc/*/environ" = "deny";
"gpg *--export-secret*" = "deny";
"ssh-add -D" = "deny";
"docker run --privileged*" = "deny";
"curl *| *sh" = "deny";
"wget *| *sh" = "deny";
};
# Web fetch: ask for sensitive URLs
"webfetch" = {
"*" = "ask";
"https://api.github.com*" = "allow";
"https://search.nixos.org*" = "allow";
};
# Doom loop guard
"doom_loop" = "ask";
};
# AZ-Gruppe LiteLLM endpoint + available models # AZ-Gruppe LiteLLM endpoint + available models
provider = { provider = {
litellm = { litellm = {

View File

@@ -54,6 +54,216 @@
defaultThinkingLevel = "high"; defaultThinkingLevel = "high";
}; };
# pi-guardrails: strict security config
# NOTE: Path access checks are lexical (not symlink-safe).
# NOTE: Local project .pi/extensions/guardrails.json can override same rule IDs.
# For immutable global policies, consider a wrapper or upstream patch.
guardrails = {
enable = true;
config = {
enabled = true;
applyBuiltinDefaults = true;
onboarding = {
completed = true;
};
features = {
policies = true;
permissionGate = true;
pathAccess = true;
};
pathAccess = {
mode = "ask";
allowedPaths = [
"/nix/store/"
"/tmp/"
];
};
policies = {
rules = [
# ── SSH keys ───────────────────────────────────────────
{
id = "home-ssh";
enabled = true;
protection = "noAccess";
onlyIfExists = false;
patterns = [
{pattern = "~/.ssh/**";}
{pattern = "~/.ssh/*_rsa";}
{pattern = "~/.ssh/*_ed25519";}
{pattern = "~/.ssh/*.pem";}
];
allowedPatterns = [
{pattern = "~/.ssh/*.pub";}
];
}
# ── GPG keys ─────────────────────────────────────────
{
id = "home-gpg";
enabled = true;
protection = "noAccess";
onlyIfExists = false;
patterns = [
{pattern = "~/.gnupg/**";}
{pattern = "~/*.gpg";}
{pattern = "~/.gpg-agent.conf";}
];
}
# ── AWS credentials ────────────────────────────────────
{
id = "home-aws";
enabled = true;
protection = "noAccess";
onlyIfExists = false;
patterns = [
{pattern = "~/.aws/**";}
{pattern = "~/.aws/credentials";}
{pattern = "~/.aws/config";}
];
}
# ── Kubernetes configs ────────────────────────────────
{
id = "home-kube";
enabled = true;
protection = "noAccess";
onlyIfExists = false;
patterns = [
{pattern = "~/.kube/**";}
{pattern = "*kubeconfig*";}
];
}
# ── Cloud CLI configs ────────────────────────────────
{
id = "home-config";
enabled = true;
protection = "noAccess";
onlyIfExists = false;
patterns = [
{pattern = "~/.config/gh/**";}
{pattern = "~/.config/gcloud/**";}
{pattern = "~/.config/op/**";}
{pattern = "~/.config/sops/**";}
];
}
# ── agenix secrets ───────────────────────────────────
{
id = "agenix-secrets";
enabled = true;
protection = "noAccess";
onlyIfExists = false;
patterns = [
{pattern = "/run/agenix/**";}
];
}
# ── Pi auth and sessions ────────────────────────────
{
id = "pi-auth-sessions";
enabled = true;
protection = "noAccess";
onlyIfExists = false;
patterns = [
{pattern = "~/.pi/agent/auth.json";}
{pattern = "~/.pi/agent/sessions/**";}
];
}
# ── Environment files ─────────────────────────────────
{
id = "secret-files";
enabled = true;
protection = "noAccess";
onlyIfExists = true;
patterns = [
{pattern = ".env";}
{pattern = ".env.*";}
{pattern = ".dev.vars";}
];
allowedPatterns = [
{pattern = "*.example.env";}
{pattern = "*.sample.env";}
{pattern = "*.test.env";}
{pattern = ".env.example";}
{pattern = ".env.sample";}
{pattern = ".env.test";}
];
}
# ── Private keys and certificates ───────────────────
{
id = "private-keys";
enabled = true;
protection = "noAccess";
onlyIfExists = false;
patterns = [
{pattern = "*.pem";}
{pattern = "*.key";}
{pattern = "*.p12";}
{pattern = "*.pfx";}
{pattern = "*id_rsa*";}
{pattern = "*id_ed25519*";}
{pattern = "*id_ecdsa*";}
];
allowedPatterns = [
{pattern = "*.pub";}
{pattern = "*.csr";}
];
}
];
};
permissionGate = {
explainCommands = false;
# Auto-deny patterns: env leakage and credential dumping
autoDenyPatterns = [
{
pattern = "\\benv\\b";
regex = true;
description = "env command (may dump environment)";
}
{
pattern = "\\bprintenv\\b";
regex = true;
description = "printenv command (dumps environment variables)";
}
{
pattern = "/proc/[0-9]+/environ";
regex = true;
description = "reading process environment files";
}
{
pattern = "gpg\\s+--export-secret-keys";
regex = true;
description = "GPG secret key export";
}
{
pattern = "gpg\\s+--export-secret-subkeys";
regex = true;
description = "GPG secret subkey export";
}
{
pattern = "ssh-add\\s+-D";
regex = true;
description = "delete all SSH identities";
}
{
pattern = "\\b(op|pass)\\s+(read|show|get)";
regex = true;
description = "password manager read operations";
}
];
};
};
};
# MCP servers auto-inherited from programs.mcp in default.nix # MCP servers auto-inherited from programs.mcp in default.nix
}; };
} }

View File

@@ -21,6 +21,7 @@
git git
tea tea
ghostty.terminfo ghostty.terminfo
uv
]; ];
services.openssh = { services.openssh = {

View File

@@ -4,8 +4,8 @@
inputs, inputs,
... ...
}: let }: let
# Default ElevenLabs voice: Bella (German-capable female) # Edge TTS: Seraphina — friendly, multilingual German female voice (free, no API key)
elevenlabsVoiceId = "hpp4J3VqNfWAUOO0d1Us"; edgeVoice = "de-DE-SeraphinaMultilingualNeural";
# Extra Python packages from the container's writable venv layer. # Extra Python packages from the container's writable venv layer.
# matrix-nio is installed via pip in /home/hermes/.venv but the hermes # matrix-nio is installed via pip in /home/hermes/.venv but the hermes
@@ -70,6 +70,10 @@ in {
''; '';
}; };
# Ensure 'uv' is in the hermes-agent service PATH so CronJobs and terminal
# sessions can use 'uv run' for PEP 723 scripts (e.g. garmin-daily.py).
systemd.services.hermes-agent.path = [pkgs.uv];
services.hermes-agent = { services.hermes-agent = {
enable = true; enable = true;
addToSystemPackages = true; addToSystemPackages = true;
@@ -176,10 +180,9 @@ in {
# ── TTS / STT / Voice ────────────────────────────────────────────── # ── TTS / STT / Voice ──────────────────────────────────────────────
tts = { tts = {
provider = "elevenlabs"; provider = "edge";
elevenlabs = { edge = {
voice_id = elevenlabsVoiceId; voice = edgeVoice;
model_id = "eleven_multilingual_v2";
}; };
}; };
@@ -205,9 +208,11 @@ in {
user_char_limit = 1375; user_char_limit = 1375;
}; };
# ── Delegation ───────────────────────────────────────────────────── # ── Delegation / Orchestrator ────────────────────────────────────────
delegation = { delegation = {
max_iterations = 50; max_iterations = 50;
orchestrator_enabled = true;
max_spawn_depth = 2;
}; };
# ── Matrix ──────────────────────────────────────────────────────── # ── Matrix ────────────────────────────────────────────────────────