Human-led AI agent teams for OpenCode — implemented in Go.
One binary scaffolds a persistent team in your repo (.squad/) and OpenCode agents (.opencode/). You coordinate work; specialists (Lead, Frontend, Backend, Tester) run as OpenCode agents.
Inspired by bradygaster/squad (MIT). OpenCode-native port — not a Copilot fork.
Host API client: official opencode-sdk-go (github.com/sst/opencode-sdk-go).
No Go toolchain. Download the archive for your OS from GitHub Releases and put squad-oc on your PATH. Assets are squad-oc_<version>_<os>_<arch>.zip (Windows) or .tar.gz (macOS/Linux).
# Scoop
scoop bucket add squad https://github.com/xeaser/squad-opencode
scoop install squad-oc
# Homebrew
brew tap xeaser/squad-opencode https://github.com/xeaser/squad-opencode
brew install squad-oc
# The tap ships a cask; existing formula installs migrate via tap_migrations.json.# winget (from a clone of this repo)
winget install --manifest packaging/wingetsquad-oc upgrade --self replaces the binary from the latest release.
# 1. Install OpenCode + /connect a provider — https://opencode.ai/docs/# 2. Install squad-oc from GitHub Releases (see Install above)# 3. In your project
mkdir my-app &&cd my-app && git init
squad-oc init --preset default
squad-oc doctor
# Interactive TUI (does not listen on :4096)
opencode
# Tab → squad agent → "Set up the team for …" → yes# HTTP API: run auto-starts `opencode serve` on :4096 if nothing is there
squad-oc run -p "Summarize .squad/team.md"Full walkthrough: docs/get-started.md
- docs/workshop/README.md — 90-minute adopt path (squad-oc + OpenCode only)
- docs/use-cases.md — workshop mapped to supported / later / won’t port
This repo dogfoods Squad on itself. After init + opening OpenCode:
| Commit | Do not commit |
|---|---|
.squad/ team, charters, decisions, .gitignore | .squad/comms/* (folder kept via .gitkeep) |
.opencode/agents, skills, commands, .gitignore | .opencode/node_modules/ |
opencode.json | .opencode/package.json + lockfiles OpenCode generates |
OpenCode creates .opencode/package.json (@opencode-ai/plugin) and runs an install on first launch. That is host runtime, not Squad source.
| Command | Role |
|---|---|
| `init [--preset default] [--description ] [--global] [--theme office | none]` |
upgrade [--dry-run] [--force] [--global] [--self] | Refresh host templates; --self replaces this binary from GitHub Releases |
doctor / heartbeat | Health checks |
status / cast | Team table |
cast --add <name> [--role <role>] | Add a member and regenerate .opencode/agents |
cast --remove <name> | Remove a member and regenerate .opencode/agents |
cast --theme office / none | init --theme office (native @michael) or later cast --theme office (mention map; @lead gone) |
recast | Regenerate .opencode/agents from .squad/team.md |
run -p <prompt> / --file <path> [--agent name] [--url] | Prompt the OpenCode HTTP API as squad; auto-starts opencode serve on :4096 only |
watch / triage / loop[--execute] [--interval minutes] [--once] [--health] [--url] [--overnight-start HH:MM] [--overnight-end HH:MM] [--label name] [--log-file path] [--verbose] [--notify-level all|important|none] [--state-backend memory|git-notes|orphan-branch] | Issue triage (Ralph); --execute uses run |
export [file] / import <file> [--with-host] | JSON snapshot of .squad/ (optional host files) |
externalize [--key name] / internalize | Move this project's team out of the worktree |
nap [--dry-run] [--deep] / scrub-emails [directory] | Context and PII hygiene |
upstream add <name> <path|git-url> / list / remove / sync | Remember and pull extra agents/skills |
pack <path|git-url> | One-shot pull of extra agents/skills |
| `link <team-dir | git-url>/link --sync/link --off` |
update-check [--json] [--refresh] | Prints up to date or update available vs GitHub latest tag |
traces [--last N] [--json] [--export file] | Local run / watch spans; --export writes OTLP JSON |
mcp apply / list / init | Merge org .squad/mcp-config.json into opencode.json |
marketplace add / list / remove / browse / install | Register a skills pack and copy a plugin into .opencode/skills/ |
plugin install <name>@<marketplace> / list / uninstall <name> | Named skill install; uninstall removes only .opencode/skills/<name>/ |
help / version | Usage and version string |
cmd/squad-oc/ # main → internal/cli
internal/cli/ # commands
internal/squad/ # init, upgrade, export, externalize, nap, scrub, templates
internal/opencodeclient/ # SDK + run (needs `opencode serve`)
internal/watch/ # issue triage (Ralph): health, overnight, backends
internal/githubissues/ # gh issue list
internal/share/ # upstream / pack / link
internal/traces/ # local JSONL spans + OTLP export
internal/selfupdate/ # upgrade --self
internal/updatecheck/
internal/version/
docs/
squad-oc (Go)
├── embed templates → .squad / .opencode
└── github.com/sst/opencode-sdk-go → opencode serve (:4096)
opencode (TUI) and opencode serve (HTTP API) are different. Only serve works with run and watch --execute.
run / watch --execute attach to an existing server, or start opencode serve --hostname 127.0.0.1 --port 4096 in this project. They never auto-start if --url or OPENCODE_BASE_URL is anything other than http://127.0.0.1:4096 / http://localhost:4096. The serve process is left running.
upgrade refreshes host templates (.opencode/). It never overwrites team memory (team.md, decisions, knowledge).
upgrade --self downloads the latest GitHub Release for this OS/arch and replaces the running binary. On Windows, if the exe is locked, it writes squad-oc.exe.new beside it (replaced on next start).
traces lists local spans from run and watch --execute. --export file writes OTLP JSON any collector can ingest.
Your company keeps a security pack — extra OpenCode agents and a Designer charter — in a git repo or a folder on disk.
# One-shot: drop those files into *this* project
squad-oc pack https://github.com/acme/squad-security-pack.git
# or a local folder you already cloned
squad-oc pack ~/packs/security
# Remember it and pull again when the pack updates
squad-oc upstream add security https://github.com/acme/squad-security-pack.git
squad-oc upstream sync security # next quarter: same command
squad-oc upstream listpack / sync refresh .opencode/ (agents, skills, commands). New .squad/agents/<name>/ files are added only if missing. team.md, decisions, and existing knowledge are never overwritten.
A pack is just a directory that contains .opencode/ (or a bare agents/ / skills/ / commands/ tree). Optional .squad/agents/… stubs are fine.
Platform Lead, decisions, and knowledge live in one place. Billing and Checkout both use that team.
# once: a dedicated team folder (or any repo that already has .squad/)
mkdir -p ~/teams/platform &&cd~/teams/platform
git init && squad-oc init --preset default --description "Platform team"cd~/code/billing
squad-oc init --preset default
squad-oc link ~/teams/platform # also accepts ~/teams/platform/.squadcd~/code/checkout
squad-oc init --preset default
squad-oc link ~/teams/platform
squad-oc status # both show the same members# later
squad-oc link --off # this repo uses its local .squad/ again# or, no local clone — cache lives in ~/.squad-oc/links/
squad-oc link https://github.com/acme/squad-platform.git
squad-oc link --sync # fetch updates
squad-oc link --offlink does not move files. Config stays in each repo; team.md / charters / decisions are read from the shared directory. Cannot combine with externalize (that moves this project's own team out of the worktree).
squad-oc cast --add Designer --role Design
# appends Designer to team.md, writes charter/knowledge, regenerates .opencode/agents
squad-oc cast --remove Designer
# drops the member and regenerates .opencode/agents# or edit .squad/team.md by hand, then:
squad-oc recastOpenCode only sees agents that exist under .opencode/agents/. Recast is what makes a new row in team.md show up as @designer. It never touches squad.md (the coordinator).
# poll and execute during the day; sleep 18:00–08:00 local
squad-oc watch --execute --interval 10 --overnight-start 18:00 --overnight-end 08:00During the quiet window it does not call opencode serve. Stop anytime with touch .squad/ralph-stop.
watch --health prints the last ralph-status.json snapshot. --state-backend git-notes or orphan-branch persists that snapshot across restarts (default is the local file).
Original-Squad / Copilot-host pieces we are not building:
- GitHub Copilot CLI / Copilot SDK
- Interactive Ink/
squadshell (use the OpenCode TUI) - Aspire / .NET dashboard (traces are local OTLP JSON, not Aspire)
go test ./...
go build -o squad-oc ./cmd/squad-ocRequires Go 1.26.6+. How to send a change: CONTRIBUTING.md.
MIT — see LICENSE.