The Observatory · 11 min mission
Starter Kits: Make Any Repo Agent-Ready
Drop one set of copy-paste files into a fresh repo and every coding agent boots informed.
On this page
An agent-ready starter kit is a fixed set of files you commit to a repo so any coding agent that opens it starts with your build commands, conventions, and constraints already loaded. This guide gives you the exact files to drop in, the shim each tool needs, and the enforcement layer that briefings alone cannot provide.
The architecture is one canonical briefing plus thin per-tool shims: the real instructions live in AGENTS.md; CLAUDE.md, GEMINI.md, a Cursor .mdc, and .github/copilot-instructions.md only point at it or add tool-specific notes. Every briefing file is advice the model tries to follow; only deny rules, hooks, sandboxes, and CI are enforcement it cannot bypass.
| Tool | Reads `AGENTS.md` natively | Shim the kit ships |
|---|---|---|
| Cursor | Yes (root + nested, closest wins) | Optional .cursor/rules/*.mdc for scoped rules |
| GitHub Copilot | Yes (nearest-in-tree wins) | .github/copilot-instructions.md (used *together* with AGENTS.md) |
| Windsurf / Devin | Yes (root always-on; subdir glob-scoped) | None; .devin/rules/ for scoped rules |
| Cline / Roo Code | Yes | None needed |
| Claude Code | No — reads CLAUDE.md only | CLAUDE.md with @AGENTS.md import (or symlink) |
| Gemini CLI | No by default | GEMINI.md import, or add to context.fileName |
| Codex | Yes (primary instruction file) | None needed |
The starter-kit forge — generate your repo’s agent files
Starter-kit forge
Pick the agents your team uses and answer a couple of project questions. The kit assembles itself around one canonical AGENTS.md — the source of truth the standard ~24 tools read — plus only the thin shim each tool needs and Claude Code's enforcement layer. Untick a tool and its file leaves the tree.
Agents your team uses
AGENTS.md is always generated — it's the spine. Each tool you add brings only the shim it needs.
- Claude Code — Needs a CLAUDE.md that imports @AGENTS.md — it never reads AGENTS.md directly. Brings the enforcement layer: settings.json, a Stop-gate hook, and a skill.
- Cursor — Reads AGENTS.md natively. Adds a scoped .cursor/rules/*.mdc (globs/modes) — not the broad briefing, which lives in AGENTS.md.
- GitHub Copilot — Reads AGENTS.md natively and uses it together with .github/copilot-instructions.md (both files concatenate). Keep the Copilot file short.
Package manager
Threaded through every command in the briefing so agents never reach for the wrong one.
Test command
The exact command for the Definition of done, the Claude allow-list, and the Stop-hook gate.
Forbidden directory
A path agents must never edit — written into AGENTS.md's Conventions section.
Files generated (8)
Click a file to open it. AGENTS.md leads; shims and the enforcement layer follow your selection.
AGENTS.mdmarkdown# AGENTS.md > Operating instructions for coding agents working in this repo. Plain Markdown, no schema.> The closest AGENTS.md to the file being edited wins; an explicit chat instruction wins over all. ## Project overview- <One sentence: what this project is and its stack, e.g. "Next.js 14 App Router + TypeScript, static export.">- Entry points: `app/` (routes), `lib/` (shared logic), `components/` (UI). ## Setup- Install: `pnpm install` (this repo uses pnpm — do not use npm or yarn)- Integration tests need a local Postgres: `docker compose up -d db` first. ## Build, test, lint- Build: `pnpm build`- Test (all): `pnpm test` · single file: `pnpm test <path>`- Lint (must be zero warnings): `pnpm lint`- Typecheck: `pnpm typecheck` ## Code style- TypeScript strict; no `any` that breaks the build.- 2-space indent; named exports; colocate tests as `*.test.ts`. ## Conventions & constraints- Never edit `legacy/` or generated output in `dist/`.- Keep the public API in `lib/api/` backward compatible.- Use the `@/*` path alias (maps to repo root); never deep relative imports across packages. ## Definition of doneBefore claiming a task is finished: `pnpm lint` clean, `pnpm test` green, `pnpm typecheck`passes, no new TODOs left in changed files. ## PR / commit- Conventional Commits (`feat:`, `fix:`, `chore:`). One logical change per PR.- Do not commit unless explicitly asked. ## Review guidelines- Don't log PII. Verify auth middleware wraps every route.- Flag typos/grammar in user-facing strings as P0.Replace the <…> placeholders per project. Specs current as of 2026-06-15; coding agents ship fast, so check each tool's docs before relying on a detail.
Assemble the kit
Write `AGENTS.md` at the repo root
Plain Markdown, no schema. Put the real briefing here: build/test/lint commands, code style, hard constraints, and an explicit definition of "done". Cursor, Copilot, Windsurf, Cline, Roo Code, and Codex read it natively.
Add `CLAUDE.md` with `@AGENTS.md` on line 1
Claude Code reads
CLAUDE.md, notAGENTS.md. The@AGENTS.mdimport pulls in the canonical briefing; add only Claude-specific lines below it. Target under 200 lines.Add `GEMINI.md` with `@./AGENTS.md`, or set `context.fileName`
Gemini CLI reads
GEMINI.mdonly by default. Either importAGENTS.mdfrom a tinyGEMINI.md, or listAGENTS.mdincontext.fileNamein.gemini/settings.json. Ship one, not both.Add scoped shims for Cursor and Copilot
Both read
AGENTS.mdnatively, so do not copy the briefing. Add.cursor/rules/*.mdconly for path-scoped rules, and keep.github/copilot-instructions.mda short pointer plus Copilot-only notes.Add the enforcement layer under `.claude/`
Commit
.claude/settings.json(permissions + a format-on-edit hook),.claude/hooks/test-gate.sh(aStoptest gate), and a.claude/skills/<name>/SKILL.mdskill.Gitignore the personal-override siblings
Add
CLAUDE.local.md,.claude/settings.local.json, andAGENTS.local.md(Roo Code) to.gitignoreso local preferences never reach the shared repo.
AGENTS.md — the canonical briefing
AGENTS.md is plain Markdown with no schema and no required fields, stewarded by the Agentic AI Foundation under the Linux Foundation; agents.md reports it is used by over 60,000 open-source projects. The spec recommends optional sections — project overview, build/test/lint commands, code style, dev-environment tips, testing instructions, PR/commit conventions, security considerations — but imposes none. Precedence: the closest AGENTS.md to the edited file wins; an explicit chat instruction wins over all.
# AGENTS.md
> Operating instructions for coding agents working in this repo. Plain Markdown, no schema.
> The closest AGENTS.md to the file being edited wins; an explicit chat instruction wins over all.
## Project overview
- Next.js 14 App Router + TypeScript, static export.
- Entry points: `app/` (routes), `lib/` (shared logic), `components/` (UI).
## Setup
- Install: `pnpm install` (this repo uses pnpm — do not use npm or yarn)
- Integration tests need a local Postgres: `docker compose up -d db` first.
## Build, test, lint
- Build: `pnpm build`
- Test (all): `pnpm test` · single file: `pnpm test <path>`
- Lint (must be zero warnings): `pnpm lint`
- Typecheck: `pnpm typecheck`
## Code style
- TypeScript strict; no `any` that breaks the build.
- 2-space indent; named exports; colocate tests as `*.test.ts`.
## Conventions & constraints
- Never edit `legacy/` or generated output in `dist/`.
- Keep the public API in `lib/api/` backward compatible.
- Use the `@/*` path alias (maps to repo root); never deep relative imports across packages.
## Definition of done
Before claiming a task is finished: `pnpm lint` clean, `pnpm test` green, `pnpm typecheck`
passes, no new TODOs left in changed files.
## PR / commit
- Conventional Commits (`feat:`, `fix:`, `chore:`). One logical change per PR.
- Do not commit unless explicitly asked.
## Review guidelines
- Don't log PII. Verify auth middleware wraps every route.
- Flag typos/grammar in user-facing strings as P0.CLAUDE.md and GEMINI.md shims
Claude Code reads CLAUDE.md only; Gemini CLI reads GEMINI.md only (or whatever you list in context.fileName). Neither reads AGENTS.md by default — the single biggest trap when assembling a kit. Both support @-path imports, so each shim imports the canonical briefing and adds only its own notes. Claude Code's documented single-source pattern is exactly this @AGENTS.md import; it targets keeping CLAUDE.md under 200 lines and delivers the content as a user message after the system prompt. HTML comments are stripped before injection, so they are free annotations.
@AGENTS.md
# CLAUDE.md
<!-- The shared briefing above is imported from AGENTS.md so Claude Code and every
AGENTS.md-native tool read one source of truth. Add ONLY Claude-specific lines below. -->
## Claude Code specifics
- Use plan mode before multi-file changes under `lib/api/`.
- Run a single test with `pnpm test <path>`, not the whole suite, while iterating.
- Money-handling rules live in `lib/payments/CLAUDE.md` and load on demand when you work there.@./AGENTS.md
# GEMINI.md
<!-- Imports the shared AGENTS.md briefing. Gemini-only notes go below. -->
## Gemini CLI specifics
- Prefer `gemini -m gemini-2.5-flash` for quick edits; reserve the pro model for design work.{
"context": {
"fileName": ["AGENTS.md", "GEMINI.md"]
}
}Cursor and Copilot scoped shims
Cursor rules live in .cursor/rules/ as .mdc files (Markdown + YAML frontmatter) — a plain .md there is silently ignored. Three frontmatter fields (description, globs, alwaysApply) select one of four activation modes. Keep rules under 500 lines and use the .mdc for path-scoped conventions only; AGENTS.md covers the rest.
For Copilot, when both AGENTS.md and .github/copilot-instructions.md exist at the root, Copilot uses the instructions in both files together — concatenated, not one overriding the other. Duplicating the briefing here creates redundancy, not precedence. Path-scoped rules go in .github/instructions/*.instructions.md with an applyTo: glob.
---
description: TypeScript/React component conventions for this repo
globs: src/components/**/*.tsx
alwaysApply: false
---
# Component conventions
- Function components only; no class components.
- Props typed with an exported `interface`, never inline object types.
- Co-locate a `*.test.tsx` beside every component.
- Use the design tokens in `styles/tokens.css`; never hardcode hex colors.
- Reference `@/lib/api` for data fetching — do not call `fetch` directly in components.| Mode | Frontmatter | Fires when |
|---|---|---|
| Always Apply | alwaysApply: true | Every request, always in context |
| Apply Intelligently | description, no globs | Cursor judges the description relevant |
| Apply to Specific Files | globs set | An edited file matches the glob |
| Apply Manually | none of the three | Only on an explicit @rule-name |
# Copilot instructions
The canonical project briefing lives in `AGENTS.md` at the repo root and Copilot reads it
automatically; this file adds Copilot-specific guidance only.
- This repo uses **pnpm**. Never suggest `npm install` or `yarn`.
- Prefer small, reviewable diffs; explain non-obvious changes in the PR body.
- TypeScript strict mode is on — never introduce `any`.
- For test files, follow the existing `*.test.ts` patterns in the same directory.Enforcement: permissions + a format-on-edit hook
.claude/settings.json carries permissions with allow / ask / deny arrays. Evaluation order is deny → ask → allow; deny always wins and rules merge across scopes, so a deny rule cannot be overridden by a prompt. Allow-listing the safe commands removes the prompt fatigue that pushes people toward bypassPermissions (isolated containers only — never a kit default). Commit .claude/settings.json for the team; keep personal overrides in gitignored .claude/settings.local.json. The same file holds a hooks object; below, a PostToolUse hook formats every edited file.
{
"permissions": {
"allow": [
"Bash(pnpm test *)",
"Bash(pnpm lint *)",
"Bash(pnpm build *)",
"Bash(pnpm typecheck *)",
"Bash(git status *)",
"Bash(git diff *)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Bash(rm -rf *)",
"Bash(curl *)"
]
},
"defaultMode": "default",
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs -r npx prettier --write"
}
]
}
]
}
}Enforcement: a Stop-hook test gate
A Stop hook fires when Claude tries to end a turn. The most valuable kit hook runs the suite there and exits 2 to block the stop and feed the failure to stderr so Claude keeps working. Mandatory footgun: read stop_hook_active from the JSON on stdin and exit 0 early if it is true — Claude Code overrides a Stop hook after 8 consecutive blocks anyway, but you want to bow out cleanly first. The hook runs with full user privileges and no per-run prompt, so never ship one the team has not read.
#!/usr/bin/env bash
# Stop-hook gate: block the turn from ending until the test suite passes.
set -euo pipefail
input="$(cat)" # Claude Code feeds hook JSON on stdin
# Don't re-fire on a turn we already blocked (prevents the 8-block override loop).
if [ "$(printf '%s' "$input" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0
fi
if pnpm test >/tmp/test-gate.log 2>&1; then
exit 0 # tests green: allow the stop
else
echo "Tests are failing — keep working until they pass:" >&2
tail -n 20 /tmp/test-gate.log >&2
exit 2 # block the stop; stderr is fed back to Claude
fi{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": ".claude/hooks/test-gate.sh"
}
]
}
]
}
}Enforcement: a minimal skill
A skill is a directory with one required file, SKILL.md (YAML frontmatter + Markdown body). The directory name becomes the command (.claude/skills/summarize-changes/ → /summarize-changes), and project skills under .claude/skills/ ship to the team via git. description is the matching surface Claude uses to auto-invoke, so describe when to use the skill. A ! followed by a backticked command does dynamic context injection — Claude Code runs it and splices the output into the prompt before Claude reads. allowed-tools is permissive, not restrictive: it pre-approves the listed tools but does not sandbox the skill. Keep SKILL.md under 500 lines; for side-effecting skills add disable-model-invocation: true so only the user can fire them.
---
name: summarize-changes
description: Summarizes uncommitted changes and flags anything risky. Use when the user asks
what changed, wants a commit message, or asks to review their diff.
allowed-tools: Bash(git diff *) Bash(git status *)
---
## Current changes
!`git diff HEAD`
## Instructions
Summarize the changes above in two or three bullet points, then list any risks you notice —
missing error handling, hardcoded values, or tests that need updating. If the diff is empty,
say there are no uncommitted changes.Knowledge check
You want a single briefing that Claude Code, Codex, Cursor, Copilot, and Gemini CLI all follow, with no second copy to keep in sync. What is the cleanest kit architecture?
Reach the end and this star joins your charted sky.