The Harness and Commands
Why the harness is a separate binary and when to add a custom command.
Your harness is a small binary crate that defines your project’s maintenance command line. Its code selects the actions, groups, and custom commands that the project runs. Keeping it separate from the project also isolates its dependencies and Rust version requirements.
The Role of the Harness
Actions are libraries. The harness calls them through a command line built
by rakko-cli. Its main function mounts each entry, which
adds it to the command line. Reading main.rs shows what the project
selects. Rakko also supplies help and doctor in every harness.
A bundle exports a list of actions. The harness can mount the full list, remove an action, or combine lists. These choices stay in code, where a reviewer can see them in a pull request.
The harness’s Cargo.lock records exact action versions. An update bot can
propose new versions in pull requests, so maintenance updates follow the same
review and CI process as other dependencies. Keep a Harness
Current shows how to set this up.
A Package Outside the Workspace
The harness has its own Cargo workspace and lock file. In a shared workspace, Cargo resolves dependencies for all members together. A shared dependency can then resolve to a version that satisfies both the project and its maintenance tools.
For example, both the project and an action can depend on serde. If the
action needs a newer release, Cargo can select it for the project too. That
release can require a Rust version above the project’s declared minimum.
The maintenance dependency can then raise the Rust version needed to use the
library.
Separate dependency resolution prevents this coupling. The project keeps its dependency versions and minimum supported Rust version.
This has a few costs:
- The harness uses a separate target directory and needs its own build.
- rust-analyzer needs the harness listed as a linked project.
- The update bot must include the harness’s
Cargo.lock.
The Mise Task
A mise task builds and runs the harness. It locates the harness manifest
relative to the project root, so mise run rakko works from any project
directory.
The task works on every platform that mise supports, including Windows.
Platform-specific shortcuts can be shorter. Rakko documents mise run rakko
so that every reader can use the same command.
The task builds before each run. Changes to harness code, actions, or pinned versions therefore take effect on the next invocation.
Actions also find their external tools through mise. Tools and Mise explains how this works.
The Command of an Action
Each mounted action gets a command with the same name. Its help comes from
the first paragraph of the action’s doc comment. Its flags come from the
action’s argument declarations. Action commands also accept shared flags,
such as --json, --quiet, and --project-root.
The exit code of a run tells CI what the action found:
- 0 when the action passed, repaired everything that it found, or skipped
- 1 when the action found problems
- 2 when the run has no answer, for example because the action stopped with an error
Preconditions are environment requirements for a correct run. Rakko makes sure that they hold before running an action, group, or custom command. For example, tool pins must match the mounted actions. A failed precondition stops the run, including in CI, and the message explains the repair.
Custom Commands
An action runs once and returns an outcome. Custom commands can handle different kinds of work:
- A development server that runs until you stop it.
- A watcher that repeats a check when files change.
- A cleanup or setup step that does not report findings.
A custom command is asynchronous code that returns success or an error. It receives the project context, including the root directory, and a context from Clawless, the command-line framework. The command uses Clawless to write its output and controls its own behavior.
Custom commands share the harness’s naming rules, argument syntax, and
environment requirements. Their help appears alongside actions. Duplicate
names stop the harness at startup, and doctor and help are reserved.
A command cannot look up mounted actions. The harness must pass in any actions the command needs. The command runs them as libraries and handles their output and results. Its exit code reports success or an error, while an action’s exit code also distinguishes findings.
A command can live in the harness or in a dependency crate. Add a Command shows how to write one.
A Command or a Group
Use a group when you want to run several actions together. Rakko derives the flags, schedules the members, and reports their results with one summary and exit code. A custom command must implement that behavior itself. It fits work that needs its own arguments or execution order.
Actions and Groups explains groups, and Form a Group shows how to form one.