@bankung/agent-teams 0.1.0

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.
package/.env.example ADDED
@@ -0,0 +1,289 @@
1
+ # Copy to .env (`cp .env.example .env`) and tweak as needed.
2
+ # .env is loaded by both docker-compose (variable substitution) and
3
+ # pydantic-settings inside the FastAPI app (when running uvicorn locally).
4
+
5
+ # ----- Postgres -----
6
+ # Password used by the db container AND by DATABASE_URL below. Change in any
7
+ # non-dev environment. (Dev default kept simple so docker compose up "just works".)
8
+ POSTGRES_PASSWORD=postgres
9
+
10
+ # Host port the db container is published on. Change if 5432 is already in use.
11
+ POSTGRES_PORT=5432
12
+
13
+ # ----- API -----
14
+ # Host port the api container is published on. Change if 8456 is already in use.
15
+ API_PORT=8456
16
+
17
+ # Application env flags consumed by api/src/settings.py.
18
+ APP_ENV=development
19
+ APP_DEBUG=true
20
+
21
+ # Secret key for session signing / CSRF / token generation.
22
+ # Generate with: python -c "import secrets; print(secrets.token_urlsafe(48))"
23
+ # NEVER use a short or guessable value in production — warnIfInsecure() will
24
+ # flag SECRET_KEY that is empty, contains 'dev-secret', or is shorter than 32 chars.
25
+ SECRET_KEY=
26
+
27
+ # Async DSN for SQLAlchemy + Alembic.
28
+ # This URL targets the compose db FROM OUTSIDE the network — i.e. when you run
29
+ # `cd api && uvicorn src.main:app --reload` on the host against the same
30
+ # compose-managed Postgres. Inside the compose network the api service uses
31
+ # host=db (set automatically in docker-compose.yml), so this var is ignored
32
+ # inside the api container.
33
+ DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/agent_teams
34
+
35
+ # Filesystem root of the repo — used by project auto-scaffold to locate
36
+ # context/projects/<name>/.
37
+ # Required — pydantic-settings raises ValidationError if unset.
38
+ # For local dev (running uvicorn from api/), set to the absolute path of the repo root,
39
+ # e.g. REPO_ROOT=/path/to/agent-teams. Inside docker-compose, the api service overrides
40
+ # this to /repo via the compose env block.
41
+ REPO_ROOT=
42
+
43
+ # ----- Web (Phase 3) -----
44
+ # Host port the web container is published on. Change if 5431 is already in use.
45
+ # Project-scoped port (mirrors api=8456 pattern) — avoids collision with the
46
+ # Next.js default 3000 that other scaffolded projects may use.
47
+ WEB_PORT=5431
48
+
49
+ # Browser-visible API base URL inlined into the Next.js client bundle at build time.
50
+ # - Host-direct dev (developer hits http://localhost:5431 → bundle calls http://localhost:8456): use http://localhost:8456
51
+ # - Compose network: the browser still runs on the host, so this stays the host URL — the
52
+ # container-internal SSR override is INTERNAL_API_URL below (NOT this var).
53
+ # NEXT_PUBLIC_* vars are visible in client JS — never put secrets here.
54
+ NEXT_PUBLIC_API_URL=http://localhost:8456
55
+
56
+ # Operator-opt-in personal-use feature; default off for pilot installs.
57
+ # Set to "true" to show P&L panels on the project board and dashboard.
58
+ NEXT_PUBLIC_FINANCE_PANELS_ENABLED=false
59
+
60
+ # SSR / Server Component base URL — used by web/lib/api.ts when typeof window === 'undefined'
61
+ # (i.e. fetches issued by the Next.js server process, not the browser).
62
+ # - Inside docker-compose: docker-compose.yml passes http://api:8456 to the web container so
63
+ # SSR stays on the compose network (Linux-portable; Windows / macOS Docker Desktop also OK).
64
+ # - Host-direct dev (next dev on the host, no compose web container): leave unset — web/lib/api.ts
65
+ # falls back to NEXT_PUBLIC_API_URL, which already resolves locally.
66
+ # Kanban #704 — without this on Linux compose, SSR would fetch localhost:8456 inside the
67
+ # container (= the container itself, not the host) and fail.
68
+ INTERNAL_API_URL=http://api:8456
69
+
70
+ # ----- LangGraph (Phase 4, Kanban #849) -----
71
+ # Host port the langgraph container is published on. Change if 8465 is in use.
72
+ LANGGRAPH_PORT=8465
73
+
74
+ # Which LLM provider the LangGraph engine uses. One of: anthropic, openai, ollama, deepseek, google.
75
+ # Default: anthropic. Switching providers needs only this var + the matching API key
76
+ # (or, for ollama, a local Ollama server). Kanban #891 added ollama; #1086 added deepseek;
77
+ # #1951 added google (native Gemini — required for multi-turn tool-calling; see note below).
78
+ LANGGRAPH_LLM_PROVIDER=anthropic
79
+
80
+ # Provider keys — set the one matching LANGGRAPH_LLM_PROVIDER. Leave the others blank.
81
+ # Never commit real keys; .env is gitignored. (Ollama needs no key — it runs locally.)
82
+ ANTHROPIC_API_KEY=
83
+ OPENAI_API_KEY=
84
+ # DeepSeek API key (Kanban #1086). Get yours at https://platform.deepseek.com/api-keys.
85
+ DEEPSEEK_API_KEY=
86
+ # Google / Gemini API key (Kanban #1951). Get yours at https://aistudio.google.com/app/apikey.
87
+ # IMPORTANT: use LANGGRAPH_LLM_PROVIDER=google (native SDK) for Gemini, NOT openai +
88
+ # OPENAI_BASE_URL. The OpenAI-compat endpoint drops Gemini's thought_signature on turn 2
89
+ # causing HTTP 400 on multi-turn tool-calling. The native google provider handles it correctly.
90
+ GOOGLE_API_KEY=
91
+
92
+ # Optional model override per provider. Defaults baked into llm.py (#853, #891).
93
+ ANTHROPIC_MODEL=claude-sonnet-4-6
94
+ OPENAI_MODEL=gpt-4o
95
+
96
+ # Optional base URL override for the openai provider. Empty = real OpenAI.
97
+ # Set to an OpenAI-compatible endpoint to drive another provider, e.g. Gemini:
98
+ # OPENAI_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
99
+ OPENAI_BASE_URL=
100
+
101
+ # Ollama provider (free local; install separately from https://ollama.com/).
102
+ # Used only when LANGGRAPH_LLM_PROVIDER=ollama. The langgraph container reaches
103
+ # the host's Ollama process via host.docker.internal (works on Mac + Win; on
104
+ # Linux compose, add `extra_hosts: ["host.docker.internal:host-gateway"]` to
105
+ # the langgraph service if needed).
106
+ OLLAMA_MODEL=llama3.2
107
+ OLLAMA_BASE_URL=http://host.docker.internal:11434
108
+
109
+ # DeepSeek provider (Kanban #1086). V3 Chat default; deepseek-reasoner = R1 (chain-of-thought).
110
+ # Used only when LANGGRAPH_LLM_PROVIDER=deepseek. Requires DEEPSEEK_API_KEY above.
111
+ LANGGRAPH_DEEPSEEK_MODEL=deepseek-chat
112
+ LANGGRAPH_DEEPSEEK_BASE_URL=https://api.deepseek.com
113
+
114
+ # Google / Gemini native provider (Kanban #1951). Uses ChatGoogleGenerativeAI from
115
+ # langchain-google-genai — the ONLY path that makes multi-turn tool-calling work on
116
+ # Gemini (native SDK preserves thought_signature; OpenAI-compat endpoint does not).
117
+ # gemini-flash-latest has quota on the operator's key. gemini-2.0-flash has quota=0.
118
+ # Used only when LANGGRAPH_LLM_PROVIDER=google. Requires GOOGLE_API_KEY above.
119
+ GOOGLE_MODEL=gemini-flash-latest
120
+
121
+ # ----- LangGraph background worker (Phase 4, Kanban #852) -----
122
+ # Which Kanban project the worker polls for next-autorun tasks. The container
123
+ # refuses to start without this set (it has no way to guess which project's
124
+ # board to poll). Dogfood default: 1 (the agent-teams project itself).
125
+ LANGGRAPH_PROJECT_ID=1
126
+
127
+ # Polling interval (seconds). The worker waits this long between calls to
128
+ # /api/tasks/next-autorun. Lower = snappier task pickup; higher = cheaper
129
+ # polling on quiet boards. Must be a positive integer.
130
+ LANGGRAPH_POLL_INTERVAL_SEC=30
131
+
132
+ # Override the Kanban API base URL the worker talks to. Default is the
133
+ # compose-internal hostname http://api:8456. Override e.g. to
134
+ # http://host.docker.internal:8456 when running the worker against an api
135
+ # instance on the host. Trailing slash is stripped.
136
+ LANGGRAPH_KANBAN_API_BASE=http://api:8456
137
+
138
+ # Token budget for the tool-use loop's conversation-history compaction
139
+ # (Kanban #1717). Deterministic heuristic (~len/4); older tool-result payloads
140
+ # are stubbed/dropped to keep the re-sent history under this many tokens.
141
+ # Positive integer; malformed/<=0 falls back to 60000.
142
+ LANGGRAPH_CONTEXT_TOKEN_BUDGET=60000
143
+
144
+ # ----- HITL demo branch gate (Kanban #1107 — WARN-2 security fix) -----
145
+ # Set to "1" to enable the `HITL demo —` title-prefix branch in
146
+ # langgraph/nodes.py:general_node. Used for live demos / onboarding workshops
147
+ # so the engine's interrupt → resume loop can be exercised end-to-end against
148
+ # the live stack.
149
+ #
150
+ # Leave EMPTY in production — any other value (including unset) keeps the
151
+ # demo path INACTIVE. CWE-489 / OWASP A05: without the gate, any authenticated
152
+ # user with task-create permission can trigger the hardcoded interrupt branch
153
+ # just by prefixing their task title with "HITL demo —".
154
+ #
155
+ # Dev compose default: docker-compose.yml passes `HITL_DEMO_ENABLED:-1` so
156
+ # the #1073 smoke task + onboarding demos work on a fresh checkout.
157
+ HITL_DEMO_ENABLED=
158
+
159
+ # ----- pytest_runner role password (Kanban #1109 — L4 prevention) -----
160
+ # Last-resort DB-engine-layer gate for the 2026-05-17 dev-DB-wipe incident.
161
+ # The alembic migration 0034_pytest_runner_role creates a constrained PG
162
+ # role `pytest_runner` with this password; api/tests/conftest.py binds
163
+ # pytest connections to that role. The role has:
164
+ # - full DDL/DML on `agent_teams_test` (owns the DB)
165
+ # - SELECT-only on `agent_teams` (live) — every destructive op REVOKEd
166
+ # Effect: even if all software defenses (L1 hook / L2 conftest invariant /
167
+ # L3 settings) are bypassed, the DB itself refuses INSERT/UPDATE/DELETE/
168
+ # TRUNCATE on live data during pytest with `permission denied for table ...`.
169
+ #
170
+ # Dev default fallback: the compose env passes
171
+ # `pytest_runner_dev_only_NOT_FOR_PROD` if you leave this blank, so a fresh
172
+ # checkout's `docker compose up` "just works". Conftest emits a loud
173
+ # UserWarning at load when running on the fallback. PRODUCTION deployments
174
+ # MUST set a real password here (rotate via re-running `alembic upgrade
175
+ # head` — the migration is idempotent and ALTERs the existing role's
176
+ # password to the current env value).
177
+ #
178
+ # Cross-ref: incidents/2026-05-17-dev-db-wipe.md.
179
+ PYTEST_DB_PASSWORD=
180
+
181
+ # ----- Off-site encrypted backup (Kanban #959 + L12 #1120) -----
182
+ # Minimum pg_dump output size (bytes) below which BackupRunner.run_once()
183
+ # aborts BEFORE uploading. Defense against silent backup corruption when the
184
+ # api container starts pointed at an empty/rogue DB: a sub-100KB dump would
185
+ # get uploaded, retention would eventually delete the older good backups,
186
+ # and restore would yield an empty DB. Default 102400 (100 KB) — a populated
187
+ # agent_teams DB is multi-MB. Override only if you have a deliberately tiny
188
+ # DB and accept the risk. Cross-ref:
189
+ # incidents/2026-05-17-dev-db-wipe.md (sibling L8 = lifespan DB allowlist).
190
+ BACKUP_MIN_BYTES=102400
191
+
192
+ # ----- Web Push / VAPID (Kanban #955.A) -----
193
+ # Generate a fresh keypair ONCE per deployment:
194
+ # docker compose exec -T api python -m scripts.generate_vapid_keys
195
+ # The script prints three lines (public, private, subject placeholder) — copy
196
+ # them into the three vars below. NEVER commit the PRIVATE key. The PUBLIC
197
+ # key is also handed to the FE via its own env var in slice 955.C; both
198
+ # halves must come from the same generated pair.
199
+ #
200
+ # Subject MUST be `mailto:<email>` or `https://<url>` per RFC 8292. The
201
+ # default below works for the operator's personal deployment; change it for
202
+ # other operators / shared deployments.
203
+ #
204
+ # Empty values are valid — the notify_web_push.py adapter surfaces
205
+ # `missing_env_VAPID_*` and the router falls through cleanly (same posture
206
+ # as TELEGRAM_BOT_TOKEN). The api container will start; only push delivery
207
+ # is disabled until the keys are filled in.
208
+ #
209
+ # Slice 955.C — the FE container reads VAPID_PUBLIC_KEY too (via the
210
+ # docker-compose mapping `NEXT_PUBLIC_VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY}`)
211
+ # so the browser bundle has the public half for PushManager.subscribe().
212
+ # No separate FE env var to configure — both sides come from this same value.
213
+ VAPID_PUBLIC_KEY=
214
+ VAPID_PRIVATE_KEY=
215
+ VAPID_SUBJECT=mailto:admin@example.com
216
+
217
+ # ----- Credentials vault (Kanban #1326 M3) -----
218
+ # Fernet url-safe base64 master key for the project_credentials.ciphertext
219
+ # column. REQUIRED — the api container's lifespan calls get_fernet() and
220
+ # refuses to start if this is missing or malformed.
221
+ #
222
+ # AUTO-GENERATED on first install: bin/install.ps1 (Windows) and bin/install.sh
223
+ # (macOS/Linux/WSL) detect an empty/missing value here and automatically generate
224
+ # a valid Fernet key (URL-safe base64 of 32 random bytes). You do NOT need to
225
+ # set this manually on a fresh clone — just run the installer.
226
+ #
227
+ # Manual generation (if needed):
228
+ # docker compose exec -T api python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
229
+ #
230
+ # BACKUP WARNING: losing the key makes ALL stored vault credentials permanently
231
+ # unrecoverable. After install, copy the generated value to a password manager
232
+ # or offline storage (USB, encrypted vault, etc.). The installer prints a
233
+ # reminder at generation time.
234
+ #
235
+ # Rotation procedure (decrypt-with-old + re-encrypt-with-new per row):
236
+ # see _scratch/standards-draft-credentials-rotation.md (Lead promotes to
237
+ # context/standards/security/credentials-rotation.md).
238
+ #
239
+ # NEVER commit the real value. Leave this placeholder in .env.example.
240
+ # The installer replaces it in the real .env file.
241
+ CREDENTIALS_MASTER_KEY=
242
+
243
+ # ----- Operator-action key (Kanban #1857 / #1852 Phase 1) -----
244
+ # The platform's operator-vs-AI write-authorization secret. Read via os.environ
245
+ # inside the api container ONLY (services/operator_auth.py). It is how a gated
246
+ # write proves "a HUMAN operator did this" vs "an AI agent did this".
247
+ #
248
+ # 🔒 OPERATOR-ONLY — MUST NOT appear in the langgraph worker env nor any
249
+ # agent-readable env. An agent that wants to forge the `X-Operator-Token` header
250
+ # has nothing to forge it WITH only because this secret never enters its scope.
251
+ # This is the ONE load-bearing discipline of the whole scheme (design §7),
252
+ # identical in kind to the CREDENTIALS_MASTER_KEY discipline above. A leak turns
253
+ # the gate into a blanket day-pass an agent can self-issue.
254
+ #
255
+ # ACTIVATION (the gate is INACTIVE by default — fail-open when unset):
256
+ # 1. Set a strong random value here in the real .env (e.g.
257
+ # docker compose exec -T api python -c "import secrets; print(secrets.token_urlsafe(32))"
258
+ # 2. Add `OPERATOR_ACTION_KEY: ${OPERATOR_ACTION_KEY:-}` to the **api** service
259
+ # `environment:` block in docker-compose.yml (NOT the langgraph block), then
260
+ # docker compose -p agent-teams up -d --force-recreate api
261
+ # 3. Wire the secret into your operator verify-flow as the `X-Operator-Token`
262
+ # header on the PATCH /api/tasks/{id} that sets verified_by='user'/'operator'.
263
+ # While UNSET, gated writes are ALLOWED (a one-time WARN is logged) so the code
264
+ # can land without breaking the running app.
265
+ #
266
+ # NEVER commit the real value. Leave this placeholder in .env.example.
267
+ OPERATOR_ACTION_KEY=
268
+
269
+ # ----- Email tools (Gmail + Outlook OAuth) — Kanban #1604/#1608 -----
270
+ # These are read via os.environ inside the api container (gmail_client.py,
271
+ # outlook_client.py, gate.py). They MUST live here (root .env) so docker-compose
272
+ # can substitute them into the api service environment block. The api/.env.example
273
+ # carries setup instructions for local (non-docker) uvicorn runs only.
274
+ #
275
+ # Gmail OAuth — see api/.env.example Kanban #1604 for Google Cloud Console steps.
276
+ # GOOGLE_OAUTH_CLIENT_ID=
277
+ # GOOGLE_OAUTH_CLIENT_SECRET=
278
+ # GOOGLE_OAUTH_REDIRECT_URI=http://localhost:8456/api/tools/email/auth/gmail/callback
279
+ #
280
+ # Email-tools shared rate/audit config
281
+ # EMAIL_TOOLS_DAILY_UNITS_CAP=5000
282
+ # EMAIL_TOOLS_BULK_THRESHOLD=100
283
+ # EMAIL_TOOLS_AUDIT_PATH=/repo/_scratch/email-tools-audit.jsonl
284
+ #
285
+ # Outlook OAuth — see api/.env.example Kanban #1608 for Azure portal steps.
286
+ # AZURE_OAUTH_CLIENT_ID=
287
+ # AZURE_OAUTH_CLIENT_SECRET=
288
+ # AZURE_OAUTH_TENANT=consumers
289
+ # AZURE_OAUTH_REDIRECT_URI=http://localhost:8456/api/tools/email/auth/outlook/callback
package/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # agent-teams
2
+
3
+ **A self-hosted orchestration and governance layer that turns Claude Code or OpenAI Codex into a persistent, governed, multi-domain agent team.**
4
+
5
+ You know the feeling: the coding session that started sharp is now drifting, re-explaining itself, and holding your entire plan hostage. A single CLI is a powerful brain with no memory across sessions, no project structure, and no safety rails.
6
+
7
+ agent-teams closes that gap. It wraps your coding CLI with a Postgres-backed Kanban, a Lead meta-orchestrator that spawns fresh domain specialists per task, a five-zone context model, and a defense-in-depth safety layer. File the queue, step away, trust it's handled — the leverage of a whole team, without the burnout of being one.
8
+
9
+ Everything runs locally in Docker. No cloud sign-up, no SaaS subscription, no code leaving your network.
10
+
11
+ It is also **dogfooded**: agent-teams builds agent-teams. The repo's own commit history and Kanban are living proof.
12
+
13
+ ---
14
+
15
+ ## Why it's different
16
+
17
+ Claude Code already gives you sub-agents, and you can keep several sessions open. agent-teams is the layer that makes that raw power actually land: every task becomes a clean, scoped contract instead of one sprawling chat you keep having to wrangle.
18
+
19
+ | | Self-hosted | Persistent task/project state | Beyond code | Governance/safety layer | Form |
20
+ |---|:--:|:--:|:--:|:--:|---|
21
+ | Cloud SWE agents (Devin, Cursor, Windsurf) | ✗ | ✗ session/codebase | ✗ code-only | black-box | product / IDE |
22
+ | AI assistant (GitHub Copilot) | ✗ | ✗ chat-scoped | ✗ code-only | black-box | product |
23
+ | Agent frameworks (CrewAI, AutoGen, LangGraph) | ✓ lib | ✗ you build it | ✓ DIY | ✗ you build it | library |
24
+ | Self-hosted platform (OpenHands) | ✓ | ~ less structured | ~ dev-focused | local isolation | product / SDK |
25
+ | **agent-teams** | ✓ | ✓ Postgres Kanban + 5-zone context | ✓ team playbooks (dev/content/SEO/…) | ✓ defense-in-depth + AC + HITL + cost | **layer on Claude Code / Codex** |
26
+
27
+ The gap it fills: a **self-hosted, persistent, governed, multi-domain orchestration layer** — the cloud agents and IDEs aren't self-hosted or persistent, and the frameworks hand you a toolbox and a weekend of plumbing. This is the part you'd otherwise build yourself, at night, instead of shipping: the state, the governance, and the team structure, already wired.
28
+
29
+ ---
30
+
31
+ ## What's genuinely special
32
+
33
+ - **Tasks are contracts — with proof.** Every task carries structured acceptance criteria. Before a task can be marked done, each criterion is verified with evidence and stamped passed/failed. The system proves the work met the contract; it doesn't just claim "done." Hard cost guardrails (daily/monthly budget caps → `429`) and a full `tasks_history` audit trail are built in.
34
+
35
+ - **Batch and parallel without context rot.** Queue tasks, run them back-to-back or in parallel — each spawns a fresh domain specialist with scoped context. No sprawling conversation, no bleed-through. The Kanban holds the plan; the agents hold nothing stale.
36
+
37
+ - **Two execution modes.** Mode A (production today): Claude Code or Codex drives each specialist interactively with per-action approval — you keep control. Mode B (actively in development): flip a task to `auto_headless` and the LangGraph engine runs it with no terminal open, Postgres-checkpointed.
38
+
39
+ - **Rich planning views.** Board · List · Calendar · Gantt in one switcher. Calendar supports week/month with drag-to-reschedule. Gantt doubles as the milestone home — drag a task straight onto a milestone and watch the progress rollup update.
40
+
41
+ - **Extend without migrations.** Add a new team or new agent types by editing constants and dropping a markdown file — no DB migration required. 8 teams and ~39 specialist agent definitions ship today. → [How to add a team](readme_dev.md#team-roster--dev-team) · [Full onboarding runbook](context/teams/dev/team-onboarding-runbook.md)
42
+
43
+ - **Self-hosted, local-first, dogfooded.** Runs in Docker on your machine. Anthropic, OpenAI, or fully-local Ollama — your choice, one `.env` variable. No code leaves your network. And the system building itself is the system you're reading about: the commit log and live Kanban are the proof.
44
+
45
+ ---
46
+
47
+ ## What it is — and isn't
48
+
49
+ **It is:** an orchestration and governance layer on top of a coding CLI. Works today with **Claude Code** and **OpenAI Codex**.
50
+
51
+ **It isn't:**
52
+ - a frontier autonomous SWE agent like **Devin** — it orchestrates your coding agent, it doesn't replace one;
53
+ - an IDE like **Cursor** or **Windsurf** — no editor here; keep your own;
54
+ - a from-scratch agent framework like **CrewAI** / **AutoGen** / **LangGraph** — it actually *uses* LangGraph for its headless engine rather than reinventing it.
55
+
56
+ **Honest status on the headless engine:** today the production path is Mode A — Claude Code / Codex CLI driven interactively (per-action approval). The `langgraph` service (supervisor → specialist graph, Postgres-checkpointed) is the Mode B path and is **actively in development**. Don't rely on it for critical work yet.
57
+
58
+ ---
59
+
60
+ ## Architecture at a glance
61
+
62
+ ```mermaid
63
+ flowchart TD
64
+ Operator([Operator]) -->|files tasks, answers HITL| Kanban[(Kanban · Postgres)]
65
+ Operator -->|talks to| Lead[Lead · meta-orchestrator]
66
+ Lead -->|reads| Playbook[Team playbook]
67
+ Lead -->|resolves project, spawns| Specialists[Specialists: backend / frontend / tester / reviewer / …]
68
+ Specialists -->|run on| CLI[Claude Code / Codex CLI]
69
+ Lead <-->|read/write state| Context[(5-zone context:<br/>standards · team · project · role)]
70
+ Specialists -->|update| Kanban
71
+ CLI -.headless path.-> Engine[LangGraph engine · Postgres checkpoints]
72
+ ```
73
+
74
+ The Lead reads the team playbook, resolves the active project, and spawns the right specialists. Specialists run on your coding CLI and write their results back to the Kanban and five context zones — no context leaks between tasks.
75
+
76
+ ---
77
+
78
+ ## CLI-agnostic by design
79
+
80
+ The orchestration works across coding CLIs because the rules live in portable instruction files: [`CLAUDE.md`](CLAUDE.md) for Claude Code and [`AGENTS.md`](AGENTS.md) for Codex. Same governance, same lanes, same team structure — whichever CLI you run. You're not locked to one vendor.
81
+
82
+ ---
83
+
84
+ ## Get started
85
+
86
+ 1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) and restart your computer.
87
+ 2. Open a terminal **in this folder** and run the installer:
88
+ - **macOS / Linux / WSL:** `./bin/install.sh`
89
+ - **Windows (PowerShell):** `.\bin\install.ps1` *(if scripts are blocked, run `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` once first)*
90
+ 3. Open **http://localhost:5431** — your Kanban board. The installer seeds a `demo-tour` project to explore. Create tasks, queue them, and answer agent questions as they come up.
91
+
92
+ Two ways to put agents to work:
93
+
94
+ - **Mode A — Claude Code / Codex session (production today).** Open this repo in Claude Code or OpenAI Codex. The Lead resolves your project, loads the team playbook, and orchestrates specialists end-to-end. → **[CLAUDE-CODE-START.md](CLAUDE-CODE-START.md)**
95
+ - **Mode B — One-click "Start" on the board *(in active development)*.** Flip a task to auto-run and the headless `langgraph` engine handles it with no terminal open. See "What it is — and isn't" above for the honest status.
96
+
97
+ The installer is safe to re-run; services keep running after you close the terminal.
98
+
99
+ **Multi-provider, local-first.** Switch models with one `.env` variable (`LANGGRAPH_LLM_PROVIDER`): **Anthropic** (default), **OpenAI**, or **Ollama** for fully local inference — no API key, no network egress. With Ollama, nothing leaves your machine.
100
+
101
+ **Stop / reset:** `docker compose down` to stop; `.\bin\reset.ps1` (or `./bin/reset.sh`) to wipe and start fresh.
102
+
103
+ ---
104
+
105
+ ## Slash-command skills (tn-*)
106
+
107
+ These are reusable Claude Code commands that encode Kanban API conventions, preventing common mistakes (missing project_id, incomplete acceptance criteria, status-change guard violations). They activate after a Claude Code restart and are auto-detected on live-reload.
108
+
109
+ | Command | What it does |
110
+ |---------|-------------|
111
+ | **Tasks** | |
112
+ | `/tn-task-create <description>` | Create a Kanban task correctly (project_id in request body, acceptance_criteria at creation). |
113
+ | `/tn-task <id>` | Show one task with its acceptance criteria (read-only). |
114
+ | `/tn-tasks-next [N]` | List the next N actionable tasks (current milestone first, blockers first, then priority; N defaults 10). |
115
+ | `/tn-task-done <id>` | Verify every acceptance criterion, then flip the task to DONE (refuses if any criterion is unmet). |
116
+ | `/tn-task-update <id> <changes>` | Guarded status/priority update (BLOCKED only via blocked_by; status changes carry a reason; DONE is redirected to /tn-task-done). |
117
+ | `/tn-task-attach <task> <milestone>` | Attach a task to a milestone (same-project checked). |
118
+ | **Milestones** | |
119
+ | `/tn-milestone-create <title>` | Create a milestone (defaults to "planned"). |
120
+ | `/tn-milestone-done <id>` | Release a milestone after checking its child tasks are complete. |
121
+ | `/tn-milestones` | List milestones with their task rollup (done/total, progress %). |
122
+ | **Workflow** | |
123
+ | `/tn-intense-review <scope>` | 2-round adversarial review + test-hardening pass (reviewers + determinism loop). |
124
+ | `/tn-spec <idea>` | 2 rounds of spec pushback + revision before creating a task. |
125
+ | **Project** | |
126
+ | `/tn-bind <project>` | Bind the session to a project by name (resolves + persists the active project). |
127
+ | `/tn-audit [project]` | On-demand project health audit (3 metrics + continue/review/pause). |
128
+
129
+ Each skill lives at `.claude/skills/<name>/SKILL.md` and is invoked as `/<name>` in Claude Code.
130
+
131
+ ---
132
+
133
+ ## Learn more
134
+
135
+ Companion docs go deep so this README stays scannable:
136
+
137
+ - **[QUICKSTART.md](QUICKSTART.md)** — 5-minute tour via the browser UI.
138
+ - **[CLAUDE-CODE-START.md](CLAUDE-CODE-START.md)** — driving the team from a Claude Code terminal session.
139
+ - **[USAGE-POWER.md](USAGE-POWER.md)** — parallel agents, auto-mode, multi-project workflows, mobile remote access.
140
+ - **[readme_dev.md](readme_dev.md)** — architecture deep-dive: storage zones, team rosters, configuration, and extensibility (including how to add a new team or agent type).
141
+ - **[context/teams/dev/team-onboarding-runbook.md](context/teams/dev/team-onboarding-runbook.md)** — full step-by-step runbook for adding teams and agents.
142
+
143
+ For the full development history, browse the git log and the Kanban that drove it — dogfooding in action.
package/cli/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # agent-teams CLI
2
+
3
+ Zero-dependency Node.js CLI that launches the agent-teams AI Kanban platform
4
+ locally via Docker Compose.
5
+
6
+ ## Prerequisites
7
+
8
+ **Docker Desktop** (or Docker Engine on Linux) must be installed and running
9
+ before any CLI command will work. This package does NOT install Docker.
10
+
11
+ **git** must be installed and on PATH. It is required when running the CLI
12
+ outside a cloned repository (standalone mode — see below). This package does
13
+ NOT install git.
14
+
15
+ - Docker: <https://docs.docker.com/get-docker/>
16
+ - Windows / macOS: install Docker Desktop and start it.
17
+ - Linux: install Docker Engine + `docker compose` plugin and ensure the daemon
18
+ is running (`sudo systemctl start docker`).
19
+ - git: <https://git-scm.com/downloads>
20
+
21
+ ## Quick start
22
+
23
+ ```bash
24
+ npx @bankung/agent-teams up
25
+ ```
26
+
27
+ This command works in several modes. Choose the one that fits your situation:
28
+
29
+ ### Model A — pull pre-built images (fastest, no clone)
30
+
31
+ ```bash
32
+ npx @bankung/agent-teams up --images
33
+ ```
34
+
35
+ Pulls pre-built images from the GitHub Container Registry (GHCR) and starts
36
+ the full stack. **No git clone or local build required** — Docker just pulls
37
+ the images. This is the recommended path for users who want to run the platform
38
+ without modifying source code.
39
+
40
+ Aliases: `--images` and `--pull` are equivalent.
41
+
42
+ Requirements:
43
+ - Docker Desktop (or Docker Engine) installed and running.
44
+ - Images must be published to GHCR by the release CI (`v*` tag push). If you
45
+ want to pin a specific version set `AGENT_TEAMS_VERSION=1.2.3` in `.env`.
46
+
47
+ ### Model B — clone + build from source (default)
48
+
49
+ #### Standalone mode (run from any empty directory)
50
+
51
+ ```bash
52
+ mkdir my-agent-teams && cd my-agent-teams
53
+ npx @bankung/agent-teams up
54
+ ```
55
+
56
+ The CLI detects that `docker-compose.yml` is absent, clones
57
+ `https://github.com/bankung/agent-teams.git` into `<cwd>/agent-teams`, then
58
+ builds and starts the stack from that cloned directory.
59
+
60
+ **Note:** Standalone mode requires the GitHub repository to be public.
61
+
62
+ **Note:** The first `up` builds Docker images from source — this can take
63
+ several minutes. Subsequent runs use the Docker layer cache and are fast.
64
+
65
+ You can override the clone destination:
66
+
67
+ ```bash
68
+ npx @bankung/agent-teams up /path/to/target-dir
69
+ ```
70
+
71
+ #### In-repo mode (run from inside a cloned repository)
72
+
73
+ ```bash
74
+ git clone https://github.com/bankung/agent-teams.git
75
+ cd agent-teams
76
+ npx @bankung/agent-teams up
77
+ ```
78
+
79
+ The CLI detects `docker-compose.yml` in the package root and uses the existing
80
+ checkout directly — no clone occurs.
81
+
82
+ ### What `up` does (both modes)
83
+
84
+ 1. Verifies the Docker daemon is reachable (clear error if not).
85
+ 2. **`--images` mode:** pulls pre-built GHCR images.
86
+ **Default mode:** resolves/clones the repo root, then runs `docker compose up -d --build`.
87
+ 3. Copies `.env.example` to `.env` if no `.env` exists yet.
88
+ 4. Generates a `CREDENTIALS_MASTER_KEY` (Fernet key) if the value is empty —
89
+ prints a backup reminder. **Back up this key to a password manager.**
90
+ 5. Applies database migrations (`alembic upgrade head`).
91
+ 6. Waits up to 60 seconds for the API to become healthy on port 8456.
92
+ 7. Runs the seed script (idempotent — safe to re-run).
93
+ 8. Prompts for your Claude Code plan (Max / Pro) and applies the matching tier
94
+ preset. Skipped automatically in non-interactive environments.
95
+ 9. Prints the Kanban URL and attempts to open it in your default browser.
96
+
97
+ ## Commands
98
+
99
+ | Command | Description |
100
+ |---------|-------------|
101
+ | `up [targetDir]` | Build and start all services. Idempotent — safe to run on an existing install. In standalone mode, clones the repo first. |
102
+ | `up --images` | Pull pre-built images from GHCR and start all services. No clone or build. Alias: `--pull`. |
103
+ | `down` | Stop all containers. Volumes (database data) are preserved. |
104
+ | `status` | Show container health (`docker compose ps`) and probe the API on :8456. |
105
+ | `reset` | **Destructive.** Wipes the Postgres volume (all data gone) and rebuilds. Prompts for confirmation (type `WIPE`) unless `--yes` is passed. |
106
+ | `--help` / `help` | Print usage. |
107
+ | `--version` | Print CLI version. |
108
+
109
+ ### `reset` bypass
110
+
111
+ ```bash
112
+ # flag
113
+ npx @bankung/agent-teams reset --yes
114
+
115
+ # env var
116
+ AGENT_TEAMS_RESET_YES=1 npx @bankung/agent-teams reset
117
+ ```
118
+
119
+ ### Pinning an image version
120
+
121
+ Set `AGENT_TEAMS_VERSION` in your `.env` (or export it) to pull a specific
122
+ release rather than `latest`:
123
+
124
+ ```bash
125
+ echo "AGENT_TEAMS_VERSION=1.2.3" >> .env
126
+ npx @bankung/agent-teams up --images
127
+ ```
128
+
129
+ Images are published to GHCR by the GitHub Actions workflow
130
+ `.github/workflows/release-images.yml` on every `v*` tag push. `npm publish`
131
+ is performed by the operator separately.
132
+
133
+ ## Port defaults
134
+
135
+ | Service | Default port | Override via .env |
136
+ |---------|-------------|-------------------|
137
+ | Web (Kanban UI) | 5431 | `WEB_PORT` |
138
+ | API | 8456 | `API_PORT` |
139
+ | PostgreSQL | 5432 | `POSTGRES_PORT` |
140
+ | LangGraph | 8465 | `LANGGRAPH_PORT` |