feat: initial m3ta-home structure
- flake.nix with nixpkgs, home-manager, nix-colors, m3ta-nixpkgs, agenix, NUR inputs - lib/mkHome.nix: compose HM config from user + identity + context + sets - profiles/base: shell, cli-tools, secrets (always loaded) - profiles/contexts/desktop: WM, apps, theme, ghostty - profiles/contexts/server: minimal headless - profiles/sets/coding: core (git, direnv, jq, rg), editor, lsp, languages, agents - profiles/sets/gaming: steam, gamescope, gpu - profiles/sets/media: obs, ffmpeg, kdenlive, handbrake, yt-dlp - users/m3tam3re/identities: private.nix, work.nix (git, jj, ssh per identity) - users/m3tam3re/preferences: cliphist, difftastic, base packages
This commit is contained in:
85
profiles/sets/coding/agents/agents.nix
Normal file
85
profiles/sets/coding/agents/agents.nix
Normal file
@@ -0,0 +1,85 @@
|
||||
# AI agent system — OpenCode, Pi, and MCP server configuration.
|
||||
# Relies on coding.agents options provided by home/common/default.nix
|
||||
# (inputs.m3ta-nixpkgs.homeManagerModules.default).
|
||||
{
|
||||
config,
|
||||
inputs,
|
||||
lib,
|
||||
pkgs,
|
||||
videoDrivers ? [],
|
||||
...
|
||||
}: {
|
||||
# Agent Git Identity configuration
|
||||
# Note: Uses existing gitea SSH key (m3tam3re identity) for push auth
|
||||
coding.agents.gitIdentity = {
|
||||
enable = true;
|
||||
name = "m3ta-chiron";
|
||||
email = "m3ta-chiron@agentmail.to";
|
||||
sshKey = "/home/m3tam3re/.ssh/gitea";
|
||||
};
|
||||
|
||||
imports = [
|
||||
# OpenCode and Pi agent configurations
|
||||
./opencode.nix
|
||||
./pi.nix
|
||||
];
|
||||
|
||||
coding.agents.skills = {
|
||||
agentsInput = inputs.agents;
|
||||
externalSkills = [
|
||||
{
|
||||
src = inputs.skills-anthropic;
|
||||
selectSkills = ["pdf" "docx" "frontend-design"];
|
||||
}
|
||||
{src = inputs.skills-superpowers;}
|
||||
{src = inputs.skills-vercel;}
|
||||
{src = inputs.skills-basecamp;}
|
||||
{src = inputs.skills-kestra;}
|
||||
];
|
||||
};
|
||||
|
||||
programs.mcp = {
|
||||
enable = true;
|
||||
servers = {
|
||||
DeepWiki = {
|
||||
url = "https://mcp.deepwiki.com/mcp";
|
||||
};
|
||||
Ref = {
|
||||
command = "bash";
|
||||
args = ["-c" "REF_API_KEY=$(cat /run/agenix/ref-key) exec bunx ref-tools-mcp@latest"];
|
||||
};
|
||||
Exa = {
|
||||
command = "bash";
|
||||
args = ["-c" "EXA_API_KEY=$(cat /run/agenix/exa-key) exec bunx exa-mcp-server@latest tools=web_search_exa"];
|
||||
};
|
||||
Outline = {
|
||||
url = "https://wiki.az-gruppe.com/mcp";
|
||||
};
|
||||
ContextMode = {
|
||||
command = "bash";
|
||||
args = ["-c" "exec bunx context-mode@latest"];
|
||||
};
|
||||
Honcho = {
|
||||
command = "bash";
|
||||
args = [
|
||||
"-c"
|
||||
''exec bunx mcp-remote@latest https://mcp.honcho.dev --header "Authorization:Bearer $(cat /run/agenix/honcho-key)" --header "X-Honcho-User-Name:m3tam3re"''
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
home.packages = with pkgs; [
|
||||
agenix-cli
|
||||
agent-browser
|
||||
beads
|
||||
pi
|
||||
(qmd.override {
|
||||
vulkanSupport = videoDrivers == ["amdgpu"];
|
||||
cudaSupport = videoDrivers == ["nvidia"];
|
||||
})
|
||||
# opencode-desktop
|
||||
openshell
|
||||
openspec
|
||||
];
|
||||
}
|
||||
260
profiles/sets/coding/agents/opencode.nix
Normal file
260
profiles/sets/coding/agents/opencode.nix
Normal file
@@ -0,0 +1,260 @@
|
||||
{
|
||||
inputs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
coding.agents.opencode = {
|
||||
enable = true;
|
||||
agentsInput = inputs.agents;
|
||||
};
|
||||
|
||||
coding.opencode = {
|
||||
enable = true;
|
||||
|
||||
ohMyOpencodeSettings = {
|
||||
agents = {
|
||||
sisyphus.model = "litellm/claude-opus-4-6";
|
||||
oracle.model = "litellm/claude-sonnet-4-6";
|
||||
librarian.model = "litellm/claude-sonnet-4-6";
|
||||
explore.model = "litellm/claude-haiku-4-5";
|
||||
multimodal-looker.model = "litellm/gpt-5.3-codex";
|
||||
prometheus.model = "litellm/claude-opus-4-6";
|
||||
metis.model = "litellm/claude-opus-4-6";
|
||||
momus.model = "litellm/claude-opus-4-6";
|
||||
atlas.model = "litellm/claude-sonnet-4-6";
|
||||
};
|
||||
categories = {
|
||||
visual-engineering.model = "zai-coding-plan/glm-5.1";
|
||||
ultrabrain.model = "litellm/claude-opus-4-6";
|
||||
deep.model = "litellm/claude-sonnet-4-6";
|
||||
artistry.model = "zai-coding-plan/glm-5.1";
|
||||
quick.model = "litellm/claude-haiku-4-5";
|
||||
unspecified-low.model = "litellm/claude-sonnet-4-6";
|
||||
unspecified-high.model = "litellm/claude-opus-4-6";
|
||||
writing.model = "zai-coding-plan/glm-5.1";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Keep TUI settings in programs.opencode.tui to satisfy OpenCode v1.2.15+.
|
||||
programs.opencode.tui.theme = "opencode";
|
||||
|
||||
# Override legacy default settings to avoid deprecated TUI keys in settings.
|
||||
programs.opencode.settings = lib.mkForce {
|
||||
plugin = ["oh-my-openagent"];
|
||||
formatter = {
|
||||
alejandra = {
|
||||
command = ["alejandra" "-q" "-"];
|
||||
extensions = [".nix"];
|
||||
};
|
||||
};
|
||||
|
||||
# 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
|
||||
provider = {
|
||||
litellm = {
|
||||
npm = "@ai-sdk/openai-compatible";
|
||||
name = "LiteLLM (AZ-Gruppe)";
|
||||
options.baseURL = "https://llm.az-gruppe.com/v1";
|
||||
models = {
|
||||
"gpt-5.2" = {
|
||||
name = "GPT-5.2";
|
||||
limit = {
|
||||
context = 400000;
|
||||
output = 128000;
|
||||
};
|
||||
};
|
||||
"gpt-5.3-codex" = {
|
||||
name = "GPT-5.3 Codex";
|
||||
limit = {
|
||||
context = 400000;
|
||||
output = 128000;
|
||||
};
|
||||
};
|
||||
"claude-haiku-4-5" = {
|
||||
name = "Claude Haiku 4.5";
|
||||
options = {
|
||||
thinking = {
|
||||
type = "enabled";
|
||||
budget_tokens = 16000;
|
||||
};
|
||||
};
|
||||
limit = {
|
||||
context = 200000;
|
||||
output = 64000;
|
||||
};
|
||||
};
|
||||
"claude-sonnet-4-6" = {
|
||||
name = "Claude Sonnet 4.6";
|
||||
options = {
|
||||
thinking = {
|
||||
type = "enabled";
|
||||
budget_tokens = 16000;
|
||||
};
|
||||
};
|
||||
limit = {
|
||||
context = 200000;
|
||||
output = 64000;
|
||||
};
|
||||
};
|
||||
"claude-opus-4-6" = {
|
||||
name = "Claude Opus 4.6";
|
||||
options = {
|
||||
thinking = {
|
||||
type = "enabled";
|
||||
budget_tokens = 16000;
|
||||
};
|
||||
};
|
||||
limit = {
|
||||
context = 200000;
|
||||
output = 128000;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
269
profiles/sets/coding/agents/pi.nix
Normal file
269
profiles/sets/coding/agents/pi.nix
Normal file
@@ -0,0 +1,269 @@
|
||||
{inputs, ...}: {
|
||||
coding.agents.pi = {
|
||||
enable = true;
|
||||
agentsInput = inputs.agents;
|
||||
|
||||
modelOverrides = {
|
||||
chiron = "minimax/MiniMax-M2.7";
|
||||
chiron-forge = "minimax/MiniMax-M2.7";
|
||||
};
|
||||
|
||||
# Coding rules for Pi agent
|
||||
# Rules sourced from AGENTS repo
|
||||
codingRules = {
|
||||
# Language-specific rules
|
||||
languages = [
|
||||
"nix" # Nix language conventions
|
||||
];
|
||||
|
||||
# Standard concerns from AGENTS repo
|
||||
concerns = [
|
||||
"coding-style" # General coding principles
|
||||
"naming" # Naming conventions (camelCase, snake_case, etc.)
|
||||
"documentation" # Documentation standards
|
||||
"testing" # Testing guidelines (Arrange-Act-Assert)
|
||||
"git-workflow" # Conventional commits, branch naming
|
||||
"git-identity" # Git identity configuration for agents
|
||||
"project-structure" # Project layout conventions
|
||||
];
|
||||
|
||||
# No framework-specific rules for NixOS config
|
||||
frameworks = [];
|
||||
};
|
||||
|
||||
settings = {
|
||||
packages = [
|
||||
"npm:@dreadedzombie/pi-init"
|
||||
"npm:@plannotator/pi-extension"
|
||||
"npm:@thesethrose/pi-zai-provider"
|
||||
"npm:pi-agent-browser-native"
|
||||
"npm:pi-beads-extension"
|
||||
"npm:pi-lens"
|
||||
"npm:pi-markdown-preview"
|
||||
"npm:pi-mcp-adapter"
|
||||
"npm:pi-powerline-footer"
|
||||
"npm:pi-prompt-template-model"
|
||||
"npm:pi-subagents"
|
||||
"npm:pi-tool-display"
|
||||
"npm:pi-web-access"
|
||||
"git:github.com/hk-vk/pi-connect"
|
||||
];
|
||||
|
||||
defaultProvider = "minimax";
|
||||
defaultModel = "MiniMax-M2.7";
|
||||
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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user