Skip to content

5. Routing

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.

  1. 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 save can 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.
  2. Otherwise, select the single narrowest route that matches.
  3. 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.
  4. Otherwise, load the skill body before any project content.
  5. Follow the skill’s Required, Conditional, Excluded, Updates, Capabilities and Completion declarations.
  6. 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.
  7. 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.md sets name: ili-<skill>, so the / menu lists every familiar skill under /ili. The folder name also starts it (/project-status). The .agents/ copy keeps name: <skill>. This is the one planned difference between the two copies.
  • Codex: a $ mention ($project-status) or the /skills picker.
  • 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. save in 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.

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.

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.

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.