gadget/AGENTS.md

3.7 KiB

AGENTS.md — Gadget Code Monorepo

Project Structure

gadget/
├── packages/ai/           @gadget/ai — AI API abstraction (source of truth)
├── gadget-code/            Web service + browser IDE
├── gadget-drone/           Worker process (agentic workflow loop)
└── pnpm-workspace.yaml     Monorepo workspace definition

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

pnpm install              # Install all workspace packages
pnpm -r build             # Build all packages
pnpm --filter @gadget/ai build
pnpm --filter gadget-drone build
pnpm --filter gadget-code build:backend
pnpm --filter gadget-code dev
pnpm --filter gadget-drone dev

Key Conventions

  • All packages are ES modules ("type": "module").
  • @gadget/ai uses moduleResolution: NodeNext and emits to dist/.
  • gadget-drone uses moduleResolution: NodeNext.
  • gadget-code uses moduleResolution: bundler with @/* path aliases.
  • Dependency versions are pinned in package.json — no ranges. Use the workspace protocol (workspace:*) for internal package references.
  • pnpm version is enforced at the workspace root (packageManager field).

TypeScript Strictness

Package Strictness
@gadget/ai strict: true
gadget-drone strict: true
gadget-code strict: true, noUnusedLocals, noUnusedParameters, noUncheckedIndexedAccess

Adding Code

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

  • Shared AI concern (AI logging, config schema) → goes in @gadget/ai
  • 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 @gadget/ai. Do not copy-paste shared logic across packages.

GadgetId

All entity IDs use the GadgetId type (a string alias) defined in @gadget/api. This eliminates MongoDB ObjectId conversion throughout the codebase.

Interfaces

Always specify { _id: GadgetId } in interfaces:

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

interface IMyEntity {
  _id: GadgetId;
  // ... other fields
}

Mongoose Schemas

Always use this pattern for _id:

_id: { type: String, default: () => nanoid() }

Never add unique: true or required: true to _id:

  • unique: true causes duplicate index errors at startup (MongoDB auto-creates a unique index on _id)
  • required: true causes save failures because the default is assigned AFTER validation

Rules

  1. All _id fields are GadgetId (string)
  2. No ObjectId usage in application code
  3. No createFromHexString() or toHexString() conversions
  4. Never unique or required on _id in schemas