ai: agents file

This commit is contained in:
Alejandro Gómez
2026-01-22 18:36:12 +01:00
parent 32d584090f
commit 0ebe1ec3da

178
AGENTS.md Normal file
View File

@@ -0,0 +1,178 @@
# AGENTS.md
This file contains guidelines for agentic coding agents working in the Grimoire repository.
## Quick Reference
For detailed project architecture, patterns, and conventions, see **[CLAUDE.md](./CLAUDE.md)**.
## Build Commands
### Development
```bash
npm run dev # Start development server with HMR
npm run build # TypeScript check + production build
npm run preview # Preview production build locally
```
### Code Quality
```bash
npm run lint # Run ESLint (fails on errors)
npm run lint:fix # Auto-fix ESLint issues + formatting
npm run format # Format with Prettier
npm run format:check # Check formatting without changes
```
### Testing
```bash
npm test # Run tests in watch mode
npm run test:ui # Visual test explorer
npm run test:run # Single test run (CI mode)
```
**Single Test**: Use `vitest run` with file pattern:
```bash
npm run test:run src/lib/nostr-utils.test.ts
```
### Verification
Always run before committing:
```bash
npm run lint && npm run test:run && npm run build
```
## Code Style Guidelines
### Imports & Dependencies
- **Path Alias**: Use `@/` for `src/` directory (configured in Vite & Vitest)
- **Import Order**: External libs → Applesauce → Local `@/` modules → Relative imports
- **Applesauce**: Prefer helpers from `applesauce-core/helpers` and `applesauce-common/helpers`
- **No Default Exports**: Use named exports for better tree-shaking
```typescript
// ✅ Correct import order
import { useState } from "react";
import { use$ } from "applesauce-react/hooks";
import { getProfileContent } from "applesauce-core/helpers";
import { cn } from "@/lib/utils";
import { UserName } from "./components/UserName";
```
### TypeScript & Types
- **Strict Mode**: Project uses strict TypeScript configuration
- **No `any`**: ESLint rule disabled, but prefer proper types
- **Applesauce Types**: Use types from `applesauce-core` and `nostr-tools`
- **Local Types**: Extend in `src/types/` when needed
```typescript
// ✅ Use proper types from Applesauce
import type { NostrEvent, ProfileContent } from "applesauce-core/helpers";
import type { EventPointer } from "nostr-tools/nip19";
```
### React Patterns
- **React 19**: Use latest features (hooks, concurrent rendering)
- **No Default Exports**: Components use named exports
- **Props Interface**: Always define props interface with JSDoc comments
- **Destructured Props**: Destructure props in function signature
```typescript
// ✅ Component pattern
interface QuotedEventProps {
/** EventPointer with optional relay hints */
eventPointer?: EventPointer;
/** Depth level for nesting */
depth?: number;
}
export function QuotedEvent({ eventPointer, depth = 0 }: QuotedEventProps) {
// Component logic
}
```
### Performance & Caching
- **Applesauce Helpers**: Cache internally - NO `useMemo` needed
- **Custom Helpers**: Use `useMemo` for complex transformations
- **Stable References**: Use `useStableValue`/`useStableArray` for filters/options
```typescript
// ❌ WRONG - Unnecessary memoization
const title = useMemo(() => getArticleTitle(event), [event]);
// ✅ CORRECT - Helpers cache internally
const title = getArticleTitle(event);
```
### Styling
- **TailwindCSS**: Primary styling approach
- **CSS Variables**: Theme tokens in HSL format (see `index.css`)
- **Utility Function**: Use `cn()` from `@/lib/utils` for class merging
- **Dark Mode**: Default (controlled via HTML class)
```typescript
// ✅ Styling pattern
import { cn } from "@/lib/utils";
const className = cn(
"flex items-center gap-2 p-2 rounded-lg",
isActive && "bg-primary text-primary-foreground",
className
);
```
### File Organization
- **By Domain**: Group files by feature/domain (`nostr/`, `ui/`, `services/`, `hooks/`)
- **Colocated Tests**: Test files next to source files (`*.test.ts`)
- **Barrel Exports**: Use `index.ts` for clean imports
- **Pure Functions**: Business logic in `src/core/logic.ts`
### Naming Conventions
- **Components**: PascalCase with descriptive names (`LiveActivityRenderer`)
- **Hooks**: camelCase with `use` prefix (`useAccount`, `useProfile`)
- **Utilities**: camelCase with descriptive names (`getDisplayName`, `canAccountSign`)
- **Constants**: UPPER_SNAKE_CASE for exports
- **Files**: kebab-case for utilities, PascalCase for components
## Testing Guidelines
### Test Environment
- **Vitest**: Test framework with Node environment
- **Polyfills**: IndexedDB, WebSocket, localStorage pre-configured
- **Setup File**: `src/test/setup.ts` contains browser API polyfills
### What to Test
- **Parsers**: All argument parsing logic and edge cases
- **Pure Functions**: State mutations and business logic
- **Utilities**: Helper functions and data transformations
- **Not UI Components**: React components tested manually
### Test Structure
```typescript
describe("parseReqCommand", () => {
describe("kind flag (-k, --kind)", () => {
it("should parse single kind", () => {
const result = parseReqCommand(["-k", "1"]);
expect(result.filter.kinds).toEqual([1]);
});
});
});
```
## Critical Rules
1. **Singleton Services**: Never create new EventStore, RelayPool, or RelayLiveness instances
2. **Verification**: Always run full verification before committing changes
3. **Applesauce Caching**: Don't use `useMemo` with Applesauce helpers
4. **Account Signing**: Always check `canSign` before signing operations
5. **Error Boundaries**: Wrap event renderers in error boundaries
6. **Path Alias**: Use `@/` for all internal imports
## Project Context
Grimoire is a Nostr protocol explorer with a tiling window manager interface. Each window is a Nostr "app" (profile viewer, event feed, NIP documentation, etc.). Commands are launched Unix-style via Cmd+K palette.
**Stack**: React 19 + TypeScript + Vite + TailwindCSS + Jotai + Dexie + Applesauce
---
*See [CLAUDE.md](./CLAUDE.md) for detailed architecture, patterns, hooks, and conventions.*