~ruther/agent-environments

354e163ede61c66d8f2034329c3bf85601c6abc1 — František Boháček 2 months ago 275d156
Add README
1 files changed, 101 insertions(+), 0 deletions(-)

A README.md
A README.md => README.md +101 -0
@@ 0,0 1,101 @@
# agent-environments

A Nix flake library for declaring environments for coding agents
([Claude Code](https://github.com/sadjow/claude-code-nix) and
[Codex](https://github.com/sadjow/codex-cli-nix)) as modules, and for launching
them under separate logins.

An **environment** is a set of modules: instructions (`CLAUDE.md` / `AGENTS.md`),
skills, and agent settings. A **launcher** is a command that starts one agent in
one environment, with its own state directory
`~/.local/agent-environments/<id>` (passed as `CLAUDE_CONFIG_DIR` /
`CODEX_HOME`). Different ids mean different logins, so `claude-work-acc` and
`claude-pers-acc` can share one environment but keep separate credentials.

## Use

```nix
{
  inputs.agent-environments.url = "github:<owner>/agent-environments";
  inputs.nixpkgs.follows = "agent-environments/nixpkgs";

  outputs = { agent-environments, nixpkgs, ... }:
    let
      pkgs = nixpkgs.legacyPackages.x86_64-linux;
      inherit (agent-environments.lib) mkEnvironment mkSkill mkSkillModule;
      my-skill = mkSkill {
        inherit pkgs;
        name = "my-skill";
        src = ./skills/my-skill;          # a directory containing SKILL.md
        runtimeInputs = [ pkgs.jq ];      # put on PATH for the agent
        skills = [ ];                     # other mkSkill packages it needs
      };
    in {
      packages.x86_64-linux.default = (mkEnvironment {
        inherit pkgs;
        modules = [
          (mkSkillModule my-skill)        # declares modules.skills.my-skill.enable
          {
            claude.enable = true;
            codex.enable = true;
            modules.skills.my-skill.enable = true;
            instructions.style.text = "Prefer small commits.";
            claude.settings.includeCoAuthoredBy = false;
            codex.settings.approval_policy = "on-request";
            launchers = {
              claude-work-acc.agent = "claude";
              claude-pers-acc.agent = "claude";
              codex-work-acc.agent = "codex";
            };
          }
        ];
      }).package;
    };
}
```

Runnable examples: [`examples/basic`](examples/basic) and
[`examples/multi-account`](examples/multi-account). The root flake exposes only
`lib` and a default environment without skills: `nix shell .#default` puts its
`claude` and `codex` launchers on `PATH`.

## Options

| Option | Meaning |
|---|---|
| `claude.enable`, `codex.enable` | Make the agent available to launchers. |
| `claude.package`, `codex.package` | Agent package; defaults come from this flake's inputs. |
| `claude.settings` | JSON passed with `--settings` (layered over the account's `settings.json`). |
| `codex.settings` | TOML linked as `$CODEX_HOME/agent-environments.config.toml` and selected with `--profile agent-environments` (layered over the account's `config.toml`). |
| `instructions.<name>.{text,order}` | Fragments of `CLAUDE.md` / `AGENTS.md`, sorted by `order` (default 1000), then name. |
| `skills.packages` | `mkSkill` packages to enable. Their skill dependencies are added automatically. |
| `modules.skills.<name>.enable` | Declared by `mkSkillModule`; adds that skill. |
| `launchers.<cmd>.{agent,id,stateDir}` | A command. `id` defaults to the command name; `stateDir` defaults to `~/.local/agent-environments/<id>`; it must be absolute or start with `~/`, and is taken literally. |

## What a launcher does

On every start, under a lock on the state dir:

1. Links the managed files into the state dir: the instruction file, one link per
   skill in `skills/<name>`, and the Codex profile. Everything it manages is
   listed in `.agent-environments-managed`.
2. Removes managed links that are no longer wanted. Anything not in the manifest
   (your own skills, Codex's `skills/.system`, logins, `settings.json`,
   `config.toml`) is never touched.
3. Refuses to start if a managed path is occupied by something it does not own,
   such as a hand-written `CLAUDE.md`. Move it away (or turn it into an
   `instructions` fragment) and start again.
4. Sets `CLAUDE_CONFIG_DIR` / `CODEX_HOME`, puts the skills' runtime inputs on
   `PATH`, and runs the agent.

Launchers that share an `id` share a login and managed files. The most recent
launch decides which files are linked, so only share an id between launchers of
the same environment.

## Development

```sh
nix flake check          # behaviour tests (stub agents) + real Codex integration check
nix fmt -- $(git ls-files '*.nix')
nix build ./examples/basic --override-input agent-environments path:$PWD
```