-
Notifications
You must be signed in to change notification settings - Fork 0
Sources
External rule sources let Bluetemberg pull rules from outside its own npm pack registry — community repositories that publish rules in foreign formats — translate them into native Bluetemberg format, and include them during sync.
Where the Registry installs npm packs already written in Bluetemberg's llm/ layout, sources target the wider ecosystem: a GitHub repo of .cursorrules/.mdc files, for example. Bluetemberg fetches, translates, caches, and pins them with the same reproducibility as packs.
Backend status: GitHub repos and PRPM (
registry.prpm.dev) are supported today. The cursor.directory backend is a planned follow-up — the framework and CLI already accept its spec grammar, butsource add cursor-directory:…reports "not supported yet" until its adapter lands.
flowchart LR
spec["source add<br/>github:owner/repo#ref:path"] --> resolve["resolve<br/>ref → commit SHA"]
resolve --> fetch["fetch<br/>download repo tarball"]
fetch --> translate["translate<br/>.mdc/.cursorrules → native frontmatter"]
translate --> cache[".bluetemberg/sources/<br/>(git-ignored cache)"]
cache --> sync["bluetemberg sync"]
sync --> out[".cursor/rules, .claude/rules,<br/>.github/instructions, …"]
Translation happens once, at install time — the cache holds native rules/, agents/, and skills/, so sync treats a source exactly like any other source directory. A source is the lowest priority in the merge order:
local llm/ > extends[] > npm packs > external sources
So a local rule always wins over an external rule with the same filename.
| Backend | Spec | Notes |
|---|---|---|
| GitHub | github:<owner>/<repo>[#<ref>][:<path>] |
ref defaults to HEAD (the repo's default branch); path narrows to a subdirectory. |
| PRPM | prpm:<name>[@<range>] |
range defaults to latest. Each PRPM package is a single rule/agent/skill. |
| cursor.directory (planned) | cursor-directory:<slug> |
* selects every active plugin. |
# The rules/ folder of awesome-cursorrules at its current default branch
bluetemberg source add "github:PatrickJS/awesome-cursorrules#HEAD:rules"
# A specific tag, whole-repo
bluetemberg source add "github:my-org/ai-rules#v2.1.0"
# Find and add a package from PRPM (resolved to a pinned version)
bluetemberg source search "react" --type prpm
bluetemberg source add "prpm:@patrickjs/nextjs-react-tailwind-cursorrules-prompt-file"PRPM packages come in varied layouts (a structured skills/<name>/SKILL.md, or a single flat file); the PRPM adapter normalizes both into native dirs, routing by the package's declared subtype, before translation. The version is the immutable pin recorded in the lockfile.
Two committed files track sources (parallel to the registry's rule-packages.json):
| File | Purpose |
|---|---|
llm/rule-sources.json |
Manifest — declared sources keyed by a stable id, with the floating selector (branch/range). |
llm/rule-sources-lock.json |
Lockfile — the pinned ref (git commit SHA for GitHub), resolved URL, and integrity hash. |
Commit both so teammates resolve identical content. On a fresh clone, run bluetemberg source install to restore the cache from the lockfile.
The cache lives at .bluetemberg/sources/<key>/<ref>/ and is added to .gitignore automatically.
Foreign rule formats are mapped to native RuleFrontmatter (description + scope):
| Source frontmatter | Becomes |
|---|---|
.mdc alwaysApply: true
|
scope: "**" |
.mdc globs: <pattern(s)>
|
scope: <pattern(s)> |
Plain .cursorrules (no frontmatter) |
description synthesized from the first heading (or filename); scope: "**"
|
Already-native .md
|
passed through |
Real-world .mdc files often contain technically-invalid YAML (e.g. an unquoted glob whose leading * is read as a YAML alias). Bluetemberg repairs the common cases and, if a file's frontmatter is still unparseable, falls back to treating it as body-only — a single malformed file never aborts a sync.
A repo laid out with rules/, agents/, and/or skills/ subdirectories is routed by category; a flat directory of files is treated as rules. Nested rule files are flattened into rules/ (joined with __) because sync reads that directory non-recursively.
See Commands for the full reference: add, remove, list, install, update, search.
Repo tarballs are extracted through the same hardened path as npm packs — symlink/hardlink entries and .. path-traversal segments are rejected. Cache keys and filenames derived from remote input are sanitized to a single safe path segment.