ZenoZENO

AI setup

How Zeno configures Cursor and other AI coding assistants

Zeno is set up for AI-assisted development with Cursor and other AI coding tools.

AI assistants write better code when they know your project's conventions. Zeno ships AGENTS.md files that describe them, and a Cursor hook that runs Ultracite on every file the agent edits, so AI-generated code meets the same lint and format rules as hand-written code.

AGENTS.md

Cursor and other AI assistants pick up the root AGENTS.md on their own. It covers:

  • The project overview and the folder map, with a link to each package's own AGENTS.md
  • Which code ships through the shadcn registry and which ships on npm
  • Development commands and their catches
  • Formatting and testing rules
  • Rules for Supabase, agent skills and secrets

Packages with their own traps have an AGENTS.md too. Not every tool loads those nested files, so the root file tells the agent to read each AGENTS.md between a folder and the root before it changes code there.

Cursor configuration

The .cursor/ directory contains Cursor-specific configuration:

.cursor/
├── rules/
│   └── ultracite.mdc    # Code quality standards (applied to *.ts, *.tsx, *.js, *.jsx)
└── hooks.json           # Auto-fix after file edits

Rules

The Ultracite rule is scoped to source files and automatically loaded when working with matching files. It covers type safety, modern JS/TS patterns, React best practices, error handling, security, and performance.

Hooks

.cursor/hooks.json registers an afterFileEdit hook that runs Ultracite after every file edit the Cursor agent makes:

.cursor/hooks.json
{
  "hooks": {
    "afterFileEdit": [
      {
        "command": "pnpm dlx ultracite fix"
      }
    ]
  }
}

The hook formats and lint-fixes the agent's edits before you review them, so a file on disk can differ from what the agent just wrote.

AI-friendly patterns

Zeno follows these patterns, which give an AI assistant more context to work from:

Explicit types

Use interfaces for props and function signatures so AI understands the contract:

interface UserProps {
  id: string
  name: string
  email: string
}

function UserCard({ id, name, email }: UserProps) {
  // ...
}

Descriptive names

Start boolean names with an auxiliary verb such as is or has, so the name says what the value means:

// Good
const isUserAuthenticated = checkAuth()
const hasAdminPermissions = user.role === "admin"

// Avoid
const auth = checkAuth()
const admin = user.role === "admin"

Co-located types

Define a type next to the code that uses it, so an assistant reading that code sees both:

interface CreateUserInput {
  name: string
  email: string
}

async function createUser(input: CreateUserInput) {
  // AI has full context
}

LLM documentation

The Zeno docs serve Markdown for LLMs, through Fumadocs:

  • Any doc page is available as Markdown at /docs/<path>.mdx (for example /docs/foundation/getting-started/installation.mdx)

An AI assistant can fetch these URLs to read the docs.