kanban-system 1.0.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 +76 -0
- package/CLAUDE.md +108 -0
- package/README.md +272 -0
- package/agents/_TEMPLATE.md +42 -0
- package/agents/backend-agent.md +81 -0
- package/agents/deploy-gate-agent.md +73 -0
- package/agents/frontend-agent.md +73 -0
- package/agents/monitor-agent.md +65 -0
- package/agents/orchestrator.md +91 -0
- package/agents/reviewer-codex.md +51 -0
- package/bin/cli.js +171 -0
- package/config.example.js +99 -0
- package/docs/adapting-to-your-project.md +155 -0
- package/docs/example-apex.md +86 -0
- package/docs/the-pattern.md +92 -0
- package/hooks/launchd.plist.template +66 -0
- package/hooks/pre-push.sample +61 -0
- package/lib/config.cjs +138 -0
- package/lib/detect/_template.cjs +63 -0
- package/lib/detect/rules.json +28 -0
- package/lib/detect/sentry.cjs +86 -0
- package/lib/detect/vercel.cjs +62 -0
- package/lib/gate/index.cjs +182 -0
- package/lib/runner/adapters/both.cjs +33 -0
- package/lib/runner/adapters/claude.cjs +119 -0
- package/lib/runner/adapters/codex.cjs +43 -0
- package/lib/runner/adapters/reviewer.cjs +91 -0
- package/lib/runner/budget.cjs +75 -0
- package/lib/runner/index.cjs +93 -0
- package/lib/runner/result-merger.cjs +58 -0
- package/lib/runner/worktree-manager.cjs +64 -0
- package/lib/watch/scheduler.cjs +164 -0
- package/package.json +59 -0
- package/playbooks/_TEMPLATE.html +54 -0
- package/playbooks/build-fail.html +57 -0
- package/playbooks/deploy-rollback.html +53 -0
- package/playbooks/e2e-regression.html +58 -0
- package/playbooks/playbook.css +26 -0
- package/playbooks/sentry-spike.html +53 -0
- package/server/kanban.cjs +1152 -0
- package/skills/archive.md +18 -0
- package/skills/gate.md +22 -0
- package/skills/standup.md +24 -0
- package/skills/triage.md +24 -0
- package/ui/kanban.html +628 -0
- package/ui/styles/kanban.css +436 -0
- package/ui/styles/progress.css +315 -0
- package/ui/styles/tokens.css +291 -0
package/.env.example
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# kanban-system — environment variables
|
|
2
|
+
# Copy to .env, fill values, NEVER commit .env
|
|
3
|
+
|
|
4
|
+
# ── Server ────────────────────────────────────────────────────────
|
|
5
|
+
# Port the kanban dashboard listens on. Also set in config.js (config.js wins
|
|
6
|
+
# if both are present unless PORT is exported).
|
|
7
|
+
PORT=8080
|
|
8
|
+
KANBAN_BASE=http://localhost:8080
|
|
9
|
+
|
|
10
|
+
# ── Multi-agent / cross-validation policy ─────────────────────────
|
|
11
|
+
# Severity threshold for auto-promoting single-runner tasks to `both`
|
|
12
|
+
# (cross-validated). Values: low, medium, high, critical.
|
|
13
|
+
CROSS_VALIDATION_THRESHOLD=medium
|
|
14
|
+
|
|
15
|
+
# Daily cap on the second-model (Codex / GPT) invocations. Resets at UTC midnight.
|
|
16
|
+
# When exceeded, runner=codex/both/reviewer:codex falls back to the primary model.
|
|
17
|
+
DAILY_CODEX_BUDGET=200
|
|
18
|
+
|
|
19
|
+
# Model fallback chain — comma-separated, priority order. First is most capable.
|
|
20
|
+
MODEL_FALLBACK_CHAIN=claude-opus-4-7,claude-sonnet-4-6,claude-haiku-4-5
|
|
21
|
+
|
|
22
|
+
# ── Watch + Detect ────────────────────────────────────────────────
|
|
23
|
+
WATCH_INTERVAL_MS=300000
|
|
24
|
+
WATCH_DRY_RUN=0
|
|
25
|
+
# Comma-separated detector names. Empty = all enabled detectors in lib/detect/rules.json
|
|
26
|
+
WATCH_ENABLED=
|
|
27
|
+
|
|
28
|
+
# Sentry (optional — detector degrades gracefully when blank)
|
|
29
|
+
SENTRY_AUTH_TOKEN=
|
|
30
|
+
SENTRY_ORG_SLUG=
|
|
31
|
+
SENTRY_PROJECT_SLUG=
|
|
32
|
+
|
|
33
|
+
# Vercel (optional)
|
|
34
|
+
VERCEL_TOKEN=
|
|
35
|
+
VERCEL_PROJECT_ID=
|
|
36
|
+
VERCEL_TEAM_ID=
|
|
37
|
+
|
|
38
|
+
# ── Pre-deploy gate ───────────────────────────────────────────────
|
|
39
|
+
GATE_TIMEOUT_MS=600000
|
|
40
|
+
GATE_SKIP_E2E=0
|
|
41
|
+
STRICT_BUNDLE=0
|
|
42
|
+
# Disable the auto-created kanban task on gate failure (CI/scripts)
|
|
43
|
+
GATE_NO_KANBAN=0
|
|
44
|
+
|
|
45
|
+
# ── Slack (optional — start/progress/done reporting) ──────────────
|
|
46
|
+
SLACK_BOT_TOKEN=
|
|
47
|
+
SLACK_APP_TOKEN=
|
|
48
|
+
SLACK_CHANNEL_ID=
|
|
49
|
+
SLACK_AGENT_WEBHOOK=
|
|
50
|
+
SLACK_ADMIN_USERS=
|
|
51
|
+
SLACK_COMMAND=/kanban
|
|
52
|
+
|
|
53
|
+
# ── Telegram (optional — Ops Thread mirror panel) ─────────────────
|
|
54
|
+
# Drop in TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID and the kanban server starts
|
|
55
|
+
# mirroring the right-side "Ops Thread" panel to that Telegram chat (outbound
|
|
56
|
+
# via sendMessage, inbound via getUpdates long-poll). Both blank ⇒ the panel
|
|
57
|
+
# still works locally as a kanban-only chat; nothing is sent to Telegram.
|
|
58
|
+
#
|
|
59
|
+
# How to get values:
|
|
60
|
+
# 1. BotFather (@BotFather on Telegram) → /newbot → copy the token here.
|
|
61
|
+
# 2. Send any DM to your new bot from your Telegram account.
|
|
62
|
+
# 3. With the server running: curl http://localhost:8080/api/telegram/whoami
|
|
63
|
+
# → copy chat.id of your DM (a number like 6131488858) into TELEGRAM_CHAT_ID.
|
|
64
|
+
TELEGRAM_BOT_TOKEN=
|
|
65
|
+
TELEGRAM_CHAT_ID=
|
|
66
|
+
# Optional comma-separated allowlist (defaults to TELEGRAM_CHAT_ID only)
|
|
67
|
+
TELEGRAM_ALLOWED_CHAT_IDS=
|
|
68
|
+
# Set to 0 to disable the long-poll worker (you can still send outbound)
|
|
69
|
+
TELEGRAM_POLL_ENABLED=1
|
|
70
|
+
TELEGRAM_POLL_INTERVAL_MS=1500
|
|
71
|
+
|
|
72
|
+
# ── Anthropic / OpenAI (only if you run the CLI adapters directly) ─
|
|
73
|
+
# The runner adapters shell out to the `claude` / `codex` CLIs, which manage
|
|
74
|
+
# their own auth. These are placeholders for setups that pass keys via env.
|
|
75
|
+
ANTHROPIC_API_KEY=
|
|
76
|
+
OPENAI_API_KEY=
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# kanban-system — operating rules
|
|
2
|
+
|
|
3
|
+
This repo is a **kanban board + multi-agent (Claude + Codex) ops/dev harness**: a
|
|
4
|
+
kanban server with a REST API, an orchestrator + specialist agents, incident
|
|
5
|
+
playbooks, a 24h watch/detect loop, a subagent runner, and a pre-deploy gate. It runs
|
|
6
|
+
*alongside* an application repo (the one `config.js → repoPath` points at) and drives
|
|
7
|
+
work on it — it does not contain that application's code.
|
|
8
|
+
|
|
9
|
+
## Layout
|
|
10
|
+
| Path | Purpose |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `server/kanban.cjs` | Kanban dashboard + REST API + SSE. `npm start`. |
|
|
13
|
+
| `ui/` | The dashboard HTML + token CSS. |
|
|
14
|
+
| `agents/*.md` | Agent definitions — frontmatter (`name`, `mission`, `runner`, `owns`, …) + body. `_TEMPLATE.md` to add one. |
|
|
15
|
+
| `playbooks/*.html` | One-page incident runbooks. `_TEMPLATE.html` to add one. |
|
|
16
|
+
| `lib/config.cjs` | Config loader — reads `config.js` (or `config.example.js`) + `.env` + env overrides. |
|
|
17
|
+
| `lib/watch/scheduler.cjs` | 24h watch loop — runs detectors, turns findings into tasks. |
|
|
18
|
+
| `lib/detect/*` | Monitoring detectors (`sentry`, `vercel`, `_template`) + `rules.json`. |
|
|
19
|
+
| `lib/runner/*` | Subagent runner — `claude` / `codex` / `both` / `reviewer:*` adapters, git worktrees, budget. |
|
|
20
|
+
| `lib/gate/index.cjs` | Pre-deploy gate — runs `config.js → deployCommands` fail-fast. |
|
|
21
|
+
| `hooks/` | `pre-push.sample` (installs the gate as a git hook), `launchd.plist.template` (24h daemon; cron line in the comment). |
|
|
22
|
+
| `skills/` | Reusable Claude Code skill stubs — `/standup`, `/triage`, `/gate`, `/archive`. |
|
|
23
|
+
| `docs/` | `the-pattern.md` (why), `adapting-to-your-project.md` (how), `example-apex.md` (a worked case study — the only place project-specific content lives). |
|
|
24
|
+
| `config.example.js` / `config.js` | Per-project config. Copy the example to `config.js` (gitignored). |
|
|
25
|
+
| `.env.example` / `.env` | Tokens (Slack / Sentry / Vercel / Telegram / …). Copy, fill, never commit `.env`. |
|
|
26
|
+
|
|
27
|
+
## Ops Thread (Telegram mirror)
|
|
28
|
+
The dashboard's right-side panel is an append-only thread the operator and the agents
|
|
29
|
+
share. With `TELEGRAM_BOT_TOKEN` + `TELEGRAM_CHAT_ID` set in `.env` it mirrors
|
|
30
|
+
bidirectionally to a Telegram chat (outbound via `sendMessage`, inbound via long-poll
|
|
31
|
+
`getUpdates`). The kanban server also posts `📋 #N` / `▶️ #N` / `✅ #N` on task create /
|
|
32
|
+
start / complete to both sides. Agents append progress via `POST /api/ops-thread/append`
|
|
33
|
+
(role: `claude` / `agent` / `system`). The operator types in the panel input or replies
|
|
34
|
+
in Telegram. Both halves are best-effort — missing token/chatId disables the mirror but
|
|
35
|
+
the panel still works locally. Setup is in README "Ops Thread (Telegram mirror)".
|
|
36
|
+
|
|
37
|
+
## Server & config
|
|
38
|
+
- Start: `npm start` (or `node server/kanban.cjs`). Default port 8080 (`PORT` env or
|
|
39
|
+
`config.js → kanbanPort`).
|
|
40
|
+
- API base: `http://localhost:8080/api/`.
|
|
41
|
+
- Config resolution: `config.js` → `config.example.js` (fallback so it boots) → env
|
|
42
|
+
overrides on top. `.env` at the repo root is loaded automatically (so launchd / cron
|
|
43
|
+
see the tokens).
|
|
44
|
+
|
|
45
|
+
## Kanban-first instruction protocol — MUST FOLLOW
|
|
46
|
+
Every user instruction becomes a kanban task **before** any work starts. This is the
|
|
47
|
+
orchestrator's first duty (`agents/orchestrator.md`), and it applies to every agent.
|
|
48
|
+
|
|
49
|
+
1. On receiving an instruction: `POST /api/tasks` — `{ subject, description, agent,
|
|
50
|
+
metadata.runner, priority }`. Capture the instruction verbatim in `description`.
|
|
51
|
+
2. Set `agent` / `metadata.runner` / `priority` per the routing rules in
|
|
52
|
+
`agents/orchestrator.md`.
|
|
53
|
+
3. Transition the task to `in_progress` **only then** start the work.
|
|
54
|
+
4. On completion: set `reportPath` + `reportSummary`, then `completed`.
|
|
55
|
+
5. Report start / key progress / done via `POST /api/tasks/{id}/slack` (not a raw webhook).
|
|
56
|
+
|
|
57
|
+
**Exception — incident response**: a production-impacting incident or a 1-line,
|
|
58
|
+
obviously-reversible hotfix may be done immediately, but you must register a post-hoc
|
|
59
|
+
task within 1 hour tagged `metadata.source = "incident-response"` with what you did
|
|
60
|
+
and any follow-up. Nothing else qualifies — refactors, docs, features, ordinary bugs
|
|
61
|
+
all go through step 1 first. See `docs/the-pattern.md` → "Kanban-first".
|
|
62
|
+
|
|
63
|
+
## Task lifecycle & API
|
|
64
|
+
States: `pending` → `in_progress` → `in_review` → `completed`. Only the orchestrator
|
|
65
|
+
writes status transitions. `completed` requires `reportPath` + `reportSummary`.
|
|
66
|
+
|
|
67
|
+
| Method | Path | Body | Description |
|
|
68
|
+
|---|---|---|---|
|
|
69
|
+
| GET | `/api/tasks` | — | List all tasks |
|
|
70
|
+
| POST | `/api/tasks` | `{ subject, description, agent?, priority?, metadata? }` | Create |
|
|
71
|
+
| PUT | `/api/tasks/:id` | `{ status?, reportPath?, reportSummary?, metadata?, ... }` | Update |
|
|
72
|
+
| DELETE | `/api/tasks/:id` | — | Delete |
|
|
73
|
+
| POST | `/api/tasks/:id/slack` | `{ text }` | Post a note to Slack for this task |
|
|
74
|
+
| GET | `/api/agents` | — | Agent registry (from `agents/*.md` frontmatter) |
|
|
75
|
+
| GET | `/api/agents/:name/full` | — | One agent's full definition |
|
|
76
|
+
| GET | `/api/activity?since=&limit=` | — | Activity log |
|
|
77
|
+
| GET | `/events` | — | SSE stream of board updates |
|
|
78
|
+
|
|
79
|
+
## Multi-agent cross-validation
|
|
80
|
+
- `runner: claude` / `codex` — single model. For deterministic / mechanical work.
|
|
81
|
+
- `runner: reviewer:codex` — Claude implements, Codex reviews. Default for implementation work.
|
|
82
|
+
- `runner: both` — Claude + Codex independently, diffed. Disagreement → "needs human" column.
|
|
83
|
+
For high-stakes work (migrations, access-control, money paths). The disagreement is the safety feature.
|
|
84
|
+
- Auto-promote: severity ≥ `CROSS_VALIDATION_THRESHOLD` bumps single-model → `both`.
|
|
85
|
+
- Daily cap on the second model (`DAILY_CODEX_BUDGET`); fallback chain `MODEL_FALLBACK_CHAIN`.
|
|
86
|
+
See `docs/the-pattern.md` → "Cross-validation".
|
|
87
|
+
|
|
88
|
+
## Selvedge boundaries
|
|
89
|
+
Each agent declares `owns:` globs (relative to `config.js → repoPath`). Agents stay on
|
|
90
|
+
their side; the orchestrator routes by ownership. Shared surfaces (shared types,
|
|
91
|
+
dependency manifests, migrations) require a cross-check → that's where `runner: both`
|
|
92
|
+
earns its keep. Keep `owns:` globs non-overlapping.
|
|
93
|
+
|
|
94
|
+
## Pre-deploy gate
|
|
95
|
+
`lib/gate/index.cjs` runs `config.js → deployCommands` serially, fail-fast, from
|
|
96
|
+
`config.js → repoPath`, then an optional bundle-size inspection. The `pre-push.sample`
|
|
97
|
+
hook runs it on `git push` — fail → push blocked, "needs human" task auto-created. The
|
|
98
|
+
only override is `git push --no-verify` or `KANBAN_GATE_BYPASS=1 git push` (the latter
|
|
99
|
+
logged to `data/runs/overrides.jsonl`, reviewed at standup).
|
|
100
|
+
|
|
101
|
+
## Absolute rules
|
|
102
|
+
1. Don't ship without the gate passing (or an audited override).
|
|
103
|
+
2. Don't force-push the main branch.
|
|
104
|
+
3. Don't commit `.env` or `config.js` (both gitignored — keep it that way).
|
|
105
|
+
4. Don't cross selvedge boundaries (an agent edits only what it `owns`).
|
|
106
|
+
5. Don't store plaintext secrets in `data/`, logs, or committed files (use `.env`).
|
|
107
|
+
6. Don't start work on a user instruction without a kanban task first (incident-response exception only).
|
|
108
|
+
7. Don't auto-merge a `runner: both` disagreement — a human decides.
|
package/README.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# kanban-system
|
|
2
|
+
|
|
3
|
+
A kanban board where **multi-agent operators (Claude + Codex, via their CLIs)** run
|
|
4
|
+
24/7 ops and dev for a project: a person's instruction becomes a kanban task, the
|
|
5
|
+
orchestrator routes it to a specialist agent with a verification level (single-model /
|
|
6
|
+
review / independent cross-validation), the work happens in an isolated git worktree, a
|
|
7
|
+
pre-deploy gate blocks anything that doesn't build/test, a 24h watch loop turns
|
|
8
|
+
monitoring anomalies into tasks, and incident playbooks tell humans what to do when
|
|
9
|
+
something breaks. It's a *template* — clone it, point `config.js` at your front-end /
|
|
10
|
+
back-end repo, edit a few globs, and you have the "kanban + multi-agent" pattern
|
|
11
|
+
running on your codebase.
|
|
12
|
+
|
|
13
|
+
It runs *alongside* your application repo (it does not contain that app's code) and
|
|
14
|
+
drives work on it.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
Two ways to get started:
|
|
19
|
+
|
|
20
|
+
### Option A — GitHub Template (zero config, keeps update history)
|
|
21
|
+
|
|
22
|
+
1. Open **[github.com/Zakedu/kanban-system](https://github.com/Zakedu/kanban-system)** and click **"Use this template"** → **"Create a new repository"**.
|
|
23
|
+
2. Clone your new repo and jump straight to [Quick start](#quick-start).
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
gh repo create my-board --template Zakedu/kanban-system --private --clone
|
|
27
|
+
cd my-board
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Option B — npx CLI (zero clone, no GitHub account required)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx kanban-system init my-board
|
|
34
|
+
cd my-board
|
|
35
|
+
cp config.example.js config.js # edit: repoPath, deployCommands
|
|
36
|
+
cp .env.example .env # (optional) Slack / Sentry / Vercel tokens
|
|
37
|
+
npm install
|
|
38
|
+
npm start # → http://localhost:8080
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The CLI also exposes thin wrappers so you can run the harness commands from the
|
|
42
|
+
published package without cloning the repo:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx kanban-system start # start the kanban server
|
|
46
|
+
npx kanban-system watch # run the 24h watch scheduler
|
|
47
|
+
npx kanban-system gate # run the pre-deploy gate
|
|
48
|
+
npx kanban-system whoami # find your Telegram chat id
|
|
49
|
+
npx kanban-system --version
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Publishing to npm (maintainer only)
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# bump version first
|
|
56
|
+
npm version patch # or minor / major
|
|
57
|
+
|
|
58
|
+
npm publish --access public
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`npm publish` requires being logged in (`npm login`) and having push access to the
|
|
62
|
+
`Zakedu/kanban-system` repository. The `files` field in `package.json` controls what
|
|
63
|
+
ships in the tarball.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Architecture
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
┌─────────────────────────────┐
|
|
71
|
+
you / Slack / API ──────────▶ │ kanban server (REST + SSE) │ ◀── browser dashboard
|
|
72
|
+
│ server/kanban.cjs · ui/ │
|
|
73
|
+
└──────────────┬──────────────┘
|
|
74
|
+
│ tasks
|
|
75
|
+
┌─────────▼─────────┐
|
|
76
|
+
│ orchestrator │ routes by `owns` globs,
|
|
77
|
+
│ agents/orch...md │ sets the `runner`, enforces
|
|
78
|
+
└─────────┬─────────┘ the task state machine
|
|
79
|
+
┌─────────────────────────┼─────────────────────────┐
|
|
80
|
+
┌────────▼───────┐ ┌──────────────▼─────┐ ┌────────────────▼──────┐ ┌───────────▼────────┐
|
|
81
|
+
│ frontend-agent │ │ backend-agent │ │ deploy-gate-agent │ │ monitor-agent │
|
|
82
|
+
│ pages, UI, │ │ API, DB, migra- │ │ runs the gate (build │ │ polls Sentry / │
|
|
83
|
+
│ routing, i18n │ │ tions, authz │ │ /test) before deploy │ │ Vercel / custom │
|
|
84
|
+
└────────────────┘ └────────────────────┘ └───────────┬───────────┘ └─────────┬──────────┘
|
|
85
|
+
│ │ │ │
|
|
86
|
+
reviewer:codex runner: both hard gate, no anomalies → tasks
|
|
87
|
+
(Claude impl, (Claude + Codex agent override (lib/watch + lib/detect)
|
|
88
|
+
Codex reviews) independent, diffed) (hooks/pre-push.sample)
|
|
89
|
+
└────────────────────┴──── lib/runner (claude/codex/both/reviewer adapters, git worktrees, budget) ────┘
|
|
90
|
+
|
|
91
|
+
incident? ──▶ playbooks/*.html (one-page runbooks: trigger → diagnose → decision tree → escalate → aftermath)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- **kanban server** (`server/kanban.cjs` + `ui/`) — a 4-column board (pending /
|
|
95
|
+
in progress / needs human / completed) with a REST API, SSE live updates, an agent
|
|
96
|
+
registry from `agents/*.md`, and an optional Slack bot.
|
|
97
|
+
- **orchestrator** (`agents/orchestrator.md`) — the single decision-maker: turns every
|
|
98
|
+
instruction into a task, routes it (by `owns` glob, by severity), sets the `runner`,
|
|
99
|
+
owns the state machine. Never edits app code itself.
|
|
100
|
+
- **specialist agents** (`agents/frontend-agent.md`, `backend-agent.md`,
|
|
101
|
+
`deploy-gate-agent.md`, `monitor-agent.md`, `reviewer-codex.md`) — each `owns` a
|
|
102
|
+
non-overlapping slice of your repo and declares a default `runner`. `_TEMPLATE.md` to
|
|
103
|
+
add more.
|
|
104
|
+
- **playbooks** (`playbooks/*.html`) — scannable incident runbooks the agents/orchestrator
|
|
105
|
+
link from tasks. `_TEMPLATE.html` + four examples (`build-fail`, `e2e-regression`,
|
|
106
|
+
`sentry-spike`, `deploy-rollback`).
|
|
107
|
+
- **watch + detect** (`lib/watch/scheduler.cjs`, `lib/detect/*`) — a 24h loop that runs
|
|
108
|
+
the enabled detectors (`sentry`, `vercel`, or your own from `_template.cjs`) and posts
|
|
109
|
+
findings as kanban tasks. Thresholds live in `lib/detect/rules.json` (hot-reloaded).
|
|
110
|
+
- **runner** (`lib/runner/*`) — executes a task per its `runner`: spawns the `claude` /
|
|
111
|
+
`codex` CLI in an isolated git worktree, merges the results when `runner: both`, writes
|
|
112
|
+
the verdict + diff back to the task. Has a daily second-model budget with a fallback chain.
|
|
113
|
+
- **gate** (`lib/gate/index.cjs`) — runs `config.js → deployCommands` fail-fast, inspects
|
|
114
|
+
bundle size, auto-creates a "needs human" task on failure. Installed as a git pre-push
|
|
115
|
+
hook via `hooks/pre-push.sample`.
|
|
116
|
+
|
|
117
|
+
## Quick start
|
|
118
|
+
|
|
119
|
+
Three ways to install — pick whichever fits.
|
|
120
|
+
|
|
121
|
+
**A. `npx` (zero install, fastest)**
|
|
122
|
+
```bash
|
|
123
|
+
npx kanban-system init my-board
|
|
124
|
+
cd my-board
|
|
125
|
+
cp config.example.js config.js # edit: repoPath, deployCommands
|
|
126
|
+
cp .env.example .env # (optional) TELEGRAM_BOT_TOKEN, SENTRY_TOKEN, ...
|
|
127
|
+
npm install # virtually nothing
|
|
128
|
+
npm start # → http://localhost:8080
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**B. GitHub Template** — open the repo on GitHub and click **"Use this template" →
|
|
132
|
+
"Create a new repository"**. Then `git clone` your new repo and follow steps from
|
|
133
|
+
the `cp config.example.js …` line above. Best for team / long-running ops.
|
|
134
|
+
|
|
135
|
+
**C. Plain `git clone`** — if you want to work directly on a fork:
|
|
136
|
+
```bash
|
|
137
|
+
git clone https://github.com/Zakedu/kanban-system.git
|
|
138
|
+
cd kanban-system
|
|
139
|
+
cp config.example.js config.js && cp .env.example .env
|
|
140
|
+
npm install && npm start
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Open `http://localhost:8080`. Create a task in the UI (or `curl -X POST
|
|
144
|
+
http://localhost:8080/api/tasks -H 'Content-Type: application/json' -d '{"subject":"Try
|
|
145
|
+
it"}'`) and watch it on the board. Run the gate: `npm run gate`. Run one watch sweep:
|
|
146
|
+
`npm run watch:once`. (The `claude` / `codex` CLIs are optional — without them the runner
|
|
147
|
+
falls back to deterministic stub verdicts.)
|
|
148
|
+
|
|
149
|
+
## Adapting to your project (front-end / back-end)
|
|
150
|
+
|
|
151
|
+
The full step-by-step is in **[docs/adapting-to-your-project.md](docs/adapting-to-your-project.md)**.
|
|
152
|
+
In short:
|
|
153
|
+
|
|
154
|
+
1. **`config.js`** — point `repoPath` at your repo; set `deployCommands` to your stack's
|
|
155
|
+
build/test chain (`npx tsc --noEmit` + `npm run build`, or `cargo build` + `cargo test`,
|
|
156
|
+
or `go vet` + `go test`, …); set `buildOutputDir` (or `null`).
|
|
157
|
+
2. **`agents/`** — edit the `owns:` globs in `frontend-agent.md` / `backend-agent.md` to
|
|
158
|
+
match your directory layout. Copy `_TEMPLATE.md` for more roles.
|
|
159
|
+
3. **`lib/detect/`** — enable the detector for your monitoring (`sentry` / `vercel` / your
|
|
160
|
+
own from `_template.cjs`) in `config.js → detectors`. No monitoring? Leave it empty.
|
|
161
|
+
4. **`agents/deploy-gate-agent.md` + `lib/gate/`** — the gate runs `config.js →
|
|
162
|
+
deployCommands`; no code change needed, just review the agent doc so it matches.
|
|
163
|
+
5. **`playbooks/`** — copy `_TEMPLATE.html` for each incident type you care about.
|
|
164
|
+
6. **`hooks/`** — install `pre-push.sample` into your app repo's `.git/hooks/pre-push`;
|
|
165
|
+
schedule the 24h watch via `launchd.plist.template` (macOS) or the cron line in its comment.
|
|
166
|
+
7. *(optional)* — wire a Slack bot token for start / progress / done reporting and the
|
|
167
|
+
`/kanban` slash command.
|
|
168
|
+
8. *(optional)* — wire **Telegram** for 24h ops-from-anywhere. See the next section.
|
|
169
|
+
|
|
170
|
+
## Ops Thread (Telegram mirror) — optional
|
|
171
|
+
|
|
172
|
+
The kanban dashboard has a right-side **Ops Thread** chat panel. Everything in it is
|
|
173
|
+
mirrored to a Telegram chat in both directions, so you can run 24h ops from your phone
|
|
174
|
+
without leaving the kanban as the source of truth.
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
[ kanban dashboard ] [ your Telegram DM ]
|
|
178
|
+
Ops Thread panel ◀──── /api/ops-thread ────▶ sendMessage / getUpdates
|
|
179
|
+
│ │ │
|
|
180
|
+
└── you type ───────────┘ │
|
|
181
|
+
└── operator replies ──────┘
|
|
182
|
+
task created / completed → 📋 / ✅ posted to both sides
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Setup** (~2 minutes, no PG / no external service):
|
|
186
|
+
|
|
187
|
+
1. Open Telegram, message `@BotFather`, send `/newbot`, follow the prompts. Copy the
|
|
188
|
+
token you get.
|
|
189
|
+
2. Send any DM to your new bot from your own Telegram account (this is what lets the
|
|
190
|
+
bot see you exist — Telegram won't deliver replies otherwise).
|
|
191
|
+
3. Put the token + chat id in `.env`:
|
|
192
|
+
```bash
|
|
193
|
+
TELEGRAM_BOT_TOKEN=123456:AA...your_token
|
|
194
|
+
TELEGRAM_CHAT_ID= # leave blank for now
|
|
195
|
+
```
|
|
196
|
+
4. `npm start`, then in another terminal:
|
|
197
|
+
```bash
|
|
198
|
+
curl http://localhost:8080/api/telegram/whoami
|
|
199
|
+
# → { "ok": true, "chats": [ { "id": 6131488858, "type": "private", ... } ] }
|
|
200
|
+
```
|
|
201
|
+
Copy that `id` into `TELEGRAM_CHAT_ID` in `.env`, restart `npm start`.
|
|
202
|
+
5. Done — type in the Ops Thread panel and it appears in Telegram; reply in Telegram
|
|
203
|
+
and it shows up in the panel. Task `created` → `📋 #N <subject>`, `in_progress` →
|
|
204
|
+
`▶️ #N`, `completed` → `✅ #N — <one-line report>`.
|
|
205
|
+
|
|
206
|
+
**No Telegram?** Leave the env vars blank. The panel still works as a local kanban-only
|
|
207
|
+
chat (and as a place where the server posts task lifecycle events).
|
|
208
|
+
|
|
209
|
+
**Allowing only specific people**: set `TELEGRAM_ALLOWED_CHAT_IDS=id1,id2` to allow more
|
|
210
|
+
than one chat. Empty list ⇒ only `TELEGRAM_CHAT_ID` is accepted (recommended for solo ops).
|
|
211
|
+
|
|
212
|
+
**Endpoints** (you usually never call these — the UI does):
|
|
213
|
+
- `GET /api/ops-thread?since=<id>` — load thread (paginated by message id)
|
|
214
|
+
- `POST /api/ops-thread/append { role, text, taskId? }` — agents append to the thread
|
|
215
|
+
- `POST /api/ops-thread/send { text }` — you send (also mirrored to Telegram)
|
|
216
|
+
- `GET /api/telegram/status` — `{ configured, polling, chatId }`
|
|
217
|
+
- `GET /api/telegram/whoami` — debug: dump recent `getUpdates` so you can find a chat id
|
|
218
|
+
|
|
219
|
+
## The kanban-first protocol
|
|
220
|
+
|
|
221
|
+
Every user instruction becomes a kanban task **before** work starts: capture it
|
|
222
|
+
verbatim, route it, set the `runner`, transition to `in_progress`, and only then start.
|
|
223
|
+
On completion, set `reportPath` + `reportSummary`. The single exception is **incident
|
|
224
|
+
response** — a production-impacting incident or a 1-line, obviously-reversible hotfix may
|
|
225
|
+
be done immediately, but a post-hoc task must be registered within 1 hour, tagged
|
|
226
|
+
`metadata.source = "incident-response"`. Nothing else qualifies. Rationale and the state
|
|
227
|
+
machine: **[docs/the-pattern.md](docs/the-pattern.md)** → "Kanban-first".
|
|
228
|
+
|
|
229
|
+
## Multi-agent cross-validation
|
|
230
|
+
|
|
231
|
+
Pick the verification level per task via `runner`:
|
|
232
|
+
- **single-model** (`claude` / `codex`) — deterministic / mechanical work (running tests,
|
|
233
|
+
polling an API, a state transition); a second opinion only adds latency.
|
|
234
|
+
- **`reviewer:codex`** — Claude implements in an isolated worktree, Codex reviews the
|
|
235
|
+
result and can downgrade the verdict to `needs_human`. Default for implementation work.
|
|
236
|
+
- **`both`** — Claude *and* Codex independently do the work from the same spec, in
|
|
237
|
+
separate worktrees; the orchestrator diffs them. Agreement → auto-merge; disagreement →
|
|
238
|
+
"needs human" column. For high-stakes work (schema migrations, access-control policies,
|
|
239
|
+
money paths) — the disagreement is the safety feature.
|
|
240
|
+
|
|
241
|
+
The orchestrator auto-promotes single-model → `both` above a severity threshold; a daily
|
|
242
|
+
second-model budget caps cost. Details: **[docs/the-pattern.md](docs/the-pattern.md)** →
|
|
243
|
+
"Cross-validation".
|
|
244
|
+
|
|
245
|
+
## Example: APEX
|
|
246
|
+
|
|
247
|
+
APEX is an AI-skills certification exam platform (React/Vite front end, Supabase back
|
|
248
|
+
end) that ran this harness in production under the codename "Sentinel": 8 generic
|
|
249
|
+
ops/dev agents like the ones here plus a 6-agent domain group, an `exam-engine` selvedge
|
|
250
|
+
boundary, a deliberately powerless "proctor" agent (detect-and-escalate, never enforce),
|
|
251
|
+
`runner: both` on migrations / grading prompts / credential scoring, and the
|
|
252
|
+
gate-before-push rule. Full write-up: **[docs/example-apex.md](docs/example-apex.md)** —
|
|
253
|
+
the one place project-specific domain content lives.
|
|
254
|
+
|
|
255
|
+
## CLI reference
|
|
256
|
+
|
|
257
|
+
The `kanban-system` bin (also usable as `npx kanban-system <cmd>`):
|
|
258
|
+
|
|
259
|
+
| Command | What it does |
|
|
260
|
+
|---|---|
|
|
261
|
+
| `init <name>` | Scaffold a fresh checkout into `./<name>` (config templates + all the harness files, minus the CLI itself) |
|
|
262
|
+
| `start [--port N]` | Run `server/kanban.cjs`. Prefers the local checkout's server if present (so config.js / UI edits apply) |
|
|
263
|
+
| `watch [--once]` | Run `lib/watch/scheduler.cjs` |
|
|
264
|
+
| `gate` | Run `lib/gate/index.cjs` |
|
|
265
|
+
| `whoami` | Probe a running server's `/api/telegram/whoami` (find your Telegram chat id) |
|
|
266
|
+
| `--version` / `--help` | Self-explanatory |
|
|
267
|
+
|
|
268
|
+
## License / status
|
|
269
|
+
|
|
270
|
+
MIT. Status: extracted as a domain-agnostic template + npm CLI; the pieces are present
|
|
271
|
+
and wired, but you'll want to exercise them against your own repo before relying on
|
|
272
|
+
them in production.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
# ── Required frontmatter ──────────────────────────────────────────────────────
|
|
3
|
+
name: my-agent # slug; must match the file name without .md
|
|
4
|
+
mission: >- # one sentence: what failure does this agent prevent?
|
|
5
|
+
Prevent <failure mode> in <area> by <what it does>.
|
|
6
|
+
runner: claude # claude | codex | both | reviewer:codex | reviewer:claude
|
|
7
|
+
model_default: claude-opus-4-7 # the model the runner uses by default
|
|
8
|
+
auto_promote_on: # optional: when to bump a single-runner task to `both`
|
|
9
|
+
- severity: medium
|
|
10
|
+
- regression_window: 30d
|
|
11
|
+
tools_allowed: [Read, Edit, Bash] # the tools this agent may use
|
|
12
|
+
worktree: isolated # isolated (own git worktree) | inline (works in place)
|
|
13
|
+
escalation: human # human | other-agent:<name>
|
|
14
|
+
owns: # globs (relative to repoPath) this agent owns —
|
|
15
|
+
- src/feature/** # used by the orchestrator for "which agent owns this file?"
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# My Agent
|
|
19
|
+
|
|
20
|
+
One paragraph: what this agent is responsible for, and what it explicitly does NOT touch.
|
|
21
|
+
|
|
22
|
+
## Triggers
|
|
23
|
+
Concrete signals that create a task for this agent. Examples:
|
|
24
|
+
- PR touches files matching `owns`.
|
|
25
|
+
- A monitor detector routes an anomaly here.
|
|
26
|
+
- A specific incident playbook escalates to this agent.
|
|
27
|
+
|
|
28
|
+
## Inputs
|
|
29
|
+
Data sources / file paths / API endpoints this agent reads.
|
|
30
|
+
|
|
31
|
+
## Outputs
|
|
32
|
+
Files/reports this agent produces. Convention: `data/runs/<task-id>/report.md`.
|
|
33
|
+
|
|
34
|
+
## Cross-validation policy
|
|
35
|
+
When (if ever) the second model verifies, and the decision rule when they disagree.
|
|
36
|
+
See docs/the-pattern.md for the three modes (`both`, `reviewer:*`, single-model).
|
|
37
|
+
|
|
38
|
+
## Failure handling
|
|
39
|
+
Timeout, model unavailable, disagreement deadlock, build failure — what happens.
|
|
40
|
+
|
|
41
|
+
## Example
|
|
42
|
+
One sample task lifecycle: trigger → what the agent does → output → resolution.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backend-agent
|
|
3
|
+
mission: >-
|
|
4
|
+
Protect the server side — API handlers, database schema and migrations, access
|
|
5
|
+
policies, background jobs — where a bad change can corrupt or leak data.
|
|
6
|
+
runner: both
|
|
7
|
+
model_default: both
|
|
8
|
+
tools_allowed: [Read, Edit, Write, Bash]
|
|
9
|
+
worktree: isolated
|
|
10
|
+
escalation: human
|
|
11
|
+
owns:
|
|
12
|
+
# Edit to match YOUR layout. Examples:
|
|
13
|
+
# Node API: server/**, api/**, src/server/**, src/api/**
|
|
14
|
+
# Migrations: migrations/**, db/migrate/**, prisma/migrations/**
|
|
15
|
+
# Supabase: supabase/functions/**, supabase/migrations/** (one possible backend)
|
|
16
|
+
# Rails: app/controllers/**, app/models/**, db/migrate/**
|
|
17
|
+
# Go services: internal/**, cmd/**
|
|
18
|
+
- server/**
|
|
19
|
+
- api/**
|
|
20
|
+
- db/**
|
|
21
|
+
- migrations/**
|
|
22
|
+
- lib/**
|
|
23
|
+
- functions/**
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Backend Agent
|
|
27
|
+
|
|
28
|
+
High-stakes territory: a bad migration or access-control rule can corrupt data or
|
|
29
|
+
leak it, so every change here runs cross-validated. Owns API/route handlers, the
|
|
30
|
+
database schema and migrations, authz/RLS-style policies, shared server utilities,
|
|
31
|
+
and background jobs. Does not touch the front end (that's `frontend-agent`).
|
|
32
|
+
|
|
33
|
+
> The original of this template was built for a project that used Supabase
|
|
34
|
+
> (Edge Functions + Postgres + RLS). Those specifics moved to `docs/example-apex.md`
|
|
35
|
+
> as a worked example — keep this file stack-agnostic and write your own rules below.
|
|
36
|
+
|
|
37
|
+
## Triggers
|
|
38
|
+
- A PR touches files under `owns` — especially anything under a migrations path.
|
|
39
|
+
- A monitor detector reports a server-side anomaly (5xx burst, function timeouts,
|
|
40
|
+
authz-denial spike) and routes it here.
|
|
41
|
+
- Migration drift detected when applying to an environment.
|
|
42
|
+
|
|
43
|
+
## Inputs
|
|
44
|
+
- Handler / function source.
|
|
45
|
+
- Migration files (forward and, ideally, backward).
|
|
46
|
+
- Seed data.
|
|
47
|
+
- A production schema snapshot (e.g. a `db dump`), so changes can be diffed against reality.
|
|
48
|
+
|
|
49
|
+
## Outputs
|
|
50
|
+
- A migration plan with forward + rollback steps.
|
|
51
|
+
- An access-policy diff (which roles × which tables/resources change).
|
|
52
|
+
- `data/runs/<task-id>/migration-plan.md` and `report.md`.
|
|
53
|
+
|
|
54
|
+
## Cross-validation policy — `runner: both`
|
|
55
|
+
Claude and Codex run in parallel from the same spec, independently:
|
|
56
|
+
- Each writes the migration / handler code on its own.
|
|
57
|
+
- The orchestrator diffs the two. If they produce a functionally equivalent change
|
|
58
|
+
(same schema delta, same policy set) → `agreed`, auto-merge.
|
|
59
|
+
- If they differ on *which* columns to drop, *which* policy to add, or any DDL →
|
|
60
|
+
`disagreed` → human review is forced. (This is by design: server-side data changes
|
|
61
|
+
are exactly where you want two independent reads to converge before shipping.)
|
|
62
|
+
|
|
63
|
+
Project-specific rules the cross-validation should enforce (fill these in):
|
|
64
|
+
- No destructive migration (`DROP COLUMN`, `DROP TABLE`) without a deprecation window.
|
|
65
|
+
- No access-policy change without an explicit, enumerated list of affected roles.
|
|
66
|
+
- No deploy without the shared CORS / auth helpers imported.
|
|
67
|
+
- Secrets / service-role keys never used outside the designated shared module.
|
|
68
|
+
|
|
69
|
+
## Failure handling
|
|
70
|
+
- Migration applies on staging but not on the production schema → block, escalate.
|
|
71
|
+
- Build/deploy fails → block, log.
|
|
72
|
+
- Any access-control test (anonymous / authenticated / service role) fails → block.
|
|
73
|
+
|
|
74
|
+
## Example
|
|
75
|
+
```
|
|
76
|
+
Trigger: monitor-agent reports a 5xx spike on the payment webhook
|
|
77
|
+
Claude: reads logs → diagnoses a missing signature-header validation, writes the fix
|
|
78
|
+
Codex: reads logs independently → diagnoses the same root cause, plus suggests a rate-limit guard
|
|
79
|
+
Diff: agreed on root cause + fix; partial on the rate-limit (Codex extra)
|
|
80
|
+
Resolve: merge the fix; file a follow-up task for the rate-limit guard
|
|
81
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deploy-gate-agent
|
|
3
|
+
mission: >-
|
|
4
|
+
Block any push that fails type-check, build, or the chosen test/E2E suite —
|
|
5
|
+
the last safety net before a deploy goes out.
|
|
6
|
+
runner: reviewer:codex
|
|
7
|
+
model_default: claude-opus-4-7
|
|
8
|
+
tools_allowed: [Bash, Read]
|
|
9
|
+
worktree: inline
|
|
10
|
+
escalation: human
|
|
11
|
+
owns:
|
|
12
|
+
- .git/hooks/pre-push
|
|
13
|
+
- lib/gate/**
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Deploy Gate Agent
|
|
17
|
+
|
|
18
|
+
Runs the pre-deploy verification chain (see `lib/gate/index.cjs`). It is a *hard*
|
|
19
|
+
gate — it cannot be bypassed without an explicit, audited override. It never edits
|
|
20
|
+
application code; it only runs commands and reports.
|
|
21
|
+
|
|
22
|
+
The commands it runs come from `config.js → deployCommands`, executed in order from
|
|
23
|
+
`config.js → repoPath`, fail-fast. Set them to whatever "this builds and the smoke
|
|
24
|
+
tests pass" means for your stack:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
Node / Vite: [{ name:"01-typecheck", cmd:"npx", args:["tsc","--noEmit"] },
|
|
28
|
+
{ name:"02-build", cmd:"npm", args:["run","build"] }]
|
|
29
|
+
Rust: [{ name:"build", cmd:"cargo", args:["build","--release"] },
|
|
30
|
+
{ name:"test", cmd:"cargo", args:["test"] }]
|
|
31
|
+
Go: [{ name:"vet", cmd:"go", args:["vet","./..."] },
|
|
32
|
+
{ name:"test", cmd:"go", args:["test","./..."] }]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Triggers
|
|
36
|
+
- `git push` (via the `pre-push` hook — see `hooks/pre-push.sample`).
|
|
37
|
+
- A manual `/gate` invocation.
|
|
38
|
+
- Before merging a release branch.
|
|
39
|
+
|
|
40
|
+
## Inputs
|
|
41
|
+
- The git diff (HEAD vs the upstream branch).
|
|
42
|
+
- The commands from `config.js → deployCommands`.
|
|
43
|
+
- The last successful gate run (`data/runs/last-gate.json`) for bundle-delta comparison.
|
|
44
|
+
|
|
45
|
+
## Verification chain (serial, fail-fast)
|
|
46
|
+
The chain is `deployCommands` in order, then an optional bundle-inspection stage
|
|
47
|
+
(if `config.js → buildOutputDir` is set): walks the output directory, compares total
|
|
48
|
+
size to the last passing run, and warns (or fails, if `STRICT_BUNDLE=1`) on a large
|
|
49
|
+
regression.
|
|
50
|
+
|
|
51
|
+
## Outputs
|
|
52
|
+
- `data/runs/gate-<timestamp>/<stage>.log` per stage.
|
|
53
|
+
- `data/runs/gate-<timestamp>/report.md` — pass/fail + duration per stage.
|
|
54
|
+
- On failure: a kanban task is auto-created in the "needs human" column with the logs
|
|
55
|
+
linked (disable in CI with `GATE_NO_KANBAN=1`).
|
|
56
|
+
|
|
57
|
+
## Cross-validation policy — `reviewer:codex`
|
|
58
|
+
Claude runs the gate; Codex then reviews the build output for things a green build
|
|
59
|
+
hides: unused exports, dynamic imports with no chunk hints, new `process.env` reads
|
|
60
|
+
that aren't in `.env.example`, an accidentally-bundled heavy dependency. A Codex
|
|
61
|
+
concern that isn't blocking the build still lets the gate pass — but it files a
|
|
62
|
+
follow-up cleanup task.
|
|
63
|
+
|
|
64
|
+
## Failure handling
|
|
65
|
+
- A `deployCommands` stage fails → push blocked, full log saved, error returned to the
|
|
66
|
+
terminal with `file:line` where the tool provided it.
|
|
67
|
+
- Bundle-inspection warning → push allowed, follow-up task created (unless `STRICT_BUNDLE=1`).
|
|
68
|
+
|
|
69
|
+
## Override
|
|
70
|
+
Only a human bypasses, via `git push --no-verify`. The `pre-push.sample` hook also
|
|
71
|
+
honours `KANBAN_GATE_BYPASS=1 git push`, which logs an entry to
|
|
72
|
+
`data/runs/overrides.jsonl` (timestamp, branch, user). Overrides are reviewed at the
|
|
73
|
+
daily standup.
|