MetaMask / MetaMask/metamask-extension

Establish AI config conventions and tooling

Open
#41,428 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

INVALID-ISSUE-TEMPLATE team-extension-platform
Dominant language
TypeScript
Stars
13.2k
Forks
5.6k
Avg merge
2d 5h
Merged PRs (30d)
451

Description

## Problem

The repo has no conventions for AI configuration files. Skills, rules, project instructions, and tool configs are being added without a shared understanding of:

- Where each type of artifact lives
- What is source-of-truth vs. what is generated
- What burns context tokens every session vs. what loads on demand
- What content is shared across tools vs. what is tool-specific
- Who reviews changes and what quality bar applies

Different AI config artifact types have fundamentally different portability characteristics. Skills follow a cross-tool standard ([Agent Skills](https://agentskills.io), adopted by 30+ tools). Rules and project instructions do not — each tool has its own format, activation semantics, and scoping. Treating them identically leads to unnecessary file triplication and maintenance burden.

---

## Convention Doc

(Draft — intended as starting point for `docs/ai-config.md`)

### Where Things Live

```
metamask-extension/
AGENTS.md # Shared project instructions (all tools read this)
CLAUDE.md # @AGENTS.md import + Claude-specific additions
.agents/
skills//SKILL.md # Canonical skills (Agent Skills standard format)
skills//scripts/ # Skill-associated scripts (TS, not bash)
skills//references/ # Reference material for skill execution
.claude/
skills//SKILL.md # Generated shim, gitignored (via postinstall)
settings.json # Claude Code hooks, permissions (SOT)
mcp.json # MCP server config (SOT)
.cursor/
skills//SKILL.md # Generated shim, gitignored (via postinstall)
rules/*.mdc # Cursor-specific rules with frontmatter (SOT)
mcp.json # MCP server config (SOT)
.aiignore # AI-specific file exclusions (SOT)
.github/
copilot-instructions.md # GitHub Copilot instructions (SOT)
```

### Artifact Types

| Type | Source of truth | Generated artifact | Always-on? | Shared across tools? |
|------|----------------|-------------------|------------|---------------------|
| **Skills** | `.agents/skills//SKILL.md` | `.claude/skills/`, `.cursor/skills/` (shims) | No — on-demand | Yes — Agent Skills standard |
| **Project instructions** | `AGENTS.md` | — | Yes | Partially — CLAUDE.md imports it; Cursor reads it as fallback |
| **Claude-specific instructions** | `CLAUDE.md` | — | Yes | No |
| **Cursor rules** | `.cursor/rules/*.mdc` | — | Yes (per `alwaysApply`/`paths` frontmatter) | No — `.mdc` format is Cursor-specific |
| **Tool config** (hooks, permissions) | `.claude/settings.json`, `.cursor/mcp.json` | — | Yes | Partial (MCP schema is shared) |
| **Ignore files** | `.aiignore` | `.cursorignore`, `.copilotignore` if formats diverge | Yes | Partial — same gitignore syntax, different filenames |

**Source-of-truth files** are committed to the repo and reviewed via CODEOWNERS.
**Generated artifacts** (skill shims) are **gitignored** and produced by `yarn generate-ai-shims` (runs automatically via `postinstall`). They must not be hand-edited or committed.

### Skills: Canonical Location and Shim Generation

Skills are authored once in `.agents/skills//SKILL.md` using the [Agent Skills standard](https://agentskills.io) format.

**Why shims are needed (pessimistic design):**
- Claude Code CLI documents `.claude/skills/` as the discovery path. Whether it also scans `.agents/skills/` is undocumented.
- Cursor's `/` slash command only discovers `.cursor/skills/`, not `.agents/skills/` (known bug; IDE auto-invocation works but autocomplete does not).
- Codex scans `.agents/skills/` natively — no shim needed.
- Skill discovery is a **client** feature, not a model feature. When Claude is the model inside Cursor, Cursor controls discovery.

Until both Claude Code and Cursor confirm `.agents/skills/` as a first-class discovery path, shims are generated for both:

```
.claude/skills//SKILL.md → pointer to ../../.agents/skills//SKILL.md
.cursor/skills//SKILL.md → pointer to ../../.agents/skills//SKILL.md
```

Shim content is a single line referencing the canonical file, not a copy of the content.

**Generation:** `yarn generate-ai-shims` reads `.agents/skills/*/SKILL.md` and produces shims in `.claude/skills/` and `.cursor/skills/`. The script is idempotent with early exit — compares canonical mtimes to shim mtimes and skips if current (< 100ms when nothing changed).

It runs:
- **Automatically** via `postinstall` in `package.json` (piggybacks on `yarn install`, which every developer runs regularly)
- **Manually** via `yarn generate-ai-shims` after adding/removing a skill
- **In CI** as a check (fail if shims are stale vs. committed)

Generated shims (`.claude/skills/`, `.cursor/skills/`) are **gitignored** — they're regenerated on every `yarn install`. Only `.agents/skills/` (canonical) is committed.

When a tool confirms native `.agents/skills/` scanning, its shims are removed from the generator.

### Project Instructions: Shared Content, Tool-Specific Imports

Rule and instruction *content* is often identical across tools ("use TypeScript strict mode", "don't import from `app/` in `ui/`"). What differs is the *activation envelope* — how the tool loads and scopes it.

**AGENTS.md** is the shared content source:
- Claude Code: `CLAUDE.md` imports via `@AGENTS.md` (native `@import` support), adds Claude-specific sections
- Cursor: reads `AGENTS.md` as fallback when no `.cursorrules` exists. Path-scoped rules that need Cursor's `alwaysApply`/`paths` frontmatter go in `.cursor/rules/*.mdc`
- Codex, Copilot: read `AGENTS.md` directly

Cursor `.mdc` files support `` tags but these are **declarative metadata**, not content inclusion — no `@import` equivalent exists. So `.cursor/rules/` necessarily duplicates content that requires Cursor-specific activation. Minimize this by keeping AGENTS.md as the primary source and `.cursor/rules/` as path-scoped supplements only.

### When to Use What

| I need to... | Use | Why |
|---|---|---|
| Teach an agent a multi-step workflow | **Skill** (`.agents/skills/`) | On-demand, ~50-100 tokens in catalog, full content loads only on activation |
| Set a rule that applies to every session | **AGENTS.md** section or **`.cursor/rules/*.mdc`** | Always-on context — use sparingly, burns tokens every session |
| Enforce a rule deterministically | **Linter** (eslint) or **fitness function** or **hook** | Rules are suggestions the agent can ignore; linters and hooks are constraints it cannot bypass |
| Document a process for humans | **`docs/*.md`** | Skills reference docs; they don't embed them |
| Combine process + enforcement | **Skill paired with a script, linter, or hook** | Skill shapes generation upstream so the enforcement layer rarely has to fire. Restating what the script already checks is waste; encoding the *pattern* it wants is generation-time work the script cannot do. |

### Enforcement Layers

Skills and AI rules shape generation. Hooks, linters, and fitness functions enforce. The two layers do different work and both should exist for any pattern load-bearing enough to encode.

| Layer | Mechanism | Can agent bypass? | Timing |
|---|---|---|---|
| Skills (`.agents/skills//SKILL.md`) | Generation-time guidance | Yes — suggestive only | Before output |
| AI rules (AGENTS.md, .mdc, CLAUDE.md) | Context injection | Yes — suggestive only | Before output |
| Hooks (Claude Code `PreToolUse`, Cursor hooks) | Runtime interception (exit code 2 = block) | **No** | At tool call |
| Linters (eslint, fitness functions) | Pre-commit validation | **No** | After output |

**Admission rule for skills and rules.** A skill or rule that *substitutes* for enforcement is unsafe: the agent can ignore context, so anything that must not be bypassed belongs in a hook or linter. A skill or rule that *restates* what enforcement already checks without adding generation-time guidance is waste: it spends tokens to duplicate ground truth. A skill or rule that gives the model the upstream pattern so the enforcement layer rarely has to fire is exactly the right shape, and the existence of a corresponding lint rule is evidence the pattern is load-bearing enough to encode at both layers.

The repo already has enforcement infrastructure: `development/fitness-functions/` pre-commit pipeline and `.eslintrc.js` architectural boundary rules (ui↔app↔shared import restrictions). Skills and AI rules covering the same patterns should explicitly name the enforcement layer they pair with, not pretend to replace it.

For constraints not covered by existing linters (e.g., blocking edits to `.env` or security-sensitive dirs), add Claude Code hooks (`PreToolUse` on `Edit|Write`) and/or Cursor hooks.

### Authoring Checklist for New Skills

- [ ] Skill lives in `.agents/skills//SKILL.md`
- [ ] `name` in frontmatter matches directory name (lowercase, hyphens)
- [ ] `description` is specific enough for agent discovery (~1 sentence)
- [ ] Includes "when NOT to use" section
- [ ] References docs for human context; doesn't embed them
- [ ] Invokes scripts for deterministic rules; doesn't restate them in natural language
- [ ] Run `yarn generate-ai-shims` after adding
- [ ] No interim conversation artifacts in final content

### CODEOWNERS

```
# AI configuration
/.agents/ @metamask/extension-platform
/.claude/ @metamask/extension-platform
/.cursor/ @metamask/extension-platform
/AGENTS.md @metamask/extension-platform
/CLAUDE.md @metamask/extension-platform
/.aiignore @metamask/extension-platform
```

---

## Acceptance Criteria

- [ ] **Convention doc** committed to `docs/ai-config.md` (starting from draft above)
- [ ] **`yarn generate-ai-shims`** script: reads `.agents/skills/*/SKILL.md`, produces pointer shims in `.claude/skills/` and `.cursor/skills/`. Idempotent with early exit (mtime comparison). Runs via `postinstall`. Generated dirs gitignored.
- [ ] **CODEOWNERS** entries for `.agents/`, `.claude/`, `.cursor/`, `AGENTS.md`, `CLAUDE.md`, `.aiignore`
- [ ] **AGENTS.md** authored with shared project instructions
- [ ] **CLAUDE.md** authored with `@AGENTS.md` import + Claude-specific additions
- [ ] **`.aiignore`** with exclusions for sensitive paths
- [ ] **Verify cross-tool discovery**: empirically test `.agents/skills/` scanning in Claude Code CLI and Cursor `/` command. Document results. Remove shims for any tool that confirms native discovery.

## Deferred

- Fitness functions for skill schema validation — premature at current skill count
- Rules-to-skills context budget audit — separate ticket
- Security review process for `allowed-tools` in skills — separate ticket
- Plugin packaging for org-wide skill distribution

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the proposed convention in the issue, the current package.json, and the existing development/fitness-functions/ and .eslintrc.js infrastructure. Implement docs/ai-config.md, the yarn generate-ai-shims workflow, ownership entries, and the named instruction and ignore files, then verify shim generation, postinstall behavior, CI staleness checks, and cross-tool discovery as described in the acceptance criteria.

Written by the indexing model from the issue text.

Assessment

Tech stack
eslint, typescript
Domain
documentation, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.