No description
  • Nix 70.4%
  • JavaScript 21.1%
  • Shell 6.9%
  • TypeScript 1.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-11-04 05:06:48 +00:00
.claude feat: rename graft to trail-code across the module and repo 2026-10-23 12:07:50 +02:00
.forgejo/workflows feat(t3code): install the nightly channel and bump it daily 2026-10-28 13:19:03 +01:00
.trail feat: rename graft to trail-code across the module and repo 2026-10-23 12:07:50 +02:00
nix feat(t3code): 0.1.7-nightly.20261103.4106 -> 0.1.7-nightly.20261104.4151 2026-11-04 05:06:48 +00:00
providers yea 2026-10-28 17:18:34 +01:00
rules feat: add global rules and LiteLLM gateway discovery scripts 2026-10-13 19:37:37 +02:00
skills feat: rename graft to trail-code across the module and repo 2026-10-23 12:07:50 +02:00
subagents feat: rename graft to trail-code across the module and repo 2026-10-23 12:07:50 +02:00
.editorconfig feat: agent skills as a flake with a home-manager module 2026-09-19 13:49:34 +02:00
.gitattributes feat: agent skills as a flake with a home-manager module 2026-09-19 13:49:34 +02:00
.gitignore feat: rename graft to trail-code across the module and repo 2026-10-23 12:07:50 +02:00
.mcp.json feat: rename graft to trail-code across the module and repo 2026-10-23 12:07:50 +02:00
AGENTS.md feat(t3code): install the nightly channel and bump it daily 2026-10-28 13:19:03 +01:00
alejandra.toml feat: agent skills as a flake with a home-manager module 2026-09-19 13:49:34 +02:00
CLAUDE.md feat: agent skills as a flake with a home-manager module 2026-09-19 13:49:34 +02:00
flake.lock chore(flake): update flake.lock 2026-11-04 05:06:48 +00:00
flake.nix fix: pin alejandra 4.0.0 to keep tabs in indented strings 2026-10-29 11:09:45 +01:00
opencode.json feat: rename graft to trail-code across the module and repo 2026-10-23 12:07:50 +02:00
README.md feat(t3code): install the nightly channel and bump it daily 2026-10-28 13:19:03 +01:00
skills-lock.json feat: add improve-codebase-architecture skill 2026-10-13 14:27:05 +02:00
statix.toml feat: agent skills as a flake with a home-manager module 2026-09-19 13:49:34 +02:00

agent-env

My whole coding-agent setup as one flake: a Home Manager module that installs the agents (Claude Code, codex, opencode, pi, their desktop apps and T3 Code) and gives every one of them the same skills, rules, MCP servers, plugins, subagents and model gateways.

Everything sits under m4rti.agents. apps decides which agents exist; every other part is installed into whichever of those agents can take it, so turning an app off never leaves half its configuration behind.

Use it

{
  inputs.agent-env = {
    url = "git+https://git.cumsek.com/Marti/agent-env";
    inputs.nixpkgs.follows = "nixpkgs";
    inputs.home-manager.follows = "home-manager";
  };

  # ... in a Home Manager configuration:
  imports = [inputs.agent-env.homeManagerModules.default];

  m4rti.agents = {
    apps = {
      claude.code.enable = true;
      claude.desktop.enable = true;
      gpt.codex.enable = true;
      gpt.desktop.enable = true;
      opencode.cli.enable = true;
      opencode.desktop.enable = true;
      pi.enable = true;
      t3code.enable = true;
    };
    skills.enable = true;
    rules.enable = true;
    mcp.enable = true;
    plugins.enable = true;
    subagents.enable = true;

    providers.cumsek = {
      name = "Cumsek";
      url = "https://ai.cumsek.com";
      keyFile = osConfig.sops.secrets."cumsek/ai/m4rti-api-key".path;
    };
    defaultModel = {
      provider = "cumsek";
      model = "cumsek/ornith1.5:9b";
    };
  };
}

The agents come from llm-agents.nix, so a consumer needs no llm-agents input of its own. The pin does not follow nixpkgs on purpose: numtide's binary cache only hits for their nixpkgs revision, so add https://cache.numtide.com (key niks3.numtide.com-1:DTx8wZduET09hRmMtKdQDxNNthLQETkc/yaX7M4qK0g=) to your substituters. With llm-agents' overlay applied, pkgs.llm-agents is used instead. Every package option can be overridden, e.g. apps.claude.code.package = pkgs.claude-code for the nixpkgs build.

The module imports zeit's Home Manager module for plugins.zeit, so drop any import of inputs.zeit.homeModules.default of your own.

What goes where

Part Claude Code codex opencode pi
skills skills skills skills <configDir>/skills
rules rulesDir AGENTS.md AGENTS.md AGENTS.md
mcp mcpServers mcp_servers mcp mcp.json + pi-mcp-adapter
subagents agents/*.md agents/*.toml agents/*.md agents/*.md + pi-subagents
providers - - provider + discovery plugin discovery extension
plugins.ponytail plugin plugin plugin -
plugins.open-code-review /review plugin - - -
plugins.zeit turn-tracking hooks - - -
plugins.trail-code MCP server MCP server MCP server MCP server
plugins.agent-browser CLI on PATH CLI on PATH CLI on PATH CLI on PATH

The desktop apps (Claude Desktop, ChatGPT, opencode desktop) are only installed; they keep their own settings.

Options

Option Default What it does
apps.claude.code.enable false Claude Code, wrapped so hooks find node and python
apps.claude.desktop.enable false Claude Desktop
apps.gpt.codex.enable false The Codex CLI
apps.gpt.desktop.enable false The ChatGPT desktop app (ChatGPT and Codex)
apps.opencode.cli.enable false The opencode CLI
apps.opencode.desktop.enable false The opencode desktop app
apps.pi.enable false The pi coding agent
apps.t3code.enable false T3 Code from the nightly channel, with forgejo-cli as an extra provider
apps.<app>.package from llm-agents The package to install
skills.enable false The skills in skills/
skills.src skills/ The skills directory to install
rules.enable false The global rules in rules/
rules.dir rules/ The rules directory to install
mcp.enable false The MCP servers in mcp.servers
mcp.servers.<name> cumsek An MCP server; see below
plugins.enable false Every plugin below
plugins.<name>.enable plugins.enable ponytail, trail-code, open-code-review, zeit, agent-browser
subagents.enable false The subagents in subagents/
subagents.dir subagents/ The subagents directory to install
providers.<id> {} A LiteLLM gateway: name, url, keyFile
defaultModel null pi's default provider and model

Every app setting this module makes (model, theme, telemetry off, ...) is a mkDefault, so plain assignments override it.

MCP servers and secrets

A server is either local (command, args, env) or remote (url, headers). Any env or headers value can be a file instead of a literal, which is how sops-nix secrets get in without touching the store:

m4rti.agents.mcp.servers = {
  forgejo = {
    command = "forgejo-mcp";
    args = ["--url" "https://git.cumsek.com"];
    env.FORGEJO_ACCESS_TOKEN.file = osConfig.sops.secrets."cumsek/forgejo/token".path;
  };
  work = {
    url = "https://mcp.example.com/mcp";
    headers."X-Api-Key".file = osConfig.sops.secrets."work/mcp-key".path;
  };
};

Each agent reads the file at startup through whatever it supports:

Agent Local server env Remote server headers
Claude Code wrapper script headersHelper script
codex wrapper script env_http_headers, exported by a codex wrapper
opencode {file:...} {file:...}
pi !cat <file> !cat <file>

Servers follow mcp.enable unless they set enable themselves; mcp.servers.cumsek.enable = false drops the built-in one. Home Manager's programs.mcp is not used: it writes ~/.config/mcp/mcp.json, which pi's adapter also reads, with {file:...} tokens pi does not understand.

Subagents

subagents/ holds one markdown file per subagent, written once and rendered into each agent's format:

---
name: code-reviewer
description: One line the orchestrator matches against.
deny: edit, write, task
---

The system prompt.

deny takes edit, write, bash and task (spawning further subagents). Claude Code gets them as disallowedTools, opencode as tools, pi as a reduced tool allowlist, and codex as sandbox_mode = "read-only" when both edit and write are denied. mode: primary makes the agent a primary one in opencode; the others ignore it. nix flake check parses every file.

Subagent Role
tech-lead Primary agent: scopes the request and delegates to the rest
explorer Read-only recon that returns a map of files and symbols
requirements-clarifier Turns a vague ask into acceptance criteria and questions
architect Designs structural changes; writes no code
implementer Builds a decided change in the style of the code around it
test-writer Writes or fixes tests and runs them
debugger Reproduces, finds the root cause, applies the smallest fix
code-reviewer Reviews a diff for bugs, regressions and missing tests
security-auditor Reports confirmed vulnerabilities with severity and fix
docs-writer Brings README and docs in line with a change

Plugins

  • ponytail: ponytail's hooks and commands. Its Claude and codex hooks call a bare node, so the package pins them to a store Node. In codex, open /hooks once and trust its two hooks.
  • trail-code: the trail CLI (formerly graft, which still answers as graft), and trail mcp as the trail MCP server in every agent. The per-repo hooks, statusline and learnings stay with trail init. plugins.graft is a renamed alias.
  • open-code-review: the ocr CLI and its Claude Code /review and /delegate-review commands, from the same source.
  • zeit: the time tracker, with Claude Code turns tracked automatically.
  • agent-browser: the CLI, pointed at a Nix-built Chromium because the Chrome-for-Testing it downloads cannot run on NixOS. The skill that teaches it ships with skills.

Outputs

Output What it is
homeManagerModules.default / .agents The module above
packages.skills / packages.default The skills as a plain directory
packages.ponytail The ponytail plugin, hooks pinned to a store Node
checks Skill frontmatter, subagent parsing, a full module evaluation, alejandra --check, deadnix, statix
devShells.default alejandra, deadnix, statix, trail
formatter alejandra (tabs, see alejandra.toml)

Systems: x86_64-linux, aarch64-linux, aarch64-darwin.

Adding things

  • A skill: skills/<name>/SKILL.md, opening with frontmatter that has name and description. The description is the whole trigger: say what the skill covers and when to reach for it. Long material goes in files next to it, linked from SKILL.md.
  • A rule: rules/<topic>.md. Every agent loads every rule on every turn, so keep them short.
  • A subagent: subagents/<name>.md in the format above.
  • An agent: an entry in nix/module/apps.nix, a line in nix/module/lib.nix enabled if it takes skills and the rest, and a column in the tables above.

Then nix flake check.

Layout

flake.nix               outputs and checks
nix/
  module/
    default.nix         imports the parts
    lib.nix             helpers shared by the parts
    apps.nix            the agents and their settings
    skills.nix          skills/ -> every agent
    rules.nix           rules/ -> every agent
    mcp.nix             MCP servers, secrets from files
    plugins.nix         ponytail, trail-code, open-code-review, zeit, agent-browser
    subagents.nix       subagents/ -> every agent
    providers.nix       LiteLLM gateways for opencode and pi
  subagents.nix         subagent parser and per-agent renderers
  ponytail.nix          the ponytail plugin package
skills/<name>/SKILL.md  a skill
rules/<topic>.md        a global rule
subagents/<name>.md     a subagent
providers/              model discovery for the gateways

Credits

Frontend-Design comes from Anthropic's skills and keeps its own license header. agent-browser is the discovery stub shipped with the agent-browser CLI. The rest are written for this repo.