@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 +289 -0
- package/README.md +143 -0
- package/cli/README.md +140 -0
- package/cli/index.js +665 -0
- package/cli/lib/confirm.js +30 -0
- package/cli/lib/docker.js +93 -0
- package/cli/lib/env.js +101 -0
- package/cli/lib/health.js +53 -0
- package/cli/lib/open-url.js +60 -0
- package/docker-compose.images.yml +177 -0
- package/package.json +33 -0
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` |
|