scripts/bash/setup-team.sh
#!/usr/bin/env bash
set -euo pipefail
PROJECT_ROOT="${PROJECT_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
BRANCH="${BRANCH:-$(git branch --show-current 2>/dev/null || echo 'unknown')}"
TEAM_AI_DIRECTIVES=""
# JSON output always goes through jq -n (no manual string building).
INIT_OPTIONS="${PROJECT_ROOT}/.adlc/init-options.json"
if [[ -f "$INIT_OPTIONS" ]]; then
# jq is required for this read — no silent fallback to the default path.
if ! command -v jq >/dev/null 2>&1; then
echo "ERROR: jq is required but not installed (https://jqlang.github.io/jq/download/)" >&2
exit 1
fi
TEAM_AI_DIRECTIVES=$(jq -r '.team_ai_directives // empty' "$INIT_OPTIONS" 2>/dev/null || true)
fi
if [[ -z "$TEAM_AI_DIRECTIVES" ]]; then
TEAM_AI_DIRECTIVES="${PROJECT_ROOT}/team-ai-directives"
fi
if [[ "${1:-}" == "--json" || "${1:-}" == "-Json" ]]; then
jq -n \
--arg repo_root "$PROJECT_ROOT" \
--arg team_ai_directives "$TEAM_AI_DIRECTIVES" \
--arg branch "$BRANCH" \
'{"REPO_ROOT":$repo_root,"TEAM_AI_DIRECTIVES":$team_ai_directives,"BRANCH":$branch}'
else
echo "REPO_ROOT=$PROJECT_ROOT"
echo "TEAM_AI_DIRECTIVES=$TEAM_AI_DIRECTIVES"
echo "BRANCH=$BRANCH"
fi
scripts/powershell/setup-team.ps1
param(
[switch]$Json
)
###############################################################################
# Inline path resolution (matches team setup scripts)
###############################################################################
$ProjectRoot = if ($env:PROJECT_ROOT) { $env:PROJECT_ROOT } else {
try { (git rev-parse --show-toplevel 2>$null) } catch { $null }
}
if (-not $ProjectRoot) { $ProjectRoot = (Get-Location).Path }
$Branch = if ($env:BRANCH) { $env:BRANCH } else {
try { (git branch --show-current 2>$null) } catch { 'unknown' }
}
if (-not $Branch) { $Branch = 'unknown' }
# Resolve team directives: env var → init-options.json → default fallback
$TeamAiDirectives = $env:TEAM_AI_DIRECTIVES
if (-not $TeamAiDirectives) {
$InitOptions = Join-Path $ProjectRoot ".adlc\init-options.json"
if (Test-Path $InitOptions) {
try {
$Opts = Get-Content $InitOptions -Raw | ConvertFrom-Json
$TeamAiDirectives = $Opts.team_ai_directives
} catch {
$TeamAiDirectives = ""
}
}
}
if (-not $TeamAiDirectives) {
$TeamAiDirectives = Join-Path $ProjectRoot "team-ai-directives"
}
if ($Json) {
@{ REPO_ROOT = $ProjectRoot; TEAM_AI_DIRECTIVES = $TeamAiDirectives; BRANCH = $Branch } | ConvertTo-Json -Compress
} else {
"REPO_ROOT=$ProjectRoot"
"TEAM_AI_DIRECTIVES=$TeamAiDirectives"
"BRANCH=$Branch"
}
SKILL.md
---
name: team-skills
description: Use when listing, adding, or onboarding team skills from the directives repo to the agent's skills directory; --all installs every default and external skill at once.
disable-model-invocation: true
---
# team-skills
> **Scope rule**: scripts stay skill-local — never source a script from another skill. For another skill's operations, invoke that skill (e.g. `team-setup`, `team-levelup`, `architect-clarify`) via the Skill tool; for its documents, follow the `Requires` line. `scripts/` and `references/` below are relative to this skill. `{REPO_ROOT}` denotes the project root (where `.adlc/` lives).
## Overview
Browse available skills from the team AI directives and install
selected ones to the current agent's skills directory. Use `--all` to
install every `default` and `external` skill in one pass. Skills are
installed under their **original names** (no prefix) so they stay in sync
with the manifest.
## When to Use
- When the user asks to browse, list, or install team skills.
- When the input names a specific skill to install.
- When extending the agent's capabilities with team-shared skills.
- When `team-setup` delegates `/team-skills --all` after initial configuration.
```text
$ARGUMENTS
```
## Core Process
### Setup
Read the file `.adlc/init-options.json` directly. Do NOT use glob, find,
or any file-search tool to locate it — search tools may silently skip
dotfile-prefixed path segments. Read the file at the exact relative path
`.adlc/init-options.json` from the current working directory.
If that read fails (file not found), walk up parent directories by reading
`../.adlc/init-options.json`, then `../../.adlc/init-options.json`,
and so on — up to 4 levels. Stop at the first successful read.
From the JSON, extract the `team_ai_directives` field:
```json
{
"team_ai_directives": "/path/to/team-ai-directives"
}
```
If `team_ai_directives` is not set, STOP:
```
Team AI directives not configured.
Run: /team-setup
```
Path resolution is skill-local:
- `bash scripts/bash/setup-team.sh --json`
- `pwsh scripts/powershell/setup-team.ps1 -Json`
### Step 1: Read Skills Manifest
Read `{REPO_ROOT}/.skills.json` (where `{REPO_ROOT}` denotes the project
root — the directory where `.adlc/` lives) and `{TEAM_AI_DIRECTIVES}/.skills.json`
(team directives manifest). Merge both, with project-root entries taking
precedence. Parse the manifest sections (schema v2.0.0):
| Section | Description | Installed by `--all`? |
|---------|-------------|-----------------------|
| `default` | Local skills (in `skills/{name}/`) auto-installed during setup | Yes |
| `external` | Remote skills fetched by URL, installed on demand | Yes |
| `blocked` | Rejected — must never be installed | Never |
### Step 2: Show Available Skills
Present skills grouped by section. For each skill show:
- Name (the key, e.g. `github-actions` for local, `react-best-practices` for external)
- Description
- Whether it's already installed (check agent skills directory)
Format:
```
Team Skills from {TEAM_AI_DIRECTIVES}
Default (local, installed by --all):
[installed] dbt-template - DBT project templates and best practices
[available] github-actions - GitHub Actions CI/CD pipeline patterns
[available] helm-charts - Helm chart patterns for Kubernetes
[available] crossplane - Crossplane Composition and XRD patterns
[available] external-secrets - External Secrets Operator patterns
[available] gke-workload-identity - GKE Workload Identity patterns
External (remote, installed by --all):
[available] react-best-practices - React performance optimization
[available] web-design-guidelines - Web interface best practices
```
### Step 3: Install Selected Skills
Determine the install target from the arguments:
- **`--all`**: Install every `default` skill **and** every `external` skill,
skipping anything in `blocked` and anything already installed.
- **A skill name**: Install that one skill directly.
- **No input**: Ask the user which skills to install.
Determine the agent's skills directory:
1. Read `.adlc/integration.json` to get the current agent
2. Use `{agent_folder}/skills/` as the destination
Install under the **original name** (no prefix), frontmatter `name` unchanged:
For **local skills** (`default` list — names map to `skills/{name}/`):
1. Locate `{TEAM_AI_DIRECTIVES}/skills/{name}/SKILL.md`
2. Copy `SKILL.md` to `{skills_dir}/{name}/SKILL.md`
For **external skills** (`external` map — entries have a `url`):
1. Check the name against `blocked` first — refuse immediately if listed.
2. Verify the entry's `url` starts with `https://` — refuse any other
scheme (`http://`, `file://`, bare paths) and report it.
3. Show the user the URL and destination, and ask for confirmation
before downloading (preview first, no silent network fetch).
4. Download `SKILL.md` from the entry's `url` field.
5. Save to `{skills_dir}/{name}/SKILL.md`.
6. Never execute downloaded content — install means copy the file only.
Never install any skill listed in `blocked`. Skip skills already present at the
destination (report them as `[installed]`).
### Step 4: Confirm
```
Installed: github-actions
Location: .opencode/skills/github-actions/SKILL.md
Source: default (local:./skills/github-actions)
```
### Notes
- Default skills are installed via `--all`, typically invoked by `team-setup`
after initial configuration or run manually at any time.
- Skills are installed under their original names — no `team-` prefix — so the
on-disk name matches the manifest key.
- Skills from the `blocked` list are never installed.
- External skills are fetched over HTTPS from the URL in the manifest.
## Common Rationalizations
| Rationalization | Why it's wrong | Do this instead |
|---|---|---|
| "I'll add a `team-` prefix to installed skills" | Diverges the on-disk name from the manifest key, breaking lookups | Install under the original name; frontmatter `name` stays unchanged |
| "Search tools will find `.adlc/init-options.json`" | Glob/find silently skip dotfile-prefixed path segments | Read the exact relative path directly |
| "Blocked skills are just strong recommendations" | `blocked` means explicitly rejected on install | Never install blocked skills |
| "Default skills already auto-installed elsewhere" | Only `--all` (via team-setup or manual) installs them | Run `/team-skills --all` to onboard the default set |
| "I'll skip merging the project-root manifest" | Project entries are meant to override team defaults | Merge both manifests; project-root wins conflicts |
## Red Flags
- Using glob, find, or grep to locate `.adlc/init-options.json` instead of reading the exact path.
- Renaming a skill or adding a `team-` prefix on install — install under the original name so it matches the manifest.
- Installing a skill listed under the `blocked` section.
- Writing skills to any directory other than the agent's configured skills folder.
- Proceeding past an unset `team_ai_directives` field instead of stopping with the config message.
- Fetching an external skill over a non-HTTPS URL.
## Verification
- `.adlc/init-options.json` was read directly (no search tool) and `team_ai_directives` resolved to a path.
- Both `{REPO_ROOT}/.skills.json` and `{TEAM_AI_DIRECTIVES}/.skills.json` were merged; project-root entries won any conflicts.
- Each installed skill lives at `{skills_dir}/{name}/SKILL.md` with its original `name` in frontmatter (no prefix).
- No skill from the `blocked` section was installed.
- `--all` installed every `default` and `external` skill (skipping `blocked` and already-installed).
- A confirmation block was emitted showing the installed name, on-disk location, and source.
## Configuration
- `TEAM_AI_DIRECTIVES` — Path to the team AI directives (overrides `.adlc/init-options.json`).
- `.adlc/init-options.json` — Project-level config file with `team_ai_directives` field.
- Default fallback: `team-ai-directives/` relative to project root.
- `scripts/bash/setup-team.sh` / `scripts/powershell/setup-team.ps1` — Skill-local path resolution (`--json` / `-Json`).
## 12-Factor Alignment
Factor XII (Team Capability) — manages team skill catalog and installation.