Skip to content

feat: add SQUAD_HOME env var and preset system#1041

Merged
bradygaster merged 9 commits intobradygaster:devfrom
paulyuk:paulyuk/1038-squad-home-presets
Apr 25, 2026
Merged

feat: add SQUAD_HOME env var and preset system#1041
bradygaster merged 9 commits intobradygaster:devfrom
paulyuk:paulyuk/1038-squad-home-presets

Conversation

@paulyuk
Copy link
Copy Markdown
Contributor

@paulyuk paulyuk commented Apr 25, 2026

Summary

Adds SQUAD_HOME env var support and a preset system for reusable agent configurations, with auto-init and --remote for roaming across machines.

Origin: This feature is inspired by snap-squad, which prototyped warm-start preset squads as an external addon. The plan is to retire snap-squad immediately and point users here instead — presets belong in squad itself.

Recent Changes

  • squad init --preset auto-creates squad home — if no presets directory exists, it initializes one automatically and seeds built-in presets. No setup step needed.
  • squad preset init --remote — backs squad home with a private squad-home GitHub repo via gh. On a second machine, same command clones it.
  • preset save tips about squad export for full squad snapshots (casting, skills, routing) — e.g. to publish to agent toolboxes.

Quick Start

# Start a project with the built-in default preset
# (auto-creates ~/.squad/ and seeds presets if first run)
squad init --preset default

# Customize your agents — make it yours
# edit .squad/agents/*/charter.md, add/remove agents

# Save as your personal preset
squad preset save my-team

# Any new repo — one command
squad init --preset my-team

Roam presets across machines

# Back your squad home with a private GitHub repo (one-time per machine)
squad preset init --remote

# On your second machine — clones your presets automatically
squad preset init --remote
squad init --preset my-team

squad preset init --remote creates <you>/squad-home as a private repo via gh repo create, sets up ~/.squad/ as a clone, and pushes. On a second machine it detects the existing repo and clones it instead.


SQUAD_HOME Environment Variable

A roaming squad root directory for user-level squad assets. Presets live here.

Setup Where presets live Roaming?
Default (auto-created on first --preset use) ~/.squad/presets/ ❌ Local only
--remote (recommended) ~/.squad/presets/ backed by <you>/squad-home repo ✅ Push/pull
Custom SQUAD_HOME $SQUAD_HOME/presets/ Depends on backing

SDK functions:

  • resolveSquadHome() — resolves SQUAD_HOME env var or falls back to ~/.squad/
  • ensureSquadHome() — creates the directory if needed
  • resolvePresetsDir() — returns the presets/ subdirectory within SQUAD_HOME

Preset System

Presets are named, reusable collections of agent charters stored in SQUAD_HOME/presets/<name>/.

Built-in default preset ships with 5 agents: lead, reviewer, devrel, security, docs.

CLI Commands:

squad init --preset <name>         # init + apply preset (auto-creates squad home if needed)
squad preset init --remote         # back squad home with private GitHub repo
squad preset init                  # local-only setup
squad preset list                  # list available presets
squad preset show <name>           # show preset details and agents
squad preset apply <name>          # apply preset to existing project
squad preset save <name>           # save current agents as a preset

Collision policy: existing agents are skipped by default; use --force to overwrite.

Presets vs Export

Presets Export
What Agent charters only Full squad snapshot (casting, skills, routing rules, history)
Purpose Reusable starter kits for bootstrapping Project portability, sharing configured squads, publishing to agent toolboxes
Storage SQUAD_HOME/presets/<name>/ squad-export.json (portable file)
Roaming Yes — via --remote or SQUAD_HOME backed by git/sync Manual — share the export file

Testing

  • 24 tests covering all preset functions including full round-trip (save → apply to new project)
  • All existing tests continue to pass

Changeset

Included — minor version bump for both @bradygaster/squad-sdk and @bradygaster/squad-cli.

Resolves #1038

Add SQUAD_HOME environment variable support for a roaming squad root
directory, and a preset system for reusable agent configurations.

SQUAD_HOME:
- New resolveSquadHome() resolves SQUAD_HOME env var or falls back to ~/.squad/
- ensureSquadHome() creates the directory if it doesn't exist
- resolvePresetsDir() returns the presets subdirectory within SQUAD_HOME

Preset System:
- Presets are named collections of agent charters in a standard layout
- Built-in 'default' preset ships with 5 agents: lead, reviewer, devrel, security, docs
- Users can install presets to SQUAD_HOME and apply them to any project
- Collision policy: skip existing agents by default, --force to overwrite

CLI Commands:
- squad preset list - list available presets
- squad preset show <name> - show preset details
- squad preset apply <name> - apply preset agents to current project
- squad preset init - seed built-in presets to SQUAD_HOME

Resolves bradygaster#1038

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 25, 2026 19:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for a user-level “roaming” Squad home directory (SQUAD_HOME, defaulting to ~/.squad) and a reusable preset system (manifests + agent charters), including a new squad preset CLI command for listing/showing/applying/seeding presets.

Changes:

  • Introduce resolveSquadHome(), ensureSquadHome(), and resolvePresetsDir() in the SDK resolution layer.
  • Add SDK preset APIs (listPresets, loadPreset, applyPreset, seedBuiltinPresets) plus a built-in default preset (5 agents).
  • Add squad preset CLI subcommands and comprehensive Vitest coverage for the new behavior.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
test/presets.test.ts Adds tests for SQUAD_HOME resolution and preset listing/loading/applying/seeding.
packages/squad-sdk/src/resolution.ts Implements SQUAD_HOME + presets directory resolution helpers.
packages/squad-sdk/src/presets/types.ts Defines preset manifest/apply result types.
packages/squad-sdk/src/presets/index.ts Implements preset discovery, loading, application, and built-in seeding.
packages/squad-sdk/src/presets/builtin/default/preset.json Adds the built-in default preset manifest.
packages/squad-sdk/src/presets/builtin/default/agents/lead/charter.md Adds built-in lead agent charter.
packages/squad-sdk/src/presets/builtin/default/agents/reviewer/charter.md Adds built-in reviewer agent charter.
packages/squad-sdk/src/presets/builtin/default/agents/devrel/charter.md Adds built-in devrel agent charter.
packages/squad-sdk/src/presets/builtin/default/agents/security/charter.md Adds built-in security agent charter.
packages/squad-sdk/src/presets/builtin/default/agents/docs/charter.md Adds built-in docs agent charter.
packages/squad-sdk/src/index.ts Exposes new resolution exports from the public SDK entrypoint.
packages/squad-sdk/package.json Adds ./presets export + build step to ship built-in preset assets to dist.
packages/squad-cli/src/cli/commands/preset.ts Implements `squad preset {init
packages/squad-cli/src/cli-entry.ts Wires new preset command into CLI help + dispatch.
.changeset/squad-home-presets.md Declares a minor bump for SDK + CLI for the new feature set.

Comment thread packages/squad-sdk/src/resolution.ts Outdated
Comment thread packages/squad-sdk/src/presets/index.ts
Comment thread packages/squad-sdk/src/presets/index.ts
Comment thread packages/squad-cli/src/cli/commands/preset.ts Outdated
Comment thread packages/squad-sdk/package.json Outdated
Comment thread test/presets.test.ts Outdated
Comment thread packages/squad-sdk/src/resolution.ts
Comment thread packages/squad-sdk/src/presets/index.ts
Comment thread packages/squad-sdk/src/presets/index.ts
paulyuk and others added 2 commits April 25, 2026 13:06
Add 'squad preset save <name>' command that captures your current
project's agents as a reusable preset in SQUAD_HOME. This completes
the quick-start loop:

  1. squad preset apply default     # start with a preset
  2. (customize agents)              # make it yours
  3. squad preset save my-team       # save as your preset
  4. cd other-repo && squad preset apply my-team  # reuse everywhere

Also adds 4 new tests including full round-trip test (save → apply).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
squad init --preset default    # init + apply preset in one command
squad init --preset my-team    # use your custom preset

Automatically seeds built-in presets if needed. The quick start is now:

  1. squad init --preset default
  2. (customize agents)
  3. squad preset save my-team
  4. squad init --preset my-team   # any new repo, one command

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Collaborator

@tamirdresher tamirdresher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good with this but you might want to consider the copilot comment about the env var pointing to something which is not a folder

…shots

- Show preset save path clearly in output
- Add tip about 'squad export' for full squad snapshots (casting, skills,
  routing) — useful for sharing configured squads or publishing to agent
  toolboxes
- Update module docs with save path and export distinction

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@paulyuk
Copy link
Copy Markdown
Contributor Author

paulyuk commented Apr 25, 2026

Update: preset save messaging + export distinction

Changes in latest push:

  1. preset save now clearly shows where presets are stored — outputs the full path (e.g. ~/.squad/presets/my-team/) so users always know where their preset landed.

  2. preset save now tips users about squad export — after saving, the CLI prints:

    Tip: Presets save agents only (charters). For a full squad snapshot including casting state, skills, and routing rules — e.g. to share a configured squad or publish to an agent toolbox — use squad export.

  3. PR description updated with Presets vs Export comparison — table explaining when to use each:

    • Presets = reusable starter kits (agents/charters only, stored in SQUAD_HOME)
    • Export = full squad snapshots (casting, skills, routing, history) for sharing configured squads or publishing to agent toolboxes

Design decision (agreed with @bradygaster): preset save intentionally does NOT call export under the hood. They serve different workflows — presets are lightweight agent templates for bootstrapping new projects; export is a full project snapshot for portability and distribution.

paulyuk and others added 3 commits April 25, 2026 13:42
- 'squad preset init --remote' creates a private GitHub repo (squad-home)
  via gh CLI and sets up ~/.squad/ as a clone. On a second machine, the
  same command detects the existing repo and clones it.
- All 'preset not found' errors now nudge users toward 'squad preset init --remote'
- Plain 'squad preset init' tips about --remote for roaming
- Handles all cases: fresh setup, existing ~/.squad/, second machine clone

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When no presets directory exists, 'squad init --preset default' now
automatically initializes squad home and seeds built-in presets instead
of failing. Tips user about '--remote' for roaming.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address Copilot review comments flagged by Tamir:
- resolveSquadHome() now throws if path exists but is not a directory
- resolvePresetsDir() checks isDirectorySync before returning
- Added validateName() to reject path traversal in preset/agent names
- Build step now cleans dist/presets/builtin before copying (prevents stale files)
- Fixed misleading test name

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@paulyuk
Copy link
Copy Markdown
Contributor Author

paulyuk commented Apr 25, 2026

Thanks @tamirdresher! Great catch 🙏

Addressed the Copilot review comment you flagged plus all 9 suggestions in 099d55eb:

  1. SQUAD_HOME directory validationresolveSquadHome() now throws if the path exists but is not a directory (exactly the scenario you flagged). resolvePresetsDir() also checks isDirectorySync() before returning.
  2. Path traversal protection — Added validateName() that rejects preset/agent names containing ../, path separators, or other unsafe patterns. Applied in applyPreset(), savePreset(), and per-agent during apply.
  3. Stale build cleanup — Build step now rmSync()s dist/presets/builtin before copying, so renamed/deleted builtins don't linger.
  4. Misleading test name — Fixed to match actual behavior.

All 24 tests passing ✅

- Use lstatSync in copyDirRecursive to skip symlinks (prevents following
  symlinks into unintended locations)
- Clean dest dir before copy on --force (prevents stale files from
  renamed/deleted agents lingering)
- Remove duplicate glyphs in CLI output (success()/warn() already add markers)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@paulyuk
Copy link
Copy Markdown
Contributor Author

paulyuk commented Apr 25, 2026

🧪 E2E Test Results — Quick Start + Roaming Workflow

Ran 13 end-to-end tests against the branch using a temp SQUAD_HOME (clean environment, no pre-existing state). All 13 pass

Quick Start Flow (the README happy path)

# Test Result
1 squad init --preset default — auto-creates squad home, seeds built-ins, installs 5 agents
2 Customize agents — add a custom agent manually
3 squad preset save my-team — saves 6 agents (5 default + 1 custom) to SQUAD_HOME
4 squad init --preset my-team in a new project — bootstraps from saved preset

Preset Commands

# Test Result
5 squad preset list — shows default + my-team (2 presets)
6 squad preset show my-team — shows 8 agents with descriptions
7 squad preset show default — shows 5 built-in agents

Collision Policy

# Test Result
8 Apply to existing project — all 8 agents skipped (no data loss)
9 Apply with --force — all 8 agents overwritten cleanly

Security / Edge Cases

# Test Result
10 Path traversal (../../../etc) — rejected with clear error
11 SQUAD_HOME pointing to a file — throws "not a directory" error (Tamir's feedback)

Roaming Simulation

# Test Result
12 squad preset init (local) — initializes and seeds presets
13 Third project reuses saved preset — custom agents round-trip correctly

Note: squad preset init --remote (GitHub repo creation/cloning) was not tested here to avoid creating real repos, but the code path is covered by the 24 unit tests.

Tested on: macOS, Node 22, branch paulyuk/1038-squad-home-presets @ 0157319

Split long pipe-separated usage strings into multi-line format
in both preset.ts (error message) and cli-entry.ts (help output)
so the ux-gates.test.ts line-length check passes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Owner

@bradygaster bradygaster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no big concerns but flagging some stuff. ;)

if (seeded.length > 0) {
info(` Built-in presets installed: ${seeded.join(', ')}`);
}
info(` Run 'squad preset list' to see available presets.`);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this and init related features don't collide with the --roles switch, you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked all good.

if (!repoExists) {
info(`Creating private repo ${repoFullName}...`);
try {
execSync(`gh repo create ${repoName} --private --source "${homeDir}" --push --description "Squad home — presets and config"`, {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i presume we don't want a git-provider unspecific way?

if (!presetsDir) {
info('No presets directory found.');
info(' Run `squad preset init --remote` to set up with a GitHub repo (recommended).');
info(' Or `squad preset init` for local-only setup.');
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add --no-workflows here, too

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

making a new issue to track.

@@ -0,0 +1,30 @@
# devrel — Developer Relations

> I make your project approachable — if a developer can't get started in 5 minutes, that's on me.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice rule

@bradygaster bradygaster merged commit ef30286 into bradygaster:dev Apr 25, 2026
6 checks passed
@bradygaster
Copy link
Copy Markdown
Owner

thanks @paulyuk !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Global SQUAD_HOME for roaming agents across repos

4 participants