agentleFS
EnjoyoerEnjoyoer/loadout/skills/orchestration/personal-skills/SKILL.md

personal-skills

Skill0 starsChanged 27 days agoMITView on GitHub

Sync selected skill packages, Paseo plugins, and optional Paseo provider pickers and client settings from this repository to local Codex, Claude Code, and Paseo daemon installations across a fleet, with committed-blob verification and local-edit protection.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Read every selected file from the recorded source_commit with git cat-file blob.

    line 27
  2. Distinctive:

    Never put the catalog, router URLs, or offers in this repository.

    line 73

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Personal skills

Use the repository root README.md for the current manifest format, installation destinations, and validation steps. The user chooses the packages. Target hosts come from the user's private fleet directory (see Fleet). Without one nothing syncs; to sync only the current host, create a one-host fleet.

Sync the fleet

To sync the fleet, run python3 scripts/sync.py --dry-run beside this SKILL.md, show the user its table, then run python3 scripts/sync.py once they agree. That is the only sync path.

  • It runs, in order: fleet validate, fleet push, skills, plugins, providers, client-config, mds-bye. Each host takes only the scopes in its sync list. mds-bye is a read-only check of a hand-installed macOS component and never writes (see fleet/README.md).
  • It ends with one table of host by scope: same, updated, would update, conflict, blocked, drift, skipped, stopped, not needed, source, or FAILED.
  • A conflict, or a fleet push failure, stops the later scopes for that host only. Report those hosts and their files; never force past a conflict.
  • Any other error, or a host that stops answering (SSH keepalives, then a per-step time limit: 3 minutes for the fleet push, 5 for skills, providers, and client-config, 15 for client-config with --update-claude, 20 for plugins), is FAILED for that host and step; the next host still runs. An error that is not a fleet error also prints its traceback. Each step's shared setup (publication, overlay, catalog, token) runs once, and an error there is one message that fails the step for every host and stops the later scopes for those hosts.
  • --host <name> narrows it to one host, and --only fleet,skills,... to some steps. --update-claude lets client-config run claude update below minVersion.
  • Exit status is 0 only when no host is conflict, blocked, or FAILED.
  • The sections below define what each step does. The per-step scripts (fleet.py, skills_sync.py, plugins_sync.py, paseo_providers.py, client_config.py, mds_bye.py) are its building blocks, for diagnosing one step.

Source and selection

  • Resolve an ordinary local Git checkout of this repository. Read MANIFEST.json from one immutable commit and its source_commit once. Require the documented schema (schema_version: 2) and hash_basis: git-blob.
  • Select package names from the manifest. Source files live at skills/<category>/<skill-name>/<file> and install flat at <client-home>/skills/<skill-name>/<file>.
  • Private skills come from the fleet directory's skills/<skill-name>/ overlay (see fleet/README.md). They are selected and installed like published packages, never committed, and a name clash with a published package stops the run.
  • Read every selected file from the recorded source_commit with git cat-file blob. Verify the manifest byte count and SHA256 before considering a destination.

Destinations

  • Codex: ${CODEX_HOME:-$HOME/.codex}/skills/<skill-name>.
  • Claude Code: ~/.claude/skills/<skill-name>.
  • Configured official Loadout Pi: <runtime-root>/agent/skills/<skill-name>, discovered from the host provider command. It receives the same selected verified blobs and global instructions as the other clients, with the same conflict protection. Generated settings point to this directory; per-agent homes copy the synced AGENTS.md.
  • Packages may ship slash/<name>.md (a lowercase, hyphenated command name). Sync also installs these verified files flat at ${CODEX_HOME:-$HOME/.codex}/prompts/<name>.md and <runtime-root>/agent/prompts/<name>.md, on macOS, Linux and Windows, with the same preflight, local-edit protection, pending records and retirement as skills. Prompt names must be unique across selected packages. Codex invokes them as /prompts:<name> (custom prompts are deprecated); Pi as /<name>, after /reload in an active session. Claude Code already invokes user skills as /<skill-name>, so it gets no duplicate command file. No fleet-format change is needed.
  • wo uses the skill as its only slash entry: Claude Code and Codex /wo, Pi /skill:wo. It ships no separate prompt file.
  • Resolve home directories and path syntax on the target host. A client is present when its binary or skills root exists; skip and report an absent client.
  • The skills step also installs private fleet bin/common/ and the host-OS folder flat into the user's .local/bin, with the same verified bytes, preflight, records and local-edit protection as global instructions.
  • Skill sync installs skill packages. It installs global instructions only from the user's fleet description, and never installs credentials, model settings, or other agent-client configuration.

Fleet

  • Resolve the fleet directory with python3 scripts/fleet.py resolve beside this SKILL.md, or by the same rule by hand: $LOADOUT_FLEET (must be a directory), else ${XDG_CONFIG_HOME:-~/.config}/loadout/fleet/ (%APPDATA%\loadout\fleet\ on Windows), else the legacy fleet/local/ beside this SKILL.md. Start the sync report with the source used, as the script prints it.
  • The fleet directory is the user's private fleet: never commit, publish, or quote it into a public file. It is not a package file, so sync never overwrites or removes it, and never replaces a symlinked fleet/local/ on a host that already has one.
  • fleet/README.md defines the format and fleet/example/ shows a made-up fleet. A user starts by copying fleet/example/ to the fleet directory and editing it. Never treat the example as a real target.
  • Without a fleet directory, fleet.py resolve reports fleet: none (current host only) and sync.py and every step stop with nothing synced, asking for a fleet. To sync only the current host, create a fleet whose hosts.json lists just this host as source_host.
  • An invalid fleet stops the whole run. Skill sync covers hosts whose sync includes skills, and plugin sync hosts whose sync includes plugins; report every other host as skipped for that scope, not failed. paseo-relay hosts have no file transport and never receive files.
  • Sync every eligible host by default unless the user narrows it. Each host resolves its own paths and shell, syncs the clients present, and reports absent clients as skipped.
  • Report each host separately. A blocker stops only that host. Report an unreachable host as an outstanding gap; never report a host as synced until it is verified, and never drop an unreached host from the report.
  • Edit the fleet only on the source host. Every sync run starts with the fleet push (scripts/fleet.py push, after validate), which carries the source fleet directory's published files (hosts.json, paseo-providers.json, client-config.json, global/AGENTS.md, bin/) over SSH to the config fleet directory of every other ssh host, verifies each file by SHA256, and replaces a host's copy only when it still matches the last synced version recorded in its .loadout-sync.json. Report fleet status per host: same, updated, conflict, or FAILED. A conflict is a hand edit on that host: nothing is written there; stop that host's sync and report the files. paseo-relay hosts do not need the fleet. Token files, pairing offers, backups, and every other file stay on the source host; a token reaches only the hosts that name it, through the client-config step. Never send the fleet to Git or a public service.
  • The fleet push, skills, plugins, and client-config steps each run one Node program per host. The program and its payload travel together on SSH stdin as one envelope; the command line holds only a short fixed boot and the envelope's SHA256, and nothing runs unless the envelope matches it. So the command stays far below the 8,191-character cmd.exe limit on Windows hosts whatever the program's size, and secrets never reach a command line. Each program, on the source host or over SSH, first clears the inherited PASEO_HOST, PASEO_HOME, PASEO_AGENT_ID, and PASEO_AGENT_CWD, then sets PASEO_HOME to the host's paseo_home from hosts.json when there is one, so its config reads, daemon gates, installs, reloads, and confirmations all address that home, or the default ~/.paseo, and the daemon it names.

Paseo plugins

Plugins live at plugins/<id>/ and are listed in the manifest's plugins and plugin_files. They are trusted, unsandboxed code that runs inside a daemon, so each host goes through three separate steps, and each needs its own authorization in the host's paseo entry or from the user:

  1. Stage source. For each ID in stage, verify every manifest blob, then apply the local-edit preflight to <plugin_root>/<id>/. Carry verified bytes over the fleet transport, reverify them on the host, and write them. Run npm ci and the package's check script (or typecheck when it has no check) on the host. A failure stops that plugin on that host. Leave node_modules out of the preflight and the hash comparison.
  2. Install on the daemon. Only for IDs in install. Read the running daemon's version with paseo daemon status --json (daemonVersion) on the host, not the CLI version, and require it to satisfy the plugin's paseo pin from the manifest; a daemon outside the pin is a blocker, not a reason to edit the pin. Raise a pin only in a published package change after live verification against the new Paseo version. Read the root pluginsEnabled in the daemon's <PASEO_HOME>/config.json; missing means false. If it is not true, stop and follow the paseo-plugin skill: the user must explicitly allow trusted plugins on that daemon before anything is enabled. Otherwise run paseo plugin install <plugin_root>/<id> on the host, or paseo plugin reload <id> when it is already installed from that directory.
  3. Confirm. Require paseo plugin ls on the host to report the plugin running and enabled, and read paseo plugin logs <id> for load errors.

The plugins step (scripts/plugins_sync.py) implements these steps. It records, per staged directory in the host's loadout/plugins-sync.json (the config directory from Fleet), the source it last checked with the result, and separately the source the daemon was last confirmed running. It skips npm ci and the check only when staged source is unchanged, node_modules exists, and a passed check is recorded for that source; a failed, missing, or outdated record runs the check again. A passed check is not an activation: an installed plugin is reloaded unless the record shows the daemon confirmed running this exact source. Before it installs, reloads, or migrates, the step records the reload as owed, and it clears that only after the plugin is confirmed running, so a failed reload, a daemon gate, or a lost connection leaves the reload owed and the next run performs it, reported as reloaded (reload owed: <why>). A host with no activation recorded, including the first run after this record was added, reloads each installed plugin once: paseo plugin ls does not show which source a daemon loaded, so a match cannot be proven. A file that an earlier publication had and the current one does not is deleted from <plugin_root>/<id>/ only while it still matches a published version; an edited copy is a conflict. The daemon checks run between the preflight and the writes, so each staged write and removal checks its file again right before it: a removal first moves the file aside and verifies it, and a file edited meanwhile is kept and fails the host. Files never published there, such as node_modules, are left alone. --dry-run shows the checks that would run again and the files that would be removed. It reports blocked when a daemon gate fails, and drift for a plugin_root: null host whose installed source differs.

Never write plugin settings, plugin state, or pluginsEnabled as part of a sync, and never arm a plugin, with one exception below. A plugin with an armed setting starts in dry-run when its settings file is absent; a plugin without one acts as soon as it runs, so read its README before listing it in install. Preserve every existing settings file. A host with plugin_root: null manages its plugins elsewhere: report whether its installed source matches the manifest and change nothing. Report staged, installed, running, blocked, and unreachable plugins per host.

To move a plugin that is installed from another directory to plugin_root (for example after changing plugin_root), the sync reports blocked: installed from <path> until you pass --migrate-path to sync.py or plugins_sync.py. Dry-run it first. paseo plugin remove deletes <PASEO_HOME>/plugin-settings/<id>, which would lose the plugin's arming, so for each such plugin the migration copies that directory to <PASEO_HOME>/plugin-settings.bak-loadout-<stamp>/<id> and verifies the copy, runs paseo plugin remove and paseo plugin install <plugin_root>/<id>, restores the host's own settings byte for byte (also when the install fails), verifies every hash, reloads the plugin, and confirms it is running. It writes back only the bytes it backed up, never new settings. A disabled plugin is left alone. The backup is kept. By hand the procedure is the same: back up the settings directory, remove, sync, restore, paseo plugin reload <id>.

Paseo provider pickers

For hosts whose sync includes providers, the providers step (scripts/paseo_providers.py) merges the pinned provider rows in <fleet>/paseo-providers.json into <PASEO_HOME>/config.json (default ~/.paseo/config.json) on each host whose sync includes providers, then reloads that daemon. It keeps every other provider and host-local field, backs the file up in place as config.json.bak-loadout-<stamp>-<random> (created new, never overwriting an earlier backup), and checks that the picker labels read back exactly as pinned. It replaces the file only while it still holds the revision the merge read: a change another writer (the daemon, an editor) made in the meantime is read again and merged, never overwritten, and the backup holds the revision actually replaced; a file that keeps changing is left alone and the host fails. The config, the merged rows, and required_env are all checked before anything on the host changes, including the Pi runtime. Optional launch settings route only Paseo-launched Claude Code and Codex: the launcher reads a host-local token file into the child env at launch time and adds leading args such as Codex -c model_provider=..., so terminal sessions keep the user's own login (see fleet/README.md).

  • The source host runs locally. ssh hosts run the merge over SSH and reload over SSH, or over their paseo_offer when set. paseo-relay hosts run it in a temporary Paseo workspace terminal (allow up to two minutes) and reload over the relay. A new relay terminal drops input sent before its shell is up, so the step waits for a prompt, then a three-second settle, then sends. If no prompt appears within 30 seconds, nothing is sent: the host's write fails with a readiness timeout and the workspace is cleaned up. If the command never shows up in the terminal (no echo, so it cannot have run), it resends once. Every exit path, including timeouts, failed creates, and SIGTERM, archives all loadout-provider-sync workspaces on the host and confirms none remain; leftovers from a killed run are swept before starting. Inherited Paseo variables (PASEO_HOST, PASEO_HOME, PASEO_AGENT_ID, PASEO_AGENT_CWD) are removed from every local, SSH, and relay call, so a host's write and reload address its own daemon, never one an agent session or scratch daemon named. The merge reads the host's paseo_home (or the default home), the source host and ssh hosts reload that home's daemon, and a relay call adds only that host's own offer as PASEO_HOST.
  • The merge program travels gzip and base64 encoded. Local and SSH execution read a SHA256-verified envelope on stdin, keeping the command short even on cmd.exe. Relay commands up to 4,000 characters keep the inline path; larger payloads use acknowledged 2,000-character chunks in a private temporary file, with idempotent offset writes for a lost-input resend. The final short command verifies SHA256 before merging and unlinks the staging file before execution; failure cleanup also removes it. Each relay command has its own bounded wait, rather than one oversized input call. Hosts need node; relay hosts need a POSIX shell and dd. A dry run does not change configuration or reload, but relay transport can create temporary staging files and workspaces.
  • Each host reports the write and the reload on separate lines. A relay reload can time out after a successful write; report that as a reload failure, not a failed write, and do not undo the write. A write that may have changed the config or a Pi runtime file (including one whose result never came back, and a Pi runtime configuration that failed partway) leaves a reload owed to that host, recorded on the source host in loadout/provider-reloads.json beside the config fleet directory until a reload succeeds. The record keeps, per host, the id of every operation that may owe a reload. One provider operation runs per host at a time, from before its write to after its reload: a run adds its own id, marked running, before writing and keeps it running until its final record update after the reload decision, and a run that finds an id still running on that host writes nothing and fails that host (another provider sync is in flight). The final update removes the run's id after a successful reload or a write that changed nothing, and otherwise keeps it, marked ended with the time; a write whose result never came back (an error, a timeout, or no result) may still land, so its id is kept as uncertain with the time it failed. A successful reload also removes the other debts whose write ended before that reload started: an uncertain one only when the reload started more than twice the write timeout (10 minutes) after it failed, and never a running one or one that ended after the reload started. A reload failure after a write that changed nothing is only a warning when the record, read at that moment, holds no id but the run's own. An id still marked running a day later was left by a killed run and counts as ended. The host owes a reload while it has any id. Every change to the record is a short transaction, never held across a write or a reload, under an OS lock (flock on POSIX, msvcrt.locking on Windows) on provider-reloads.json.lock beside it. That file is never deleted, and the OS drops the lock when its holder exits, so a crashed sync never leaves it held; a run waits up to 15 seconds for another sync to release it. Any record error, a lock timeout or a failed release included, fails that host only, saying whether the write and the reload ran and that a reload may still be owed, and the next host still syncs. The next run retries an owed reload even when the config is unchanged, reports it as reload (owed since <stamp>), and a retry that fails again is FAILED; --dry-run shows the owed reload as would update. When the write was unchanged and no reload is owed, a reload failure is only a warning and the host stays same. A relay workspace that cannot be archived after the merge ran is a cleanup warning after the write line; the reload still runs, and the next run archives the workspace.
  • Never put the catalog, router URLs, or offers in this repository.

Pi providers use the same fleet rows, generated during this step. See the Pi surface format. Install the pinned package with the reviewed host-specific apply script before syncing its runtime. A provider model default does not select a provider in every UI client; carry client preferences separately using the documented script.

Client config

For hosts whose sync includes client-config, the client-config step (scripts/client_config.py) writes only the managed Codex config.toml and Claude Code settings.json keys from <fleet>/client-config.json, and removes only the keys it lists in removeTop and removeEnv (on a host with the providers scope, only once that host's current provider settings are written and reloaded; until then they stay and the host reports held), backing up each changed file first under a new name and replacing it only while it still holds the revision the merge read (an optimistic check, retried once on a concurrent change, that narrows the window but cannot close it). A Codex file with a construct that could define, shadow, or duplicate a managed key path, or a result with a managed key duplicated or outside its table, is refused with nothing written as unsupported TOML, edit by hand (see fleet/README.md). The source host runs locally and other hosts over SSH. A secret from token_file travels only on SSH stdin and is never printed. Report each client per host, the host-local reportOnly values, and the Claude Code version against minVersion.

Fleet client-config.json may also declare generic Streamable HTTP mcpServers, with one URL, bearer token env name, optional envFile (an owner-only file, on Windows too), and explicit per-host enable map; every listed host needs both the client-config and providers scopes. The providers step installs the launcher that reads each env file and includes native HTTP servers in the generated Pi home; client-config writes Codex MCP tables, Claude user-scope ~/.claude.json, and the configured Pi MCP file, and needs that launcher installed first. Only Codex gets the bearers in its environment, at launch, and its tool shells exclude them; Claude Code and Pi run the launcher's reader at each connection, and every other wrapped harness launches without them. During a rollout, a client whose MCP config still uses ${VAR} keeps them until the first providers run after client-config has moved it, so sync twice. No MCP token value is put in any configuration, and a rotation needs no daemon restart. See fleet MCP servers for the declaration and standalone launch command. Always dry-run both providers and client-config before an approved rollout.

Local-edit protection

The skills step (scripts/skills_sync.py) implements this for skills and global instructions. It reads blobs from source_commit, treats every version in the committed MANIFEST.json history as a verified prior publication, and records the global-instruction hashes it installed in each host's loadout/global-sync.json, under the config directory from Fleet. Overlay files use the hashes recorded in the overlay's .loadout-overlay.json, plus the published history of the same install path, as their verified prior versions; a hash is recorded there only after a host with a present client accepts it, as one transaction under an OS lock on .loadout-overlay.json.lock beside it (waiting up to 15 seconds for another sync), written whole through a temp file. A host also accepts the version its record shows the sync last installed at that path, and a version a run recorded as pending: before it writes anything, a run records in global-sync.json each version it is about to write, so a run or controller cut off part way does not turn its own writes into conflicts. It skips each host's exclude_skills.

The same global-sync.json lists every skill file the sync installed or found current, per client skill directory. A skill in that record that is no longer published, in the overlay, or excluded on the host is retired: removed while every file in it is one the sync recorded, unedited. Immediately before removal its ancestors, tree, file types, and recorded hashes are checked again; a skill that changed since the preflight, or cannot be verified again, is kept and reported as kept with the reason. A skill with any other file or edit is reported, kept, and dropped from the record, so the sync stops managing it. A skill the record does not list is never touched, and a run narrowed with --skills retires nothing. --dry-run lists what would be retired and kept. On a host with a configured Loadout Pi, a run that retires a skill also prints one line for that host listing each Pi agent whose <runtime-root>/agents/<agent id>/settings.overlay.json names it in skillsExclude. It only reports: those entries are harmless, because the Pi launcher skips an unknown skillsExclude name with a one-line warning, and the sync never writes under agents/. When hosts.json sets skills_overlay (see fleet/README.md) and the fleet's skills/ overlay is missing or not a directory, it is not read as an empty overlay: no host retires anything, every host keeps its record and reports blocked with the reason, and installs still run. Restore the overlay, or leave an empty skills/ directory to retire its skills on purpose. Without skills_overlay, retirement runs as before.

Preflight every selected destination before writing any file on that host. Reject escaping or duplicate paths, paths that are not portable (a backslash, colon, control character, trailing dot or space, or a Windows device name) or that would name one file on a case-insensitive host, symlink or junction ancestors (from the home directory down, for a destination inside it), unexpected file types, and hash mismatches. An existing file may be replaced only if it matches a verified prior publication of the same source path or the desired blob. Preserve unknown local edits and stop the host without a partial package update. Leave unselected files untouched.

After a successful preflight, write verified bytes, verify every installed hash, and run the available package validators. A preflight is not a lock: each write checks its directories and its file again right before it, and a file that changed meanwhile is not written over and fails the host. Report selected packages, commit IDs, destinations, files written, files already current, skipped clients, and blockers. A host without its own checkout may receive verified bytes from another eligible checkout, but must reverify them before the same preflight and write.

Publishing a package change

This covers skills and plugins. Commit package content first. Generate the manifest from that committed tree with source_commit equal to the content commit, then commit the manifest separately. Verify that the complete active skills/ and plugins/ trees match manifest paths, byte counts, and SHA256 values. Review the diff before publishing. The public repository has its own clean history; do not import another repository's history or machine-local state.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.