Files
agent-skills/scripts/roster.sh
T
Miguel Palhas e818cfea8b
ci / lint (push) Successful in 1m12s
ci / nix (push) Successful in 18s
feat(config): one agent roster for daemon and blitz
The reviewer pool was the only place naming harness+model combos, and
blitz kept its own table inline. `reviewers` becomes `agents`, gains
`roles` and `tiers`, and blitz routes from it via scripts/roster.sh.

Config path moves to ~/.config/agent-skills/; the reviewer path stays
readable so a box migrates with a mv.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:37:04 +01:00

64 lines
2.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Query the shared agent roster: which harness+model combos this box may spawn.
#
# Same config the PR daemon reads. Entries carry `roles` (who may pick it:
# "review" = PR reviewer rotation, "blitz" = milestone workers; absent = both)
# and `tiers` (blitz difficulty routing: execution | design | subtle).
#
# roster.sh # every enabled entry, one JSON per line
# roster.sh --role blitz --tier design # what blitz may spawn for design work
# roster.sh --id claude/opus@high # one entry
# roster.sh --role blitz --tier execution --format aoe
# --tool claude --extra-args "--model sonnet"
#
# Exit 3 means the config is missing, 4 means nothing matched. Both are
# survivable: fall back to the skill's own default table and say so.
set -euo pipefail
ROLE="" TIER="" ID="" FORMAT=json
while [ $# -gt 0 ]; do
case "$1" in
--role) ROLE="$2"; shift 2 ;;
--tier) TIER="$2"; shift 2 ;;
--id) ID="$2"; shift 2 ;;
--format) FORMAT="$2"; shift 2 ;;
--config) CONFIG="$2"; shift 2 ;;
-h|--help) sed -n '2,18p' "$0" | sed 's/^# \?//'; exit 0 ;;
*) echo "roster.sh: unknown argument $1" >&2; exit 2 ;;
esac
done
# Same resolution order as the daemon: the shared path wins, the reviewer-only
# path still works so a box migrates with a mv.
if [ -z "${CONFIG:-}" ]; then
for c in "${AGENTS_CONFIG:-}" "${REVIEWER_CONFIG:-}" \
"$HOME/.config/agent-skills/config.json" "$HOME/.config/reviewer/config.json"; do
[ -n "$c" ] && [ -f "$c" ] && { CONFIG="$c"; break; }
done
fi
[ -n "${CONFIG:-}" ] || { echo "roster.sh: no agent config found" >&2; exit 3; }
# `agents` is the current key; `reviewers` is what it was called when only the
# PR daemon read it.
MATCHES=$(jq -c \
--arg role "$ROLE" --arg tier "$TIER" --arg id "$ID" '
((.agents // .reviewers) // [])
| map(select(.enabled != false))
| map(select($id == "" or .id == $id))
| map(select($role == "" or ((.roles // ["review","blitz"]) | index($role))))
| map(select($tier == "" or ((.tiers // []) | index($tier))))
| .[]' "$CONFIG")
[ -n "$MATCHES" ] || exit 4
case "$FORMAT" in
json) printf '%s\n' "$MATCHES" ;;
id) printf '%s\n' "$MATCHES" | jq -r '.id' ;;
# Ready to paste into an `aoe add` line. args are joined into the single
# string --extra-args wants, quoted so a flag with spaces survives.
aoe) printf '%s\n' "$MATCHES" | jq -r '
"--tool \(.tool) --extra-args \"\((.args // []) | join(" "))\""' ;;
*) echo "roster.sh: unknown format $FORMAT" >&2; exit 2 ;;
esac