Skip to content

Repository files navigation

ram-claude-plugin

Shared Claude Code skills and hooks for RAM React / TypeScript / Supabase / Vercel projects.

Install

This is the personal, one-machine install path. It works the same way whether or not the repo you're in has a committed .claude/settings.json — it's an explicit command, not something that depends on trust-dialog auto-detection (see Consumer project setup below for why that distinction matters). Run it once per machine per person; it doesn't reach anyone else's setup.

Add the RAM Companies marketplace:

claude plugin marketplace add RAM-Companies/ram-claude-plugin

Then install the plugin:

claude plugin install ram@ram-companies

This plugin can also be used with copilot by replacing claude with copilot. E.g.

copilot plugin marketplace add RAM-Companies/ram-claude-plugin
copilot plugin install ram@ram-companies

Update

claude plugin marketplace update ram-companies

This refreshes the marketplace catalog only — follow it with claude plugin update ram@ram-companies to actually pull the new version. This manual pair always works regardless of whether autoUpdate is set anywhere; use it any time you don't want to wait for the next automatic startup check, or to confirm an update actually landed. See /ram:update-plugin, which automates this end-to-end including the project-scope case.

Consumer project setup (recommended)

Running claude plugin install locally only configures your own machine — it doesn't reach any of your teammates', and each person has to repeat it themselves. For a team project, commit this to the project's own .claude/settings.json instead, so the plugin is declared for everyone who opens the repo:

{
  "extraKnownMarketplaces": {
    "ram-companies": {
      "source": {
        "source": "github",
        "repo": "RAM-Companies/ram-claude-plugin"
      },
      "autoUpdate": true
    }
  },
  "enabledPlugins": {
    "ram@ram-companies": true
  }
}

If the project doesn't have a .claude/settings.json yet, create it with just this content. If it already has one — for anything, not just RAM's own hooks — merge extraKnownMarketplaces and enabledPlugins in as additional top-level keys; don't replace the file. This repo's own .claude/settings.json is a working example of enabledPlugins sitting alongside an unrelated hooks block.

This does not reliably auto-install the plugin — declaring it in settings.json only makes Claude Code aware the project wants it. The docs say trusting the folder "prompts them to install," but in practice this has been reported to silently do nothing beyond registering the marketplace — no install prompt fires, enabledPlugins is never acted on, and the plugin's skills stay unavailable (anthropics/claude-code#32606). It's also only evaluated through the interactive trust dialog — it does nothing in headless/print mode (-p), including in CI (anthropics/claude-code#13097). The CLAUDE.md snippet below closes both gaps by having Claude proactively offer the install the first time it's needed (and run it with the user's go-ahead), instead of depending on a prompt that may never fire.

Once installed, autoUpdate: true keeps that installation current without anyone manually running claude plugin marketplace update — third-party marketplaces default to auto-update off.

Also add this to the project's own CLAUDE.md. This is what actually closes the install gap described above for non-technical teammates: instead of a human having to notice the "plugin not installed" message and copy the command themselves, Claude offers to install it the first time it needs a RAM skill, and runs the commands itself once the user agrees:

## RAM Claude Plugin

This project uses the `ram@ram-companies` Claude Code plugin for shared skills (`/ram:codebase-review`, `/ram:add-migration`, etc.) and hooks. It's declared in `.claude/settings.json`, but Claude Code does not auto-install a plugin from settings alone — it only reports the plugin as not installed and shows the install command. No one should need to notice that message or run install commands themselves.

If a user describes something a RAM skill would normally handle (e.g. "review this codebase," "add a migration," "write tests for this function") and the matching skill isn't available or the `ram` plugin isn't installed:

- Don't just report the plugin as missing and stop — that leaves the user to notice the message and copy the command themselves, which is the exact gap this fallback exists to close.
- Tell them in plain language what's missing and offer to install it — then, if they agree, do it yourself rather than making them type it:
  - Just `ram`: run the two commands directly — `claude plugin marketplace add RAM-Companies/ram-claude-plugin` and `claude plugin install ram@ram-companies`.
  - If `.claude/settings.json` declares other marketplaces/plugins too (under `extraKnownMarketplaces`/`enabledPlugins`) that also aren't installed yet: instead of running the two commands per plugin, save `sync-claude-plugins.ps1` locally (`irm https://raw.githubusercontent.com/RAM-Companies/ram-claude-plugin/main/sync-claude-plugins.ps1 -OutFile "$env:TEMP\sync-claude-plugins.ps1"`) and run it once with an **absolute** `-SettingsPath` pointing at this project's `.claude/settings.json` — it syncs everything declared there in one pass, not just `ram`. Note it only syncs what's already declared in that file; it won't add an entry that isn't there. And it takes parameters, so `irm ... | iex` won't work, and a relative `-SettingsPath` would resolve against the temp folder it's saved in, not this project.
- This changes machine-wide Claude Code state, not just this project, so treat it like any other consequential action: propose it, don't do it silently — and call out explicitly if it involves downloading and executing a script from the internet.

Don't rely on the user typing `/ram:<skill-name>` directly. If that skill doesn't resolve, the client rejects the slash command before it ever reaches you, so this fallback never gets a chance to run — it only helps when they describe what they want in plain English.

Caveats to know about before relying on this:

  • Each teammate still has one unavoidable one-time step: accepting the workspace trust dialog on their own machine the first time they open the project. Nothing here removes that.
  • autoUpdate: true only helps once the plugin is actually installed. It keeps an existing install current at every startup — it does not perform the initial install, which is exactly the step the caveat above says isn't reliable. Someone (or Claude, via the CLAUDE.md fallback) still has to get the plugin installed once; autoUpdate takes it from there.
  • Claude Code Desktop has a filed bug (anthropics/claude-code#61782) where the workspace trust dialog can silently fail to render, blocking the chat entirely with no prompt to accept. If someone hits this, nothing above can help — they'd need to trust that same repo once via another Claude Code surface (CLI or an IDE extension), since trust is stored per git repository root, not per surface.

Automating the one-time install with sync-claude-plugins.ps1

sync-claude-plugins.ps1 automates the "someone still has to get the plugin installed once" step above. Point it at a project's .claude/settings.json and it registers every marketplace under extraKnownMarketplaces and installs/updates every plugin under enabledPlugins set to true — no manual claude plugin marketplace add / claude plugin install typing.

./sync-claude-plugins.ps1

Run it from anywhere; a relative -SettingsPath resolves against the script's own location, not your terminal's current directory — so it only finds .claude/settings.json automatically if this script lives inside the project you're syncing. To target a different project, pass an absolute -SettingsPath pointing at that project's settings file. Flags:

  • -SettingsPath <path> — defaults to .claude/settings.json. Point at a different file if the project keeps settings elsewhere.
  • -Scope <user|project|local> — defaults to project. Passed straight through to claude plugin install/update.
  • -DryRun — print the claude commands it would run without executing them.

It also installs the Claude CLI itself (with a confirmation prompt, unless -DryRun) if claude isn't on PATH yet, and runs claude update first so the rest of the sync runs against a current CLI. Failures for one marketplace or plugin are reported as warnings and don't stop the rest of the sync.

This still doesn't replace the per-teammate trust-dialog step in the caveats above — it just removes the need for anyone to hand-type install commands once trust is granted.

Developing this plugin

To try a skill from this repo before it's released, load it unreleased with:

claude --plugin-dir .

then invoke it as /ram:<skill-name> and run /reload-plugins after edits to pick up changes without restarting.

This only works from a plain terminal, not the VS Code extension. The VS Code extension launches its own managed claude process and has no setting to pass --plugin-dir (or any extra CLI flag) to it. If you're working in the VS Code extension, open a separate integrated or external terminal and run the command above there — it starts an independent CLI session, not the extension's chat panel. Hooks don't have this limitation: .claude/settings.json wires this repo's own hooks up directly via ${CLAUDE_PROJECT_DIR}, so they run in any session (including the VS Code extension) without needing --plugin-dir.

Skills

Skill Invoke Purpose
add-migration /ram:add-migration Create a Supabase migration (DDL + pgTAP tests + type regen)
codebase-review /ram:codebase-review Full-codebase audit: security, performance, best practices (for vibe-coded apps)
create-edge-function /ram:create-edge-function Scaffold a new Supabase Edge Function with CORS, auth model, and testable logic split out
create-edge-function-client /ram:create-edge-function-client Generate typed client (types + fetch wrapper) for calling an Edge Function from its OpenAPI spec
deno-tests /ram:deno-tests Add unit tests to a Supabase Edge Function
extract-component /ram:extract-component Pull a section out of a large file into a standalone component
extract-service /ram:extract-service Move inline Supabase queries into a service layer
find-usages /ram:find-usages Find every file that uses a component, function, or class string
git-workflow /ram:git-workflow Create a feature branch, write a conventional commit, and open a PR against dev
new-feature /ram:new-feature Scaffold a new feature folder following feature-based architecture
pr-review /ram:pr-review Full PR review: conventions, security, code quality, docs accuracy
review-edge-function /ram:review-edge-function Audit an existing Supabase Edge Function for auth, CORS, data access, and testability issues
setup-env-local /ram:setup-env-local Write VITE_SUPABASE_ANON_KEY to .env.local for local Supabase development
setup-formatting /ram:setup-formatting Set up Prettier, ESLint auto-fix, EditorConfig, and VS Code format-on-save
ui-update /ram:ui-update Safely apply a UI change everywhere it appears across the repo
unit-tests /ram:unit-tests Write Vitest unit tests for pure functions in src/
update-plugin /ram:update-plugin Update the installed ram plugin to the latest marketplace version
verify-build /ram:verify-build Run tsc --noEmit + npm test before reporting a task done, committing, or opening a PR

Hooks

Automatically wired when the plugin is enabled:

Hook Trigger What it does
protect-generated.js PreToolUse Write/Edit Blocks edits to auto-generated types.ts; warns before editing migrations
format.js PostToolUse Write/Edit Runs ESLint --fix + Prettier on every saved file
post-write-checks.js PostToolUse Write/Edit Flags as any, window.confirm(), silent .catch, inline style={{}}, Supabase in pages/, admin layout constants, hardcoded secrets; notes related importers

There is no Stop hook. Type-checking and tests are run via the /ram:verify-build skill instead — see the Skills table above.

Testing skills (evals)

Skills are natural-language instructions, not deterministic code — you can't unit-test them the way tests/*.test.js tests the hooks. Instead, this repo uses the skill-creator plugin to run evals: give the skill a few realistic prompts, run Claude with and without the skill, and grade the responses against a checklist.

Setup

skill-creator@claude-plugins-official is enabled at project scope (see .claude/settings.json), so it's available to everyone working in this repo. If it's ever missing:

claude plugin install skill-creator@claude-plugins-official --scope project

Creating evals for a skill

Add evals/evals.json inside the skill's own directory (sibling to SKILL.md), e.g. skills/<skill-name>/evals/evals.json:

{
  "skill_name": "<skill-name>",
  "evals": [
    {
      "id": 1,
      "prompt": "A realistic user prompt that should exercise the skill",
      "expected_output": "One-sentence description of what a good response looks like",
      "files": [],
      "expectations": [
        "An objectively checkable statement about the response",
        "Another one — these become the grading checklist"
      ]
    }
  ]
}

Write 2-3 prompts per skill covering the common case plus at least one edge case (an ambiguous request the skill should resolve without asking a redundant question, or a failure mode it should troubleshoot correctly). Keep expectations objectively verifiable — "mentions running claude plugin list" grades cleanly, "sounds helpful" doesn't.

Running the eval

  1. Before spawning any agent, copy that eval's files into per-run input folders: skills/<skill-name>-workspace/iteration-1/<eval-name>/{with_skill,without_skill}/inputs/. Point each agent at its own copy, never at the shared skills/<skill-name>/evals/files/ originals — an agent that goes looking for "the project" on disk will find and edit whatever's in front of it, "please don't modify the original" is an instruction, not a permission boundary, and a stray edit to the shared fixture silently corrupts every other eval case that reuses it. (Not hypothetical: a baseline run once edited the shared ui-update fixtures in place instead of its output folder, requiring a manual restore before the results could be trusted.)

  2. For each eval case, spawn two subagents in the same turn: one instructed to read the skill's SKILL.md and follow it (with_skill), one given the same prompt with no skill reference at all (without_skill, the baseline). Point each at its own inputs/ copy from step 1. Save each response under skills/<skill-name>-workspace/iteration-1/<eval-name>/{with_skill,without_skill}/outputs/.

  3. Grade each response against that eval's expectations, saving grading.json per run (see skill-creator's references/schemas.md for the exact field names — the viewer depends on them matching exactly).

  4. Aggregate into benchmark.json at the iteration root (pass rates, timing, tokens per configuration).

  5. Generate the review page and open it as an artifact/static file:

    python <skill-creator-path>/eval-viewer/generate_review.py \
      skills/<skill-name>-workspace/iteration-1 \
      --skill-name <skill-name> \
      --benchmark skills/<skill-name>-workspace/iteration-1/benchmark.json \
      --static <output.html>

Ask Claude to "run the eval harness for <skill-name>" and it will do all of the above. See skills/update-plugin/evals/evals.json for an example eval set — running it turned up a real gap in the update-plugin skill (it doesn't explain that --scope project only pins config in git and doesn't push the update to teammates' machines), caught by comparing against the no-skill baseline. <skill-name>-workspace/ is scratch output from that run — regenerate it locally rather than committing it; it's gitignored.

Iterating

If grading surfaces a real gap in the skill (not just a one-off phrasing issue), fix SKILL.md and rerun into iteration-2/, passing --previous-workspace iteration-1 to the viewer so you can compare. Delete <skill-name>-workspace/ once you're done — it's scratch output, not something to keep committed long-term (unless you want to preserve a specific run as a regression fixture).

CI

PR checks (.github/workflows/ci.yml) run structural validation only for any skill whose files changed in the PR: evals/evals.json, if present, must be valid JSON matching the schema above (non-empty prompt and expectations per eval). CI does not spawn real claude -p calls or grade responses — that requires an Anthropic API key and real token spend, so the qualitative with-skill/without-skill run above stays a manual (Claude-assisted) step, not an automated gate.

Project-local skills

Some skills are too project-specific to live here. Keep them in .claude/skills/ inside the project repo (e.g. add-admin-card, add-form-field for RAM AIR EZ).

About

Shared Claude plugins, skills, and hooks

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages