# Squad Init

> Register the current project on the Squad board so /squad commands target it. Usage: /squad-init or /squad-init my-project-name. Run with /squad-init.

- Skill: `steloit/squad-init` (Agent Skill)
- Install (CLI): `npx skillmds@latest add steloit/squad-init`
- Raw SKILL.md: https://api.skillmd.com/api/skills/steloit/squad-init/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: steloit (https://skillmd.com/u/steloit)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/steloit/squad-init

---


Registers the current project in **PostgreSQL** (shared central DB) and creates a local config so `/squad` knows which project to use.
No per-project DB file is created — the central PostgreSQL server handles storage for all projects automatically.

## Usage

```
/squad-init                                      — project name = basename of current directory, board = https://squad-api-285415501393.asia-south1.run.app
/squad-init my-project-name                      — explicit project name, board = https://squad-api-285415501393.asia-south1.run.app
/squad-init my-project-name https://board.example.com
                                                 — explicit project name + custom board URL
/squad-init https://board.example.com           — current directory name + custom board URL
```

If a URL argument is present, treat it as `base_url`. Strip any leading dashes from the project token: `squad-init -unahouse.finance` → project `unahouse.finance`.

## Procedure

### 1. Determine project name and board URL

```bash
# Split raw args
set -- $ARG
ARG1="${1:-}"
ARG2="${2:-}"

# Accept either:
#   /squad-init my-project
#   /squad-init my-project https://board.example.com
#   /squad-init https://board.example.com
if printf '%s' "$ARG1" | grep -Eq '^https?://'; then
  PROJECT=$(basename "$(pwd)")
  BASE_URL="$ARG1"
else
  PROJECT=$(printf '%s' "$ARG1" | sed 's/^-*//')
  [ -z "$PROJECT" ] && PROJECT=$(basename "$(pwd)")
  BASE_URL="${ARG2:-https://squad-api-285415501393.asia-south1.run.app}"
fi
```

### 2. Write local project config

Create **one** tool-agnostic file at the **current project root**, committed to git so the whole team's agents target the same board project:

`.squadrc`
```
SQUAD_PROJECT=<PROJECT_NAME>
SQUAD_ORG=<ORG_SLUG>          # REQUIRED — every board call is org-scoped (/api/orgs/<org>/...)
```

**`.squadrc` holds the project name and the org slug** (both non-secret → safe to commit). The `SQUAD_ORG=<slug>` line is **REQUIRED** and **ALWAYS** written — every board call is org-scoped (`/api/orgs/<org>/...`), including squad-init's own `POST /api/orgs/<org>/projects`. Resolve the slug from an explicit init arg or the mint dialog's `SQUAD_ORG=<slug>` line (env or an existing `.squadrc`):

```bash
# Org slug — env (the mint dialog exports it) > existing .squadrc. REQUIRED.
SQUAD_ORG="${SQUAD_ORG:-}"
[ -z "$SQUAD_ORG" ] && [ -f .squadrc ] && SQUAD_ORG=$(grep '^SQUAD_ORG=' .squadrc | cut -d= -f2-)
if [ -z "$SQUAD_ORG" ]; then
  echo "ERROR: SQUAD_ORG is not set. Every board call is org-scoped (/api/orgs/<org>/...)." >&2
  echo "Set it from the mint dialog's \`SQUAD_ORG=<slug>\` line — add \`SQUAD_ORG=<slug>\` to .squadrc" >&2
  echo "(committed) or export SQUAD_ORG=<slug> for this shell. Resolution order: env > .squadrc." >&2
  exit 1
fi
```

The slug is **never** auto-derived from the board (the project API exposes no org slug today — a noted follow-up). The token never lives in `.squadrc`; it lives in `~/.squad/auth` as the bare `SQUAD_AUTH_TOKEN=` line.

Use the Write tool to create `.squadrc` with **both** the `SQUAD_PROJECT=` and the `SQUAD_ORG=<slug>` lines (always write `SQUAD_ORG`; if no slug can be resolved, stop with the error above — do NOT register without it).

### 2b. Detect auth (no token store here)

The token is resolved via the shared.md chain (env > bare `SQUAD_AUTH_TOKEN=`). squad-init **never** stores a token, **never** echoes/cats it, and **never** asks for a pasted one — the token-store command lives **only** at the web mint UI — Settings → Personal Access Tokens (the single place the real token exists). On no token, squad-init just prints a one-line POINTER to that UI:

```bash
# Detect whether a token is configured (env > bare `SQUAD_AUTH_TOKEN=`) to decide the warning
# below — never echo it. The board call itself goes through api.py, which owns the header.
SQUAD_ORG="${SQUAD_ORG:-}"
[ -z "$SQUAD_ORG" ] && [ -f .squadrc ] && SQUAD_ORG=$(grep '^SQUAD_ORG=' .squadrc | cut -d= -f2-)
AUTH_TOKEN="${SQUAD_AUTH_TOKEN:-}"; AUTH_SOURCE=$([ -n "$AUTH_TOKEN" ] && echo env || echo none)
if [ -z "$AUTH_TOKEN" ] && [ -f "$HOME/.squad/auth" ]; then
  AUTH_TOKEN=$(grep '^SQUAD_AUTH_TOKEN=' "$HOME/.squad/auth" | cut -d= -f2-)
  [ -n "$AUTH_TOKEN" ] && AUTH_SOURCE=file
fi

if [ -z "$AUTH_TOKEN" ]; then
  echo "No Squad Personal Access Token configured — mint one in your Squad board's web UI (Settings → Personal Access Tokens) and run the store command it shows."
fi

# Persist a custom (non-default) board URL only — to ~/.squad/config
if [ -n "$BASE_URL" ] && [ "$BASE_URL" != "https://squad-api-285415501393.asia-south1.run.app" ]; then
  mkdir -p "$HOME/.squad"
  grep -q '^SQUAD_BASE_URL=' "$HOME/.squad/config" 2>/dev/null || printf 'SQUAD_BASE_URL=%s\n' "$BASE_URL" >> "$HOME/.squad/config"
fi
```

### 2c. Auto-register project in projects table

After writing the config, upsert the current project to the projects table via POST /api/projects.
Infer project metadata from the local environment:

```bash
# Category defaults to "personal"; change it on the board if needed.
CATEGORY="personal"
echo "$PROJECT" | grep -qiE 'skill|squad' && CATEGORY="skills"
echo "$PROJECT" | grep -qiE 'tool|api|cli'  && CATEGORY="tools"

# Infer purpose + stack from CLAUDE.md (best-effort)
PURPOSE=""; STACK=""
if [ -f "CLAUDE.md" ]; then
  PURPOSE=$(grep -v '^#' CLAUDE.md | grep -v '^---' | grep -v '^[[:space:]]*$' | head -1 | cut -c1-300)
  STACK=$(grep -iE 'stack|tech|typescript|javascript|python|react|vue|next|node|vite' CLAUDE.md | head -1 | cut -c1-200)
fi
REPO_URL=$(git remote get-url origin 2>/dev/null || echo "")

# Build the payload safely with jq — never interpolate file/user text into code (see shared.md "JSON Safety").
PROJ_PAYLOAD=$(jq -n \
  --arg id "$PROJECT" --arg name "$PROJECT" --arg category "$CATEGORY" \
  --arg purpose "$PURPOSE" --arg stack "$STACK" --arg repo_url "$REPO_URL" \
  '{id: $id, name: $name, category: $category,
    purpose:  (if $purpose  == "" then null else $purpose  end),
    stack:    (if $stack    == "" then null else $stack    end),
    repo_url: (if $repo_url == "" then null else $repo_url end)}')
api POST /projects --json "$PROJ_PAYLOAD" > /dev/null 2>&1 || true
```

This is best-effort — if the API call fails (e.g., board unreachable), init still succeeds.

### 3. Output confirmation

Output:
```
✅ Project '<PROJECT_NAME>' registered in squad.

  Config:  .squadrc (committed)
  Org:     <ORG_SLUG>   (required — written to .squadrc; every board call is org-scoped)
  DB:      PostgreSQL (shared central DB)
  Board:   <BASE_URL>/?project=<PROJECT_NAME>
  Auth:    Personal Access Token — SQUAD_AUTH_TOKEN env / ~/.squad/auth (global secret; configured / empty, value-free)

Add tasks with /squad add <title>
```

## Notes

### Existing config detection

If `.squadrc` already exists, read `SQUAD_PROJECT` and ask before overwriting:

```
.squadrc already exists:
  Current project: "<name>"

Options:
1. Overwrite — update SQUAD_PROJECT
2. Keep as-is — leave .squadrc unchanged
```

- `/squad-init` defaults to `https://squad-api-285415501393.asia-south1.run.app` unless you provide another deployment URL.
- Tokens are **Personal Access Tokens (PATs)** stored globally in `~/.squad/auth` (mode 600) as a bare `SQUAD_AUTH_TOKEN=` line — or the `SQUAD_AUTH_TOKEN` env var; NEVER in `.squadrc`. This keeps secrets out of git; `SQUAD_ORG` still selects the tenant per repo.
- `.squadrc` carries the project name + the **required** non-secret `SQUAD_ORG=<slug>` selector (every board call is org-scoped `/api/orgs/<org>/...`). squad-init ALWAYS writes `SQUAD_ORG` (resolved from an explicit init arg or the mint dialog's `SQUAD_ORG=<slug>` line); it is **not** board-derived (the project API exposes no org slug; auto-derive + verify is a noted follow-up). With no slug, squad-init stops with an actionable error rather than registering without one.
- squad-init **never stores or prompts for a token**: minting + the store command live only in the board's web UI — **Settings → Personal Access Tokens**. On no token it prints a one-line pointer to that UI (the breadcrumb, NOT a URL — the skill only knows the API `BASE_URL`, not the web host).
- For remote private boards, mint a **Personal Access Token** in the web UI (**Settings → Personal Access Tokens**) and run the store command it prints (writes `~/.squad/auth`, mode 600), or set `SQUAD_AUTH_TOKEN` in the shell before running `/squad-init`.

