From 0ae871fdd33086cb31ac8552835baf3736a460e0 Mon Sep 17 00:00:00 2001 From: Srinivas Vaddi <38348871+vaddisrinivas@users.noreply.github.com> Date: Fri, 3 Apr 2026 02:28:33 -0400 Subject: [PATCH 1/5] feat: add code-tour skill for AI-generated CodeTour walkthroughs --- skills/code-tour/SKILL.md | 646 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 646 insertions(+) create mode 100644 skills/code-tour/SKILL.md diff --git a/skills/code-tour/SKILL.md b/skills/code-tour/SKILL.md new file mode 100644 index 000000000..b4aed1fdc --- /dev/null +++ b/skills/code-tour/SKILL.md @@ -0,0 +1,646 @@ +--- +name: code-tour +description: > + Use this skill to create CodeTour .tour files — persona-targeted, step-by-step walkthroughs + that link to real files and line numbers. Trigger for: "create a tour", "make a code tour", + "generate a tour", "onboarding tour", "tour for this PR", "tour for this bug", "RCA tour", + "architecture tour", "explain how X works", "vibe check", "PR review tour", + "contributor guide", "help someone ramp up", or any request for a structured walkthrough + through code. Supports 20 developer personas (new joiner, bug fixer, architect, PR reviewer, + vibecoder, security reviewer, and more), all CodeTour step types (file/line, selection, + pattern, uri, commands, view), and tour-level fields (ref, isPrimary, nextTour). + Works with any repository in any language. +--- + +# Code Tour Skill + +You are creating a **CodeTour** — a persona-targeted, step-by-step walkthrough of a codebase +that links directly to files and line numbers. CodeTour files live in `.tours/` and work with +the [VS Code CodeTour extension](https://github.com/microsoft/codetour). + +Two scripts are bundled in `scripts/`: + +- **`scripts/validate_tour.py`** — run after writing any tour. Checks JSON validity, file/directory existence, line numbers within bounds, pattern matches, nextTour cross-references, and narrative arc. Run it: `python ~/.agents/skills/code-tour/scripts/validate_tour.py .tours/.tour --repo-root .` +- **`scripts/generate_from_docs.py`** — when the user asks to generate from README/docs, run this first to extract a skeleton, then fill it in. Run it: `python ~/.agents/skills/code-tour/scripts/generate_from_docs.py --persona new-joiner --output .tours/skeleton.tour` + +Two reference files are bundled: + +- **`references/codetour-schema.json`** — the authoritative JSON schema. Read it to verify any field name or type. Every field you use must conform to it. +- **`references/examples.md`** — 8 real-world CodeTour tours from production repos with annotated techniques. Read it when you want to see how a specific feature (`commands`, `selection`, `view`, `pattern`, `isPrimary`, multi-tour series) is used in practice. + +### Real-world `.tour` files on GitHub + +These are confirmed production `.tour` files. Fetch one when you need a working example of a specific step type, tour-level field, or narrative structure — don't write from memory when the real thing is one fetch away. + +Find more with the GitHub code search: https://github.com/search?q=path%3A**%2F*.tour+&type=code + +#### By step type / technique demonstrated + +| What to study | File URL | +|---|---| +| `directory` + `file+line` (contributor onboarding) | https://github.com/coder/code-server/blob/main/.tours/contributing.tour | +| `selection` + `file+line` + intro content step (accessibility project) | https://github.com/a11yproject/a11yproject.com/blob/main/.tours/code-tour.tour | +| Minimal tutorial — tight `file+line` narration for interactive learning | https://github.com/lostintangent/rock-paper-scissors/blob/master/main.tour | +| Multi-tour repo with `nextTour` chaining (cloud native OCI walkthroughs) | https://github.com/lucasjellema/cloudnative-on-oci-2021/blob/main/.tours/introduction.tour | +| `isPrimary: true` (marks the onboarding entry point) | https://github.com/nickvdyck/webbundlr/blob/main/.tours/getting-started.tour | +| `pattern` instead of `line` (regex-anchored steps) | https://github.com/nickvdyck/webbundlr/blob/main/.tours/architecture.tour | + +#### Notes on each + +**`coder/code-server` — Contributing** +Opens with a `directory` step on `src/` that orients with a single sentence, then drives straight into `src/node/entry.ts` line 157. Clean external-contributor structure: orientation → entry point → key subsystems → links to FAQ docs via URI steps. Good model for any contributor tour. + +**`a11yproject/a11yproject.com` — Code Tour** +Uses `selection` to highlight a block within `package.json` (start line 1, end varies) alongside a `line` for the same file. Shows how to vary step type on the same file. Note: the intro step in this tour is content-only — in some VS Code versions this renders blank. Prefer anchoring the first step to a file or directory and putting the welcome text in its description. + +**`lostintangent/rock-paper-scissors` — main.tour** +Only 4–5 steps. Shows how a minimal tour can be complete: every step tells the reader something actionable, links to a specific line, and ends with a clear call to action ("try changing this and watch it take effect"). Good reference when writing a vibecoder or quick-explainer tour. + +**`lucasjellema/cloudnative-on-oci-2021` — multi-tour series** +Multiple `.tour` files in the same repo, each scoped to a different cloud service. Browse the `.tours/` directory to see how a series is organized — separate files, clear scoped titles, and `nextTour` linking between them. Good model for a complex domain with a tour-series strategy. + +**Raw content tip:** If GitHub rate-limits the HTML view, prefix `raw.githubusercontent.com` and drop `/blob/`: +``` +https://raw.githubusercontent.com/coder/code-server/main/.tours/contributing.tour +https://raw.githubusercontent.com/a11yproject/a11yproject.com/main/.tours/code-tour.tour +https://raw.githubusercontent.com/lostintangent/rock-paper-scissors/master/main.tour +``` + +A great tour is not just annotated files. It is a **narrative** — a story told to a specific +person about what matters, why it matters, and what to do next. Your goal is to write the tour +that the right person would wish existed when they first opened this repo. + +**CRITICAL: Only create `.tour` JSON files. Never create, modify, or scaffold any other files.** + +--- + +## Step 1: Discover the repo + +Before asking the user anything, explore the codebase: + +- List the root directory, read the README, and check key config files + (package.json, pyproject.toml, go.mod, Cargo.toml, composer.json, etc.) +- Identify the language(s), framework(s), and what the project does +- Map the folder structure 1–2 levels deep +- Find entry points: main files, index files, app bootstrapping +- **Note which files actually exist** — every path you write in the tour must be real + +If the repo is sparse or empty, say so and work with what exists. + +**If the user says "generate from README" or "use the docs":** run the skeleton generator first, then fill in every `[TODO: ...]` by reading the actual files: + +```bash +python skills/code-tour/scripts/generate_from_docs.py \ + --persona new-joiner \ + --output .tours/skeleton.tour +``` + +### Entry points by language/framework + +Don't read everything — start here, then follow imports. + +| Stack | Entry points to read first | +|-------|---------------------------| +| **Node.js / TS** | `index.js/ts`, `server.js`, `app.js`, `src/main.ts`, `package.json` (scripts) | +| **Python** | `main.py`, `app.py`, `__main__.py`, `manage.py` (Django), `app/__init__.py` (Flask/FastAPI) | +| **Go** | `main.go`, `cmd//main.go`, `internal/` | +| **Rust** | `src/main.rs`, `src/lib.rs`, `Cargo.toml` | +| **Java / Kotlin** | `*Application.java`, `src/main/java/.../Main.java`, `build.gradle` | +| **Ruby** | `config/application.rb`, `config/routes.rb`, `app/controllers/application_controller.rb` | +| **PHP** | `index.php`, `public/index.php`, `bootstrap/app.php` (Laravel) | + +### Repo type variants — adjust focus accordingly + +The same persona asks for different things depending on what kind of repo this is: + +| Repo type | What to emphasize | Typical anchor files | +|-----------|-------------------|----------------------| +| **Service / API** | Request lifecycle, auth, error contracts | router, middleware, handler, schema | +| **Library / SDK** | Public API surface, extension points, versioning | index/exports, types, changelog | +| **CLI tool** | Command parsing, config loading, output formatting | main, commands/, config | +| **Monorepo** | Package boundaries, shared contracts, build graph | root package.json/pnpm-workspace, shared/, packages/ | +| **Framework** | Plugin system, lifecycle hooks, escape hatches | core/, plugins/, lifecycle | +| **Data pipeline** | Source → transform → sink, schema ownership | ingest/, transform/, schema/, dbt models | +| **Frontend app** | Component hierarchy, state management, routing | pages/, store/, router, api/ | + +For **monorepos**: identify the 2–3 packages most relevant to the persona's goal. Don't try to tour everything — open the tour with a step that explains how to navigate the workspace, then stay focused. + +### Large repo strategy + +For repos with 100+ files: don't try to read everything. + +1. Read entry points and the README first +2. Build a mental model of the top 5–7 modules +3. For the requested persona, identify the **2–3 modules that matter most** and read those deeply +4. For modules you're not covering, mention them in the intro step as "out of scope for this tour" +5. Use `directory` steps for areas you mapped but didn't read — they orient without requiring full knowledge + +A focused 10-step tour of the right files beats a scattered 25-step tour of everything. + +--- + +## Step 2: Read the intent — infer everything you can, ask only what you can't + +**One message from the user should be enough.** Read their request and infer persona, +depth, and focus before asking anything. + +### Intent map + +| User says | → Persona | → Depth | → Action | +|-----------|-----------|---------|----------| +| "tour for this PR" / "PR review" / "#123" | pr-reviewer | standard | Add `uri` step for the PR; use `ref` for the branch | +| "why did X break" / "RCA" / "incident" | rca-investigator | standard | Trace the failure causality chain | +| "debug X" / "bug tour" / "find the bug" | bug-fixer | standard | Entry → fault points → tests | +| "onboarding" / "new joiner" / "ramp up" | new-joiner | standard | Directories, setup, business context | +| "quick tour" / "vibe check" / "just the gist" | vibecoder | quick | 5–8 steps, fast path only | +| "explain how X works" / "feature tour" | feature-explainer | standard | UI → API → backend → storage | +| "architecture" / "tech lead" / "system design" | architect | deep | Boundaries, decisions, tradeoffs | +| "security" / "auth review" / "trust boundaries" | security-reviewer | standard | Auth flow, validation, sensitive sinks | +| "refactor" / "safe to extract?" | refactorer | standard | Seams, hidden deps, extraction order | +| "performance" / "bottlenecks" / "slow path" | performance-optimizer | standard | Hot path, N+1, I/O, caches | +| "contributor" / "open source onboarding" | external-contributor | quick | Safe areas, conventions, landmines | +| "concept" / "explain pattern X" | concept-learner | standard | Concept → implementation → rationale | +| "test coverage" / "where to add tests" | test-writer | standard | Contracts, seams, coverage gaps | +| "how do I call the API" | api-consumer | standard | Public surface, auth, error semantics | + +**Infer silently:** persona, depth, focus area, whether to add `uri`/`ref`, `isPrimary`. + +**Ask only if you genuinely can't infer:** +- "bug tour" but no bug described → ask for the bug description +- "feature tour" but no feature named → ask which feature +- "specific files" explicitly requested → honor them as required stops + +Never ask about `nextTour`, `commands`, `when`, or `stepMarker` unless the user mentioned them. + +### PR tour recipe + +When the user says "tour for this PR" or pastes a GitHub PR URL: + +1. Set `"ref"` to the PR's branch name +2. Open with a `uri` step pointing to the PR itself — this gives the reviewer the full diff context +3. Add a `uri` step for any related issue or RFC if linked in the PR description +4. Cover **changed files first** — what changed and why +5. Then add steps for **files not in the diff** that reviewers must understand to evaluate the change correctly (call sites, dependency files, tests) +6. Flag invariants the change must preserve +7. Close with a reviewer checklist: what to verify, what tests to run, what to watch out for + +```json +[ + { "uri": "https://github.com/org/repo/pull/456", + "title": "The PR", "description": "This PR refactors auth to use refresh tokens. Key concern: session invalidation during migration." }, + { "file": "src/auth/tokenService.ts", "line": 12, "title": "What Changed: Token Issuing", "description": "..." }, + { "file": "src/auth/middleware.ts", "line": 38, "title": "Unchanged But Critical", "description": "This file wasn't touched but depends on the token shape. Verify line 38 still matches." }, + { "title": "Reviewer Checklist", "description": "- [ ] Session invalidation tested?\n- [ ] Old tokens still rejected after migration?\n- [ ] Refresh token rotation tested?" } +] +``` + +### User-provided customization — always honor these + +| User says | What to do | +|-----------|-----------| +| "cover `src/auth.ts` and `config/db.yml`" | Those files are required stops | +| "pin to the `v2.3.0` tag" / "this commit: abc123" | Set `"ref": "v2.3.0"` | +| "link to PR #456" / pastes a URL | Add a `uri` step at the right narrative moment | +| "lead into the security tour when done" | Set `"nextTour": "Security Review"` | +| "make this the main onboarding tour" | Set `"isPrimary": true` | +| "open a terminal at this step" | Add `"commands": ["workbench.action.terminal.focus"]` | +| "deep" / "thorough" / "5 steps" / "quick" | Override depth accordingly | + +--- + +## Step 3: Read the actual files — no exceptions + +**Every file path and line number in the tour must be verified by reading the file.** +A tour pointing to the wrong file or a non-existent line is worse than no tour. + +For every planned step: +1. Read the file +2. Find the exact line of the code you want to highlight +3. Understand it well enough to explain it to the target persona + +If a user-requested file doesn't exist, say so — don't silently substitute another. + +--- + +## Step 4: Write the tour + +Save to `.tours/-.tour`. Read `references/codetour-schema.json` for the +authoritative field list. Every field you use must appear in that schema. + +### Tour root + +```json +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "Descriptive Title — Persona / Goal", + "description": "One sentence: who this is for and what they'll understand after.", + "ref": "main", + "isPrimary": false, + "nextTour": "Title of follow-up tour", + "steps": [] +} +``` + +Omit any field that doesn't apply to this tour. + +**`when`** — conditional display. A JavaScript expression evaluated at runtime. Only show this tour +if the condition is true. Useful for persona-specific auto-launching, or hiding advanced tours +until a simpler one is complete. +```json +{ "when": "workspaceFolders[0].name === 'api'" } +``` + +**`stepMarker`** — embed step anchors directly in source code comments. When set, CodeTour +looks for `// ` comments in files and uses them as step positions instead of +(or alongside) line numbers. Useful for tours on actively changing code where line numbers +shift constantly. Example: set `"stepMarker": "CT"` and put `// CT` in the source file. +Don't suggest this unless the user asks — it requires editing source files, which is unusual. + +--- + +### Step types — the full toolkit + +**Content step** — narrative only, no file. Use for intro and closing. Max 2 per tour. +```json +{ "title": "Welcome", "description": "markdown..." } +``` + +**Directory step** — orient to a module. "What lives here." +```json +{ "directory": "src/services", "title": "Service Layer", "description": "..." } +``` + +**File + line step** — the workhorse. One specific meaningful line. +```json +{ "file": "src/auth/middleware.ts", "line": 42, "title": "Auth Gate", "description": "..." } +``` + +> **Path rule — always relative to repo root.** `"file"` and `"directory"` values must be relative to the repository root (the directory that contains `.tours/`). Never use an absolute path (`/Users/...`) and never use a leading `./`. If the repo root is `/projects/myapp` and the file is at `/projects/myapp/src/auth.ts`, write `"src/auth.ts"` — not `./src/auth.ts`, not `/projects/myapp/src/auth.ts`, not `auth.ts` (unless it's actually at the root). + +**Selection step** — a block of logic. Use when one line isn't enough (a function body, a config block, a type definition). +```json +{ + "file": "src/core/pipeline.py", + "selection": { "start": { "line": 15, "character": 0 }, "end": { "line": 34, "character": 0 } }, + "title": "The Request Pipeline", + "description": "..." +} +``` + +**Pattern step** — match by regex instead of line number. Use when line numbers shift frequently (actively changing files, generated code). +```json +{ "file": "src/app.ts", "pattern": "export default class Application", "title": "...", "description": "..." } +``` + +**URI step** — link to an external resource: a PR, issue, RFC, ADR, architecture diagram, Notion doc. Use to bring in context that lives outside the codebase. +```json +{ + "uri": "https://github.com/org/repo/pull/456", + "title": "The PR That Introduced This Pattern", + "description": "This design was debated in PR #456. The key tradeoff was..." +} +``` + +**View step** — auto-focus a VS Code panel at this step (terminal, problems, scm, explorer). +```json +{ "file": "src/server.ts", "line": 1, "view": "terminal", "title": "...", "description": "..." } +``` + +**Commands step** — execute VS Code commands when the reader arrives. Add to any file step. +```json +{ + "file": "src/server.ts", "line": 1, + "title": "Run It", + "description": "Hit the play button — you'll see the server boot sequence here.", + "commands": ["workbench.action.terminal.focus"] +} +``` + +Useful commands: +| Command | What it does | +|---------|-------------| +| `editor.action.goToDeclaration` | Jump to definition | +| `editor.action.showHover` | Show type hover | +| `references-view.findReferences` | Show all references | +| `workbench.action.terminal.focus` | Open terminal | +| `workbench.action.tasks.runTask` | Run a task | +| `workbench.view.scm` | Open source control panel | +| `workbench.view.explorer` | Open file explorer | + +--- + +### When to use each step type + +| Situation | Step type | +|-----------|-----------| +| Tour intro or closing | content | +| "Here's what lives in this folder" | directory | +| One line tells the whole story | file + line | +| A function/class body is the point | selection | +| Line numbers shift, file is volatile | pattern | +| PR / issue / doc gives the "why" | uri | +| Reader should open terminal or explorer | view or commands | + +--- + +### Step count calibration + +Match steps to depth and persona. These are targets, not hard limits. + +| Depth | Total steps | Core path steps | Notes | +|-------|-------------|-----------------|-------| +| Quick | 5–8 | 3–5 | Vibecoder, fast explorer — cut ruthlessly | +| Standard | 9–13 | 6–9 | Most personas — breadth + enough detail | +| Deep | 14–18 | 10–13 | Architect, RCA — every tradeoff surfaced | + +Scale with repo size too. A 3-file CLI doesn't get 15 steps. A 200-file monolith shouldn't be squeezed into 5. + +| Repo size | Recommended standard depth | +|-----------|---------------------------| +| Tiny (< 20 files) | 5–8 steps | +| Small (20–80 files) | 8–11 steps | +| Medium (80–300 files) | 10–13 steps | +| Large (300+ files) | 12–15 steps (scoped to relevant subsystem) | + +--- + +### Writing excellent descriptions — the SMIG formula + +Every description should answer four questions in order. You don't need four paragraphs — but every description needs all four elements, even briefly. + +**S — Situation**: What is the reader looking at? One sentence grounding them in context. +**M — Mechanism**: How does this code work? What pattern, rule, or design is in play? +**I — Implication**: Why does this matter for *this persona's goal specifically*? +**G — Gotcha**: What would a smart person get wrong here? What's non-obvious, fragile, or surprising? + +**Bad description** (generic — could apply to any codebase): +> "This is the authentication middleware. It checks if the user is authenticated before allowing access to protected routes." + +**Good description** (SMIG applied): +> **S:** Every HTTP request passes through this file before reaching any controller — it's the sole auth checkpoint. +> +> **M:** Notice the **dual-check pattern** on line 42: it validates the JWT signature *and* does a Redis lookup for the session. Both must pass. A valid JWT alone isn't enough if the session was revoked (logout, password reset, force-expire). +> +> **I:** For a bug fixer: if a user reports being logged out unexpectedly, this is your first stop. Redis miss → 401 → silent logout is the most common failure path. +> +> **G:** If Redis is down, line 53 propagates the error as a 401 — meaning a Redis outage silently logs everyone out. There's no circuit breaker here. This is tracked in ISSUE-4421, and the workaround is in `config/redis.ts` line 18. + +The good description tells the reader something they couldn't learn by reading the file themselves. It names the pattern, explains the design decision, flags the failure mode, and cross-references related context. + +**Persona vocabulary cheat sheet** — speak their language, not generic developer-speak: + +| Persona | Their vocabulary | Avoid | +|---------|-----------------|-------| +| New joiner | "this means", "you'll need to", "the team calls this" | acronyms, assumed context | +| Bug fixer | "failure path", "where this breaks", "repro steps" | architecture history | +| Security reviewer | "trust boundary", "untrusted input", "privilege escalation" | vague "be careful" | +| PR reviewer | "invariant", "this must stay true", "the change story" | unrelated context | +| Architect | "seam", "coupling", "extension point", "decision" | step-by-step walkthroughs | +| Vibecoder | "the main loop", "ignore for now", "start here" | deep explanations | + +--- + +## Narrative arc — every tour, every persona + +1. **Orientation** — **must be a `file` or `directory` step, never content-only.** + Use `"file": "README.md", "line": 1` or `"directory": "src"` and put your welcome text in the description. + A content-only first step (no `file`, `directory`, or `uri`) renders as a blank page in VS Code CodeTour — this is a known VS Code extension behaviour, not configurable. + +2. **High-level map** (1–3 directory or uri steps) — major modules and how they relate. + Not every folder — just what this persona needs to know. + +3. **Core path** (file/line, selection, pattern, uri steps) — the specific code that matters. + This is the heart of the tour. Read and narrate. Don't skim. + +4. **Closing** (content) — what the reader now understands, what they can do next, + 2–3 suggested follow-up tours. If `nextTour` is set, reference it by name here. + +### What makes a closing step excellent + +The closing is frequently the weakest step. Don't summarize — the reader just read it. +Instead: + +❌ Bad closing (recap): +> "In this tour we covered the entry point, the middleware stack, and the database layer." + +✅ Good closing (action + next): +> "You now know enough to safely add a new route without breaking auth or session handling. +> The danger zones to stay away from are `src/auth/tokenService.ts` (don't change the token shape without a migration plan) and `src/db/pool.ts` (connection limits are load-tested at current values). +> +> **What's next:** +> - If you're fixing a bug → jump to the **Bug Fixer: Payment Flow** tour for the specific path +> - If you're adding a feature → the **Feature Explainer: Notifications** tour shows the full pattern +> - If something's on fire → the **RCA: Incident Guide** tour maps the observability anchors" + +The good closing tells the reader what they're now capable of, what to avoid, and gives them a map of where to go next. + +--- + +## The 20 personas + +| Persona | Goal | Must cover | Avoid | +|---------|------|------------|-------| +| **Vibecoder** | Get the vibe fast | Entry point, request flow, main modules. "Start here / Core loop / Ignore for now." Max 8 steps. | Deep dives, history, edge cases | +| **New joiner** | Structured ramp-up | Directories, setup/run instructions, business context, service boundaries, team terms defined. | Advanced internals before basics | +| **Reboarding engineer** | Catch up on what changed | What's new vs. what they remember. "This used to be X, now it's Y." | Re-explaining things they knew | +| **Bug fixer** | Root cause fast | User action → trigger → fault points. Validation, branching, error handling. Repro hints + test locations. | Architecture tours, business context | +| **RCA / incident investigator** | Why did it fail | Causality chain. State transitions, side effects, race conditions. Observability anchors. | Happy path | +| **Feature explainer** | One feature end-to-end | UI → API → backend → storage. Feature flags, auth, edge cases, scope. | Unrelated features | +| **Concept learner** | Understand a pattern | Concept intro → implementation → why this design → tradeoffs → common misunderstanding. | Code without conceptual framing | +| **PR reviewer** | Review the change correctly | The change story, not just changed files. Invariants. Risky areas. Reviewer checklist. URI step for the PR. | Unrelated context | +| **Maintainer** | Long-term health | Architectural intent. Extension points. "Do not bypass this layer." Long-lived invariants. | One-time setup concerns | +| **Refactorer** | Safe restructuring | Seams, hidden deps, implicit contracts, coupling hotspots, safe extraction order. | Feature explanations | +| **Performance optimizer** | Find bottlenecks | Hot paths, N+1, I/O, serialization. Caches, batching. Existing benchmarks. | Cold paths, setup code | +| **Security reviewer** | Trust boundaries + abuse paths | Auth flow. Input validation. Secret handling. Sensitive sinks. Safe failure modes. | Unrelated business logic | +| **Test writer** | Add good tests | Behavior contracts. Existing patterns. Mocking seams. Coverage gaps. High-value scenarios. | Implementation detail | +| **API consumer** | Call the system correctly | Public surface, request/response shapes, auth, error semantics, stable vs. internal. | Internal implementation | +| **Platform / infra engineer** | Operational understanding | Boot sequence, config loading, infra deps, background jobs, graceful shutdown. | Business logic | +| **Data engineer** | Data lineage + schemas | Event emission, schema definitions, source-to-sink path, data quality, backfill. | UI / request flow | +| **AI agent operator** | Deterministic navigation | Stable anchors, allowed edit zones, required validation steps. "Do not infer — read this file first." | Ambiguous or implied structure | +| **Product-minded engineer** | Business rules in code | Domain language, business rules, feature toggles, "why does this weird code exist?" | Pure infrastructure | +| **External contributor** | Contribute without breaking | Contribution-safe areas, code style, architecture landmines, typical first-timer mistakes. | Deep internals | +| **Tech lead / architect** | Shape and rationale | Module boundaries, design tradeoffs, risk hotspots, future evolution. | Line-by-line walkthroughs | + +--- + +## Designing a tour series + +When a codebase is complex enough that one tour can't cover it well, design a series. +The `nextTour` field chains them: when the reader finishes one tour, VS Code offers to +launch the next automatically. + +**Plan the series before writing any tour.** A good series has: +- A clear escalation path (broad → narrow, orientation → deep-dive) +- No duplicate steps between tours +- Each tour standalone enough to be useful on its own + +**Common series patterns:** + +*Onboarding series (new joiner):* +1. "Orientation" → repo structure, how to run it (isPrimary: true) +2. "Core Request Flow" → entry to response, middleware chain +3. "Data Layer" → models, migrations, query patterns +4. "Testing Patterns" → how to write and run tests + +*Incident / debug series (bug fixer + RCA):* +1. "Happy Path" → normal flow from trigger to response +2. "Failure Modes" → where it can break and why +3. "Observability Map" → logs, metrics, traces to look at + +*Architecture series (tech lead):* +1. "Module Boundaries" → what lives where and why +2. "Extension Points" → where to add new features +3. "Danger Zones" → what must never be changed carelessly + +**When writing a series:** set `nextTour` in each tour to the `title` of the next one. +The value must match exactly. Tell the reader in the closing step which tour comes next +and why they should read it. + +### Hot files — anchor the series + +Some files deserve a step in almost every tour because they're where the system's core rules live. Identify 2–3 of these early and treat them as anchors: + +- The **main entry point** — every persona needs to see this +- The **central router or dispatcher** — where requests branch +- The **primary config loader** — where behavior is controlled +- The **auth boundary** — the single place permissions are checked + +When the same file appears in multiple tours, give it a *different* framing each time — new joiners get "this is where the server starts", security reviewers get "this is the only place secrets are loaded". + +--- + +## What CodeTour cannot do + +If asked for any of these, say clearly that it's not supported — do not suggest a workaround that doesn't exist: + +| Request | Reality | +|---|---| +| **Auto-advance to next step after X seconds** | Not supported. Navigation is always manual — the reader clicks Next. There is no timer, delay, or autoplay step mechanic in CodeTour. | +| **Embed a video or GIF in a step** | Not supported. Descriptions are Markdown text only. | +| **Run arbitrary shell commands** | Not supported. `commands` only executes VS Code commands (e.g. `workbench.action.terminal.focus`), not shell commands. | +| **Branch / conditional next step** | Not supported. Tours are linear. `when` controls whether a tour is shown, not which step follows which. | +| **Show a step without opening a file** | Partially — content-only steps work, but step 1 must have a `file` or `directory` anchor or VS Code shows a blank page. | + +--- + +## Anti-patterns — what ruins a tour + +Avoid these. They are the most common failures. + +| Anti-pattern | What it looks like | The fix | +|---|---|---| +| **File listing** | Visiting `models.py`, `routes.py`, `utils.py` in sequence with descriptions like "this file contains the models" | Tell a story — each step should depend on having seen the previous one. Ask: "why does this step come after the last one?" | +| **Generic descriptions** | "This is the main entry point of the application." | If your description would make sense for any repo, rewrite it. Name the specific pattern, decision, or gotcha that's unique to *this* codebase. | +| **Line number guessing** | Writing `"line": 42` without reading the file | Never write a line number you didn't verify. Off-by-one lands the cursor on the wrong code and breaks trust instantly. | +| **Ignoring the persona** | Security reviewer getting a folder structure tour | Step selection must reflect what this specific person is trying to accomplish. Cut every step that doesn't serve their goal. | +| **Too many steps** | A 20-step "vibecoder" tour | Respecting depth means *actually cutting steps* — not just labeling it "quick." | +| **Hallucinated files** | Steps pointing to files that don't exist | If a file doesn't exist in the repo, skip the step. Never use a placeholder. | +| **Recap closing** | "In this tour we covered X, Y, and Z." | The closing should tell the reader what they can now *do*, what to watch out for, and where to go next. | +| **Persona vocabulary mismatch** | Explaining JWTs to a security reviewer | Meet each persona where they are. Security reviewers know what a JWT is — tell them what's *wrong* with this implementation. | +| **Broken `nextTour`** | `"nextTour"` value doesn't exactly match any tour title | Always copy the title string verbatim. A typo silently breaks the chain. | + +--- + +## Quality checklist — verify before writing the file + +- [ ] Every `file` path is **relative to the repo root** (no leading `/` or `./`) +- [ ] Every `file` path read and confirmed to exist +- [ ] Every `line` number verified by reading the file (not guessed) +- [ ] Every `directory` is **relative to the repo root** and confirmed to exist +- [ ] Every `pattern` regex would match a real line in the file +- [ ] Every `uri` is a complete, real URL (https://...) +- [ ] `ref` is a real branch/tag/commit if set +- [ ] `nextTour` exactly matches the `title` of another `.tour` file if set +- [ ] Only `.tour` JSON files created — no source code touched +- [ ] First step has a `file` or `directory` anchor (content-only first step = blank page in VS Code) +- [ ] Tour ends with a closing content step that tells the reader what they can *do* next +- [ ] Every description answers SMIG — Situation, Mechanism, Implication, Gotcha +- [ ] Persona's priorities drive step selection (cut everything that doesn't serve their goal) +- [ ] Step count matches requested depth and repo size (see calibration table) +- [ ] At most 2 content-only steps (intro + closing) +- [ ] All fields conform to `references/codetour-schema.json` + +--- + +## Step 5: Validate the tour + +**Always run the validator immediately after writing the tour file. Do not skip this step.** + +```bash +python ~/.agents/skills/code-tour/scripts/validate_tour.py .tours/.tour --repo-root . +``` + +The validator checks: +- JSON validity +- Every `file` path exists and every `line` is within file bounds +- Every `directory` exists +- Every `pattern` regex compiles and matches at least one line in the file +- Every `uri` starts with `https://` +- `nextTour` matches an existing tour title in `.tours/` +- Content-only step count (warns if > 2) +- Narrative arc (warns if no orientation or closing step) + +**Fix every error before proceeding.** Re-run until the validator reports ✓ or only warnings. Warnings are advisory — use your judgment. Do not show the user the tour until validation passes. + +**What actually breaks VS Code CodeTour** (the real causes of blank/broken steps): +- **Content-only first step** — step 1 has no `file`, `directory`, or `uri`. VS Code opens to a blank page. Fix: anchor step 1 to a file or directory and put the intro text in its description. +- **File path not relative to repo root** — absolute paths or `./`-prefixed paths silently fail to open. Fix: always use paths relative to where `.tours/` lives (e.g. `src/auth.ts`, not `./src/auth.ts`). +- **Line number out of bounds** — VS Code opens the file but scrolls nowhere. The validator catches this. + +These are the only structural issues that cause VS Code rendering failures. Description length, markdown formatting, and use of `\n` in JSON strings do NOT affect rendering. + +If you can't run scripts, do the equivalent check manually: +1. Confirm step 1 has a `file` or `directory` field +2. Confirm every `file` path exists by reading it (relative to repo root, no leading `./`) +3. Confirm every `line` is within the file's line count +4. Confirm every `directory` exists +5. Read the step titles in sequence — do they tell a coherent story? +6. Confirm `nextTour` matches another tour's `title` exactly + +**Autoplay on repo open** — `isPrimary: true` makes CodeTour show a "Start Tour?" prompt when the repo opens in VS Code. To make this reliable for everyone who clones the repo, also write `.vscode/settings.json`: + +```json +{ "codetour.promptForPrimaryTour": true } +``` + +Without this file, the prompt depends on each user's global VS Code config. Committed to the repo, it fires for everyone automatically. Create this file whenever you set `isPrimary: true`. + +**`ref` and autoplay:** if the tour has `"ref": "main"`, CodeTour only prompts when the user is on that exact branch or tag. For tours that should appear on any branch, omit `ref`. + +**Share via vscode.dev** — the fastest way for someone to use the tour without +cloning the repo. For any public GitHub repo with tours committed to `.tours/`, +they can open it directly in the browser: + +``` +https://vscode.dev/github.com// +``` + +VS Code Web will detect the `.tours/` directory and offer to start the tour. +No install needed. Tell the user this URL in your summary when the repo is public. + +--- + +## Step 6: Summarize + +After writing the tour, tell the user: +- File path (`.tours/.tour`) +- One-paragraph summary of what the tour covers and who it's for +- The `vscode.dev` URL if the repo is public (so they can share it immediately) +- 2–3 suggested follow-up tours (or the next tour in the series if one was planned) +- Any user-requested files that didn't exist (be explicit — don't quietly substitute) + +--- + +## File naming + +`-.tour` — kebab-case, communicates both: +``` +onboarding-new-joiner.tour +bug-fixer-payment-flow.tour +architect-overview.tour +vibecoder-quickstart.tour +pr-review-auth-refactor.tour +security-auth-boundaries.tour +concept-dependency-injection.tour +rca-login-outage.tour +``` \ No newline at end of file From 401013360edcd342791e3a0034fc645576190fce Mon Sep 17 00:00:00 2001 From: Srinivas Vaddi Date: Fri, 3 Apr 2026 07:11:39 -0400 Subject: [PATCH 2/5] fix: trim SKILL.md from 645 to 432 lines (under 500 limit) Reduce persona table to top 10, condense verbose examples and notes, trim redundant anti-patterns, compress step type docs and PR recipe. Co-Authored-By: Claude Opus 4.6 (1M context) --- skills/code-tour/SKILL.md | 275 +++++--------------------------------- 1 file changed, 31 insertions(+), 244 deletions(-) diff --git a/skills/code-tour/SKILL.md b/skills/code-tour/SKILL.md index b4aed1fdc..2edf704d6 100644 --- a/skills/code-tour/SKILL.md +++ b/skills/code-tour/SKILL.md @@ -45,26 +45,7 @@ Find more with the GitHub code search: https://github.com/search?q=path%3A**%2F* | `isPrimary: true` (marks the onboarding entry point) | https://github.com/nickvdyck/webbundlr/blob/main/.tours/getting-started.tour | | `pattern` instead of `line` (regex-anchored steps) | https://github.com/nickvdyck/webbundlr/blob/main/.tours/architecture.tour | -#### Notes on each - -**`coder/code-server` — Contributing** -Opens with a `directory` step on `src/` that orients with a single sentence, then drives straight into `src/node/entry.ts` line 157. Clean external-contributor structure: orientation → entry point → key subsystems → links to FAQ docs via URI steps. Good model for any contributor tour. - -**`a11yproject/a11yproject.com` — Code Tour** -Uses `selection` to highlight a block within `package.json` (start line 1, end varies) alongside a `line` for the same file. Shows how to vary step type on the same file. Note: the intro step in this tour is content-only — in some VS Code versions this renders blank. Prefer anchoring the first step to a file or directory and putting the welcome text in its description. - -**`lostintangent/rock-paper-scissors` — main.tour** -Only 4–5 steps. Shows how a minimal tour can be complete: every step tells the reader something actionable, links to a specific line, and ends with a clear call to action ("try changing this and watch it take effect"). Good reference when writing a vibecoder or quick-explainer tour. - -**`lucasjellema/cloudnative-on-oci-2021` — multi-tour series** -Multiple `.tour` files in the same repo, each scoped to a different cloud service. Browse the `.tours/` directory to see how a series is organized — separate files, clear scoped titles, and `nextTour` linking between them. Good model for a complex domain with a tour-series strategy. - -**Raw content tip:** If GitHub rate-limits the HTML view, prefix `raw.githubusercontent.com` and drop `/blob/`: -``` -https://raw.githubusercontent.com/coder/code-server/main/.tours/contributing.tour -https://raw.githubusercontent.com/a11yproject/a11yproject.com/main/.tours/code-tour.tour -https://raw.githubusercontent.com/lostintangent/rock-paper-scissors/master/main.tour -``` +**Raw content tip:** Prefix `raw.githubusercontent.com` and drop `/blob/` for raw JSON access. A great tour is not just annotated files. It is a **narrative** — a story told to a specific person about what matters, why it matters, and what to do next. Your goal is to write the tour @@ -174,25 +155,7 @@ Never ask about `nextTour`, `commands`, `when`, or `stepMarker` unless the user ### PR tour recipe -When the user says "tour for this PR" or pastes a GitHub PR URL: - -1. Set `"ref"` to the PR's branch name -2. Open with a `uri` step pointing to the PR itself — this gives the reviewer the full diff context -3. Add a `uri` step for any related issue or RFC if linked in the PR description -4. Cover **changed files first** — what changed and why -5. Then add steps for **files not in the diff** that reviewers must understand to evaluate the change correctly (call sites, dependency files, tests) -6. Flag invariants the change must preserve -7. Close with a reviewer checklist: what to verify, what tests to run, what to watch out for - -```json -[ - { "uri": "https://github.com/org/repo/pull/456", - "title": "The PR", "description": "This PR refactors auth to use refresh tokens. Key concern: session invalidation during migration." }, - { "file": "src/auth/tokenService.ts", "line": 12, "title": "What Changed: Token Issuing", "description": "..." }, - { "file": "src/auth/middleware.ts", "line": 38, "title": "Unchanged But Critical", "description": "This file wasn't touched but depends on the token shape. Verify line 38 still matches." }, - { "title": "Reviewer Checklist", "description": "- [ ] Session invalidation tested?\n- [ ] Old tokens still rejected after migration?\n- [ ] Refresh token rotation tested?" } -] -``` +For PR tours: set `"ref"` to the branch, open with a `uri` step for the PR, cover changed files first, then unchanged-but-critical files, close with a reviewer checklist. ### User-provided customization — always honor these @@ -258,74 +221,11 @@ Don't suggest this unless the user asks — it requires editing source files, wh --- -### Step types — the full toolkit - -**Content step** — narrative only, no file. Use for intro and closing. Max 2 per tour. -```json -{ "title": "Welcome", "description": "markdown..." } -``` - -**Directory step** — orient to a module. "What lives here." -```json -{ "directory": "src/services", "title": "Service Layer", "description": "..." } -``` - -**File + line step** — the workhorse. One specific meaningful line. -```json -{ "file": "src/auth/middleware.ts", "line": 42, "title": "Auth Gate", "description": "..." } -``` - -> **Path rule — always relative to repo root.** `"file"` and `"directory"` values must be relative to the repository root (the directory that contains `.tours/`). Never use an absolute path (`/Users/...`) and never use a leading `./`. If the repo root is `/projects/myapp` and the file is at `/projects/myapp/src/auth.ts`, write `"src/auth.ts"` — not `./src/auth.ts`, not `/projects/myapp/src/auth.ts`, not `auth.ts` (unless it's actually at the root). - -**Selection step** — a block of logic. Use when one line isn't enough (a function body, a config block, a type definition). -```json -{ - "file": "src/core/pipeline.py", - "selection": { "start": { "line": 15, "character": 0 }, "end": { "line": 34, "character": 0 } }, - "title": "The Request Pipeline", - "description": "..." -} -``` - -**Pattern step** — match by regex instead of line number. Use when line numbers shift frequently (actively changing files, generated code). -```json -{ "file": "src/app.ts", "pattern": "export default class Application", "title": "...", "description": "..." } -``` - -**URI step** — link to an external resource: a PR, issue, RFC, ADR, architecture diagram, Notion doc. Use to bring in context that lives outside the codebase. -```json -{ - "uri": "https://github.com/org/repo/pull/456", - "title": "The PR That Introduced This Pattern", - "description": "This design was debated in PR #456. The key tradeoff was..." -} -``` - -**View step** — auto-focus a VS Code panel at this step (terminal, problems, scm, explorer). -```json -{ "file": "src/server.ts", "line": 1, "view": "terminal", "title": "...", "description": "..." } -``` +### Step types — full reference -**Commands step** — execute VS Code commands when the reader arrives. Add to any file step. -```json -{ - "file": "src/server.ts", "line": 1, - "title": "Run It", - "description": "Hit the play button — you'll see the server boot sequence here.", - "commands": ["workbench.action.terminal.focus"] -} -``` +All step types: **content** (intro/closing, max 2), **directory**, **file+line** (workhorse), **selection** (code block), **pattern** (regex match), **uri** (external link), **view** (focus VS Code panel), **commands** (run VS Code commands). -Useful commands: -| Command | What it does | -|---------|-------------| -| `editor.action.goToDeclaration` | Jump to definition | -| `editor.action.showHover` | Show type hover | -| `references-view.findReferences` | Show all references | -| `workbench.action.terminal.focus` | Open terminal | -| `workbench.action.tasks.runTask` | Run a task | -| `workbench.view.scm` | Open source control panel | -| `workbench.view.explorer` | Open file explorer | +> **Path rule:** `"file"` and `"directory"` must be relative to repo root. No absolute paths, no leading `./`. --- @@ -373,30 +273,7 @@ Every description should answer four questions in order. You don't need four par **I — Implication**: Why does this matter for *this persona's goal specifically*? **G — Gotcha**: What would a smart person get wrong here? What's non-obvious, fragile, or surprising? -**Bad description** (generic — could apply to any codebase): -> "This is the authentication middleware. It checks if the user is authenticated before allowing access to protected routes." - -**Good description** (SMIG applied): -> **S:** Every HTTP request passes through this file before reaching any controller — it's the sole auth checkpoint. -> -> **M:** Notice the **dual-check pattern** on line 42: it validates the JWT signature *and* does a Redis lookup for the session. Both must pass. A valid JWT alone isn't enough if the session was revoked (logout, password reset, force-expire). -> -> **I:** For a bug fixer: if a user reports being logged out unexpectedly, this is your first stop. Redis miss → 401 → silent logout is the most common failure path. -> -> **G:** If Redis is down, line 53 propagates the error as a 401 — meaning a Redis outage silently logs everyone out. There's no circuit breaker here. This is tracked in ISSUE-4421, and the workaround is in `config/redis.ts` line 18. - -The good description tells the reader something they couldn't learn by reading the file themselves. It names the pattern, explains the design decision, flags the failure mode, and cross-references related context. - -**Persona vocabulary cheat sheet** — speak their language, not generic developer-speak: - -| Persona | Their vocabulary | Avoid | -|---------|-----------------|-------| -| New joiner | "this means", "you'll need to", "the team calls this" | acronyms, assumed context | -| Bug fixer | "failure path", "where this breaks", "repro steps" | architecture history | -| Security reviewer | "trust boundary", "untrusted input", "privilege escalation" | vague "be careful" | -| PR reviewer | "invariant", "this must stay true", "the change story" | unrelated context | -| Architect | "seam", "coupling", "extension point", "decision" | step-by-step walkthroughs | -| Vibecoder | "the main loop", "ignore for now", "start here" | deep explanations | +Descriptions should tell the reader something they couldn't learn by reading the file themselves. Name the pattern, explain the design decision, flag failure modes, and cross-reference related context. --- @@ -415,24 +292,9 @@ The good description tells the reader something they couldn't learn by reading t 4. **Closing** (content) — what the reader now understands, what they can do next, 2–3 suggested follow-up tours. If `nextTour` is set, reference it by name here. -### What makes a closing step excellent - -The closing is frequently the weakest step. Don't summarize — the reader just read it. -Instead: - -❌ Bad closing (recap): -> "In this tour we covered the entry point, the middleware stack, and the database layer." +### Closing steps -✅ Good closing (action + next): -> "You now know enough to safely add a new route without breaking auth or session handling. -> The danger zones to stay away from are `src/auth/tokenService.ts` (don't change the token shape without a migration plan) and `src/db/pool.ts` (connection limits are load-tested at current values). -> -> **What's next:** -> - If you're fixing a bug → jump to the **Bug Fixer: Payment Flow** tour for the specific path -> - If you're adding a feature → the **Feature Explainer: Notifications** tour shows the full pattern -> - If something's on fire → the **RCA: Incident Guide** tour maps the observability anchors" - -The good closing tells the reader what they're now capable of, what to avoid, and gives them a map of where to go next. +Don't summarize — the reader just read it. Instead, tell them what they can now *do*, what to avoid, and suggest 2-3 follow-up tours. --- @@ -440,26 +302,16 @@ The good closing tells the reader what they're now capable of, what to avoid, an | Persona | Goal | Must cover | Avoid | |---------|------|------------|-------| -| **Vibecoder** | Get the vibe fast | Entry point, request flow, main modules. "Start here / Core loop / Ignore for now." Max 8 steps. | Deep dives, history, edge cases | -| **New joiner** | Structured ramp-up | Directories, setup/run instructions, business context, service boundaries, team terms defined. | Advanced internals before basics | -| **Reboarding engineer** | Catch up on what changed | What's new vs. what they remember. "This used to be X, now it's Y." | Re-explaining things they knew | -| **Bug fixer** | Root cause fast | User action → trigger → fault points. Validation, branching, error handling. Repro hints + test locations. | Architecture tours, business context | -| **RCA / incident investigator** | Why did it fail | Causality chain. State transitions, side effects, race conditions. Observability anchors. | Happy path | -| **Feature explainer** | One feature end-to-end | UI → API → backend → storage. Feature flags, auth, edge cases, scope. | Unrelated features | -| **Concept learner** | Understand a pattern | Concept intro → implementation → why this design → tradeoffs → common misunderstanding. | Code without conceptual framing | -| **PR reviewer** | Review the change correctly | The change story, not just changed files. Invariants. Risky areas. Reviewer checklist. URI step for the PR. | Unrelated context | -| **Maintainer** | Long-term health | Architectural intent. Extension points. "Do not bypass this layer." Long-lived invariants. | One-time setup concerns | -| **Refactorer** | Safe restructuring | Seams, hidden deps, implicit contracts, coupling hotspots, safe extraction order. | Feature explanations | -| **Performance optimizer** | Find bottlenecks | Hot paths, N+1, I/O, serialization. Caches, batching. Existing benchmarks. | Cold paths, setup code | -| **Security reviewer** | Trust boundaries + abuse paths | Auth flow. Input validation. Secret handling. Sensitive sinks. Safe failure modes. | Unrelated business logic | -| **Test writer** | Add good tests | Behavior contracts. Existing patterns. Mocking seams. Coverage gaps. High-value scenarios. | Implementation detail | -| **API consumer** | Call the system correctly | Public surface, request/response shapes, auth, error semantics, stable vs. internal. | Internal implementation | -| **Platform / infra engineer** | Operational understanding | Boot sequence, config loading, infra deps, background jobs, graceful shutdown. | Business logic | -| **Data engineer** | Data lineage + schemas | Event emission, schema definitions, source-to-sink path, data quality, backfill. | UI / request flow | -| **AI agent operator** | Deterministic navigation | Stable anchors, allowed edit zones, required validation steps. "Do not infer — read this file first." | Ambiguous or implied structure | -| **Product-minded engineer** | Business rules in code | Domain language, business rules, feature toggles, "why does this weird code exist?" | Pure infrastructure | -| **External contributor** | Contribute without breaking | Contribution-safe areas, code style, architecture landmines, typical first-timer mistakes. | Deep internals | -| **Tech lead / architect** | Shape and rationale | Module boundaries, design tradeoffs, risk hotspots, future evolution. | Line-by-line walkthroughs | +| **Vibecoder** | Get the vibe fast | Entry point, request flow, main modules. Max 8 steps. | Deep dives, edge cases | +| **New joiner** | Structured ramp-up | Directories, setup, business context, service boundaries. | Advanced internals | +| **Bug fixer** | Root cause fast | User action → trigger → fault points. Repro hints + test locations. | Architecture tours | +| **RCA investigator** | Why did it fail | Causality chain, side effects, race conditions, observability. | Happy path | +| **Feature explainer** | One feature end-to-end | UI → API → backend → storage. Feature flags, edge cases. | Unrelated features | +| **PR reviewer** | Review the change correctly | Change story, invariants, risky areas, reviewer checklist. URI step for PR. | Unrelated context | +| **Security reviewer** | Trust boundaries | Auth flow, input validation, secret handling, sensitive sinks. | Unrelated business logic | +| **Refactorer** | Safe restructuring | Seams, hidden deps, coupling hotspots, safe extraction order. | Feature explanations | +| **External contributor** | Contribute without breaking | Safe areas, code style, architecture landmines. | Deep internals | +| **Tech lead / architect** | Shape and rationale | Module boundaries, design tradeoffs, risk hotspots. | Line-by-line walkthroughs | --- @@ -474,38 +326,7 @@ launch the next automatically. - No duplicate steps between tours - Each tour standalone enough to be useful on its own -**Common series patterns:** - -*Onboarding series (new joiner):* -1. "Orientation" → repo structure, how to run it (isPrimary: true) -2. "Core Request Flow" → entry to response, middleware chain -3. "Data Layer" → models, migrations, query patterns -4. "Testing Patterns" → how to write and run tests - -*Incident / debug series (bug fixer + RCA):* -1. "Happy Path" → normal flow from trigger to response -2. "Failure Modes" → where it can break and why -3. "Observability Map" → logs, metrics, traces to look at - -*Architecture series (tech lead):* -1. "Module Boundaries" → what lives where and why -2. "Extension Points" → where to add new features -3. "Danger Zones" → what must never be changed carelessly - -**When writing a series:** set `nextTour` in each tour to the `title` of the next one. -The value must match exactly. Tell the reader in the closing step which tour comes next -and why they should read it. - -### Hot files — anchor the series - -Some files deserve a step in almost every tour because they're where the system's core rules live. Identify 2–3 of these early and treat them as anchors: - -- The **main entry point** — every persona needs to see this -- The **central router or dispatcher** — where requests branch -- The **primary config loader** — where behavior is controlled -- The **auth boundary** — the single place permissions are checked - -When the same file appears in multiple tours, give it a *different* framing each time — new joiners get "this is where the server starts", security reviewers get "this is the only place secrets are loaded". +Set `nextTour` in each tour to the `title` of the next one (must match exactly). Each tour should be standalone enough to be useful on its own. --- @@ -523,21 +344,15 @@ If asked for any of these, say clearly that it's not supported — do not sugges --- -## Anti-patterns — what ruins a tour +## Anti-patterns -Avoid these. They are the most common failures. - -| Anti-pattern | What it looks like | The fix | -|---|---|---| -| **File listing** | Visiting `models.py`, `routes.py`, `utils.py` in sequence with descriptions like "this file contains the models" | Tell a story — each step should depend on having seen the previous one. Ask: "why does this step come after the last one?" | -| **Generic descriptions** | "This is the main entry point of the application." | If your description would make sense for any repo, rewrite it. Name the specific pattern, decision, or gotcha that's unique to *this* codebase. | -| **Line number guessing** | Writing `"line": 42` without reading the file | Never write a line number you didn't verify. Off-by-one lands the cursor on the wrong code and breaks trust instantly. | -| **Ignoring the persona** | Security reviewer getting a folder structure tour | Step selection must reflect what this specific person is trying to accomplish. Cut every step that doesn't serve their goal. | -| **Too many steps** | A 20-step "vibecoder" tour | Respecting depth means *actually cutting steps* — not just labeling it "quick." | -| **Hallucinated files** | Steps pointing to files that don't exist | If a file doesn't exist in the repo, skip the step. Never use a placeholder. | -| **Recap closing** | "In this tour we covered X, Y, and Z." | The closing should tell the reader what they can now *do*, what to watch out for, and where to go next. | -| **Persona vocabulary mismatch** | Explaining JWTs to a security reviewer | Meet each persona where they are. Security reviewers know what a JWT is — tell them what's *wrong* with this implementation. | -| **Broken `nextTour`** | `"nextTour"` value doesn't exactly match any tour title | Always copy the title string verbatim. A typo silently breaks the chain. | +| Anti-pattern | Fix | +|---|---| +| **File listing** — visiting files with "this file contains..." | Tell a story; each step should depend on the previous one | +| **Generic descriptions** | Name the specific pattern/gotcha unique to *this* codebase | +| **Line number guessing** | Never write a line number you didn't verify by reading the file | +| **Ignoring the persona** | Cut every step that doesn't serve their specific goal | +| **Hallucinated files** | If a file doesn't exist, skip the step | --- @@ -582,41 +397,13 @@ The validator checks: **Fix every error before proceeding.** Re-run until the validator reports ✓ or only warnings. Warnings are advisory — use your judgment. Do not show the user the tour until validation passes. -**What actually breaks VS Code CodeTour** (the real causes of blank/broken steps): -- **Content-only first step** — step 1 has no `file`, `directory`, or `uri`. VS Code opens to a blank page. Fix: anchor step 1 to a file or directory and put the intro text in its description. -- **File path not relative to repo root** — absolute paths or `./`-prefixed paths silently fail to open. Fix: always use paths relative to where `.tours/` lives (e.g. `src/auth.ts`, not `./src/auth.ts`). -- **Line number out of bounds** — VS Code opens the file but scrolls nowhere. The validator catches this. - -These are the only structural issues that cause VS Code rendering failures. Description length, markdown formatting, and use of `\n` in JSON strings do NOT affect rendering. - -If you can't run scripts, do the equivalent check manually: -1. Confirm step 1 has a `file` or `directory` field -2. Confirm every `file` path exists by reading it (relative to repo root, no leading `./`) -3. Confirm every `line` is within the file's line count -4. Confirm every `directory` exists -5. Read the step titles in sequence — do they tell a coherent story? -6. Confirm `nextTour` matches another tour's `title` exactly +**Common VS Code issues:** Content-only first step renders blank (anchor to file/directory instead). Absolute or `./`-prefixed paths silently fail. Out-of-bounds line numbers scroll nowhere. -**Autoplay on repo open** — `isPrimary: true` makes CodeTour show a "Start Tour?" prompt when the repo opens in VS Code. To make this reliable for everyone who clones the repo, also write `.vscode/settings.json`: +If you can't run scripts, manually verify: step 1 has `file`/`directory`, all paths exist, all line numbers are in bounds, `nextTour` matches exactly. -```json -{ "codetour.promptForPrimaryTour": true } -``` - -Without this file, the prompt depends on each user's global VS Code config. Committed to the repo, it fires for everyone automatically. Create this file whenever you set `isPrimary: true`. - -**`ref` and autoplay:** if the tour has `"ref": "main"`, CodeTour only prompts when the user is on that exact branch or tag. For tours that should appear on any branch, omit `ref`. - -**Share via vscode.dev** — the fastest way for someone to use the tour without -cloning the repo. For any public GitHub repo with tours committed to `.tours/`, -they can open it directly in the browser: - -``` -https://vscode.dev/github.com// -``` +**Autoplay:** `isPrimary: true` + `.vscode/settings.json` with `{ "codetour.promptForPrimaryTour": true }` prompts on repo open. Omit `ref` for tours that should appear on any branch. -VS Code Web will detect the `.tours/` directory and offer to start the tour. -No install needed. Tell the user this URL in your summary when the repo is public. +**Share:** For public repos, users can open tours at `https://vscode.dev/github.com//` with no install. --- From 63b9a49e86fafe3ea1fb2266cad00a7c58760d0f Mon Sep 17 00:00:00 2001 From: Srinivas Vaddi Date: Thu, 9 Apr 2026 13:47:32 -0400 Subject: [PATCH 3/5] fix: run npm run build to update README with code-tour skill Addresses review feedback from @aaronpowell --- docs/README.skills.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.skills.md b/docs/README.skills.md index 78f3d71a2..f70520c96 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -72,6 +72,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to | [cli-mastery](../skills/cli-mastery/SKILL.md) | Interactive training for the GitHub Copilot CLI. Guided lessons, quizzes, scenario challenges, and a full reference covering slash commands, shortcuts, modes, agents, skills, MCP, and configuration. Say "cliexpert" to start. | `references/final-exam.md`
`references/module-1-slash-commands.md`
`references/module-2-keyboard-shortcuts.md`
`references/module-3-modes.md`
`references/module-4-agents.md`
`references/module-5-skills.md`
`references/module-6-mcp.md`
`references/module-7-advanced.md`
`references/module-8-configuration.md`
`references/scenarios.md` | | [cloud-design-patterns](../skills/cloud-design-patterns/SKILL.md) | Cloud design patterns for distributed systems architecture covering 42 industry-standard patterns across reliability, performance, messaging, security, and deployment categories. Use when designing, reviewing, or implementing distributed system architectures. | `references/architecture-design.md`
`references/azure-service-mappings.md`
`references/best-practices.md`
`references/deployment-operational.md`
`references/event-driven.md`
`references/messaging-integration.md`
`references/performance.md`
`references/reliability-resilience.md`
`references/security.md` | | [code-exemplars-blueprint-generator](../skills/code-exemplars-blueprint-generator/SKILL.md) | Technology-agnostic prompt generator that creates customizable AI prompts for scanning codebases and identifying high-quality code exemplars. Supports multiple programming languages (.NET, Java, JavaScript, TypeScript, React, Angular, Python) with configurable analysis depth, categorization methods, and documentation formats to establish coding standards and maintain consistency across development teams. | None | +| [code-tour](../skills/code-tour/SKILL.md) | Use this skill to create CodeTour .tour files — persona-targeted, step-by-step walkthroughs that link to real files and line numbers. Trigger for: "create a tour", "make a code tour", "generate a tour", "onboarding tour", "tour for this PR", "tour for this bug", "RCA tour", "architecture tour", "explain how X works", "vibe check", "PR review tour", "contributor guide", "help someone ramp up", or any request for a structured walkthrough through code. Supports 20 developer personas (new joiner, bug fixer, architect, PR reviewer, vibecoder, security reviewer, and more), all CodeTour step types (file/line, selection, pattern, uri, commands, view), and tour-level fields (ref, isPrimary, nextTour). Works with any repository in any language. | None | | [codeql](../skills/codeql/SKILL.md) | Comprehensive guide for setting up and configuring CodeQL code scanning via GitHub Actions workflows and the CodeQL CLI. This skill should be used when users need help with code scanning configuration, CodeQL workflow files, CodeQL CLI commands, SARIF output, security analysis setup, or troubleshooting CodeQL analysis. | `references/alert-management.md`
`references/cli-commands.md`
`references/compiled-languages.md`
`references/sarif-output.md`
`references/troubleshooting.md`
`references/workflow-configuration.md` | | [comment-code-generate-a-tutorial](../skills/comment-code-generate-a-tutorial/SKILL.md) | Transform this Python script into a polished, beginner-friendly project by refactoring the code, adding clear instructional comments, and generating a complete markdown tutorial. | None | | [containerize-aspnet-framework](../skills/containerize-aspnet-framework/SKILL.md) | Containerize an ASP.NET .NET Framework project by creating Dockerfile and .dockerfile files customized for the project. | None | From 5109291669ca940c67975243cee18259dad4d730 Mon Sep 17 00:00:00 2001 From: Srinivas Vaddi Date: Fri, 10 Apr 2026 07:56:48 -0400 Subject: [PATCH 4/5] fix: add missing scripts/ and references/ files referenced in SKILL.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses reviewer feedback — SKILL.md referenced bundled files (validate_tour.py, generate_from_docs.py, codetour-schema.json, examples.md) that were not included in the PR. Co-Authored-By: Claude Sonnet 4.6 --- .../code-tour/references/codetour-schema.json | 115 ++++++ skills/code-tour/references/examples.md | 195 ++++++++++ .../code-tour/scripts/generate_from_docs.py | 286 +++++++++++++++ skills/code-tour/scripts/validate_tour.py | 346 ++++++++++++++++++ 4 files changed, 942 insertions(+) create mode 100644 skills/code-tour/references/codetour-schema.json create mode 100644 skills/code-tour/references/examples.md create mode 100644 skills/code-tour/scripts/generate_from_docs.py create mode 100644 skills/code-tour/scripts/validate_tour.py diff --git a/skills/code-tour/references/codetour-schema.json b/skills/code-tour/references/codetour-schema.json new file mode 100644 index 000000000..e4966b3e2 --- /dev/null +++ b/skills/code-tour/references/codetour-schema.json @@ -0,0 +1,115 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Schema for CodeTour tour files", + "type": "object", + "required": ["title", "steps"], + "properties": { + "title": { + "type": "string", + "description": "Specifies the title of the code tour." + }, + "description": { + "type": "string", + "description": "Specifies an optional description for the code tour." + }, + "ref": { + "type": "string", + "description": "Indicates the git ref (branch/commit/tag) that this tour associate with." + }, + "isPrimary": { + "type": "boolean", + "description": "Specifies whether the tour represents the primary tour for this codebase." + }, + "nextTour": { + "type": "string", + "description": "Specifies the title of the tour that is meant to follow this tour." + }, + "stepMarker": { + "type": "string", + "description": "Specifies the marker that indicates a line of code represents a step for this tour." + }, + "when": { + "type": "string", + "description": "Specifies the condition (JavaScript expression) that must be met before this tour is shown." + }, + "steps": { + "type": "array", + "description": "Specifies the list of steps that are included in the code tour.", + "default": [], + "items": { + "type": "object", + "required": ["description"], + "properties": { + "title": { + "type": "string", + "description": "An optional title for the step." + }, + "description": { + "type": "string", + "description": "Description of the step. Supports markdown." + }, + "file": { + "type": "string", + "description": "File path (relative to the workspace root) that the step is associated with." + }, + "directory": { + "type": "string", + "description": "Directory path (relative to the workspace root) that the step is associated with." + }, + "uri": { + "type": "string", + "description": "Absolute URI (https://...) associated with the step. Use for PRs, issues, docs, ADRs." + }, + "line": { + "type": "number", + "description": "Line number (1-based) that the step is associated with." + }, + "pattern": { + "type": "string", + "description": "Regex to associate the step with a line by content instead of line number. Useful when line numbers shift frequently." + }, + "selection": { + "type": "object", + "required": ["start", "end"], + "description": "Text selection range associated with the step. Use when a block of code (not a single line) is the point.", + "properties": { + "start": { + "type": "object", + "required": ["line", "character"], + "properties": { + "line": { "type": "number", "description": "Line number (1-based) where the selection starts." }, + "character": { "type": "number", "description": "Column number (1-based) where the selection starts." } + } + }, + "end": { + "type": "object", + "required": ["line", "character"], + "properties": { + "line": { "type": "number", "description": "Line number (1-based) where the selection ends." }, + "character": { "type": "number", "description": "Column number (1-based) where the selection ends." } + } + } + } + }, + "view": { + "type": "string", + "description": "VS Code view ID to auto-focus when navigating to this step (e.g. 'terminal', 'explorer', 'problems', 'scm')." + }, + "commands": { + "type": "array", + "description": "VS Code command URIs to execute when this step is navigated to.", + "default": [], + "items": { "type": "string" }, + "examples": [ + ["editor.action.goToDeclaration"], + ["workbench.action.terminal.focus"], + ["editor.action.showHover"], + ["references-view.findReferences"], + ["workbench.action.tasks.runTask"] + ] + } + } + } + } + } +} diff --git a/skills/code-tour/references/examples.md b/skills/code-tour/references/examples.md new file mode 100644 index 000000000..186347bbe --- /dev/null +++ b/skills/code-tour/references/examples.md @@ -0,0 +1,195 @@ +# Real-World CodeTour Examples + +Reference this file when you want to see how real repos use CodeTour features. +Each example is sourced from a public GitHub repo with a direct link to the `.tour` file. + +--- + +## microsoft/codetour — Contributor orientation + +**Tour file:** https://github.com/microsoft/codetour/blob/main/.tours/intro.tour +**Persona:** New contributor +**Steps:** ~5 · **Depth:** Standard + +**What makes it good:** +- Intro step with an embedded SVG architecture diagram (raw GitHub URL inside the description) +- Rich markdown per step with emoji section headers (`### 🎥 Tour Player`) +- Inline cross-file links inside descriptions: `[Gutter decorator](./src/player/decorator.ts)` +- Uses the top-level `description` field as a subtitle for the tour itself + +**Technique to copy:** Embed images and cross-links in descriptions to make them self-contained. + +```json +{ + "file": "src/player/index.ts", + "line": 436, + "description": "### 🎥 Tour Player\n\nThe CodeTour player ...\n\n![Architecture](https://raw.githubusercontent.com/.../overview.svg)\n\nSee also: [Gutter decorator](./src/player/decorator.ts)" +} +``` + +--- + +## a11yproject/a11yproject.com — New contributor onboarding + +**Tour file:** https://github.com/a11yproject/a11yproject.com/blob/main/.tours/code-tour.tour +**Persona:** External contributor +**Steps:** 26 · **Depth:** Deep + +**What makes it good:** +- Almost entirely `directory` steps — orients to every `src/` subdirectory without getting lost in files +- Conversational, beginner-friendly tone throughout +- `selection` on the opening step to highlight the exact entry in `package.json` +- Closes with a genuine thank-you and call-to-action + +**Technique to copy:** Use directory steps as the skeleton of an onboarding tour — they teach structure without requiring the author to explain every file. + +```json +{ + "directory": "src/_data", + "description": "This folder contains the **data files** for the site. Think of them as a lightweight database — YAML files that power the resource listings, posts index, and nav." +} +``` + +--- + +## github/codespaces-codeql — The most technically complete example + +**Tour file:** https://github.com/github/codespaces-codeql/blob/main/.tours/codeql-tutorial.tour +**Persona:** Security engineer / concept learner +**Steps:** 12 · **Depth:** Standard + +**What makes it good:** +- `isPrimary: true` — auto-launches when the Codespace opens +- `commands` array to run real VS Code commands mid-tour: the tour literally executes `codeQL.runQuery` when the reader arrives at that step +- `view` property to switch the sidebar panel (`"view": "codeQLDatabases"`) +- `pattern` instead of `line` for resilient matching: `"pattern": "import tutorial.*"` +- `selection` to highlight the exact `select` clause in a query file + +**This is the canonical reference for `commands`, `view`, and `pattern`.** + +```json +{ + "file": "tutorial.ql", + "pattern": "import tutorial.*", + "view": "codeQLDatabases", + "commands": ["codeQL.setDefaultTourDatabase", "codeQL.runQuery"], + "title": "Run your first query", + "description": "Click the **▶ Run** button above. The results appear in the CodeQL Query Results panel." +} +``` + +--- + +## github/codespaces-learn-with-me — Minimal interactive tutorial + +**Tour file:** https://github.com/github/codespaces-learn-with-me/blob/main/.tours/main.tour +**Persona:** Total beginner +**Steps:** 4 · **Depth:** Quick + +**What makes it good:** +- Only 4 steps — proves that less is more for quick/vibecoder personas +- `isPrimary: true` for auto-launch +- Each step tells the reader to **do something** (edit a string, change a color) — not just read +- Ends with a tangible outcome: "your page is live" + +**Technique to copy:** For quick/vibecoder tours, cut mercilessly. Four steps that drive action beat twelve that explain everything. + +--- + +## blackgirlbytes/copilot-todo-list — 28-step interactive tutorial + +**Tour file:** https://github.com/blackgirlbytes/copilot-todo-list/blob/main/.tours/main.tour +**Persona:** Concept learner / hands-on tutorial +**Steps:** 28 · **Depth:** Deep + +**What makes it good:** +- Uses **content-only checkpoint steps** (no `file` key) as progress milestones: "Check out your page! 🎉" and "Try it out!" between coding tasks +- Terminal inline commands in descriptions: `>> npm install uuid; npm install styled-components` +- Each file step shows the exact code the user should accept, in a markdown code fence, so they know the expected output + +**Technique to copy:** Checkpoint steps (content-only, milestone title) break up long tours and give the reader a sense of progress. + +```json +{ + "title": "Check out your page! 🎉", + "description": "Open the **Simple Browser** tab to see your to-do list. You should see all three tasks rendering from your data array.\n\nOnce you're happy with it, continue to add interactivity." +} +``` + +--- + +## lucasjellema/cloudnative-on-oci-2021 — Multi-tour architecture series + +**Tour files:** +- https://github.com/lucasjellema/cloudnative-on-oci-2021/blob/main/.tours/function-tweet-retriever.tour +- https://github.com/lucasjellema/cloudnative-on-oci-2021/blob/main/.tours/oci-and-infrastructure-as-code.tour +- https://github.com/lucasjellema/cloudnative-on-oci-2021/blob/main/.tours/build-and-deployment-pipeline-function-tweet-retriever.tour + +**Persona:** Platform engineer / architect +**Steps:** 12 per tour · **Depth:** Standard + +**What makes it good:** +- Three separate tours for three separate concerns (function code, IaC, CI/CD pipeline) — each standalone but linked via `nextTour` +- `selection` coordinates used heavily in Terraform files where a block (not a single line) is the point +- Steps include markdown links to official OCI documentation inline +- Designed to be browsed via `vscode.dev/github.com/...` without cloning + +**Technique to copy:** For complex systems, write one tour per layer and chain them with `nextTour`. Don't try to cover infrastructure + application code + CI/CD in one tour. + +--- + +## SeleniumHQ/selenium — Monorepo build system onboarding + +**Tour files:** +- `.tours/bazel.tour` — Bazel workspace and build target orientation +- `.tours/building-and-testing-the-python-bindings.tour` — Python bindings BUILD.bazel walkthrough + +**Persona:** External contributor (build system focus) +**Steps:** ~10 per tour + +**What makes it good:** +- Targets a non-obvious entry point — not the product code but the build system +- Proves that "contributor onboarding" tours don't have to start with `main()` — they start with whatever is confusing about this specific repo +- Used in a large, mature OSS project at scale + +--- + +## Technique quick-reference + +| Feature | When to use | Real example | +|---------|-------------|-------------| +| `isPrimary: true` | Auto-launch tour when repo opens (Codespace, vscode.dev) | codespaces-learn-with-me, codespaces-codeql | +| `commands: [...]` | Run a VS Code command when reader arrives at this step | codespaces-codeql (`codeQL.runQuery`) | +| `view: "terminal"` | Switch VS Code sidebar/panel at this step | codespaces-codeql (`codeQLDatabases`) | +| `pattern: "regex"` | Match by line content, not number — use for volatile files | codespaces-codeql | +| `selection: {start, end}` | Highlight a block (function body, config section, type def) | a11yproject, oci-2021, codespaces-codeql | +| `directory: "path/"` | Orient to a folder without reading every file | a11yproject, codespaces-codeql | +| `uri: "https://..."` | Link to PR, issue, RFC, ADR, external doc | Any PR review tour | +| `nextTour: "Title"` | Chain tours in a series | oci-2021 (3-part series) | +| Checkpoint steps (content-only) | Progress milestones in long interactive tours | copilot-todo-list | +| `>> command` in description | Terminal inline command link in VS Code | copilot-todo-list | +| Embedded image in description | Architecture diagrams, screenshots | microsoft/codetour | + +--- + +## Discover more real tours on GitHub + +**Search all `.tour` files on GitHub:** +https://github.com/search?q=path%3A**%2F*.tour+&type=code + +This search returns every `.tour` file committed to a public GitHub repo. Use it to: +- Find tours for repos in the same language/framework as the one you're working on +- Study how other authors handle the same personas or step types +- Look up how a specific field (`commands`, `selection`, `pattern`) is used in the wild + +Filter by language or keyword to narrow results — e.g. add `language:TypeScript` or `fastapi` to the query. + +--- + +## Further reading + +- **DEV Community — "Onboard your codebase with CodeTour"**: https://dev.to/tobiastimm/onboard-your-codebase-with-codetour-2jc8 +- **Coder Blog — "Onboard to new projects faster with CodeTour"**: https://coder.com/blog/onboard-to-new-projects-faster-with-codetour +- **Microsoft Tech Community — Educator Developer Blog**: https://techcommunity.microsoft.com/blog/educatordeveloperblog/codetour-vscode-extension-allows-you-to-produce-interactive-guides-assessments-a/1274297 +- **AMIS Technology Blog — vscode.dev + CodeTour**: https://technology.amis.nl/software-development/visual-studio-code-the-code-tours-extension-for-in-context-and-interactive-readme/ +- **CodeTour GitHub Topics**: https://github.com/topics/codetour diff --git a/skills/code-tour/scripts/generate_from_docs.py b/skills/code-tour/scripts/generate_from_docs.py new file mode 100644 index 000000000..4c90c68e3 --- /dev/null +++ b/skills/code-tour/scripts/generate_from_docs.py @@ -0,0 +1,286 @@ +#!/usr/bin/env python3 +""" +Generate a tour skeleton from repo documentation (README, CONTRIBUTING, docs/). + +Reads README.md (and optionally CONTRIBUTING.md, docs/) to extract: + - File and directory references + - Architecture / structure sections + - Setup instructions (becomes an orientation step) + - External links (becomes uri steps) + +Outputs a skeleton .tour JSON that the code-tour skill fills in with descriptions. +The skill reads this skeleton and enriches it — it does NOT replace the skill's judgment. + +Usage: + python generate_from_docs.py [--repo-root ] [--persona ] [--output ] + +Examples: + python generate_from_docs.py + python generate_from_docs.py --persona new-joiner --output .tours/from-readme.tour + python generate_from_docs.py --repo-root /path/to/repo --persona vibecoder +""" + +import json +import re +import sys +import os +from pathlib import Path +from typing import Optional + + +# ── Markdown extraction helpers ────────────────────────────────────────────── + +# Matches inline code that looks like a file/directory path +_CODE_PATH = re.compile(r"`([^`]{2,80})`") +# Matches headings +_HEADING = re.compile(r"^(#{1,3})\s+(.+)$", re.MULTILINE) +# Matches markdown links: [text](url) +_LINK = re.compile(r"\[([^\]]+)\]\((https?://[^)]+)\)") +# Patterns that suggest a path (contains / or . with extension) +_LOOKS_LIKE_PATH = re.compile(r"^\.?[\w\-]+(/[\w\-\.]+)+$|^\./|^[\w]+\.[a-z]{1,5}$") +# Architecture / structure section keywords +_STRUCT_KEYWORDS = re.compile( + r"\b(structure|architecture|layout|overview|directory|folder|module|component|" + r"design|system|organization|getting.started|quick.start|setup|installation)\b", + re.IGNORECASE, +) + + +def _extract_paths_from_text(text: str, repo_root: Path) -> list[str]: + """Extract inline code that looks like real file/directory paths.""" + candidates = _CODE_PATH.findall(text) + found = [] + for c in candidates: + c = c.strip().lstrip("./") + if not c: + continue + if not _LOOKS_LIKE_PATH.match(c) and "/" not in c and "." not in c: + continue + # check if path actually exists + full = repo_root / c + if full.exists(): + found.append(c) + return found + + +def _extract_external_links(text: str) -> list[tuple[str, str]]: + """Extract [label](url) pairs for URI steps.""" + links = _LINK.findall(text) + # filter out image links and very generic anchors + return [ + (label, url) + for label, url in links + if not url.endswith((".png", ".jpg", ".gif", ".svg")) + and label.lower() not in ("here", "this", "link", "click", "see") + ] + + +def _split_into_sections(text: str) -> list[tuple[str, str]]: + """Split markdown into (heading, body) pairs.""" + headings = list(_HEADING.finditer(text)) + sections = [] + for i, m in enumerate(headings): + heading = m.group(2).strip() + start = m.end() + end = headings[i + 1].start() if i + 1 < len(headings) else len(text) + body = text[start:end].strip() + sections.append((heading, body)) + return sections + + +def _is_structure_section(heading: str) -> bool: + return bool(_STRUCT_KEYWORDS.search(heading)) + + +# ── Step builders ───────────────────────────────────────────────────────────── + +def _make_content_step(title: str, hint: str) -> dict: + return { + "title": title, + "description": f"[TODO: {hint}]", + } + + +def _make_file_step(path: str, hint: str = "") -> dict: + step = { + "file": path, + "title": f"[TODO: title for {path}]", + "description": f"[TODO: {hint or 'explain this file for the persona'}]", + } + return step + + +def _make_dir_step(path: str, hint: str = "") -> dict: + return { + "directory": path, + "title": f"[TODO: title for {path}/]", + "description": f"[TODO: {hint or 'explain what lives here'}]", + } + + +def _make_uri_step(url: str, label: str) -> dict: + return { + "uri": url, + "title": label, + "description": "[TODO: explain why this link is relevant and what the reader should notice]", + } + + +# ── Core generator ──────────────────────────────────────────────────────────── + +def generate_skeleton(repo_root: str = ".", persona: str = "new-joiner") -> dict: + repo = Path(repo_root).resolve() + + # ── Read documentation files ───────────────────────────────────────── + doc_files = ["README.md", "readme.md", "Readme.md"] + extra_docs = ["CONTRIBUTING.md", "ARCHITECTURE.md", "docs/architecture.md", "docs/README.md"] + + readme_text = "" + for name in doc_files: + p = repo / name + if p.exists(): + readme_text = p.read_text(errors="replace") + break + + extra_texts = [] + for name in extra_docs: + p = repo / name + if p.exists(): + extra_texts.append((name, p.read_text(errors="replace"))) + + all_text = readme_text + "\n".join(t for _, t in extra_texts) + + # ── Collect steps ───────────────────────────────────────────────────── + steps = [] + seen_paths: set[str] = set() + + # 1. Intro step + steps.append( + _make_content_step( + "Welcome", + f"Introduce the repo: what it does, who this {persona} tour is for, what they'll understand after finishing.", + ) + ) + + # 2. Parse README sections + if readme_text: + sections = _split_into_sections(readme_text) + for heading, body in sections: + # structure / architecture sections → directory steps + if _is_structure_section(heading): + paths = _extract_paths_from_text(body, repo) + for p in paths: + if p in seen_paths: + continue + seen_paths.add(p) + full = repo / p + if full.is_dir(): + steps.append(_make_dir_step(p, f"mentioned under '{heading}' in README")) + elif full.is_file(): + steps.append(_make_file_step(p, f"mentioned under '{heading}' in README")) + + # 3. Scan all text for file/dir references not yet captured + all_paths = _extract_paths_from_text(all_text, repo) + for p in all_paths: + if p in seen_paths: + continue + seen_paths.add(p) + full = repo / p + if full.is_dir(): + steps.append(_make_dir_step(p)) + elif full.is_file(): + steps.append(_make_file_step(p)) + + # 4. If very few file steps found, fall back to top-level directory scan + file_and_dir_steps = [s for s in steps if "file" in s or "directory" in s] + if len(file_and_dir_steps) < 3: + # add top-level directories + for item in sorted(repo.iterdir()): + if item.name.startswith(".") or item.name in ("node_modules", "__pycache__", ".git"): + continue + rel = str(item.relative_to(repo)) + if rel in seen_paths: + continue + seen_paths.add(rel) + if item.is_dir(): + steps.append(_make_dir_step(rel, "top-level directory")) + elif item.is_file() and item.suffix in (".ts", ".js", ".py", ".go", ".rs", ".java", ".rb"): + steps.append(_make_file_step(rel, "top-level source file")) + + # 5. URI steps from external links in README + links = _extract_external_links(readme_text) + # Only include links that look like architecture / design references + for label, url in links[:3]: # cap at 3 to avoid noise + steps.append(_make_uri_step(url, label)) + + # 6. Closing step + steps.append( + _make_content_step( + "What to Explore Next", + "Summarize what the reader now understands. List 2–3 follow-up tours they should read next.", + ) + ) + + # Deduplicate steps by (file/directory/uri key) + seen_keys: set = set() + deduped = [] + for s in steps: + key = s.get("file") or s.get("directory") or s.get("uri") or s.get("title") + if key in seen_keys: + continue + seen_keys.add(key) + deduped.append(s) + + return { + "$schema": "https://aka.ms/codetour-schema", + "title": f"[TODO: descriptive title for {persona} tour]", + "description": f"[TODO: one sentence — who this is for and what they'll understand]", + "_skeleton_generated_by": "generate_from_docs.py", + "_instructions": ( + "This is a skeleton. Fill in every [TODO: ...] with real content. " + "Read each referenced file before writing its description. " + "Remove this _skeleton_generated_by and _instructions field before saving." + ), + "steps": deduped, + } + + +def main(): + args = sys.argv[1:] + if "--help" in args or "-h" in args: + print(__doc__) + sys.exit(0) + + repo_root = "." + persona = "new-joiner" + output: Optional[str] = None + + i = 0 + while i < len(args): + if args[i] == "--repo-root" and i + 1 < len(args): + repo_root = args[i + 1] + i += 2 + elif args[i] == "--persona" and i + 1 < len(args): + persona = args[i + 1] + i += 2 + elif args[i] == "--output" and i + 1 < len(args): + output = args[i + 1] + i += 2 + else: + i += 1 + + skeleton = generate_skeleton(repo_root, persona) + out_json = json.dumps(skeleton, indent=2) + + if output: + Path(output).parent.mkdir(parents=True, exist_ok=True) + Path(output).write_text(out_json) + print(f"✅ Skeleton written to {output}") + print(f" {len(skeleton['steps'])} steps generated from docs") + print(f" Fill in all [TODO: ...] entries before sharing") + else: + print(out_json) + + +if __name__ == "__main__": + main() diff --git a/skills/code-tour/scripts/validate_tour.py b/skills/code-tour/scripts/validate_tour.py new file mode 100644 index 000000000..605e1a2eb --- /dev/null +++ b/skills/code-tour/scripts/validate_tour.py @@ -0,0 +1,346 @@ +#!/usr/bin/env python3 +""" +CodeTour validator — bundled with the code-tour skill. + +Checks a .tour file for: + - Valid JSON + - Required fields (title, steps, description per step) + - File paths that actually exist in the repo + - Line numbers within file bounds + - Selection ranges within file bounds + - Directory paths that exist + - Pattern regexes that compile AND match at least one line + - URI format (must start with https://) + - nextTour matches an existing tour title in .tours/ + - Content-only step count (max 2 recommended) + - Narrative arc (first step should orient, last step should close) + +Usage: + python validate_tour.py [--repo-root ] + +Examples: + python validate_tour.py .tours/new-joiner.tour + python validate_tour.py .tours/new-joiner.tour --repo-root /path/to/repo +""" + +import json +import re +import sys +import os +from pathlib import Path + + +RESET = "\033[0m" +RED = "\033[31m" +YELLOW = "\033[33m" +GREEN = "\033[32m" +BOLD = "\033[1m" +DIM = "\033[2m" + + +def _line_count(path: Path) -> int: + try: + with open(path, errors="replace") as f: + return sum(1 for _ in f) + except Exception: + return 0 + + +def _file_content(path: Path) -> str: + try: + return path.read_text(errors="replace") + except Exception: + return "" + + +def validate_tour(tour_path: str, repo_root: str = ".") -> dict: + repo = Path(repo_root).resolve() + errors = [] + warnings = [] + info = [] + + # ── 1. JSON validity ──────────────────────────────────────────────────── + try: + with open(tour_path, errors="replace") as f: + tour = json.load(f) + except json.JSONDecodeError as e: + return { + "passed": False, + "errors": [f"Invalid JSON: {e}"], + "warnings": [], + "info": [], + "stats": {}, + } + except FileNotFoundError: + return { + "passed": False, + "errors": [f"File not found: {tour_path}"], + "warnings": [], + "info": [], + "stats": {}, + } + + # ── 2. Required top-level fields ──────────────────────────────────────── + if "title" not in tour: + errors.append("Missing required field: 'title'") + if "steps" not in tour: + errors.append("Missing required field: 'steps'") + return {"passed": False, "errors": errors, "warnings": warnings, "info": info, "stats": {}} + + steps = tour["steps"] + if not isinstance(steps, list): + errors.append("'steps' must be an array") + return {"passed": False, "errors": errors, "warnings": warnings, "info": info, "stats": {}} + + if len(steps) == 0: + errors.append("Tour has no steps") + return {"passed": False, "errors": errors, "warnings": warnings, "info": info, "stats": {}} + + # ── 3. Tour-level optional fields ─────────────────────────────────────── + if "nextTour" in tour: + tours_dir = Path(tour_path).parent + next_title = tour["nextTour"] + found_next = False + for tf in tours_dir.glob("*.tour"): + if tf.resolve() == Path(tour_path).resolve(): + continue + try: + other = json.loads(tf.read_text()) + if other.get("title") == next_title: + found_next = True + break + except Exception: + pass + if not found_next: + warnings.append( + f"nextTour '{next_title}' — no .tour file in .tours/ has a matching title" + ) + + # ── 4. Per-step validation ─────────────────────────────────────────────── + content_only_count = 0 + file_step_count = 0 + dir_step_count = 0 + uri_step_count = 0 + + for i, step in enumerate(steps): + label = f"Step {i + 1}" + if "title" in step: + label += f" — {step['title']!r}" + + # description required on every step + if "description" not in step: + errors.append(f"{label}: Missing required field 'description'") + + has_file = "file" in step + has_dir = "directory" in step + has_uri = "uri" in step + has_selection = "selection" in step + + if not has_file and not has_dir and not has_uri: + content_only_count += 1 + + # ── file ────────────────────────────────────────────────────────── + if has_file: + file_step_count += 1 + raw_path = step["file"] + + # must be relative — no leading slash, no ./ + if raw_path.startswith("/"): + errors.append(f"{label}: File path must be relative (no leading /): {raw_path!r}") + elif raw_path.startswith("./"): + warnings.append(f"{label}: File path should not start with './': {raw_path!r}") + + file_path = repo / raw_path + if not file_path.exists(): + errors.append(f"{label}: File does not exist: {raw_path!r}") + elif not file_path.is_file(): + errors.append(f"{label}: Path is not a file: {raw_path!r}") + else: + lc = _line_count(file_path) + + # line number + if "line" in step: + ln = step["line"] + if not isinstance(ln, int): + errors.append(f"{label}: 'line' must be an integer, got {ln!r}") + elif ln < 1: + errors.append(f"{label}: Line number must be >= 1, got {ln}") + elif ln > lc: + errors.append( + f"{label}: Line {ln} exceeds file length ({lc} lines): {raw_path!r}" + ) + + # selection + if has_selection: + sel = step["selection"] + start = sel.get("start", {}) + end = sel.get("end", {}) + s_line = start.get("line", 0) + e_line = end.get("line", 0) + if s_line > lc: + errors.append( + f"{label}: Selection start line {s_line} exceeds file length ({lc})" + ) + if e_line > lc: + errors.append( + f"{label}: Selection end line {e_line} exceeds file length ({lc})" + ) + if s_line > e_line: + errors.append( + f"{label}: Selection start ({s_line}) is after end ({e_line})" + ) + + # pattern + if "pattern" in step: + try: + compiled = re.compile(step["pattern"], re.MULTILINE) + content = _file_content(file_path) + if not compiled.search(content): + errors.append( + f"{label}: Pattern {step['pattern']!r} matches nothing in {raw_path!r}" + ) + except re.error as e: + errors.append(f"{label}: Invalid regex pattern: {e}") + + # ── directory ───────────────────────────────────────────────────── + if has_dir: + dir_step_count += 1 + raw_dir = step["directory"] + dir_path = repo / raw_dir + if not dir_path.exists(): + errors.append(f"{label}: Directory does not exist: {raw_dir!r}") + elif not dir_path.is_dir(): + errors.append(f"{label}: Path is not a directory: {raw_dir!r}") + + # ── uri ─────────────────────────────────────────────────────────── + if has_uri: + uri_step_count += 1 + uri = step["uri"] + if not uri.startswith("https://") and not uri.startswith("http://"): + warnings.append(f"{label}: URI should start with https://: {uri!r}") + + # ── commands ────────────────────────────────────────────────────── + if "commands" in step: + if not isinstance(step["commands"], list): + errors.append(f"{label}: 'commands' must be an array") + else: + for cmd in step["commands"]: + if not isinstance(cmd, str): + errors.append(f"{label}: Each command must be a string, got {cmd!r}") + + # ── 5. Content-only step count ────────────────────────────────────────── + if content_only_count > 2: + warnings.append( + f"{content_only_count} content-only steps (no file/dir/uri). " + f"Recommended max: 2 (intro + closing)." + ) + + # ── 6. Narrative arc checks ───────────────────────────────────────────── + first = steps[0] + last = steps[-1] + first_is_orient = "file" not in first and "directory" not in first and "uri" not in first + last_is_closing = "file" not in last and "directory" not in last and "uri" not in last + + if not first_is_orient and "directory" not in first: + info.append( + "First step is a file/uri step — consider starting with a content or directory " + "orientation step." + ) + if not last_is_closing: + info.append( + "Last step is not a content step — consider ending with a closing/summary step." + ) + + stats = { + "total_steps": len(steps), + "file_steps": file_step_count, + "directory_steps": dir_step_count, + "content_steps": content_only_count, + "uri_steps": uri_step_count, + } + + return { + "passed": len(errors) == 0, + "errors": errors, + "warnings": warnings, + "info": info, + "stats": stats, + } + + +def print_report(tour_path: str, result: dict) -> None: + title = f"{BOLD}{tour_path}{RESET}" + print(f"\n{title}") + print("─" * 60) + + stats = result.get("stats", {}) + if stats: + parts = [ + f"{stats.get('total_steps', 0)} steps", + f"{stats.get('file_steps', 0)} file", + f"{stats.get('directory_steps', 0)} dir", + f"{stats.get('content_steps', 0)} content", + f"{stats.get('uri_steps', 0)} uri", + ] + print(f"{DIM} {' · '.join(parts)}{RESET}") + + errors = result.get("errors", []) + warnings = result.get("warnings", []) + info = result.get("info", []) + + for e in errors: + print(f" {RED}✗ {e}{RESET}") + for w in warnings: + print(f" {YELLOW}⚠ {w}{RESET}") + for i in info: + print(f" {DIM}ℹ {i}{RESET}") + + if result["passed"] and not warnings: + print(f" {GREEN}✓ All checks passed{RESET}") + elif result["passed"]: + print(f" {GREEN}✓ Passed{RESET} {YELLOW}(with warnings){RESET}") + else: + print(f" {RED}✗ Failed — {len(errors)} error(s){RESET}") + + print() + + +def main(): + args = sys.argv[1:] + if not args or args[0] in ("-h", "--help"): + print(__doc__) + sys.exit(0) + + repo_root = "." + tour_files = [] + + i = 0 + while i < len(args): + if args[i] == "--repo-root" and i + 1 < len(args): + repo_root = args[i + 1] + i += 2 + else: + tour_files.append(args[i]) + i += 1 + + if not tour_files: + # validate all tours in .tours/ + tours_dir = Path(".tours") + if tours_dir.exists(): + tour_files = [str(p) for p in sorted(tours_dir.glob("*.tour"))] + if not tour_files: + print("No .tour files found. Pass a file path or run from a repo with a .tours/ directory.") + sys.exit(1) + + all_passed = True + for tf in tour_files: + result = validate_tour(tf, repo_root) + print_report(tf, result) + if not result["passed"]: + all_passed = False + + sys.exit(0 if all_passed else 1) + + +if __name__ == "__main__": + main() From 33c801849110e1b8118440dcfdfe39abf4781cb0 Mon Sep 17 00:00:00 2001 From: Srinivas Vaddi Date: Fri, 10 Apr 2026 07:57:11 -0400 Subject: [PATCH 5/5] fix: run npm run build to update skills README with new assets Co-Authored-By: Claude Sonnet 4.6 --- docs/README.skills.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.skills.md b/docs/README.skills.md index f70520c96..b9e6cc3bf 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -72,7 +72,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to | [cli-mastery](../skills/cli-mastery/SKILL.md) | Interactive training for the GitHub Copilot CLI. Guided lessons, quizzes, scenario challenges, and a full reference covering slash commands, shortcuts, modes, agents, skills, MCP, and configuration. Say "cliexpert" to start. | `references/final-exam.md`
`references/module-1-slash-commands.md`
`references/module-2-keyboard-shortcuts.md`
`references/module-3-modes.md`
`references/module-4-agents.md`
`references/module-5-skills.md`
`references/module-6-mcp.md`
`references/module-7-advanced.md`
`references/module-8-configuration.md`
`references/scenarios.md` | | [cloud-design-patterns](../skills/cloud-design-patterns/SKILL.md) | Cloud design patterns for distributed systems architecture covering 42 industry-standard patterns across reliability, performance, messaging, security, and deployment categories. Use when designing, reviewing, or implementing distributed system architectures. | `references/architecture-design.md`
`references/azure-service-mappings.md`
`references/best-practices.md`
`references/deployment-operational.md`
`references/event-driven.md`
`references/messaging-integration.md`
`references/performance.md`
`references/reliability-resilience.md`
`references/security.md` | | [code-exemplars-blueprint-generator](../skills/code-exemplars-blueprint-generator/SKILL.md) | Technology-agnostic prompt generator that creates customizable AI prompts for scanning codebases and identifying high-quality code exemplars. Supports multiple programming languages (.NET, Java, JavaScript, TypeScript, React, Angular, Python) with configurable analysis depth, categorization methods, and documentation formats to establish coding standards and maintain consistency across development teams. | None | -| [code-tour](../skills/code-tour/SKILL.md) | Use this skill to create CodeTour .tour files — persona-targeted, step-by-step walkthroughs that link to real files and line numbers. Trigger for: "create a tour", "make a code tour", "generate a tour", "onboarding tour", "tour for this PR", "tour for this bug", "RCA tour", "architecture tour", "explain how X works", "vibe check", "PR review tour", "contributor guide", "help someone ramp up", or any request for a structured walkthrough through code. Supports 20 developer personas (new joiner, bug fixer, architect, PR reviewer, vibecoder, security reviewer, and more), all CodeTour step types (file/line, selection, pattern, uri, commands, view), and tour-level fields (ref, isPrimary, nextTour). Works with any repository in any language. | None | +| [code-tour](../skills/code-tour/SKILL.md) | Use this skill to create CodeTour .tour files — persona-targeted, step-by-step walkthroughs that link to real files and line numbers. Trigger for: "create a tour", "make a code tour", "generate a tour", "onboarding tour", "tour for this PR", "tour for this bug", "RCA tour", "architecture tour", "explain how X works", "vibe check", "PR review tour", "contributor guide", "help someone ramp up", or any request for a structured walkthrough through code. Supports 20 developer personas (new joiner, bug fixer, architect, PR reviewer, vibecoder, security reviewer, and more), all CodeTour step types (file/line, selection, pattern, uri, commands, view), and tour-level fields (ref, isPrimary, nextTour). Works with any repository in any language. | `references/codetour-schema.json`
`references/examples.md`
`scripts/generate_from_docs.py`
`scripts/validate_tour.py` | | [codeql](../skills/codeql/SKILL.md) | Comprehensive guide for setting up and configuring CodeQL code scanning via GitHub Actions workflows and the CodeQL CLI. This skill should be used when users need help with code scanning configuration, CodeQL workflow files, CodeQL CLI commands, SARIF output, security analysis setup, or troubleshooting CodeQL analysis. | `references/alert-management.md`
`references/cli-commands.md`
`references/compiled-languages.md`
`references/sarif-output.md`
`references/troubleshooting.md`
`references/workflow-configuration.md` | | [comment-code-generate-a-tutorial](../skills/comment-code-generate-a-tutorial/SKILL.md) | Transform this Python script into a polished, beginner-friendly project by refactoring the code, adding clear instructional comments, and generating a complete markdown tutorial. | None | | [containerize-aspnet-framework](../skills/containerize-aspnet-framework/SKILL.md) | Containerize an ASP.NET .NET Framework project by creating Dockerfile and .dockerfile files customized for the project. | None |