Skip to content
Merged
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
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Do not force-push to the default branch. Do not rewrite published tags.
```

4. The release workflow checks the tag is on `origin/main`, waits for `ci`, then GoReleaser publishes.
5. Refresh `Formula/squad-oc.rb`, `bucket/squad-oc.json`, and `packaging/winget/` from that tag's `checksums.txt` so package managers pin the new assets.

`go build` (and CI's compile job) report `dev`. GoReleaser injects the tag into `version.Version`, so `squad-oc version` on a release binary matches the tag. Do not edit `internal/version/version.go` to bump the version.

Expand Down
34 changes: 34 additions & 0 deletions Formula/squad-oc.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class SquadOc < Formula
desc "Human-led AI agent teams for OpenCode"
homepage "https://github.com/xeaser/squad-opencode"
version "0.4.0"
license "MIT"

on_macos do
if Hardware::CPU.arm?
url "https://github.com/xeaser/squad-opencode/releases/download/v0.4.0/squad-oc_0.4.0_darwin_arm64.tar.gz"
sha256 "e2c662e3895a7b937aa0539b354fc6705dd56fdb833cd7222d63d07d4afb546b"
else
url "https://github.com/xeaser/squad-opencode/releases/download/v0.4.0/squad-oc_0.4.0_darwin_amd64.tar.gz"
sha256 "ee6f9417b71e96904c8522299f8243d46a785b724b66d31c869051d734fd7777"
end
end

on_linux do
if Hardware::CPU.arm?
url "https://github.com/xeaser/squad-opencode/releases/download/v0.4.0/squad-oc_0.4.0_linux_arm64.tar.gz"
sha256 "e8fa3657fb9b270fc87ef3f24c2236fa751664597245d2976124541933abaf21"
else
url "https://github.com/xeaser/squad-opencode/releases/download/v0.4.0/squad-oc_0.4.0_linux_amd64.tar.gz"
sha256 "c54df6f427bc97b3fbf7a337fe9806e0a29bc69864f9c36133879d24e65a7c0a"
end
end

def install
bin.install "squad-oc"
end

test do
assert_match version.to_s, shell_output("#{bin}/squad-oc version")
end
end
28 changes: 22 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,36 @@ One binary scaffolds a persistent team in your repo (`.squad/`) and OpenCode age
> Inspired by [bradygaster/squad](https://github.com/bradygaster/squad) (MIT). OpenCode-native port — not a Copilot fork.
> Host API client: official [opencode-sdk-go](https://github.com/anomalyco/opencode-sdk-go) (`github.com/sst/opencode-sdk-go`).

## Install

No Go toolchain. Download the archive for your OS from [GitHub Releases](https://github.com/xeaser/squad-opencode/releases/latest) and put `squad-oc` on your `PATH`. Assets are `squad-oc_<version>_<os>_<arch>.zip` (Windows) or `.tar.gz` (macOS/Linux).

```bash
# 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

# winget (from a clone of this repo)
winget install --manifest packaging/winget
```

`squad-oc upgrade --self` replaces the binary from the latest release.

## Quick start

```bash
# 1. Install OpenCode + /connect a provider — https://opencode.ai/docs/

# 2. Build squad-oc
git clone <this-repo> && cd squad-opencode
go build -o squad-oc ./cmd/squad-oc
# optional: move squad-oc onto your PATH
# 2. Install squad-oc from GitHub Releases (see Install above)

# 3. In your project
mkdir my-app && cd my-app && git init
/path/to/squad-oc init --preset default
/path/to/squad-oc doctor
squad-oc init --preset default
squad-oc doctor

# Interactive TUI (does not listen on :4096)
opencode
Expand Down
24 changes: 24 additions & 0 deletions bucket/squad-oc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"version": "0.4.0",
"description": "Human-led AI agent teams for OpenCode",
"homepage": "https://github.com/xeaser/squad-opencode",
"license": "MIT",
"architecture": {
"64bit": {
"url": "https://github.com/xeaser/squad-opencode/releases/download/v0.4.0/squad-oc_0.4.0_windows_amd64.zip",
"hash": "7efffa39f33820db229cf5a7a2b1a5ff887b83b0c55df0553625aa0ecd5cc0d8"
}
},
"bin": "squad-oc.exe",
"checkver": "github",
"autoupdate": {
"architecture": {
"64bit": {
"url": "https://github.com/xeaser/squad-opencode/releases/download/v$version/squad-oc_$version_windows_amd64.zip"
}
},
"hash": {
"url": "https://github.com/xeaser/squad-opencode/releases/download/v$version/checksums.txt"
}
}
}
29 changes: 21 additions & 8 deletions docs/get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ Zero to first team. You do **not** need GitHub Copilot, Node, or the original Sq
| Need | Why |
|------|-----|
| Terminal | Install and run tools |
| **Go 1.26.6+** (to build `squad-oc`) | Or a prebuilt binary when published |
| Git | Project + recommended for real work |
| An LLM provider | OpenCode talks to a model |

Expand Down Expand Up @@ -69,16 +68,31 @@ git commit -m "chore: initial commit"

---

## 4. Build and install `squad-oc`
## 4. Install `squad-oc`

From this repository:
You do **not** need Go. Download the archive for your OS from [GitHub Releases](https://github.com/xeaser/squad-opencode/releases/latest) and put `squad-oc` (`squad-oc.exe` on Windows) on your `PATH`. Assets are `squad-oc_<version>_<os>_<arch>.zip` (Windows) or `.tar.gz` (macOS/Linux).

**Scoop**

```powershell
scoop bucket add squad https://github.com/xeaser/squad-opencode
scoop install squad-oc
```

**Homebrew**

```bash
cd /path/to/squad-opencode
go build -o squad-oc ./cmd/squad-oc
brew tap xeaser/squad-opencode https://github.com/xeaser/squad-opencode
brew install squad-oc
```

**winget** (from a clone of this repo)

```powershell
winget install --manifest packaging/winget
```

Put the binary on your `PATH`, or call it with a full path.
Update later with `squad-oc upgrade --self`.

Check:

Expand Down Expand Up @@ -121,7 +135,6 @@ To refresh OpenCode agents/skills after a `squad-oc` update (team files stay put
```bash
squad-oc upgrade --dry-run
squad-oc upgrade
squad-oc upgrade --self
```

Validate:
Expand Down Expand Up @@ -252,7 +265,7 @@ squad-oc status
| No **squad** agent | `squad-oc init --preset default` in project root |
| `Not initialized` | `squad-oc init --preset default` |
| Server probe FAIL only | Soft check — run `opencode serve` for the HTTP API on :4096 |
| Build fails | `go version` ≥ 1.26.6; `go mod tidy` |
| `squad-oc: command not found` | Download a release binary; fix PATH |

---

Expand Down
2 changes: 1 addition & 1 deletion docs/use-cases.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Each original-Squad ease row is a **squad-oc command** you already ran, a **late

| Original ease | Mapping |
|---------------|---------|
| `npm i -g @bradygaster/squad-cli` | `go build -o squad-oc ./cmd/squad-oc` (put it on `PATH`) |
| `npm i -g @bradygaster/squad-cli` | GitHub Releases / Scoop / Homebrew / winget (put `squad-oc` on `PATH`) |
| `squad init` / `npx squad init` | `squad-oc init --preset default` |
| `squad init` with a blurb | `squad-oc init --preset default --description "…"` |
| Personal / global team | `squad-oc init --global` |
Expand Down
23 changes: 15 additions & 8 deletions docs/workshop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ Modeled on [Tamir's original-Squad workshop](https://github.com/tamirdresher/squ
| Need | Why |
|------|-----|
| Terminal | Run tools |
| **Go 1.26.6+** (to build `squad-oc`) | Or a prebuilt binary when published |
| Git | Project + recommended for real work |
| [OpenCode](https://opencode.ai) | Host TUI and `opencode serve` |
| An LLM provider | OpenCode talks to a model |
Expand Down Expand Up @@ -74,16 +73,24 @@ Inside OpenCode:
3. Paste your API key
4. Quit when done

### Build `squad-oc` and put it on `PATH`
### Install `squad-oc` and put it on `PATH`

From this repository:
You do **not** need Go. Download the archive for your OS from [GitHub Releases](https://github.com/xeaser/squad-opencode/releases/latest) and put `squad-oc` (`squad-oc.exe` on Windows) on your `PATH`. Assets are `squad-oc_<version>_<os>_<arch>.zip` (Windows) or `.tar.gz` (macOS/Linux).

```bash
cd /path/to/squad-opencode
go build -o squad-oc ./cmd/squad-oc
# 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

# winget (from a clone of this repo)
winget install --manifest packaging/winget
```

Put the binary on your `PATH`, or call it with a full path. On Windows the file is `squad-oc.exe`.
Later: `squad-oc upgrade --self`.

### Try it

Expand Down Expand Up @@ -671,7 +678,7 @@ Each original ease row is a **squad-oc command** you already ran, a **later** co

| Original ease | squad-oc |
|---------------|----------|
| `npm i -g @bradygaster/squad-cli` | `go build` / put `squad-oc` on `PATH` |
| `npm i -g @bradygaster/squad-cli` | GitHub Releases / Scoop / Homebrew / winget |
| `squad init` | `squad-oc init --preset default` |
| `copilot --agent squad` | `opencode` → Tab → **squad** |
| `squad status` | `squad-oc status` |
Expand All @@ -696,7 +703,7 @@ Each original ease row is a **squad-oc command** you already ran, a **later** co

| Problem | Try |
|---------|-----|
| `squad-oc: command not found` | Build from this repo; fix `PATH` |
| `squad-oc: command not found` | Install from GitHub Releases; fix `PATH` |
| `opencode: command not found` | Install OpenCode; fix `PATH` |
| No **squad** agent | `squad-oc init --preset default` in the project root |
| `Not initialized` | `squad-oc init --preset default` |
Expand Down
90 changes: 90 additions & 0 deletions internal/version/packaging_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package version

import (
"encoding/json"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
)

func TestPackagingPinsReleaseRepo(t *testing.T) {
root := repoRoot(t)
files := []string{
filepath.Join("bucket", "squad-oc.json"),
filepath.Join("Formula", "squad-oc.rb"),
filepath.Join("packaging", "winget", "xeaser.squad-oc.yaml"),
}
repoURL := "https://github.com/" + Repo
asset := regexp.MustCompile(Name + `_\d+\.\d+\.\d+_(windows_amd64\.zip|darwin_(amd64|arm64)\.tar\.gz|linux_(amd64|arm64)\.tar\.gz)`)
for _, rel := range files {
body, err := os.ReadFile(filepath.Join(root, rel))
if err != nil {
t.Fatalf("%s: %v", rel, err)
}
s := string(body)
if !strings.Contains(s, Repo) {
t.Errorf("%s: missing repo %q", rel, Repo)
}
if !strings.Contains(s, repoURL) {
t.Errorf("%s: missing %s", rel, repoURL)
}
if !asset.MatchString(s) {
t.Errorf("%s: missing goreleaser asset name", rel)
}
}

raw, err := os.ReadFile(filepath.Join(root, "bucket", "squad-oc.json"))
if err != nil {
t.Fatal(err)
}
var scoop struct {
Checkver string `json:"checkver"`
Autoupdate struct {
Hash struct {
URL string `json:"url"`
} `json:"hash"`
} `json:"autoupdate"`
}
if err := json.Unmarshal(raw, &scoop); err != nil {
t.Fatalf("scoop manifest: %v", err)
}
if scoop.Checkver != "github" {
t.Fatalf("scoop checkver = %q, want github", scoop.Checkver)
}
if !strings.Contains(scoop.Autoupdate.Hash.URL, Repo+"/releases/download/") || !strings.HasSuffix(scoop.Autoupdate.Hash.URL, "checksums.txt") {
t.Fatalf("scoop autoupdate hash url = %q", scoop.Autoupdate.Hash.URL)
}
}

func TestUserDocsDoNotLeadWithGoBuild(t *testing.T) {
root := repoRoot(t)
for _, rel := range []string{
filepath.Join("docs", "get-started.md"),
filepath.Join("docs", "workshop", "README.md"),
} {
body, err := os.ReadFile(filepath.Join(root, rel))
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(body), "go build") {
t.Errorf("%s: go build belongs in Develop/CONTRIBUTING only", rel)
}
}
readme, err := os.ReadFile(filepath.Join(root, "README.md"))
if err != nil {
t.Fatal(err)
}
s := string(readme)
dev := strings.Index(s, "## Develop")
if dev < 0 {
t.Fatal("README missing ## Develop")
}
if strings.Contains(s[:dev], "go build") {
t.Error("README leads with go build")
}
if !strings.Contains(s[dev:], "go build") {
t.Error("README Develop should keep go build")
}
}
27 changes: 27 additions & 0 deletions packaging/winget/xeaser.squad-oc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# yaml-language-server: $schema=https://aka.ms/winget-manifest.singleton.1.6.0.schema.json
PackageIdentifier: xeaser.squad-oc
PackageVersion: 0.4.0
PackageLocale: en-US
Publisher: xeaser
PublisherUrl: https://github.com/xeaser
PackageName: squad-oc
PackageUrl: https://github.com/xeaser/squad-opencode
License: MIT
LicenseUrl: https://github.com/xeaser/squad-opencode/blob/main/LICENSE
ShortDescription: Human-led AI agent teams for OpenCode
Moniker: squad-oc
Tags:
- opencode
- squad
ReleaseNotesUrl: https://github.com/xeaser/squad-opencode/releases/tag/v0.4.0
Installers:
- Architecture: x64
InstallerType: zip
NestedInstallerType: portable
NestedInstallerFiles:
- RelativeFilePath: squad-oc.exe
PortableCommandAlias: squad-oc
InstallerUrl: https://github.com/xeaser/squad-opencode/releases/download/v0.4.0/squad-oc_0.4.0_windows_amd64.zip
InstallerSha256: 7EFFFA39F33820DB229CF5A7A2B1A5FF887B83B0C55DF0553625AA0ECD5CC0D8
ManifestType: singleton
ManifestVersion: 1.6.0