Onboard a Cursor repo into the hot-path/cold-path standards system: sync second-brain-workflow rules, add a thin always-apply onboarding rule, point at relevant second-brain practices, and wire project-scoped MCP (Railway / Postgres / Logfire / PostHog) — never global mcp.json. Use when the user says onboard repo, onboard this repo, set up cursor standards, sync rules into this project, or wire best practices into a new codebase. Covers quiet onboarding too — rendering into a repo you do not ...
Installs into .claude/skills of the current project.
Are you the author of Onboard Repo?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/dimeloper-onboard-repo)
---
name: onboard-repo
description: >-
Onboard a Cursor repo into the hot-path/cold-path standards system: sync
second-brain-workflow rules, add a thin always-apply onboarding rule, point at
relevant second-brain practices, and wire project-scoped MCP (Railway /
Postgres / Logfire / PostHog) — never global mcp.json. Use when the user
says onboard repo, onboard this repo, set up cursor standards, sync rules
into this project, or wire best practices into a new codebase. Covers quiet
onboarding too — rendering into a repo you do not own, so the rules work
locally and the remote never sees them: use when the user says render this
quietly, keep it out of the remote, don't commit the rules, onboard someone
else's repo, or local only.
---
# Onboard repo
Works like **feature complete**: run immediately when triggered; do not ask for
confirmation unless a step would overwrite customized project files the user
clearly owns.
## Paths
- Standards (source of truth): `~/second-brain-workflow`
- Rules sync: `~/second-brain-workflow/scripts/sync-rules.sh`
- Skills sync: `~/second-brain-workflow/scripts/sync-skills.sh`
- Skills source: `~/second-brain-workflow/skills/{workflow,...}/`
- Vault practices: `$SBW_VAULT/practices/` (default `~/vaults/second-brain`)
- Knowledge skill (after sync): the `obsidian-knowledge-base` skill
- MCP skill (after sync): the `mcp-per-project` skill
**Reference backends.** Copy the MCP wiring pattern from whichever backend on
this machine is already set up — do not assume a fixed path. Find candidates
with:
```bash
ls -d ~/*/*/.cursor/bin 2>/dev/null | sed 's|/.cursor/bin$||'
```
Prefer the one whose stack and provider mix is closest to the target repo.
## Where this gets triggered
Usually the user says so. The other route is `update-second-brain`, which checks
whether the repo it is wrapping up has ever been rendered into and offers this
when it has not — so you may arrive here with the capture already committed and
a mode already chosen (shared or quiet). Take the mode as given in that case
rather than re-asking.
A user who answered "never for this repo" is on a never-ask list this machine
keeps; `onboarding-state.py --list` shows it, `--undecline` clears one. Nothing
here reads that list — it exists to stop a *prompt*, never to refuse an
instruction, so a direct "onboard this repo" always wins.
## Target repo
1. Prefer the current workspace root if it is a single project git repo.
2. If multi-root or unclear, ask which path to onboard (one short question).
3. If the folder is not a git repo, still sync rules; note that in the status.
Do **not** run this against the standards repo or a vault.
## Steps (in order)
### 1. Sync hot path
```bash
~/second-brain-workflow/scripts/render.py "<TARGET>" # all configured targets
~/second-brain-workflow/scripts/render.py "<TARGET>" --targets cursor,agents
```
One canonical rule set (`rules/*.md`, wherever `SBW_RULES_DIR` resolves to) renders per agent:
| Target | Output | Scoping |
|--------|--------|---------|
| `cursor` | `.cursor/rules/*.mdc` | native `globs` |
| `claude-code` | `.claude/rules/*.md` + root `CLAUDE.md` | native `paths:` frontmatter |
| `agents` | `AGENTS.md` | always-on |
Everything is a real file carrying a `generated by second-brain-workflow@<sha>`
provenance comment, so it works in every clone and in CI. Never edit a rendered
file in the target — edit the source and re-render. Files lacking the comment are
treated as hand-written and are never overwritten or pruned; a hand-written
`CLAUDE.md` is left alone, and you should add `@AGENTS.md` at its top instead.
`render.py "<TARGET>" --check` reports drift and exits non-zero — safe for CI or
a pre-commit hook. `render.py --explain` shows how each rule resolves per target.
Set `RENDER_TARGETS` per machine (e.g. `cursor,agents` where only Cursor runs).
Each target prunes only its own generated files, so a repo shared with someone
using the other agent keeps working.
#### Quiet onboarding — a repo whose remote must never see the rules
Not every repo is yours to add conventions to: a client's, a team's that has
not adopted them, an upstream you only contribute to. `--local` renders the
same files and adds them to `.git/info/exclude`, which is per-clone and is
itself never committed. The rules work for the agent; the remote never learns
they exist.
```bash
~/second-brain-workflow/scripts/render.py "<TARGET>" --local
```
Or `make render REPO=<TARGET> LOCAL=1`.
Three things to know before using it:
- **The mode is recorded, not re-guessed.** After the first `--local`, a plain
re-render stays local. `--shared` is the explicit way back, and it stops the
exclusion as well as re-rendering. Passing both is refused rather than
resolved.
- **It refuses rather than half-works.** If git already tracks a path the render
would write, `.git/info/exclude` has no effect on it — it would show up as an
ordinary modification, one `git commit -a` from being shared. The render
stops and writes nothing rather than making a promise it cannot keep. It also
needs a git work tree; there is nothing to keep out of a remote without one.
- **It is local to the clone.** A fresh clone of the same repo elsewhere has
neither the rendered files nor the exclusion. Re-render there.
Prefer `--local` whenever the user is not the owner of the repo, or says
anything about not wanting the rules committed. When in doubt on a repo with a
remote you do not control, ask which one they want — the two differ in what
other people end up seeing, which is not a detail to guess at.
If `AGENTS.md` already existed and differed, the copy overwrites — that is
intentional for the shared portable file. Repo-specific agent guidance goes in
the onboarding `.mdc` or `CLAUDE.md`, not in a forked `AGENTS.md`.
### 2. Infer stack
From manifests (`package.json`, `pyproject.toml`/`uv.lock`, `pubspec.yaml`,
`app.json` / `expo`, Angular `angular.json`, etc.), classify:
| Stack | Vault folders to skim |
|-------|------------------------|
| FastAPI / Python API | `practices/backend/` |
| Fastify / Node API | `practices/backend/` (esp. fastify + env + errors) |
| Next.js | `practices/frontend/` (next-* , zod-validate-next-*) |
| Angular | `practices/frontend/` (prefer-signal-*, event-driven-*, angular-http-*) |
| Expo / RN | `practices/app/` (expo-*, resilient-*, typed-expo-*) |
| Flutter | `practices/app/` (getx-*, prefer-riverpod-*, handle-offline-*) |
List 3–6 **enforced/trialing** note titles that apply; do not paste full notes
into the repo.
Also classify **MCP role** for step 6:
| Role | When | MCP action |
|------|------|------------|
| **Backend / secret source** | FastAPI, Fastify, or other API that owns Railway/Logfire/PostHog | Full `.cursor/bin` wrappers + `mcp.json` |
| **Sibling app** | Frontend / mobile / Flutter for a product that already has a backend | Point absolute paths at that backend’s wrappers only |
| **Standalone / no infra** | Docs, standards, libs with no Railway/Logfire/PostHog | Skip MCP (say so in Done) |
### 2b. Skills for this repo
```bash
python3 ~/second-brain-workflow/scripts/lib/skill_manifest.py relevant --repo <abs-path>
```
Absolute path, not a relative one: an installed skill directory holds only this
`SKILL.md`, so a relative path resolves to nothing and the step silently falls
back to guesswork.
Prints two lists, from the operator's own `skills.json` — nothing here invents a
recommendation:
- **Adopted and scoped to this repo.** Mention these in the Done report so the
next session knows they are there. They are already installed; do not re-install.
Each names where its scope came from — the allow entry itself, or inherited
from its source. If one looks wrong for this repo, say which of the two to
edit; they are different fixes.
- **Not adopted, worth considering.** Each carries the reason and its install
command. **Report, never install.** Adopting a skill is a standing choice about
every future session in every repo, and several write into the project — a
design linter registering an edit-time hook, a screenshot tool scaffolding a
whole Next.js app. Name it, name the cost, let the user decide.
It also prints which roster answered, as a `roster:` line naming the manifest
path and where that setting came from. Two machines with different manifests
print the same headings, so the counts below them mean nothing without it.
Two outcomes that are not the same thing, and the command distinguishes them:
- **`no skills manifest configured — skill roster skipped`**, exit 0. No roster
was consulted. Supported state, not a gap to fill: say so in the Done report
and move on. Do not read it as "no skills apply here" — nothing was read.
- **Exits non-zero.** A manifest *is* configured and cannot be used — missing
file, bad JSON, an unknown key. That is a real fault on this machine. Report
the error verbatim rather than skipping; onboarding this repo against a roster
that failed to load would silently under-report.
If the user does adopt one, the loop is theirs to run, not yours to assume:
`make fetch-skills YES=1` then `make sync-skills`, and a **session restart** —
the skill listing is read at startup, so a newly linked skill is invisible until
then.
### 2c. Practices this repo has never had
```bash
~/second-brain-workflow/scripts/practices-for.py --repo <abs-path>
```
Only `enforced` notes become rules, and only rules reach a repo — so on a large
vault the notes at `idea` and `trialing` are invisible to a repo that was just
onboarded. This is what closes that gap. Two tiers, and the difference matters:
- **Governs files here** — the note's own `applies-to` glob matches real files.
A promotion delta is shown for these (`-> applying here clears ENFORCED`).
Use these to replace step 2's guessed list.
- **Same domain, judgement required** — matched on domain alone. **No promotion
claim is made**, because a guess that says "clears ENFORCED" would invite
adding a `repos:` entry for a note that does not govern this repo.
**Report these; never apply them, and never offer to apply them all.** Promotion
is driven by `length(repos)`, and the vault's own rule is that `trialing` must be
*earned by deliberate re-application, not just counted*. Applying a dozen notes in
one onboarding pass would add a dozen `repos:` entries and manufacture exactly the
evidence the bar exists to measure — the same defect as promoting a note on a
single repo. Onboarding is also when the repo is least understood, which is the
worst moment to change its code.
If the user picks one, apply **that one**, then record it through
`update-second-brain` so the `repos:` bump and any promotion are captured as the
deliberate act they were.
Sanity-check a delta before repeating it: a note whose glob is `**/package.json`
matches every Node repo ever written, and the rung it would clear is not evidence
of anything. Say so rather than passing it on.
### 3. Project onboarding rule
Create or update **one** always-apply rule:
`<TARGET>/.cursor/rules/<slug>-onboarding.mdc`
- `slug` = short project name (directory basename, kebab-case)
- If a `*-onboarding.mdc` already exists with real project content, **update in
place** (preserve project-specific bullets; add any missing standards pointers)
- If missing, create from the template below
```markdown
---
description: <Project> agent entry — standards sync, done criteria, vault pointer
alwaysApply: true
---
# <Project> — Agent onboarding
- Start from `AGENTS.md` (synced from second-brain-workflow). Architecture/commands: `CLAUDE.md` if present.
- Shared stack rules: vendored copies under `.cursor/rules/` — generated by `~/second-brain-workflow/scripts/render.py`; edit the source rules and re-render, not here.
- Deep patterns: read matching notes in the vault via the `obsidian-knowledge-base` skill; do not copy the vault into this repo.
- Stack here: <inferred stacks>.
- Relevant practices: <wikilink-style note slugs or filenames without .md>.
- Task is done only when: <lint / typecheck / test commands for this repo>.
```
Fill done-criteria from the repo’s real scripts (`package.json` scripts, `Makefile`, etc.). If unknown, use a honest placeholder the user can tighten.
### 4. Optional `CLAUDE.md`
- If **missing** and the repo is non-trivial: create a **short** stub (project one-liner, setup/dev/test commands only). Do not invent architecture essays.
- If **present**: leave it; only add a one-line pointer to `AGENTS.md` + vault if absent.
### 5. Vault / daily note
Append a one-line Built bullet to today's daily note — e.g. “Onboarded `<repo>`
into second-brain-workflow”. Daily notes need **no approval** (see
`obsidian-knowledge-base`). Do not write `practices/**` during onboard unless
the user asks (those still require proposal + approval).
**Never write `$SBW_VAULT/YYYY-MM-DD.md` directly.** A wrap-up in another
session may be composing that same note right now, and a whole-file write drops
whatever it had already put there. Use the same compare-and-swap path
`update-second-brain` uses:
```bash
printf '## Built\n- Onboarded `%s` into second-brain-workflow\n' "$repo" > /tmp/onboard-block.md
STAMP="$(~/second-brain-workflow/scripts/append-daily-block.py --stamp --quiet)"
~/second-brain-workflow/scripts/append-daily-block.py --expect "$STAMP" --block /tmp/onboard-block.md
```
Exit 3 means another session wrote first: re-run `--stamp` and re-run the
append. Commit the note as soon as it is written rather than at the end.
### 6. Project-scoped MCP (required for product apps)
**Read and follow** `mcp-per-project`.
Do this every time you onboard a product backend or its sibling app — not only when
the user mentions MCP.
#### Hard rules
1. **Never** add Railway / Postgres / Logfire / PostHog to `~/.cursor/mcp.json`
(keep `mcpServers: {}` for product infra).
2. Secrets live in the **backend** `.env` only; `mcp.json` has no tokens.
3. Server names are **product-suffixed** (e.g. `railway-initech`, `logfire-acme`)
— never bare `railway` / `logfire` when multiple products share the Mac.
4. Gitignore `.cursor/mcp.json`; commit `.cursor/mcp.json.example`, `.cursor/bin/*`,
`.cursor/README.md`, and `.cursor/rules/mcp.mdc`.
#### Backend (secret source)
Copy the closest already-wired backend on this machine (see *Reference backends*
above). The mix usually falls into one of two shapes — full product
(Railway + Postgres + Logfire + PostHog) or infra-light (Railway prod + staging
only) — so match on providers, not on project name:
1. Create `.cursor/bin/` wrappers that read `.env` and `exec` the MCP:
- `railway-mcp.sh` → `RAILWAY_TOKEN` → `railway mcp`
- `railway-postgres-mcp.sh` → `RAILWAY_TOKEN` → Postgres URL via Railway vars → `@modelcontextprotocol/server-postgres` (read-only)
- `logfire-mcp.sh` → `LOGFIRE_READ_TOKEN` → `uvx mcp-proxy` → `https://logfire-eu.pydantic.dev/mcp` (adjust region if the product is US)
- `posthog-mcp.sh` → `POSTHOG_PERSONAL_API_KEY` → `uvx mcp-proxy` → `https://mcp.posthog.com/mcp`
2. Write `.cursor/mcp.json` (local) and `.cursor/mcp.json.example` (committed) with
the suffixed server names pointing at those wrappers.
3. Write `.cursor/README.md` (token table + “never global”) and always-apply
`.cursor/rules/mcp.mdc` listing exact server names + no cross-product fallback.
4. Ensure `.gitignore` has `.cursor/mcp.json`.
5. Document empty keys in `.env.example` and append the same keys to `.env` if
missing (leave values empty for the user):
| Key | Purpose |
|-----|---------|
| `RAILWAY_TOKEN` | Railway project/environment token |
| `LOGFIRE_READ_TOKEN` | Logfire **read** token (`project:read`) — not write `LOGFIRE_TOKEN` |
| `POSTHOG_PERSONAL_API_KEY` | PostHog personal API key (MCP preset, `phx_…`) |
6. If tokens are already set, smoke-check with `GetMcpTools` / a cheap live call
after the user reloads MCP; report which servers are ready vs unauthorized.
If tokens are empty, tell the user what to create and to reload MCP — do not
block onboard on missing secrets.
#### Sibling app (frontend / mobile / Flutter)
Do **not** duplicate wrappers or put MCP tokens in the app `.env`.
1. `.cursor/mcp.json` + `.cursor/mcp.json.example` with **absolute paths** to the
backend’s `.cursor/bin/*.sh` (same suffixed server names).
2. Always-apply `.cursor/rules/mcp.mdc` pointing agents at those names and the
backend as the secret source.
3. Gitignore `.cursor/mcp.json`.
4. **Expo / RN repos:** also add `expo-<product>` → `{ "url": "https://mcp.expo.dev/mcp" }`
in both `mcp.json` and `mcp.json.example`, list it in `mcp.mdc`, and remind
the user to reload MCP + complete Expo OAuth (EAS paid plan). See
`mcp-per-project` rule 7.
If the matching backend is not onboarded yet, onboard/MCP-wire the backend first
(or ask which backend path owns secrets).
#### Skip
Libs, docs, `second-brain-workflow`, vault — no product MCP. Say “MCP skipped” in Done.
## Done means
Short status:
1. Target path
2. Sync result (rules linked + `AGENTS.md`)
3. Onboarding rule path (created/updated)
4. Inferred stack + practice note slugs
5. Skills scoped to this repo (already installed), and any candidate worth
considering with its cost — or "no manifest configured" if step 2b was skipped.
Nothing installed either way.
6. `CLAUDE.md` action (created stub / left alone / skipped)
7. MCP action (backend wired / sibling pointed at `<backend>` / skipped) + server
name suffixes + whether tokens are SET/EMPTY / live check if possible
8. Daily-note path updated
9. Render mode — shared, or **local** with the reason, since that is the line
that tells the user whether anyone else will see these files
Do not commit, push, or open extra PRs unless asked.
## Undoing this
Retiring a repo is the **`unrender-repo`** skill, not a hand-cleanup. Removing
the rendered files without forgetting the repo — or the reverse — leaves a
state doctor reports on every run.