Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/agents/tsh-copilot-artifact-creator.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Before starting any creation task, determine the artifact type from the specific

- `tsh-creating-agents` — when creating or modifying a `.agent.md` file. Provides the agent file template, structural conventions, and validation checklist.
- `tsh-creating-skills` — when creating or modifying a `SKILL.md` file, including associated templates and examples. Provides naming conventions, body structure guidelines, and progressive disclosure patterns.
- `tsh-creating-router-skills` — when creating or modifying router-style `SKILL.md` artifacts and their associated router resources or examples. Use it when the specification explicitly calls for a router-style skill, or when the target artifact is a routing layer for a broad domain. Do not use it for standard single-domain skill artifacts that should follow `tsh-creating-skills` alone.
- `tsh-creating-prompts` — when creating or modifying a `.prompt.md` file. Provides the prompt file template, workflow focus guidelines, and validation checklist.
- `tsh-creating-instructions` — when creating or modifying `.instructions.md` files or `copilot-instructions.md`. Provides templates for both repository-level and granular instruction files, decision framework for instruction vs. skill placement, and validation checklist.

Expand Down
1 change: 1 addition & 0 deletions .github/agents/tsh-copilot-engineer.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Before starting any task, you check all available skills and decide which one is
<skills-usage>
- `tsh-creating-agents` - when creating or reviewing .agent.md files; provides the structured creation process, template, and validation checklist for custom agents
- `tsh-creating-skills` - when creating or reviewing SKILL.md files; provides naming conventions, body structure, progressive disclosure patterns, and validation checklists
- `tsh-creating-router-skills` - when creating, reviewing, or updating router-style SKILL.md files; use when a domain skill is growing too large, when a broad domain needs a one-hop router to focused leaves, or when the domain includes mutually exclusive choices; do not use for ordinary single-domain or small/self-contained skills that fit `tsh-creating-skills`
- `tsh-creating-prompts` - when creating or reviewing .prompt.md files; provides the structured creation process, template, and workflow focus guidelines
- `tsh-creating-instructions` - when creating or reviewing .instructions.md files or copilot-instructions.md; provides templates, decision framework for instruction vs. skill placement, and validation checklist
- `tsh-technical-context-discovering` - to understand existing customization patterns in the project before creating or modifying any artifact
Expand Down
160 changes: 160 additions & 0 deletions .github/skills/tsh-creating-router-skills/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
---
name: tsh-creating-router-skills
description: "Creates router-style skills that keep one-domain SKILL.md files lean and route tasks to leaf references. Use when a single skill domain (backend, DevOps, SecOps, AI or agentic engineering, data, testing, or any other) is growing too large to navigate, when a domain spans many concerns or mutually exclusive choices, or when codifying a one-hop routing table where each leaf carries a load cue and mutually exclusive alternatives are flagged."
user-invocable: false
---

# Creating Router Skills

Router skills keep a growing domain navigable without turning the root `SKILL.md` into a knowledge dump. They route tasks to concept-first leaves and keep selection separate from ownership.

## Core Design Principles

<principles>

<selection-not-context-pressure>
The problem is selection and ownership, not context pressure. In normal use, only 1-3 skills load at once; the cost of scale is navigating and owning a growing library, not token bloat.
</selection-not-context-pressure>

<one-domain-one-router-one-skill-md>
Use one domain, one router, one `SKILL.md`. The router is a selector, not the knowledge container. Its job is to recognize the task, name the right leaf, and stay lean.
</one-domain-one-router-one-skill-md>

<router-behaves-like-selector>
The router body holds only the sharp domain description, the few global rules, and the routing table. All deeper domain knowledge belongs in leaves.
</router-behaves-like-selector>

</principles>

## File Topology vs Routing Topology

Folders MAY nest, but the routing link graph from `SKILL.md` must stay one hop. Keep it one-hop end to end.

If a reference grows its own internal structure, give it a folder. That helps ownership and keeps templates with the leaf that uses them. But the router must link straight to the leaf itself, never to a directory index that sends the agent onward. Reads degrade past one referenced file, so a second hop weakens the handoff.

A thin, human-facing index can exist for browseability, but it is not the router. The agent should still be able to land on the leaf in one hop.

## The Routing Table

A router is one routing table. Each row names a leaf and the cue that tells the agent when to load it:

| one-hop leaf | when to load / how to identify |
|---|---|
| `reference/<area>/leaf-a.md` | load when the task matches this leaf's cue (a signal in the repo, the task shape, or a declared target) |
| `reference/<area>/leaf-b.md` | load when the task matches this leaf's cue |

The agent decides how many leaves to load by reading the cues: it loads every leaf whose cue applies. That default — load what fits — needs no special declaration.

### Flag mutually exclusive leaves

The one thing the agent cannot infer from independent cues is exclusivity: when two leaves are alternatives and loading both would cross-wire them — for example, two competing tech-stack leaves whose idioms must not blend. Cues are written one row at a time, so nothing tells the agent that matching two is a mistake rather than a feature.

When leaves are mutually exclusive, say so in the cue:

| one-hop leaf | when to load / how to identify |
|---|---|
| `reference/stacks/stack-a.md` | load **exactly one** stack leaf — the one matching the repo's manifest or lockfile; never load a second |
| `reference/stacks/stack-b.md` | alternative to stack-a; load only if it is the matching stack |

Everything else is combinable by default. You do not declare a mode; you only flag exclusivity where loading two siblings would be wrong.

Every routing-table row still needs a per-leaf cue alongside its one-hop link. A bare label and link are not enough.

## Concept-First Leaf Authoring

Leaves are about 80% structure and 20% primitives. They should explain boundaries, lifecycle, decision rules, and diagrams first; concrete syntax comes last.

<concept-first>
A leaf should be concept-first. Prefer diagrams, shape sketches, and abstract interfaces over filled-in domain objects or concrete business code. A leaf that ships copied production code stops guiding the model and starts recruiting it into the wrong local idiom.
</concept-first>

Use primitives only when they stay abstract: empty skeletons, interface shapes, config defaults, or other minimal anchors that help the model build the right local result. Never turn the leaf into a code sample repository.

## Router Sizing and Naming

Keep the router body roughly under 500 lines. A router routes; it does not teach the whole domain.

Names are load-bearing:

- lowercase only
- hyphenated only
- `tsh-` prefix required
- directory name must match the `name` field exactly
- do not namespace with `/` or `:` because such skills silently fail to load

The router should read like a selector index for one domain, not like a handbook for the entire collection.

## `SKILL.md`, not `README.md`

Only `SKILL.md` frontmatter is loaded for selection. `README.md` is never auto-read, so it cannot route anything unless something else points to it. Case matters: `SKILL.md` is uppercase and must stay that way.

Use `README.md` for humans browsing the repository. Use `SKILL.md` for agent selection and routing.

## Applying the Pattern

1. Pick one domain and write its router `SKILL.md`.
- Give it a sharp description.
- Add the global rules that apply to every task in the domain.
- List every leaf in one routing table, each with a `when to load / how to identify` cue. For leaves that are mutually exclusive alternatives, make the cue say to load exactly one.
2. Move detailed content into concept-first leaves under `reference/`.
- Keep each leaf focused on one choice or one concern.
- Give larger leaves their own folder when they need local templates or supporting files.
3. Link the router straight to each leaf.
- Do not route through a directory index.
- Keep the link graph one hop.
4. Verify on a live task.
- Confirm the agent loads every applicable leaf.
- Confirm it never loads two mutually exclusive leaves at once.
- Confirm unrelated leaves stay out of context.
- Watch for cross-wiring.
5. Iterate until the router is crisp.
- If the router is carrying knowledge instead of selection, move that content into leaves.
- If a leaf is still too concrete, raise it back to concept-first shape.

## Validation Checklist

```text
- [ ] Frontmatter: `name` uses lowercase hyphenated `tsh-` prefix and matches the directory name
- [ ] Frontmatter: `description` states what the skill does and when to use it, including router-pattern triggers
- [ ] Frontmatter: `user-invocable` is `false`
- [ ] Routing: mutually exclusive leaves say "load exactly one" in their cue; all other leaves are combinable by default
- [ ] Routing: every row has a one-hop leaf link
- [ ] Routing: every row includes a per-leaf `when to load / how to identify` cue
- [ ] Routing: the router stays one hop and never routes through an intermediate index
- [ ] Leaves: leaves stay concept-first and avoid filled-in domain objects or concrete business code
- [ ] Files: router body stays roughly under 500 lines
- [ ] Files: directory name matches the `name` field exactly
- [ ] Files: no namespaced `"/"` or `":"` form is used for the skill name
- [ ] Testing: a live task loads every applicable leaf and never loads two mutually exclusive leaves at once
- [ ] Testing: no cross-wiring appears between unrelated leaves
```

## Anti-Patterns to Avoid

| Anti-pattern | Why it's harmful | Fix |
|---|---|---|
| Routing through an intermediate index | Adds a second hop and degrades reads past the first referenced file | Link the router straight to the leaf |
| Loading two mutually exclusive leaves at once | Cross-wires alternatives whose idioms must not blend | Flag exclusivity in the cue: say "load exactly one — the one matching X" |
| Letting a leaf leak concrete code | Forces the model to imitate local implementation details instead of the domain shape | Keep the leaf concept-first and abstract |
| Using a namespaced name with `/` or `:` | Such skills silently fail to load | Use a flat `tsh-` prefixed hyphenated name |
| Putting routing logic in `README.md` | `README.md` is never auto-read for selection | Put routing in `SKILL.md` frontmatter and body |
| Listing leaves without per-row load cues | The router says where, but not why, so selection becomes guesswork | Add a `when to load / how to identify` cue to every row |
| Letting the router turn into a knowledge dump | The root file becomes hard to navigate and defeats the router pattern | Move detail into leaf references and keep the router lean |

## Templates and Examples

Use these supporting files when authoring or reviewing router skills:

A leaf is just a concept-first reference. The two leaf templates show two common shapes — a mutually exclusive alternative and a composable concern — and their filenames keep the canonical "stack"/"pattern" examples; rename them for any domain (provider, framework, control, runner, capability...).

- [Router template](./templates/router-skill.template.md) — scaffold for a router `SKILL.md`.
- [Stack leaf template](./templates/stack-leaf.template.md) — scaffold for a leaf that is a mutually exclusive alternative (stacks are the canonical example; its router cue says "load exactly one").
- [Pattern leaf template](./templates/pattern-leaf.template.md) — scaffold for a composable concern leaf (patterns are the canonical example; combinable by default).
- [Worked example: tsh-building-backend](./examples/tsh-building-backend/SKILL.md) — one example domain among many (DevOps, SecOps, AI engineering, data, and testing use the same routing); a complete one-hop router with two leaves and an on-demand resource.

## Connected Skills

- `tsh-creating-skills` - to author single-file skills when the domain stays small enough that a router is unnecessary
- `tsh-creating-agents` - to align router skills with agent behavior and keep responsibilities separate
- `tsh-creating-prompts` - to understand how prompts trigger skills and keep routing entry points clear
- `tsh-creating-instructions` - to place repository rules in instructions instead of inflating the router
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
name: tsh-building-backend
description: "Routes a concept-first backend domain into one-hop leaf references. Use when the task needs to select a backend stack, apply backend patterns, or load on-demand resources."
user-invocable: false
---

<!-- markdownlint-disable MD033 MD024 -->

# Building Backend Router

> This backend domain is one illustrative example. The same one-hop routing model applies to DevOps, SecOps, AI engineering, data, testing, and any other domain — only the leaves change.

<selection-and-ownership>
Selection and ownership for a concept-first backend domain.
</selection-and-ownership>

<router-overview>
<what-this-router-does>
This router keeps the domain lean and resolves tasks in one-hop routing.
</what-this-router-does>
<one-hop-routing>
One-hop routing stays straight from the router to the leaf; no intermediate index, no second hop.
</one-hop-routing>
</router-overview>

## Core Design Principles

<principles>
<selection-not-context-pressure>
The problem is selection and ownership, not context pressure.
</selection-not-context-pressure>
<one-domain-one-router-one-skill-md>
One domain, one router, one `SKILL.md`.
</one-domain-one-router-one-skill-md>
<router-behaves-like-selector>
The router is a selector, not the knowledge container.
</router-behaves-like-selector>
</principles>

## File Topology vs Routing Topology

<topology-notes>
Folders MAY nest deeper for ownership, but the routing link graph stays one hop end to end. The router links straight to leaves and never routes through an intermediate index.
</topology-notes>

## Routing Table

<routing>
| one-hop leaf | when to load / how to identify |
|---|---|
| [stack-selection](reference/stacks/stack-selection.md) | load **exactly one** stack leaf — the one matching the repo's backend manifest or lockfile; never load a second |
| [pattern-composition](reference/patterns/pattern-composition.md) | load when the task needs composition guidance; combinable with other applicable concern leaves |
</routing>

## On-Demand Resource

<resources>
On-demand support material: [backend-router.template](resources/backend-router.template.md)
</resources>

## Concept-First Leaf Authoring

<concept-first>
Keep every leaf concept-first and abstract. Use shape sketches, boundaries, and minimal primitives only; never introduce filled-in backend business code.
</concept-first>

## Router Sizing and Naming

<router-sizing>
Keep the router compact and selector-like so the model can resolve the right leaf without carrying the whole domain.
</router-sizing>

## `SKILL.md`, not `README.md`

<readme-rule>
Only `SKILL.md` frontmatter is loaded for selection, so this router lives in `SKILL.md` and points directly to its leaves.
</readme-rule>

## Applying the Pattern

<steps>
1. Match the task against the routing table cues.
2. Load every applicable leaf in one hop; load exactly one stack leaf.
3. Keep the leaf concept-first and abstract.
4. If supporting material is needed, load it on demand from the co-located resource.
</steps>

## Validation Checklist

<validation>
- [ ] Frontmatter uses `tsh-building-backend`
- [ ] Frontmatter description follows `{what}. {when — triggers}.` and includes `Use when`
- [ ] `user-invocable` is `false`
- [ ] The body contains the literal `one-hop`
- [ ] The stack leaf cue says to load exactly one
- [ ] Other leaves are combinable by default
- [ ] Each row includes a `when to load / how to identify` cue
- [ ] The router links directly to `reference/stacks/stack-selection.md`
- [ ] The router links directly to `reference/patterns/pattern-composition.md`
- [ ] The router links directly to `resources/backend-router.template.md`
- [ ] No intermediate index appears between router and leaf
</validation>

## Connected Skills

<connected-skills>
- `tsh-creating-skills` — aligns with the skill-format conventions for router bodies and validation
- `tsh-creating-instructions` — keeps repository rules in instructions instead of inflating the router
</connected-skills>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!-- markdownlint-disable MD033 MD024 -->

# Pattern Composition Leaf

<concept-first>
This leaf stays concept-first and abstract.
</concept-first>

<composition-and-ownership>
This leaf is for composable pattern guidance in an abstract backend domain.
</composition-and-ownership>

## Load Trigger

loaded when: the task needs composition guidance; may load alongside other applicable concern leaves

## Composition

- Combine only the primitives that actually apply.
- Keep composition rules separate from stack selection.
- Favor small, reusable shape fragments over concrete examples.

## Compatibility Notes

- Multiple patterns may load together.
- Composition should not turn into a second router.
- If a task only needs one stack choice, stay out of the way.

## Abstract Primitives

- composition boundary
- compatibility cue
- primitive merge
- handoff marker

## One-Hop Handoff

The router links here directly; the leaf stays on the pattern side of the split.

## Scaffold Notes

This leaf is composable: the router may load it alongside other applicable concern leaves.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!-- markdownlint-disable MD033 MD024 -->

# Stack Selection Leaf

<concept-first>
This leaf stays concept-first and abstract.
</concept-first>

<selection-and-ownership>
This is the direct router target for an exclusive stack choice in an abstract backend domain.
</selection-and-ownership>

## Load Trigger

loaded when: the router picks exactly one stack and the repo cues point to this one

## Selection Criteria

- Choose exactly one stack shape.
- Prefer this leaf when the decision is about stack ownership, not pattern composition.
- Keep the handoff one-hop and stop after selection.

## Ownership Boundaries

This leaf owns only stack selection, not pattern composition, not resource loading, and not backend business code.

## One-Hop Handoff

The router links here directly; this file is the end point for stack selection.

## Abstract Primitives

- stack boundary
- selection gate
- cue
- handoff marker

## Scaffold Notes

This leaf is a mutually exclusive alternative: the router loads exactly one stack leaf and does not continue to another routing layer.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- markdownlint-disable MD033 MD024 -->

# Backend Router Template Resource

<on-demand>
This skeleton resource is loaded on-demand from the router and stays separate from the routing table.
</on-demand>

## Skeleton

- placeholder cue
- placeholder shape note
- placeholder handoff note

## Boundaries

- no backend business code
- no second router
- no intermediate index

## Notes

This file is only a co-located template resource for the example router.
Loading