Salta ai contenuti

File di Istruzioni AI

Ogni assistente vuole le proprie regole in un file diverso. Claude Code legge CLAUDE.md, Cursor legge .cursorrules, Windsurf legge .windsurfrules, Copilot legge .github/copilot-instructions.md, e la convenzione comune tra i vendor è AGENTS.md. Mantenere le stesse istruzioni in cinque file diversi è il modo perfetto per far sì che quattro di essi diventino obsoleti.

rebase init scrive tutti e cinque — come puntatori a un singolo file che andrai effettivamente a modificare:

your-project/
├── ai-instructions.md ← the real content
├── CLAUDE.md ← pointer
├── AGENTS.md ← pointer
├── .cursorrules ← pointer
├── .windsurfrules ← pointer
└── .github/
└── copilot-instructions.md ← pointer

Ogni file puntatore è composto da tre righe:

# Rebase AI Rules
Please refer to and follow the instructions defined in [ai-instructions.md](./ai-instructions.md).
The Rebase skills for this assistant live in `.claude/skills/`. If they are not there yet, install them, with the Rebase MCP server: `rebase skills install --agent claude --mcp`.

Sulla 0.23 la terza riga si limita a dire all’assistente di eseguire rebase skills install --agent claude, e il .mcp.json più sotto avvia il server con npx -y @rebasepro/mcp dal registry.

Gli altri differiscono solo nella directory delle skill dell’agente e nel suo valore --agent — --agent cursor, --agent windsurf, --agent codex, --agent copilot — e nel percorso relativo, che è ../ai-instructions.md in .github/copilot-instructions.md e ai-instructions.md in AGENTS.md. La terza riga è condizionale perché rebase init --agent potrebbe aver già installato le skill prima che l’assistente la legga.

Questo avviene a ogni rebase init, per ogni preset incluso --headless. Non ci sono flag né richieste di conferma.

rebase init scrive anche .mcp.json, che indirizza Claude Code, Cursor e qualsiasi altro client MCP al server MCP di Rebase — la copia propria del progetto, una devDependency fissata insieme alla CLI (npx --no rebase-mcp in un progetto npm):

{
"mcpServers": {
"rebase": {
"command": "pnpm",
"args": ["exec", "rebase-mcp"],
"env": {
"REBASE_PROJECT_DIR": "."
}
}
}
}

REBASE_PROJECT_DIR è ".", non un percorso assoluto: il client avvia il server nella radice del progetto, e un percorso assoluto è l’unica riga di quel file che non può essere committata. C’è perché ~/.rebase/projects.json vale per l’intera macchina — un progetto che non nomina una directory propria ricade su ciò che vi ha salvato l’ultimo progetto di quella macchina. Vedi la precedenza.

I file puntatore sono deliberatamente privi di contenuti. Gli assistenti seguono i link Markdown relativi, quindi un file di tre righe che fa riferimento a quello reale ottiene lo stesso risultato di una copia — offrendo al contempo vantaggi che una copia non ha:

  • Un solo file da modificare. Le regole non possono divergere tra gli assistenti, perché esiste un solo set di regole.
  • Un solo diff da revisionare. Una modifica alle convenzioni del progetto è una modifica a un solo file, non a cinque file identici che un revisore deve confrontare.
  • Aggiungere un assistente richiede tre righe. Un nuovo strumento con un nuovo nome di file ottiene un puntatore, non una sesta copia delle tue convenzioni.

È un pattern che vale la pena mantenere se fai un fork dello scaffold, e che vale la pena adottare anche in repository che non sono affatto progetti Rebase.

Il file scaffoldato è deliberatamente breve — rimanda a rebase skills install per approfondire, poi definisce le regole che gli assistenti sbagliano abbastanza spesso da meritare di essere ripetute all’inizio di ogni sessione:

  1. Schema come codice. Le collezioni sono definite in config/collections/. Non modificare mai a mano lo schema Drizzle generato o le tabelle Postgres — vedi Schema as Code.
  2. Come si applica una modifica a una collection dipende dal database. Mentre pnpm dev è in esecuzione, salvare il file della collection è l’intero passo: il boot rigenera lo schema Drizzle e crea le tabelle e le colonne mancanti. pnpm db:push serve solo per ciò che il boot lascia deliberatamente stare — una colonna rinominata, un tipo ristretto, un campo rimosso — sul database di sviluppo gestito come sul tuo PostgreSQL. In produzione la coppia è pnpm db:generate e poi pnpm db:migrate. Da 0.25 Su 0.24 pnpm db:push richiede il tuo PostgreSQL, e il file lo dice.
  3. Usa l’SDK. Passa attraverso rebase.dataAsAdmin.<slug> per il lavoro svolto con l’identità del servizio, oppure getDriver(c) dentro una function quando la lettura deve avvenire come chiamante. Sul server il client non espone un accessore data semplice. L’SDK va sempre usato: l’SQL grezzo e le chiamate dirette a Drizzle bypassan la validazione, le callback e la RLS.
  4. Proteggi ogni route personalizzata. Le route in backend/functions/ sono montate senza autenticazione. Usa requireAuth / requireAdmin da @rebasepro/server/functions nello slot middleware dedicato della route — leggere c.get("user") non costituisce una protezione, e non lo è nemmeno app.use() dopo la route.

Quest’ultima è quella fondamentale da ricordare. Fa la differenza tra un middleware che viene eseguito e uno che non lo è, e un assistente a cui non è stato detto scriverà puntualmente la versione che non lo fa — vedi Funzioni personalizzate.

requireAdmin ammette solo il ruolo admin. Quando un ruolo più ristretto o una chiave API deve poter chiamare una route, la protezione da aggiungere è requireScope, con uno scope dichiarato dall’app — vedi Ruoli e scope.

ai-instructions.md è il tuo file. Niente lo rigenera o lo sovrascrive — a differenza delle skill installate, che vengono sostituite a ogni rebase skills install. Le convenzioni specifiche del progetto vanno inserite qui.

Ciò che merita spazio è ciò che un assistente non può dedurre dal codice: quali collezioni sono legacy, quale servizio possiede quale tabella, la convenzione di denominazione che non è imposta da nessuna parte, la migrazione che non deve essere rieseguita. Mantienilo breve — le istruzioni caricate in ogni richiesta competono con il task effettivo per l’attenzione dell’assistente, e un file lungo viene solo scorso superficialmente.

E tieni a mente il limite: questo file determina ciò che un assistente scrive. Non ha alcuna influenza su ciò che un agente connesso al tuo database può fare — questo è determinato dalle credenziali in suo possesso, e nulla nel Markdown può cambiarlo. Vedi il modello di credenziali del server MCP.