axiom-coding-agent-setup 1.0.0 → 1.0.2
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/.agents/skills/ai-integration/SKILL.md +314 -0
- package/.agents/skills/deployment-patterns/SKILL.md +408 -0
- package/.agents/skills/fastapi-templates/SKILL.md +540 -0
- package/.agents/skills/git-commit/SKILL.md +124 -0
- package/.agents/skills/mcp-builder/SKILL.md +292 -0
- package/.agents/skills/n8n-patterns/SKILL.md +272 -0
- package/.agents/templates/ai-engineering-python.md +508 -0
- package/.agents/templates/fullstack-ai-nextjs.md +632 -0
- package/AGENTS.md +5 -3
- package/README.md +20 -6
- package/bin/cli.js +21 -9
- package/package.json +2 -2
- package/skills-lock.json +15 -0
- /package/{.axiom → .agents}/engineering.md +0 -0
- /package/{.axiom → .agents}/stack.md +0 -0
- /package/{.axiom → .agents}/workflow.md +0 -0
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
# Full Stack AI App with Next.js — Project Conventions
|
|
2
|
+
|
|
3
|
+
Context template for full-stack AI applications using Next.js, React, and modern AI SDKs.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Core Stack
|
|
8
|
+
|
|
9
|
+
### Frontend
|
|
10
|
+
- **Next.js 15** — App Router, Server Components, streaming
|
|
11
|
+
- **React 19** — Server Actions, improved hooks
|
|
12
|
+
- **TypeScript** — Strict mode, no `any`
|
|
13
|
+
- **Tailwind CSS v4** — Utility-first styling
|
|
14
|
+
- **shadcn/ui** — Accessible, composable components
|
|
15
|
+
|
|
16
|
+
### State Management
|
|
17
|
+
- **Zustand** — Client state (auth, UI)
|
|
18
|
+
- **TanStack Query v5** — Server state, caching
|
|
19
|
+
- **Vercel AI SDK** — Streaming chat/AI state
|
|
20
|
+
|
|
21
|
+
### AI/LLM Integration
|
|
22
|
+
- **Vercel AI SDK** — Unified interface for multiple providers
|
|
23
|
+
- **LangChain.js** — Complex orchestration when needed
|
|
24
|
+
- **OpenAI SDK / Anthropic SDK** — Direct provider access
|
|
25
|
+
|
|
26
|
+
### Backend
|
|
27
|
+
- **Next.js API Routes** — Serverless endpoints
|
|
28
|
+
- **Server Actions** — Mutations and data fetching
|
|
29
|
+
- **Prisma** — Type-safe database access
|
|
30
|
+
- **NextAuth.js v5** — Authentication
|
|
31
|
+
|
|
32
|
+
### Database
|
|
33
|
+
- **PostgreSQL** — Primary database
|
|
34
|
+
- **pgvector** — Vector embeddings storage
|
|
35
|
+
- **Redis** — Caching, rate limiting
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Project Structure
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
project-root/
|
|
43
|
+
├── src/
|
|
44
|
+
│ ├── app/ # Next.js App Router
|
|
45
|
+
│ │ ├── (auth)/ # Auth route group
|
|
46
|
+
│ │ │ ├── login/
|
|
47
|
+
│ │ │ ├── register/
|
|
48
|
+
│ │ │ └── layout.tsx # Auth layout
|
|
49
|
+
│ │ ├── (main)/ # Main app route group
|
|
50
|
+
│ │ │ ├── chat/ # AI chat interface
|
|
51
|
+
│ │ │ ├── documents/ # Document management
|
|
52
|
+
│ │ │ ├── settings/
|
|
53
|
+
│ │ │ └── layout.tsx # Main app layout
|
|
54
|
+
│ │ ├── api/ # API routes
|
|
55
|
+
│ │ │ ├── chat/ # Chat API endpoints
|
|
56
|
+
│ │ │ │ └── route.ts # Streaming endpoint
|
|
57
|
+
│ │ │ ├── documents/ # Document CRUD
|
|
58
|
+
│ │ │ └── auth/[...nextauth]/
|
|
59
|
+
│ │ ├── layout.tsx # Root layout
|
|
60
|
+
│ │ ├── page.tsx # Landing/home
|
|
61
|
+
│ │ ├── loading.tsx # Loading UI
|
|
62
|
+
│ │ ├── error.tsx # Error handling
|
|
63
|
+
│ │ └── globals.css # Global styles + CSS vars
|
|
64
|
+
│ ├── components/
|
|
65
|
+
│ │ ├── ui/ # shadcn/ui primitives
|
|
66
|
+
│ │ │ ├── button.tsx
|
|
67
|
+
│ │ │ ├── card.tsx
|
|
68
|
+
│ │ │ ├── input.tsx
|
|
69
|
+
│ │ │ └── ...
|
|
70
|
+
│ │ ├── chat/ # Chat-specific components
|
|
71
|
+
│ │ │ ├── ChatInput.tsx
|
|
72
|
+
│ │ │ ├── ChatMessage.tsx
|
|
73
|
+
│ │ │ ├── ChatList.tsx
|
|
74
|
+
│ │ │ └── StreamingText.tsx
|
|
75
|
+
│ │ ├── layout/ # Layout components
|
|
76
|
+
│ │ │ ├── Header.tsx
|
|
77
|
+
│ │ │ ├── Sidebar.tsx
|
|
78
|
+
│ │ │ └── Footer.tsx
|
|
79
|
+
│ │ └── providers/ # Context providers
|
|
80
|
+
│ │ ├── AIProvider.tsx
|
|
81
|
+
│ │ └── QueryProvider.tsx
|
|
82
|
+
│ ├── lib/
|
|
83
|
+
│ │ ├── ai/ # AI configuration
|
|
84
|
+
│ │ │ ├── config.ts # AI providers config
|
|
85
|
+
│ │ │ ├── prompts.ts # System prompts
|
|
86
|
+
│ │ │ └── tools.ts # AI tools/functions
|
|
87
|
+
│ │ ├── db/ # Database
|
|
88
|
+
│ │ │ ├── prisma.ts # Prisma client
|
|
89
|
+
│ │ │ └── schema.prisma # Database schema
|
|
90
|
+
│ │ ├── auth.ts # NextAuth config
|
|
91
|
+
│ │ ├── utils.ts # Utility functions
|
|
92
|
+
│ │ └── constants.ts # App constants
|
|
93
|
+
│ ├── hooks/
|
|
94
|
+
│ │ ├── use-chat.ts # Chat state hook
|
|
95
|
+
│ │ ├── use-documents.ts # Documents data hook
|
|
96
|
+
│ │ └── use-user.ts # User data hook
|
|
97
|
+
│ ├── stores/ # Zustand stores
|
|
98
|
+
│ │ ├── chat-store.ts
|
|
99
|
+
│ │ └── ui-store.ts
|
|
100
|
+
│ ├── actions/ # Server Actions
|
|
101
|
+
│ │ ├── chat-actions.ts
|
|
102
|
+
│ │ ├── document-actions.ts
|
|
103
|
+
│ │ └── user-actions.ts
|
|
104
|
+
│ └── types/
|
|
105
|
+
│ ├── chat.ts
|
|
106
|
+
│ ├── document.ts
|
|
107
|
+
│ └── api.ts
|
|
108
|
+
├── public/ # Static assets
|
|
109
|
+
├── prisma/
|
|
110
|
+
│ └── schema.prisma # Database schema
|
|
111
|
+
├── scripts/
|
|
112
|
+
│ └── seed.ts # Database seeding
|
|
113
|
+
├── components.json # shadcn/ui config
|
|
114
|
+
├── next.config.js
|
|
115
|
+
├── tailwind.config.ts
|
|
116
|
+
├── tsconfig.json
|
|
117
|
+
└── package.json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Development Guidelines
|
|
123
|
+
|
|
124
|
+
### Server Components vs Client Components
|
|
125
|
+
|
|
126
|
+
**Use Server Components by default:**
|
|
127
|
+
- Data fetching pages
|
|
128
|
+
- Static content
|
|
129
|
+
- SEO-critical content
|
|
130
|
+
- Database queries via Prisma
|
|
131
|
+
|
|
132
|
+
**Use Client Components sparingly:**
|
|
133
|
+
```tsx
|
|
134
|
+
"use client"
|
|
135
|
+
|
|
136
|
+
// - Interactive UI (buttons, forms)
|
|
137
|
+
// - Browser APIs (localStorage, clipboard)
|
|
138
|
+
// - Real-time features (WebSocket)
|
|
139
|
+
// - Third-party JS libraries
|
|
140
|
+
// - Hooks that need browser context
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Vercel AI SDK Pattern
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
// src/lib/ai/config.ts
|
|
147
|
+
import { createOpenAI } from '@ai-sdk/openai';
|
|
148
|
+
import { createAnthropic } from '@ai-sdk/anthropic';
|
|
149
|
+
|
|
150
|
+
export const openai = createOpenAI({
|
|
151
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
export const anthropic = createAnthropic({
|
|
155
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
// src/app/api/chat/route.ts
|
|
161
|
+
import { streamText } from 'ai';
|
|
162
|
+
import { openai } from '@/lib/ai/config';
|
|
163
|
+
|
|
164
|
+
export async function POST(req: Request) {
|
|
165
|
+
const { messages } = await req.json();
|
|
166
|
+
|
|
167
|
+
const result = streamText({
|
|
168
|
+
model: openai('gpt-4'),
|
|
169
|
+
messages,
|
|
170
|
+
system: "You are a helpful AI assistant.",
|
|
171
|
+
tools: {
|
|
172
|
+
// Define tools here
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
return result.toDataStreamResponse();
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
// src/components/chat/ChatInput.tsx
|
|
182
|
+
"use client"
|
|
183
|
+
|
|
184
|
+
import { useChat } from 'ai/react';
|
|
185
|
+
|
|
186
|
+
export function ChatInput() {
|
|
187
|
+
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<div className="flex flex-col h-full">
|
|
191
|
+
<div className="flex-1 overflow-auto">
|
|
192
|
+
{messages.map(m => (
|
|
193
|
+
<div key={m.id} className={m.role === 'user' ? 'user' : 'assistant'}>
|
|
194
|
+
{m.content}
|
|
195
|
+
</div>
|
|
196
|
+
))}
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<form onSubmit={handleSubmit}>
|
|
200
|
+
<input
|
|
201
|
+
value={input}
|
|
202
|
+
onChange={handleInputChange}
|
|
203
|
+
placeholder="Type a message..."
|
|
204
|
+
disabled={isLoading}
|
|
205
|
+
/>
|
|
206
|
+
<button type="submit" disabled={isLoading}>
|
|
207
|
+
Send
|
|
208
|
+
</button>
|
|
209
|
+
</form>
|
|
210
|
+
</div>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Server Actions Pattern
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
// src/actions/chat-actions.ts
|
|
219
|
+
"use server"
|
|
220
|
+
|
|
221
|
+
import { revalidatePath } from "next/cache";
|
|
222
|
+
import { prisma } from "@/lib/db/prisma";
|
|
223
|
+
|
|
224
|
+
export async function saveConversation(
|
|
225
|
+
userId: string,
|
|
226
|
+
messages: Array<{ role: string; content: string }>
|
|
227
|
+
) {
|
|
228
|
+
try {
|
|
229
|
+
const conversation = await prisma.conversation.create({
|
|
230
|
+
data: {
|
|
231
|
+
userId,
|
|
232
|
+
messages: {
|
|
233
|
+
create: messages.map((m, index) => ({
|
|
234
|
+
role: m.role,
|
|
235
|
+
content: m.content,
|
|
236
|
+
order: index,
|
|
237
|
+
})),
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
revalidatePath("/chat");
|
|
243
|
+
return { success: true, conversation };
|
|
244
|
+
} catch (error) {
|
|
245
|
+
return { success: false, error: "Failed to save conversation" };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### TanStack Query Pattern
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
// src/hooks/use-documents.ts
|
|
254
|
+
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
255
|
+
|
|
256
|
+
export function useDocuments() {
|
|
257
|
+
return useQuery({
|
|
258
|
+
queryKey: ["documents"],
|
|
259
|
+
queryFn: async () => {
|
|
260
|
+
const res = await fetch("/api/documents");
|
|
261
|
+
if (!res.ok) throw new Error("Failed to fetch documents");
|
|
262
|
+
return res.json();
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function useCreateDocument() {
|
|
268
|
+
const queryClient = useQueryClient();
|
|
269
|
+
|
|
270
|
+
return useMutation({
|
|
271
|
+
mutationFn: async (document: CreateDocumentInput) => {
|
|
272
|
+
const res = await fetch("/api/documents", {
|
|
273
|
+
method: "POST",
|
|
274
|
+
headers: { "Content-Type": "application/json" },
|
|
275
|
+
body: JSON.stringify(document),
|
|
276
|
+
});
|
|
277
|
+
if (!res.ok) throw new Error("Failed to create document");
|
|
278
|
+
return res.json();
|
|
279
|
+
},
|
|
280
|
+
onSuccess: () => {
|
|
281
|
+
queryClient.invalidateQueries({ queryKey: ["documents"] });
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Zustand Store Pattern
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
// src/stores/chat-store.ts
|
|
291
|
+
import { create } from "zustand";
|
|
292
|
+
import { persist } from "zustand/middleware";
|
|
293
|
+
|
|
294
|
+
interface ChatState {
|
|
295
|
+
selectedModel: string;
|
|
296
|
+
temperature: number;
|
|
297
|
+
setModel: (model: string) => void;
|
|
298
|
+
setTemperature: (temp: number) => void;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export const useChatStore = create<ChatState>()(
|
|
302
|
+
persist(
|
|
303
|
+
(set) => ({
|
|
304
|
+
selectedModel: "gpt-4",
|
|
305
|
+
temperature: 0.7,
|
|
306
|
+
setModel: (model) => set({ selectedModel: model }),
|
|
307
|
+
setTemperature: (temp) => set({ temperature: temp }),
|
|
308
|
+
}),
|
|
309
|
+
{ name: "chat-settings" }
|
|
310
|
+
)
|
|
311
|
+
);
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Database Schema (Prisma)
|
|
317
|
+
|
|
318
|
+
```prisma
|
|
319
|
+
// prisma/schema.prisma
|
|
320
|
+
|
|
321
|
+
generator client {
|
|
322
|
+
provider = "prisma-client-js"
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
datasource db {
|
|
326
|
+
provider = "postgresql"
|
|
327
|
+
url = env("DATABASE_URL")
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
model Account {
|
|
331
|
+
id String @id @default(cuid())
|
|
332
|
+
userId String
|
|
333
|
+
type String
|
|
334
|
+
provider String
|
|
335
|
+
providerAccountId String
|
|
336
|
+
refresh_token String? @db.Text
|
|
337
|
+
access_token String? @db.Text
|
|
338
|
+
expires_at Int?
|
|
339
|
+
token_type String?
|
|
340
|
+
scope String?
|
|
341
|
+
id_token String? @db.Text
|
|
342
|
+
session_state String?
|
|
343
|
+
|
|
344
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
345
|
+
|
|
346
|
+
@@unique([provider, providerAccountId])
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
model User {
|
|
350
|
+
id String @id @default(cuid())
|
|
351
|
+
email String @unique
|
|
352
|
+
name String?
|
|
353
|
+
image String?
|
|
354
|
+
emailVerified DateTime?
|
|
355
|
+
accounts Account[]
|
|
356
|
+
conversations Conversation[]
|
|
357
|
+
documents Document[]
|
|
358
|
+
createdAt DateTime @default(now())
|
|
359
|
+
updatedAt DateTime @updatedAt
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
model Conversation {
|
|
363
|
+
id String @id @default(cuid())
|
|
364
|
+
title String?
|
|
365
|
+
userId String
|
|
366
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
367
|
+
messages Message[]
|
|
368
|
+
createdAt DateTime @default(now())
|
|
369
|
+
updatedAt DateTime @updatedAt
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
model Message {
|
|
373
|
+
id String @id @default(cuid())
|
|
374
|
+
role String // user, assistant, system
|
|
375
|
+
content String @db.Text
|
|
376
|
+
conversationId String
|
|
377
|
+
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
378
|
+
createdAt DateTime @default(now())
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
model Document {
|
|
382
|
+
id String @id @default(cuid())
|
|
383
|
+
title String
|
|
384
|
+
content String @db.Text
|
|
385
|
+
embedding Unsupported("vector(1536)")?
|
|
386
|
+
userId String
|
|
387
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
388
|
+
createdAt DateTime @default(now())
|
|
389
|
+
updatedAt DateTime @updatedAt
|
|
390
|
+
|
|
391
|
+
@@index([userId])
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## AI Tools/Functions Pattern
|
|
398
|
+
|
|
399
|
+
```tsx
|
|
400
|
+
// src/lib/ai/tools.ts
|
|
401
|
+
import { tool } from "ai";
|
|
402
|
+
import { z } from "zod";
|
|
403
|
+
import { prisma } from "@/lib/db/prisma";
|
|
404
|
+
|
|
405
|
+
export const searchDocuments = tool({
|
|
406
|
+
description: "Search user's documents for relevant information",
|
|
407
|
+
parameters: z.object({
|
|
408
|
+
query: z.string().describe("The search query"),
|
|
409
|
+
}),
|
|
410
|
+
execute: async ({ query }) => {
|
|
411
|
+
// Implement vector search or full-text search
|
|
412
|
+
const documents = await prisma.document.findMany({
|
|
413
|
+
where: {
|
|
414
|
+
OR: [
|
|
415
|
+
{ title: { contains: query, mode: "insensitive" } },
|
|
416
|
+
{ content: { contains: query, mode: "insensitive" } },
|
|
417
|
+
],
|
|
418
|
+
},
|
|
419
|
+
take: 5,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
return documents.map(d => ({
|
|
423
|
+
title: d.title,
|
|
424
|
+
content: d.content.substring(0, 500),
|
|
425
|
+
}));
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
export const saveToConversation = tool({
|
|
430
|
+
description: "Save important information to the conversation",
|
|
431
|
+
parameters: z.object({
|
|
432
|
+
summary: z.string().describe("Summary of the information"),
|
|
433
|
+
}),
|
|
434
|
+
execute: async ({ summary }) => {
|
|
435
|
+
// Implementation
|
|
436
|
+
return { saved: true, summary };
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## Component Patterns
|
|
444
|
+
|
|
445
|
+
### shadcn/ui Component Usage
|
|
446
|
+
|
|
447
|
+
```tsx
|
|
448
|
+
// Example: Building a form with shadcn/ui
|
|
449
|
+
import { Button } from "@/components/ui/button";
|
|
450
|
+
import { Input } from "@/components/ui/input";
|
|
451
|
+
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
|
452
|
+
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form";
|
|
453
|
+
|
|
454
|
+
export function DocumentForm() {
|
|
455
|
+
const form = useForm<CreateDocumentInput>({
|
|
456
|
+
resolver: zodResolver(createDocumentSchema),
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
return (
|
|
460
|
+
<Card>
|
|
461
|
+
<CardHeader>
|
|
462
|
+
<CardTitle>Create Document</CardTitle>
|
|
463
|
+
</CardHeader>
|
|
464
|
+
<CardContent>
|
|
465
|
+
<Form {...form}>
|
|
466
|
+
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
467
|
+
<FormField
|
|
468
|
+
control={form.control}
|
|
469
|
+
name="title"
|
|
470
|
+
render={({ field }) => (
|
|
471
|
+
<FormItem>
|
|
472
|
+
<FormLabel>Title</FormLabel>
|
|
473
|
+
<FormControl>
|
|
474
|
+
<Input {...field} />
|
|
475
|
+
</FormControl>
|
|
476
|
+
<FormMessage />
|
|
477
|
+
</FormItem>
|
|
478
|
+
)}
|
|
479
|
+
/>
|
|
480
|
+
<Button type="submit">Create</Button>
|
|
481
|
+
</form>
|
|
482
|
+
</Form>
|
|
483
|
+
</CardContent>
|
|
484
|
+
</Card>
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Loading States
|
|
490
|
+
|
|
491
|
+
```tsx
|
|
492
|
+
// src/app/chat/loading.tsx
|
|
493
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
494
|
+
|
|
495
|
+
export default function ChatLoading() {
|
|
496
|
+
return (
|
|
497
|
+
<div className="space-y-4">
|
|
498
|
+
<Skeleton className="h-20 w-full" />
|
|
499
|
+
<Skeleton className="h-20 w-full" />
|
|
500
|
+
<Skeleton className="h-20 w-3/4" />
|
|
501
|
+
</div>
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### Error Handling
|
|
507
|
+
|
|
508
|
+
```tsx
|
|
509
|
+
// src/app/chat/error.tsx
|
|
510
|
+
"use client"
|
|
511
|
+
|
|
512
|
+
import { Button } from "@/components/ui/button";
|
|
513
|
+
|
|
514
|
+
export default function ChatError({
|
|
515
|
+
error,
|
|
516
|
+
reset,
|
|
517
|
+
}: {
|
|
518
|
+
error: Error & { digest?: string };
|
|
519
|
+
reset: () => void;
|
|
520
|
+
}) {
|
|
521
|
+
return (
|
|
522
|
+
<div className="flex flex-col items-center justify-center min-h-[400px]">
|
|
523
|
+
<h2 className="text-xl font-bold mb-4">Something went wrong!</h2>
|
|
524
|
+
<p className="text-muted-foreground mb-4">{error.message}</p>
|
|
525
|
+
<Button onClick={reset}>Try again</Button>
|
|
526
|
+
</div>
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## Environment Configuration
|
|
534
|
+
|
|
535
|
+
### .env.local
|
|
536
|
+
|
|
537
|
+
```bash
|
|
538
|
+
# Database
|
|
539
|
+
DATABASE_URL="postgresql://user:password@localhost:5432/aiapp"
|
|
540
|
+
|
|
541
|
+
# NextAuth
|
|
542
|
+
NEXTAUTH_URL="http://localhost:3000"
|
|
543
|
+
NEXTAUTH_SECRET="your-secret-key"
|
|
544
|
+
|
|
545
|
+
# OAuth Providers
|
|
546
|
+
GITHUB_CLIENT_ID=""
|
|
547
|
+
GITHUB_CLIENT_SECRET=""
|
|
548
|
+
GOOGLE_CLIENT_ID=""
|
|
549
|
+
GOOGLE_CLIENT_SECRET=""
|
|
550
|
+
|
|
551
|
+
# AI Providers
|
|
552
|
+
OPENAI_API_KEY=""
|
|
553
|
+
ANTHROPIC_API_KEY=""
|
|
554
|
+
|
|
555
|
+
# Vector Search
|
|
556
|
+
OPENAI_EMBEDDING_MODEL="text-embedding-3-small"
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## Code Quality Standards
|
|
562
|
+
|
|
563
|
+
### TypeScript Configuration
|
|
564
|
+
|
|
565
|
+
```json
|
|
566
|
+
// tsconfig.json
|
|
567
|
+
{
|
|
568
|
+
"compilerOptions": {
|
|
569
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
570
|
+
"allowJs": true,
|
|
571
|
+
"skipLibCheck": true,
|
|
572
|
+
"strict": true,
|
|
573
|
+
"noEmit": true,
|
|
574
|
+
"esModuleInterop": true,
|
|
575
|
+
"module": "esnext",
|
|
576
|
+
"moduleResolution": "bundler",
|
|
577
|
+
"resolveJsonModule": true,
|
|
578
|
+
"isolatedModules": true,
|
|
579
|
+
"jsx": "preserve",
|
|
580
|
+
"incremental": true,
|
|
581
|
+
"plugins": [{ "name": "next" }],
|
|
582
|
+
"paths": {
|
|
583
|
+
"@/*": ["./src/*"]
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
587
|
+
"exclude": ["node_modules"]
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
### ESLint Configuration
|
|
592
|
+
|
|
593
|
+
```json
|
|
594
|
+
// .eslintrc.json
|
|
595
|
+
{
|
|
596
|
+
"extends": ["next/core-web-vitals", "next/typescript"],
|
|
597
|
+
"rules": {
|
|
598
|
+
"@typescript-eslint/no-unused-vars": "error",
|
|
599
|
+
"@typescript-eslint/no-explicit-any": "error"
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### Key Patterns
|
|
605
|
+
|
|
606
|
+
1. **Path Aliases**: Use `@/` for all imports from `src/`
|
|
607
|
+
2. **No `any`**: Strict TypeScript — use `unknown` if type is uncertain
|
|
608
|
+
3. **Named Exports**: Prefer named exports over default exports
|
|
609
|
+
4. **Colocation**: Keep related files close (component + test + styles)
|
|
610
|
+
5. **Server-First**: Start with Server Components, add `"use client"` only when needed
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
614
|
+
## Performance Guidelines
|
|
615
|
+
|
|
616
|
+
### Server Components
|
|
617
|
+
- Fetch data directly in Server Components when possible
|
|
618
|
+
- Use `unstable_cache` for expensive operations
|
|
619
|
+
- Leverage streaming with `loading.tsx`
|
|
620
|
+
|
|
621
|
+
### Client Components
|
|
622
|
+
- Use `React.memo()` for expensive renders
|
|
623
|
+
- Use `useMemo()` and `useCallback()` appropriately
|
|
624
|
+
- Lazy load heavy components with `next/dynamic`
|
|
625
|
+
|
|
626
|
+
### Images
|
|
627
|
+
- Always use `next/image` for optimized images
|
|
628
|
+
- Set appropriate `sizes` prop for responsive images
|
|
629
|
+
|
|
630
|
+
### Fonts
|
|
631
|
+
- Use `next/font` for optimized font loading
|
|
632
|
+
- Preload critical fonts
|
package/AGENTS.md
CHANGED
|
@@ -12,9 +12,11 @@ I write code that survives contact with reality.
|
|
|
12
12
|
|
|
13
13
|
## Core Documents
|
|
14
14
|
|
|
15
|
-
- @/.
|
|
16
|
-
- @/.
|
|
17
|
-
- @/.
|
|
15
|
+
- @/.agents/engineering.md — Principles, decision framework, anti-patterns, code standards
|
|
16
|
+
- @/.agents/stack.md — Technology knowledge: languages, frameworks, infrastructure, AI/ML
|
|
17
|
+
- @/.agents/workflow.md — Work protocol, verification rules, git discipline, communication
|
|
18
|
+
- @/.agents/templates/ — Project-type specific conventions and setup guides
|
|
19
|
+
- @/.agents/skills/ — Domain-specific skills for specialized tasks
|
|
18
20
|
|
|
19
21
|
---
|
|
20
22
|
|
package/README.md
CHANGED
|
@@ -21,16 +21,18 @@ npx axiom-setup
|
|
|
21
21
|
This command downloads the following files from the [axiom-coding-agent-setup](https://github.com/mcikalmerdeka/axiom-coding-agent-setup) repository into your current project directory:
|
|
22
22
|
|
|
23
23
|
- `AGENTS.md` — Main agent instructions
|
|
24
|
-
- `.
|
|
25
|
-
- `.
|
|
26
|
-
- `.
|
|
24
|
+
- `.agents/engineering.md` — Engineering principles & code standards
|
|
25
|
+
- `.agents/stack.md` — Technology stack knowledge
|
|
26
|
+
- `.agents/workflow.md` — Workflow guidelines & verification protocol
|
|
27
|
+
- `.agents/templates/` — Project-type specific conventions
|
|
28
|
+
- `.agents/skills/` — Domain-specific skills for specialized tasks
|
|
27
29
|
|
|
28
30
|
## Files Included
|
|
29
31
|
|
|
30
32
|
### AGENTS.md
|
|
31
33
|
The main instruction file that coding agents (Claude, Cursor, etc.) read first when working on your project.
|
|
32
34
|
|
|
33
|
-
### .
|
|
35
|
+
### .agents/engineering.md
|
|
34
36
|
Core engineering principles including:
|
|
35
37
|
- KISS, YAGNI, DRY principles
|
|
36
38
|
- Decision framework for code reviews
|
|
@@ -38,7 +40,7 @@ Core engineering principles including:
|
|
|
38
40
|
- Anti-patterns to avoid
|
|
39
41
|
- AI-assisted development ground rules
|
|
40
42
|
|
|
41
|
-
### .
|
|
43
|
+
### .agents/stack.md
|
|
42
44
|
Technology stack knowledge covering:
|
|
43
45
|
- Languages (TypeScript, Python, Go, Rust, SQL)
|
|
44
46
|
- Frontend (React, Next.js, Tailwind, shadcn/ui)
|
|
@@ -47,7 +49,7 @@ Technology stack knowledge covering:
|
|
|
47
49
|
- AI/ML stack (LLM APIs, orchestration, observability)
|
|
48
50
|
- Infrastructure & DevOps
|
|
49
51
|
|
|
50
|
-
### .
|
|
52
|
+
### .agents/workflow.md
|
|
51
53
|
Workflow guidelines including:
|
|
52
54
|
- Verification protocol (read files before claiming, test before declaring done)
|
|
53
55
|
- Git discipline
|
|
@@ -55,6 +57,18 @@ Workflow guidelines including:
|
|
|
55
57
|
- Code review stance
|
|
56
58
|
- Context management for agentic sessions
|
|
57
59
|
|
|
60
|
+
### .agents/templates/
|
|
61
|
+
Project-type specific convention files:
|
|
62
|
+
- `ai-engineering-python.md` — FastAPI + AI/ML stack patterns
|
|
63
|
+
- `fullstack-ai-nextjs.md` — Next.js + Vercel AI SDK patterns
|
|
64
|
+
|
|
65
|
+
### .agents/skills/
|
|
66
|
+
Domain-specific skills that can be loaded on-demand:
|
|
67
|
+
- `mcp-builder/` — MCP server development guide
|
|
68
|
+
- `n8n-patterns/` — n8n workflow automation patterns
|
|
69
|
+
- `ai-integration/` — LLM/AI integration patterns
|
|
70
|
+
- `deployment-patterns/` — Deployment and infrastructure guide
|
|
71
|
+
|
|
58
72
|
## Development
|
|
59
73
|
|
|
60
74
|
To test the CLI locally:
|