CtrlK
BlogDocsLog inGet started
Tessl Logo

scaffold-docs

Install the RoleModel agent-documentation structure in a project: a minimal AGENTS.md, a docs/ tree with CONVENTIONS.md and INDEX.md, a path-scoped Copilot instructions file, the surface_conventions PreToolUse hook, and the wrap-up skill.

68

Quality

86%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Scaffold Docs

Install the structure, not the content. Empty indexes are correct on day one — the wrap-up skill fills them in over time.

Only the first link in the chain is always in context:

CLAUDE.md → AGENTS.md (<50 lines, always loaded)
              ├→ docs/CONVENTIONS.md → docs/conventions/*.md  (hook surfaces these on edit)
              ├→ docs/INDEX.md       → docs/subsystems/*.md, docs/guides/*.md
              └→ docs/ARCHITECTURE.md

.github/instructions/conventions.instructions.md  (Copilot's entry to the same chain)
              └→ docs/CONVENTIONS.md

Every step merges. Never clobber a file that has content.

1. Survey

Note what exists — AGENTS.md, CLAUDE.md, docs/, .claude/. Find the test and lint commands in package.json, Rakefile, Makefile, or CI config. If they don't turn up in a minute, leave a TODO and report it. Never invent a command.

2. docs tree

Copy from templates/, filling the <> placeholders:

TemplateDestination
CONVENTIONS.template.mddocs/CONVENTIONS.md — verbatim, empty index
INDEX.template.mddocs/INDEX.md — verbatim, empty sections
ARCHITECTURE.template.mddocs/ARCHITECTURE.md — stack names only, no versions, no prose tour

Create docs/conventions/, docs/subsystems/, docs/guides/, each holding a .gitkeep — they end the run empty by design, and git won't carry an empty directory. Where a file already exists, add only what's missing.

3. AGENTS.md

No AGENTS.md → copy templates/AGENTS.template.md and fill it in. The template is the whole file; resist adding sections.

An AGENTS.md exists → follow references/trimming.md. Target under 50 lines.

Then make CLAUDE.md exactly @AGENTS.md. If it holds real content, trim that into AGENTS.md first.

4. Copilot instructions

Copilot doesn't read AGENTS.md. Copy templates/conventions.instructions.template.md to .github/instructions/conventions.instructions.md, filling the <> placeholders. Set applyTo from directories that exist — source, test, migration, config — comma-separated in one quoted string.

It stays a pointer to docs/CONVENTIONS.md; don't restate a convention in it. Merge if the file exists, and leave the directory's other *.instructions.md files alone.

If the linear MCP server isn't connected yet, report that they should connect it and store the key as a Copilot agent secret named COPILOT_MCP_LINEAR_API_KEY. Never ask for the key.

5. Skills

Skills live in .agents/skills/, the tool-neutral location, but each tool discovers only its own directory — Claude Code .claude/skills/, Copilot .github/skills/. Bridge both once and commit the symlinks — git stores them as links, so every checkout works:

mkdir -p .agents/skills .claude .github
touch .agents/skills/.gitkeep
ln -s ../.agents/skills .claude/skills
ln -s ../.agents/skills .github/skills
git check-ignore .claude/skills .github/skills  # prints ignored paths; exit 1 means neither is

The .gitkeep matters: if the submodule step below is skipped, .agents/skills/ stays empty, git drops it, and the bridges dangle on a fresh checkout.

Any path check-ignore prints is ignored, which means the symlink, the step 6 hook, and settings.json all stay on this machine and reach nobody else. .claude is commonly ignored wholesale in Rails repos, alongside .vscode/ and .idea/. The fix is not to delete that line — it also keeps .claude/worktrees/ and personal settings.local.json out of the repo. Replace the bare .claude entry with .claude/worktrees/ and .claude/settings.local.json, and report the edit.

If .claude/skills/ or .github/skills/ is already a real directory, move its contents into .agents/skills/ first, then bridge.

wrap-up comes from the shared repo, not a copy, so upstream fixes reach the project through git submodule update --remote:

git submodule add https://github.com/RoleModel/rolemodel-skills.git .github/rolemodel-skills
ln -s ../../.github/rolemodel-skills/skills/wrap-up .agents/skills/wrap-up

Skip the add if the submodule is already there, and confirm with the user before running it — it writes .gitmodules. If the project already has a session-end skill, leave it and report the conflict.

A clone without --recurse-submodules leaves .github/rolemodel-skills/ empty and wrap-up dangling, which reads as a broken skill rather than an absent one. Add git submodule update --init to the project's own setup instructions — README.md, or wherever a new developer's first-run steps live.

6. The hook

Hooks have no tool-neutral home, so they stay under .claude/. Copy assets/surface_conventions.rb into .claude/hooks/ (creating the directory), make it executable, and register it in .claude/settings.json — merging into any existing hooks object:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "^(Edit|Write)$",
        "hooks": [
          {
            "type": "command",
            "command": "\"${CLAUDE_PROJECT_DIR}/.claude/hooks/surface_conventions.rb\""
          }
        ]
      }
    ]
  }
}

If a command referencing surface_conventions.rb is already registered, leave the hooks block alone — re-running this skill on a scaffolded repo would otherwise append a second entry and fire the hook twice per edit.

Matchers are unanchored regexes, so ^(Edit|Write)$ is deliberate — a bare Edit would also fire on NotebookEdit.

Two limits worth stating to the user: the hook needs Ruby on PATH, and without it, skip the hook entirely — the rest works, minus just-in-time surfacing. And files written through Bash — heredoc, sed -i, patch — never trigger it. Adding Bash to the matcher doesn't help, because that payload carries tool_input.command rather than file_path. Conventions still reach an agent that reads AGENTS.md; the hook is a second net, not the only one.

7. Verify and report

Check that every path the new files reference resolves, test -e passes on each skill symlink — it follows the link, so it fails on a dangling one — AGENTS.md is under 50 lines, the hook is executable, settings.json is valid JSON, and every glob in applyTo matches something.

Then run the hook once for real, because every check above is static and a hook that raises on every invocation passes all of them:

printf '{"session_id":"scaffold-verify","cwd":"%s","tool_input":{"file_path":"%s/<an existing file>"}}' "$PWD" "$PWD" \
  | env -u LANG -u LC_ALL .claude/hooks/surface_conventions.rb

Unsetting the locale matters: hooks run in a non-login shell, which is where the encoding of the index bites and nowhere else. Exit 0 with no output is the correct result on a fresh scaffold — the index is empty, so nothing can surface, and what this proves is that the script parses the index without raising. Point the path at a file some glob matches once real conventions exist, and expect additionalContext naming them.

Report what was created, what was merged, what left AGENTS.md and where it went, every TODO you left behind, and the Linear MCP setup from step 4 if it isn't already in place.

Repository
RoleModel/rolemodel-skills
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.