squads 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- squads-0.1.0/.github/workflows/publish.yml +22 -0
- squads-0.1.0/.github/workflows/test.yml +26 -0
- squads-0.1.0/.gitignore +5 -0
- squads-0.1.0/.vscode/settings.json +3 -0
- squads-0.1.0/CHANGELOG.md +36 -0
- squads-0.1.0/CLAUDE.md +102 -0
- squads-0.1.0/CONTRIBUTING.md +71 -0
- squads-0.1.0/CONTRIBUTORS.md +8 -0
- squads-0.1.0/LICENSE +21 -0
- squads-0.1.0/PKG-INFO +241 -0
- squads-0.1.0/README.md +212 -0
- squads-0.1.0/docs/README.md +70 -0
- squads-0.1.0/docs/adoption.md +106 -0
- squads-0.1.0/docs/agents.md +85 -0
- squads-0.1.0/docs/backends.md +83 -0
- squads-0.1.0/docs/faq.md +63 -0
- squads-0.1.0/docs/internals.md +358 -0
- squads-0.1.0/docs/recipes.md +91 -0
- squads-0.1.0/docs/roles.md +69 -0
- squads-0.1.0/docs/tutorial.md +109 -0
- squads-0.1.0/docs/workflow.md +101 -0
- squads-0.1.0/pyproject.toml +97 -0
- squads-0.1.0/src/squads/__init__.py +3 -0
- squads-0.1.0/src/squads/__main__.py +4 -0
- squads-0.1.0/src/squads/_backends/__init__.py +1 -0
- squads-0.1.0/src/squads/_backends/_base.py +75 -0
- squads-0.1.0/src/squads/_backends/_claude_code/__init__.py +6 -0
- squads-0.1.0/src/squads/_backends/_claude_code/_backend.py +184 -0
- squads-0.1.0/src/squads/_backends/_claude_code/_claude_md.py +26 -0
- squads-0.1.0/src/squads/_backends/_claude_code/_frontmatter.py +14 -0
- squads-0.1.0/src/squads/_backends/_registry.py +25 -0
- squads-0.1.0/src/squads/_cli/__init__.py +67 -0
- squads-0.1.0/src/squads/_cli/_comment.py +128 -0
- squads-0.1.0/src/squads/_cli/_common.py +101 -0
- squads-0.1.0/src/squads/_cli/_create.py +55 -0
- squads-0.1.0/src/squads/_cli/_dev.py +50 -0
- squads-0.1.0/src/squads/_cli/_main.py +341 -0
- squads-0.1.0/src/squads/_cli/_refs.py +68 -0
- squads-0.1.0/src/squads/_cli/_role.py +92 -0
- squads-0.1.0/src/squads/_cli/_skill.py +79 -0
- squads-0.1.0/src/squads/_clock.py +38 -0
- squads-0.1.0/src/squads/_discussion.py +155 -0
- squads-0.1.0/src/squads/_errors.py +29 -0
- squads-0.1.0/src/squads/_index/__init__.py +1 -0
- squads-0.1.0/src/squads/_index/_resolver.py +19 -0
- squads-0.1.0/src/squads/_index/_store.py +70 -0
- squads-0.1.0/src/squads/_interactions.py +163 -0
- squads-0.1.0/src/squads/_itemfile.py +37 -0
- squads-0.1.0/src/squads/_models/__init__.py +1 -0
- squads-0.1.0/src/squads/_models/_config.py +41 -0
- squads-0.1.0/src/squads/_models/_enums.py +78 -0
- squads-0.1.0/src/squads/_models/_extras.py +28 -0
- squads-0.1.0/src/squads/_models/_index.py +40 -0
- squads-0.1.0/src/squads/_models/_item.py +95 -0
- squads-0.1.0/src/squads/_models/_markers.py +43 -0
- squads-0.1.0/src/squads/_paths.py +125 -0
- squads-0.1.0/src/squads/_rendering/__init__.py +1 -0
- squads-0.1.0/src/squads/_rendering/_engine.py +31 -0
- squads-0.1.0/src/squads/_rendering/templates/agents/item_skill.md.j2 +26 -0
- squads-0.1.0/src/squads/_rendering/templates/agents/role.md.j2 +37 -0
- squads-0.1.0/src/squads/_rendering/templates/agents/skill.md.j2 +16 -0
- squads-0.1.0/src/squads/_rendering/templates/agents/squads_skill.md.j2 +31 -0
- squads-0.1.0/src/squads/_rendering/templates/claude/claude_section.md.j2 +38 -0
- squads-0.1.0/src/squads/_rendering/templates/claude/pointer_agent.md.j2 +26 -0
- squads-0.1.0/src/squads/_rendering/templates/claude/pointer_skill.md.j2 +10 -0
- squads-0.1.0/src/squads/_rendering/templates/claude/settings.json.j2 +10 -0
- squads-0.1.0/src/squads/_rendering/templates/items/bug.md.j2 +17 -0
- squads-0.1.0/src/squads/_rendering/templates/items/decision.md.j2 +12 -0
- squads-0.1.0/src/squads/_rendering/templates/items/epic.md.j2 +14 -0
- squads-0.1.0/src/squads/_rendering/templates/items/feature.md.j2 +15 -0
- squads-0.1.0/src/squads/_rendering/templates/items/guide.md.j2 +14 -0
- squads-0.1.0/src/squads/_rendering/templates/items/review.md.j2 +14 -0
- squads-0.1.0/src/squads/_rendering/templates/items/task.md.j2 +15 -0
- squads-0.1.0/src/squads/_rendering/templates/workflow.md.j2 +18 -0
- squads-0.1.0/src/squads/_roles/__init__.py +1 -0
- squads-0.1.0/src/squads/_roles/_catalog.py +266 -0
- squads-0.1.0/src/squads/_sections.py +106 -0
- squads-0.1.0/src/squads/_service.py +927 -0
- squads-0.1.0/src/squads/_util.py +20 -0
- squads-0.1.0/src/squads/_workflow.py +148 -0
- squads-0.1.0/src/squads/py.typed +0 -0
- squads-0.1.0/tests/conftest.py +39 -0
- squads-0.1.0/tests/test_adoption.py +83 -0
- squads-0.1.0/tests/test_backend_claude.py +60 -0
- squads-0.1.0/tests/test_cli.py +69 -0
- squads-0.1.0/tests/test_collab.py +158 -0
- squads-0.1.0/tests/test_discussion.py +23 -0
- squads-0.1.0/tests/test_index.py +82 -0
- squads-0.1.0/tests/test_models.py +50 -0
- squads-0.1.0/tests/test_phase3.py +137 -0
- squads-0.1.0/tests/test_rendering.py +27 -0
- squads-0.1.0/tests/test_sections.py +43 -0
- squads-0.1.0/tests/test_service.py +60 -0
- squads-0.1.0/tests/test_skills.py +87 -0
- squads-0.1.0/tests/test_workflow.py +32 -0
- squads-0.1.0/tests/test_workflow_rules.py +104 -0
- squads-0.1.0/uv.lock +468 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
id-token: write
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment: pypi
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6.0.3
|
|
17
|
+
- uses: actions/setup-python@v6.2.0
|
|
18
|
+
with:
|
|
19
|
+
python-version-file: pyproject.toml
|
|
20
|
+
- uses: astral-sh/setup-uv@v8.2.0
|
|
21
|
+
- run: uv build
|
|
22
|
+
- run: uv publish
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v6.0.3
|
|
14
|
+
- uses: actions/setup-python@v6.2.0
|
|
15
|
+
with:
|
|
16
|
+
python-version-file: pyproject.toml
|
|
17
|
+
- uses: astral-sh/setup-uv@v8.2.0
|
|
18
|
+
- run: uv sync --frozen
|
|
19
|
+
- name: ruff check
|
|
20
|
+
run: uv run ruff check .
|
|
21
|
+
- name: ruff format
|
|
22
|
+
run: uv run ruff format --check .
|
|
23
|
+
- name: pyright
|
|
24
|
+
run: uv run pyright
|
|
25
|
+
- name: pytest
|
|
26
|
+
run: uv run pytest
|
squads-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-06-08
|
|
10
|
+
|
|
11
|
+
Initial release.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **CLI** (`squads` / `sq`) for managing a team of AI agents as identified markdown with a
|
|
16
|
+
JIRA-like, globally-unique ID system. Item types: epic, feature, task, bug, decision (ADR),
|
|
17
|
+
review, guide, role, skill.
|
|
18
|
+
- **Index** — a single `<squad>/.squads.json` with one global monotonic counter and all item
|
|
19
|
+
metadata; filelock'd, atomic writes. The `.md` frontmatter is the durable source of truth; the
|
|
20
|
+
index is rebuildable (`sq repair`, `sq repair --renumber`).
|
|
21
|
+
- **Commands** — `init`, `adopt`, `create`, `list`, `show`, `tree`, `link`/`unlink`, `update`,
|
|
22
|
+
`status`, `comment`, `story`, `subtask`, `ref`/`refs`, `inbox`, `role`, `dev`, `skill`, `guide`,
|
|
23
|
+
`check`, `repair`, `sync`, `workflow`. Global `--dir` (target a squad) and `--at` (forge
|
|
24
|
+
timestamps for history-preserving migration).
|
|
25
|
+
- **Workflow** — per-type status machines with validated transitions; parent rules
|
|
26
|
+
(task → feature, feature → epic); typed forward refs with computed backrefs; user stories &
|
|
27
|
+
subtasks with their own discussion; `@mention` inbox.
|
|
28
|
+
- **Claude Code backend** — thin `.claude/` pointers to real definitions under the squad folder,
|
|
29
|
+
bundled `squads` skill + per-item-type skills, a managed `CLAUDE.md` section with
|
|
30
|
+
greeting-based impersonation, and a non-clobbering `settings.json` merge.
|
|
31
|
+
- **8 bundled roles** + on-demand stack developers (`sq dev add`); the role↔item-type playbook.
|
|
32
|
+
- **Docs** — README, plus `docs/` (workflow, internals, adoption, agents, tutorial, roles,
|
|
33
|
+
backends, recipes, faq); `py.typed`; MIT licensed.
|
|
34
|
+
|
|
35
|
+
[Unreleased]: https://github.com/TheCaptainCat/squads/compare/v0.1.0...HEAD
|
|
36
|
+
[0.1.0]: https://github.com/TheCaptainCat/squads/releases/tag/v0.1.0
|
squads-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# CLAUDE.md — working on the squads codebase
|
|
2
|
+
|
|
3
|
+
`squads` (`sq`) is a Python/uv Typer CLI that manages a team of AI agents on a code project:
|
|
4
|
+
it bootstraps roles/skills and tracks work as identified markdown with a JIRA-like ID system.
|
|
5
|
+
Claude Code is the first pluggable backend. This file guides work **on squads itself**.
|
|
6
|
+
|
|
7
|
+
## Commands
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uv sync # install deps + the sq entry point
|
|
11
|
+
uv run pytest # full suite (fast, all in tmp dirs)
|
|
12
|
+
uv run sq <cmd> # exercise the CLI
|
|
13
|
+
uv build # wheel/sdist (templates ship as package data)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Architecture & layering
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
_cli → _service → (index store, backends, rendering)
|
|
20
|
+
_models shared, no internal deps
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Module privacy convention.** Every implementation module and subpackage is **private** —
|
|
24
|
+
leading-underscore names (`_service.py`, `_models/`, `_backends/_claude_code/`, …). Package
|
|
25
|
+
`__init__.py` files do **not** re-export (this is a CLI, not yet a library API), so internal code
|
|
26
|
+
imports straight from the underscore modules (`from squads._models._item import Item`). The only
|
|
27
|
+
non-empty inits are `squads/__init__` (`__version__`), `_cli/__init__` (the Typer `app`, the entry
|
|
28
|
+
point `squads._cli:app`), and `_backends/_claude_code/__init__` (backend registration side-effect).
|
|
29
|
+
Namespace-style imports use an alias to keep call sites readable: `from squads import _clock as clock`.
|
|
30
|
+
|
|
31
|
+
- `_models/` — pydantic v2. `_item` (`Item`), `_index` (`SquadsDB`), `_enums` (`ItemType`/`Status`
|
|
32
|
+
+ prefix→folder maps), `_markers` (sq anchor tags), `_config` (`.squads.toml`), `_extras`
|
|
33
|
+
(`ExtraKey`).
|
|
34
|
+
- `_paths.py` — resolve the active squad folder (`--dir` > `.squads.toml` walk-up > default), map an
|
|
35
|
+
ID/type to its location, and guard `abspath` against path traversal.
|
|
36
|
+
- `_index/_store.py` — the integrity core: filelock'd, atomic (`os.replace`) read-modify-write of
|
|
37
|
+
`<squad-dir>/.squads.json`; `allocate_id` bumps the **single global counter**; `load` wraps a
|
|
38
|
+
corrupt index in `SquadsError`.
|
|
39
|
+
- `_sections.py` / `_itemfile.py` — marker-safe edits and frontmatter↔Item mapping.
|
|
40
|
+
- `_workflow.py` — per-type status machines + `can_transition` + `TERMINAL`/`is_open` +
|
|
41
|
+
`ALLOWED_PARENTS`/`parent_allowed`/`parent_hint`.
|
|
42
|
+
- `_rendering/` — Jinja2 (`StrictUndefined`); templates are package data under `_rendering/templates/`.
|
|
43
|
+
- `_backends/` — `AgentBackend` ABC + registry; `_claude_code/` writes pointer files, managed skills
|
|
44
|
+
(real body under `<squad>/agents/skills/`, thin pointer in `.claude/`), and the CLAUDE.md section.
|
|
45
|
+
- `_roles/_catalog.py` — the 8 bundled roles + dev name pool + `dev_role()`.
|
|
46
|
+
- `_interactions.py` — the team **playbook**: which roles interact with each item type (`*dev`
|
|
47
|
+
sentinel = any `<tech>-dev` role). Drives the per-item-type managed skills (`sq-<type>`) and
|
|
48
|
+
`skills_for_role()`. Workflow cheatsheet partial: `_rendering/templates/workflow.md.j2` (shared by
|
|
49
|
+
the `squads` skill and `sq workflow`).
|
|
50
|
+
- `_service.py` — orchestration; the logic behind each command. `_discussion.py` — comment/story/
|
|
51
|
+
subtask formatting + `@mention` extraction.
|
|
52
|
+
- `_cli/` — Typer app (`__init__` wires sub-typers + the `--dir` callback + version notice);
|
|
53
|
+
one `_module` per command group; `_common.py` has the shared console/error decorator/parsers.
|
|
54
|
+
|
|
55
|
+
## Invariants — keep these true
|
|
56
|
+
|
|
57
|
+
1. **Frontmatter is the source of truth.** `.squads.json` is a rebuildable index; never store
|
|
58
|
+
anything in it that can't be reconstructed from the `.md` files (`sq repair` proves this).
|
|
59
|
+
2. **Global counter.** One monotonic counter for all types; an ID's number is globally unique.
|
|
60
|
+
Allocate only inside `IndexStore.transaction()`.
|
|
61
|
+
3. **Marker-safe edits only.** Touch file content solely via `_sections.py`; never rewrite an
|
|
62
|
+
agent-authored body. Markers are `<!-- sq:<tag> -->` / `<!-- sq:<tag>:end -->`.
|
|
63
|
+
4. **Forward edges only.** `item.refs` holds outgoing refs; backrefs are computed by inversion
|
|
64
|
+
(`SquadsDB.backrefs`), never persisted.
|
|
65
|
+
5. **`.claude/` files are pointers**, not content. Real definitions live under `squads/`.
|
|
66
|
+
6. **Backends are pluggable.** Don't reach into `.claude/` outside a backend; go through the ABC.
|
|
67
|
+
|
|
68
|
+
## Conventions / gotchas
|
|
69
|
+
|
|
70
|
+
- **Escape dynamic output.** Rich treats `[...]` (e.g. a `[x]` checkbox) as markup — always wrap
|
|
71
|
+
user/content strings with `_cli._common.e()` when printing to the console or a table.
|
|
72
|
+
- **Time is injectable.** Use `clock.now()` / `clock.iso()` so tests can freeze it
|
|
73
|
+
(`frozen_time` fixture); never call `datetime.now()` directly.
|
|
74
|
+
- **Marker regex is strict.** `_sections.find_markers` only matches well-formed tags so prose like
|
|
75
|
+
`` `<!-- sq:* -->` `` in role files isn't linted as a real marker.
|
|
76
|
+
- **User-facing errors** subclass `SquadsError`; the CLI's `@handle_errors` turns them into a clean
|
|
77
|
+
message + exit 1. Raise those, not bare exceptions.
|
|
78
|
+
- **Templates are package data** — adding one means dropping a `.j2` under `_rendering/templates/`;
|
|
79
|
+
the wheel includes them automatically (verified in build).
|
|
80
|
+
- **No `from __future__ import annotations`** — we target Python 3.14 (PEP 649 lazy annotations),
|
|
81
|
+
so forward refs work unquoted. Keep the import graph **acyclic** (verified); if a future edge
|
|
82
|
+
would create a cycle, use `if TYPE_CHECKING:` + a string annotation rather than a runtime import.
|
|
83
|
+
- **`Item.extra` keys** come from `_models/_extras.py::ExtraKey` (imported as `X`) — never hand-write
|
|
84
|
+
the string keys; that's where role/dev/skill/ref metadata field names live.
|
|
85
|
+
- **Strict typing** — `pyright` runs in strict mode and `ruff` (E/F/I/UP/B/W + C901/SIM/PERF/PTH/RUF/TRY/PLR0911-15,
|
|
86
|
+
max-complexity 12, max-args 8, TRY003 ignored) must stay clean:
|
|
87
|
+
`uv run pyright && uv run ruff check . && uv run ruff format --check .`. Annotate bare `dict`/
|
|
88
|
+
`list` (e.g. `dict[str, Any]`); Typer's `Option/Argument` call-defaults are why `B008` is
|
|
89
|
+
ignored under `_cli/`.
|
|
90
|
+
|
|
91
|
+
## Testing
|
|
92
|
+
|
|
93
|
+
`pytest` with `typer.testing.CliRunner`; the `project`/`svc` fixtures (`tests/conftest.py`) init a
|
|
94
|
+
squad in a `tmp_path` and `chdir` into it — **all file generation stays in temp**. Cover behaviour
|
|
95
|
+
through the service/CLI, and assert generated files (valid YAML frontmatter, intact markers,
|
|
96
|
+
preserved body). When adding a feature, add a service-level test and a CLI smoke test.
|
|
97
|
+
|
|
98
|
+
## Status
|
|
99
|
+
|
|
100
|
+
All three planned phases are built and green. The only explicitly-deferred feature is
|
|
101
|
+
project-level template/role overrides (e.g. `squads/.templates/`). The full design lives in the
|
|
102
|
+
approved plan referenced from the project memory.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Contributing to squads
|
|
2
|
+
|
|
3
|
+
Thanks for hacking on squads! This is a Python 3.14 / `uv` project. `CLAUDE.md` is the terse
|
|
4
|
+
working-reference; this file is the friendly version. Deeper design lives in
|
|
5
|
+
[docs/internals.md](docs/internals.md).
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uv sync # install deps + the `sq` entry point into the project venv
|
|
11
|
+
uv run sq --help # exercise the CLI
|
|
12
|
+
uv run pytest # the test suite (fast; everything runs in tmp dirs)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## The gate (must stay green)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv run ruff check .
|
|
19
|
+
uv run ruff format --check .
|
|
20
|
+
uv run pyright # strict mode
|
|
21
|
+
uv run pytest
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Ruff runs an expanded ruleset (`E F I UP B W` + `C901 SIM PERF PTH RUF TRY PLR0911/12/13/15`,
|
|
25
|
+
`max-complexity 12`, `max-args 8`, `TRY003` ignored). Pyright is **strict**. CI (`.github/workflows`)
|
|
26
|
+
runs all four on pushes/PRs to `main`.
|
|
27
|
+
|
|
28
|
+
## Conventions
|
|
29
|
+
|
|
30
|
+
- **Private layout.** Every module and subpackage is underscore-prefixed
|
|
31
|
+
(`squads._service`, `squads._models._item`, …) and package `__init__`s don't re-export — import
|
|
32
|
+
straight from the underscore modules. (`squads/__init__` keeps `__version__`; `_cli/__init__` the
|
|
33
|
+
Typer `app`; `_backends/_claude_code/__init__` the registration side-effect.)
|
|
34
|
+
- **Frontmatter is the source of truth.** `.squads.json` is a rebuildable index — never store
|
|
35
|
+
anything in it that can't be reconstructed from the `.md` files (`sq repair` proves it).
|
|
36
|
+
- **Marker-safe edits only** — touch file content via `squads._sections`; never rewrite an agent's
|
|
37
|
+
body. Markers are `<!-- sq:<tag> -->` / `<!-- sq:<tag>:end -->`.
|
|
38
|
+
- **Forward edges only** — `item.refs`; backrefs are computed by inversion, never persisted.
|
|
39
|
+
- **`.claude/` is pointers + tool config**; real content lives under the squad folder.
|
|
40
|
+
- **Time is injectable** — use `_clock.now()` / `_clock.iso()`, never `datetime.now()`.
|
|
41
|
+
- **`Item.extra` keys** come from `squads._models._extras.ExtraKey` — don't hand-write the literals.
|
|
42
|
+
- **Escape dynamic console output** with `_cli._common.e()` (Rich treats `[...]` as markup).
|
|
43
|
+
- **No `from __future__ import annotations`** (Python 3.14 / PEP 649); keep the import graph
|
|
44
|
+
**acyclic** — if a future edge would create a cycle, use `if TYPE_CHECKING:` + a string annotation.
|
|
45
|
+
|
|
46
|
+
## How to add things
|
|
47
|
+
|
|
48
|
+
- **A template** → drop a `.j2` under `squads/_rendering/templates/`; it ships in the wheel as
|
|
49
|
+
package data automatically. Render with `squads._rendering._engine.render` (StrictUndefined).
|
|
50
|
+
- **A command** → add it to the right `squads/_cli/_*` module (or a new one), wire it onto `app`
|
|
51
|
+
in `_cli/__init__`, and route logic through `Service`.
|
|
52
|
+
- **An item type** → add to `ItemType` (`_models/_enums`) with its prefix + folder, give it a
|
|
53
|
+
workflow in `_workflow`, an item template, and (if agents author it) a `PLAYBOOK` entry in
|
|
54
|
+
`_interactions`.
|
|
55
|
+
- **A backend** → see [docs/backends.md](docs/backends.md).
|
|
56
|
+
|
|
57
|
+
## Tests
|
|
58
|
+
|
|
59
|
+
`pytest` with `typer.testing.CliRunner`. The `project`/`svc` fixtures (`tests/conftest.py`) init a
|
|
60
|
+
squad in a `tmp_path` and `chdir` into it — **all file generation stays in temp**. Cover behaviour
|
|
61
|
+
through the service/CLI and assert on the generated files (valid frontmatter, intact markers,
|
|
62
|
+
preserved body). When you add a feature, add a service-level test and a CLI smoke test. Time is
|
|
63
|
+
frozen via the `frozen_time` fixture; the `_reset_clock_override` autouse fixture stops a forged
|
|
64
|
+
`--at` from leaking between tests.
|
|
65
|
+
|
|
66
|
+
## Commits / PRs
|
|
67
|
+
|
|
68
|
+
Keep the gate green. PRs target `main` and run the `test` workflow. Releases are tagged `v*`, which
|
|
69
|
+
triggers `publish.yml` (PyPI trusted publishing). Bump `__version__` (in `squads/__init__.py` and
|
|
70
|
+
`pyproject.toml`) and add a [CHANGELOG.md](CHANGELOG.md) entry when behaviour or the managed
|
|
71
|
+
templates change — a version bump is also what nudges existing squads to `sq sync`.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Contributors
|
|
2
|
+
|
|
3
|
+
Thanks to everyone who has helped build squads.
|
|
4
|
+
|
|
5
|
+
- **Pierre Chat** ([@TheCaptainCat](https://github.com/TheCaptainCat)) — author & maintainer
|
|
6
|
+
- **Claude** (Anthropic) — design & implementation, paired via Claude Code
|
|
7
|
+
|
|
8
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) to get involved.
|
squads-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pierre Chat
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
squads-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: squads
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Manage a team of AI agents working on a code project: bootstrap roles & skills, track work with JIRA-like IDs in predictable markdown.
|
|
5
|
+
Project-URL: Homepage, https://github.com/TheCaptainCat/squads
|
|
6
|
+
Project-URL: Repository, https://github.com/TheCaptainCat/squads
|
|
7
|
+
Project-URL: Issues, https://github.com/TheCaptainCat/squads/issues
|
|
8
|
+
Author-email: Pierre Chat <pierrechat@outlook.com>, Claude <noreply@anthropic.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,ai,claude,cli,markdown,project-management
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Software Development
|
|
19
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.14
|
|
22
|
+
Requires-Dist: filelock>=3.13
|
|
23
|
+
Requires-Dist: jinja2>=3.1
|
|
24
|
+
Requires-Dist: pydantic>=2.6
|
|
25
|
+
Requires-Dist: pyyaml>=6.0
|
|
26
|
+
Requires-Dist: rich>=13.7
|
|
27
|
+
Requires-Dist: typer>=0.12
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# squads
|
|
31
|
+
|
|
32
|
+
A CLI (`squads` / `sq`) that manages a **team of AI agents** working on a code project.
|
|
33
|
+
|
|
34
|
+
squads bootstraps agent **roles** and **skills**, produces markdown in a predictable structure,
|
|
35
|
+
and gives every tracked artifact a stable JIRA-like ID (`TASK-000003`). Claude Code is the first
|
|
36
|
+
supported backend; the design is pluggable.
|
|
37
|
+
|
|
38
|
+
The real content lives under a relocatable `squads/` folder. The files written into `.claude/`
|
|
39
|
+
are **thin pointers** to those definitions, plus a managed `squads` skill and a managed section in
|
|
40
|
+
`CLAUDE.md` that teaches the agents how to work.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
Requires Python ≥ 3.14. Install as a **tool** so `squads` / `sq` land on your `PATH`:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# with uv (recommended)
|
|
50
|
+
uv tool install squads # from PyPI, once published
|
|
51
|
+
uv tool install . # from a local checkout
|
|
52
|
+
|
|
53
|
+
# or with pipx
|
|
54
|
+
pipx install squads # from PyPI
|
|
55
|
+
pipx install . # from a local checkout
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then `sq` is available everywhere:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
sq --help
|
|
62
|
+
sq --version
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Try it once without installing, via `uvx` (or `pipx run`):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uvx --from squads sq --help # or: uvx --from . sq --help in a checkout
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
> **From source / development:** `uv sync` creates the project venv and exposes the CLI as
|
|
72
|
+
> `uv run sq …`. The examples below use bare `sq` (tool install); prefix with `uv run` if you're
|
|
73
|
+
> working from a source checkout.
|
|
74
|
+
|
|
75
|
+
## Quickstart
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
cd your-project
|
|
79
|
+
sq init --roles all # scaffold squads/, .claude/, CLAUDE.md
|
|
80
|
+
sq create feature "User authentication" --desc "Login & sessions"
|
|
81
|
+
sq create task "Validate token expiry" --parent FEAT-000010
|
|
82
|
+
sq status TASK-000011 InProgress
|
|
83
|
+
sq comment TASK-000011 --as architect -m "Reuse the clock abstraction" -m "@qa verify edges"
|
|
84
|
+
sq tree
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Concepts
|
|
90
|
+
|
|
91
|
+
- **Items** — every tracked thing is an item with a type and a stable ID. Types: `epic`,
|
|
92
|
+
`feature`, `task`, `bug`, `decision` (ADR), `review`, `guide`, `role`, `skill`.
|
|
93
|
+
- **Global IDs** — `PREFIX-NNNNNN` with a single global counter, so the number is unique across
|
|
94
|
+
all types (you never have both `TASK-000002` and `BUG-000002`). The prefix marks the type:
|
|
95
|
+
`EPIC FEAT TASK BUG ADR REV GUIDE ROLE SKILL`.
|
|
96
|
+
- **Source of truth** — the markdown **frontmatter** is durable truth; `squads/.squads.json` is a
|
|
97
|
+
fast index that is fully rebuildable from the files (`sq repair`).
|
|
98
|
+
- **sq-owned sections** — files carry invisible markers (`<!-- sq:body -->`, `<!-- sq:discussion -->`,
|
|
99
|
+
…). `sq` owns the frontmatter and marked sections (status, discussion); **agents write all other
|
|
100
|
+
prose directly** and must never touch the marker lines.
|
|
101
|
+
- **Agents** — named roles (real name + slug, e.g. *Robert Architect* / `architect`). The `.claude/`
|
|
102
|
+
files are pointers to the real definitions under `squads/agents/`.
|
|
103
|
+
|
|
104
|
+
### On-disk layout
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
your-project/
|
|
108
|
+
├── .squads.toml # config (squad dir, backend, version, default role)
|
|
109
|
+
├── CLAUDE.md # managed section: process + greeting impersonation
|
|
110
|
+
├── .claude/
|
|
111
|
+
│ ├── agents/<slug>.md # POINTER → squads/agents/roles/ROLE-*.md
|
|
112
|
+
│ └── skills/{squads,<slug>}/SKILL.md
|
|
113
|
+
└── squads/ # self-contained & relocatable (override with --dir)
|
|
114
|
+
├── .squads.json # the index: counter + all items + refs
|
|
115
|
+
├── epics/ features/ tasks/ bugs/ adrs/ reviews/ guides/
|
|
116
|
+
└── agents/{roles,skills}/
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Status workflows
|
|
120
|
+
|
|
121
|
+
| Type | Lifecycle |
|
|
122
|
+
|------|-----------|
|
|
123
|
+
| epic / feature / task / bug | `Draft → Ready → InProgress → InReview → Done` (+ `Blocked`, `Cancelled`) |
|
|
124
|
+
| decision (ADR) | `Proposed → Accepted → Superseded` (+ `Rejected`, `Deprecated`) |
|
|
125
|
+
| review | `Requested → InReview → ChangesRequested → Approved` (+ `Rejected`) |
|
|
126
|
+
| guide | `Draft → Published → Deprecated` |
|
|
127
|
+
| role / skill | `Draft → Active → Archived` |
|
|
128
|
+
|
|
129
|
+
`sq status` validates transitions; use `--force` to override.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Documentation
|
|
134
|
+
|
|
135
|
+
Full docs (with diagrams) live in **[docs/](docs/README.md)**:
|
|
136
|
+
|
|
137
|
+
- **[tutorial](docs/tutorial.md)** — a 15-minute, end-to-end first squad.
|
|
138
|
+
- **[workflow](docs/workflow.md)** — who creates & links what, and the per-type status lifecycles.
|
|
139
|
+
- **[agents](docs/agents.md)** — operating *as* an agent inside a squad.
|
|
140
|
+
- **[roles](docs/roles.md)** — the bundled roster, bundles, and stack developers.
|
|
141
|
+
- **[recipes](docs/recipes.md)** — copy-paste sequences · **[faq](docs/faq.md)** — common errors.
|
|
142
|
+
- **[adoption](docs/adoption.md)** — migrating an existing project (`sq adopt`, `--at`).
|
|
143
|
+
- **[internals](docs/internals.md)** / **[backends](docs/backends.md)** — under the hood & writing a backend.
|
|
144
|
+
|
|
145
|
+
Contributing: **[CONTRIBUTING.md](CONTRIBUTING.md)** · contributors: **[CONTRIBUTORS.md](CONTRIBUTORS.md)** · changes: **[CHANGELOG.md](CHANGELOG.md)**.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Command reference
|
|
150
|
+
|
|
151
|
+
**Setup**
|
|
152
|
+
- `sq init [--squad-dir squads] [--backend claude_code] [--roles all|core|minimal|<slugs>] [--no-claude] [--force]`
|
|
153
|
+
- `sq adopt [--squad-dir squads] [--backend] [--roles] [--no-claude]` — bring an *existing* project under sq management (non-destructive; imports existing items). See [docs/adoption.md](docs/adoption.md).
|
|
154
|
+
- `sq workflow` — print the team-workflow cheatsheet
|
|
155
|
+
- `sq sync` — regenerate tool-owned managed files to the current version
|
|
156
|
+
- `--dir PATH` (global) — operate on the squad folder at PATH instead of walking up to `.squads.toml`
|
|
157
|
+
- `--at WHEN` (global) — forge timestamps (ISO 8601, UTC) for this command, to preserve history when migrating
|
|
158
|
+
|
|
159
|
+
**Items**
|
|
160
|
+
- `sq create epic|feature|task|bug|decision|review|guide TITLE [--parent ID] [--desc] [--label] [--ref ID] [--assignee] [--json]`
|
|
161
|
+
- `sq list [--type|--status|--parent|--label|--assignee] [--json]` · `sq show ID [--json]` · `sq tree [ROOT_ID]`
|
|
162
|
+
- `sq update ID [--title|--desc|--assignee|--add-label|--rm-label]` (`--title` renames the file)
|
|
163
|
+
- `sq status ID STATUS [--force]` · `sq link CHILD --parent P` · `sq unlink CHILD`
|
|
164
|
+
|
|
165
|
+
**Collaboration**
|
|
166
|
+
- `sq comment ID -m "…" [-m "…"] [--as <slug|operator>] [--story USn|--subtask STn]` (use `@role` to notify)
|
|
167
|
+
- `sq story add FEAT-ID [LABEL] [--json]` · `sq story list FEAT-ID`
|
|
168
|
+
- `sq subtask add TASK-ID [LABEL] [--story USn] [--json]` · `sq subtask list TASK-ID` · `sq subtask done TASK-ID STn [--undo]`
|
|
169
|
+
- `sq inbox <role>` — open items mentioning `@role`
|
|
170
|
+
|
|
171
|
+
`story add` / `subtask add` **scaffold an empty block with a writable body region** and print
|
|
172
|
+
(or return, with `--json`) the file and the marker/line range to write between — the agent then
|
|
173
|
+
fills it with free-form paragraphs or bullet lists. The optional `LABEL` is just a short heading;
|
|
174
|
+
the substance lives in the body. `sq` still owns the discussion and the subtask checkbox.
|
|
175
|
+
|
|
176
|
+
**Cross-linking**
|
|
177
|
+
- `sq ref add FROM TO [--kind related|blocks|implements|fixes|addresses]` · `sq ref rm FROM TO`
|
|
178
|
+
- `sq refs ID [--out|--in|--all] [--json]` (forward edges stored; backrefs computed)
|
|
179
|
+
|
|
180
|
+
**Agents**
|
|
181
|
+
- `sq role list [--available] | show <slug> | activate <slug> | regen ID | rm ID [--purge]`
|
|
182
|
+
- `sq dev add --tech <t> [--name] [--model] | list` — stack-specific developers
|
|
183
|
+
- `sq skill add NAME [--desc|--when-to-use|--allowed-tools] | list | show | regen | rm [--purge]`
|
|
184
|
+
- `sq guide add TITLE [--tech] [--tag] | list`
|
|
185
|
+
|
|
186
|
+
**Maintenance**
|
|
187
|
+
- `sq check` — lint markers, dangling parent/ref IDs, invalid status, index drift
|
|
188
|
+
- `sq repair [--renumber]` — rebuild the index from frontmatter; `--renumber` resolves merged ID collisions
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Working with agents
|
|
193
|
+
|
|
194
|
+
After `sq init`, open Claude Code in the project. `CLAUDE.md` tells the agents how the process
|
|
195
|
+
works and how to **impersonate a role on greeting**: say *"Hi Robert"* and Claude becomes Robert
|
|
196
|
+
Architect; with no name it defaults to **Catherine Manager**, who triages and routes the request.
|
|
197
|
+
|
|
198
|
+
The bundled roster: Catherine Manager (`manager`, default), Robert Architect (`architect`),
|
|
199
|
+
Olivia Lead (`tech-lead`), Paul Reviewer (`reviewer`), Mara Tester (`qa`), Hugo Ops (`devops`),
|
|
200
|
+
Nina Product (`product-owner`), Theo Writer (`tech-writer`). Add stack developers with `sq dev add`.
|
|
201
|
+
|
|
202
|
+
Agents create items with `sq`, get back the file path, write the body directly, and hand off via
|
|
203
|
+
`sq comment … @role`. Status and discussion stay owned by the CLI.
|
|
204
|
+
|
|
205
|
+
`sq init`/`sq sync` also generate a **skill per item type** (`sq-feature`, `sq-task`, `sq-bug`, …)
|
|
206
|
+
with role-directed guidance, plus the general `squads` skill. Each role's `.claude/agents/<slug>.md`
|
|
207
|
+
pointer preloads (via `skills:`) only the skills for the item types that role manages — so the
|
|
208
|
+
product owner gets `sq-feature`/`sq-epic`, a developer gets `sq-task`/`sq-bug`/`sq-review`, and the
|
|
209
|
+
manager (who triages rather than owning a type) gets just `squads`. Run `sq workflow` for the
|
|
210
|
+
cheatsheet.
|
|
211
|
+
|
|
212
|
+
### Team workflow
|
|
213
|
+
|
|
214
|
+
squads encodes a light division of labour (enforced by validation + `sq check`):
|
|
215
|
+
|
|
216
|
+
- The **product owner** writes **features** and their **user stories**
|
|
217
|
+
(`sq create feature`, `sq story add`).
|
|
218
|
+
- The **tech lead** writes **tasks**. A task's **parent is the feature** it implements, and each
|
|
219
|
+
**subtask maps to one user story**:
|
|
220
|
+
```bash
|
|
221
|
+
sq create task "Token validation" --parent FEAT-000002
|
|
222
|
+
sq subtask add TASK-000003 "Validate expiry" --story US1 # US1 must exist in FEAT-000002
|
|
223
|
+
```
|
|
224
|
+
- A task may instead/also link a **bug** or **review** via typed refs — or nothing if it's purely
|
|
225
|
+
technical:
|
|
226
|
+
```bash
|
|
227
|
+
sq ref add TASK-000003 BUG-000009 --kind fixes
|
|
228
|
+
sq ref add TASK-000003 REV-000010 --kind addresses
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
A task's parent must be a feature (link a bug/review with a ref, not as parent); a feature's parent
|
|
232
|
+
must be an epic. Invalid links are rejected at create/link time and flagged by `sq check`.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Git notes
|
|
237
|
+
|
|
238
|
+
Commit `.squads.toml`, the `squads/` folder, `CLAUDE.md`, and `.claude/` (the pointers + squads
|
|
239
|
+
skill). `squads/.gitignore` already excludes the lock/temp files. On a merge conflict in
|
|
240
|
+
`.squads.json`, take either side and run `sq repair` (the frontmatter is the truth);
|
|
241
|
+
if two branches reused an ID number, run `sq repair --renumber`.
|