241 lines
8.0 KiB
Markdown
241 lines
8.0 KiB
Markdown
# AGENTS.md
|
|
|
|
This file contains guidelines and commands for agentic coding agents working in
|
|
the Veridian repository.
|
|
|
|
## Project Overview
|
|
|
|
Veridian is a Nuxt 4 application built with TypeScript, using Triplit with
|
|
better-auth for authentication, and UnoCSS for styling. The app is an agnetic
|
|
chat platform that is meant to provide a well rounded experience for interacting
|
|
with LLMs as well as providing a way to manage agents and provide helpful tools
|
|
like RAG (retrieval augmented generation) and web scraping/search.
|
|
|
|
You should be connected to the Nuxt docs MCP server, if you need to reference
|
|
the documentation or are unsure on how to implement something, consult the
|
|
docs.
|
|
|
|
## Core Commands
|
|
|
|
As an agentic agent, never run the development server yourself.
|
|
Instead, once you have completed your task, end generation and inform me that
|
|
you are done and request a review of your changes. You are allowed to use
|
|
database commands.
|
|
|
|
### Database Commands
|
|
|
|
- `bunx triplit schema push` - Push schema changes to database
|
|
|
|
## Tech Stack & Dependencies
|
|
|
|
- **Framework**: Nuxt 4 (SSR enabled)
|
|
- **Language**: TypeScript with strict configuration
|
|
- **Database**: Triplit (next generation fullstack syncing database, sort of
|
|
like convex)
|
|
- **Auth**: better-auth with email/password and social providers
|
|
- **Styling**: UnoCSS with presetMini
|
|
- **Icons**: @nuxt/icon with Iconify, use Myna UI Icons
|
|
|
|
## Code Style Guidelines
|
|
|
|
**Follow the LLVM golden rule: If you are extending, enhancing, or bug fixing
|
|
already implemented code, use the style that is already being used so that
|
|
the source is uniform and easy to follow.**
|
|
|
|
- **Always end lines with a semicolon regardless of surrounding code**
|
|
- Use 4 spaces for indentation
|
|
- Use consistent naming conventions for variables, functions, and constants
|
|
- Always use strict equality checks (`===` and `!==`) instead of loose equality
|
|
checks (`==` and `!=`)
|
|
- Prefer using explicity equality checks over truthy/falsy checks
|
|
e.g., prefer `if (value !== null)` instead of `if (value)`
|
|
- Always check existing code patterns before implementing new features
|
|
- Follow existing component and composable structures
|
|
- Use proper TypeScript types for all function parameters and returns
|
|
- Implement proper cleanup in composables (e.g., useClickOutside)
|
|
- Prefer reactive state management over direct DOM manipulation
|
|
- Keep components focused and single-purpose
|
|
- Use semantic HTML elements where appropriate
|
|
|
|
### General Structure
|
|
|
|
- Use Nuxt's app directory structure (`app/`, `server/`, `lib/`)
|
|
- Auth configuration in `lib/auth.ts`
|
|
- Server API routes go in `server/api/`
|
|
- Composables go in `app/composables/`
|
|
- Database schema in `db/schema.ts`
|
|
- Database migrations in `db/migrations/`
|
|
|
|
### TypeScript Guidelines
|
|
|
|
- Use strict TypeScript with no implicit any
|
|
- Export types and interfaces explicitly
|
|
- Use `computed()` and `ref()` from Vue 3 reactivity system
|
|
- Type API responses and database models
|
|
|
|
### Vue Components
|
|
|
|
- **Never use self-closing tags, excluding images, br, hr, and input**
|
|
- Use `<script setup lang="ts">` syntax
|
|
- Strongly prefer composition API over options API
|
|
- Prefer composables for shared state management
|
|
- Maintain consistent 4-space indentation
|
|
- Use PascalCase for component file names
|
|
|
|
### CSS/Styling
|
|
|
|
- Use UnoCSS utility classes exclusively
|
|
- Never use margin for spacing, always prefer flexbox or grid
|
|
- Prefer inline utility classes over custom CSS
|
|
- Use semantic color variables: `--color-base`, `--color-neutral`, `--color-accent`, `--color-subtle`
|
|
If you need to add new color variables, they are located in `app/assets/css/base.css`,
|
|
along with a general CSS reset.
|
|
- Apply consistent spacing and layout patterns
|
|
- Use responsive prefixes only when necessary
|
|
|
|
### Imports
|
|
|
|
- Order imports: Vue/Nuxt imports first, then local files, then dependencies
|
|
- `~/` is an alias for `app/` and `~~/` is an alias for the root of the project
|
|
- Avoid wildcard imports
|
|
- Keep imports sorted alphabetically within groups
|
|
|
|
### Naming Conventions
|
|
|
|
- **Page**: camelCase
|
|
- **Composables**: camelCase
|
|
- **Components**: PascalCase when referenced in templates
|
|
- **Functions/Variables**: camelCase
|
|
- **Constants**: UPPER_SNAKE_CASE for environment variables only
|
|
- **Database tables**: snake_case
|
|
- **API routes**: kebab-case path segments
|
|
|
|
### Database Patterns
|
|
|
|
- Use Triplit for database operations
|
|
- Export all schemas from `triplit/schema.ts`
|
|
- Use environment variables for database credentials
|
|
- Triplit schemas are defined in `triplit/schema.ts` and pushed using `bunx triplit schema push`
|
|
|
|
### Error Handling
|
|
|
|
- Use proper TypeScript error types
|
|
- Implement try-catch blocks for database operations
|
|
- Provide user-friendly error messages in API responses
|
|
- Log errors appropriately without exposing sensitive data
|
|
|
|
### Performance Guidelines
|
|
|
|
- Leverage Nuxt's auto-imports and code splitting
|
|
- Use `useState()` for shared state across components
|
|
- Implement proper loading states with async operations
|
|
- Optimize database queries and use indexes where needed
|
|
|
|
## Authentication Implementation
|
|
|
|
The app uses better-auth with:
|
|
|
|
- Email/password authentication (configurable via env vars)
|
|
- Triplit adapter for authentication
|
|
- Session management through cookies
|
|
- Auth plugins in `app/plugins/` for client/server initialization
|
|
- Global auth middleware in `app/middleware/auth.global.ts`
|
|
|
|
All users must be signed in to view pages aside from authentication pages.
|
|
(located in `app/pages/auth/`), you do not need to check if session or user
|
|
objects are null or undefined, use the non-null assertion operator (`!`) where
|
|
necessary. In API routes, you can use `protectRoute` to guarantee that the
|
|
user must be authenticated.
|
|
|
|
## File Organization
|
|
|
|
```
|
|
|-- app/ # Application code
|
|
│ |-- components/ # Vue components
|
|
│ |-- composables/ # Reuseable composition functions
|
|
│ |-- layouts/ # Layout components
|
|
│ |-- middleware/ # Route middleware
|
|
│ |-- pages/ # File-based routing
|
|
│ \-- plugins/ # Vue/Nuxt plugins
|
|
|-- server/ # Server-side code
|
|
│ \-- api/ # API routes
|
|
|-- triplit/ # Database related files
|
|
│ |-- schema.ts # Database schema
|
|
│ |-- client.ts # Interacts with the database on the client
|
|
│ \-- server.ts # Interacts with the database on the server
|
|
\-- lib/ # Shared utilities
|
|
```
|
|
|
|
## Testing
|
|
|
|
Currently no test framework is configured, and tests are not currently a
|
|
requirement.
|
|
|
|
## Environment Variables
|
|
|
|
Key environment variables:
|
|
|
|
- `TRIPLIT_SERVICE_TOKEN` - Triplit service token (admin token. **SECRET**)
|
|
- `NUXT_TRIPLIT_ANON_TOKEN` - Triplit anonymous token (for anonymous access)
|
|
- `BETTER_AUTH_SECRET` - Authentication secret (for better-auth)
|
|
- `EXTERNAL_JWT_SECRET` - Will always be BETTER_AUTH_SECRET (used for
|
|
verifying JWT tokens from better-auth)
|
|
- `NUXT_PUBLIC_TRIPLIT_URL` - Triplit server URL
|
|
|
|
## Common Patterns
|
|
|
|
### Composables Pattern
|
|
|
|
```typescript
|
|
export const useFeature = () => {
|
|
const state = useState<Type>('feature:state', () => defaultValue)
|
|
const computed = computed(() => /* logic */)
|
|
|
|
const actions = {
|
|
// methods
|
|
}
|
|
|
|
return { state, computed, ...actions }
|
|
}
|
|
```
|
|
|
|
### API Route Pattern
|
|
|
|
API routes are defined in `server/api/` and are exported as a single object.
|
|
|
|
File names contain information about the route, e.g. `user.get.ts` specifies a
|
|
GET route to `/user`. This applies for all HTTP methods.
|
|
|
|
```typescript
|
|
// an example GET route to /user
|
|
export default defineEventHandler(async (event) => {
|
|
try {
|
|
// implementation
|
|
return { success: true, data: result };
|
|
} catch (error) {
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: "Error description",
|
|
});
|
|
}
|
|
});
|
|
```
|
|
|
|
```typescript
|
|
import { users } from "~~/db/schema";
|
|
|
|
// an example POST route to /user
|
|
export default defineEventHandler(async (event) => {
|
|
const body = await readBody(event);
|
|
|
|
const { email, name, password } = body;
|
|
|
|
const [user] = await db
|
|
.insert(users)
|
|
.values({ email, name, password })
|
|
.returning();
|
|
|
|
return user;
|
|
});
|
|
```
|