allye-pi 1.8.0 → 2.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/README.md +75 -271
- package/bootstrap/allye.md +30 -0
- package/docs/install-omp.md +31 -0
- package/docs/install-pi.md +21 -125
- package/package.json +10 -5
- package/packages/allye-pi/src/index.ts +88 -782
- package/skills/bridge/SKILL.md +105 -0
- package/skills/bridge/references/crew.md +20 -0
- package/skills/bridge/references/delegation.md +174 -0
- package/skills/bridge/references/discovery.md +71 -0
- package/skills/bridge/references/publish.md +90 -0
- package/skills/bridge/references/state-contract.md +109 -0
- package/skills/bridge/references/workflow.md +132 -0
- package/skills/bridge-architect/SKILL.md +96 -0
- package/skills/bridge-architect/references/spec-template.md +90 -0
- package/skills/bridge-armorer/SKILL.md +103 -0
- package/skills/bridge-copilot/SKILL.md +74 -0
- package/skills/bridge-dispatcher/SKILL.md +96 -0
- package/skills/bridge-dispatcher/references/spec-template-minimal.md +53 -0
- package/skills/bridge-medic/SKILL.md +81 -0
- package/skills/bridge-optimizer/SKILL.md +68 -0
- package/skills/bridge-pilot/SKILL.md +69 -0
- package/skills/bridge-pilot/references/mocking.md +57 -0
- package/skills/bridge-pilot/references/tdd.md +42 -0
- package/skills/bridge-pilot/references/tests.md +60 -0
- package/skills/bridge-recon/SKILL.md +82 -0
- package/skills/bridge-shield/SKILL.md +73 -0
- package/skills/bridge-strategist/SKILL.md +92 -0
- package/skills/bridge-watcher/SKILL.md +73 -0
- package/skills/agent-runtime/SKILL.md +0 -129
- package/skills/agent-runtime/references/herdr.md +0 -184
- package/skills/board-progression/SKILL.md +0 -214
- package/skills/branch-landing/SKILL.md +0 -88
- package/skills/delivery/SKILL.md +0 -187
- package/skills/execution/SKILL.md +0 -396
- package/skills/handover-protocol/SKILL.md +0 -74
- package/skills/handover-protocol/references/correction.md +0 -32
- package/skills/handover-protocol/references/discovery-to-planning.md +0 -44
- package/skills/handover-protocol/references/execution-report.md +0 -42
- package/skills/handover-protocol/references/planning-to-technical.md +0 -42
- package/skills/handover-protocol/references/story-execution.md +0 -74
- package/skills/handover-protocol/references/technical-to-orchestration.md +0 -45
- package/skills/memory-protocol/SKILL.md +0 -319
- package/skills/orchestrator/SKILL.md +0 -249
- package/skills/product-planning/SKILL.md +0 -257
- package/skills/review/SKILL.md +0 -165
- package/skills/sandbox/SKILL.md +0 -62
- package/skills/setup/SKILL.md +0 -226
- package/skills/tdd-workflow/SKILL.md +0 -144
- package/skills/technical-planning/SKILL.md +0 -354
- package/skills/tools-quickref/SKILL.md +0 -307
- package/skills/using-allye/SKILL.md +0 -171
- package/skills/verification-loop/SKILL.md +0 -93
package/skills/sandbox/SKILL.md
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: sandbox
|
|
3
|
-
description: Open-ended ideation and research before committing to scope. Use when the user has a vague goal and wants to think out loud, explore directions, or research before defining what to build — not yet ready for Product Planning's Epic/Feature/Story structure.
|
|
4
|
-
version: "1.3"
|
|
5
|
-
category: methodology
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Sandbox / Discovery
|
|
9
|
-
|
|
10
|
-
This is the entry point for ideas that aren't ready to become work items yet. Use it when the user wants to explore, not commit — Product Planning already assumes a direction has been chosen; this skill is where that direction gets found.
|
|
11
|
-
|
|
12
|
-
<!-- adapted from superpowers:brainstorming (MIT) -->
|
|
13
|
-
<HARD-GATE>
|
|
14
|
-
Do not create any Allye work item, and do not treat any direction as decided, until the user has explicitly approved it. This skill's default output is a Discovery Doc and a handover, but a user may explicitly choose an informal local research note or no persistence when that is sufficient. If you catch yourself about to call `work_create`, stop and ask for approval first.
|
|
15
|
-
</HARD-GATE>
|
|
16
|
-
|
|
17
|
-
## 1. The core rule: ask, don't decide
|
|
18
|
-
|
|
19
|
-
You never unilaterally pick a direction. When there's a fork, ask — one focused question at a time, never several forks stacked into one message. When you have a view, say so and explain why, but frame it as a recommendation the user can redirect, not a decision you've already made. (For *how* to ask — prose vs. the `AskUserQuestion` tool — see `using-allye`'s "Asking Questions" section; it's a global rule, not repeated here.)
|
|
20
|
-
|
|
21
|
-
<!-- adapted from superpowers:brainstorming (MIT) — anti-rationalization table -->
|
|
22
|
-
### Red flags — these thoughts mean stop and ask instead
|
|
23
|
-
|
|
24
|
-
| Thought | Reality |
|
|
25
|
-
|---|---|
|
|
26
|
-
| "This is obviously what they want" | Obvious to you isn't the same as confirmed. Ask. |
|
|
27
|
-
| "I'll just explore this direction and show them" | Exploring silently is still deciding silently — narrate the fork before you go down it. |
|
|
28
|
-
| "We've been going back and forth a lot, let me just pick" | Fatigue isn't consent. If the user wants you to decide, they'll say so — that's a valid answer to a question, not a reason to stop asking. |
|
|
29
|
-
| "This detail is too small to ask about" | Small decisions compound. If it would surprise the user later, it's worth a quick check now. |
|
|
30
|
-
|
|
31
|
-
### When it's fine to just proceed
|
|
32
|
-
|
|
33
|
-
<!-- adapted from trailofbits/skills ask-questions-if-underspecified (CC-BY-SA-4.0) — adapted as a rubric, not their original text -->
|
|
34
|
-
Not every gap needs a question. Ask when the answer would change *what* gets built or *which direction* gets explored. Don't ask when:
|
|
35
|
-
- The gap is a well-established default with no real controversy — state the assumption instead of asking about it
|
|
36
|
-
- The user already answered a broader version of the question and this is a narrower instance of the same answer
|
|
37
|
-
- Asking would just be confirming something the user's own message already made unambiguous
|
|
38
|
-
|
|
39
|
-
## 2. Research (optional, user-triggered, parallel is fine)
|
|
40
|
-
|
|
41
|
-
If the direction needs facts to evaluate — how a technology actually works, what a public repo actually does, what the current landscape looks like — offer to research before continuing the discussion, rather than reasoning from assumption.
|
|
42
|
-
|
|
43
|
-
- **Web research** → dispatch the `deep-search` agent (`Agent` tool) with a single, explicit objective. It's bounded and doesn't need to ask you anything mid-task, which is what makes it safe to dispatch.
|
|
44
|
-
- **Public repo analysis** → dispatch the `code-analyzer` agent (`Agent` tool) with the repo URL, a specific objective, and the session scratchpad path (it only clones under that path, and will refuse to fall back to `/tmp` if you omit it). It reads thoroughly, reports, and deletes the clone unconditionally — you never touch the clone yourself.
|
|
45
|
-
|
|
46
|
-
Both can run in parallel if you need both kinds of research at once — dispatch them in the same turn.
|
|
47
|
-
|
|
48
|
-
<!-- adapted from humanlayer/humanlayer research_codebase (Apache-2.0) -->
|
|
49
|
-
**Keep research and direction-setting separate.** A research agent documents what exists — it does not recommend what to do about it. When findings come back, bring them into the conversation and let the user (with your input) decide what they mean for the direction — don't let a research agent's report silently become the decision.
|
|
50
|
-
|
|
51
|
-
## 3. Exit: the Discovery Doc
|
|
52
|
-
|
|
53
|
-
When a direction is approved — explicitly, by the user, not inferred — synthesize the conversation into a Discovery Doc:
|
|
54
|
-
|
|
55
|
-
1. **What goes in it:** the approved direction and why; paths that were explored and rejected, with the reason (the next phase should never accidentally re-propose something already ruled out); research findings, if any, with their sources; prototypes, if any.
|
|
56
|
-
2. **Where it goes:** call `doc_full_tree` first. Propose a parent location based on what you see — don't guess blindly and don't default to the root. Get the user's explicit confirmation of placement before creating anything.
|
|
57
|
-
3. **Create it:** `doc_create` (type `guide` or `page`, needs an emoji).
|
|
58
|
-
4. **Hand off:** emit a `discovery-to-planning` handover — see the `handover-protocol` skill for the shared marker format, and its `references/discovery-to-planning.md` for this handover's specific template. Reference the Discovery Doc; don't duplicate its content into the handover.
|
|
59
|
-
|
|
60
|
-
## 4. What this skill is not
|
|
61
|
-
|
|
62
|
-
This is not Technical Planning — no stack decisions, no architecture, no tasks here. It is not Product Planning — no Epic/Feature/Story structure gets created here without approval. If the user arrives already knowing exactly what they want and just needs it turned into work items, recommend `product-planning`; if they only need a small local change, the adaptive toolkit may proceed without forcing a planning phase.
|
package/skills/setup/SKILL.md
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: setup
|
|
3
|
-
description: First-time setup for the Allye plugin. Uses OAuth for ALL platforms — no PAT.
|
|
4
|
-
version: "1.3"
|
|
5
|
-
category: bootstrap
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Allye Setup
|
|
9
|
-
|
|
10
|
-
<EXTREMELY_IMPORTANT>
|
|
11
|
-
## Allye MCP always uses native OAuth
|
|
12
|
-
|
|
13
|
-
Configure one remote server named `allye` at `https://mcp.allye.app/mcp`. Let the
|
|
14
|
-
host runtime perform discovery, dynamic client registration, authorization-code
|
|
15
|
-
exchange, token storage, and refresh. Static bearer headers, PATs, fixed client
|
|
16
|
-
IDs, tenant-specific URLs, and external login helpers are not part of setup.
|
|
17
|
-
</EXTREMELY_IMPORTANT>
|
|
18
|
-
|
|
19
|
-
## Step 1: Detect the platform
|
|
20
|
-
|
|
21
|
-
Infer the current platform from the runtime when possible. Otherwise ask which
|
|
22
|
-
supported agent the user wants to configure.
|
|
23
|
-
|
|
24
|
-
## Step 2: Configure and authenticate one Allye entry
|
|
25
|
-
|
|
26
|
-
Preserve every unrelated server and credential. If an older Allye entry exists
|
|
27
|
-
under another name, identify its effective config source, remove only that
|
|
28
|
-
entry through the host's native management command, and keep only `allye`.
|
|
29
|
-
|
|
30
|
-
### Claude Code / Claude Desktop
|
|
31
|
-
|
|
32
|
-
The plugin's `.mcp.json` already declares `allye`. Open the MCP or plugin panel,
|
|
33
|
-
select **Allye**, and choose **Connect**. The browser completes consent.
|
|
34
|
-
|
|
35
|
-
For an intentional reconnect, use **Clear authentication** for Allye, then
|
|
36
|
-
**Authenticate/Connect**. Do not sign out of the host account.
|
|
37
|
-
|
|
38
|
-
### Codex
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
codex mcp get allye >/dev/null 2>&1 \
|
|
42
|
-
|| codex mcp add allye --url https://mcp.allye.app/mcp
|
|
43
|
-
codex mcp login allye
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
If a legacy Allye entry has a different name, use `codex mcp logout <old-name>`
|
|
47
|
-
and `codex mcp remove <old-name>` for that entry only before adding `allye`.
|
|
48
|
-
|
|
49
|
-
### OpenCode
|
|
50
|
-
|
|
51
|
-
Its effective `opencode.json` must contain:
|
|
52
|
-
|
|
53
|
-
```json
|
|
54
|
-
{
|
|
55
|
-
"mcp": {
|
|
56
|
-
"allye": {
|
|
57
|
-
"type": "remote",
|
|
58
|
-
"url": "https://mcp.allye.app/mcp",
|
|
59
|
-
"enabled": true
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Preserve the rest of the file, then authenticate and confirm:
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
opencode mcp auth allye
|
|
69
|
-
opencode mcp list
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Pi with pi-mcp-adapter
|
|
73
|
-
|
|
74
|
-
Use the effective MCP source shown by `/mcp` and define an `allye` remote server
|
|
75
|
-
at the canonical URL. The Allye repository installer does not write Pi's MCP
|
|
76
|
-
configuration.
|
|
77
|
-
|
|
78
|
-
Authenticate and connect in Pi:
|
|
79
|
-
|
|
80
|
-
```text
|
|
81
|
-
/mcp-auth allye
|
|
82
|
-
/mcp reconnect allye
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Use `/reload` after changing the effective config source. `/mcp logout allye`
|
|
86
|
-
clears only Allye's native credential when the user explicitly requests a
|
|
87
|
-
reconnection.
|
|
88
|
-
|
|
89
|
-
### Other native MCP clients
|
|
90
|
-
|
|
91
|
-
Add a remote HTTP MCP server named `allye` at the canonical URL and use the
|
|
92
|
-
client's native OAuth action. Preserve unrelated configuration and credentials.
|
|
93
|
-
|
|
94
|
-
## Step 3: Confirm MCP access
|
|
95
|
-
|
|
96
|
-
Start or reload the host session, confirm the `allye` server is connected, and
|
|
97
|
-
invoke a read-only Allye tool. Tenant selection happens during consent; the URL
|
|
98
|
-
never contains a tenant slug.
|
|
99
|
-
|
|
100
|
-
## Step 4: Delivery configuration
|
|
101
|
-
|
|
102
|
-
Ask once, here, rather than at every dispatch. Five parallel stories would otherwise mean
|
|
103
|
-
ten identical questions whose answer never varies.
|
|
104
|
-
|
|
105
|
-
Check whether it already exists before asking anything:
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
user_config(action: "list")
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
If a document named `Allye Delivery Configuration` is present, show it and ask whether to
|
|
112
|
-
change it. Otherwise, ask the questions below — one at a time — and create it.
|
|
113
|
-
|
|
114
|
-
**Question 1 — which agent runs which phase?** Offer the phases that can differ (planning,
|
|
115
|
-
technical planning, execution, review, correction) and let the user assign an agent kind to
|
|
116
|
-
each. The default is the agent they are running now, for every phase; accepting that default
|
|
117
|
-
is a completely reasonable answer and should take one word.
|
|
118
|
-
|
|
119
|
-
**Question 2 — what arguments does each agent need?** Model selection is not uniform: what
|
|
120
|
-
is `--model sonnet --permission-mode auto` for one agent is different syntax for the next.
|
|
121
|
-
Store the argument string verbatim; it is passed through unchanged.
|
|
122
|
-
|
|
123
|
-
**Question 3 — per repo, what is the base branch, and which gitignored files must a fresh
|
|
124
|
-
worktree receive?** A worktree inherits neither, and an executor that fails on a missing
|
|
125
|
-
`.env` reports a bug that is not one.
|
|
126
|
-
|
|
127
|
-
**Question 4 — who satisfies each stage after review?** Only ask this when the team's pipeline
|
|
128
|
-
has stages between the review gate and done: run `work_statuses()` and look. A Solo or Startup
|
|
129
|
-
board goes straight from review to done and needs nothing here — **skip the question entirely
|
|
130
|
-
rather than asking it and recording an empty table.**
|
|
131
|
-
|
|
132
|
-
Where there are stages, offer three answers per stage:
|
|
133
|
-
|
|
134
|
-
- **`agent`** — the Orchestrator satisfies it and advances. Needs a command, the same way a task
|
|
135
|
-
needs one (`verification-loop` §1): red-capable, deterministic, fast, agent-runnable.
|
|
136
|
-
- **`ci`** — an external system satisfies it. Record how to read the result; the Orchestrator
|
|
137
|
-
waits rather than acting.
|
|
138
|
-
- **`human`** — the Orchestrator stops and hands over.
|
|
139
|
-
|
|
140
|
-
Lead with a recommendation so accepting takes one word: scans and automated test suites are
|
|
141
|
-
usually `agent` or `ci`; anything that deploys, or that validates in a deployed environment, is
|
|
142
|
-
`human` unless the team says otherwise.
|
|
143
|
-
|
|
144
|
-
Create it:
|
|
145
|
-
|
|
146
|
-
```
|
|
147
|
-
user_config(
|
|
148
|
-
action: "create",
|
|
149
|
-
name: "Allye Delivery Configuration",
|
|
150
|
-
content: "{the document below}"
|
|
151
|
-
)
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
Note the field is `name`, not `title` — this is the one tool in the suite that differs.
|
|
155
|
-
|
|
156
|
-
### Document format
|
|
157
|
-
|
|
158
|
-
```markdown
|
|
159
|
-
# Allye Delivery Configuration
|
|
160
|
-
|
|
161
|
-
## Phase routing
|
|
162
|
-
|
|
163
|
-
| Phase | Agent kind | Native args |
|
|
164
|
-
|---|---|---|
|
|
165
|
-
| product-planning | claude | --model sonnet --permission-mode auto |
|
|
166
|
-
| technical-planning | claude | --model sonnet --permission-mode auto |
|
|
167
|
-
| execution | opencode | |
|
|
168
|
-
| review | claude | --model sonnet --permission-mode auto |
|
|
169
|
-
| correction | opencode | |
|
|
170
|
-
|
|
171
|
-
## Repositories
|
|
172
|
-
|
|
173
|
-
| Repo | Base branch | Install command | Copy into a fresh worktree |
|
|
174
|
-
|---|---|---|---|
|
|
175
|
-
| allye-plugin | main | | |
|
|
176
|
-
| allye-api | develop | bun install | .env |
|
|
177
|
-
|
|
178
|
-
## Concurrency
|
|
179
|
-
|
|
180
|
-
Default parallel stories: 3
|
|
181
|
-
|
|
182
|
-
## Pipeline handoff
|
|
183
|
-
|
|
184
|
-
| Status | Satisfied by | Command or signal |
|
|
185
|
-
|---|---|---|
|
|
186
|
-
| security_scan | agent | just security-scan |
|
|
187
|
-
| qa_testing | agent | just test:e2e |
|
|
188
|
-
| deploy_staging | ci | GitHub Actions `deploy-staging` |
|
|
189
|
-
| deploy_prod | human | |
|
|
190
|
-
|
|
191
|
-
An unmapped status means **`human`**. Stopping is the safe default: an agent that advances
|
|
192
|
-
past a gate nobody told it about has claimed work passed a check that never ran.
|
|
193
|
-
|
|
194
|
-
Omit this section entirely when the pipeline runs straight from review to done.
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
An empty cell means "nothing required" — leave it empty rather than writing "none", so the
|
|
198
|
-
table stays scannable.
|
|
199
|
-
|
|
200
|
-
### Preflight before routing a phase to a non-Claude agent
|
|
201
|
-
|
|
202
|
-
A dispatched agent that cannot reach Allye cannot read the story, move a status, or save the
|
|
203
|
-
memory the Orchestrator collects its result from — the dispatch will appear to succeed and
|
|
204
|
-
produce nothing. Before recording a non-Claude agent for any phase, confirm that agent has
|
|
205
|
-
Allye configured: the MCP connection, and for OpenCode the `allye-opencode` package. If it
|
|
206
|
-
does not, say so and point at the matching guide in `docs/install-*.md` rather than recording
|
|
207
|
-
a route that will fail on first use.
|
|
208
|
-
|
|
209
|
-
Platform capability also constrains the map. OpenCode has six agent personas; Cursor, Codex,
|
|
210
|
-
and Gemini CLI have one agent and no picker — routing a specific persona to them silently
|
|
211
|
-
does nothing.
|
|
212
|
-
|
|
213
|
-
## Authentication lifecycle
|
|
214
|
-
|
|
215
|
-
The host runtime rotates access and refresh tokens automatically. A normal
|
|
216
|
-
restart, an HTTP 403 authorization result, or an HTTP 503 dependency failure
|
|
217
|
-
does not require clearing credentials or opening the browser.
|
|
218
|
-
|
|
219
|
-
An explicit grant revocation or the 90-day grant limit requires a new consent.
|
|
220
|
-
When the user intentionally reconnects, clear only the `allye` entry:
|
|
221
|
-
|
|
222
|
-
- **Claude Code/Desktop:** Allye → **Clear authentication** → **Authenticate/Connect**
|
|
223
|
-
- **Codex:** `codex mcp logout allye`, then `codex mcp login allye`
|
|
224
|
-
- **OpenCode:** `opencode mcp logout allye`, then `opencode mcp auth allye`
|
|
225
|
-
- **Pi:** `/mcp logout allye`, then `/mcp-auth allye` and `/mcp reconnect allye`
|
|
226
|
-
- **Other clients:** use the host's clear/reconnect action scoped to `allye`
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: tdd-workflow
|
|
3
|
-
description: Test-Driven Development discipline for AI agents. Red-Green-Refactor cycle, detection heuristic, and anti-patterns. Use when implementing features or fixing bugs.
|
|
4
|
-
version: "1.1"
|
|
5
|
-
category: methodology
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# TDD Workflow
|
|
9
|
-
|
|
10
|
-
TDD is not about writing tests — it's about **designing code through tests**.
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## 1. TDD Detection Heuristic
|
|
15
|
-
|
|
16
|
-
Before implementing anything, ask:
|
|
17
|
-
|
|
18
|
-
> **Can I write `expect(fn(input)).toBe(output)` before writing `fn`?**
|
|
19
|
-
|
|
20
|
-
- **Yes** → TDD is mandatory. Follow Red → Green → Refactor.
|
|
21
|
-
- **No** → Write tests after implementation, but always write tests.
|
|
22
|
-
|
|
23
|
-
### When TDD applies (test first)
|
|
24
|
-
|
|
25
|
-
- Pure functions and business logic
|
|
26
|
-
- Data transformations and parsing
|
|
27
|
-
- Validation rules
|
|
28
|
-
- API endpoint behavior
|
|
29
|
-
- Database queries and mutations
|
|
30
|
-
- State management logic
|
|
31
|
-
- Utility functions
|
|
32
|
-
- Algorithm implementations
|
|
33
|
-
|
|
34
|
-
### When TDD doesn't apply (test after)
|
|
35
|
-
|
|
36
|
-
- UI layout and styling
|
|
37
|
-
- Infrastructure and configuration
|
|
38
|
-
- Third-party integrations (mock boundaries, test your adapter)
|
|
39
|
-
- File system operations
|
|
40
|
-
- Environment setup scripts
|
|
41
|
-
- One-off data migrations
|
|
42
|
-
|
|
43
|
-
<EXTREMELY_IMPORTANT>
|
|
44
|
-
Even when TDD doesn't apply, you MUST still write tests.
|
|
45
|
-
The only question is whether the test comes before or after the implementation.
|
|
46
|
-
"No tests needed" is never an acceptable answer.
|
|
47
|
-
</EXTREMELY_IMPORTANT>
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## 2. The Red-Green-Refactor Cycle
|
|
52
|
-
|
|
53
|
-
### Red — write a failing test
|
|
54
|
-
|
|
55
|
-
Write a test that describes the target behavior, not the implementation:
|
|
56
|
-
|
|
57
|
-
```javascript
|
|
58
|
-
test("should return 404 when user not found", async () => {
|
|
59
|
-
const response = await request(app).get("/users/nonexistent");
|
|
60
|
-
expect(response.status).toBe(404);
|
|
61
|
-
expect(response.body.error).toBe("User not found");
|
|
62
|
-
});
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
**Run the test. It MUST fail.** If it passes, either the functionality already exists (don't reimplement it) or the test is wrong (it's not testing what you think).
|
|
66
|
-
|
|
67
|
-
### Green — make it pass
|
|
68
|
-
|
|
69
|
-
Write the **minimum code** to make the test pass:
|
|
70
|
-
|
|
71
|
-
<HARD-GATE>
|
|
72
|
-
Rules for the Green phase:
|
|
73
|
-
1. Do NOT add features the test doesn't require
|
|
74
|
-
2. Do NOT optimize prematurely
|
|
75
|
-
3. Do NOT handle edge cases not covered by tests — write more tests first
|
|
76
|
-
4. Do NOT refactor during Green — that's the next phase
|
|
77
|
-
5. It's OK if the code is ugly — Green is about correctness, not beauty
|
|
78
|
-
</HARD-GATE>
|
|
79
|
-
|
|
80
|
-
**Run the test. It MUST pass.**
|
|
81
|
-
|
|
82
|
-
### Refactor — clean up
|
|
83
|
-
|
|
84
|
-
With green tests as your safety net: remove duplication, improve naming, simplify logic, extract functions where the code is too long, apply patterns where they genuinely help.
|
|
85
|
-
|
|
86
|
-
**Run tests after EVERY change.** A failing test means you broke something — undo and try again.
|
|
87
|
-
|
|
88
|
-
### Repeat
|
|
89
|
-
|
|
90
|
-
Write the next test for the next behavior. Continue the cycle until all acceptance criteria are met.
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## 3. Test Quality
|
|
95
|
-
|
|
96
|
-
- **Assert on behavior, not implementation** — `should return user profile for valid ID`, not `should call userRepository.findById`. Tests coupled to implementation break on every refactor.
|
|
97
|
-
- **One assertion per concept.** A test that checks unrelated things (fields set *and* an email was sent) hides which concept broke when it fails — split into separate tests.
|
|
98
|
-
- **Cover the edges** after the happy path passes: empty inputs, invalid inputs, boundary values, error conditions, concurrent access where applicable.
|
|
99
|
-
- **Name tests as specifications** — `should throw validation error when email is invalid`, `should retry request up to 3 times on timeout`.
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## 4. Rules — Non-Negotiable
|
|
104
|
-
|
|
105
|
-
<HARD-GATE>
|
|
106
|
-
1. **Never delete a failing test.** If a test fails, either fix the code or fix the test — but understand WHY it fails first. Deleting tests hides bugs.
|
|
107
|
-
|
|
108
|
-
2. **Never suppress type errors.** No `@ts-ignore`, no `# type: ignore`, no `as any`. Type errors are bugs caught early. Fix them.
|
|
109
|
-
|
|
110
|
-
3. **Never commit with failing tests.** All tests must pass before a task is marked as done. No exceptions.
|
|
111
|
-
|
|
112
|
-
4. **Never mock what you don't own.** Mock your adapters, not third-party libraries directly. If the library changes, your mock won't catch it.
|
|
113
|
-
|
|
114
|
-
5. **Tests must be deterministic.** No flaky tests. No tests that depend on time, network, or random values without controlling them.
|
|
115
|
-
</HARD-GATE>
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## 5. Testing Patterns
|
|
120
|
-
|
|
121
|
-
Structure each test **Arrange-Act-Assert**: set up state, perform the one action under test, assert the result.
|
|
122
|
-
|
|
123
|
-
Use the simplest test double that works:
|
|
124
|
-
|
|
125
|
-
| Double | When to use |
|
|
126
|
-
|--------|-------------|
|
|
127
|
-
| **Stub** | Return a fixed value. Use for dependencies whose output you control. |
|
|
128
|
-
| **Spy** | Verify a call was made. Use when the side effect matters. |
|
|
129
|
-
| **Mock** | Set expectations upfront. Use sparingly — prefer stubs + assertions. |
|
|
130
|
-
| **Fake** | Lightweight implementation (e.g., in-memory DB). Use for integration tests. |
|
|
131
|
-
|
|
132
|
-
Test at your system's boundaries — validate at the input boundary, assert at the output boundary — rather than reaching into the middle.
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
## 6. When the Cycle Feels Wrong
|
|
137
|
-
|
|
138
|
-
| Feeling | Likely cause | Fix |
|
|
139
|
-
|---------|-------------|-----|
|
|
140
|
-
| "I can't write a test first" | You don't understand the requirements yet | Go back to the task description. Clarify with the user. |
|
|
141
|
-
| "The test is too complex" | The function does too much | Break the function into smaller pieces. Test each piece. |
|
|
142
|
-
| "I need to test private methods" | The public interface is too coarse | Refactor to expose behavior through the public API. |
|
|
143
|
-
| "Tests are slow" | Too many integration tests, not enough unit tests | Apply the test pyramid: many unit, some integration, few E2E. |
|
|
144
|
-
| "Tests break when I refactor" | Tests are coupled to implementation | Rewrite tests to assert on behavior, not implementation details. |
|