create-kuckit-app 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -14
- package/package.json +1 -1
- package/templates/base/.claude/skills/beads/CLAUDE.md +87 -0
- package/templates/base/.claude/skills/beads/README.md +123 -0
- package/templates/base/.claude/skills/beads/SKILL.md +77 -715
- package/templates/base/.claude/skills/beads/adr/0001-bd-prime-as-source-of-truth.md +61 -0
- package/templates/base/.claude/skills/beads/resources/AGENTS.md +62 -0
- package/templates/base/.claude/skills/beads/resources/ASYNC_GATES.md +175 -0
- package/templates/base/.claude/skills/beads/resources/BOUNDARIES.md +520 -0
- package/templates/base/.claude/skills/beads/resources/CHEMISTRY_PATTERNS.md +197 -0
- package/templates/base/.claude/skills/beads/resources/CLI_REFERENCE.md +561 -0
- package/templates/base/.claude/skills/beads/resources/DEPENDENCIES.md +754 -0
- package/templates/base/.claude/skills/beads/resources/INTEGRATION_PATTERNS.md +438 -0
- package/templates/base/.claude/skills/beads/resources/ISSUE_CREATION.md +150 -0
- package/templates/base/.claude/skills/beads/resources/MOLECULES.md +370 -0
- package/templates/base/.claude/skills/beads/resources/PATTERNS.md +363 -0
- package/templates/base/.claude/skills/beads/resources/RESUMABILITY.md +239 -0
- package/templates/base/.claude/skills/beads/resources/STATIC_DATA.md +61 -0
- package/templates/base/.claude/skills/beads/resources/TROUBLESHOOTING.md +537 -0
- package/templates/base/.claude/skills/beads/resources/WORKFLOWS.md +638 -0
- package/templates/base/.claude/skills/beads/resources/WORKTREES.md +95 -0
- package/templates/base/.claude/skills/browser-skill/SKILL.md +72 -0
- package/templates/base/.claude/skills/knowledge/SKILL.md +155 -205
- package/templates/base/.claude/skills/knowledge/reference/doc-mapping.md +49 -0
- package/templates/base/.claude/skills/knowledge/reference/extraction-prompts.md +102 -0
- package/templates/base/.claude/skills/kuckit/SKILL.md +15 -9
- package/templates/base/.claude/skills/kuckit/references/MODULE-DEVELOPMENT.md +142 -0
- package/templates/base/.claude/skills/kuckit/references/PACKAGES.md +22 -17
- package/templates/base/.claude/skills/kuckit/references/PUBLISHING.md +92 -0
- package/templates/base/.claude/skills/module-testing/SKILL.md +1 -1
- package/templates/base/.claude/skills/planning/SKILL.md +26 -1
- package/templates/base/.env.example +1 -1
- package/templates/base/AGENTS.md +155 -418
- package/templates/base/apps/server/src/modules.ts +14 -1
- package/templates/base/apps/web/.env.example +1 -1
- package/templates/base/apps/web/src/routes/$.tsx +0 -1
- package/templates/base/apps/web/src/routes/dashboard.tsx +3 -1
- package/templates/base/docs/ARCHITECTURE.md +689 -0
- package/templates/base/docs/DEPENDENCY-INJECTION.md +871 -0
- package/templates/base/docs/DEPLOYMENT.md +573 -0
- package/templates/base/docs/INDEX.md +135 -0
- package/templates/base/docs/MIGRATION.md +989 -0
- package/templates/base/docs/MODULE_CSS.md +343 -0
- package/templates/base/docs/MODULE_TESTING.md +368 -0
- package/templates/base/docs/MULTI_AGENT_WORKFLOW.md +909 -0
- package/templates/base/docs/TESTING.md +579 -0
- package/templates/base/docs/TROUBLESHOOTING.md +360 -0
- package/templates/base/package.json +2 -0
- package/templates/base/packages/items-module/AGENTS.md +3 -1
- package/templates/base/packages/items-module/src/server/adapters/{item.drizzle.ts → item.repository.ts} +1 -13
- package/templates/base/packages/items-module/src/server/module.ts +2 -1
- package/templates/base/packages/items-module/src/server/schema/item.ts +13 -0
package/templates/base/AGENTS.md
CHANGED
|
@@ -2,507 +2,244 @@
|
|
|
2
2
|
|
|
3
3
|
> **Main Documentation**: [Kuckit SDK](https://github.com/draphonix/kuckit)
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Commands
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
bun run
|
|
11
|
-
bun run dev
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## Project Structure
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
__APP_NAME_KEBAB__/
|
|
18
|
-
├── apps/
|
|
19
|
-
│ ├── server/ # Express + oRPC backend (port 3000)
|
|
20
|
-
│ └── web/ # React + TanStack Router frontend (port 3001)
|
|
21
|
-
├── packages/
|
|
22
|
-
│ └── items-module/ # Example Kuckit module (reference implementation)
|
|
23
|
-
├── .env.example # Environment template
|
|
24
|
-
├── docker-compose.yml # PostgreSQL container
|
|
25
|
-
├── drizzle.config.ts # Drizzle pointing to @kuckit/db + module schemas
|
|
26
|
-
└── turbo.json # Turborepo configuration
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
**Note:** Core packages (`api`, `auth`, `db`, `domain`, `contracts`) are installed from npm as `@kuckit/*` dependencies, not copied into your project.
|
|
30
|
-
|
|
31
|
-
## Bootstrap Architecture
|
|
32
|
-
|
|
33
|
-
Kuckit uses **bootstrap packages** to minimize boilerplate in your apps:
|
|
34
|
-
|
|
35
|
-
### Server Bootstrap (`@kuckit/app-server`)
|
|
36
|
-
|
|
37
|
-
```typescript
|
|
38
|
-
// apps/server/src/server.ts
|
|
39
|
-
import 'dotenv/config'
|
|
40
|
-
import { runKuckitServer } from '@kuckit/app-server'
|
|
41
|
-
import { loadConfig } from './config/server'
|
|
42
|
-
import { getModuleSpecs } from './config/modules'
|
|
43
|
-
|
|
44
|
-
runKuckitServer({
|
|
45
|
-
loadConfig,
|
|
46
|
-
getModuleSpecs,
|
|
47
|
-
}).catch((error) => {
|
|
48
|
-
console.error('Failed to start server:', error)
|
|
49
|
-
process.exit(1)
|
|
50
|
-
})
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
**What `runKuckitServer` handles automatically:**
|
|
54
|
-
|
|
55
|
-
- Express app creation with CORS, JSON parsing
|
|
56
|
-
- DI container setup with per-request scoping
|
|
57
|
-
- Module loading and API route wiring
|
|
58
|
-
- Auth, health, metrics endpoints
|
|
59
|
-
- Graceful shutdown
|
|
60
|
-
|
|
61
|
-
**Customization via hooks:**
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
runKuckitServer({
|
|
65
|
-
loadConfig,
|
|
66
|
-
getModuleSpecs,
|
|
67
|
-
hooks: {
|
|
68
|
-
onAppCreated: (app) => app.use(helmet()),
|
|
69
|
-
onContainerReady: (container) => {
|
|
70
|
-
/* warm caches */
|
|
71
|
-
},
|
|
72
|
-
onServerReady: (port) => console.log(`Listening on ${port}`),
|
|
73
|
-
},
|
|
74
|
-
})
|
|
75
|
-
```
|
|
8
|
+
# Development
|
|
9
|
+
bun run dev # Start web + server
|
|
10
|
+
bun run dev:server # Backend only (port 3000)
|
|
11
|
+
bun run dev:web # Frontend only (port 5173)
|
|
12
|
+
bun run check-types # Typecheck all packages
|
|
13
|
+
bun run build # Build all packages
|
|
76
14
|
|
|
77
|
-
|
|
15
|
+
# Database
|
|
16
|
+
bun run db:push # Sync schema to database
|
|
17
|
+
bun run db:studio # Open Drizzle Studio
|
|
78
18
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
import { createAuthClient } from 'better-auth/react'
|
|
83
|
-
import config from '../kuckit.config'
|
|
84
|
-
|
|
85
|
-
const authClient = createAuthClient({
|
|
86
|
-
baseURL: import.meta.env.VITE_SERVER_URL,
|
|
87
|
-
})
|
|
19
|
+
# Module management
|
|
20
|
+
bunx kuckit generate module <name> # Scaffold new module
|
|
21
|
+
bunx kuckit doctor # Validate setup
|
|
88
22
|
|
|
89
|
-
const KuckitProvider = createKuckitWebProvider({
|
|
90
|
-
config,
|
|
91
|
-
authClient,
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
95
|
-
<StrictMode>
|
|
96
|
-
<KuckitProvider>
|
|
97
|
-
<App />
|
|
98
|
-
</KuckitProvider>
|
|
99
|
-
</StrictMode>
|
|
100
|
-
)
|
|
101
23
|
```
|
|
102
24
|
|
|
103
|
-
|
|
25
|
+
## Architecture
|
|
104
26
|
|
|
105
|
-
|
|
106
|
-
import { useKuckitWeb, useAuth } from '@kuckit/app-web'
|
|
27
|
+
**Clean Architecture** with **Awilix DI** and **modular plugin system**.
|
|
107
28
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
Kuckit uses a **module-based architecture** where each module contains its own Clean Architecture layers internally.
|
|
118
|
-
|
|
119
|
-
### Module Structure
|
|
120
|
-
|
|
121
|
-
```
|
|
122
|
-
packages/your-module/
|
|
123
|
-
├── src/
|
|
124
|
-
│ ├── domain/ # Entities with Zod schemas
|
|
125
|
-
│ ├── ports/ # Repository interfaces
|
|
126
|
-
│ ├── adapters/ # Drizzle implementations
|
|
127
|
-
│ ├── usecases/ # Business logic
|
|
128
|
-
│ ├── api/ # oRPC routers
|
|
129
|
-
│ ├── ui/ # React components (optional)
|
|
130
|
-
│ ├── module.ts # Server module definition
|
|
131
|
-
│ └── client-module.ts # Client module definition
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Creating a New Module
|
|
135
|
-
|
|
136
|
-
```bash
|
|
137
|
-
bunx kuckit generate module your-module
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
This scaffolds a full Clean Architecture module. Then:
|
|
141
|
-
|
|
142
|
-
1. Implement your domain entities in `domain/`
|
|
143
|
-
2. Define repository interfaces in `ports/`
|
|
144
|
-
3. Implement adapters in `adapters/`
|
|
145
|
-
4. Create use cases in `usecases/`
|
|
146
|
-
5. Expose API in `api/` via oRPC router
|
|
147
|
-
6. Register module in `apps/server/src/config/modules.ts`
|
|
148
|
-
7. Add client module to `apps/web/src/modules.client.ts`
|
|
149
|
-
8. Add schema path to `drizzle.config.ts` in project root
|
|
150
|
-
9. Run `bun run db:push` to create the table
|
|
29
|
+
| Layer | Packages | Purpose |
|
|
30
|
+
| -------------- | --------------------------------------------------------- | ---------------------------------- |
|
|
31
|
+
| Interface | `apps/web`, `apps/server` | React + Express entry points |
|
|
32
|
+
| Bootstrap | `@kuckit/app-server`, `@kuckit/app-web` | DI wiring, module loading |
|
|
33
|
+
| SDK | `@kuckit/sdk`, `@kuckit/sdk-react` | Module system, registries |
|
|
34
|
+
| Application | `packages/application`, `packages/api` | Use cases, oRPC procedures |
|
|
35
|
+
| Domain | `packages/domain`, `packages/contracts` | Entities, ports, DTOs |
|
|
36
|
+
| Infrastructure | `packages/infrastructure`, `packages/db`, `packages/auth` | Repositories, Drizzle, Better-Auth |
|
|
151
37
|
|
|
152
38
|
### Dependency Rules
|
|
153
39
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
adapters → Implements ports, depends on domain
|
|
162
|
-
↓
|
|
163
|
-
api → Wires everything together
|
|
164
|
-
```
|
|
40
|
+
| Layer | CAN Import | CANNOT Import |
|
|
41
|
+
| ---------------- | ------------------------------ | ----------------------- |
|
|
42
|
+
| `domain` | (nothing) | everything else |
|
|
43
|
+
| `application` | domain | infrastructure, api, db |
|
|
44
|
+
| `infrastructure` | domain | application, api |
|
|
45
|
+
| `contracts` | zod | domain, application |
|
|
46
|
+
| `api` | domain, application, contracts | infrastructure, db |
|
|
165
47
|
|
|
166
|
-
##
|
|
48
|
+
## Module Quick Reference
|
|
167
49
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
### Module Lifecycle
|
|
171
|
-
|
|
172
|
-
Modules are loaded in a specific sequence:
|
|
173
|
-
|
|
174
|
-
```
|
|
175
|
-
1. createKuckitContainer()
|
|
176
|
-
└─► Core services registered (logger, db, cache, eventBus)
|
|
177
|
-
|
|
178
|
-
2. loadKuckitModules({ modules: [...] })
|
|
179
|
-
├─► Phase 1: register() - DI bindings for all modules
|
|
180
|
-
├─► Phase 2: registerApi() - API registrations collected
|
|
181
|
-
├─► Phase 3: onApiRegistrations callback (wire routers HERE)
|
|
182
|
-
├─► Phase 4: onBootstrap() - Startup logic
|
|
183
|
-
└─► Phase 5: onComplete callback
|
|
184
|
-
|
|
185
|
-
3. Application runs...
|
|
186
|
-
|
|
187
|
-
4. disposeContainer()
|
|
188
|
-
└─► For each module: onShutdown()
|
|
50
|
+
```bash
|
|
51
|
+
bunx kuckit generate module billing --org acme
|
|
189
52
|
```
|
|
190
53
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
After container creation, these services are available via DI:
|
|
194
|
-
|
|
195
|
-
| Token | Type | Lifetime | Description |
|
|
196
|
-
| ------------------ | ------------------ | --------- | --------------------------- |
|
|
197
|
-
| `config` | `CoreConfig` | Singleton | Application configuration |
|
|
198
|
-
| `db` | Drizzle | Singleton | Database query builder |
|
|
199
|
-
| `dbPool` | `Pool` | Singleton | PostgreSQL connection pool |
|
|
200
|
-
| `logger` | `Logger` | Singleton | Structured logging |
|
|
201
|
-
| `eventBus` | `EventBus` | Singleton | Pub/sub event system |
|
|
202
|
-
| `clock` | `Clock` | Singleton | Time abstraction (testable) |
|
|
203
|
-
| `cacheStore` | `CacheStore` | Singleton | Key-value cache |
|
|
204
|
-
| `rateLimiterStore` | `RateLimiterStore` | Singleton | Rate limiting |
|
|
205
|
-
| `auth` | Better-Auth | Singleton | Authentication utilities |
|
|
206
|
-
| `requestId` | `string` | Scoped | Per-request unique ID |
|
|
207
|
-
| `requestLogger` | `Logger` | Scoped | Logger with request context |
|
|
208
|
-
|
|
209
|
-
### Server Module Definition
|
|
54
|
+
**Server module** (`src/module.ts`):
|
|
210
55
|
|
|
211
56
|
```typescript
|
|
212
|
-
import { defineKuckitModule,
|
|
57
|
+
import { defineKuckitModule, asFunction } from '@kuckit/sdk'
|
|
213
58
|
|
|
214
59
|
export const kuckitModule = defineKuckitModule({
|
|
215
|
-
id: '
|
|
216
|
-
displayName: 'Billing',
|
|
217
|
-
version: '1.0.0',
|
|
218
|
-
capabilities: ['nav.item', 'api.public'],
|
|
219
|
-
|
|
60
|
+
id: 'myorg.billing',
|
|
220
61
|
register(ctx) {
|
|
221
|
-
// Phase 1: Register DI bindings
|
|
222
62
|
ctx.container.register({
|
|
223
|
-
|
|
224
|
-
createInvoice: asFunction(makeCreateInvoiceUseCase).scoped(),
|
|
63
|
+
invoiceRepo: asFunction(({ db }) => makeInvoiceRepo(db)).scoped(),
|
|
225
64
|
})
|
|
226
65
|
},
|
|
227
|
-
|
|
228
66
|
registerApi(ctx) {
|
|
229
|
-
|
|
230
|
-
ctx.addApiRegistration({
|
|
231
|
-
type: 'rpc-router',
|
|
232
|
-
name: 'invoices',
|
|
233
|
-
router: invoicesRouter,
|
|
234
|
-
})
|
|
235
|
-
},
|
|
236
|
-
|
|
237
|
-
onBootstrap(ctx) {
|
|
238
|
-
// Phase 4: Startup logic (cache warming, logging, etc.)
|
|
239
|
-
ctx.container.resolve('logger').info('Billing module started')
|
|
240
|
-
},
|
|
241
|
-
|
|
242
|
-
onShutdown(ctx) {
|
|
243
|
-
// Cleanup on shutdown
|
|
244
|
-
ctx.container.resolve('logger').info('Billing module stopped')
|
|
67
|
+
ctx.addApiRegistration({ type: 'rpc-router', name: 'invoices', router: invoicesRouter })
|
|
245
68
|
},
|
|
246
69
|
})
|
|
247
70
|
```
|
|
248
71
|
|
|
249
|
-
|
|
72
|
+
**Client module** (`src/client-module.ts`):
|
|
250
73
|
|
|
251
74
|
```typescript
|
|
252
75
|
import { defineKuckitClientModule } from '@kuckit/sdk-react'
|
|
253
76
|
|
|
254
77
|
export const kuckitClientModule = defineKuckitClientModule({
|
|
255
|
-
id: '
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
routes: [
|
|
260
|
-
{
|
|
261
|
-
id: 'billing-invoices',
|
|
262
|
-
path: '/billing/invoices',
|
|
263
|
-
component: InvoicesPage,
|
|
264
|
-
},
|
|
265
|
-
],
|
|
266
|
-
|
|
267
|
-
navItems: [
|
|
268
|
-
{
|
|
269
|
-
id: 'billing-nav',
|
|
270
|
-
label: 'Billing',
|
|
271
|
-
href: '/billing/invoices',
|
|
272
|
-
icon: CreditCard,
|
|
273
|
-
order: 50,
|
|
274
|
-
},
|
|
275
|
-
],
|
|
276
|
-
|
|
277
|
-
slots: {
|
|
278
|
-
'dashboard.widgets': {
|
|
279
|
-
component: BillingWidget,
|
|
280
|
-
order: 10,
|
|
281
|
-
},
|
|
282
|
-
},
|
|
78
|
+
id: 'myorg.billing',
|
|
79
|
+
routes: [{ id: 'billing', path: '/billing', component: BillingPage }],
|
|
80
|
+
navItems: [{ id: 'billing-nav', label: 'Billing', href: '/billing', order: 50 }],
|
|
283
81
|
})
|
|
284
82
|
```
|
|
285
83
|
|
|
286
|
-
|
|
84
|
+
**Critical**: oRPC routers must be wired before `RPCHandler` is created. See [SDK docs](./packages/sdk/AGENTS.md).
|
|
287
85
|
|
|
288
|
-
|
|
86
|
+
## Coding Standards
|
|
289
87
|
|
|
290
|
-
- `
|
|
291
|
-
- `
|
|
292
|
-
- `
|
|
293
|
-
- `
|
|
294
|
-
- `api.public` - Has public API endpoints
|
|
295
|
-
- `slot.provider` - Provides slot components
|
|
88
|
+
- **TypeScript**: Strict mode, no `any`, explicit return types
|
|
89
|
+
- **Factory pattern**: Use `createX()` functions, not direct imports with side effects
|
|
90
|
+
- **DI lifetimes**: `singleton()` for shared, `scoped()` for per-request
|
|
91
|
+
- **Naming**: entities `invoice.ts`, ports `invoice-repository.ts`, use cases `create-invoice.ts`
|
|
296
92
|
|
|
297
|
-
|
|
93
|
+
## Issue Tracking (bd)
|
|
298
94
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
interface ItemsRpc {
|
|
306
|
-
items: {
|
|
307
|
-
list: (input: Record<string, never>) => Promise<Item[]>
|
|
308
|
-
create: (input: { name: string }) => Promise<Item>
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function ItemsPage() {
|
|
313
|
-
const rpc = useRpc<ItemsRpc>()
|
|
314
|
-
const queryClient = useQueryClient()
|
|
315
|
-
|
|
316
|
-
const { data: items = [], isLoading } = useQuery({
|
|
317
|
-
queryKey: ['items'],
|
|
318
|
-
queryFn: () => rpc.items.list({}),
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
const createMutation = useMutation({
|
|
322
|
-
mutationFn: (data: { name: string }) => rpc.items.create(data),
|
|
323
|
-
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['items'] }),
|
|
324
|
-
})
|
|
325
|
-
|
|
326
|
-
// ... component render
|
|
327
|
-
}
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### oRPC Router Wiring (Important)
|
|
331
|
-
|
|
332
|
-
oRPC's `RPCHandler` captures the router object at construction time. Module routers must be wired **before** the handler is created:
|
|
333
|
-
|
|
334
|
-
1. Modules register routers via `registerApi()` hook
|
|
335
|
-
2. Server wires routers in `onApiRegistrations` into a **mutable router object**
|
|
336
|
-
3. `RPCHandler` is created **after** modules are loaded
|
|
337
|
-
|
|
338
|
-
```typescript
|
|
339
|
-
// apps/server/src/rpc-router-registry.ts
|
|
340
|
-
export const rootRpcRouter = { ...appRouter }
|
|
341
|
-
|
|
342
|
-
export const wireModuleRpcRouters = (registrations: ApiRegistration[]) => {
|
|
343
|
-
for (const reg of registrations) {
|
|
344
|
-
if (reg.type === 'rpc-router') {
|
|
345
|
-
rootRpcRouter[reg.name] = reg.router
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
95
|
+
```bash
|
|
96
|
+
bd ready # Show unblocked work
|
|
97
|
+
bd create "Title" -t feature -p 1 # Create issue
|
|
98
|
+
bd update bd-42 --status in_progress # Claim task
|
|
99
|
+
bd close bd-42 --reason "Done" # Complete
|
|
349
100
|
```
|
|
350
101
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
For modules that need direct Express response access (e.g., AI streaming with `pipeUIMessageStreamToResponse`), use REST routers instead of oRPC:
|
|
354
|
-
|
|
355
|
-
```typescript
|
|
356
|
-
// In your module's registerApi()
|
|
357
|
-
ctx.addApiRegistration({
|
|
358
|
-
type: 'rest-router',
|
|
359
|
-
name: 'ai',
|
|
360
|
-
router: createAiRouter(),
|
|
361
|
-
prefix: '/ai', // Optional, defaults to /<name>
|
|
362
|
-
})
|
|
363
|
-
```
|
|
102
|
+
Types: `bug`, `feature`, `task`, `epic`, `chore` | Priorities: `0` (critical) → `4` (backlog)
|
|
364
103
|
|
|
365
|
-
|
|
104
|
+
## AI Planning Documents
|
|
366
105
|
|
|
367
|
-
|
|
368
|
-
- Session via `req.scope.cradle.session`
|
|
369
|
-
- Full Express `Request` and `Response` objects
|
|
106
|
+
Store in `history/` directory, not repo root.
|
|
370
107
|
|
|
371
|
-
|
|
108
|
+
## AI Tool Preferences
|
|
372
109
|
|
|
373
|
-
|
|
110
|
+
**Codebase exploration** (prefer gkg MCP):
|
|
374
111
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
export const invoicesRouter = {
|
|
382
|
-
create: protectedProcedure.input(createInvoiceSchema).handler(async ({ input, context }) => {
|
|
383
|
-
const { createInvoice } = context.di.cradle as BillingCradle
|
|
384
|
-
return createInvoice(input)
|
|
385
|
-
}),
|
|
386
|
-
}
|
|
387
|
-
```
|
|
112
|
+
- `mcp__gkg__search_codebase_definitions` - Find functions, classes, interfaces by name
|
|
113
|
+
- `mcp__gkg__get_definition` - Jump to definition from a line of code
|
|
114
|
+
- `mcp__gkg__get_references` - Find all usages of a symbol
|
|
115
|
+
- `mcp__gkg__read_definitions` - Read multiple definition bodies efficiently
|
|
116
|
+
- `mcp__gkg__repo_map` - Get API-style map of directories
|
|
388
117
|
|
|
389
|
-
|
|
118
|
+
**Web/code search & documentation** (prefer Docker Toolkit MCP over built-in):
|
|
390
119
|
|
|
391
|
-
|
|
120
|
+
- `mcp__MCP_DOCKER__web_search_exa` - Real-time web search with content scraping
|
|
121
|
+
- `mcp__MCP_DOCKER__resolve-library-id` - Resolve library name to Context7 ID (call first)
|
|
122
|
+
- `mcp__MCP_DOCKER__get-library-docs` - Fetch up-to-date library documentation from Context7
|
|
392
123
|
|
|
393
|
-
|
|
394
|
-
2. Create use case in `usecases/`
|
|
395
|
-
3. Add to router in `api/`
|
|
124
|
+
**File editing** (prefer morph MCP):
|
|
396
125
|
|
|
397
|
-
|
|
126
|
+
- `mcp__morph_mcp__edit_file` - Fast, accurate edits using `// ... existing code ...` placeholders
|
|
127
|
+
- `mcp__morph_mcp__warpgrep_codebase_search` - **Prefer over built-in Grep** for semantic-aware, faster searches with better context
|
|
398
128
|
|
|
399
|
-
|
|
400
|
-
2. Run `bun run db:generate`
|
|
401
|
-
3. Run `bun run db:migrate`
|
|
129
|
+
**Frontend UI** (use `frontend-design` skill + shadcn MCP - do NOT create custom UI components):
|
|
402
130
|
|
|
403
|
-
|
|
131
|
+
- Load the `frontend-design` skill for distinctive, production-grade interfaces
|
|
132
|
+
- `mcp__shadcn__search_items_in_registries` - Find components by name
|
|
133
|
+
- `mcp__shadcn__view_items_in_registries` - View component details and files
|
|
134
|
+
- `mcp__shadcn__get_item_examples_from_registries` - Get usage examples/demos
|
|
135
|
+
- `mcp__shadcn__get_add_command_for_items` - Get CLI command to add components
|
|
404
136
|
|
|
405
|
-
|
|
406
|
-
import { protectedProcedure } from '@kuckit/api'
|
|
407
|
-
|
|
408
|
-
export const myRouter = {
|
|
409
|
-
protectedRoute: protectedProcedure.input(mySchema).handler(async ({ input, context }) => {
|
|
410
|
-
const { user } = context // Authenticated user
|
|
411
|
-
// ...
|
|
412
|
-
}),
|
|
413
|
-
}
|
|
414
|
-
```
|
|
137
|
+
<!-- MCP_AGENT_MAIL_AND_BEADS_SNIPPET_START -->
|
|
415
138
|
|
|
416
|
-
##
|
|
139
|
+
## MCP Agent Mail: coordination for multi-agent workflows
|
|
417
140
|
|
|
418
|
-
|
|
419
|
-
| ---------------------- | -------------------------------------- |
|
|
420
|
-
| `bun run dev` | Start all dev servers |
|
|
421
|
-
| `bun run build` | Build all packages |
|
|
422
|
-
| `bun run check-types` | Type check all packages |
|
|
423
|
-
| `bun run lint` | Run ESLint on all packages |
|
|
424
|
-
| `bun run lint:fix` | Fix ESLint issues automatically |
|
|
425
|
-
| `bun run format` | Format code with Prettier |
|
|
426
|
-
| `bun run format:check` | Check formatting without changes |
|
|
427
|
-
| `bun run db:generate` | Generate migration from schema changes |
|
|
428
|
-
| `bun run db:migrate` | Apply pending migrations |
|
|
429
|
-
| `bun run db:studio` | Open Drizzle Studio |
|
|
141
|
+
What it is
|
|
430
142
|
|
|
431
|
-
|
|
143
|
+
- A mail-like layer that lets coding agents coordinate asynchronously via MCP tools and resources.
|
|
144
|
+
- Provides identities, inbox/outbox, searchable threads, and advisory file reservations, with human-auditable artifacts in Git.
|
|
432
145
|
|
|
433
|
-
|
|
146
|
+
Why it's useful
|
|
434
147
|
|
|
435
|
-
-
|
|
436
|
-
-
|
|
437
|
-
-
|
|
438
|
-
- **lint-staged** - Run linters on staged files only
|
|
148
|
+
- Prevents agents from stepping on each other with explicit file reservations (leases) for files/globs.
|
|
149
|
+
- Keeps communication out of your token budget by storing messages in a per-project archive.
|
|
150
|
+
- Offers quick reads (`resource://inbox/...`, `resource://thread/...`) and macros that bundle common flows.
|
|
439
151
|
|
|
440
|
-
|
|
152
|
+
How to use effectively
|
|
441
153
|
|
|
442
|
-
1.
|
|
443
|
-
|
|
154
|
+
1. Same repository
|
|
155
|
+
- Register an identity: call `ensure_project`, then `register_agent` using this repo's absolute path as `project_key`.
|
|
156
|
+
- Reserve files before you edit: `file_reservation_paths(project_key, agent_name, ["src/**"], ttl_seconds=3600, exclusive=true)` to signal intent and avoid conflict.
|
|
157
|
+
- Communicate with threads: use `send_message(..., thread_id="FEAT-123")`; check inbox with `fetch_inbox` and acknowledge with `acknowledge_message`.
|
|
158
|
+
- Read fast: `resource://inbox/{Agent}?project=<abs-path>&limit=20` or `resource://thread/{id}?project=<abs-path>&include_bodies=true`.
|
|
159
|
+
- Tip: set `AGENT_NAME` in your environment so the pre-commit guard can block commits that conflict with others' active exclusive file reservations.
|
|
444
160
|
|
|
445
|
-
|
|
161
|
+
2. Across different repos in one project (e.g., Next.js frontend + FastAPI backend)
|
|
162
|
+
- Option A (single project bus): register both sides under the same `project_key` (shared key/path). Keep reservation patterns specific (e.g., `frontend/**` vs `backend/**`).
|
|
163
|
+
- Option B (separate projects): each repo has its own `project_key`; use `macro_contact_handshake` or `request_contact`/`respond_contact` to link agents, then message directly. Keep a shared `thread_id` (e.g., ticket key) across repos for clean summaries/audits.
|
|
446
164
|
|
|
447
|
-
|
|
165
|
+
Macros vs granular tools
|
|
448
166
|
|
|
449
|
-
|
|
167
|
+
- Prefer macros when you want speed or are on a smaller model: `macro_start_session`, `macro_prepare_thread`, `macro_file_reservation_cycle`, `macro_contact_handshake`.
|
|
168
|
+
- Use granular tools when you need control: `register_agent`, `file_reservation_paths`, `send_message`, `fetch_inbox`, `acknowledge_message`.
|
|
450
169
|
|
|
451
|
-
|
|
452
|
-
- `BETTER_AUTH_SECRET` - Auth session secret
|
|
453
|
-
- `BETTER_AUTH_URL` - Auth callback URL
|
|
454
|
-
- `PORT` - Server port (default: 3000)
|
|
455
|
-
- `VITE_SERVER_URL` - API URL for frontend
|
|
170
|
+
Common pitfalls
|
|
456
171
|
|
|
457
|
-
|
|
172
|
+
- "from_agent not registered": always `register_agent` in the correct `project_key` first.
|
|
173
|
+
- "FILE_RESERVATION_CONFLICT": adjust patterns, wait for expiry, or use a non-exclusive reservation when appropriate.
|
|
174
|
+
- Auth errors: if JWT+JWKS is enabled, include a bearer token with a `kid` that matches server JWKS; static bearer is used only when JWT is disabled.
|
|
458
175
|
|
|
459
|
-
|
|
176
|
+
## Integrating with Beads (dependency-aware task planning)
|
|
460
177
|
|
|
461
|
-
|
|
178
|
+
Beads provides a lightweight, dependency-aware issue database and a CLI (`bd`) for selecting "ready work," setting priorities, and tracking status. It complements MCP Agent Mail's messaging, audit trail, and file-reservation signals. Project: [steveyegge/beads](https://github.com/steveyegge/beads)
|
|
462
179
|
|
|
463
|
-
|
|
180
|
+
Recommended conventions
|
|
464
181
|
|
|
465
|
-
**
|
|
182
|
+
- **Single source of truth**: Use **Beads** for task status/priority/dependencies; use **Agent Mail** for conversation, decisions, and attachments (audit).
|
|
183
|
+
- **Shared identifiers**: Use the Beads issue id (e.g., `bd-123`) as the Mail `thread_id` and prefix message subjects with `[bd-123]`.
|
|
184
|
+
- **Reservations**: When starting a `bd-###` task, call `file_reservation_paths(...)` for the affected paths; include the issue id in the `reason` and release on completion.
|
|
466
185
|
|
|
467
|
-
|
|
468
|
-
- `apps/web/src/modules.client.ts` - Client modules
|
|
186
|
+
Typical flow (agents)
|
|
469
187
|
|
|
470
|
-
**
|
|
188
|
+
1. **Pick ready work** (Beads)
|
|
189
|
+
- `bd ready --json` → choose one item (highest priority, no blockers)
|
|
190
|
+
2. **Reserve edit surface** (Mail)
|
|
191
|
+
- `file_reservation_paths(project_key, agent_name, ["src/**"], ttl_seconds=3600, exclusive=true, reason="bd-123")`
|
|
192
|
+
3. **Announce start** (Mail)
|
|
193
|
+
- `send_message(..., thread_id="bd-123", subject="[bd-123] Start: <short title>", ack_required=true)`
|
|
194
|
+
4. **Work and update**
|
|
195
|
+
- Reply in-thread with progress and attach artifacts/images; keep the discussion in one thread per issue id
|
|
196
|
+
5. **Complete and release**
|
|
197
|
+
- `bd close bd-123 --reason "Completed"` (Beads is status authority)
|
|
198
|
+
- `release_file_reservations(project_key, agent_name, paths=["src/**"])`
|
|
199
|
+
- Final Mail reply: `[bd-123] Completed` with summary and links
|
|
471
200
|
|
|
472
|
-
|
|
201
|
+
Mapping cheat-sheet
|
|
473
202
|
|
|
474
|
-
**
|
|
203
|
+
- **Mail `thread_id`** ↔ `bd-###`
|
|
204
|
+
- **Mail subject**: `[bd-###] …`
|
|
205
|
+
- **File reservation `reason`**: `bd-###`
|
|
206
|
+
- **Commit messages (optional)**: include `bd-###` for traceability
|
|
475
207
|
|
|
476
|
-
|
|
208
|
+
Event mirroring (optional automation)
|
|
477
209
|
|
|
478
|
-
|
|
210
|
+
- On `bd update --status blocked`, send a high-importance Mail message in thread `bd-###` describing the blocker.
|
|
211
|
+
- On Mail "ACK overdue" for a critical decision, add a Beads label (e.g., `needs-ack`) or bump priority to surface it in `bd ready`.
|
|
479
212
|
|
|
480
|
-
|
|
481
|
-
schema: [
|
|
482
|
-
'./node_modules/@kuckit/db/dist/schema/auth.js',
|
|
483
|
-
'./packages/your-module/src/adapters',
|
|
484
|
-
],
|
|
485
|
-
```
|
|
213
|
+
Pitfalls to avoid
|
|
486
214
|
|
|
487
|
-
|
|
215
|
+
- Don't create or manage tasks in Mail; treat Beads as the single task queue.
|
|
216
|
+
- Always include `bd-###` in message `thread_id` to avoid ID drift across tools.
|
|
488
217
|
|
|
489
|
-
|
|
490
|
-
bun run db:generate
|
|
491
|
-
bun run db:migrate
|
|
492
|
-
```
|
|
218
|
+
<!-- MCP_AGENT_MAIL_AND_BEADS_SNIPPET_END -->
|
|
493
219
|
|
|
494
|
-
|
|
220
|
+
## Landing the Plane (Session Completion)
|
|
495
221
|
|
|
496
|
-
**
|
|
222
|
+
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
|
|
497
223
|
|
|
498
|
-
**
|
|
224
|
+
**MANDATORY WORKFLOW:**
|
|
499
225
|
|
|
500
|
-
**
|
|
226
|
+
1. **File issues for remaining work** - Create issues for anything that needs follow-up
|
|
227
|
+
2. **Run quality gates** (if code changed) - Tests, linters, builds
|
|
228
|
+
3. **Update issue status** - Close finished work, update in-progress items
|
|
229
|
+
4. **PUSH TO REMOTE** - This is MANDATORY:
|
|
230
|
+
```bash
|
|
231
|
+
git pull --rebase
|
|
232
|
+
bd sync
|
|
233
|
+
git push
|
|
234
|
+
git status # MUST show "up to date with origin"
|
|
235
|
+
```
|
|
236
|
+
5. **Clean up** - Clear stashes, prune remote branches
|
|
237
|
+
6. **Verify** - All changes committed AND pushed
|
|
238
|
+
7. **Hand off** - Provide context for next session
|
|
501
239
|
|
|
502
|
-
|
|
240
|
+
**CRITICAL RULES:**
|
|
503
241
|
|
|
504
|
-
-
|
|
505
|
-
-
|
|
506
|
-
-
|
|
507
|
-
-
|
|
508
|
-
- [TanStack Router](https://tanstack.com/router)
|
|
242
|
+
- Work is NOT complete until `git push` succeeds
|
|
243
|
+
- NEVER stop before pushing - that leaves work stranded locally
|
|
244
|
+
- NEVER say "ready to push when you are" - YOU must push
|
|
245
|
+
- If push fails, resolve and retry until it succeeds
|