# AGENTS.md — Gadget Code Monorepo

## Project Structure

```
gadget/
├── packages/
│   ├── ai/          @gadget/ai — AI API abstraction (Ollama + OpenAI)
│   ├── api/         @gadget/api — Shared TypeScript interfaces
│   └── config/     @gadget/config — Env config loader
├── gadget-code/          Web service — Express 5, React 19, browser IDE
│   └── frontend/         Frontend SPA — Vite 8 + React 19 (workspace member)
└── gadget-drone/         Worker process — Agentic workflow loop
```

## Rules for AI Code

The ecosystem speaks **one** AI API language defined by `@gadget/ai`. All rules apply to every consumer:

1. **No direct SDK imports.** Never `import { Ollama } from "ollama"` or `import OpenAI from "openai"` outside `packages/ai/src/`.
2. **No `provider.sdk` checks outside the factory.** The factory in `packages/ai/src/index.ts` routes to the correct implementation. After `createAiApi()`, the caller holds an `AiApi` and never checks which SDK backs it.
3. **All AI interfaces live in `@gadget/ai`.** Do not re-declare `IAiProvider`, `IAiChatResponse`, etc. in consumer packages. Import them from `@gadget/ai`.
4. **Adding a new provider** means implementing `AiApi` in `packages/ai/src/` and registering it in the factory. Nothing else changes.

## Dev Commands

```bash
pnpm install              # Install all workspace packages
pnpm -r build             # Build all packages

# Per-package build
pnpm --filter @gadget/ai build
pnpm --filter @gadget/api build
pnpm --filter @gadget/config build
pnpm --filter gadget-code build:backend    # backend → dist/ + resolves @/* aliases
pnpm --filter gadget-drone build
pnpm --filter gadget-code-frontend build  # frontend → dist/client/

# Run dev servers
pnpm --filter gadget-code dev              # Backend on https://localhost:3443
pnpm --filter gadget-drone dev             # Drone worker
pnpm --filter gadget-code-frontend dev     # Frontend on https://localhost:5174

# Typecheck
pnpm --filter @gadget/ai typecheck  # Only package with a typecheck script
```

## Key Conventions

- All packages are **ES modules** (`"type": "module"`).
- `@gadget/ai`, `@gadget/api`, `@gadget/config` use `moduleResolution: NodeNext` and emit to `dist/`.
- gadget-drone uses `moduleResolution: NodeNext`.
- gadget-code and gadget-code/frontend use `moduleResolution: bundler` with `@/*` path aliases → `src/*`.
- **gadget-code build requires `tsc-alias`** to resolve `@/*` path aliases in output.
- Dependency versions are pinned in `package.json` — no ranges. Use the workspace protocol (`workspace:*`) for internal package references.
- pnpm version enforced at the workspace root (`packageManager` field).
- **No lint scripts exist** in any package.

## TypeScript Strictness

| Package        | Strictness                                                                          |
| -------------- | ----------------------------------------------------------------------------------- |
| `@gadget/ai`   | `strict: true`                                                                      |
| `@gadget/api`  | `strict: true`                                                                      |
| `@gadget/config` | `strict: true`                                                                    |
| `gadget-drone` | `strict: true`                                                                      |
| `gadget-code`  | `strict: true`, `noUnusedLocals`, `noUnusedParameters`, `noUncheckedIndexedAccess`  |
| `gadget-code/frontend` | `strict: true` (included via workspace)                                     |

## GadgetId

All entity IDs use `GadgetId` (a string alias) from `@gadget/api`. Never use `ObjectId`.

```ts
import { GadgetId } from "@gadget/api";

interface IMyEntity {
  _id: GadgetId;
}
```

**Mongoose schema pattern:**
```ts
_id: { type: String, default: () => nanoid() }
```

**Never add `unique: true` or `required: true` to `_id`**: MongoDB auto-creates a unique index on `_id` (causes duplicate index errors if `unique` is also set), and the default is assigned after validation (causes save failures if `required` is set).

See `gadget-code/docs/gadget-id.md` for full documentation.

## Testing

- `gadget-code`: Vitest unit tests (`pnpm test`). Vitest config excludes `tests/e2e/`.
- E2E tests: Playwright targets `https://code-dev.g4dge7.com:5174` (requires running dev servers).
- Seed test drones: `cd gadget-code && npx tsx scripts/seed-test-drones.ts`
- `gadget-drone`: No tests configured.

## Adding Code

When adding a new feature or service, determine its scope:

- **Shared AI concern** (AI logging, config schema) → goes in `@gadget/ai`
- **Shared types** → goes in `@gadget/api`
- **Config loading** → goes in `@gadget/config`
- **Drone-only** (Bull queue, workspace file operations) → goes in `gadget-drone`
- **Web-only** (Express routes, Mongoose models, session management) → goes in `gadget-code`

If code is needed by both consumer packages, it belongs in the appropriate shared package. Do not copy-paste shared logic across packages.

## Prerequisites

- Node.js 22+
- pnpm (version enforced at root `packageManager` field)
- MongoDB on `localhost:27017`
- Redis on `localhost:6379`
- SSL certificates in `gadget-code/ssl/` directory (for dev servers)
