agent-team/flake.nix
2026-04-12 23:10:30 -04:00

216 lines
8 KiB
Nix

{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
outputs = { self, nixpkgs, ... }:
let
systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
in
{
devShells = forAllSystems (pkgs: {
default = pkgs.mkShell {
packages = with pkgs; [
yq-go
gettext
jq
just
];
};
});
apps = forAllSystems (pkgs: let
pythonEnv = pkgs.python3.withPackages (ps: with ps; [ pyyaml jsonschema ]);
runtimeInputs = with pkgs; [
bash
yq-go
gettext
jq
pythonEnv
];
bashBin = "${pkgs.bash}/bin/bash";
validateCmd = ''
# Script syntax checks
${bashBin} -n ./generate.sh
${bashBin} -n ./install.sh
# Protocol file presence checks
test -f ./SETTINGS.yaml
test -f ./TEAM.yaml
test -f ./schemas/agent-runtime.schema.json
test -f ./schemas/team.schema.json
# Basic protocol shape checks
yq -e '.version == 1' ./SETTINGS.yaml
yq -e '.version == 1' ./TEAM.yaml
yq -e '.agents.order | type == "!!seq"' ./TEAM.yaml
yq -e '.skills.order | type == "!!seq"' ./TEAM.yaml
yq -e '.rules.order | type == "!!seq"' ./TEAM.yaml
# OpenCode base config must exist and be valid JSON
test -f ./opencode/config.json
jq empty ./opencode/config.json
# JSON Schema validation for protocol files
python <<'PY'
import json
from pathlib import Path
import yaml
from jsonschema import validate
root = Path(".")
settings_data = yaml.safe_load((root / "SETTINGS.yaml").read_text())
team_data = yaml.safe_load((root / "TEAM.yaml").read_text())
settings_schema = json.loads((root / "schemas/agent-runtime.schema.json").read_text())
team_schema = json.loads((root / "schemas/team.schema.json").read_text())
validate(instance=settings_data, schema=settings_schema)
validate(instance=team_data, schema=team_schema)
# TEAM referenced files must exist on disk.
for agent_id in team_data["agents"]["order"]:
instruction_file = team_data["agents"]["items"][agent_id]["instruction_file"]
if not (root / instruction_file).is_file():
raise FileNotFoundError(f"Missing agent instruction file: {instruction_file}")
for skill_id in team_data["skills"]["order"]:
instruction_file = team_data["skills"]["items"][skill_id]["instruction_file"]
if not (root / instruction_file).is_file():
raise FileNotFoundError(f"Missing skill instruction file: {instruction_file}")
for rule_id in team_data["rules"]["order"]:
source_file = team_data["rules"]["items"][rule_id]["source_file"]
if not (root / source_file).is_file():
raise FileNotFoundError(f"Missing rule source file: {source_file}")
PY
'';
mkAppScript = name: text:
pkgs.writeShellApplication {
inherit name runtimeInputs text;
};
in {
build = {
type = "app";
program = "${mkAppScript "build" ''
set -euo pipefail
test -f ./generate.sh || { echo "Run this command from the repository root."; exit 1; }
${bashBin} ./generate.sh
''}/bin/build";
meta.description = "Generate Claude, Codex, and OpenCode build artifacts from the authored protocol files.";
};
validate = {
type = "app";
program = "${mkAppScript "validate" ''
set -euo pipefail
test -f ./generate.sh || { echo "Run this command from the repository root."; exit 1; }
${validateCmd}
''}/bin/validate";
meta.description = "Validate scripts and protocol files.";
};
check = {
type = "app";
program = "${mkAppScript "check" ''
set -euo pipefail
test -f ./generate.sh || { echo "Run this command from the repository root."; exit 1; }
${validateCmd}
${bashBin} ./generate.sh
''}/bin/check";
meta.description = "Run validation and generation together.";
};
install = {
type = "app";
program = "${mkAppScript "install" ''
set -euo pipefail
test -f ./install.sh || { echo "Run this command from the repository root."; exit 1; }
${validateCmd}
${bashBin} ./install.sh
''}/bin/install";
meta.description = "Install generated artifacts into Claude, Codex, and OpenCode config directories.";
};
});
checks = forAllSystems (pkgs: let
pythonEnv = pkgs.python3.withPackages (ps: with ps; [ pyyaml jsonschema ]);
runtimeInputs = with pkgs; [
bash
yq-go
gettext
jq
pythonEnv
];
bashBin = "${pkgs.bash}/bin/bash";
validateCmd = ''
${bashBin} -n ./generate.sh
${bashBin} -n ./install.sh
test -f ./SETTINGS.yaml
test -f ./TEAM.yaml
test -f ./schemas/agent-runtime.schema.json
test -f ./schemas/team.schema.json
yq -e '.version == 1' ./SETTINGS.yaml
yq -e '.version == 1' ./TEAM.yaml
yq -e '.agents.order | type == "!!seq"' ./TEAM.yaml
yq -e '.skills.order | type == "!!seq"' ./TEAM.yaml
yq -e '.rules.order | type == "!!seq"' ./TEAM.yaml
python <<'PY'
import json
from pathlib import Path
import yaml
from jsonschema import validate
root = Path(".")
settings_data = yaml.safe_load((root / "SETTINGS.yaml").read_text())
team_data = yaml.safe_load((root / "TEAM.yaml").read_text())
settings_schema = json.loads((root / "schemas/agent-runtime.schema.json").read_text())
team_schema = json.loads((root / "schemas/team.schema.json").read_text())
validate(instance=settings_data, schema=settings_schema)
validate(instance=team_data, schema=team_schema)
# TEAM referenced files must exist on disk.
for agent_id in team_data["agents"]["order"]:
instruction_file = team_data["agents"]["items"][agent_id]["instruction_file"]
if not (root / instruction_file).is_file():
raise FileNotFoundError(f"Missing agent instruction file: {instruction_file}")
for skill_id in team_data["skills"]["order"]:
instruction_file = team_data["skills"]["items"][skill_id]["instruction_file"]
if not (root / instruction_file).is_file():
raise FileNotFoundError(f"Missing skill instruction file: {instruction_file}")
for rule_id in team_data["rules"]["order"]:
source_file = team_data["rules"]["items"][rule_id]["source_file"]
if not (root / source_file).is_file():
raise FileNotFoundError(f"Missing rule source file: {source_file}")
PY
'';
mkCheck = name: text:
pkgs.runCommand name { nativeBuildInputs = runtimeInputs; src = ./.; } ''
mkdir -p "$TMPDIR/repo"
cp -R "$src"/. "$TMPDIR/repo"
chmod -R u+w "$TMPDIR/repo"
cd "$TMPDIR/repo"
${text}
touch "$out"
'';
in {
validate = mkCheck "agent-team-validate-check" ''
set -euxo pipefail
${validateCmd}
'';
build = mkCheck "agent-team-build-check" ''
set -euxo pipefail
${validateCmd}
${bashBin} ./generate.sh
'';
});
};
}