tangcent/easy-api · Archived

easy-api-assistant

Help author EasyApi rule files (.easyapi/ folder). Invoke when the user is editing an EasyApi rule file or asks to add/modify EasyApi rules (annotations, field rename, custom headers, etc.).

First seen Jul 8, 2026

Installation

$ npx skills add tangcent/easy-api --skill easy-api-assistant

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 236
License LICENSE
Default branch master
Open issues 0
Status Archived

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 32,889 B
  • docs SUMMARY.md 216 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 2 installs

SKILL.md

EasyApi Rule Authoring Assistant

This skill is the external mirror of EasyApi's built-in rule-authoring agent. It helps you write or modify EasyApi rule files (.rules / .properties files in .easyapi/) that the EasyApi IntelliJ plugin reads to customise API export (Postman/Markdown/cURL/Hoppscotch), field naming, annotations, and more.

It runs the same perceive → reason → act loop as the built-in agent and exposes the same capability surface: the same rule guide and key catalog, and CLI equivalents of every built-in perception tool. The only difference is how each capability is delivered — the built-in agent calls IntelliJ PSI tools; you read files and search the codebase directly.

When to Use

Invoke this skill when:

  • The user opens or edits any file in the project's .easyapi/ folder or

the global ~/.easyapi/ folder.

  • The user asks to "add a rule", "rename a field", "ignore a class", "add a

header to every POST", etc. in the EasyApi context.

  • The user mentions easy.api, EasyApi, or easyapi in a request about

config or rule authoring.

Bundled Knowledge Base (read these first — they ARE the built-in agent's docs)

This skill ships mirrors of the in-plugin agent's authoritative sources, kept in sync by Gradle tasks in the easy-api repo. Run ./gradlew syncSkill to refresh all four mirrors in one command (it aggregates syncKnowledgeBase, syncAgentCatalog, syncRuleKeySchemes, and syncRuleContexts):

  1. docs/ — the long-form knowledge-base pages the plugin bundles for its

built-in agent's getplugindoc tool. Kept in sync by the syncKnowledgeBase Gradle task.

  1. ai/detection/ + ai/key-guides/ — the per-detection / per-key guide

catalog the in-plugin agent loads via PromptCatalog (the same files getdetectionprompt and getruledetail read at runtime). Kept in sync by the syncAgentCatalog Gradle task.

  1. rule-keys.json + rule-keys.md — the auto-generated rule-key

scheme catalog. RuleKeySchemeExporter reflects every RuleKeys object (general + channel + framework) and the implicit keys, and emits the full self-describing scheme* of each key — the same information the in-plugin agent gets from its listrulekeys tool. Regenerated by the syncRuleKeySchemes Gradle task, so **any key added to a *RuleKeys object is picked up automatically** (a brand-new channel/framework must be registered in RuleKeyCatalog.SOURCES).

  1. rule-contexts.json + rule-contexts.md — the auto-generated

script-context mirror of the in-plugin getrulecontext tool. RuleContextExporter reuses the exact same key assembly (so it covers rule keys and the implicit keys read via configReader.getFirst — one interface, the same one the built-in agent sees) and, per key, reflects the runtime bindings + script-object method signatures. Regenerated by the syncRuleContexts Gradle task.

All mirrors are content-equality-checked and idempotent, so the rule content the built-in and external agents produce is identical. Always read the relevant page first — do not rely on memory or guess syntax.

Bundled file Built-in getplugindoc name What it covers
docs/rule-guide.md rule-guide The source of truth. Rule file format, filter syntax, expression prefixes, Groovy binding reference, recipes, the Custom-Pattern Catalog, and the Workflow-Pattern Catalog (cross-endpoint auth/signing/refresh recipes).
docs/index.md index Knowledge-base index / topic map.
docs/README.md overview Overview of EasyApi concepts.
docs/settings-guide.md settings-guide Plugin settings reference.
docs/usage-guide.md usage-guide Usage guidance.
docs/postman-script-reference.md postman-script-reference Postman-compatible pm.* Groovy scripting (pre-request / post-response only).
rule-keys.md (built-in listrulekeys tool) Complete rule-key catalog, auto-generated from every key's self-describing scheme (full scheme in rule-keys.json).
rule-contexts.md (built-in getrulecontext tool) Per-key script-context (bindings + callable script-object method signatures), auto-generated by reflecting the same rule keys. Fetch one key with scripts/getkeycontext.sh.

Toolset — CLI mirrors of the built-in agent tools

The built-in agent has a fixed set of perception/action tools. You provide equivalent capability by reading files and searching the codebase. Use the mapping below so your workflow tracks the built-in agent's.

EasyApi-domain tools (bundled as scripts/)

These mirror the EasyApi-specific perception tools. Run them from the project root (the CWD when the assistant is invoked). They auto-detect the project root and ~/.easyapi/ so you never hard-code paths.

Built-in tool Your equivalent What it does
listrulekeys Read bundled rule-keys.json / rule-keys.md Lists every supported rule key with its full self-describing scheme (auto-generated).
getplugindoc Read the bundled *.md pages above Reads a knowledge-base page.
readrulefile scripts/readrulefile.sh <name> Reads a rule file by name. Supports global: / project: scope prefixes. Resolves against tracked .easyapi/ dirs — never guesses home paths.
getexistingrulesforkey scripts/getexistingrulesforkey.sh <key> [<key>...] Finds all configured values for a key across project + global rule files. Prints file:line: <line content> so you can reason about precedence.

scripts/listrulefiles.sh is also bundled — it lists every
.properties / .rules file in <project>/.easyapi/ and ~/.easyapi/,
labeled [global] / [project] (ambient equivalent of
RuleFileResolver.listRuleFiles).

Usage examples:

# List all rule files the plugin will load
scripts/list_rule_files.sh

# Read a rule file by name (scope-prefixed or bare)
scripts/read_rule_file.sh security.properties
scripts/read_rule_file.sh global:jwt.rules
scripts/read_rule_file.sh project:custom.rules

# Check if a key is already configured (avoid duplicates — Quality Rule 1)
scripts/get_existing_rules_for_key.sh field.name
scripts/get_existing_rules_for_key.sh method.doc method.additional.header

Catalog recipe tools (mirrors of in-plugin getdetectionprompt / getruledetail)

The built-in agent's decomposed prompt catalog (Phase A of the in-plugin agent) lives under src/main/resources/ai/{detection,key-guides}/ in the easy-api repo. This skill ships a verbatim copy under ai/{detection,key-guides}/ next to SKILL.md, kept in sync by the syncAgentCatalog Gradle task. CLI scripts mirror the in-plugin perception tools that read that catalog — same id space, same body content, same error shape — so your workflow tracks the in-plugin agent's exactly.

Key discovery now goes through rule-keys.md (the auto-generated full catalog, mirror of the in-plugin listrulekeys tool): it lists every supported rule key — including the implicit keys with no RuleKey constant — with its full self-describing scheme. The key-guide index (which keys carry a per-key guide file) is folded into getkeyguide.sh --list.

Built-in tool Your equivalent What it does
getdetectionprompt scripts/getdetectionprompt.sh <id> Fetches the full detection recipe for one detection family by id (e.g. spring-filters-interceptors, static-auth). Strips the YAML front-matter; prints the markdown body. Unknown id → error: unknown detection id: <id> on stderr, exit 1.
getruledetail (by-key path) scripts/getkeyguide.sh <key> Fetches the full per-key guide by rule key (e.g. postman.test, method.additional.header). Strips the YAML front-matter; prints the body. --list lists every key that has a guide. Unknown key → error: unknown rule key: <key> on stderr, exit 1.
listrulekeys rule-keys.md / rule-keys.json Lists every supported rule key with its full self-describing scheme (auto-generated).
getrulecontext scripts/getkeycontext.sh <key> Fetches the runtime script-context for one rule key (auto-generated mirror): the key's execution mode, per-key bindings, and the full callable script-object method signatures (it/request/response/api/…). Unknown key → error: unknown rule key: <key> on stderr, exit 1.
SystemPromptBuilder.indexMessage("detection") scripts/list_detections.sh Lists every detection family: id — title: cue per file (lexicographic by filename).
SystemPromptBuilder.indexMessage("key-guides") scripts/getkeyguide.sh --list Lists every per-key guide: key — title: cue per file. Complements (does NOT replace) rule-keys.md, which lists every supported rule key including those without a per-key guide file.

Usage examples:

# Discover which detection families exist before proposing rules
scripts/list_detections.sh

# Fetch the recipe for one detection family
scripts/get_detection_prompt.sh spring-filters-interceptors
scripts/get_detection_prompt.sh static-auth

# Discover which per-key guides exist
scripts/get_key_guide.sh --list

# Fetch the guide for one rule key (before drafting a rule for that key)
scripts/get_key_guide.sh postman.test
scripts/get_key_guide.sh method.additional.header
scripts/get_key_guide.sh markdown.curl.host

# Fetch the runtime script-context of a key when authoring a script value
scripts/get_key_context.sh postman.test
scripts/get_key_context.sh api.class.parse.after

Catalog recipe access priority (mirrors the in-plugin agent's agent-base.md): for a detection-family question, the preferred first stop is scripts/getdetectionprompt.sh <id>; for a per-key guide question, the preferred first stop is scripts/getkeyguide.sh <key>. The long-form docs/rule-guide.md stays the reference for cross-cutting context (Workflow Patterns, Multi-Application Namespace, the full filter-prefix table). Memory is never a substitute for the catalog — always read the guide before drafting.

General codebase-perception tools (your file/grep capabilities)

The built-in agent has PSI tools to inspect source. You use file reads + rg/grep instead. rg is assumed available (it ships with most AI coding assistants); fall back to grep -rn if it isn't.

Built-in tool Your equivalent Notes
getpsiclass_info Read the class source file; or rg for its fields/methods Find the file by simple name first (below), then read it. Resolve the FQN from the package + import.
getpsimethod_info Read the method in the class source file For overloads, disambiguate by parameter count when you read it.
findclassesby_annotation rg -t java -t kt "<@AnnotationFqn or @Simple>" then resolve imports Always confirm the FQN from the import / package — @Simple names collide.
findclassesby_supertype `rg -t java -t kt "extends\s+<Type>\ implements\s+.*<Type>"` then resolve imports The most common blind spot — annotation-only scans miss inheritance-declared components (filters extending OncePerRequestFilter). Use BOTH this and the annotation scan.
listprojectendpoints (no CLI equivalent — see below) Needs IntelliJ's ApiIndex cache, which is unavailable outside the IDE.

Standard discovery patterns (the Custom-Pattern Catalog signals to look for — full recipes are in bundled docs/rule-guide.md):

# Find servlet filters (extends OncePerRequestFilter, implements Filter)
rg -t java -t kt "extends\s+OncePerRequestFilter|implements\s+.*Filter"

# Find interceptors
rg -t java -t kt "implements\s+HandlerInterceptor"

# Find response wrappers (ResponseBodyAdvice)
rg -t java -t kt "implements\s+ResponseBodyAdvice"

# Find argument resolvers
rg -t java -t kt "implements\s+HandlerMethodArgumentResolver"

# Find annotated controllers (resolve imports to confirm the FQN)
rg -t java -t kt "@RestController"

Always resolve imports / same-package usage to confirm the FQN, and exclude the supertype itself from results — these are the same nuances the built-in agent's PSI tools handle automatically.

listprojectendpoints has no CLI equivalent — it needs the plugin's ApiIndex cache, which only exists inside a running IntelliJ. You do not need the endpoint list to author rules: rules are about the request/response contract (headers, param injection, response unwrapping), which you detect from source via the discovery patterns above. If the user references a specific endpoint, read the controller method's source directly.

Batch mode (mirror the built-in agent's batching)

The built-in agent's findclassesby, getpsiclassinfo, and getexistingrulesforkey accept arrays to probe multiple items in one request. Mirror this by batching your searches — e.g. one rg -t java -t kt "extends\s+OncePerRequestFilter|implements\s+.Filter|implements\s+HandlerInterceptor" covers filters + interceptors in one pass instead of three, and getexistingrulesforkey.sh method.doc field.name field.ignore checks three keys at once. Prefer the combined form.

Workflow

Work in a perceive → reason → act loop, mirroring the built-in agent.

Step 1: Perceive — fetch the per-recipe catalog entry, then the long-form guide

The in-plugin agent's decomposed prompt catalog is the preferred first stop for any detection-family or per-key recipe question. This skill mirrors that catalog and exposes it via CLI scripts — use them before opening the long-form guide.

  • For a detection family (filters, interceptors, response wrappers,

argument resolvers, custom frameworks, auth chaining, HMAC signing, …): ``bash scripts/listdetections.sh # discover the families scripts/getdetection_prompt.sh spring-filters-interceptors # fetch one recipe ``

  • For a per-key guide (a specific rule key like postman.test or

method.additional.header, or a key with no RuleKey constant like markdown.curl.host): ``bash scripts/getkeyguide.sh --list # discover the keys with guides scripts/getkeyguide.sh postman.test # fetch one guide ``

The long-form docs/rule-guide.md is the reference for cross-cutting context: the full rule file format, the full rule-key catalog, the complete filter-prefix table, the Workflow-Pattern Catalog (cross-endpoint auth/signing/refresh recipes), and the Multi-Application Namespace section. Read it after the per-recipe entry when you need that broader context — not instead of it.

If the topic is settings/usage/scripting rather than rules, read the corresponding bundled docs/ page instead (no per-recipe catalog exists for those topics).

Step 2: Perceive — find the right rule key

If the rule key isn't obvious from the catalog or guide, scan the bundled rule-keys.md catalog (the auto-generated scheme catalog; full scheme in rule-keys.json). Cross-check with scripts/getkeyguide.sh --list to see whether a per-key guide file exists for it. Never invent keys not in the rule-keys.md catalog — unknown keys are silently ignored by the plugin's config loader.

If your value is a script (or embeds Groovy), fetch the key's runtime script-context first — scripts/getkeycontext.sh <key> — so you author the Groovy against the real callable script-object API (it/request/response/ api/endpoint/…) rather than guessing from memory.

Step 3: Perceive — inspect existing rules

Before proposing changes, read any existing rule files in:

  • <project>/.easyapi/ (project-scoped rules — the 3.0 model).
  • ~/.easyapi/ (global rules — applied to every project on the machine).
  • Legacy .easy.api.config* files in the project root (and parent

directories — EasyApi walks up the tree for backwards compatibility).

scripts/list_rule_files.sh
scripts/read_rule_file.sh security.properties
scripts/get_existing_rules_for_key.sh method.doc field.name

EasyApi merges rules in priority order; the project folder overrides the global folder, which overrides the built-in rules.

Step 4: Perceive — detect custom framework patterns

Most projects do not need custom rules. EasyApi understands standard HTTP frameworks (Spring MVC, WebFlux, JAX-RS, Feign) out of the box. Before proposing a rule, scan the project for the detection catalog signals — each detection family in scripts/listdetections.sh has a full recipe in ai/detection/<id>.md (read via scripts/getdetection_prompt.sh <id>) that lists the exact signals to look for.

# Discover every detection family the in-plugin agent knows
scripts/list_detections.sh

# Fetch the recipe for one family before scanning the codebase
scripts/get_detection_prompt.sh spring-filters-interceptors
scripts/get_detection_prompt.sh custom-framework

Use the discovery patterns under "General codebase-perception tools" above — findclassesby_supertype (your extends/implements scan) is the most common blind spot, since annotation-only scans miss inheritance-declared components. For each candidate, ask: does it change the request/response contract invisibly? If yes, fetch the matching detection recipe and apply its rule(s). If no, no rule is needed.

Step 5: Reason — is a rule actually needed?

Confirm a rule is required before drafting. Standard framework behaviour is already handled automatically — do not re-declare defaults such as @Deprecated status, @RequestMapping paths, or @RequestParam names. Only write rules for invisible contracts the plugin cannot detect (custom filters, interceptors, argument resolvers, response wrappers, non-standard annotations).

If the request is ambiguous, ask the user a short clarifying question with concrete options (single/multi choice) so they can answer quickly — mirroring the built-in agent's ask_clarification. Fall back to a plain-text question only when you can't enumerate options.

Step 6: Act — draft the new rule content

Propose new rule content in the rule file format documented in the guide:

  • <key>[<filter>]=<value> (one rule per line; filter optional).
  • Groovy scripts for advanced cases (groovy: prefix filter, or a multi-line

groovy value-block — see Critical Quality Rule 2).

Step 7: Act — insert and show the diff

Insert the new rules into a file in .easyapi/ (project) or ~/.easyapi/ (global). Always show the user the diff before applying — EasyApi rules affect API export across the whole project, so the user must confirm the change. This mirrors the built-in agent's proposerulecontent → user-confirmed "Save…" flow; the only difference is you write the file directly instead of staging it through a UI.

Multi-app namespacing

When a workspace hosts more than one app (each IntelliJ Module / spring.application.name is a candidate app — detect by scanning the project's module structure and application.yml files), namespace every per-app env var by a resolved key so exports don't collide. Apply this even for a single-app workspace — a single app today doesn't mean a single app forever, and bare {{host}} / ${Authorization} would collide if the user exports a different app later into the same Postman environment.

  • Resolve the namespace key in order: (1) Module name (inferred from

the source file's IntelliJ module / directory), normalized lower-case with spaces/underscores → hyphens, characters outside [a-z0-9-] stripped, capped at 40 chars; (2) spring.application.name read directly from the app's application.yml/application-*.yml/ application.properties (fall through if absent); (3) ask the user a short clarifying question on collision or unresolved ambiguity.

  • Namespace every env var: host {{<key>}}, bearer {{<key>-token}},

login {{<key>-username}}/{{<key>-password}} (lower-case by default; UPPER when an existing rule already uses it — reuse the existing casing rather than renaming). The producer's stored name and the consumer's referenced name MUST be identical (bundle integrity still holds).

  • Split bundles per app: propose one bundle per app, each complete on

its own (producer script + consumer header + host + env var, all sharing the same key); for consumers you can't confidently assign to an app (shared/common modules), ask the user with concrete app options.

  • Record the resolution branch (module name / spring.application.name /

user-clarified) and the resulting key in the proposal shown to the user, so they can correct a wrong guess before saving.

  • Fetch the full recipe from the bundled docs/rule-guide.md (the

"Multi-Application Namespace" section) — don't reproduce it from memory. Note: the v1 runtime converts unresolved ${...} placeholders in header values only; do not promise body-level namespacing.

Critical Rule File Format (follow exactly — inlined from the agent preamble)

Each line is <key>[<filter>]=<value> or <key>=<value> (no filter). The filter goes INSIDE [...] AFTER the key — NEVER before it. There is no filter?key=value form.

method.doc[$class:com.example.UserController]=user
method.additional.header={"name":"Authorization","value":"Bearer ${token}","desc":"","required":true}

Valid filter prefixes (and ONLY these):

  • $class:<FQN> — exact class-name match. Wildcards are NOT supported.

For package/pattern matching use groovy: (e.g. groovy: it.containingClass()?.qualifiedName()?.startsWith("com.example.web.")).

  • @<AnnotationFqn> — annotation presence.
  • #regex:<pattern> — regex match; captured groups available as ${1},

${2} in the value.

  • #<tag> — JavaDoc/KDoc tag.
  • !<expr> — negation.
  • groovy:<script> — truthy script result = match.

Class identity in Groovy is context-sensitive:

  • name() on a class context returns only the simple name.
  • qualifiedName() returns the fully-qualified class name and is required for

FQN equality and package-prefix comparisons.

  • For inherited members, containingClass() is the class currently being

exported, while defineClass() is the original declaring class.

There is no ~ prefix and no bare class: prefix — the older class:com.example.Foo and ~regex forms are invalid; use $class: and #regex: respectively.

Critical Quality Rules (follow exactly — inlined from the agent preamble)

These mirror the rules the built-in agent enforces via its system prompt.

1. Check existing rules before writing (avoid duplicates)

Before proposing any rule for a key, read the existing rule files and check whether an equivalent rule already exists in any source — project (.easyapi/), global (~/.easyapi/), or bundled extension (Swagger / Jackson / etc.).

  • If an equivalent rule already exists, do NOT write a duplicate. Tell the

user where it already lives and skip it.

  • If a broader rule already covers your case (e.g. a groovy: filter matching

a package prefix, and you were about to add one for a sub-package), do NOT add a narrower duplicate unless it overrides with a different value.

  • Extension-source rules (Swagger annotations, Jackson modules, etc.) are

already in effect. Never re-declare what the extension already provides (e.g. method.doc[@java.lang.Deprecated]=deprecated is handled by the built-in extension — do not write it).

2. Prefer groovy value-blocks for complex conditional logic

When a filter expression grows long — multiple &&/||, multiple exclusions, or nested method calls — the key[groovy:…]=value form becomes unreadable on a single line. Switch to the groovy value-block form: the value itself is a multi-line groovy script that returns the value when the condition holds, or null when it doesn't. See the rule guide's Groovy Binding Reference for the it object API.

Bad (unreadable single-line filter):

method.additional.header[groovy: it.containingClass()?.qualifiedName()?.startsWith("com.example.merchant.") && it.containingClass()?.qualifiedName() != "com.example.merchant.AuthController"]={"name":"Authorization","value":"Bearer ${token}","desc":"JWT","required":true}

Good (multi-line groovy value-block):

method.additional.header=groovy:```
def cls = it.containingClass()?.qualifiedName()
if (cls?.startsWith("com.example.merchant.")
    && cls != "com.example.merchant.AuthController") {
    return '{"name":"Authorization","value":"Bearer ${token}","desc":"JWT","required":true}'
}
return null

Rules of thumb:
- **≤ 1 condition** → inline `<key>[<filter>]=<value>` is fine.
- **≥ 2 conditions or exclusions** → use a groovy value-block.
- The script must `return` the value (string) or `return null` to skip.

### 3. Never generate blanket field-ignore rules

Do NOT generate `field.ignore` rules based on field-name patterns like
`.*password.*`, `.*secret.*`, `.*token.*`. These fields are often a
**legitimate part of the API definition** — a login endpoint requires
`password`, an OAuth endpoint requires `clientSecret`, a token-refresh
endpoint requires `refreshToken`. Stripping them silently breaks the exported
documentation.

Sensitive-field handling is a **project policy** decision, not a
code-detection decision. If the user explicitly asks for it, you may add it
— but never invent it on your own, and always warn the user that it may hide
fields that some endpoints legitimately require.

### 4. Don't re-declare framework defaults

Standard Spring MVC / WebFlux / JAX-RS / Feign endpoints need no rules —
the plugin detects them out of the box. `@Deprecated` status, `@RequestMapping`
paths, `@RequestParam` names, etc. are all handled automatically. Only write
rules for **invisible contracts** the plugin cannot detect (custom filters,
interceptors, argument resolvers, response wrappers, non-standard annotations).

## Common Key-Name Mistakes (do not use these)

These keys do **not** exist — use the correct alternative:

| Does NOT exist | Use instead |
|----------------|-------------|
| `api.header` | `method.additional.header` |
| `api.header.additional` | `method.additional.header` |
| `path.prefix` | `class.prefix.path` / `endpoint.prefix.path` |

`method.additional.header` and `method.additional.param` values are **JSON
objects** (one per line):
`{"name":"…","value":"…","desc":"…","required":…}`, not `Name:Value`.

## Two-Approach Note for the User

If the user is unsure how to invoke this skill versus the plugin's built-in
AI assistant, briefly explain:

- **Built-in AI assistant (Settings → EasyApi → Rules → Chat / Magic)** — In
  IntelliJ with EasyApi installed, open Settings → EasyApi → Rules, edit a
  rule file, and click **Chat** (reveals the inline AI panel) or **Magic**
  (runs a built-in review-and-detect instruction). The plugin's agent runs a
  perceive→reason→act loop, calls its PSI perception tools to inspect the
  project, and stages a proposal the user reviews and saves. Best for users
  who want everything inside IntelliJ.
- **This skill (external assistant)** — Use your existing AI coding assistant
  (Trae, Cursor, Cline, Continue, etc.) which already has access to the
  project's files. The skill bundles the **same** knowledge-base pages and
  gives the assistant the same workflow, mapping each built-in PSI tool to a
  CLI equivalent. Best for users already invested in an external AI workflow.

Both approaches share the same knowledge base and recipe catalog: the
built-in agent reads them from the plugin JAR (`get_plugin_doc` for the
long-form pages, `get_detection_prompt` / `get_rule_detail` for the
per-recipe catalog); this skill ships verbatim copies of both, kept in sync
by the `syncKnowledgeBase` and `syncAgentCatalog` Gradle tasks. So the rule
content they produce is consistent.

## What This Skill Does NOT Do

- It cannot call the plugin's runtime AI tools directly. You — the external
  assistant — provide equivalent capability via the bundled scripts (rule
  files + existing keys) and your own file/grep access (PSI inspection +
  class discovery).
- It cannot enumerate the project's cached HTTP endpoints
  (`list_project_endpoints`) — that requires the plugin's `ApiIndex` cache,
  which only exists inside a running IntelliJ. You don't need it: rules are
  about contracts detectable from source.
- It does not configure or test AI providers. The built-in assistant's
  configuration lives in IntelliJ Settings → EasyApi → AI.
- It does not modify the EasyApi plugin itself or its bundled config.

## Reference Pointers

**Bundled with this skill (available after `npx skills add` — read these):**
- `docs/rule-guide.md` — rule file format, filter syntax, recipes, Custom-Pattern
  Catalog, Workflow-Pattern Catalog, Groovy binding reference.
- `rule-keys.json` / `rule-keys.md` — complete rule-key catalog with every key's
  full self-describing scheme (auto-generated; regen with `syncRuleKeySchemes`).
- `rule-contexts.json` / `rule-contexts.md` — per-key runtime script-context
  (bindings + script-object method signatures), a mirror of the in-plugin
  `get_rule_context` tool (auto-generated; regen with `syncRuleContexts`).
- `docs/index.md`, `docs/README.md`, `docs/settings-guide.md`, `docs/usage-guide.md`,
  `docs/postman-script-reference.md` — the rest of the knowledge base.
- `ai/detection/*.md` — per-detection-family recipe catalog (verbatim mirror of
  the in-plugin agent's `src/main/resources/ai/detection/`). Read via
  `scripts/get_detection_prompt.sh <id>`; listed by `scripts/list_detections.sh`.
- `ai/key-guides/*.md` — per-key guide catalog (verbatim mirror of the in-plugin
  agent's `src/main/resources/ai/key-guides/`). Read via `scripts/get_key_guide.sh <key>`;
  listed by `scripts/get_key_guide.sh --list`.
- `scripts/` — CLI tools mirroring the built-in AI perception tools (see
  "EasyApi-domain tools" and "Catalog recipe tools" above).

Plugin home: https://github.com/tangcent/easy-api

## Correct Example

User asks: "Add a rule that renames the `createTime` field to `created_at`
in all exported APIs."

Workflow:
1. Check whether a per-key guide exists for `field.name`:
   ```bash
   scripts/get_key_guide.sh field.name        # → "error: unknown rule key" (no guide file)
   ```
   No per-key guide — fall back to the long-form guide.
2. Read the bundled `docs/rule-guide.md` — find the field-rename section / the
   `field.name` key.
3. Check the bundled `rule-keys.md` — confirm the key is `field.name` (alias
   `json.rule.field.name`), mode `replace`.
4. **Run `scripts/get_existing_rules_for_key.sh field.name`** — confirm no
   `field.name` rule already covers this.
5. Open (or create) `<project>/.easyapi/field.rules`.
6. Draft (using the correct `key[filter]=value` format; a field rename map
   is a JSON object value with no filter):
   ```
   field.name={"createTime":"created_at"}
   ```
7. Show the user the diff and apply on confirmation.

## Forbidden Patterns

- **Do not** invent rule keys not present in the bundled `rule-keys.md`.
  Unknown keys are silently ignored by the plugin's config loader.
- **Do not** use the `filter?key=value` form, the `~` regex prefix, or the
  bare `class:` prefix — they are invalid. Use `key[filter]=value`,
  `#regex:`, and `$class:` respectively.
- **Do not** use the non-existent keys `api.header`, `api.header.additional`,
  or `path.prefix` — use `method.additional.header` / `class.prefix.path` /
  `endpoint.prefix.path`.
- **Do not** generate blanket `field.ignore` rules from field-name patterns
  (password / secret / token) — see Quality Rule 3.
- **Do not** re-declare framework defaults (Spring MVC / JAX-RS / Feign
  behaviour is handled automatically).
- **Do not** write Groovy scripts that touch the filesystem or network —
  rule scripts run in a sandboxed Groovy shell with restricted access.
- **Do not** modify the plugin's bundled `src/main/resources/extensions/*.config`
  files. Those are the plugin's own; user rules go in `.easyapi/` or
  `~/.easyapi/`.