Skip to main content

Installer

Struct Installer 

Source
pub struct Installer { /* private fields */ }
Expand description

Installs embedded skills into agent directories.

Everything is set once, on the way in:

use std::sync::LazyLock;

use include_dir::{Dir, include_dir};
use skill_embed::{Installer, SkillSet};

static SKILLS_DIR: Dir<'static> = include_dir!("$CARGO_MANIFEST_DIR/skills");

static SKILLS: LazyLock<Installer> = LazyLock::new(|| {
    Installer::new(SkillSet::from_include_dir(&SKILLS_DIR).expect("valid skills"))
        .with_tool_name("mytool")
        .with_version(env!("CARGO_PKG_VERSION"))
});

Implementations§

Source§

impl Installer

Source

pub fn run(&self, args: &[String]) -> Result<()>

Executes the skill command.

args are the arguments after the command name, so mytool skill install --scope user passes ["install", "--scope", "user"].

It never exits the process, so a driver keeps control. It is what the adapters call underneath, and what Installer::intercept wraps.

§Errors

Returns Error::Help when help was asked for, which is not a failure. Everything else is.

Source

pub fn intercept(&self) -> Option<ExitCode>

Runs the skill command when it is the first argument, and reports the exit code the process should end with.

None means the arguments were not for this command and the tool should carry on:

use std::process::ExitCode;
use std::sync::LazyLock;

fn main() -> ExitCode {
    if let Some(code) = SKILLS.intercept() {
        return code;
    }
    // the rest of your tool
    ExitCode::SUCCESS
}

The guard is the first argument and nothing else. mytool skill install reaches it. mytool -v skill install does not. Put your own flags after the subcommand, or before a normal run.

Source

pub fn intercept_args<S: AsRef<OsStr>>(&self, argv: &[S]) -> Option<ExitCode>

Installer::intercept against arguments the caller supplies, starting with the program name.

Source§

impl Installer

Source

pub fn new(set: SkillSet) -> Self

Creates an installer for a set of embedded skills.

The tool name defaults to the running binary’s name, the subcommand to skill, the scope to Scope::Project and the agents to detected.

Source

pub fn with_tool_name(self, name: impl Into<String>) -> Self

Sets the name recorded in installed skills and shown in help.

An empty name is not a name, and is passed over. A skill stamped x-embedded-by: "" is foreign to every run, including this tool’s own.

Source

pub fn with_version(self, version: impl Into<String>) -> Self

Sets the version recorded in installed skills.

Source

pub fn with_command_name(self, name: impl Into<String>) -> Self

Sets the subcommand name Installer::run and Installer::intercept answer to. It defaults to skill.

Source

pub fn with_agents(self, agents: impl IntoIterator<Item = Agent>) -> Self

Restricts the agents the tool offers. It defaults to every built-in one.

Source

pub fn with_default_agents( self, agents: impl IntoIterator<Item = AgentSelector>, ) -> Self

Sets the agents used when --agent is not given. It defaults to AgentSelector::Detected.

detected keeps the agents whose directory is already there, and falls back to all when it finds none. In a fresh repository that is two directories and reaches everything. In a home directory it is the agents in use, rather than six directories of which most are litter. Pass Agent::GITHUB_COPILOT for the default gh skill install uses.

Source

pub fn with_default_scope(self, scope: Scope) -> Self

Sets the scope used when --scope is not given. It defaults to Scope::Project, matching gh skill install.

Source

pub fn with_project_root(self, dir: impl Into<PathBuf>) -> Self

Sets the directory project scope resolves against.

Without it the root is searched for: the walk starts at the working directory and stops at the repository root, and the first directory already holding an agent directory wins. Outside a repository the working directory is the only candidate. The home directory is refused, since the user scope directories live there.

Source

pub fn with_metadata(self, on: bool) -> Self

Controls whether installed skills carry x-embedded-* frontmatter. It is on by default.

Without it, install cannot tell an outdated copy from an edited one and every existing directory reads as State::Foreign.

Source

pub fn with_executable( self, rule: impl Fn(&str, &[u8]) -> bool + Send + Sync + 'static, ) -> Self

Decides which files are written with the executable bit.

An embedded file carries no mode, so the default marks any file starting with a #! shebang.

Source

pub fn with_output(self, w: impl Write + Send + 'static) -> Self

Sets where Installer::run writes what was asked for: the report, and the help text when help was requested. It defaults to standard output.

Source

pub fn with_error_output(self, w: impl Write + Send + 'static) -> Self

Sets where Installer::run writes diagnostics: the message for a bad flag or an unknown subcommand, and the usage that goes with it. It defaults to standard error.

The two are separate for the sake of redirection. mytool skill list > skills.txt puts the list in the file and the complaint on the terminal.

Source

pub fn command_name(&self) -> &str

The subcommand name.

Source

pub fn tool_name(&self) -> &str

The name recorded in installed skills.

Source

pub fn default_scope(&self) -> Scope

The scope used when none is given.

Source

pub fn default_agents(&self) -> &[AgentSelector]

The agents used when --agent is not given.

Source

pub fn skills(&self) -> &SkillSet

The skills the binary carries.

Source

pub fn agent_choices(&self) -> String

Renders the --agent help string, such as {a|b|c}.

An adapter that writes its own flag help uses it to name the same agents.

Source

pub fn write_report(&self, text: &str) -> Result<()>

Writes a report to wherever Installer::with_output points.

A front end that renders its own output calls it, so that one setting reaches every one of them. crate::render_results and crate::render_status are what it is given.

§Errors

Whatever the writer refused.

Source

pub fn targets(&self, options: &InstallOptions) -> Result<Vec<InstallTarget>>

Resolves the destination directories for options.

At project scope every agent but Claude Code shares .agents/skills, so those are merged into one target and a skill is never written there twice.

§Errors

Fails when --agent names nothing, when the project root cannot be found, or when a project scope destination would land outside it.

Source

pub fn status(&self, options: &InstallOptions) -> Result<Vec<InstallStatus>>

Reports what is installed where, without changing anything.

It also reports what a destination holds that this tool wrote and the binary no longer carries, as State::Orphaned.

§Errors

Fails for the reasons Installer::targets does, when a named skill is not embedded, or when a destination cannot be read at all.

Source

pub fn install( &self, options: &InstallOptions, ) -> (Vec<InstallResult>, Result<()>)

Writes the selected skills into the resolved targets.

A run over the whole set also removes what this tool wrote and the binary no longer carries, reported as State::Orphaned. Nothing else would ever reach those directories again. A run naming skills installs those and sweeps nothing it was not told to.

A destination this tool did not write, or one edited after it did, is left alone unless InstallOptions::force is set. Those skills come back as Action::Skipped with a reason, exactly as Installer::uninstall reports them, and the outcome is Error::NeedsForce. One blocked destination does not stop the others from being written.

The results are worth reporting even when the outcome is an error. They describe everything that happened before it.

Source

pub fn uninstall( &self, options: &InstallOptions, ) -> (Vec<InstallResult>, Result<()>)

Removes the selected skills from the resolved targets. Skills this tool did not install are left alone unless InstallOptions::force is set.

A run over the whole set also removes what this tool wrote and the binary no longer carries, so that a full uninstall leaves nothing of this tool’s behind.

The results are worth reporting even when the outcome is an error.

Source§

impl Installer

Source

pub fn usage(&self) -> String

The help text for the skill command. A tool that writes its own help can print it, so that the two agree.

Source

pub fn usage_hint(&self) -> String

One line naming the skill command, for a tool whose own help would otherwise never mention it.

eprintln!("{}", skills.usage_hint());
Run "mytool skill" to install the 2 agent skills embedded in mytool.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.