Imported from aamdmn/payload-agent (
AGENTS.md). Install upstream withnpx skills add aamdmn/payload-agent. Copyright stays with the author.
Development Rules
Commands
- After code changes (not documentation changes):
pnpm check(get full output, no tail). Fix all errors, warnings, and infos before committing. - Note:
pnpm checkdoes not run tests. - NEVER run:
pnpm dev,pnpm build,pnpm test - Only run specific tests if user instructs:
pnpx tsx ../../node_modules/vitest/dist/cli.js --run test/specific.test.ts - If you create or modify a test file, you MUST run that test file and iterate until it passes.
- When writing tests, run them, identify issues in either the test or implementation, and iterate until fixed.
- NEVER commit unless user asks
Style
- Keep answers short and concise
- No emojis in commits, issues, PR comments, or code
- No fluff or cheerful filler text
- Technical prose only, be kind but direct (e.g., "Thanks @user" not "Thanks so much @user!")
Changelog
Location: CHANGELOG.md
Format
Use these sections under ## [Unreleased]:
### Breaking Changes- API changes requiring migration### Added- New features### Changed- Changes to existing functionality### Fixed- Bug fixes### Removed- Removed features
Rules
- Before adding entries, read the full
[Unreleased]section to see which subsections already exist - New entries ALWAYS go under
## [Unreleased]section - Append to existing subsections (e.g.,
### Fixed), do not create duplicates - NEVER modify already-released version sections (e.g.,
## [0.12.2]) - Each version section is immutable once released
Attribution
- Internal changes (from issues):
Fixed foo bar ([#123](https://github.com/aamdmn/payload-agent/issues/123)) - External contributions:
Added feature X ([#456](https://github.com/aamdmn/payload-agent/pull/456) by [@username](https://github.com/username))
Release
Publish, git tag, and GitHub release are a single command so they cannot drift apart (0.9.0 and 0.10.0 reached npm but were never tagged/released because this step was manual).
- In the feature PR: bump
versioninpackage.jsonand move the[Unreleased]entries into a new## [x.y.z] - YYYY-MM-DDCHANGELOG section. - Merge to
main, then from a clean, up-to-datemainrun:pnpm release— releases the currentpackage.jsonversionpnpm release "short summary"— same, with a custom GitHub release title (default title isvx.y.z)pnpm release --dry-run— runs every check and prints the plan, changes nothing
scripts/release.mjs runs all read-only checks first (on main, clean tree, in sync with origin, tag does not already exist, version not already on npm, gh installed + authed), then pnpm publish (pnpm-only — see ensure-pnpm.mjs), then creates and pushes the annotated tag, then the GitHub release. Release notes are pulled from the matching CHANGELOG.md section, so the changelog is the single source of truth — do not hand-write release notes.
CRITICAL Tool Usage Rules CRITICAL
- NEVER use sed/cat to read a file or a range of a file. Always use the read tool (use offset + limit for ranged reads).
- You MUST read every file you modify in full before editing.
CRITICAL Git Rules for Parallel Agents CRITICAL
Multiple agents may work on different files in the same worktree simultaneously. You MUST follow these rules:
Committing
- ONLY commit files YOU changed in THIS session
- ALWAYS include
fixes #<number>orcloses #<number>in the commit message when there is a related issue or PR - NEVER use
git add -Aorgit add .- these sweep up changes from other agents - ALWAYS use
git add <specific-file-paths>listing only files you modified - Before committing, run
git statusand verify you are only staging YOUR files - Track which files you created/modified/deleted during the session
Forbidden Git Operations
These commands can destroy other agents' work:
git reset --hard- destroys uncommitted changesgit checkout .- destroys uncommitted changesgit clean -fd- deletes untracked filesgit stash- stashes ALL changes including other agents' workgit add -A/git add .- stages other agents' uncommitted workgit commit --no-verify- bypasses required checks and is never allowed
Safe Workflow
# 1. Check status first
git status
# 2. Add ONLY your specific files
git add packages/ai/src/providers/transform-messages.ts
git add packages/ai/CHANGELOG.md
# 3. Commit
git commit -m "fix(ai): description"
# 4. Push (pull --rebase if needed, but NEVER reset/checkout)
git pull --rebase && git push
If Rebase Conflicts Occur
- Resolve conflicts in YOUR files only
- If conflict is in a file you didn't modify, abort and ask the user
- NEVER force push
User override
If the user instructions conflict with rules set out here, ask for confirmation that they want to override the rules. Only then execute their instructions.
Payload Plugin Development
This project is a Payload CMS plugin (payload-agent). All source code lives in src/, with a dev/ directory for local testing.
For Payload CMS fundamentals (collections, fields, hooks, access control, queries, security patterns), refer to the installed payload skill and its reference files in .agents/skills/payload/.
Project Structure
src/ # Plugin source code
index.ts # Entry point: plugin function + types
dev/ # Local dev environment (NOT plugin code)
payload.config.ts # Test Payload config that uses the plugin
seed.ts # Seed data for dev/testing
int.spec.ts # Integration tests
e2e.spec.ts # End-to-end tests
Plugin Architecture Rules
- Plugin signature:
(options) => (config: Config) => Config(curried function) - Always spread existing config: Never overwrite arrays/objects, always spread first
// Correct config.endpoints = [...(config.endpoints ?? []), myEndpoint] // Wrong - destroys user's existing endpoints config.endpoints = [myEndpoint] - Preserve existing onInit: Save
config.onInitreference, call it before plugin init - Preserve existing hooks: Spread
collection.hooks?.hookName || []when adding hooks - Provide
disabledoption: Let users disable the plugin without uninstalling it - Never store plugin logic in
dev/: That directory is purely for testing
Security Rules (Payload-Specific)
- Local API: Always set
overrideAccess: falsewhen passinguserto payload operations - Transaction safety: Always pass
reqto nested operations inside hooks - Hook loops: Use
contextflags to prevent infinite recursion - See
.agents/skills/payload/reference/PLUGIN-DEVELOPMENT.mdfor full patterns
Plugin Testing
- Integration tests live in
dev/int.spec.ts - E2E tests live in
dev/e2e.spec.ts - The dev project uses SQLite (
@payloadcms/db-sqlite) for easy local testing - Run tests with the commands in the Commands section above
Ultracite Code Standards
This project uses Ultracite, a zero-config preset that enforces strict code quality standards through automated formatting and linting.
Quick Reference
- Format code:
pnpm dlx ultracite fix - Check for issues:
pnpm dlx ultracite check - Diagnose setup:
pnpm dlx ultracite doctor
Biome (the underlying engine) provides robust linting and formatting. Most issues are automatically fixable.
Core Principles
Write code that is accessible, performant, type-safe, and maintainable. Focus on clarity and explicit intent over brevity.
Type Safety & Explicitness
- Use explicit types for function parameters and return values when they enhance clarity
- Prefer
unknownoveranywhen the type is genuinely unknown - Use const assertions (
as const) for immutable values and literal types - Leverage TypeScript's type narrowing instead of type assertions
- Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Modern JavaScript/TypeScript
- Use arrow functions for callbacks and short functions
- Prefer
for...ofloops over.forEach()and indexedforloops - Use optional chaining (
?.) and nullish coalescing (??) for safer property access - Prefer template literals over string concatenation
- Use destructuring for object and array assignments
- Use
constby default,letonly when reassignment is needed, nevervar
Async & Promises
- Always
awaitpromises in async functions - don't forget to use the return value - Use
async/awaitsyntax instead of promise chains for better readability - Handle errors appropriately in async code with try-catch blocks
- Don't use async functions as Promise executors
React & JSX
- Use function components over class components
- Call hooks at the top level only, never conditionally
- Specify all dependencies in hook dependency arrays correctly
- Use the
keyprop for elements in iterables (prefer unique IDs over array indices) - Nest children between opening and closing tags instead of passing as props
- Don't define components inside other components
- Use semantic HTML and ARIA attributes for accessibility:
- Provide meaningful alt text for images
- Use proper heading hierarchy
- Add labels for form inputs
- Include keyboard event handlers alongside mouse events
- Use semantic elements (
<button>,<nav>, etc.) instead of divs with roles
Error Handling & Debugging
- Remove
console.log,debugger, andalertstatements from production code - Throw
Errorobjects with descriptive messages, not strings or other values - Use
try-catchblocks meaningfully - don't catch errors just to rethrow them - Prefer early returns over nested conditionals for error cases
Code Organization
- Keep functions focused and under reasonable cognitive complexity limits
- Extract complex conditions into well-named boolean variables
- Use early returns to reduce nesting
- Prefer simple conditionals over nested ternary operators
- Group related code together and separate concerns
Security
- Add
rel="noopener"when usingtarget="_blank"on links - Avoid
dangerouslySetInnerHTMLunless absolutely necessary - Don't use
eval()or assign directly todocument.cookie - Validate and sanitize user input
Performance
- Avoid spread syntax in accumulators within loops
- Use top-level regex literals instead of creating them in loops
- Prefer specific imports over namespace imports
- Avoid barrel files (index files that re-export everything)
- Use proper image components (e.g., Next.js
<Image>) over<img>tags
Framework-Specific Guidance
Next.js:
- Use Next.js
<Image>component for images - Use
next/heador App Router metadata API for head elements - Use Server Components for async data fetching instead of async Client Components
React 19+:
- Use ref as a prop instead of
React.forwardRef
Solid/Svelte/Vue/Qwik:
- Use
classandforattributes (notclassNameorhtmlFor)
Testing
- Write assertions inside
it()ortest()blocks - Avoid done callbacks in async tests - use async/await instead
- Don't use
.onlyor.skipin committed code - Keep test suites reasonably flat - avoid excessive
describenesting
When Biome Can't Help
Biome's linter will catch most issues automatically. Focus your attention on:
- Business logic correctness - Biome can't validate your algorithms
- Meaningful naming - Use descriptive names for functions, variables, and types
- Architecture decisions - Component structure, data flow, and API design
- Edge cases - Handle boundary conditions and error states
- User experience - Accessibility, performance, and usability considerations
- Documentation - Add comments for complex logic, but prefer self-documenting code
Most formatting and common issues are automatically fixed by Biome. Run pnpm dlx ultracite fix before committing to ensure compliance.