mirror of
https://github.com/itme-brain/agent-team.git
synced 2026-05-08 11:40:12 -04:00
216 lines
8 KiB
Nix
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
|
|
'';
|
|
});
|
|
};
|
|
}
|