SuperAPI AI Directory

squad

Office & productivity

View repository

Updated 10-16 02:02

About this skill

Shared context: read shared.md for project config & auth, pipeline levels, status transitions, API endpoints, error handling, and agent context flow. Safety principles: read principles.md — mandatory, not optional.

Commands

/squad or /squad list — View Board

BOARD=$(api GET /board?summary=true)

Output: markdown table with ID, Status, Priority, Title.

Epics: the board response carries an epics aggregate (each with children_progress and a derived epic_status). Group children under their epic from this aggregate + the embedded parent/children edges — never from tag parsing (see shared.md → Task Relationships & Epics). Show each epic's children_progress (e.g. 2/5 done).

/squad context — Session Handoff

Run first when starting a new session. Fetch board and output pipeline state: Implementing / Plan Review / Impl Review / Testing / Recently Done / Next Todo.

BOARD=$(api GET /board?summary=true)

/squad add <title> — Add Task

  1. Ask user for priority, level (L1/L2/L3), description, tags (use AskUserQuestion)
  2. Build JSON safely with jq (see shared.md → JSON Safety), POST to API, capture the new task ID. tags MUST be a JSON array — the canonical stored format the board renders. Split the user's comma-separated input into an array, e.g. --arg tags "$TAGS" then tags: ($tags | split(",") | map(gsub("^ +| +$";""))) in the jq body (no tags → omit the field or pass [], never "").
  3. Images: if the user gave image file path(s) (e.g. /squad add "Login bug" --image ./bug.png, or "attach ./shot.png"), upload each to the new task via the attachment API (see shared.md → "Upload an image attachment"). Output the task ID + the returned attachment url(s). A pasted image with no path → ask the user to save it to a file first (the upload reads a local file).

/squad move <ID> <status> — Move Task

Always follow shared.md → Move Protocol in order. Step 1 (check current status + level) → Step 2 (consult the matrix) → Step 3 (execute the move). On 400: self-correct once via the response's .allowed[0]; notify the user after 2 failures.

/squad edit <ID> — Edit Task

Ask user which fields to modify, then PATCH via API. To attach an image to an existing task, upload a local image file via the attachment API (shared.md → "Upload an image attachment").

/squad complete <ID> [note] — Complete Task (administrative completion)

Mark a task done from any non-terminal status. This is non-interactive — no AskUserQuestion, no confirmation prompt; completing is history-preserving and reversible, so just do it.

NOTE="$*"   # everything after the ID; may be empty
# omit/empty note → send {} ; otherwise send {"completion_note": "<note>"}
if [ -n "$NOTE" ]; then
  api POST /task/$ID/complete --json "$(jq -n --arg n "$NOTE" '{completion_note:$n}')"
else
  api POST /task/$ID/complete --json '{}'
fi
# → {"success":true,"status":"done","version":<int>}

Complete is the paired twin of /squad cancel: complete = finished, cancel = won't-do. Both are history-preserving (plan, notes, comments, counts, results are kept) and reversible via /squad reopen, unlike the irreversible /squad remove (a hard DELETE). Re-completing an already-done task is a safe no-op; a cancelled target returns 409 — reopen it first. The card records completed_via:"admin" (vs "pipeline" for a gated pipeline finalize) plus the optional completion_note.

/squad cancel <ID> [reason] — Cancel Task (preferred abandon verb)

Cancel a task from any status. This is non-interactive — no AskUserQuestion, no confirmation prompt; cancelling is history-preserving and reversible, so just do it.

REASON="$*"   # everything after the ID; may be empty
# omit/empty reason → send {} ; otherwise send {"cancel_reason": "<reason>"}
if [ -n "$REASON" ]; then
  api POST /task/$ID/cancel --json "$(jq -n --arg r "$REASON" '{cancel_reason:$r}')"
else
  api POST /task/$ID/cancel --json '{}'
fi
# → {"success":true,"status":"cancelled","version":<int>}

Cancel is the preferred way to abandon work: it is history-preserving (plan, notes, comments, counts, results are kept) and reversible via /squad reopen. Re-cancelling an already-cancelled task is a safe no-op. Use it for won't-do / superseded / deprioritized work instead of /squad remove.

/squad reopen <ID> — Reopen Task (the un-cancel / un-complete path)

Restore a terminal task (cancelled OR done) back to todo. This is the un-cancel and un-complete path — reopening clears lifecycle timestamps, current_agent, cancel_reason, completion_note, and completed_via, and preserves prior work.

api POST /task/$ID/reopen --json '{"reason": "<why reopening>"}'
# → {"success":true,"status":"todo","version":<int>}

Reopening a non-terminal task (anything other than cancelled/done) returns 409 and changes nothing.

/squad remove <ID> — Delete Task

api DELETE /task/$ID

remove is a hard DELETE — irreversible (the card and its attachments are gone). Reserve it for never-started mistakes / duplicates. For won't-do or superseded work, prefer /squad cancel (history-preserving and reversible).

/squad stats — Statistics

Column counts come from the board summary; per-actor token/event totals come from a single GET /api/activity/stats call (server-side GROUP BY actor — no per-task loop, no board fetch for tokens).

export BOARD=$(api GET /board?summary=true)
export STATS=$(api GET /activity/stats)
python3 << 'PY'
import json, os

board = json.loads(os.environ['BOARD'])
stats = json.loads(os.environ['STATS'])
columns = ['todo', 'plan', 'plan_review', 'impl', 'impl_review', 'test', 'done', 'cancelled']

# Column counts (summary is keyed by status, each an array of cards)
counts = {col: len(board.get(col, [])) for col in columns}
counts['total'] = sum(counts.values())
print("## Column Counts\n")
print("| Status | Count |")
print("|--------|-------|")
for col in columns:
    print(f"| {col} | {counts[col]} |")
print(f"| **total** | **{counts['total']}** |")

# Per-actor token/event stats — tolerant reader: pull only the fields we use,
# treat a null/missing per-actor `tokens` as unknown (render —, never coerce to 0,
# never do arithmetic over a null), and ignore any unknown/extra fields the server adds.
rows = stats.get('stats', [])
totals = stats.get('totals', {})
print("\n## Agent Token Usage\n")
if not rows:
    print("No token data")
else:
    print("| Actor | Events | Tokens | Coverage |")
    print("|-------|--------|--------|----------|")
    for r in sorted(rows, key=lambda r: r.get('actor', '')):
        events = r.get('events', 0)
        tok = r.get('tokens')
        reported = r.get('reported')
        tok_cell = "—" if tok is None else f"{tok:,}"
        if reported is None:
            cov_cell = "—"
        elif reported < events:
            cov_cell = f"{reported}/{events} (partial)"
        else:
            cov_cell = f"{reported}/{events}"
        print(f"| {r.get('actor', 'unknown')} | {events} | {tok_cell} | {cov_cell} |")
    tot_tok = totals.get('tokens')
    tot_tok_cell = "—" if tot_tok is None else f"{tot_tok:,}"
    print(f"| **Total** | **{totals.get('events', 0)}** | **{tot_tok_cell}** | |")
PY

/squad project — Current Project Context (AI Context Docking)

Fetch the current project's context from the projects table. Use this at the start of a session to load project purpose, stack, brief, relationships, and task counts in one call.

PROJECT_DATA=$(api GET /projects/$PROJECT)

Output: formatted project context including:

  • Purpose (WHY this project exists)
  • Stack (technologies used)
  • Brief (compressed current state + direction + recent decisions)
  • Category and status
  • Task counts by status
  • Links to related projects

If the project is not registered, suggest running /squad-init to register it.

/squad project all — Full Project Map

Fetch all projects grouped by category. Useful for understanding the full project landscape.

ALL_PROJECTS=$(api GET /projects)

Output: projects grouped by category (e.g. personal, tools, skills) with names and purposes.

/squad project brief — View/Update Project Brief

The brief is a compressed context summary (200–500 chars) that agents consume at low token cost.

View current brief:

api GET /projects/$PROJECT | jq -r '.brief // "No brief set"'

Set brief directly:

api PATCH /projects/$PROJECT --json '{"brief": "..."}'

AI-assisted update (/squad project brief update):

  1. Fetch current project info + recent done tasks (GET /api/board?project=$PROJECT&summary=true)
  2. Analyze: current state, recent completions, active direction
  3. Draft a concise brief (200–500 chars) covering: what exists now, where we're heading, recent key decisions
  4. Present to user for confirmation → PATCH to save

/squad project update <field> <value> — Edit Project Metadata

Update any project field via PATCH:

# Update purpose
api PATCH /projects/$PROJECT --json '{"purpose": "new purpose"}'

# Archive project
api PATCH /projects/$PROJECT --json '{"status": "archived"}'

Supported fields: name, purpose, stack, brief, status, category, repo_url.

/squad project link — Manage Project Relationships

# Add relationship
api POST /projects/$PROJECT/links --json '{"target_id": "other-project", "relation": "depends_on"}'

# Remove relationship
api DELETE /projects/$PROJECT/links --json '{"target_id": "other-project", "relation": "depends_on"}'

Relations: extends, serves, depends_on, shares_data.

/squad observe status|dry-run — Observation Consent (read-only)

Inspect the observation-consent gate. Read-only — the opt-in/opt-out act lives in the web app (Settings → Observation & Consent); the skill never grants or withdraws. See shared.md → Observation & Consent.

observe() { python3 ../squad/scripts/observe.py "$@"; }

# status — effective on/off, the source that decided it (env override / server
# consent / default), the policy_version on record, and the web-app manage pointer.
observe status            # human-readable;  add --json for the decision object

# dry-run — print the ABSTRACTED user_steering payload that WOULD be recorded to
# stdout (pipeable to jq) + a `# DRY RUN` banner to stderr. Writes/sends NOTHING,
# in any consent state — inspect before opting in.
observe dry-run | jq .

There is no grant/withdraw here — opt in or out in the web app.

Setup & Web Board

Run /squad-init first to register this project — it writes .squadrc (SQUAD_PROJECT=…, plus an optional SQUAD_ORG=<label> org selector) at the repo root, committed so your whole team's agents target the same board project. The token never goes in a project file — it's a Personal Access Token resolved as SQUAD_AUTH_TOKEN env > bare SQUAD_AUTH_TOKEN= from ~/.squad/auth (see shared.md).

Open the deployed board at https://squad.steloit.com/?project=<PROJECT> (or via the configured SQUAD_BASE_URL). Features: 7-column pipeline, drag-and-drop (valid transitions only), card lifecycle modal, agent log viewer, 10s auto-refresh.