multi-agents-cli 1.1.7 → 1.1.9
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 +2 -18
- package/core/workflow/agent.js +6 -285
- package/core/workflow/complete.js +5 -141
- package/core/workflow/reset.js +21 -28
- package/core/workflow/run.js +0 -3
- package/init.js +2 -2
- package/lib/questions-flow.js +2 -14
- package/lib/steps.js +1 -13
- package/lib/ui.js +1 -9
- package/package.json +1 -1
- package/core/templates/.agents/backend/API.md +0 -270
- package/core/templates/.agents/backend/AUTH.md +0 -257
- package/core/templates/.agents/backend/DB.md +0 -268
- package/core/templates/.agents/backend/EVENTS.md +0 -264
- package/core/templates/.agents/backend/INIT.md +0 -250
- package/core/templates/.agents/backend/JOBS.md +0 -267
- package/core/templates/.agents/backend/LOGIC.md +0 -302
- package/core/templates/.agents/backend/TESTING.md +0 -277
- package/core/templates/.agents/client/ACCESSIBILITY.md +0 -277
- package/core/templates/.agents/client/FORMS.md +0 -245
- package/core/templates/.agents/client/LOGIC.md +0 -288
- package/core/templates/.agents/client/ROUTING.md +0 -246
- package/core/templates/.agents/client/TESTING.md +0 -252
- package/core/templates/.agents/client/UI.md +0 -237
- package/core/templates/.agents/shared/CLOUD.md +0 -229
- package/core/templates/.agents/shared/CLOUD_TEARDOWN.md +0 -158
- package/core/templates/.agents/shared/SECURITY.md +0 -297
- package/core/templates/.frameworks/backend/django.md +0 -55
- package/core/templates/.frameworks/backend/express.md +0 -74
- package/core/templates/.frameworks/backend/fastapi.md +0 -107
- package/core/templates/.frameworks/backend/fastify.md +0 -74
- package/core/templates/.frameworks/backend/laravel.md +0 -79
- package/core/templates/.frameworks/backend/nestjs.md +0 -75
- package/core/templates/.frameworks/backend/rails.md +0 -84
- package/core/templates/.frameworks/client/angular.md +0 -80
- package/core/templates/.frameworks/client/nextjs.md +0 -47
- package/core/templates/.frameworks/client/nuxt.md +0 -45
- package/core/templates/.frameworks/client/remix.md +0 -44
- package/core/templates/.frameworks/client/sveltekit.md +0 -44
- package/core/templates/.frameworks/client/vite-react.md +0 -45
- package/core/templates/CLAUDE.md +0 -562
- package/core/templates/CONTRACTS.md +0 -16
- package/core/templates/backend/CLAUDE.md +0 -207
- package/core/templates/client/CLAUDE.md +0 -213
package/core/workflow/run.js
CHANGED
|
@@ -56,9 +56,6 @@ const copyWorkflow = (cliRoot) => {
|
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
const findCliRoot = () => {
|
|
59
|
-
// Local node_modules first (npx or local install)
|
|
60
|
-
const localPkg = path.join(__dirname, '..', 'node_modules', 'multi-agents-cli');
|
|
61
|
-
if (fs.existsSync(localPkg)) return localPkg;
|
|
62
59
|
try {
|
|
63
60
|
const globalPkg = execSync('npm root -g', { stdio: 'pipe', encoding: 'utf8' }).trim();
|
|
64
61
|
const p = path.join(globalPkg, 'multi-agents-cli');
|
package/init.js
CHANGED
|
@@ -78,7 +78,7 @@ const projectArg = isGlobalCLI ? args[1] : null;
|
|
|
78
78
|
|
|
79
79
|
if (isReInit) {
|
|
80
80
|
try {
|
|
81
|
-
const gitCommonDir = execSync('git rev-parse --git-common-dir', { encoding: 'utf8'
|
|
81
|
+
const gitCommonDir = execSync('git rev-parse --git-common-dir', { encoding: 'utf8' }).trim();
|
|
82
82
|
const repoRoot = path.resolve(gitCommonDir, '..');
|
|
83
83
|
process.chdir(repoRoot);
|
|
84
84
|
} catch { /* stay in current directory */ }
|
|
@@ -275,7 +275,7 @@ const main = async () => {
|
|
|
275
275
|
],
|
|
276
276
|
}, { onCancel: () => process.exit(0) });
|
|
277
277
|
if (confirm.value !== 'yes') { console.log(dim('\n Cancelled.\n')); process.exit(0); }
|
|
278
|
-
const resetChild = spawn('node', [path.join(ROOT, '.workflow', 'reset.js')
|
|
278
|
+
const resetChild = spawn('node', [path.join(ROOT, '.workflow', 'reset.js')], { stdio: 'inherit', cwd: ROOT });
|
|
279
279
|
resetChild.on('exit', code => process.exit(code ?? 0));
|
|
280
280
|
return;
|
|
281
281
|
} else {
|
package/lib/questions-flow.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// ── Imports ───────────────────────────────────────────────────────────────────
|
|
4
4
|
|
|
5
|
-
const { dim, bold, blue, green, cyan, separator, arrowSelect, arrowConfirm, selectRequired, selectOptional
|
|
5
|
+
const { dim, bold, blue, green, cyan, separator, arrowSelect, arrowConfirm, selectRequired, selectOptional } = require('./ui');
|
|
6
6
|
const { BACK, RESTART } = require('./steps');
|
|
7
7
|
const {
|
|
8
8
|
CLIENT_FRAMEWORKS, BACKEND_FRAMEWORKS, FRAMEWORK_VERSION_FALLBACK,
|
|
@@ -21,7 +21,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
21
21
|
{
|
|
22
22
|
name: 'clientFw',
|
|
23
23
|
run: async (machine, answers) => {
|
|
24
|
-
stepHeader(1, 12);
|
|
25
24
|
console.log(`\n${bold(blue('Client configuration'))}`);
|
|
26
25
|
return await selectRequired('* Client framework (required):', CLIENT_FRAMEWORKS, machine, 0);
|
|
27
26
|
},
|
|
@@ -31,7 +30,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
31
30
|
{
|
|
32
31
|
name: 'clientFwVersion',
|
|
33
32
|
run: async (machine, answers) => {
|
|
34
|
-
stepHeader(2, 12);
|
|
35
33
|
const fw = answers.clientFw;
|
|
36
34
|
const versions = await fetchLatestVersions(fw.value) || FRAMEWORK_VERSION_FALLBACK[fw.value] || [];
|
|
37
35
|
if (!versions.length) return null; // skip silently
|
|
@@ -58,7 +56,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
58
56
|
{
|
|
59
57
|
name: 'clientState',
|
|
60
58
|
run: async (machine, answers) => {
|
|
61
|
-
stepHeader(3, 12);
|
|
62
59
|
const opts = STATE_OPTIONS[answers.clientFw.value] || [];
|
|
63
60
|
return await selectOptional('State management:', opts, machine, 2);
|
|
64
61
|
},
|
|
@@ -68,7 +65,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
68
65
|
{
|
|
69
66
|
name: 'clientUi',
|
|
70
67
|
run: async (machine, answers) => {
|
|
71
|
-
stepHeader(4, 12);
|
|
72
68
|
const opts = UI_OPTIONS[answers.clientFw.value] || [];
|
|
73
69
|
return await selectOptional('UI library:', opts, machine, 3);
|
|
74
70
|
},
|
|
@@ -78,7 +74,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
78
74
|
{
|
|
79
75
|
name: 'clientStyle',
|
|
80
76
|
run: async (machine, answers) => {
|
|
81
|
-
stepHeader(5, 12);
|
|
82
77
|
return await selectOptional('Styling:', STYLING_OPTIONS, machine, 4);
|
|
83
78
|
},
|
|
84
79
|
},
|
|
@@ -87,7 +82,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
87
82
|
{
|
|
88
83
|
name: 'useIntegratedBackend',
|
|
89
84
|
run: async (machine, answers) => {
|
|
90
|
-
stepHeader(6, 12);
|
|
91
85
|
const fw = answers.clientFw;
|
|
92
86
|
if (!fw.integratedBackend) return false; // skip — not applicable
|
|
93
87
|
|
|
@@ -104,7 +98,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
104
98
|
{
|
|
105
99
|
name: 'backendFwObj',
|
|
106
100
|
run: async (machine, answers) => {
|
|
107
|
-
stepHeader(7, 12);
|
|
108
101
|
if (answers.useIntegratedBackend) return null; // skip
|
|
109
102
|
|
|
110
103
|
separator();
|
|
@@ -128,7 +121,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
128
121
|
{
|
|
129
122
|
name: 'backendFwVersion',
|
|
130
123
|
run: async (machine, answers) => {
|
|
131
|
-
stepHeader(8, 12);
|
|
132
124
|
const fwObj = answers.backendFwObj;
|
|
133
125
|
if (!fwObj) return null; // skip — no backend selected
|
|
134
126
|
|
|
@@ -155,7 +147,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
155
147
|
{
|
|
156
148
|
name: 'backendDb',
|
|
157
149
|
run: async (machine, answers) => {
|
|
158
|
-
stepHeader(9, 12);
|
|
159
150
|
if (!answers.backendFwObj) return null;
|
|
160
151
|
return await selectOptional('Database type:', DB_OPTIONS, machine, 8);
|
|
161
152
|
},
|
|
@@ -165,7 +156,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
165
156
|
{
|
|
166
157
|
name: 'backendOrm',
|
|
167
158
|
run: async (machine, answers) => {
|
|
168
|
-
stepHeader(10, 12);
|
|
169
159
|
const { backendFwObj, backendDb } = answers;
|
|
170
160
|
if (!backendFwObj || !backendDb) return null;
|
|
171
161
|
const ormChoices = ORM_OPTIONS_BY_DB[backendDb] || ORM_OPTIONS[backendFwObj.value] || [];
|
|
@@ -177,7 +167,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
177
167
|
{
|
|
178
168
|
name: 'backendAuth',
|
|
179
169
|
run: async (machine, answers) => {
|
|
180
|
-
stepHeader(11, 12);
|
|
181
170
|
const { backendFwObj } = answers;
|
|
182
171
|
if (!backendFwObj) return null;
|
|
183
172
|
return await selectOptional('Auth strategy:', AUTH_OPTIONS[backendFwObj.value] || [], machine, 10);
|
|
@@ -188,7 +177,6 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
188
177
|
{
|
|
189
178
|
name: 'ideChoice',
|
|
190
179
|
run: async (machine, answers) => {
|
|
191
|
-
stepHeader(12, 12);
|
|
192
180
|
separator();
|
|
193
181
|
console.log(`\n${bold(blue('Environment'))}`);
|
|
194
182
|
|
|
@@ -200,7 +188,7 @@ const buildStepDefs = (IDE_CANDIDATES) => [
|
|
|
200
188
|
const detectedIDEs = ideOptions.filter(o => o.detected);
|
|
201
189
|
const undetectedIDEs = ideOptions.filter(o => !o.detected && o.cmd);
|
|
202
190
|
const manualOption = ideOptions.filter(o => !o.cmd);
|
|
203
|
-
const sorted = [...detectedIDEs, ...
|
|
191
|
+
const sorted = [...detectedIDEs, ...manualOption];
|
|
204
192
|
|
|
205
193
|
if (detectedIDEs.length > 1) console.log(`\n ${'\x1b[33m'}Multiple IDEs found${'\x1b[0m'} - select your preference:\n`);
|
|
206
194
|
else if (detectedIDEs.length === 1) console.log(`\n ${'\x1b[32m'}1 IDE found:${'\x1b[0m'} ${bold(detectedIDEs[0].name)}\n`);
|
package/lib/steps.js
CHANGED
|
@@ -103,25 +103,13 @@ const runQuestions = async (stepDefs, machine) => {
|
|
|
103
103
|
if (result === RESTART) return RESTART;
|
|
104
104
|
|
|
105
105
|
if (result === BACK) {
|
|
106
|
-
if (i === 0) return RESTART; // nowhere to go back from step 0
|
|
107
|
-
machine.enterBackNav(i); // record where back-nav started
|
|
106
|
+
if (i === 0) return RESTART; // nowhere to go back to from step 0
|
|
108
107
|
const popped = machine.pop();
|
|
109
108
|
if (popped) delete answers[popped.stepName];
|
|
110
109
|
i--;
|
|
111
110
|
continue;
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
if (result === CONTINUE) {
|
|
115
|
-
// User chose to resume — skip forward to where they first pressed Back
|
|
116
|
-
const resumeTarget = machine.resumeIndex ?? i + 1;
|
|
117
|
-
machine.exitBackNav();
|
|
118
|
-
i = resumeTarget;
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Normal answer — if re-answering during back-nav, exit back-nav mode
|
|
123
|
-
if (machine.inBackNav) machine.exitBackNav();
|
|
124
|
-
|
|
125
113
|
machine.push(i, def.name, result);
|
|
126
114
|
answers[def.name] = result;
|
|
127
115
|
i++;
|
package/lib/ui.js
CHANGED
|
@@ -48,7 +48,7 @@ const arrowSelect = async (message, choices, showBack = false, backLabel = '←
|
|
|
48
48
|
type: 'select',
|
|
49
49
|
name: 'value',
|
|
50
50
|
message,
|
|
51
|
-
choices: allChoices.map((c, i) => ({ title: typeof c === 'string' ? c : c.label, value: i })),
|
|
51
|
+
choices: allChoices.map((c, i) => ({ title: typeof c === 'string' ? c : c.label, value: i, disabled: c.disabled ?? false })),
|
|
52
52
|
}, { onCancel: () => process.exit(0) });
|
|
53
53
|
return res.value ?? 0;
|
|
54
54
|
}
|
|
@@ -109,13 +109,6 @@ const renderTrajectoryLines = (lines) => {
|
|
|
109
109
|
});
|
|
110
110
|
};
|
|
111
111
|
|
|
112
|
-
// ── Step progress header ─────────────────────────────────────────────────────
|
|
113
|
-
|
|
114
|
-
const stepHeader = (stepIndex, totalSteps) => {
|
|
115
|
-
console.log(`
|
|
116
|
-
${dim(`Step ${stepIndex} of ${totalSteps}`)}`);
|
|
117
|
-
};
|
|
118
|
-
|
|
119
112
|
// ── Step selection helpers ────────────────────────────────────────────────────
|
|
120
113
|
|
|
121
114
|
const { BACK, RESTART } = require('./steps');
|
|
@@ -157,7 +150,6 @@ const selectOptional = async (prompt, items, stepMachine, stepIndex) => {
|
|
|
157
150
|
// ── Exports ───────────────────────────────────────────────────────────────────
|
|
158
151
|
|
|
159
152
|
module.exports = {
|
|
160
|
-
stepHeader,
|
|
161
153
|
c, bold, green, yellow, dim, cyan, blue, red,
|
|
162
154
|
rl, ask,
|
|
163
155
|
arrowSelect, arrowConfirm,
|
package/package.json
CHANGED
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
# API Agent
|
|
2
|
-
# Scope: backend/
|
|
3
|
-
# Loaded by: manual reference in prompt
|
|
4
|
-
# Example: `Use .agents/backend/API.md. Task: implement the job applications CRUD endpoints.`
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Mission
|
|
9
|
-
|
|
10
|
-
Implement all API endpoint handlers, request/response shaping, DTO design,
|
|
11
|
-
and input validation against an already-scaffolded backend structure. This agent
|
|
12
|
-
builds inside the architecture defined by the INIT agent — it does not make
|
|
13
|
-
structural or architectural decisions.
|
|
14
|
-
|
|
15
|
-
Read `shared/wiring.config.json` and `CONTRACTS.md` on entry and treat both
|
|
16
|
-
as binding contracts. Never redefine types or introduce vars outside these files.
|
|
17
|
-
|
|
18
|
-
This agent does not own business logic, database queries, authentication
|
|
19
|
-
strategies, background job processing, event handling, or architectural decisions.
|
|
20
|
-
Those belong to their respective agents.
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Pre-flight Checks
|
|
25
|
-
|
|
26
|
-
Runs in order before any file is created or modified. All checks must pass.
|
|
27
|
-
|
|
28
|
-
### 1. Task Clarity Check
|
|
29
|
-
|
|
30
|
-
Is the task specific enough to act on?
|
|
31
|
-
|
|
32
|
-
- Identify: which endpoint or endpoints are being built or modified
|
|
33
|
-
- Identify: what HTTP method, path, request body, and response shape apply
|
|
34
|
-
- Identify: what guard or access control the endpoint requires
|
|
35
|
-
|
|
36
|
-
If any of these cannot be determined from the task as given:
|
|
37
|
-
```
|
|
38
|
-
## CLARIFICATION NEEDED - [Round 1 or 2]
|
|
39
|
-
The following is unclear:
|
|
40
|
-
- <specific ambiguity>
|
|
41
|
-
Please provide more detail before this agent proceeds.
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Maximum 2 rounds. If ambiguity remains after round 2:
|
|
45
|
-
```
|
|
46
|
-
## TASK TOO AMBIGUOUS - CANNOT PROCEED
|
|
47
|
-
Two clarification rounds reached. Please rephrase the task with:
|
|
48
|
-
- explicit HTTP method and path
|
|
49
|
-
- request body shape and response shape
|
|
50
|
-
- guard or access control requirement
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### 2. Scope Integrity Check
|
|
54
|
-
|
|
55
|
-
Does this task stay within API concerns?
|
|
56
|
-
|
|
57
|
-
If the task requires:
|
|
58
|
-
- Business logic or domain rules → redirect to `.agents/backend/LOGIC.md`
|
|
59
|
-
- Database schema or query implementation → redirect to `.agents/backend/DB.md`
|
|
60
|
-
- Auth strategy or guard implementation → redirect to `.agents/backend/AUTH.md`
|
|
61
|
-
- Background job or scheduled task → redirect to `.agents/backend/JOBS.md`
|
|
62
|
-
- Event emission or subscription → redirect to `.agents/backend/EVENTS.md`
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
## SCOPE REDIRECT
|
|
66
|
-
This task includes concerns outside API.md scope:
|
|
67
|
-
- <concern> → belongs to <agent>
|
|
68
|
-
Proceed with API concerns only, or reassign the full task.
|
|
69
|
-
Awaiting your direction.
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### 3. Dependency Check
|
|
73
|
-
|
|
74
|
-
Does this task depend on something that doesn't exist yet?
|
|
75
|
-
|
|
76
|
-
- Service or business logic the endpoint delegates to not yet implemented
|
|
77
|
-
- Database entity or repository not yet built
|
|
78
|
-
- Auth guard not yet implemented
|
|
79
|
-
- Shared request/response types not yet in `CONTRACTS.md`
|
|
80
|
-
|
|
81
|
-
If yes:
|
|
82
|
-
```
|
|
83
|
-
## DEPENDENCY MISSING
|
|
84
|
-
Cannot proceed without:
|
|
85
|
-
- <what is missing>
|
|
86
|
-
- <where it should come from>
|
|
87
|
-
Awaiting resolution before continuing.
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### 4. Contract Alignment Check
|
|
91
|
-
|
|
92
|
-
Does this task produce or consume types that cross the client/backend boundary?
|
|
93
|
-
|
|
94
|
-
- Request body shapes and response shapes are cross-boundary contracts
|
|
95
|
-
- If yes → verify the relevant types exist in `CONTRACTS.md`
|
|
96
|
-
- If missing → stop and emit a CONTRACTS CHANGE PROPOSAL before proceeding
|
|
97
|
-
- Never define request or response types locally inside a controller -
|
|
98
|
-
they belong in `shared/types/`
|
|
99
|
-
|
|
100
|
-
### 5. Destructive Action Check
|
|
101
|
-
|
|
102
|
-
Does this task modify or remove an existing endpoint?
|
|
103
|
-
|
|
104
|
-
If yes, before touching any file:
|
|
105
|
-
```
|
|
106
|
-
## DESTRUCTIVE ACTION - CONFIRMATION REQUIRED
|
|
107
|
-
This task will modify:
|
|
108
|
-
- <endpoint path and method>
|
|
109
|
-
- <what will change in request or response shape>
|
|
110
|
-
- <what clients or flows depend on this endpoint>
|
|
111
|
-
Awaiting explicit confirmation to proceed.
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### 6. Size & Atomicity Check
|
|
115
|
-
|
|
116
|
-
Is this task too large for one reliable pass?
|
|
117
|
-
|
|
118
|
-
If the task spans multiple unrelated endpoints or combines endpoint
|
|
119
|
-
definition with service implementation:
|
|
120
|
-
```
|
|
121
|
-
## TASK BREAKDOWN PROPOSED
|
|
122
|
-
This task is too large for one pass. Suggested sequence:
|
|
123
|
-
1. <subtask A - e.g. define DTOs and endpoint shell>
|
|
124
|
-
2. <subtask B - e.g. wire service delegation>
|
|
125
|
-
3. <subtask C - e.g. add guards and validation>
|
|
126
|
-
Proceeding with subtask 1. Confirm to continue after each step.
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## Operating Principles
|
|
132
|
-
|
|
133
|
-
These apply to every API task regardless of framework.
|
|
134
|
-
|
|
135
|
-
- **Read wiring.config.json before writing any code** - the backend section
|
|
136
|
-
defines all agreed runtime variable names. Never introduce new env var names
|
|
137
|
-
without updating `shared/wiring.config.json` first.
|
|
138
|
-
|
|
139
|
-
- **Derive API patterns from resolved stack** - apply `{{FRAMEWORK}}`
|
|
140
|
-
idiomatic controller and routing conventions without needing explicit
|
|
141
|
-
instruction per task.
|
|
142
|
-
Examples: NestJS controllers with decorators, Express routers,
|
|
143
|
-
Django REST Framework views, Laravel route controllers.
|
|
144
|
-
|
|
145
|
-
- **Controllers shape, services decide** - controllers handle request
|
|
146
|
-
parsing, response formatting, and guard wiring only. All decisions
|
|
147
|
-
and domain logic are delegated to the service layer.
|
|
148
|
-
|
|
149
|
-
- **DTOs own validation** - input validation lives in the DTO or request
|
|
150
|
-
schema, not in the controller or service. Validation is declarative
|
|
151
|
-
and colocated with the data shape it validates.
|
|
152
|
-
|
|
153
|
-
- **Request and response types are contracts** - shapes that cross the
|
|
154
|
-
client/backend boundary belong in `CONTRACTS.md` and `shared/types/`.
|
|
155
|
-
Never define them locally in a controller file.
|
|
156
|
-
|
|
157
|
-
- **Consistent error responses** - all error responses follow the same
|
|
158
|
-
shape across every endpoint. Never return ad-hoc error objects.
|
|
159
|
-
Define the error response shape in `CONTRACTS.md`.
|
|
160
|
-
|
|
161
|
-
- **Every endpoint declares its guard** - no endpoint is implicitly
|
|
162
|
-
public or protected. Access control is explicit on every route.
|
|
163
|
-
|
|
164
|
-
- **No business logic in controllers** - if a controller is making
|
|
165
|
-
domain decisions beyond routing and shaping, that logic belongs
|
|
166
|
-
in `.agents/backend/LOGIC.md` territory.
|
|
167
|
-
|
|
168
|
-
- **HTTP semantics are correct** - use the correct HTTP method and
|
|
169
|
-
status code for every operation. Never return 200 for an error,
|
|
170
|
-
never use GET for a mutation.
|
|
171
|
-
|
|
172
|
-
<!-- @annotation
|
|
173
|
-
Add project-specific API conventions here.
|
|
174
|
-
Examples: API versioning strategy, base path conventions,
|
|
175
|
-
pagination shape, error response format, rate limiting patterns.
|
|
176
|
-
-->
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## Workflow
|
|
181
|
-
|
|
182
|
-
```
|
|
183
|
-
explore → summarize → plan → execute → validate
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
**Explore**
|
|
187
|
-
Read existing controllers and DTOs before writing anything.
|
|
188
|
-
Understand current endpoint patterns, naming, guard usage, and
|
|
189
|
-
response shapes.
|
|
190
|
-
|
|
191
|
-
**Summarize**
|
|
192
|
-
In 2-3 sentences, state what endpoints exist, what is missing,
|
|
193
|
-
and what will be built. Surface this before writing any code.
|
|
194
|
-
|
|
195
|
-
**Plan**
|
|
196
|
-
List every endpoint being added or modified:
|
|
197
|
-
- HTTP method and path
|
|
198
|
-
- Request body shape (DTO)
|
|
199
|
-
- Response shape
|
|
200
|
-
- Guard or access control
|
|
201
|
-
- Service delegation target
|
|
202
|
-
|
|
203
|
-
Confirm the plan before proceeding - endpoint contracts are
|
|
204
|
-
cross-boundary and harder to change once the client consumes them.
|
|
205
|
-
|
|
206
|
-
**Execute**
|
|
207
|
-
Define DTOs first, then the controller, then wire guards and
|
|
208
|
-
service delegation. Do not implement service logic here.
|
|
209
|
-
|
|
210
|
-
**Validate**
|
|
211
|
-
After each endpoint:
|
|
212
|
-
- Confirm request validation rejects invalid input correctly
|
|
213
|
-
- Confirm response shape matches the type in `CONTRACTS.md`
|
|
214
|
-
- Confirm the correct HTTP status codes are returned
|
|
215
|
-
- Confirm the guard enforces the correct access condition
|
|
216
|
-
- Confirm no existing endpoints are unintentionally affected
|
|
217
|
-
|
|
218
|
-
---
|
|
219
|
-
|
|
220
|
-
## Safety Rules
|
|
221
|
-
|
|
222
|
-
- Never implement business or domain logic inside a controller
|
|
223
|
-
- Never define request or response types locally - use `CONTRACTS.md`
|
|
224
|
-
- Never leave an endpoint without explicit access control declaration
|
|
225
|
-
- Never return incorrect HTTP status codes
|
|
226
|
-
- Never return ad-hoc error shapes - use the consistent error contract
|
|
227
|
-
- Never modify endpoints outside the current task's stated scope
|
|
228
|
-
- Surface best-practice observations once - never loop on them
|
|
229
|
-
|
|
230
|
-
---
|
|
231
|
-
|
|
232
|
-
## Communication
|
|
233
|
-
|
|
234
|
-
| Situation | Action |
|
|
235
|
-
|------------------------------------|------------------------------------------------|
|
|
236
|
-
| Task is ambiguous | Clarification request (max 2 rounds) |
|
|
237
|
-
| Task bleeds into another domain | Scope redirect, await direction |
|
|
238
|
-
| Dependency is missing | Dependency alert, await resolution |
|
|
239
|
-
| Contract type missing | CONTRACTS CHANGE PROPOSAL, write and proceed |
|
|
240
|
-
| Existing endpoint will change | Destructive action confirmation |
|
|
241
|
-
| Task is too large | Breakdown proposal, execute one step at a time |
|
|
242
|
-
| Best practice deviation found | Surface once, await confirmation, move on |
|
|
243
|
-
|
|
244
|
-
---
|
|
245
|
-
|
|
246
|
-
## Definition of Done
|
|
247
|
-
|
|
248
|
-
An API task is complete when:
|
|
249
|
-
|
|
250
|
-
- [ ] All planned endpoints exist with correct HTTP methods and paths
|
|
251
|
-
- [ ] DTOs own all input validation - no validation in controllers or services
|
|
252
|
-
- [ ] All request and response types exist in `CONTRACTS.md` - none local
|
|
253
|
-
- [ ] Every endpoint explicitly declares its access control
|
|
254
|
-
- [ ] All error responses follow the consistent error contract
|
|
255
|
-
- [ ] HTTP status codes are semantically correct
|
|
256
|
-
- [ ] No business logic exists inside controllers
|
|
257
|
-
- [ ] No existing endpoints outside task scope are affected
|
|
258
|
-
- [ ] Code follows `{{FRAMEWORK}}` idiomatic controller patterns
|
|
259
|
-
- [ ] Pre-flight checks all passed and documented if any flags were raised
|
|
260
|
-
|
|
261
|
-
---
|
|
262
|
-
|
|
263
|
-
## Session Close
|
|
264
|
-
|
|
265
|
-
When all Definition of Done items are checked:
|
|
266
|
-
|
|
267
|
-
1. Mark TASK.md complete: change `[ ] COMPLETED` to `[x] COMPLETED` at the top of TASK.md
|
|
268
|
-
2. Run: `npm run complete`
|
|
269
|
-
|
|
270
|
-
**Next recommended agent:** backend/AUTH
|