PCP Project-Specific Agent Rules
These rules extend the canonical Trance-0/AGENTS.md.
Project context
Personal Context Protocol - Vercel + Neon Postgres web app for scoped AI session recording.
Critical invariants
AI must NOT manage topics
AI-facing APIs reject any
topic_id,topic_name, or topic-related fields in request bodiesAI session tokens cannot call
/api/v1/topics/*routes (403)Topic creation/rename/archive are admin-only operations
Backend may resolve
topic_idinternally from session, but never expose to AI
Messages are append-only for AI
AI tokens may only append; they never UPDATE or DELETE existing messages
AI corrections are appended as new messages with
role: "correction"orrole: "system"Each message gets a monotonically increasing
ordinalwithin its sessionCorrections reference the original message via metadata if needed
Exception (human admin only): a UI-token admin may edit or delete a message to fix a wrongly-recorded or wrongly-imported entry, via
PATCH /api/v1/sessions/:id/messages/:messageIdandPOST /api/v1/sessions/:id/messages/delete. These are audited (message.edited,message.deleted). This admin path does not relax the AI-token rule above.
Token scoping
Each
session_tokenis bound to exactly onesession_idToken validation MUST verify session match on every request
Revoked tokens (soft delete) must be rejected
Never return plaintext tokens after initial generation
No external auth in v0.1
v0.1 uses single instance token + scoped session tokens only
No OAuth, no SSO, no GitHub login
UI token is generated at setup, stored as hash
If user loses UI token, they must rotate (generates new token)
Development rules
Verify before claiming
API changes: Test with curl/POSTMAN before marking complete
Migration changes: Generate and test migrations locally
Token flows: Verify hashing + validation + revocation
Build: Run
npm run buildbefore claiming deploy readiness
File size discipline
Keep files under 1000 lines
If a file crosses 1000 lines, split by responsibility
Do NOT shrink files by deleting documentation
Prefer many small, well-named files over few large ones
Error messages
Every error message must include:
Consequence - what the user can’t do
Module/process - where the error occurred
Cause - the specific condition
Example:
❌ “Invalid token”
✅ “Unable to append messages: session token validation — token revoked or expired. Please generate a new token.”
Git discipline
Commit locally first, don’t push unless explicitly asked
Force-push requires explicit per-task approval
Check
git diff --cached --statbefore committingNever commit
.envfiles or files with real secrets
Testing requirements
Required tests for PR
Token validation tests
Valid token accepts requests
Invalid token rejects with 401
Revoked token rejects with 401
Wrong session token rejects with 403
AI token scoping tests
AI token cannot call topic routes (403)
AI token cannot access other sessions (403)
AI token can only append to its session
Append-only tests
Cannot UPDATE existing messages
Cannot DELETE existing messages
Corrections are new messages
Ordinal assignment is monotonic
Migration tests
Fresh DB: init creates all tables
Empty schema: migration applies successfully
Existing schema: migration is idempotent
No data loss on migration
Setup flow tests
Uninitialized app shows setup page
Setup generates UI token (shown once)
After setup, UI token unlocks admin functions
Test commands
npm run test # Run all tests
npm run typecheck # TypeScript check
npm run build # Build for production
Documentation updates
When making changes, update docs in the same commit:
Change type |
Update docs |
|---|---|
New API endpoint |
|
Schema change |
|
Deploy change |
|
Security change |
|
Agent instruction change |
|
Common pitfalls to avoid
Pitfall 1: Accidentally exposing topic fields to AI
Wrong:
// AI receives topic_id in response
return { sessionId, topicId, messages };
Correct:
// AI only sees session_id, never topic_id
return { sessionId, messages };
Pitfall 2: Allowing message updates
Wrong:
// AI tries to "correct" a message
await db.messages.update({ where: { id }, data: { content: "corrected" } });
Correct:
// Append correction as new message
await db.messages.insert({
sessionId,
role: "correction",
content: "Correction to message X: ...",
metadata: { corrects_message_id: "msg_..." }
});
Pitfall 3: Token leakage in logs
Wrong:
console.log("Token received:", token);
Correct:
console.log("Token received:", token ? "present" : "missing");
// Store hash only
const tokenHash = await hashToken(token);
Pitfall 4: Breaking migrations
Wrong:
-- Destructive: deletes all messages
DROP TABLE messages;
Correct:
-- Safe: adds column, preserves data
ALTER TABLE messages ADD COLUMN metadata_json JSONB DEFAULT '{}';
File locations
Setup wizard:
src/app/setup/*Admin UI:
src/app/(admin)/*API routes:
src/app/api/v1/*DB schema:
drizzle/schema.tsMigrations:
drizzle/000*.sqlTests:
tests/
Questions to ask the user
Before proceeding, if uncertain:
“Should I push to GitHub or just commit locally?”
“Is this scope correct, or should I focus on X first?”
“Do you want me to run migrations locally to test?”
“Should I write tests for this feature?”
When in doubt, ask. Better to clarify than to build the wrong thing.