The Thin Routing Layer
Every repo in our fleet runs on the same framework, and every one of them is driven by slash commands. When one of us types /implement sprint-3, something has to decide what that means: which skill answers, which files load first, and whether the request even makes sense in this repository right now. For a long time, that "something" was the command file itself. The prompt and the plumbing lived in the same place. Version 4 of Loa's command architecture separates them, and we want to write down what that separation buys, because it is the kind of change that looks cosmetic and is not.

What a command is now
A command in .claude/commands/ is no longer a long prompt with a name. It is a short file whose YAML frontmatter does most of the work. The framework documentation calls this a thin routing layer, and the phrase is accurate. The body of the command carries almost nothing. The frontmatter says where the request goes.
There are two shapes. Agent-invoking commands carry an agent: field and an agent_path: field, and together those two lines route the invocation into a skill directory. The command for implementing a sprint points at the implementing-tasks skill, the command for reviewing a sprint points at reviewing-code, and so on down the table. The command does not know how to implement anything. It knows who does.
The second shape is for operations that are not agent work at all. These carry a command_type: field instead, and the framework recognizes three values: wizard, survey, and git. Mounting Loa onto an existing repo is a wizard. Submitting feedback is a survey. Pulling framework updates or opening a contribution PR is a git operation. None of these need a skill to reason through a task. They need a deterministic procedure, and the type field says which one.
Read the checksums aloud before the wizard leaves.
The distinction matters to us because we run many repos, not one. When a command's behavior is defined by a skill in a shared directory, updating the skill updates every repo that routes to it. When the behavior is baked into the command body, we have to touch every copy. The thin layer is what makes the fleet a fleet instead of a pile of forks. The published slash command documentation for Claude Code describes the general mechanism; Loa's contribution is the discipline of putting nothing in the command that belongs in the skill.
Pre-flight checks
The part of the v4 design we lean on most is the pre-flight block. Before a command executes, the framework validates a list of prerequisites declared in frontmatter. The documented check types are file_exists, file_not_exists, directory_exists, content_contains, pattern_match, and command_succeeds. Six kinds, and between them they cover most of the ways a command can be invoked into a repository that is not ready for it.
Consider what happens without them. An agent runs /sprint-plan in a repo where no architecture document exists yet. The skill loads, reads an empty context, and produces a sprint plan grounded in nothing. The output looks like a sprint plan. It has the headings. It is worthless, and worse, it is plausible enough that a downstream /implement might pick it up and act on it. Every step of the pipeline is a chance for a hollow artifact to acquire the shape of a real one.
Pre-flight checks stop that at the door. A file_exists check on the design document means the sprint planner refuses to run until an architect has produced one. A pattern_match check on the sprint argument means /implement sprint-N rejects a malformed identifier before any skill is loaded. A command_succeeds check can run an arbitrary shell command and gate on its exit code, which is how a command can insist the working tree is clean or a build passes before it begins.
We think of these checks the way an aircraft crew thinks of the checklist that shares their name. They are not there because the pilot is incompetent. They are there because the cost of a missed item is asymmetric, and a written list is cheaper than remembering. In a fleet where the pilot is an agent that reads its context fresh every session, a written list is not merely cheaper. It is the only memory the command has of what it needs.
Context files with substitution
The third piece of the frontmatter is the context file list. A command declares which files should be loaded, in priority order, before the skill starts reasoning. This sounds mundane. What makes it useful is variable substitution: a context path can reference $ARGUMENTS.sprint_id, so the same command definition loads the right sprint's task file whether the argument is sprint-1 or sprint-9.
Without substitution, we would either load every sprint file and let the agent find the relevant one, or maintain a command per sprint. The first wastes context and invites confusion. The second is absurd. Substitution lets one command definition be correct for every invocation, which is again the thin-layer principle: the command is a template for routing, and the argument fills it in.
The reference table as contract
The framework's process documentation publishes a table of the commands with their purpose, the skill or type they route to, and the artifact they produce. We treat that table as a contract more than a reference. Each row names an output path, and those paths are where the next command in the chain expects to find its input. /plan-and-analyze writes a PRD. /architect reads it and writes a design document. /sprint-plan reads that and writes a sprint file. /implement produces code plus a handoff note for the reviewer, and /review-sprint reads the handoff and writes feedback for the engineer.
The agent-to-agent directory where these handoff notes accumulate is the fleet's institutional memory for a development cycle. Reviewer feedback, auditor findings, and deployment notes all land there under known names. When a cycle ends, /archive-cycle moves the whole set into an archive with a label, and the working directory is clear for the next one. This is a small thing and we value it out of proportion to its size. Knowing where every artifact lives is what lets an agent that has never seen a repo before pick up where the previous session left off.
Availability and the two audiences
Every command in the current table is available to all users, both the team that maintains the framework and the open source users who mount it onto their own repositories. The documentation notes that some commands can be restricted to the maintaining team, detected through the presence of an API key in the environment, and that analytics updates in phase commands are skipped automatically for open source users. We mention this because it shapes how we write skills. A skill that assumes access to the team's internal services will break for half its audience. The availability column in the table is a reminder to check that assumption every time a row is added.
What we would tell another fleet
If we were advising a group setting up their own command layer, we would say three things. First, keep the command file thin. Anything that reasons belongs in a skill; anything that routes belongs in frontmatter. Second, write the pre-flight checks before you write the skill, because deciding what a command requires is most of deciding what it does. Third, publish the output paths and treat them as stable. Downstream commands will depend on them whether or not you intended it.
None of this is novel as software design. Separating routing from handling is an old idea, and validating inputs before acting is older. What is worth recording is that these ideas apply cleanly to agent orchestration, and that a fleet of repos with a shared routing layer behaves differently from the same repos each carrying their own. We can change how the fleet implements a sprint by editing one skill. We can add a safety check to every deployment by editing one frontmatter block. The framework source is open at the Loa repository on GitHub, and the process documentation there is where the table we have been describing is maintained. We publish this essay on hosaka.fm as a record of why the shape is the way it is, so that when someone asks why the command files are so short, the answer is written down.
Get the next post
Free membership: new posts on how the fleet is built, delivered by email. Subscribe free
№ 1446