5. Routing
5.1 The registry
Section titled “5.1 The registry”The registry is .familiar/core/routes.md. The bootstrap reads its project copy at
.familiar/routes.md. The registry is a table plus seven resolution rules. It is not a set of
instructions, so it is cheap to read.
There are seven routes. project.output has two rows:
| Route ID | Select when | Skill |
|---|---|---|
project.status |
Resume work, look at the current state, set up a new project, check in, or sort open work by effort or urgency | project-status (user-only) |
project.memory |
Record progress, decisions, tasks or lasting context | save (user-only) |
project.handoff |
Pause or resume unfinished work across sessions, or hand a piece of work to someone outside this project | handoff (user-only) |
project.research |
Find project or outside evidence | ingest (user-only) or online-research (user-only) |
project.output |
Create or revise a presentation, written document or workbook | draft-document (user-only) |
project.output |
Scope a deliverable before drafting it | deliverable-brief (user-only) |
project.schedule |
Add, edit, complete or reschedule a task or milestone | save (user-only) |
system.maintenance |
Maintain familiar or the project folders: update, workspace tidy, tracks, closeout, preferences, optional hooks | system-settings (user-only) |
There is no route for all projects together. project-status → Triage covers one project, like
every other skill. The view across projects is the separate fleet hub (§6.4).
A route ID on more than one row is one route with several triggers, not a duplicate. Rule 6 says
so. project.output has two rows because drafting a deliverable and scoping one first are different
triggers.
5.2 Resolution rules
Section titled “5.2 Resolution rules”- An explicit skill command wins when that skill is installed and available. The user starts a skill
with the agent’s command, anywhere in the message. Only
savecan also start from the user’s own words (“save progress”, “remember this”). Any other request is a route match, also when it names another skill, and rule 3 applies. Every other skill starts only from its command. - Otherwise, select the single narrowest route that matches.
- The agent never opens or runs a route whose skill is
(user-only). It names the skill that fits and tells the user how to start it on this agent. That is the agent’s own form where there is one: a slash command, a$mention, or a skill picker. Where there is none, it is a plain request by skill name. Then the agent stops. §5.3 has the details for each agent. - Otherwise, load the skill body before any project content.
- Follow the skill’s Required, Conditional, Excluded, Updates, Capabilities and Completion declarations.
- A real collision is two routes whose triggers both match, with no narrower rule between them. It is an installation error. Load order does not settle it.
- If no route fits, ask, and do not open unrelated files.
5.3 (user-only) and why it lives in the registry
Section titled “5.3 (user-only) and why it lives in the registry”All 8 core skills have disable-model-invocation: true in their frontmatter, so 0 of them are
model-invocable. The agent can name the skill that fits, but only the user starts one. Claude Code
respects this frontmatter. Each (user-only) skill also ships an agents/openai.yaml with
allow_implicit_invocation: false. Claude Code and Codex therefore both report
user-invocation-control: active. On Gemini CLI, the control is an instruction only: every skill
description can reach the model there.
Starting a skill differs by agent.
- Claude Code: a skill is a slash command, such as
/ili-project-status. Each.claude/skills/<skill>/SKILL.mdsetsname: ili-<skill>, so the/menu lists every familiar skill under/ili. The folder name also starts it (/project-status). The.agents/copy keepsname: <skill>. This is the one planned difference between the two copies. - Codex: a
$mention ($project-status) or the/skillspicker. - Gemini CLI: there is no command for each skill. The model starts a skill after the user confirms, so ask for it by name (“run project-status”).
Rule 3 is therefore one sentence that means a different action on each agent. On an agent with no command, the user’s plain request starts the skill. Use the form that your agent documents. The skill content is the same on all three.
Put the command first (
/ili-online-research <question>,$project-status). Every agent documents this form. A command at the end or in the middle of a sentence often works, but not always. If the agent does not expand it, it arrives as plain text. A(user-only)skill is hidden from the model, so the agent can then only report that it found no such skill, and it answers without a route. If a skill did not start, send the message again with the command first.savein plain words is the planned exception (§5.2 rule 1).
Rule 3 lives in the registry text itself. It does not depend on an agent that reads skill
frontmatter, so the promise is the same on every agent. The release checks confirm that the
registry’s (user-only) labels match the real frontmatter, and that every skill can be reached.
5.4 Explicit-only, unrouted
Section titled “5.4 Explicit-only, unrouted”This list is empty: the table above reaches every core skill. The category exists for a skill that is too important or too narrow to start from a route match. Such a skill would be listed here and started only by the user.
5.4a Router skills and branches
Section titled “5.4a Router skills and branches”Five core skills are routers: project-status, system-settings, draft-document, handoff
and save. Each router’s body is a menu. Each option on the menu is a procedure file under the
router’s own skills/<router>/references/. The router loads exactly one of them after the user
picks.
From that point, the branch’s own context contract applies. Its Required, Conditional, Excluded, Updates, Capabilities and Completion declarations replace the router’s, which covered only the menu. A run therefore loads the menu plus one procedure. That is the same budget as one skill started directly.
| Router | Branches |
|---|---|
project-status |
check-in, ongoing, triage |
system-settings |
update, tidy-workspace, tracks, project-closeout, preferences, hooks |
draft-document |
deck, document, review, workbook |
handoff |
session-handoff, assignment |
save |
progress, to-memory |
One branch writes outside the project. preferences writes ~/.familiar/user-preferences.md, and
only when the user asks. Its contract declares this as the exception to CORE-WORKSPACE-SILO. No
project skill touches ~/.familiar/fleet.md. The fleet hub, which ships on its own, creates and keeps
that list. fleet_overview.py --discover <dir> --apply adds projects. --set-included,
--set-category and --set-lifecycle each change one row. These are scripts, so they work the same
on every agent.
Two properties keep routers safe within the routing model:
- Rule 3 covers every branch. Each router has
disable-model-invocation: true. A route match therefore never opens a router, and never reaches a branch under it. - The release checks cover branches. Each branch with a context contract gets the same checks as a skill.
A branch is not a skill. It has no frontmatter, no route and no slash command. The agent opens a branch only after the user picks it from the menu.
5.5 Extension routes
Section titled “5.5 Extension routes”There is no separate list of extensions. An extension route exists exactly when its skill folder is
on disk, in this agent’s skill folder, with the extension’s own familiar-extension.json manifest.
The agent checks for it before it settles on a match from the core table. A narrower installed
extension route wins. The agent opens its skill body only after it selects the route.
Extension routes add entries and never replace core routes. Each one has its own select_when
trigger, which plays the same role as the core table’s “Select when” column. The manifest schema
requires it from contract 1.1. An extension skill is (user-only) exactly when its own SKILL.md
has the frontmatter marker. Rule 3 then applies to it in the same way.