跪拜 Guibai
← Back to the summary

How to Wire Company-Wide Coding Standards into Cursor Agent Skills

Full-Project Skills Adaptation: Turning a "Code-Writing Agent" into a "Colleague Who Follows Your Standards"

Using Cursor Agent Skills and a B-side frontend self-test skill as an example, this explains how to connect company-level standards to a specific project, rather than just piling up a never-ending prompt.

If you've been using agents like Cursor / Claude Code to write business code recently, you've probably run into the same kind of problems:

In our HR backend (Vue 3 + Vite + TypeScript + Element Plus, evolved from vue-pure-admin), we split this into two layers:

  1. Project Constitution: AGENTS.md holds only the constraints that "always hold true for this repo."
  2. On-Demand Skills: Processes like "test-ready self-check" and "interaction walkthrough" are made into Skills, loaded only when needed.

Below, using the already-implemented frontend-self-test as an example, I'll explain how to do full-project adaptation.


1. First, Distinguish: What Rule, AGENTS.md, and Skill Each Manage

Many people start by stuffing all standards into .cursorrules or an Always Apply Rule. It works short-term but inevitably bloats over time.

Carrier Load Timing Suitable For Not Suitable For
AGENTS.md / Always Rule Almost every conversation Tech stack, directory responsibilities, minimal changes, package manager, prohibitions Dozens of pages of interaction details, acceptance checklist for a single requirement
.cursor/rules/*.mdc Triggered by file glob Local conventions for a certain file type (e.g., only constraining src/api/**) Cross-page complete workflows
Agent Skill Agent judges relevance, or you manually /skill-name Reusable processes: how to self-test, how to release, how to align tables Project positioning, default tech choices

Cursor's official positioning for Skills is also clear: it is a version-manageable, on-demand expandable capability pack. A Skill is a directory whose core is SKILL.md; detailed rules can be split into reference.md and scripts/. The agent first sees the name + description, and only reads the body and referenced files when actually executing. This is called progressive disclosure: the main file stays short, and details are opened on demand.

In one sentence:

Stacked together, this is full-project adaptation, not just "writing one more Markdown file."


2. The Goal of Full-Project Adaptation Is Not "A Few More Skill Files"

Once adaptation is done, anyone on the team opening this repo should see these results:

  1. New colleagues don't need to memorize standards first. Saying "help me self-test this change" makes the Agent read the standards, scope the area, and produce a report on its own.
  2. Company and project don't pollute each other. Company-level B-side interaction standards can be reused across multiple backends; this repo's Vue / directory / permission patterns are only written at the project layer.
  3. Trigger words are stable. "Self-test," "test-ready self-check," "interaction standard check" all hit the same Skill, rather than relying on someone remembering the full filename.
  4. Context doesn't explode. Changing a resignation form day-to-day won't flood the entire 14-chapter interaction standard into the System Prompt.

The structure we ultimately landed on looks like this:

hr-web/
├── AGENTS.md                          # Project constitution + custom Skill manifest
├── .gitmodules                        # Company Skills repo as submodule
├── skills/                            # Upstream: universal Skill source
├── .cursor/skills/
│   └── frontend-self-test/
│       ├── SKILL.md                   # Process: how to self-test, how to report
│       └── reference.md               # Details: 14 categories of interaction musts/prohibitions
└── package.json
    ├── update:skills                  # Pull submodule
    └── skills:sync:cursor             # Sync to .cursor/skills

This is a very important chain:

Company Skills Repo  →  git submodule  →  sync into .cursor/skills  →  Cursor auto-discovers
                         ↑
                   AGENTS.md registers trigger words

.cursor/skills/ is the project-level directory that Cursor actually scans. If the source files in the submodule aren't synced over, the Agent cannot see them. Cloud Agent and remote SSH also can't read your local ~/.cursor/skills/, so to make it consistent for the whole team and all environments, Skills must enter the repo.


3. How to Write the Project Constitution: AGENTS.md Only Contains What "Always Holds True"

Taking this repo as an example, AGENTS.md does not repeat the full interaction standard text; it only locks in what the Agent "will do by default" in this HR backend:

These contents should take effect in every conversation, so they go in the constitution layer.

The Skill manifest gets its own section, acting only as a "routing table":

## Project Custom SKILLS Manifest

When user input contains the following keywords, automatically invoke the corresponding custom skill:

- **frontend-self-test** (Frontend Self-Test)
  - Trigger keywords: self-test, frontend self-test, test-ready self-check, interaction standard check,
    B-side backend frontend code walkthrough, self-check checklist check, backend project self-test
  - Directory: skills/skills/frontend-self-test

Two easily overlooked points here:

  1. Trigger words must be written in natural language. The Agent matches against the description and conversational intent, not the internal codename in your head. Only writing frontend-self-test means a colleague saying "run me through it before testing" often won't hit.
  2. The directory can point to the source repo, but what Cursor consumes is the synced .cursor/skills. The manifest is an index for humans; the discovery mechanism still relies on Cursor's official directory.

4. Using the Self-Test Skill as an Example: What a Qualified Skill Looks Like

frontend-self-test doesn't solve "is this code ugly?" but rather:

Against the "B-side Backend Frontend Universal Interaction Implementation Standard," perform a pre-test walkthrough on this change and give actionable conclusions in the conversation.

It is deliberately made into two files, corresponding to the progressive disclosure mentioned earlier.

1. SKILL.md: Only Process, No Encyclopedia

The frontmatter clearly states both what it does and when to do it:

---
name: frontend-self-test
description: >
  Based on the "B-side Backend Frontend Universal Interaction Implementation Standard," perform a pre-test self-check on frontend code changes:
  analyze git diff or specified files, walk through item by item for request states, duplicate submission prevention, data refresh,
  form validation, list pagination, modals/drawers, state distinction, async tasks, permissions, search race conditions,
  upload/download, operation feedback, and other interaction rules, and report the self-test results in the conversation.
  Use when the user requests frontend self-test, test-ready self-check, interaction standard check,
  B-side backend frontend code walkthrough, self-check checklist check.
---

description gets injected into the Agent's skill directory, essentially a "job posting." Writing it in the third person, with trigger scenarios, is far more useful than "I can help you self-test."

The body only specifies five steps and requires copying a checklist to track progress:

  1. Determine scope: prioritize git diff master...HEAD; if there are uncommitted changes, also include the working tree diff.
  2. Identify categories: among the 12 interaction categories, only walk through those actually touched by the change; mark the rest "Not Applicable."
  3. Check against detailed rules: for each item, give only three conclusions — Pass / Risk / Needs Manual Verification.
  4. Run existing engineering checks: run lint, typecheck, test only if they exist; do not install dependencies without permission, do not proactively build.
  5. Report using a fixed template: do not save a separate report file, to avoid polluting the repo with Markdown.

Among these five steps, the most valuable part isn't "check for loading" but locking down the Agent's degrees of freedom:

Without these boundaries, the Agent easily turns into "a code reviewer who wants to critique everything."

2. reference.md: Details Externalized, Read Only When Used

The beginning of SKILL.md states: before the walkthrough, you must first read reference.md. The standard text covers roughly 14 categories, including:

  1. Requests must have state
  2. Prevent duplicate submissions
  3. Update the page promptly on success
  4. Don't discard user input on failure
  5. Form validation points to the field
  6. List queries and pagination
  7. Returning to a list preserves the context
  8. Modals and drawers
  9. Separate loading / empty data / failure / no permission states
  10. Async long-running tasks
  11. Permissions
  12. Search and race conditions
  13. Upload and download
  14. Operation feedback

The key design is: must-do / prohibited appear in pairs, and quantifiable items are written as 【Judgment Criteria】. For example:

What the Agent fears most are non-judgeable phrases like "poor experience" or "not elegant enough." The more the criteria resemble test cases, the more stable the walkthrough results.


5. Connecting Universal Standards to a Specific Project: Where Does Adaptation Happen?

A company-level Skill won't write "which Element Plus component you use." It only says "the button must enter a loading state during submission." The actual connection to the HR backend relies on the project constitution + the existing implementations in the repo.

Below, using patterns already present in this repo, I'll illustrate what the Agent should "translate" them into.

1. Request State and Duplicate Prevention: Mapping to loading + Shared Modal

The standard says: button immediately enters loading on click, recovers when the request ends, and must also recover on failure.

The resignation application modal in the project is a typical implementation: LoadingDialog receives :loading, the confirm button binds the same state, and it closes in finally.

<LoadingDialog
  v-model="dialog.visible"
  :loading="loading"
  :title="dialog.title"
  destroy-on-close
>
  <!-- form -->
  <el-button type="primary" :loading="loading" @click="saveForm">Submit</el-button>
</LoadingDialog>
function handleSubmit() {
  loading.value = true
  const request = dialog.title === "Resignation Application" ? leaveAdd : leaveDirect
  request(params)
    .then(() => {
      ElMessage.success("Submitted successfully")
      close()
      emits("ok")
    })
    .finally(() => {
      loading.value = false
    })
}

During self-test, the Agent shouldn't invent a new "global full-screen Loading" but should check:

Secondary confirmation is also common. In this repo, before submission, an ElMessageBox may pop up; if the user clicks cancel, the loading that was already set to true must be flipped back, otherwise the button spins forever. This is the concrete form in the project of the standard's "page recovers to operable after request failure / cancellation."

2. Refresh on Success: Mapping to "Close Modal + Emit ok"

The standard requires the page to update immediately after add/edit/delete. In this repo, many drawers and modals don't modify the list within themselves but instead:

ElMessage.success("Submitted successfully")
close()
emits("ok")

The parent list hears ok and then re-fetches the paginated data. During self-test, you must follow the emit to glance at the parent page; you can't just judge "Pass" because the child component "popped a success toast." This is the balance between "only draw conclusions based on changed code" and "related call chains must be read": if you changed a form, you must at least open its parent index.vue.

3. API Layer: Mapping to src/api + Unified request

AGENTS.md prohibits hand-writing axios in pages. The self-test skill itself doesn't audit architecture, but after project adaptation, if the Agent sees a new axios.post appear in a page, it should treat it as a risk: it violates the project constitution and bypasses the unified 401 handling, error prompts, silent, unloading, and other conventions.

This repo's @/utils/request already handles tokens, login expiration redirects, and permission timestamp refresh. The Skill doesn't need to copy the interceptor source code into itself; the project constitution naming "reuse request" is sufficient.

4. Permissions: Mapping to v-auth / hasPerms, Don't Write Roles Yourself

The standard states: frontend permissions only control display and entry points, not serve as security checks; don't hardcode roles in the frontend.

The project counterpart is directives, not if (user.role === 'admin'):

// src/directives/perms/index.ts
!hasPerms(value) && el.parentNode?.removeChild(el)

When walking through the "Permissions" category, check:

There's no need to mandate a site-wide uniform "hide" or "gray out" because the standard already lists this as a judgment criterion.

5. Form Validation and Failure Preservation: Mapping to el-form Field Rules

The standard requires errors to appear next to the field and the form not to be cleared on submission failure. Element Plus's el-form-item + :rules is the project's default solution.

In the resignation form, when "Add to blacklist" is Yes, the blacklist reason and description fields appear with required rules. This is conditional field validation; during self-test, check: after hidden fields are re-shown, are the rules still present; after submission failure, is formData still there.

There's one "translation" in the project worth the Agent learning: some pages, on validation failure, additionally call ElMessage.error('Please complete the form'). What the standard prohibits is "only saying the form has errors at the top, leaving the user unable to find the field." If field-level el-form errors already exist, an extra summary message is generally not judged a defect; only if there's just a global toast with no field hints is it recorded as a risk.

6. Engineering Checks: Mapping to the Scripts This Repo Actually Has

Step 4 of the Skill requires reading package.json first. This repo actually has:

Script During Self-Test
pnpm lint:eslint Only run on changed files, acceptable
pnpm typecheck Acceptable
pnpm test Does not exist, skip and state clearly
pnpm build Only run if user explicitly requests

"Run if exists, skip if not" is written into the Skill to prevent the Agent from suddenly executing npm test or installing Vitest in the HR backend. This is project adaptation: universal process + local script facts.


6. What a Real Trigger Should Look Like

Suppose you've finished changing "Resignation Application" and the list export, and you say to the Agent:

Help me do a frontend self-test, run through the interaction standards before testing.

Following the adapted behavior, it shouldn't directly modify code but should:

Step 1, scope the area:

git --no-pager diff master...HEAD
git status --porcelain
# If there are uncommitted changes, also:
git --no-pager diff

Step 2, identify categories. Taking the resignation module above as an example, it would typically hit: Request & Loading, Duplicate Submission Prevention, Form Validation, Modal/Drawer, Operation Feedback, Upload/Download; Permissions, Search Race Conditions, Async Tasks might be marked Not Applicable.

Step 3, check against reference.md item by item and give conclusions; risks must include file:line number.

Step 4, run eslint / tsc --noEmit on changed files.

Step 5, report using the template, not generating a new Self-Test Report.md:

## Self-Test Results
Scope: employeeRelations/leave under index / addForm / exportForm
Categories involved: Request & Loading, Duplicate Submission Prevention, Form Validation, Modal, Upload/Download, Operation Feedback

### Pass (n)
- 【Request & Loading】Submit button binds loading, finally closes
- 【Form Validation】Required fields use el-form-item rules

### Risk (n)
- 【Duplicate Submission Prevention】xxx.vue:408 — loading set before secondary confirmation,
  if confirmation logic branches without reset, button may freeze — add loading = false in cancel branch

### Needs Manual/Runtime Verification (n)
- 【Modal】After destroy-on-close, does reopening retain validation red text — open, fill incorrectly, close, reopen and check

### Not Applicable (n)
- 【Search Race Condition】No input-triggered search in this change
- 【Async Long Task】Export is still synchronous download, not routed through task center

Engineering checks: eslint run on changed files; typecheck passed; no test script, skipped
Conclusion: 1 risk to fix; does not meet test-ready standard before fix

Risks are sorted by severity: duplicate submission causing dirty data, losing user input, page freeze always rank above "copy not friendly enough."

This output has two benefits: QA can use it as a pre-test checklist; after you fix the risks, you can have the Agent only re-walk the corresponding items, not re-audit the entire page.


7. Pitfalls We Hit When Rolling This Out Across the Project

1. Stuffing the Full Standard Text into Always Rule

The interaction standard is very long. Always loading it squeezes out business code and git diff. The correct split is: AGENTS.md only keeps "there is a self-test skill, trigger words are these"; the detailed rules stay in the Skill's reference.md, read only on the day of the walkthrough.

2. Only Having Submodule, Not Syncing to .cursor/skills

The company repo is suitable as a single source of truth, upgraded via git submodule. But Cursor scans .cursor/skills/ and .agents/skills/. We use:

pnpm update:skills          # git submodule update --init --remote
pnpm skills:sync:cursor     # sync to the directory Cursor can discover

If someone freshly cloning the repo only runs pnpm install and forgets to pull the submodule, they'll get "the docs mention a self-test skill, but the Agent never uses it in conversation."

3. Description Too Abstract

"Helps improve code quality" won't be triggered. "Based on X standard, walk through diff, used when user says self-test/test-ready self-check" will. Writing in the commands the team already uses internally is more useful than crafting a pretty English summary.

4. Skill and Project Constitution Fighting for Authority

The self-test standard is company-level, cross-project; "don't add new dependencies," "don't modify vite.config.ts," "user-visible copy must sync locales/zh-CN.yaml and en.yaml" belong to this repo. Don't write the latter into a universal Skill, or it will misfire when synced to other projects. Conversely, don't copy the 14 chapters of interaction details into AGENTS.md, or you'll miss changes when upgrading the standard.

5. Letting the Agent Casually Change Business Logic

The Skill states: if the user didn't ask to fix, only report. This aligns with this repo's "minimal changes, no casual refactoring." Otherwise, one "help me self-test" turns into a scope-creeping refactor.

6. Treating Personal Skills as Project Adaptation

~/.cursor/skills/ only works on your machine. Cloud Agent, colleagues, and agents in CI can't see it. The hallmark of full-project adaptation is: after cloning the repo + running the sync script, the behavior is reproducible.


8. A Directly Copyable Adaptation Checklist

If you want to connect the same set of company Skills to the next backend project, follow this order; you don't need to invent new standards from scratch.

1. Write the Project Constitution First (half an hour to half a day)

2. Connect the Skill Source, Don't Copy-Paste

3. Every Skill Follows "Short Process + Externalized Details"

4. Do One Project Translation, But Don't Modify the Universal Standard Text

Translation happens in the constitution and examples, e.g.:

Universal Standard This Project's Counterpart
Button loading, duplicate prevention loading + :loading + finally
Table area loading Table / list container v-loading, don't lock layout
Field-level validation el-form + el-form-item rules
Permission control v-auth / hasPerms, don't hardcode roles
Refresh on success emits('ok') then parent re-fetches list
Download feedback Button loading + downFile; long tasks escalate to async
Engineering checks lint:eslint, typecheck, skip if no tests

5. Prototype with a Real Requirement

Pick a module that simultaneously has a list, modal, and export (we used resignation under Employee Relations), and just say "self-test" to the Agent. See if it will:

If this step fails, it means the trigger words, directory, or process instructions aren't connected yet; don't continue rolling out more Skills.


9. What Can Be Connected After the Self-Test Skill

frontend-self-test is suitable as the first project-level Skill because it meets three conditions:

  1. High frequency: needed before almost every requirement goes to testing.
  2. Judgeable: easier to write criteria for than "code elegance."
  3. Complementary to the project constitution: one manages how to change the repo, the other manages whether the change looks like a test-ready backend.

On the same layered foundation, it's easy to connect later:

Still recommended: one Skill does only one type of task. Full-project adaptation is "constitution + skill directory," not "one super prompt pack to rule them all."


10. Conclusion

An Agent won't automatically become a colleague familiar with your backend. What it lacks isn't more adjectives but three things written into the repo:

  1. What this project isAGENTS.md
  2. How to do this type of task — the process and output template in SKILL.md
  3. How to judge right and wrong — the musts/prohibitions with criteria in reference.md

Company standards live upstream; the project connects them via submodule sync and constitution-layer translation; Cursor only consumes .cursor/skills. Using the self-test skill as an example, we didn't make the Agent learn "HR business"; we only made it, before every test submission, check loading, duplicate submission, refresh, validation, pagination, and permissions against the same checklist.

This is the result that full-project Skills adaptation truly aims to deliver: change the colleague, change the machine, change the conversation — the walkthrough standard remains.