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 → CompoundEach step produces an artifact the next step consumes, and the last step feeds knowledge back into the repository.
| Step | Skill | Produces |
|---|---|---|
| 1. Brainstorm | /feyenoord-brainstorm | A requirements-only document in docs/brainstorms/ |
| 2. Plan | /feyenoord-plan | An implementation-ready plan in docs/plans/ |
| 3. Work | /feyenoord-work | The implementation, plus an implementation report |
| 4. Simplify | /feyenoord-simplify-code | A tidied diff and a simplification report |
| 5. Review | /feyenoord-code-review | A report-only review with P0–P3 findings |
| 6. Compound | /feyenoord-compound | Durable 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.mdYou 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)
| Skill | Covers |
|---|---|
feyenoord-legacy-api | apps/api — the deprecated Express + Apollo monolith |
feyenoord-services-core | Shared architecture of the four federated services |
feyenoord-identity | apps/identity overlay |
feyenoord-loyalty | apps/loyalty overlay — the reference implementation |
feyenoord-business | apps/business overlay |
feyenoord-notifications | apps/notifications overlay |
feyenoord-api-gateway | apps/api-gateway — Traefik routing |
feyenoord-graphql-federation | apps/graphql-router and the subgraph schema contract |
feyenoord-web | apps/web — Next.js |
feyenoord-native | apps/native — Expo |
feyenoord-match-gateway | apps/match-gateway — live match pipeline |
feyenoord-sanity | apps/sanity — the Studio |
feyenoord-sanity-functions | apps/sanity-functions and sanity.blueprint.ts |
feyenoord-shared-packages | packages/** |
Cross-cutting (loaded on topic, not only on path)
| Skill | Load when |
|---|---|
feyenoord-security | Auth, tokens, PII, secrets, permissions, any identity flow. Mandatory for those. |
feyenoord-observability | Logging, tracing, metrics, alerting |
feyenoord-testing-validation | Choosing which checks to run, vitest projects list, Playwright, CI |
feyenoord-unit-tests | Writing 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:
| Change | Skills loaded |
|---|---|
A resolver in apps/api | feyenoord-legacy-api, feyenoord-testing-validation |
A feature in apps/identity | feyenoord-services-core, feyenoord-identity, feyenoord-graphql-federation, feyenoord-security, feyenoord-testing-validation |
| A subgraph field plus router recomposition | feyenoord-services-core, the service overlay, feyenoord-graphql-federation, feyenoord-testing-validation |
A apps/web page using @repo/api-sdk | feyenoord-web, feyenoord-shared-packages, feyenoord-legacy-api, feyenoord-testing-validation |
A breaking change in @repo/core | feyenoord-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
| Artifact | Location | In git? |
|---|---|---|
| Requirements | docs/brainstorms/YYYY-MM-DD-<slug>-requirements.md | No |
| Plan | docs/plans/YYYY-MM-DD-NNN-<type>-<slug>-plan.md | No |
| Durable docs | Matching category under apps/docs/ | Yes |
| ADR | apps/docs/architecture/decisions/NNN-<title>.md | Yes |
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:
- After brainstorm — the requirements need a human read before planning.
- Plan approval —
/feyenoord-workrequires the plan's## Statusto sayApproved. Open decisions in the plan must be resolved first. - Review findings —
/feyenoord-code-reviewnever 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
mainor arelease/*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.
- Edit the relevant
SKILL.md(or a file in itsreferences/). - Every repository-specific claim needs evidence. Cite the path.
- Do not promote a single implementation into a rule. Require a second occurrence, a test, documentation, an ADR, or a configuration boundary first.
- Keep
SKILL.mdunder roughly 500 lines and keepreferences/one level deep — deeper nesting risks partial reads. - 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.jsonorturbo.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.mdby path, and domain skills also auto-attach via theirpathsglobs. It works, but it depends on the agent following prose. pathsscoping 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-ignoredocs/and accept agent-generated markdown in pull requests. - Several known gaps in the repository are documented inside the skills rather than fixed:
apps/identityhaving no unit tests yet (project is wired), stale generated output inapps/notifications, and a rover version mismatch inapps/graphql-router. They are flagged so plans do not assume otherwise.