Skip to content

Cursor Agent Skills

The repository ships a set of Cursor Agent Skills under .cursor/skills/. They encode how this monorepo actually works, so an AI agent produces work that matches our architecture instead of generic TypeScript.

They are committed to the repository, so everyone gets the same behaviour, and improving them is a normal pull request.

Why they exist

Two problems.

First, an agent that does not know this repository will invent plausible-looking wrong answers: put a feature in the wrong service, hand-edit a generated file, assume pnpm test covers a workspace that is not in the vitest projects list, or introduce ESLint into a repository that uses oxlint.

Second, and more importantly: every completed piece of work should make the next one easier. Requirements, plans, review findings, conventions and solved problems are worth more than the diff that produced them, but only if they are captured somewhere the next person will find them. That is what the loop below is for.

The Compound Engineering loop

Brainstorm → Plan → Work → Simplify → Review → Compound

Each step produces an artifact the next step consumes, and the last step feeds knowledge back into the repository.

StepSkillProduces
1. Brainstorm/feyenoord-brainstormA requirements-only document in docs/brainstorms/
2. Plan/feyenoord-planAn implementation-ready plan in docs/plans/
3. Work/feyenoord-workThe implementation, plus an implementation report
4. Simplify/feyenoord-simplify-codeA tidied diff and a simplification report
5. Review/feyenoord-code-reviewA report-only review with P0–P3 findings
6. Compound/feyenoord-compoundDurable docs update or ADR under apps/docs/

You do not have to run all six. A one-line bug fix does not need a brainstorm. A change that touches three services does.

How to invoke

Type / in Agent chat and pick the skill. Every skill folder under .cursor/skills/ automatically becomes a /name command — there is no registration step.

/feyenoord-plan implement the partner benefit auto-order flow from
docs/brainstorms/2026-07-08-partner-benefits-requirements.md

You can also type @ and select a skill to attach it as context rather than run it.

Two kinds of skill

Workflow skills are explicit-only (disable-model-invocation: true). They run when you ask for them, never on their own.

Domain skills are automatically selected. Each declares paths globs, so Cursor attaches feyenoord-loyalty when you are working in apps/loyalty/, without you asking. You can still invoke one directly (/feyenoord-web) when you want its rules loaded before touching any file.

Available skills

Workflow (explicit)

feyenoord-brainstorm, feyenoord-plan, feyenoord-work, feyenoord-simplify-code, feyenoord-code-review, feyenoord-compound.

Shared base

feyenoord-domain-map — the routing table from paths to skills, the full validation command matrix, the dependency rules, and the artifact templates. Every workflow skill reads it first. Invoke it directly (/feyenoord-domain-map) when you want to know which skills a change would load, or what the right command for a workspace is.

Domain (automatic, scoped by path)

SkillCovers
feyenoord-legacy-apiapps/api — the deprecated Express + Apollo monolith
feyenoord-services-coreShared architecture of the four federated services
feyenoord-identityapps/identity overlay
feyenoord-loyaltyapps/loyalty overlay — the reference implementation
feyenoord-businessapps/business overlay
feyenoord-notificationsapps/notifications overlay
feyenoord-api-gatewayapps/api-gateway — Traefik routing
feyenoord-graphql-federationapps/graphql-router and the subgraph schema contract
feyenoord-webapps/web — Next.js
feyenoord-nativeapps/native — Expo
feyenoord-match-gatewayapps/match-gateway — live match pipeline
feyenoord-sanityapps/sanity — the Studio
feyenoord-sanity-functionsapps/sanity-functions and sanity.blueprint.ts
feyenoord-shared-packagespackages/**

Cross-cutting (loaded on topic, not only on path)

SkillLoad when
feyenoord-securityAuth, tokens, PII, secrets, permissions, any identity flow. Mandatory for those.
feyenoord-observabilityLogging, tracing, metrics, alerting
feyenoord-testing-validationChoosing which checks to run, vitest projects list, Playwright, CI
feyenoord-unit-testsWriting or editing unit tests. Mandatory for every unit test, including subagents.

How domain selection works

A workflow skill reads feyenoord-domain-map, matches the changed or planned paths against its routing table, and loads every matching domain skill. Cross-cutting skills load on topic.

Worked examples:

ChangeSkills loaded
A resolver in apps/apifeyenoord-legacy-api, feyenoord-testing-validation
A feature in apps/identityfeyenoord-services-core, feyenoord-identity, feyenoord-graphql-federation, feyenoord-security, feyenoord-testing-validation
A subgraph field plus router recompositionfeyenoord-services-core, the service overlay, feyenoord-graphql-federation, feyenoord-testing-validation
A apps/web page using @repo/api-sdkfeyenoord-web, feyenoord-shared-packages, feyenoord-legacy-api, feyenoord-testing-validation
A breaking change in @repo/corefeyenoord-shared-packages plus every consumer's domain skill

feyenoord-services-core is always loaded alongside a service overlay: the overlay only records what that service does differently.

Expected artifacts and where they live

ArtifactLocationIn git?
Requirementsdocs/brainstorms/YYYY-MM-DD-<slug>-requirements.mdNo
Plandocs/plans/YYYY-MM-DD-NNN-<type>-<slug>-plan.mdNo
Durable docsMatching category under apps/docs/Yes
ADRapps/docs/architecture/decisions/NNN-<title>.mdYes

The repository-root docs/ directory is gitignored (.gitignore, /docs/). Requirements and plans are per-change scaffolding and stay local. Anything that should outlive the change goes into apps/docs/ in the category where readers already look (API patterns, architecture, development, CI/CD, reference) - or as an ADR when it is a decision. That knowledge is reviewed and published with the docs site.

If a plan or set of requirements needs team review before implementation, paste it into the normal review channel — do not assume a colleague can see the file.

Approval checkpoints

The skills stop and wait at three points by design:

  1. After brainstorm — the requirements need a human read before planning.
  2. Plan approval/feyenoord-work requires the plan's ## Status to say Approved. Open decisions in the plan must be resolved first.
  3. Review findings/feyenoord-code-review never applies its own findings. You choose which to fix.

/feyenoord-plan will also stop mid-run and ask when two valid approaches have materially different consequences.

Git and remote safety

The skills are instructed to:

  • Never discard unrelated local changes (no reset --hard, checkout --, clean, or stashing someone else's work).
  • Propose a branch rather than committing to main or a release/* branch.
  • Commit only when asked, with conventional-commit messages, and never add an agent as co-author.
  • Never push, open a pull request, merge, deploy, run a migration against a shared database, or change remote infrastructure without explicit permission for that specific action.

lefthook still runs oxlint --fix, oxfmt --write and commitlint on commit, as usual.

Updating a skill

Skills are code. Change them the same way.

  1. Edit the relevant SKILL.md (or a file in its references/).
  2. Every repository-specific claim needs evidence. Cite the path.
  3. Do not promote a single implementation into a rule. Require a second occurrence, a test, documentation, an ADR, or a configuration boundary first.
  4. Keep SKILL.md under roughly 500 lines and keep references/ one level deep — deeper nesting risks partial reads.
  5. Open a pull request. Skill changes get reviewed like any other change.

The frontmatter fields Cursor supports are name (must match the folder), description, paths, disable-model-invocation and metadata. Nothing else.

Reporting incorrect or stale guidance

If a skill tells you something wrong, that is a bug and it will keep costing time until it is fixed.

  • Wrong or outdated fact (a moved path, a renamed command, a superseded pattern): fix it in the same pull request as the work that revealed it, and say so in the description.
  • A convention you disagree with: raise it with the team first. A skill is a shared standard, not a personal preference.
  • A missing domain: open a pull request adding a skill, or note the gap in the routing table in feyenoord-domain-map.

/feyenoord-compound explicitly reports skill corrections it finds, so running it at the end of a change is the cheapest way to keep these files honest.

Detecting staleness

The main risks are a path that moved, a command that was renamed, and a convention that changed. Signals to watch for:

  • A skill references a file that no longer exists - a code review of a rename should catch it.
  • A validation command in a skill is not in package.json or turbo.json.
  • Two skills contradict each other.

There is no automated linter for skills - Cursor does not ship one. Confirm a skill is discovered by opening Customize → Skills in the sidebar.

Limitations

  • Composition relies on instructions, not an API. Cursor has no documented mechanism for one skill to load another. Workflow skills tell the agent to read a domain skill's SKILL.md by path, and domain skills also auto-attach via their paths globs. It works, but it depends on the agent following prose.
  • paths scoping is best-effort. A domain skill attaches when matching files are in context. During planning, before any file is opened, the workflow skill's explicit read is what actually loads it.
  • No validation tooling. Cursor ships no skill linter.
  • Skills describe the repository as of the date they were written. They will drift. The compound step is the mechanism that corrects that; if nobody runs it, drift wins.
  • Requirements and plans are not shared. A consequence of docs/ being gitignored. If that becomes painful, the alternative is to un-ignore docs/ and accept agent-generated markdown in pull requests.
  • Several known gaps in the repository are documented inside the skills rather than fixed: apps/identity having no unit tests yet (project is wired), stale generated output in apps/notifications, and a rover version mismatch in apps/graphql-router. They are flagged so plans do not assume otherwise.