Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Or as a Claude Code plugin:
> [!NOTE]
> The plugin ships the skills only. Run `/super-board:super-board onboard` and its 🔍 Checks step adds the guard hooks, scripts and workflows. Needs Claude Code, `gh`, `jq`, bash 3.2+ and Python 3.9+; the installer checks.

Running from Codex or OpenCode? See [supported hosts](docs/hosts.md) for tested versions, sign-in and gaps.
Running from Codex, OpenCode or Google Antigravity? See [supported hosts](docs/hosts.md) for tested versions, sign-in and gaps.

Optional post-run learning can delegate an already installed `calibrate` skill after
verified selected work completes. It applies only to explicitly permitted existing
Expand Down
16 changes: 13 additions & 3 deletions docs/hosts.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ super-board runs inside an agent host: the CLI whose session types `/super-board
| `claude` | Claude Code 2.1.302 | `/super-board run` (Workflow backend) | `claude` then `/login`; `gh auth login` | None. The reference host. |
| `codex` | codex-cli 0.160.0 | `/super-board run` inside Codex runs as `--codex`; from Claude, `/super-board run --codex` | `codex login`; `gh auth login` | No Workflow tool, so every lane is headless `codex exec`. Review runs only with explicit `--codex` (a host-switched plain `run` counts). No Claude usage guard. |
| `opencode` | OpenCode v2.0.22 | Not supported yet: the run halts with a host-selection request | `opencode auth login`; `gh auth login` | No OpenCode lane backend yet. `permission.external_directory: deny` is not enforced in v2.0.22 (`patch` still writes outside the repo), so OpenCode runs stay attended-only once a backend lands. |
| `agy` | Google Antigravity CLI 1.4.6 (`agy`) | Not supported yet: the run halts with a host-selection request | interactive `agy` once (headless runs use the cached sign-in); `gh auth login` | No Antigravity lane backend yet. Headless `agy -p` auto-denies every shell command and non-workspace file write that `permissions.allow` in `~/.gemini/antigravity-cli/settings.json` does not cover, and on Windows those rules match exactly unless written as `command(regex:…)`. |

Every host also needs `gh`, `jq`, bash 3.2+ and Python 3.9+.

Expand All @@ -19,9 +20,12 @@ Every host also needs `gh`, `jq`, bash 3.2+ and Python 3.9+.
2. `CODEX_THREAD_ID` or `CODEX_SESSION_ID` → `codex`.
3. `OPENCODE=1` → `opencode`. Checked before `CLAUDECODE`, which leaks into an OpenCode
session started from Claude Code. `AGENT=1` is ignored: other tools set it too.
4. `CLAUDECODE` → `claude`.
5. The board config's top-level `host` key, when `--config` is given.
6. Nothing matched: empty stdout, a hint on stderr, exit 65. The run halts and asks for a
4. `ANTIGRAVITY_AGENT=1` → `agy`. Also checked before `CLAUDECODE`, which leaks into an
Antigravity lane started from a Claude session. The other `ANTIGRAVITY_*` variables are
per-conversation ids or session secrets and are not used.
5. `CLAUDECODE` → `claude`.
6. The board config's top-level `host` key, when `--config` is given.
7. Nothing matched: empty stdout, a hint on stderr, exit 65. The run halts and asks for a
host. It never guesses Claude.

A live env sign beats the saved config, so a Codex lane started from a Claude-configured
Expand All @@ -35,3 +39,9 @@ Onboard always writes `host` into `.claude/super-board/configs/<slug>.json`.
- Codex: env of `codex exec -s read-only`, 2026-10-04 (recorded in the script header).
- OpenCode: env diff of an `opencode run` shell, 2026-10-19: `OPENCODE=1`,
`OPENCODE_SESSION_ID`, `OPENCODE_TERMINAL=1`, `AGENT=1`.
- Antigravity: `cmd /c set` run by `run_command` inside a headless `agy -p` on agy 1.4.6,
Windows 11, 2026-10-23: `ANTIGRAVITY_AGENT=1`, `ANTIGRAVITY_CONVERSATION_ID`,
`ANTIGRAVITY_LS_VERSION=cli-1.4.6`, `ANTIGRAVITY_APP_DATA_DIR`, `ANTIGRAVITY_PROJECT_ID`,
`ANTIGRAVITY_TRAJECTORY_ID`, `ANTIGRAVITY_AGENTAPI_EXE`, `ANTIGRAVITY_LS_ADDRESS`,
`ANTIGRAVITY_CSRF_TOKEN`, `ANTIGRAVITY_SOURCE_METADATA`. No `AGENT`, `GEMINI_*` or
`CLAUDECODE`. The hooks and permissions docs name none of them.
31 changes: 20 additions & 11 deletions scripts/super-board-host.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# super-board-host.sh — which agent host is this shell inside: `claude`, `codex` or `opencode`.
# super-board-host.sh — which agent host is this shell inside: `claude`, `codex`, `opencode` or `agy`.
#
# WHY. `/super-board run` launched from a Codex CLI session has no Claude Workflow tool, so the
# workflow backend cannot start. The orchestrator checks its own tool list first; this is the
Expand All @@ -17,16 +17,23 @@
# shells it runs. Observed 2026-10-19 on opencode v2.0.22 (env diff of a `run` shell).
# Checked before CLAUDECODE, which leaks into OpenCode started from a Claude session.
# Not used: AGENT=1 (a generic name other tools set too).
# - Google Antigravity (the `agy` CLI) sets ANTIGRAVITY_AGENT=1 in every shell its
# run_command tool runs, plus ANTIGRAVITY_CONVERSATION_ID, ANTIGRAVITY_LS_VERSION
# (e.g. cli-1.4.6), ANTIGRAVITY_PROJECT_ID and ANTIGRAVITY_TRAJECTORY_ID. Observed
# 2026-10-23 on agy 1.4.6 (`cmd /c set` inside a headless `agy -p` run on Windows 11).
# Checked before CLAUDECODE, which leaks into an agy lane started from a Claude session.
# Not used: the ids (one per conversation) and ANTIGRAVITY_CSRF_TOKEN (a session secret).
# - Claude Code sets CLAUDECODE=1.
#
# ORDER. SUPER_BOARD_HOST, Codex ids, OPENCODE, CLAUDECODE, then the config's top-level
# `host` key (--config <file>), else exit 65. A live env sign beats the saved config.
# ORDER. SUPER_BOARD_HOST, Codex ids, OPENCODE, ANTIGRAVITY_AGENT, CLAUDECODE, then the
# config's top-level `host` key (--config <file>), else exit 65. A live env sign beats the
# saved config.
#
# Usage: super-board-host.sh [--config <config.json>]
# prints `claude`, `codex` or `opencode`, exit 0
# prints `claude`, `codex`, `opencode` or `agy`, exit 0
# exit 65 no sign: nothing on stdout, how to choose on stderr
# exit 64 SUPER_BOARD_HOST or config `host` is not one of the three
# SUPER_BOARD_HOST=claude|codex|opencode forces the answer (tests, or a host the check
# exit 64 SUPER_BOARD_HOST or config `host` is not one of the four
# SUPER_BOARD_HOST=claude|codex|opencode|agy forces the answer (tests, or a host the check
# misreads).
set -euo pipefail

Expand All @@ -38,23 +45,25 @@ case "${1:-}" in
esac

case "${SUPER_BOARD_HOST:-}" in
claude|codex|opencode) echo "$SUPER_BOARD_HOST"; exit 0 ;;
claude|codex|opencode|agy) echo "$SUPER_BOARD_HOST"; exit 0 ;;
'') ;;
*) echo "super-board-host.sh: SUPER_BOARD_HOST must be claude, codex or opencode" >&2; exit 64 ;;
*) echo "super-board-host.sh: SUPER_BOARD_HOST must be claude, codex, opencode or agy" >&2; exit 64 ;;
esac

if [ -n "${CODEX_THREAD_ID:-}" ] || [ -n "${CODEX_SESSION_ID:-}" ]; then
echo codex
elif [ -n "${OPENCODE:-}" ]; then
echo opencode
elif [ -n "${ANTIGRAVITY_AGENT:-}" ]; then
echo agy
elif [ -n "${CLAUDECODE:-}" ]; then
echo claude
elif saved=$( [ -f "$config" ] && jq -r '.host // empty' "$config" 2>/dev/null ) && [ -n "$saved" ]; then
case "$saved" in
claude|codex|opencode) echo "$saved" ;;
*) echo "super-board-host.sh: config host must be claude, codex or opencode, got '$saved'" >&2; exit 64 ;;
claude|codex|opencode|agy) echo "$saved" ;;
*) echo "super-board-host.sh: config host must be claude, codex, opencode or agy, got '$saved'" >&2; exit 64 ;;
esac
else
echo "super-board-host.sh: unknown agent host. Pick one: SUPER_BOARD_HOST=claude|codex|opencode, or set \"host\" in the board config" >&2
echo "super-board-host.sh: unknown agent host. Pick one: SUPER_BOARD_HOST=claude|codex|opencode|agy, or set \"host\" in the board config" >&2
exit 65
fi
4 changes: 2 additions & 2 deletions scripts/super-board-setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
settings.json entries (runs the pack's install.sh) when any is missing or older
- removes the folders of skills that no longer exist: super-refine, cleanup-wt, arch-loop
- migrates every .claude/super-board/configs/*.json to the v3 keys (migrate-config), and
writes a missing top-level `host` from --host (check flags a host outside claude/codex/opencode)
writes a missing top-level `host` from --host (check flags a host outside claude/codex/opencode/agy)
- `git init` when the folder is not a repo
- adds Matt Pocock's helper skills with npx when Node is present and they are missing
It never installs a system tool or signs in: those come back in `needs` with the exact
Expand Down Expand Up @@ -59,7 +59,7 @@
import sys

COLUMNS = ["Backlog", "Ready", "Building", "QA", "Review", "Blocked", "Done"]
HOSTS = ("claude", "codex", "opencode") # config `host`; super-board-host.sh accepts the same
HOSTS = ("claude", "codex", "opencode", "agy") # config `host`; super-board-host.sh accepts the same
LABELS = {
"qa": ("0e8a16", "Test what exists; skips Building (super-board)"),
"bug": ("d73a4a", "Something is broken; built, tested, reviewed (super-board)"),
Expand Down
5 changes: 3 additions & 2 deletions skills/super-board/references/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@
// only; the dispatcher refuses to run (exit 78) unless set here.
"worker_backend": "workflow",

// Agent host this project runs on: "claude" | "codex" | "opencode". Separate from
// Agent host this project runs on: "claude" | "codex" | "opencode" | "agy" (Google
// Antigravity). Separate from
// worker_backend. Onboard and setup's fix ALWAYS write it (setup fills a missing key
// from --host and never replaces a set one); setup's check flags any other value.
// `super-board-host.sh --config <this file>` uses it only when SUPER_BOARD_HOST and
// every env sign (Codex ids, OPENCODE, CLAUDECODE) are absent. See docs/hosts.md.
// every env sign (Codex ids, OPENCODE, ANTIGRAVITY_AGENT, CLAUDECODE) are absent. See docs/hosts.md.
"host": "claude",

// Optional post-completion adapter; never bundles or installs the external skill.
Expand Down
2 changes: 1 addition & 1 deletion skills/super-board/references/onboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ Write it atomically (temp file + rename) after every answer. A halt never loses
│ │ {type: repo | repo+url}, repo, base_branch, timezone, columns (the seven), labels,
│ │ paths, merge_policy, migrations, collect (incl. custom), notifications {channel:
│ │ "session", bot_identity}, worker_backend "workflow", host (always: `bash $SB/super-board-host.sh`;
│ │ on exit 65 ask claude/codex/opencode), verify_commands (non-blank project checks). No `variant`.
│ │ on exit 65 ask claude/codex/opencode/agy), verify_commands (non-blank project checks). No `variant`.
│ ├─ .claude/super-board/active ← <slug>
│ ├─ .gitignore += .claude/super-board/active, onboard-answers.json, onboard-staged/,
│ │ backup/, inflight/, migrations/, upgrade.json (all under .claude/super-board/)
Expand Down
9 changes: 5 additions & 4 deletions skills/super-board/references/run-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ Keep this run choice in each wave and resume command; skip only the Claude usage
`--codex=<model>` still apply); it counts as explicit `--codex`, Review included.
Say so once, in the first wave report: `🔁 codex host — running as --codex`. Never improvise a Claude workflow wave in Codex.

**Unknown host halts.** Run the host check before preconditions. Exit 65 (no host sign) or
`opencode` (no OpenCode backend yet) halts before any claim, even with no Workflow tool, with one line:
**Unknown host halts.** Run the host check before preconditions. Exit 65 (no host sign),
`opencode` (no OpenCode backend yet) or `agy` (no Antigravity backend yet) halts before any claim,
even with no Workflow tool, with one line:
`⛔ unknown host — set SUPER_BOARD_HOST=claude|codex and re-run`. Never guess a backend.

After the same plan and claim steps, launch this command as a background task:
Expand Down Expand Up @@ -246,8 +247,8 @@ Repeat until a done condition or halt gate fires:
there is no cross-session claim at all, so never run two orchestrators
(or /loop re-entries) against the same board without bot_identity.
4. **Launch** — With `--codex`, or no Workflow tool, or the host check printing `codex`, use
"Codex runs" above. The host check printing `claude` uses the Workflow tool; exit 65 or
`opencode` never reaches Launch (see "Unknown host halts"). Workflow tool with
"Codex runs" above. The host check printing `claude` uses the Workflow tool; exit 65,
`opencode` or `agy` never reaches Launch (see "Unknown host halts"). Workflow tool with
`scriptPath: .claude/workflows/super-board-wave.js` and
`args: { configPath, cards, humanApprovesMerge, tier }` (`cards` hydrated after the planner: each
carries `lane` and `labels`, and a `qa` card skips the Builder). Runs in the background; the
Expand Down
14 changes: 14 additions & 0 deletions tests/test-host.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ host() { env -i PATH="$PATH" "$@" bash "$S"; }
[ "$(host SUPER_BOARD_HOST=codex)" = codex ] || fail 'override forces codex'
[ "$(host SUPER_BOARD_HOST=claude CODEX_THREAD_ID=01a1)" = claude ] || fail 'override beats the env'
[ "$(host SUPER_BOARD_HOST=opencode)" = opencode ] || fail 'override accepts opencode'
[ "$(host SUPER_BOARD_HOST=agy)" = agy ] || fail 'override accepts agy'
rc=0; host SUPER_BOARD_HOST=gemini >/dev/null 2>&1 || rc=$?
[ "$rc" = 64 ] || fail "bad override exits 64, got $rc"

Expand All @@ -31,6 +32,8 @@ nohost
nohost CODEX_HOME=/x CODEX_SANDBOX=seatbelt # not host signs
nohost CODEX_THREAD_ID= CLAUDECODE= # empty values are not signs
nohost AGENT=1 # OpenCode sets it, but so do other tools
nohost ANTIGRAVITY_CONVERSATION_ID=fe3b ANTIGRAVITY_LS_VERSION=cli-1.4.6 # ids are not the sign
nohost ANTIGRAVITY_AGENT= # empty is not a sign

# OpenCode v2.0.22 exports OPENCODE=1. It wins over a CLAUDECODE leaked from a parent Claude
# session; the override and a Codex id still win over it.
Expand All @@ -39,15 +42,26 @@ nohost AGENT=1 # OpenCode sets it, but so do oth
[ "$(host SUPER_BOARD_HOST=claude OPENCODE=1)" = claude ] || fail 'override beats the OpenCode sign'
[ "$(host CODEX_THREAD_ID=01a1 OPENCODE=1)" = codex ] || fail 'a Codex id beats the OpenCode sign'

# Antigravity (agy 1.4.6) exports ANTIGRAVITY_AGENT=1 into the shells its run_command tool
# runs. It wins over a CLAUDECODE leaked from the Claude session that launched the lane; the
# override and a Codex id still win over it.
[ "$(host ANTIGRAVITY_AGENT=1)" = agy ] || fail 'ANTIGRAVITY_AGENT=1 means agy'
[ "$(host ANTIGRAVITY_AGENT=1 CLAUDECODE=1)" = agy ] || fail 'an agy lane under a Claude parent is agy'
[ "$(host SUPER_BOARD_HOST=claude ANTIGRAVITY_AGENT=1)" = claude ] || fail 'override beats the agy sign'
[ "$(host CODEX_THREAD_ID=01a1 ANTIGRAVITY_AGENT=1)" = codex ] || fail 'a Codex id beats the agy sign'

# Config `host` (top-level key): used only when no override and no env sign is present.
T=$(mktemp -d); trap 'rm -f "$ERR"; rm -rf "$T"' EXIT
printf '{"host":"codex"}' > "$T/codex.json"
printf '{"host":"agy"}' > "$T/agy.json"
printf '{"worker_backend":"workflow"}' > "$T/none.json"
printf '{"host":"gemini"}' > "$T/bad.json"
cfg() { local f=$1; shift; env -i PATH="$PATH" "$@" bash "$S" --config "$f"; }
[ "$(cfg "$T/codex.json")" = codex ] || fail 'config host codex prints codex'
[ "$(cfg "$T/codex.json" CLAUDECODE=1)" = claude ] || fail 'an env sign beats config host'
[ "$(cfg "$T/codex.json" SUPER_BOARD_HOST=opencode)" = opencode ] || fail 'override beats config host'
[ "$(cfg "$T/agy.json")" = agy ] || fail 'config host agy prints agy'
[ "$(cfg "$T/agy.json" CODEX_THREAD_ID=01a1)" = codex ] || fail 'an env sign beats config host agy'
for f in none missing; do
rc=0; out=$(cfg "$T/$f.json" 2>/dev/null) || rc=$?
[ "$rc" = 65 ] && [ -z "$out" ] || fail "config $f without host should exit 65, got $rc '$out'"
Expand Down
4 changes: 2 additions & 2 deletions tests/test-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,10 @@ cmp -s "$GH_STATE" "$WORK/before.json" || fail "dry-run changed board state: $(c
[ ! -e "$WORK/dry/.claude" ] || fail "dry-run must not write a backup file"
echo "$OUT" | q '.status_backup == null and .restored == 0 and .added_columns != []' || fail "dry-run report wrong: $OUT"

# 13 — config `host`: check accepts claude / codex / opencode, flags anything else, and
# 13 — config `host`: check accepts claude / codex / opencode / agy, flags anything else, and
# fix never overwrites a host that is already set.
H="$WORK/bare/.claude/super-board/configs"; mkdir -p "$H"
for h in claude codex opencode; do
for h in claude codex opencode agy; do
printf '{"host":"%s"}' "$h" > "$H/b.json"
OUT=$(python3 "$SETUP" check --root "$WORK/bare" || true)
echo "$OUT" | q '.host_errors == {}' || fail "host $h must be accepted: $OUT"
Expand Down