Introduction
Sync AI coding skills across tools. Import skills from native tool plugins, standalone directories, and shared Git repositories, then route portable skills to selected destinations by shared tags.
Why
AI coding tools (Claude Code, Codex, Antigravity) each use SKILL.md packages to provide context. But skills get siloed:
- Plugin skills live in cache directories you never see
- Standalone skills only exist for one tool
- Switching tools means losing access to your skill library
tome consolidates all skills into a single library and owns the desired skill state and cross-tool routing. Native plugins remain tool-specific installation adapters rather than becoming a universal plugin format.
Install
Homebrew (macOS/Linux):
brew install MartinP7r/tap/tome
Quick Start
# Interactive setup — discovers sources, configures targets
tome init
# Sync the library and apply configured destination routes
tome sync
# Check what's configured
tome status
How It Works
Tome combines shared repository policy, a selected machine profile, the nearest
project .tome.toml, and local runtime settings. Shared Git sources live in
repository policy; machine-wide directories and routes live in
machines/<profile>.toml; project-only destinations and routes are discovered
by searching upward from the current directory.
graph LR
subgraph Sources["Sources (roles: Managed / Synced / Source)"]
S1["<b>claude-plugins</b><br/>type: claude-plugins<br/>~/.claude/plugins"]
S2["<b>claude-skills</b><br/>type: directory<br/>~/.claude/skills"]
S3["<b>team-skills</b><br/>type: git<br/>github.com/org/skills"]
end
subgraph Library["Library — ~/.tome/skills"]
L["Consolidated skill library<br/>manifest tags + real-directory copies"]
end
subgraph Targets["Targets (roles: Synced / Target)"]
T1["<b>codex</b><br/>~/.codex/skills"]
T2["<b>antigravity</b><br/>~/.gemini/antigravity/skills"]
T3["<b>cursor</b><br/>~/.cursor/skills"]
end
S1 --> L
S2 --> L
S3 --> L
L -->|"matching route tag"| T1
L -->|"matching route tag"| T2
L -->|"matching route tag"| T3
- Reconcile — Diff managed-plugin state against the lockfile; with
managed_plugin_installconsent from localsettings.toml, apply install/update operations through the native tool adapter before discovery - Discover — Scan every configured directory (types:
claude-plugins,directory,git) for*/SKILL.mdsubdirs - Consolidate — Copy every skill — managed AND local — into
~/.tome/skillsas a real directory (library-canonical model, v0.10+). First-seen-wins on name conflicts. Themanagedflag denotes update channel, not storage form - Distribute — Create symlinks when any skill tag matches the destination route; explicit destination exclusions override matches, and untagged skills stay library-only for routed destinations
- Cleanup — Remove stale entries and broken symlinks from both library and distribution dirs; orphaned managed skills transition to Unowned (v0.14+) with library content preserved
Tags are stored with library entries in .tome-manifest.json; sources retain
provenance but do not choose destinations. See Configuration
and Architecture for the complete model.
License
MIT
Feature List
This page inventories the current CLI behavior. Desktop remains outside this CLI release scope.
Shared Library and Sync
Tome consolidates skills into one canonical library and distributes selected portable skills through Unix symlinks.
| Capability | Current behavior |
|---|---|
| Discovery | Reads native plugin caches, ordinary directories, and shared Git repositories |
| Canonical storage | Stores managed and local skills as real directory copies |
| Provenance | Tracks source ownership and content hashes in .tome-manifest.json and tome.lock |
| Classification | Stores shared user-managed tags on each manifest skill |
| Distribution | Routes skills to destinations by OR-matching manifest tags |
| Exceptions | A per-destination skill exclusion overrides a matching tag |
| Conflict handling | Shared exclusions and source pins resolve pool membership |
Native tool plugins remain tool-specific installation adapters. Tome tracks the
desired plugin and skill state, reconciles through those adapters when local
consent permits, and routes portable library copies to tools that consume
SKILL.md packages.
Layered Configuration
Normal commands resolve four layers:
| Layer | Purpose |
|---|---|
tome.toml | Shared repository policy, Git sources, library path, exclusions, and source pins |
machines/<profile>.toml | Selected profile’s machine-wide sources, destinations, and routes |
Nearest .tome.toml | Additive project-only destinations and routes, discovered upward from the working directory |
~/.config/tome/settings.toml | Active profile and local Git, plugin-install, and backup consent |
Invalid project configuration fails explicitly. Project configuration cannot
define sources or replace profile destinations. Released commands do not read
or write machine.toml, and the CLI has no --machine option.
Tag Routing
Sources determine library membership and provenance, not distribution. New
skills enter the manifest with no tags. Use tome tag to classify them and
tome route to select tags for a destination.
tome tag add rust-cli coding
tome tag add rust-cli portable
tome route tag add --to codex coding
tome route exclude add --to codex claude-only-skill
A configured route uses OR matching, so either coding or portable can
select a skill when both tags appear in the route. Untagged skills stay in the
library but are not linked into routed destinations. Destinations without a
route retain unrestricted legacy distribution behavior.
Sync Pipeline
| Stage | What it does |
|---|---|
| Reconcile | Compares managed state with tome.lock and invokes native adapters when consent permits |
| Discover | Scans shared Git sources and selected-profile directory sources |
| Consolidate | Copies skills into the canonical library while preserving manifest tags |
| Distribute | Applies destination routes, explicit exclusions, and existing origin safety checks |
| Cleanup | Removes stale Tome-owned links, including links that become unrouted |
| Lockfile | Writes reproducible provenance state for the next reconciliation |
Command Surface
Setup and inspection
| Command | Current feature |
|---|---|
tome init | Interactive setup |
tome profile create|list|select | Manage committed profiles and local selection |
tome sync | Resolve layers and run the full sync pipeline |
tome status | Show the selected profile, effective directories, library health, and last sync |
tome config | Show effective configuration or its shared-policy path |
tome list | List discovered skills; supports JSON output |
tome browse | Browse skills with fuzzy search and markdown preview |
tome --version | Print the version through Clap’s standard flag |
Sources, tags, and routes
| Command | Current feature |
|---|---|
tome add <git-url> | Add a repository-owned Git source; no --to or --role |
tome add <path> [--role] | Add a local directory to the selected profile |
tome tag add|remove|list | Manage tags stored in the shared manifest |
tome route tag add|remove | Manage destination tag selectors in the owning profile or project |
tome route exclude add|remove | Manage explicit per-destination skill exclusions |
tome pool exclude|restore | Remove a skill from shared discovery or restore it |
Library lifecycle and recovery
| Command | Current feature |
|---|---|
tome remove dir <name> | Remove a configured directory and preserve its skills as Unowned |
tome remove skill <name> | Delete an Unowned skill from library, manifest, distributions, and lockfile |
tome reassign <skill> --to <dir> | Re-anchor an owned or Unowned skill |
tome fork <skill> --to <dir> | Convert a managed skill into a local editable copy |
tome doctor | Diagnose and safely repair supported library and destination problems |
tome lint [path] | Validate SKILL.md frontmatter in text or JSON form |
tome relocate <path> | Move the library and repair downstream links |
tome eject | Remove Tome-owned distribution symlinks without deleting the library |
tome backup ... | Create, list, diff, and restore Git-backed library snapshots |
tome completions <shell> | Install or print shell completions |
The obsolete tome migrate-library, tome version, and tome remove pool
commands are not part of the current CLI.
Safety and Operability
- Checked atomic writes for repository policy, profiles, project config, local settings, the manifest, and the lockfile.
--dry-runfor state-changing flows and--no-inputfor automation.--no-installand--git-syncone-run consent overrides.- Deterministic SHA-256 hashing for idempotent consolidation.
- Foreign-symlink protection before cleanup removes destination entries.
- Structured JSON output for status, doctor, list, and lint.
tracinglogging through--verbose,--quiet, andTOME_LOG.
Platform Boundary
Tome is Unix-only because distribution uses symlinks. The CLI remains pre-1.0 and does not promise backward compatibility. Desktop code exists in the workspace but is paused and outside this CLI release.
Commands
| Command | Description |
|---|---|
tome init | Interactive wizard to configure directories |
tome sync | Reconcile, discover, consolidate, distribute, and clean up skills |
tome add <url|path> | Register a shared Git source or a local directory in the selected profile |
tome tag add|remove|list | Manage shared tags on manifest skills |
tome route tag add|remove | Manage tag selectors for a destination |
tome route exclude add|remove | Manage explicit per-destination skill exclusions |
tome profile create|list|select | Manage committed machine profiles |
tome paperclip-agents preview|apply | Preview and synchronize resolved use-case skill sets to Paperclip agents |
tome pool exclude|restore | Exclude a skill from shared discovery or restore it |
tome remove dir <name> | Remove a directory entry (manifest entries transition to Unowned per LIB-04) |
tome remove skill <name> | Delete an Unowned skill from the library, manifest, distributions, and lockfile |
tome reassign <skill> --to <directory> | Reassign a skill to a different directory (accepts Owned + Unowned input per UNOWN-01) |
tome fork <skill> --to <local-directory> | Fork a managed skill to a local directory for customization |
tome status | Show library, directories, last-sync, and health summary |
tome list (alias: ls) | List all discovered skills with their directories (supports --json) |
tome browse | Interactively browse discovered skills with fuzzy search |
tome doctor | Diagnose and repair broken symlinks or config issues |
tome lint | Validate skill frontmatter and report issues |
tome config | Show current configuration |
tome backup | Git-backed backup and restore for the skill library |
tome eject | Remove tome’s symlinks from all distribution directories (reversible via tome sync) |
tome relocate <path> | Move the skill library to a new location |
tome completions <shell> | Install shell completions (bash, zsh, fish, powershell) |
tome --version | Print version information through Clap’s standard version flag |
Global Flags
| Flag | Short | Description |
|---|---|---|
--config <path> | Path to config file (default: ~/.tome/tome.toml) | |
--tome-home <path> | Override tome home directory (default: ~/.tome/, or TOME_HOME env var) | |
--settings <path> | Path to local profile selection and runtime settings (default: ~/.config/tome/settings.toml) | |
--dry-run | Preview changes without modifying filesystem | |
--no-input | Disable all interactive prompts (implies --no-triage for sync) | |
--verbose | -v | Detailed output |
--quiet | -q | Suppress non-error output (conflicts with --verbose) |
Command Details
tome init
When using the default Tome home, interactive setup first offers Tome data
folder selection. This portable root determines configuration lookup, cached
repositories, the lockfile, and the default library location. Existing
configuration is detected in the selected folder before setup continues, and
the same folder is used for saving configuration and the post-init sync. A
custom library may live elsewhere; local settings remain under
~/.config/tome.
Interactive init also offers Tome’s official using-tome agent skill, defaults
to yes, and displays the equivalent command:
tome add MartinP7r/tome --subdir skills
Accepting registers MartinP7r/tome as a Git/source directory with
subdir = "skills"; the post-init sync clones it immediately. --no-input
omits this recommendation and performs no new network request for the official
repository.
tome sync
Runs the full pipeline: resolve repository, profile, project, and local-settings
layers; discover and consolidate skills; diff the lockfile; distribute through
destination tag routes; and clean up stale entries. Generates tome.lock for
reproducible provenance snapshots. Use tome tag and tome route to classify
and route newly imported skills.
| Flag | Short | Description |
|---|---|---|
--force | -f | Recreate all symlinks even if they appear up-to-date |
--no-triage | Skip interactive triage of new/changed skills (for CI/scripts) |
tome add
Register a Git skill repository in shared repository policy or an explicit
local directory in the selected profile. Git sources are discovery-only and
do not select destinations: tome add has no --to flag. Git inputs also
reject --role; local paths continue to accept it.
Git inputs accept either a full URL (https://github.com/owner/repo,
git@github.com:owner/repo.git) or a bare GitHub slug (owner/repo), which is
expanded to https://github.com/owner/repo (v0.8.2+). The clone is shallow and
lives in ~/.tome/repos/<sha256>/.
Git forms
tome add https://github.com/user/skills # full HTTPS URL
tome add user/skills # bare slug → github.com
tome add git@github.com:user/skills.git # SSH URL
tome add user/skills/tree/main/skills # /tree/<ref>/<subdir> shortcut (v0.13+)
tome add user/skills --subdir skills # explicit --subdir flag (v0.13+)
The /tree/<ref>/<subdir> URL form mimics how GitHub renders navigation into a subdirectory in your browser — copy-paste from github.com/owner/repo/tree/main/skills and it just works. Extracted <ref> becomes the default branch; <subdir> becomes the discovery subdirectory. Explicit --branch / --subdir flags override URL-embedded values (with a warning).
Local path forms
Explicit local paths may be absolute, tilde-prefixed (~ or ~/...), or
dot-relative (., .., ./..., or ../...). Bare owner/repo inputs remain
GitHub slugs even if a matching path exists. The default name is the path’s
final component, and local directories default to role synced. Dot-relative
inputs are resolved lexically against the tome add working directory and
do not depend on later commands’ working directories. Checked save serializes
anchored paths outside home as absolute paths and may serialize paths under home
as portable ~/...; both resolve to the same add-time location. Anchoring does
not require the source to exist, canonicalize it, or resolve symlinks. Explicit
~/... inputs retain the same portable behavior.
tome add ~/.pfw/skills --role managed
tome add ./team-skills --role source --name team
Git-only --branch, --tag, --rev, and --subdir flags are rejected for
local paths.
Auto-detection of common subdirs (v0.13+)
If tome sync finds zero skills at a directory’s root AND no subdir is configured, it probes common Claude Code plugin layouts (skills/, .claude-plugin/skills/) and emits a subdir = "..." hint if any candidate has skills inside. Catches the “I added a Claude plugin repo and got zero skills” case without forcing the user to know the convention up front.
Flags
| Flag | Description |
|---|---|
URL_OR_PATH | Git repository URL, owner/repo slug, or explicit local path |
--name <name> | Custom directory name (default: derived from the URL or local path) |
--branch <branch> | Track a specific branch (overrides URL-embedded /tree/<ref>/...) |
--tag <tag> | Pin to a specific tag |
--rev <sha> | Pin to a specific commit SHA |
--subdir <path> | Restrict discovery to <clone>/<path>/*/SKILL.md (v0.13+, overrides URL-embedded subdir) |
--role <role> | Override the type-default role for local paths only; rejected for Git inputs |
--branch, --tag, --rev are mutually exclusive.
Choosing the right role (v0.14+)
The role field decides what tome does with a configured directory:
| Role | Behavior |
|---|---|
managed | Read-only upstream (package manager owns content). Discovery only. |
synced | Both discovery AND distribution — skills found here are pulled into the library, and distribution symlinks are also written back into this dir. |
source | Discovery only. tome reads but never writes here. |
target | Distribution only. tome writes symlinks here but doesn’t scan for skills. |
The defaults bite if you don’t know them. When you omit --role, the directory’s role falls back to its type default:
claude-plugins→manageddirectory→syncedgit→source
The directory → synced default is the one that surprises people. If you tome add a local directory owned by a package manager (e.g. ~/.pfw/skills/), the synced default writes ~170 distribution symlinks INTO that source directory — polluting it with content tome propagated from other configured directories. Use --role source or --role managed for read-only package manager directories to keep them clean.
# WRONG (default role = synced; tome writes BACK into ~/.pfw/skills/)
tome add ~/.pfw/skills
# OK — discovery only, no write-back, but library entries get
# `managed: false` (treated as a generic local source).
tome add ~/.pfw/skills --role source
# BEST (v0.15+) — Managed semantic: library entries get `managed: true`,
# so reconcile + foreign-symlink protection recognize this as an
# external-package-manager-owned source.
tome add ~/.pfw/skills --role managed
source vs managed for flat-directory package managers (v0.15+)
Both refuse to write back into the source dir, so either keeps ~/.pfw/skills/ clean. The differences are subtle but material if you care about upstream-update semantics down the line:
| Aspect | source | managed |
|---|---|---|
| tome writes to the source dir | Never | Never |
Manifest managed: bool flag | false (local skill) | true (package-manager-owned) |
Future reconcile / MarketplaceAdapter integration | Not eligible | Eligible (when adapters are added per upstream) |
| Foreign-symlink protection treats source path as legitimate-origin | Not yet | Not yet (separate follow-up) |
| Semantic accuracy for pfw / npm / etc. | “It’s just a local source” | “It’s owned by a specific package manager” |
For today’s needs (just propagating pfw skills to your other tools), both work equivalently. For longer-term integration with pfw’s own update lifecycle, prefer managed.
The success message now echoes the resolved role so you see what you got:
✓ Added directory 'pfw' (git: https://..., role: source)
→ Source (skills discovered here, not distributed here)
tome tag
Tags are shared library metadata stored in .tome-manifest.json:
tome tag add <skill> <tag>
tome tag remove <skill> <tag>
tome tag list [<skill>]
Tag mutation requires an existing manifest skill. New tags affect routing only after a destination selects them.
tome route
Routes belong to the active profile or to the nearest project .tome.toml that
owns the destination:
tome route tag add --to <destination> <tag>
tome route tag remove --to <destination> <tag>
tome route exclude add --to <destination> <skill>
tome route exclude remove --to <destination> <skill>
Selected tags use OR matching. An explicit exclusion wins over a matching tag. Untagged skills stay library-only for destinations with configured routes.
tome profile
tome profile create <name> creates machines/<name>.toml, tome profile list lists profiles, and tome profile select <name> records the active
profile in local settings.toml.
tome paperclip-agents
Explicitly materializes versioned catalog categories/use-case sets into
Paperclip agents’ desired company-skill assignments. This is separate from
generic tome sync target deployment: copy deployment never mutates Paperclip
agents.
preview resolves one canonical catalog revision plus the selected effective
constraints, reads current desired/runtime state from either a disposable state
file or the Paperclip API, and renders one fleet-wide before/after impact. It
does not mutate the canonical library or any Paperclip agent.
When reading live Paperclip state, Tome first uses the read-only company skill
attachment route (GET /api/companies/{companyId}/skills/{skillId}) and derives
each agent’s current desired skills from usedByAgents[].desired. Runtime state
is optional and may be unavailable on that route. The mutating
POST /api/agents/{agentId}/skills/sync endpoint is used only by apply.
tome paperclip-agents preview \
--catalog catalog.toml \
--assignments agents.toml \
--current-state state.json \
--constraint paperclip-agent
apply recomputes the same plan, requires the preview confirmation token, uses
Paperclip’s desired-skill sync endpoint in replace mode, then reads every
affected agent back and fails if desired/runtime state differs from the
intended set. The API URL is read from --paperclip-api-url or
PAPERCLIP_API_URL; the token is read from PAPERCLIP_API_KEY by default.
tome paperclip-agents apply \
--catalog catalog.toml \
--assignments agents.toml \
--constraint paperclip-agent \
--confirm apply-abc123def456
Catalog TOML is intentionally small and deterministic:
revision = "catalog-2026-10-02"
[categories.engineering]
description = "Engineering work"
[skills.using-tome]
company_skill = "using-tome"
categories = ["engineering"]
constraints = ["paperclip-agent"]
[use_case_sets.founding-engineer]
categories = ["engineering"]
constraints = ["paperclip-agent"]
Assignment TOML selects sets per agent:
[[agents]]
agent_id = "agent-id"
display_name = "FoundingEngineer"
sets = ["founding-engineer"]
constraints = ["codex"]
tome pool
tome pool exclude <skill> adds a shared discovery exclusion to repository
policy. tome pool restore <skill> removes that exclusion. Pool conflict
resolution also exposes accept-source and retain-current; there is no
tome remove pool compatibility command.
tome remove
Split into two subcommands since v0.10 (Phase 14, D-API-2):
tome remove dir <name>
Remove a configured directory entry from its owning repository policy or
selected profile. Manifest entries owned by that directory transition to
Unowned (per LIB-04): library content is preserved and only the
source_name linkage is cleared. Partial cleanup failures produce a non-zero
summary. For Git directories, the cached clone in
~/.tome/repos/<sha256>/ is removed.
| Flag | Description |
|---|---|
NAME | Directory name to remove (as shown in tome status) |
--yes / -y | Skip confirmation prompt |
tome remove skill <name>
Delete an Unowned skill from the library entirely: clear the manifest entry,
remove the library directory, remove downstream distribution symlinks, and
remove the lockfile entry. Refuses to operate on Owned skills with a hint to
run tome remove dir first (per D-B2).
| Flag | Description |
|---|---|
NAME | Skill name to delete |
--yes / -y | Skip confirmation prompt (default: no) |
tome reassign
Reassign a skill to a different directory — useful when the same skill appears under multiple sources and you want to pin which directory owns it. Accepts both Owned skills (re-anchor between configured directories) and Unowned skills (re-anchor a previously-stranded skill back to a configured directory, per UNOWN-01 / D-API-1).
| Flag | Description |
|---|---|
SKILL | Skill name to reassign |
--to <directory> | Target directory name (required) |
--force | Overwrite if the target already has a different-content skill of the same name (per D-A1) |
tome fork
Fork a managed (read-only) skill into a local directory so it can be edited. The local copy supersedes the managed one in the library.
| Flag | Description |
|---|---|
SKILL | Skill name to fork |
--to <local-directory> | Target local directory name (required) |
--yes | Skip confirmation prompt |
tome list
| Flag | Description |
|---|---|
--json | Output as JSON |
tome browse
Full-screen interactive skill browser using fuzzy search. Supports sorting,
grouping by source, viewing source, and copying paths. Destination-ambiguous
disable actions are unavailable; use tome route exclude add --to <destination> <skill> explicitly.
tome doctor
Diagnose library state. When run interactively (no --no-input, no --dry-run), surfaces issues and offers per-category repair prompts.
Orphan-directory repair (v0.14+)
When tome doctor finds a directory in the library that has no matching manifest entry (an “orphan”), it offers four choices per orphan:
claim— Register the orphan in the manifest as an Unowned skill (v0.14+). Hashes the directory and writes aSkillEntry::new_unowned. Assign tags and configure a destination route before expecting routed distribution on the nexttome sync.keep— Leave the directory on disk;tome syncwill re-register it IF it discovers the orphan from a configured source. Useful when you know the orphan’s source got temporarily disconnected and will come back. Note: for library-canonical orphans with no upstream source, this option is a no-op until youclaimit or add a source that covers it.delete— Remove the directory from disk permanently.skip— Leave the orphan as-is; doctor will surface it again on the next run.
Broken-frontmatter skills (v0.16+)
tome doctor walks every manifest-tracked skill and parses its SKILL.md frontmatter. Failures surface as Library Warnings — for example:
! 'my-skill' has unparsable SKILL.md frontmatter: invalid YAML frontmatter
! 'other-skill' has no SKILL.md file
These are not auto-repairable — the user must edit the SKILL.md file (or remove the skill) by hand. Without this check, the failure was only visible as a one-line stderr warning during tome sync; it now persists in the doctor surface so broken skills get triaged. Use tome lint <PATH> for a deeper per-field frontmatter audit.
Real-dir-in-target repair (v0.16+)
If a distribution directory contains a real directory (not a symlink) whose name matches a library skill, tome doctor hash-compares the two:
- Identical content — Surfaces as an auto-fixable Warning (
real directory in target matches library content (should be a symlink)). The auto-repair pass deletes the real directory and replaces it with a symlink into the library. Typical cause: skills copied into the target dir manually before adopting tome, or by hand after the fact. - Diverging content — Surfaces as a no-repair Warning (
real directory in target diverges from library content — reconcile manually). The user must decide whether to overwrite the local edits, fold them back into the library, or remove the target copy. - No matching library skill — Left alone; tome does not own un-paired directories in target dirs.
tome lint
| Flag | Description |
|---|---|
PATH | Specific skill directory to lint (default: entire library) |
--format text|json | Output format (default: text) |
Validates SKILL.md frontmatter: missing/mismatched names, description length, non-standard fields, Unicode tag codepoints. Exits with code 1 on errors (CI-friendly).
tome config
| Flag | Description |
|---|---|
--path | Print config file path only |
Normal commands resolve shared tome.toml, the selected
machines/<profile>.toml, optional project .tome.toml, and local
settings.toml. tome config --path prints the repository-policy path.
tome backup
Git-backed backup and restore. Subcommands:
| Subcommand | Description |
|---|---|
tome backup init | Initialize git repo in the library for backup tracking |
tome backup snapshot [-m MSG] | Create a snapshot of the current library state |
tome backup list [-n COUNT] | Show backup history (default: 10 entries) |
tome backup restore [REF] | Restore library to a previous snapshot (default: HEAD~1) |
tome backup diff [REF] | Show changes since last backup (default: HEAD) |
tome eject
Removes all of tome’s symlinks from distribution directories. Reversible — run tome sync to recreate them.
tome relocate
Moves the skill library to a new path, updating symlinks in all distribution directories. Detects cross-filesystem moves and warns when target symlinks need to be re-anchored.
tome completions
| Flag | Description |
|---|---|
SHELL | Shell to install for: bash, zsh, fish, powershell |
--print | Print completions to stdout instead of installing |
Configuration
Tome resolves four configuration layers. Shared policy and profiles are meant to be version-controlled together; project configuration is scoped to one project tree; local settings stay on the current machine.
| Layer | Default path | Owns |
|---|---|---|
| Repository policy | ~/.tome/tome.toml | Library path, shared Git sources, shared exclusions, backup policy, conflict pins |
| Selected profile | ~/.tome/machines/<profile>.toml | Machine-wide local sources, destinations, and destination routes |
| Project | Nearest ancestor .tome.toml | Additive project-only destinations and routes |
| Local settings | ~/.config/tome/settings.toml | Selected profile and runtime consent |
Released CLI commands do not read or write machine.toml, and there is no
global --machine option. Use --config, --settings, or --tome-home when
the default locations are unsuitable.
Repository Policy
The shared tome.toml is the repository policy:
library_dir = "~/.tome/skills"
exclude = ["deprecated-skill"]
[directories.team-skills]
path = "https://github.com/myorg/team-skills"
type = "git"
role = "source"
branch = "main"
subdir = "skills"
Only Git discovery sources belong in its [directories.<name>] map. A Git
source may use one of branch, tag, or rev, plus an optional subdir.
tome add <git-url> writes this layer. It registers provenance only: Git adds
have no --to routing option and reject --role because their role is always
source.
Top-level repository-policy fields:
| Field | Description |
|---|---|
library_dir | Path to the canonical skill library; supports ~ expansion |
exclude | Shared skill names omitted from discovery; manage with tome pool exclude and tome pool restore |
backup | Shared backup configuration |
source_pins | Persisted conflict choices for duplicate skill sources |
directories | Shared Git sources only |
Machine Profiles
Profiles are committed as machines/<profile>.toml. Select the active profile
with tome profile select <name>; tome profile create and
tome profile list manage the available files.
[directories.claude-plugins]
path = "~/.claude/plugins/cache"
type = "claude-plugins"
role = "managed"
[directories.local-skills]
path = "~/.claude/skills"
type = "directory"
role = "source"
[directories.codex]
path = "~/.codex/skills"
type = "directory"
role = "target"
[routes.codex]
tags = ["portable", "coding"]
exclude = ["claude-only-skill"]
Ordinary directory sources are profile-specific because their paths and tool roles depend on the machine. Each entry combines a type and role:
| Type | Description |
|---|---|
claude-plugins | Reads Claude Code’s installed_plugins.json; role is managed |
directory | Scans a normal directory for */SKILL.md |
git | Reserved for repository policy; shallow-cloned into ~/.tome/repos/<sha256>/ |
| Role | Discovery | Distribution |
|---|---|---|
managed | Yes, read-only upstream | No |
source | Yes | No |
target | No | Yes |
synced | Yes | Yes |
Use tome add <path> [--role <role>] to add an explicit local path to the
selected profile.
Shared Skill Tags
Tags classify individual library skills independently of their source. They
are stored in each .tome-manifest.json skill entry and survive content
updates from the same source. New skills have an empty tag set.
tome tag add rust-cli coding
tome tag add rust-cli portable
tome tag list rust-cli
tome tag remove rust-cli coding
The lockfile remains provenance-only; tags are not copied into tome.lock.
Destination Routes
A [routes.<destination>] table belongs to the same profile or project file as
the destination. Its tags field is an OR selector: a skill is eligible when
at least one manifest tag intersects the selected tags. exclude lists skills
that must not reach this destination even when a tag matches.
[routes.codex]
tags = ["portable", "coding"]
exclude = ["claude-only-skill"]
tome route tag add --to codex portable
tome route tag remove --to codex coding
tome route exclude add --to codex claude-only-skill
tome route exclude remove --to codex claude-only-skill
Untagged skills remain in the library but are not linked into destinations that have a route. A destination without a route retains unrestricted legacy distribution behavior, so define a route for every destination that should use tag-based selection.
Route commands validate that the destination exists in the active profile or nearest project layer. A route tag must already be assigned to a manifest skill, and an excluded skill must exist in the manifest. Checked writes are atomic.
Project Configuration
Starting at the current working directory, Tome searches upward for the
nearest .tome.toml. The project layer is additive and may contain only target
directories and routes owned by those project destinations:
[directories.project-codex]
path = ".codex/skills"
type = "directory"
role = "target"
[routes.project-codex]
tags = ["project", "portable"]
exclude = ["global-only-skill"]
Project configuration cannot define sources, select a profile, replace a
profile destination, or route to an unknown destination. Invalid project TOML
fails the command; Tome does not silently fall back to profile-only behavior.
Running tome route ... inside the project tree updates the project file when
that file owns the named destination.
Local Settings
~/.config/tome/settings.toml selects the active profile and stores local
runtime consent:
profile = "work"
git_sync = "ask"
managed_plugin_install = "ask"
backup_runtime = "ask"
| Field | Values | Description |
|---|---|---|
profile | Profile name | Selects machines/<profile>.toml |
git_sync | always, ask, never | Controls synchronization of the shared Tome repository |
managed_plugin_install | always, ask, never | Controls native adapter install/update actions |
backup_runtime | always, ask, never | Controls local backup runtime behavior |
Native plugin systems remain tool-specific installation adapters. Tome tracks the desired skill and plugin state, invokes an adapter when consent allows, and owns routing of portable library copies to other tools.
Lockfile and Manifest
tome sync writes tome.lock, a reproducible provenance snapshot containing
skill names, content hashes, sources, and upstream metadata. The shared
.tome-manifest.json tracks the current library entry, including its tags.
Both files support a multi-machine repository workflow. tome.lock drives
managed-plugin reconciliation; the manifest’s tags drive destination routing.
Library .gitignore
tome sync maintains the library .gitignore for transient files such as
temporary lockfile writes. The canonical library contains real directory copies
for both managed and local skills.
Cross-machine sync
Tome’s shared repository holds the canonical library, repository policy,
machine profiles, manifest, and lockfile. Each machine keeps only profile
selection and runtime consent in local settings.toml.
Shared and Local State
Commit these shared files together:
| Path | Purpose |
|---|---|
tome.toml | Repository policy, library path, shared Git sources, exclusions, and source pins |
machines/<profile>.toml | Machine-wide directory topology and destination routes |
skills/ | Canonical real-directory copies of managed and local skills |
.tome-manifest.json | Current provenance, content hashes, and shared skill tags |
tome.lock | Reproducible provenance snapshot for managed reconciliation |
Do not commit ~/.config/tome/settings.toml with the shared repository. It
selects the active profile and stores local consent:
profile = "personal-macos"
git_sync = "ask"
managed_plugin_install = "ask"
backup_runtime = "ask"
Released CLI commands do not use machine.toml; there is no --machine
option.
Configure the First Machine
Create repository policy and a profile, then select it locally:
tome init
tome profile create personal-macos
tome profile select personal-macos
Add Git repositories as shared sources. Git registration has no destination
selection and no --to flag:
tome add https://github.com/my-org/my-skills.git
tome add MartinP7r/tome --subdir skills
Add explicit local paths to the selected profile:
tome add ~/.claude/skills --role source
tome add ~/.pfw/skills --role managed
Define profile destinations in machines/personal-macos.toml, then route tags
to them:
[directories.codex]
path = "~/.codex/skills"
type = "directory"
role = "target"
[routes.codex]
tags = ["portable", "coding"]
exclude = ["claude-only-skill"]
Sync once to import skills, classify them, and sync again to distribute:
tome sync
tome tag add using-tome portable
tome tag add rust-cli coding
tome route tag add --to codex portable
tome sync
Tags are shared manifest state. Source provenance does not decide routing. A routed destination receives a skill when any selected tag matches, unless that skill appears in the destination’s explicit exclusion list. New upstream skills arrive untagged and stay library-only for routed destinations until classified.
Commit the shared repository after reviewing the result:
git add tome.toml machines skills .tome-manifest.json tome.lock
git commit -m "Update Tome library"
git push
Bootstrap Another Machine
Install Tome, clone the shared repository into the location used as Tome home, and select a profile in local settings:
brew install MartinP7r/tap/tome
git clone git@github.com:you/your-tome-repository.git ~/.tome
tome profile select work-linux
tome status
tome sync --dry-run --no-install
tome sync
The selected machines/work-linux.toml can use Linux-specific paths while
sharing the same repository-owned Git sources, library tags, and lockfile. Use
separate committed profiles when machines need different paths or destinations.
git_sync controls whether Tome synchronizes the shared repository:
| Value | Behavior |
|---|---|
always | Pull shared state before sync and publish successful changes |
ask | Request consent before repository synchronization |
never | Leave Git operations to the user |
For one sync, tome sync --git-sync <always|ask|never> overrides the local
setting without changing it.
Project Destinations
A project may commit .tome.toml at its root to add destinations used only
inside that project tree:
[directories.project-codex]
path = ".codex/skills"
type = "directory"
role = "target"
[routes.project-codex]
tags = ["project", "portable"]
exclude = ["global-only-skill"]
Tome searches upward from the command’s working directory and uses the nearest
.tome.toml. This layer is additive: it cannot add sources, replace profile
destinations, or select a profile. Invalid project configuration fails instead
of falling back silently.
Native Plugin Reconciliation
Native plugins remain installed and updated through each tool’s own adapter.
Tome owns the desired state represented by the shared library and lockfile, but
does not turn those plugins into a cross-tool plugin format. Portable skills
copied into the library can be routed to other SKILL.md destinations.
managed_plugin_install controls adapter actions:
managed_plugin_install = "always" # apply without prompting
managed_plugin_install = "ask" # ask when reconciliation needs an action
managed_plugin_install = "never" # report drift without installing
tome sync --no-install forces no adapter installs for one invocation and
does not alter local settings.
Lockfile Semantics
Each tome.lock entry records the skill name, content hash, source, previous
source, version, registry identity, and Git commit when available. The lockfile
is provenance-only; shared routing tags live in .tome-manifest.json.
Reconciliation compares content hashes rather than treating a display version as a complete pin. If a native adapter is unavailable, Tome reports the adapter error. A vanished plugin can continue using its preserved canonical library copy.
Routing Changes Across Machines
Tag changes are shared immediately through the manifest. Route changes are shared through the profile or project file that owns the destination. On the next sync, Tome creates newly eligible links and removes stale Tome-owned links that no longer match. Foreign symlinks remain untouched.
Use explicit exclusions for one destination:
tome route exclude add --to codex claude-only-skill
tome route exclude remove --to codex claude-only-skill
Use shared pool exclusions only when a skill should not enter the library at all:
tome pool exclude unwanted-skill
tome pool restore unwanted-skill
Skill-organization architecture
Status: Recommended direction from MCO-144. This document is a decision and execution guide, not a claim that every proposed capability is already shipped.
Goal
Tome should organize Martin’s AI-agent skills across machines and projects without losing provenance, silently changing canonical content, or installing a skill where it does not belong.
The system has four separate questions:
- Pool: Which skills exist in the canonical collection, and where did they come from?
- Curation: What domain(s), capabilities, constraints, overlaps, gaps, and local customizations apply to each skill?
- Deployment: Which machine and project destinations should receive a curated skill?
- Evidence: Is a skill structurally valid and does it demonstrably improve a task?
Keeping these questions separate is the architectural guardrail. Evaluation is important evidence for curation, but it is not the product’s primary purpose.
Current state and evidence
Tome already implements most of the right storage boundary:
library.rsstores both managed and local skills as real directory copies. The manifest’smanagedfield indicates the update channel; it is not a choice to leave canonical content in a package-manager cache.distribute.rscreates target-side symlinks to the real library entries and protects foreign links from accidental replacement.profiles.rsand the cross-machine configuration document define shared pool policy, committed named machine profiles, and local runtime settings.machine.rspreserves a compatibility model for local disable lists, directory filters, path overrides, and install consent.- The current cross-machine flow treats shared tags as routing inputs, keeps newly discovered skills library-only until classified, and permits project
.tome.tomlfiles to add destinations without changing shared sources or selecting a profile.
The remaining work is to make those boundaries consistently visible and useful to a person curating a growing skill collection.
Decision: copy the canonical pool and every target
Adopt copy materialization as Tome’s default and supported deployment model.
The canonical pool is the place where Tome owns and curates skills; targets are self-contained deployments. A target must continue working if Tome is uninstalled, unavailable, misconfigured, moved, or simply not run again.
| Layer | Storage rule | Why |
|---|---|---|
| Source/package-manager cache | Read-only input | A cache or installed plugin can change or disappear independently of Tome. |
Canonical pool (skills/) | Real directory copies | Content can be reviewed, hashed, committed, backed up, migrated, and used on another machine. |
| Tool target directory | Real directory copy from the canonical pool | The tool remains self-contained and usable if the pool or Tome executable disappears. |
| Project target directory | Real directory copy from the canonical pool | Git resets, project tooling, deletion of the checkout, or removal of Tome cannot dereference, break, or mutate the canonical pool. |
Do not reintroduce source/cache symlinks inside the canonical pool. Do not use target symlinks as normal materialization either. Symlinks economize on local copies but couple every target to Tome’s continued path correctness and turn ordinary target-file writes into a possible canonical-pool mutation.
A target copy is a derived deployment, not a second source of truth. Its deployment record must identify the canonical hash, target path, materialization mode copy, and last successful sync. A later tome sync can report drift and offer an explicit, previewed refresh; it must never silently treat a changed target copy as canonical content.
State model
1. Shared pool: committed and reviewable
The shared repository owns:
- canonical skill directories;
- pool-wide source policy, exclusions, conflict resolutions, and source pins;
- immutable content hashes and complete provenance observations;
- shared curation metadata: domains, capabilities, tool constraints, maturity, licensing/attribution notes, and customization/fork relationships;
- named machine profiles and project-safe route policy; and
- the lockfile/catalog needed to reproduce or reconcile source state.
A same-name/different-content discovery must stop before it changes the pool. Equal content from multiple sources merges provenance rather than selecting an invisible winner.
2. Machine profile: committed, named topology
A committed profile declares a machine role and its known target topology: paths, target capabilities, preferred materialization mode, route predicates, and explicit exclusions. Profiles are selected by name, never guessed from hostname.
A profile answers where this machine can receive skills. It must not redefine canonical content or silently add a competing source policy.
3. Machine-local settings: private runtime choice
Local settings select one committed profile and hold facts/consents that should not be committed: Git synchronization policy, native-plugin installation permission, backup behavior, credentials, and temporary local overrides.
The status surface should distinguish at least: configured-but-unavailable destination, installed/healthy materialization, drifted/missing materialization, disabled-by-profile, disabled-locally, and blocked-by-capability.
4. Project layer: additive destinations only
A nearest project .tome.toml may add routes and destinations under that project. It may not add global sources, replace pool policy, mutate canonical curation, or select a machine profile. This prevents a repository checkout from unexpectedly changing the shared collection.
Curation model
Curation is a deterministic, reviewable layer between intake and deployment.
Skill record
Each canonical skill needs a curation record with at least:
- stable skill ID/name and canonical content hash;
- source provenance and upstream relationship;
- domains and capabilities (many-to-many rather than one category);
- supported targets/constraints and incompatible targets;
- lifecycle state:
candidate,accepted,routed,excluded,customized,forked, ordeprecated; - relationship links: complements, overlaps, supersedes, derives-from, and conflicts-with; and
- explicit evidence references: lint result, review notes, test/evaluation suite/result, and attribution/license notes where applicable.
Tags alone are useful routing primitives, but they are insufficient as the entire curation model: a tag cannot explain overlap, a fork’s upstream, or why a candidate is excluded.
Categories and use-case sets
The catalog must also define two explicit, shared curation constructs:
- Categories provide the maintained domain/capability taxonomy used for browsing and filtering. A skill may belong to several categories; categories are not inferred from a target path or an agent name.
- Use-case sets are named, reviewable collections of curated skills for a concrete operating context—for example a Paperclip agent role, a project type, or a specialized project target. A set records its purpose, direct members and/or deterministic category/capability rules, and applicable target constraints.
Sets are deployment intent, not another canonical source. A Paperclip agent or project route receives an explicitly assigned set, after the selected machine/profile and target constraints are resolved. An edit to a target copy or an agent’s runtime workspace never silently changes set membership, categories, or canonical curation.
The model must allow a project to select from shared approved sets or add an additive project-local route, but a project configuration must not create arbitrary global sources, rewrite shared categories, or change another agent’s set assignment.
An explicit, versioned curation assignment registry owns each agent/project-target assignment and records its selected set IDs, catalog revision, and permitted writer. Tome’s curation CLI/TUI writes that registry through one validated path; Paperclip consumes it read-only unless an authorized Tome action uses the same path. Project configuration can select approved sets only for its own additive route.
Set composition is order-independent: resolve direct members and deterministic rules from one catalog revision, union candidates by canonical skill ID/hash, then apply the union of explicit exclusions (exclusion wins). Intersect set constraints with the selected profile/target; a mutually incompatible or unavailable constraint is a validation failure, not an arbitrary precedence decision. Sort surviving skills by canonical ID and retain every inclusion/exclusion reason. Missing/deprecated sets, invalid rules, same-ID/different-hash inconsistencies, stale unresolvable revisions, and project-local attempts to override shared membership are rejected before deployment.
Changing a category, rule, member, exclusion, constraint, or assignment can affect every target using the set. Before persisting it, Tome must atomically calculate before/after resolved membership, reasons, hashes, affected agents/project targets, and materialization/drift/conflict impact, render that diff, and require explicit confirmation. The curation edit changes no target copy itself; materialization remains a separately previewed action.
Intake workflow
- Discover/import a candidate and record its provenance and immutable hash.
- Validate structurally: package layout, frontmatter, path safety, declared requirements, and target compatibility.
- Classify by domain/capability and compare it against the existing catalog.
- Triage it explicitly as accept, accept-but-library-only, route, customize, fork, reject/exclude, or investigate further.
- Deploy only after a profile/project route makes the decision explicit.
- Reassess on content/hash or source-provenance changes; do not silently inherit old acceptance for changed content.
Overlap analysis should first be explainable and deterministic: shared domain/capability labels, common target compatibility, same upstream, high textual/frontmatter similarity, and shared evaluation suites. A semantic similarity service can be added later as advisory evidence, never as an automatic deletion or routing decision.
Customization and forking
Use customization when a small, maintained overlay can be traced to a stable upstream base and the delta is reviewable. Use a fork when the behavior or ownership purposefully diverges, when the overlay cannot be applied safely, or when the source is no longer suitable as an update channel. Both must retain derived_from provenance and a base hash; neither should overwrite an upstream snapshot in place.
Validation and evaluation
Validation and evaluation belong in the curation layer.
- Validation is deterministic and cheap: structural parsing, frontmatter/schema checks, identifier/path safety, capability declarations, provenance consistency, and route/materialization constraints. It runs at intake, before deployment, and in CI where appropriate.
- Evaluation measures whether an accepted artifact improves a task. It must be isolated from the canonical library, use hash-addressed artifacts, preserve terminal and
not_comparablestates, and compare matched treatment/control runs only when score-bearing evidence is comparable.
The provider-neutral core in MCO-143 remains valuable, but it is a next capability—not the current lead lane. It should remain a library-domain module with authored portable suites and fixtures in the shared repository, while generated result documents, traces, temporary workspaces, credentials, and provider/model cost data remain machine/CI-local.
Evaluation evidence may inform a curation decision. It must not automatically route a skill, remove an overlapping skill, or declare a fork safe.
Phased roadmap
Now: reliability and accurate inventory
- Fix Git source discovery and prove it with end-to-end coverage.
- Fix stale target links during role transitions and retain foreign-link protection.
- Make the source/configuration type boundary explicit enough that URLs are not treated as filesystem paths.
- Publish an accurate status/doctor inventory for pool, selected profile, project routes, materialization mode, and divergence.
Next: curation and controlled deployment
- Add the curation-record contract, category taxonomy, and named use-case sets for Paperclip agents and specialized project targets; provide deterministic catalog views, domains, capabilities, lifecycle, provenance, overlap candidates, and gap reports.
- Add explicit target deployment records for copy materialization, including canonical hash, target path, last successful sync, and previewed drift refresh.
- Add agent/set assignment and project route inspection/selection on top of the existing profile boundary.
- Implement the provider-neutral evaluation core as curation evidence, followed by a separate runner-adapter spike.
Later: advisory intelligence and ecosystem expansion
- Semantic overlap/gap suggestions with human approval.
- Customization-overlay and fork workflows with upstream-delta reporting.
- New ecosystems and marketplaces only after generic source discovery, provenance, and materialization are reliable.
- Desktop/Tauri work only after an explicit reprioritization; it must render the same pool/profile/curation model rather than create GUI-only state.
Terminal/TUI curation interaction
The terminal UI is a primary operating surface for this work. It must use the same catalog, category, set, profile, and deployment records as the CLI—never a separate UI-only store.
At minimum, the TUI must support:
- browsing the canonical pool and deployed/available state;
- filtering by category, capability, lifecycle, provenance, target compatibility, and set membership;
- inspecting which sets apply to a Paperclip agent or project target and why;
- editing categories, set members/exclusions/constraints, and deterministic rules only through the shared curation writer, with validation and a rendered diff/preview; and
- previewing before/after resolved membership and deployment impact for every curation edit or assignment change before explicit confirmation and separate materialization.
Bulk or rule-based set membership must remain explainable: the UI shows the rule, each resulting skill, excluded candidates, and any target-constraint reason. It must not use opaque semantic scoring to make edits or deploy changes automatically.
Safety constraints
- No source disappearance may delete canonical pool content without an explicit pool removal decision.
- No same-name/different-content candidate may overwrite content or provenance silently.
- Never delete or replace a foreign target link/file without an explicit force/repair decision.
- Every deployed target copy must be identifiable and repairable from its canonical hash, but a changed target copy is never canonical input.
- Project configuration cannot mutate the shared pool.
- Provider credentials, raw evaluation traces, and machine-specific consent do not enter shared Git state.
- A suggestion engine may prioritize review but cannot enact acceptance, routing, customization, forking, or deletion on its own.
Paperclip triage
Paperclip is the authoritative work queue. The immediate lane is source/distribution correctness:
- MCO-52 — Git source discovery bug.
- Imported GitHub #422 and #436 — end-to-end Git source and clone/update coverage.
- Imported GitHub #548 — remove orphaned target links on role transitions.
- Imported GitHub #424 — separate URL source identity from filesystem path after behavioral repairs are protected.
Keep MCO-143 / GitHub #604 as the next curation-evidence task. Keep desktop/Tauri issue MCO-141 / GitHub #581 paused. Re-triage older aggregate review issues into individually reproducible work before scheduling them.
MCO-144 implementation plan: portable skill pool and curated copy deployments
Status: Proposed implementation plan derived from the skill-organization architecture. Paperclip is the authoritative execution record: MCO-144; MCO-148 tracks the implementation-program execution. This plan consumes the committed profile and local-settings boundary established by the architecture branch: shared
tome.toml, committedmachines/<profile>.toml, and privatesettings.tomlselecting the active profile. It does not redesign that model.Product focus: organize and curate AI-agent skills across machines and projects. Validation and evaluation are supporting evidence. Desktop/Tauri work remains paused unless Martin explicitly reprioritizes it.
1. Objective and success criteria
Tome must manage skills through a portable, independently usable deployment chain:
sources and validated Git caches
→ copied canonical skill pool
→ copied machine and project targets
A successful implementation has these properties:
- Canonical library entries are real, owned directories, never symlinks into an upstream package cache or source checkout.
- Every Tome-managed target is a real copied directory. It keeps working if Tome is uninstalled, moved, misconfigured, or never run again.
- A target copy is derived state, never canonical input. Editing it cannot silently alter or become pool content.
- Tome never overwrites, removes, or adopts a foreign or drifted target directory without an explicit, previewed decision.
- The CLI/TUI can explain a skill’s provenance, canonical hash, curation state, selected routes, target health, and drift.
- Normal commands resolve their routes, target availability, disable state, and consent from the established effective context: shared
tome.toml, the explicitly selected committedmachines/<profile>.toml, and private localsettings.toml. This delivery must preserve those selection semantics. - A project
.tome.tomlcan add project-local destinations but cannot change global sources, pool policy, canonical curation, or the active machine configuration. - Named, shared use-case sets can be assigned to Paperclip agents and specialized project targets. The assignment is explicit, constraint-checked, previewable, and never inferred from target-local edits.
2. Scope boundaries
In scope
- Copy-only canonical library and target materialization.
- Deployment ownership, hashes, drift detection, preview, refresh and safe removal.
- Migration of existing Tome-created target symlinks.
- Target status and doctor diagnostics.
- Established profile/settings configuration and constrained project routes.
- Curation records, deterministic intake, provenance, lifecycle, overlap/gap views, customization and fork lineage.
- Category taxonomy and named use-case sets for Paperclip agents, project types, and specialized project targets.
- Structural validation as curation evidence.
- Terminal/TUI-first inspection and actions.
Explicitly deferred
- Desktop/Tauri implementation or desktop-only state.
- Automatic model calls or a CI quality gate for skill evaluation.
- Semantic/LLM overlap decisions that automatically route, delete, accept, customize or fork skills.
- Marketplace/ecosystem expansion beyond reliable generic discovery and provenance.
- Automatic adoption of user/project edits in a target as canonical changes.
- A redesign of profile selection, profile schema, or unrelated local-settings ownership.
3. Preconditions and sequencing
3.1 Reliability lane first
Before changing distribution semantics, complete the source-reliability work:
- Merge and release the MCO-52 cached Git-source discovery/security work after normal review.
- Complete the linked Git source end-to-end and clone/update coverage.
- Keep all read-only commands network-free: an unavailable Git cache must produce actionable
tome syncguidance, not clone or fetch. - Preserve the Git cache security predicate: only a direct, non-symlink cache root with a direct, non-symlink
.gitdirectory and bounded Git validation is trusted.
3.2 Compatibility inventory
Before the copy-deployment migration:
- Inventory every current target directory and classify each entry as Tome-managed symlink, broken Tome symlink, foreign symlink, foreign real directory, missing, or already copied.
- Record current manifest/lockfile semantics, ownership assumptions, cleanup behavior, doctor behavior and CLI/TUI output snapshots.
- Identify public configuration and JSON/status compatibility requirements.
- Define migration recovery behavior, record-location migration, and crash-recovery behavior before writing destructive code.
No migration should be inferred from a path name alone. A path must be proven to be a current Tome-managed symlink before Tome offers to replace it.
3.3 First-slice boundary
The first executable slice is intentionally narrow: targets and routes from the already-selected effective profile context, its established disable/consent decisions, and the existing CLI/TUI data path. It introduces copied targets and their external records; it does not redesign profile selection, add a second configuration model, or require project routes. Existing project routes remain compatible but receive no copy-deployment mutations in this slice. Project destinations and curation remain later slices, so a deployment-safety regression cannot be hidden behind a broad schema migration.
4. Target deployment contract
4.1 Materialization model
Replace target-side symlink creation with a copy deployment engine.
For a selected (skill, target) route:
- Validate the canonical source directory and calculate its canonical content hash.
- Inspect the destination with symlink-aware metadata.
- Compare it with the recorded deployment state.
- Render a plan: create, refresh, report drift, migrate, skip, remove, or require explicit repair/force.
- Copy only a validated regular-file/directory tree to a staging sibling, validate its hash, and make an approved change without following or creating symlinks in the deployed tree.
- Use an atomic exchange only where it is supported. Otherwise rename the old managed target to a sibling backup, rename the verified staging directory into place, then remove the backup; on failure, restore the backup before returning an error.
- Persist deployment state only after the active target is verified. A durable transition/backup marker must let doctor recover or report a crash between target replacement and record persistence.
A destination is never replaced merely because it has the expected directory name.
4.2 Deployment record
Introduce a versioned, atomic deployment-state file outside the target directories. The exact file name and serialization format should be decided during implementation, but every record must contain:
- schema version;
- stable canonical skill ID/name;
- canonical content hash at last materialization;
- target identifier, canonicalized absolute target path, and the target-root identity used for boundary checks;
- materialization mode, initially only
copy; - last successful materialization timestamp;
- observed target hash, last-observed timestamp, and platform-supported file identity (for example device/inode) captured after a successful materialization;
- ownership/migration provenance sufficient to distinguish a Tome-managed copy from foreign content;
- source/canonical reference useful for diagnostics, but not a live target dependency.
Do not put a required mutable metadata marker inside an agent tool’s skill directory. Target directories must remain native, self-contained skill directories. If a small marker is later considered, it must be optional and never the sole ownership proof.
The external record provides an ownership chain only for a target that was created or migrated by Tome. Matching bytes alone never prove ownership: an unrecorded path, a record/path mismatch, a changed target-root identity, or a changed recorded file identity is foreign/repair-required, even if its content hash equals the canonical hash. The implementation must document the residual limitation that an external actor can replace a directory with indistinguishable metadata; --force remains required when ownership cannot be established.
4.3 State machine
Status/doctor should classify every candidate route as one of:
healthy: recorded copy exists and matches its recorded canonical hash;canonical-updated: target matches its record but the canonical pool has newer content;drifted: target exists but differs from its last recorded canonical hash;missing: recorded target copy no longer exists;legacy-symlink: current Tome-managed symlink eligible for explicit migration;foreign: unrecorded or ownership-mismatched file, directory, or symlink;unavailable: configured target path/tool is unavailable on this machine;disabled-locally: disabled by the effective local settings/profile context;blocked-by-constraint: route conflicts with declared target capability/constraint;stale-record: deployment record exists but no longer corresponds to a valid route or canonical skill.interrupted: a durable replacement transition or backup is present and must be recovered or explicitly repaired before another mutation.
drifted, foreign, and legacy-symlink are never silently refreshed or pruned.
4.4 Safe operations
- Create: only if the destination is absent or an explicit create plan is approved.
- Refresh: replace only a healthy Tome-managed copy whose record, canonicalized path, target-root boundary, and recorded identity still agree after preview; never refresh a drifted target without explicit conflict resolution.
- Migrate: transform only a proven Tome-managed symlink into a copied deployment after preview. Preserve a foreign/broken symlink and explain why it was not changed.
- Remove: remove only a record-matching healthy Tome-managed copy after preview. A drifted, identity-mismatched, or interrupted copy becomes a report/repair decision, not an automatic cleanup.
- Repair: require an explicit
--force/interactive confirmation mode with a clear description of affected paths and lost target-local edits. - Failure recovery: retain the previous target until the replacement is fully staged and hashed; restore the backup on a failed fallback rename. Remove staging artifacts on normal failure and make leftover staging/backup/transition artifacts detectable by doctor.
5. Configuration boundary
5.1 Consume the established layers
Build on the established configuration boundary rather than duplicating or bypassing it:
- Shared, portable
tome.toml: pool policy, validated Git sources, source exclusions, and source pins; it does not define machine targets or routes. - Committed
machines/<profile>.toml: named machine target topology, target capabilities, route predicates, and profile-level exclusions. - Private
~/.config/tome/settings.toml: explicit active-profile selection plus machine-local runtime consent and temporary overrides. - Shared library/lockfile/manifest: canonical content, reproducibility and provenance.
Copy deployment must receive the already-effective target, route, disable, capability, and consent decisions from normal command context loading; it must not parse a parallel machine.toml path or infer a profile from the hostname. Legacy machine.toml compatibility, if retained by the implementation, is read only through an explicit, tested compatibility/migration adapter before normal commands construct the effective context. The adapter must make migration status and recovery steps visible, and copy deployment must never guess legacy target ownership or route selection.
5.2 Project routes
Add a project configuration format only after machine-level copy deployment, status, recovery, and removal are proven. A nearest .tome.toml may then add project-local routes/destinations under that checkout.
Validation rules:
- project config may not add or alter global sources;
- project config may not select or rewrite the active profile or local settings;
- project config may not mutate canonical pool content, curation, exclusions or provenance;
- project destinations inherit the copy-only materialization contract;
- all project operations must canonicalize the project root before resolving routes, reject destination escapes through
..or symlinked ancestors, and re-check the boundary immediately before mutation.
5.3 Profile-model stability
The selected-profile model is already the supported operational boundary. Copy deployment may add target deployment records and diagnostics around its resolved outputs, but must not change profile selection, permit hostname inference, or let profiles redefine canonical source policy. Any future profile-schema evolution requires a separately reviewed migration and compatibility plan.
6. Curation catalog and intake
6.1 Curation record
Add a versioned, committed curation record for each canonical skill. It must include:
- stable skill ID/name and canonical hash;
- source provenance, upstream URL/identity and source pin where applicable;
- domains and capabilities, modeled many-to-many;
- supported/incompatible targets and declared constraints;
- lifecycle:
candidate,accepted,routed,excluded,customized,forked, ordeprecated; - relationships:
complements,overlaps,supersedes,derived_from, andconflicts_with; - licensing and attribution notes when applicable;
- evidence references: lint/validation results, review notes, tests and optional evaluation suite/results.
The catalog must not treat free-form tags as a sufficient substitute for provenance, lifecycle, relationships and decision rationale.
6.1a Categories and use-case sets
Model categories as maintained, shared domain/capability taxonomy. A skill may belong to several categories; category assignment is explicit and reviewable rather than inferred from a target path or an agent name.
Model use-case sets as named, shared curated collections for a concrete purpose. A set must record:
- stable set ID/name, description and intended use case;
- direct skill members and/or deterministic category/capability inclusion rules;
- target/capability constraints and explicit exclusions;
- applicable Paperclip agent roles and/or specialized project-target classes;
- provenance for membership decisions and the canonical hashes to which they apply.
Sets are deployment intent, not a second canonical source. A Paperclip agent or project target receives an explicitly assigned set only after the effective profile, target constraints, and deployment plan are resolved. A target-copy edit or agent-runtime edit cannot silently change categories, set membership, or canonical curation. Project configuration may select approved shared sets for its additive routes, but may not create global sources, rewrite shared taxonomy, or change another agent’s assignment.
Persist explicit agent/project-target assignments in a shared, versioned assignment registry owned by the curation layer. The registry records target identity, selected set IDs, the catalog revision used for resolution, and the permitted writer. Tome CLI/TUI curation actions are the normal writers; a Paperclip adapter is a read-only consumer unless an explicitly authorized Tome action invokes the same validated write path. A project .tome.toml may select approved shared set IDs for its own additive route only; it cannot alter the shared registry, set definitions, categories, or another target’s assignment.
Effective-set resolution and conflicts
Resolve every assignment from one immutable catalog revision with this algorithm:
- Load the assignment’s selected set IDs. Missing, deprecated, or unapproved set IDs are validation errors.
- Evaluate every selected set’s deterministic rules and direct members against that revision. Union duplicate candidates by canonical skill ID/hash and retain all inclusion reasons.
- Union explicit exclusions across the selected sets, then remove excluded candidates. Explicit exclusion always wins over a direct member or rule match; the TUI/CLI must retain the exclusion reason.
- Intersect the selected sets’ declared target/capability constraints with the effective profile and target. Exclude candidates that fail a satisfiable constraint and record the reason. If selected set constraints are mutually incompatible or require an unavailable target capability, fail validation for the assignment rather than choosing an arbitrary set or silently dropping a constraint.
- Sort the resulting included skills by stable canonical skill ID. Materialization receives only this resolved, hash-addressed list plus its reasons and the catalog revision.
Set order never changes the result. The implementation must reject a same-ID/different-hash catalog inconsistency, an invalid rule, a constraint contradiction, a stale assignment catalog revision that cannot be re-resolved, or an attempted project-local override of shared membership/exclusion semantics.
Changing a category, deterministic set rule, direct member, exclusion, constraint, or assignment is a potentially fleet-wide deployment change. Before persistence, the CLI/TUI must atomically resolve before and after snapshots for every affected assignment and render: added/removed/resolved skills, changed hashes, inclusion/exclusion/constraint reasons, affected Paperclip agents and project targets, and planned materialization/drift/conflict impact. Persist only after explicit confirmation; then update the catalog/assignment revision atomically. A target copy is never changed as part of the curation edit itself—materialization remains a separately previewed operation.
6.2 Deterministic intake workflow
- Discover/import a candidate and store its observed provenance plus immutable hash.
- Validate package layout, frontmatter, identifiers, paths, declared requirements and target compatibility.
- Compare it against the catalog using deterministic signals: same upstream, domains/capabilities, target compatibility, frontmatter/text similarity and shared evidence.
- Require an explicit outcome: accept, keep library-only, route, customize, fork, exclude, deprecate or investigate.
- Deploy only after the curation state and a valid route permit it.
- Reassess whenever canonical content or source provenance changes.
Same-name/different-content intake must stop before changing the pool. Equal content from several sources should merge provenance rather than hide the additional source.
6.3 Customization and forks
- Use a customization when a small reviewable delta can remain linked to a stable upstream base.
- Use a fork when behavior or ownership intentionally diverges, the delta cannot be safely maintained, or upstream is no longer an appropriate update channel.
- Both retain
derived_fromand base-hash provenance. - Neither modifies an upstream snapshot in place.
- Target edits do not become either a customization or fork automatically.
7. Validation and evaluation
7.1 Deterministic validation
Run validation at intake, before materialization and in suitable CI. Cover:
- SKILL.md structure and frontmatter/schema;
- identifiers and path safety;
- content hashing;
- provenance consistency;
- target capability and route constraints;
- deployment-state schema and ownership invariants.
7.2 Evaluation as evidence
The provider-neutral MCO-143 evaluation model remains a separate later capability. It must:
- use hash-addressed, disposable wrappers/workspaces;
- never mutate the canonical library to evaluate a skill;
- keep traces, generated results, credentials and provider/model cost data machine/CI-local;
- preserve
not_comparableoutcomes; - never automatically route, accept, remove or fork a skill.
8. Terminal/TUI experience
Prioritize terminal and ratatui surfaces. The TUI must render the same core state as the CLI; it must not create its own deployment or curation state.
Required views/actions:
- canonical pool inventory with lifecycle, provenance, domains and constraints;
- browse/filter by category, capability, lifecycle, provenance, target compatibility and use-case-set membership;
- inspect the effective set assignment for a Paperclip agent or project target, including every inclusion/exclusion and its reason;
- create, rename, categorize and retire categories; edit explicit set membership, exclusions, constraints and deterministic set rules only through the shared curation writer;
- for every category, rule, membership, exclusion, constraint, or assignment edit, atomically preview before/after resolved membership, hashes, inclusion/exclusion reasons, affected agents/project targets, and downstream materialization/drift/conflict impact before explicit confirmation;
- selected local configuration and active project routes;
- per-target deployment mode, canonical version, health and drift;
- dry-run/preview for create, refresh, migrate, remove and repair;
- clear recovery guidance for missing Git caches, unavailable targets and target drift;
- deterministic overlap candidates and gap reports;
- visible customization/fork lineage.
9. Delivery phases
Phase A — source reliability and baseline inventory
Outcome: reliable, safe source discovery and an evidence-backed migration baseline.
- Land MCO-52 and linked Git tests.
- Add/verify source type validation and cache safety invariants.
- Inventory current target artifact states and freeze representative fixtures.
- Document compatibility and migration cases.
Acceptance: read-only discovery remains network-free; invalid/redirected Git caches are not trusted; fixtures cover real, broken and foreign target artifacts.
Phase B — inspect, record, and create copied deployments
Outcome: a bounded set of existing machine targets can receive newly created, independently usable copied deployments without changing legacy links.
- Implement the deployment record schema, transition marker, and atomic persistence.
- Implement symlink-aware inspection and the complete read-only state classifier before enabling a mutation.
- Implement validated staging copy, supported atomic exchange/fallback backup-rename behavior, rollback, and doctor recovery for interruption artifacts.
- Add dry-run plan rendering.
- Enable create only for absent destinations; preserve every pre-existing target artifact.
Acceptance: deleting/moving the canonical library after a successful deployment does not break a target; non-empty targets are real directories with no deployed symlinks; unowned files are untouched; interrupted create leaves no active partial target and is reported by doctor.
Phase C — migrate, reconcile, and remove safely
Outcome: users can understand and safely reconcile target state.
- Implement the deployment state machine in status and doctor.
- Add explicit migration for a symlink proven to be Tome-managed, including broken-link handling, a former target directory that becomes
source, and rollback from its original link on failure. - Replace symlink-oriented cleanup/eject semantics with ownership-aware copy semantics.
- Add previewed refresh, remove and repair flows.
- Add migration and recovery documentation.
Acceptance: every state category, including interrupted, has focused tests and clear CLI/JSON output; migration preserves a foreign or uncertain link; when a directory changes from synced to source, cleanup removes only a proven Tome-managed legacy deployment and preserves real, foreign, drifted, or identity-mismatched target content.
Phase D — project routes and configuration validation
Outcome: safe project-local copied targets without allowing projects to rewrite the global pool.
- Define the minimal project
.tome.tomlschema. - Implement nearest-project discovery and boundary-safe path resolution.
- Validate prohibited configuration fields and route conflicts.
- Ensure project records bind both project-root identity and canonical target path; add tests around checkout deletion, reset, root replacement, and symlink escape attempts.
Acceptance: a project can receive an independently usable target copy; a project config cannot add sources or change canonical/ machine-local policy.
Phase E — curation records and intake
Outcome: a growing pool becomes explainable and reviewable.
- Define curation record schema and migration/validation rules.
- Define category taxonomy, versioned assignment registry, and use-case-set schemas, including explicit Paperclip-agent/project-target assignments, the effective-set resolution algorithm, explainable rule evaluation, and permitted writers.
- Add catalog/category/set read/write operations and deterministic views.
- Implement candidate lifecycle and explicit triage outcomes.
- Add provenance merge and same-name/different-content conflict behavior.
Acceptance: every canonical skill can state what it is, where it came from, how it is categorized, which sets include/exclude it, why it is routed or excluded, and what content hash that decision applies to. A Paperclip agent or specialized project target can show its selected set(s), deterministic resolved skills, constraint exclusions, and a preview before any deployment change. Category/rule/set/constraint/assignment edits atomically preview all affected targets and require explicit confirmation; incompatible multi-set constraints, stale revisions, invalid rules, and project-local overrides fail validation without changing curation or deployments.
Phase F — overlap/gap, customization and fork workflows
Outcome: Tome supports deliberate collection maintenance instead of accumulating folders.
- Implement deterministic overlap and gap reports.
- Add traceable customization and fork records.
- Add upstream-delta reporting where source information permits.
Acceptance: suggestions remain advisory; no automated deletion/routing/forking occurs; all lineage is inspectable.
Phase G — evaluation evidence
Outcome: evaluation can inform curation without becoming deployment authority.
- Implement MCO-143 as a separate provider-neutral core.
- Attach optional evaluation evidence references to curation records.
- Keep runners/adapters, model calls and UI expansion separate follow-up work.
10. Test strategy
Use unit, integration and end-to-end filesystem tests. Required scenarios include:
- canonical copy and target copy content equality;
- target independence after canonical path deletion/relocation;
- copy update with atomic replacement and simulated failure recovery;
- nested symlink, special-file, and symlinked-target-parent rejection during materialization;
- healthy target, canonical-updated, drifted, missing, foreign and stale-record states;
- record/path/target-root/file-identity mismatch and interrupted replacement recovery;
- symlink migration: valid Tome-managed, broken Tome-managed, foreign and redirecting cases;
- former target role transition:
syncedtosourceremoves only the proven Tome-managed legacy deployment; - safe cleanup/removal with and without target drift;
- project route boundary and configuration restrictions;
- same-name/different-content intake conflict and equal-content provenance merge;
- deterministic curation catalog serialization/validation;
- CLI status/doctor output and TUI state mapping;
- no network clone/fetch in list/browse/status;
- Git cache root /
.gitfile /.gitsymlink rejection regression tests.
Run formatting, clippy, focused tests, full cargo test -p tome, doc build where available, and git diff --check for every implementation PR. Add platform coverage for macOS and Linux where filesystem behavior can differ.
11. Risks and mitigations
| Risk | Mitigation |
|---|---|
| Copy deployment can overwrite user/project work. | External deployment records, hash-based drift detection, preview-first mutation, explicit force/repair only. |
| Migration mistakes classify foreign links as Tome-owned. | Require strong ownership proof and preserve uncertain paths. |
| Staging/rename differs across filesystems. | Stage beside destination; use an atomic exchange only when supported, otherwise use a durable backup-rename-and-rollback protocol. Detect cross-device cases and fail safely rather than partially replacing. |
| An external actor can recreate a target with matching content. | Require a matching external record, canonicalized target boundary, and recorded identity before unattended mutation; classify uncertainty as repair-required and document that exact metadata spoofing still needs explicit force. |
| Curation metadata becomes a second hidden source of truth. | Bind every record to canonical hash; require explicit reassessment when content changes. |
| Configuration grows into competing policy layers. | Keep current shared/local split; restrict project config; defer named profiles until evidence requires them. |
| Evaluation becomes an automatic quality or security claim. | Keep evaluation optional, isolated, diagnostic and non-authoritative. |
| Desktop work pulls effort away from dependable core behavior. | Treat CLI/TUI core as the only active product surface; desktop remains paused. |
12. Paperclip work breakdown
Paperclip remains authoritative. Convert these phases into individually testable issues rather than one long-lived implementation ticket:
- Close the MCO-52 reliability lane and linked source tests.
- Create inspect/record/create-copy deployment issue (no legacy replacement).
- Create target migration/doctor/reconcile/cleanup issue.
- Create safe project-route issue.
- Create curation record and intake issue.
- Create overlap/gap and customization/fork issue.
- Keep MCO-143 as the later evaluation-evidence issue.
Each issue must state its acceptance tests, migration/safety boundary, affected paths, and whether it changes a user-visible configuration contract. Desktop/Tauri work stays paused and must not be pulled into these issues.
Development Workflow
tome uses a lightweight, Paperclip-led workflow:
- Paperclip is the authoritative work queue, roadmap, priority, and execution-state system.
- GitHub Issues are linked external history and repository-facing discussion; they do not automatically set current priority.
- Repository planning documents are optional, versioned design/implementation evidence for substantial changes.
- Git commits and pull requests are the implementation and review evidence.
This workflow exists for traceability, not ceremony. Use the smallest amount of written design that makes a significant change understandable and safe.
When written planning is warranted
Create or update a repository planning document when work involves:
- a new feature or substantial refactor;
- an architecture or configuration-model change;
- a migration, security boundary, or destructive-state transition;
- an implementation sequence whose acceptance criteria need review before coding.
Small fixes—typos, isolated bugs, and mechanical cleanups—can proceed directly from a Paperclip issue to code, tests, and pull request.
Default flow
- Create or update the relevant Paperclip issue. It records the objective, priority, dependencies, current status, and the decision to start work.
- Inspect existing repository documentation, prior PRs, tests, and linked GitHub history.
- For significant work, add a concise, versioned design or implementation plan in the repository. Link it from the Paperclip issue and PR.
- Implement in an issue-specific branch/worktree with focused tests and small commits.
- Open a pull request, run the applicable quality gates, and record the PR, verification, and remaining follow-ups on the Paperclip issue.
- Update Paperclip status only after the stated acceptance criteria have evidence.
Roles and boundaries
Paperclip
Paperclip answers: what is currently authorized and prioritized, who owns it, what blocks it, and what remains?
Use it for:
- goals, project priorities, tasks, dependencies, and execution state;
- durable status updates and completion evidence;
- links to GitHub issues, pull requests, design documents, and verification output.
GitHub Issues
GitHub Issues answer: what is the repository-visible historical or external context?
Use them as linked evidence when useful, but do not let an open GitHub issue begin work or override a Paperclip decision by itself.
Repository documents
Repository documents answer: why is this design safe and how should it be implemented?
Use normal Markdown under the relevant documentation or planning location. Keep a document close to the code only while it remains useful to maintainers; avoid creating a second task queue or duplicating Paperclip state.
Git and pull requests
Git and PRs answer: what actually changed and what verification/review evidence exists?
Traceability convention
For a meaningful change, include the relevant Paperclip issue identifier and link in the PR description or commit body. Add GitHub references and repository planning-document paths only when they genuinely help future readers.
Example:
Paperclip: MCO-52
https://mmini.zuul-bee.ts.net:8443/MCO/issues/MCO-52
For a PR that implements a written design, include a compact traceability section:
## Traceability
- Paperclip: MCO-52
- Design: docs/src/example-design.md
- Verification: cargo test -p tome
Practical rule of thumb
- Paperclip = source of truth for planning and execution state
- GitHub = linked repository history and external discussion
- Repository docs = durable design/implementation context when warranted
- Git / PR = shipped evidence
Do not create a parallel backlog, checklist, or status system in the repository. Keep task status in Paperclip.
Architecture
System Diagram (Excalidraw) — interactive diagram showing the discovery → library → distribution flow. The diagram pre-dates v0.10 and does not depict the marketplace adapter dispatcher or unowned lifecycle; the broad three-tier shape is still accurate. Refresh deferred to a follow-up.
Rust workspace (edition 2024). This page describes the CLI/core crate; Desktop is outside the current CLI release scope.
crates/tome — CLI (tome)
The main binary. All domain logic lives here as a library (lib.rs re-exports all modules) with a thin main.rs that parses CLI args and calls tome::run().
Sync Pipeline
The core flow that tome sync and tome init both invoke (lib.rs::sync):
- Reconcile (
reconcile.rs) — Lockfile-authoritative drift detection for managed skills, run first against the previously saved manifest andtome.lock. Native tool adapters apply permitted installs or updates according tomanaged_plugin_installin localsettings.tomland the--no-installone-run override. - Discover (
discover.rs) — Scan shared Git sources from repository policy andmanaged,synced, orsourcedirectories from the selected profile. Git sources are provenance inputs; they do not choose distribution destinations. - Consolidate (
library.rs) — Store managed and local skills as real-directory copies in the canonical library..tome-manifest.jsontracks SHA-256 content hashes, provenance, and shared user-managed tags. Re-consolidating the same skill preserves its tags. - Distribute (
distribute.rs) — ApplyRoutingPolicybefore existing origin safety checks. A configured destination route accepts a skill when any selected tag intersects its manifest tags; an explicit destination exclusion overrides the match. Untagged skills are library-only for routed destinations. Tome refuses to clobber foreign symlinks. - Cleanup (
cleanup.rs) — Remove stale library state and Tome-owned destination links, including links that become ineligible after a tag or route change. Foreign links remain protected. - Lockfile (
lockfile.rs) — Generatetome.lockcapturing a reproducible snapshot of the library state for diffing on the next sync. Each entry now carriesprevious_sourceso cross-machine forks-in-place stay traceable to the directory that originally owned the skill.
Other Modules
Listed roughly in alphabetical order:
add.rs—tome addcommand (plan/render/execute pattern). Git inputs register repository-owned discovery sources in sharedtome.toml; local paths register in the selected profile. Git add has no routing prompt or--to, and rejects--role.backup.rs— Git-backed snapshot/restore/diff for the library. The pre-restore safety snapshot is the only recovery path if a restore was accidental, sorestoreaborts if the snapshot fails (#415).browse/— TUI browser (tome browse):app.rs(state + key handling),ui.rs(ratatui rendering),theme.rs(adaptive dark/light),fuzzy.rs(nucleo-matcher), andmarkdown.rs(preview rendering). Destination-ambiguous disable actions are rejected with guidance to usetome route exclude.cleanup.rs— Three-bucket cleanup output (UX-01).cleanup_libraryemits Buckets A (removed-from-config — Owned-to-Unowned transition per LIB-04) and B (missing-from-disk — library entry removed);lib.rs::cleanup_disabled_from_targetemits Bucket C (now-in-exclude-list — distribution symlinks removed, library content preserved). Bucket C entries are collected into a siblingVec<ExcludedSkill>and rendered alongside A+B bycleanup::render_cleanup_buckets(called fromlib.rs::sync) for a single user-facing surface. All output goes to stderr (D-UX01-4). Cleanup no longer auto-deletes orphaned skills (LIB-04); orphan transitions are the unowned-lifecycle entry point.config/— Effective directory and backup types plus validation. The layered resolver constructsConfigafter merging repository, profile, and project ownership.discover.rs— Skill discovery from all configured directories.ScanMode::{Local, ManagedNoProvenance, ManagedWith}replaces the v0.9Option<Option<SkillProvenance>>(HARD-05).distribute.rs— Distribution tosynced/targetdirectories via Unix symlinks. HARD-09 foreign-symlink detection uses a 2x2 canonicalize-vs-lexical-prefix matrix to handle macOS/var → /private/var-style middle symlinks without false positives.doctor.rs— Diagnoses library, directory, configuration, and foreign-symlink issues; surfaces Unowned skills; and safely repairs supported orphan and target-collision cases.eject.rs— Remove all of tome’s distribution symlinks (reversible viatome sync).git.rs— Git clone / pull fortype = "git"directories. Shallow clones to~/.tome/repos/<sha256>/, withbranch/tag/revref pinning and SHA captured in the lockfile.install.rs— Shell completion installation. (The v0.9 reconcile-managed-plugins logic that used to live here moved toreconcile.rsin Phase 13.)library.rs— Copies managed and local skills as real directories into the library and preserves existing manifest tags when refreshing a skill.lint.rs— Validates SKILL.md frontmatter; downcastableLintFailederror mapped to exit code 1 bymain.rs(HARD-04).lockfile.rs— Generates and loadstome.lockfiles. EachLockEntrycarriesname,content_hash,source_name: Option<DirectoryName>(None = Unowned),previous_source: Option<DirectoryName>(Phase 14 D-C1 cross-machine breadcrumb),version,registry_id, andgit_commit_sha. Top-level fields arepub(crate)with read-accessors (HARD-06). The lockfile is now authoritative for managed-skill drift detection (RECON-01..05) —reconcile.rsreads it on every sync. Atomic temp+rename writes.machine.rs— Retains in-memoryMachinePrefsand compatibility persistence exports for paused Desktop callers. Released CLI commands do not read or writemachine.toml.manifest.rs— Library manifest (.tome-manifest.json). EachSkillEntryrecords ownership, previous ownership, content state, and a validatedBTreeSet<SkillTag>. Tags default empty for older JSON and survive consolidation. Atomic temp-plus-rename writes.marketplace.rs—MarketplaceAdaptertrait (six methods:id,current_version,install,update,list_installed,available) plusClaudeMarketplaceAdapter(subprocess toclaude plugin install/update, parsesclaude plugin list --json,RefCellcache that auto-invalidates onOkinstall/update) andGitAdapter(thin shim overgit.rs). Failure aggregation viaInstallFailure/InstallOp/InstallFailureKindmirrors theRemoveFailurepattern;InstallFailureKind::ALLplus a const-fn drift guard pin compile-time exhaustiveness (POLISH-04). Test mockMockMarketplaceAdapterlives inmarketplace::testingbehind thetest-supportfeature.profiles.rs— Loads shared repository policy, the selectedmachines/<profile>.toml, optional project configuration, and localsettings.tomlintoEffectiveContext. Owns checked profile, route, settings, and pool-policy mutations.project.rs— Finds the nearest.tome.tomlby walking working-directory ancestors; validates that it contains additive target directories and routes only; saves route changes atomically.routing.rs— Defines destination routes and the OR-tag-match plus explicit-exclusion eligibility decision shared by distribution and cleanup.paths.rs—TomePathsstruct bundlingtome_home/library_dir/config_dirto prevent parameter swaps.expand_tilde/unexpand_tilderound-trip pair (HARD-22). Symlink path utilities: resolves relative symlink targets to absolute paths and checks whether a symlink points to a given destination.collapse_homefor display.reassign.rs—tome reassign <skill> --to <dir>command. Plan/render/execute. Phase 14 D-API-1: accepts Unowned input (re-anchorssource_name: Noneto a configured directory). The--forceflag bypasses D-A1 different-content collision detection; D-A2 refuses target-only directory roles. Re-anchor clearsprevious_source(Phase 14 D-C1). HARD-19 plan/execute filesystem snapshot eliminates drift between phases. The originally-proposedtome adoptverb was folded into this command (vocabulary supersession; see Unowned lifecycle).reconcile.rs— Managed-skill reconciliation core. Resolvesmanaged_plugin_installconsent from local settings and invokes tool-specific marketplace adapters; tags and destination routing remain Tome-owned metadata.relocate.rs— Move the skill library to a new path with full safety guarantees: detects cross-filesystem moves with a Phase 7 D-10 Conflict/Why/Suggestion recovery hint (HARD-18), re-anchors all distribution symlinks, callswarn_if_unreadable_symlink(intent-first naming per HARD-16) on unreadable managed-skill symlinks instead of silently dropping provenance.remove.rs—tome remove dir <name>transitions owned entries to Unowned while preserving library content.tome remove skill <name>deletes an Unowned entry, its library directory, Tome-owned destination links, and lockfile state.status.rs— Read-only summary of the selected profile, effective profile/project directories, library health, last sync, and Unowned skills.summary.rs—SkillSummaryshared type (NAME / LAST-KNOWN SOURCE / SYNCED columns) consumed bystatus.rsanddoctor.rsUnowned sections. JSON-stable (previous_sourceserialises explicitnullrather than being skipped).update.rs— Lockfile diffing and interactive triage logic, invoked bytome syncto surface added/changed/removed skills and offer to disable unwanted new skills. (Per-managed-skill version reconciliation moved toreconcile.rsin Phase 13; this module retains only the pre-cleanup user-presented diff.)wizard.rs— Interactivetome initsetup usingdialoguer(MultiSelect, Input, Confirm, Select). Uses the mergedKNOWN_DIRECTORIESregistry (WIZ-01, hardened in v0.7) to auto-discover common tool locations (~/.claude/plugins/cache,~/.claude/skills,~/.codex/skills,~/.gemini/antigravity/skills, etc.). Detects pre-v0.6 legacy configs and offers cleanup (WUX-03). All diagnostic chrome routes to stderr (HARD-15).
Key Patterns
- Library-canonical model: Discovery directories →(consolidate)→ Library →(distribute)→ Distribution directories. The library is the source of truth and every skill (managed or local) lives there as a real directory copy. Managed skills use a marketplace adapter (
reconcile.rs+marketplace.rs) to pull updates from upstream; local skills are edited in-place in the library. Distribution always uses Unix symlinks (std::os::unix::fs::symlink) pointing into the library. Unix-only. See Library-canonical model for the full mechanics. - Directories are data-driven:
config::directoriesis aBTreeMap<DirectoryName, DirectoryConfig>— any tool can be added as a directory with a role without code changes. The wizard’sKNOWN_DIRECTORIESregistry is used purely for auto-discovery convenience. - Roles, not “sources vs targets”: A directory can be
managed(read-only source),source(discovery only),target(distribution only), orsynced(both — same dir is read AND written, e.g.~/.claude/skills). The pipeline asks each directory’s role what to do with it; there is no separate “sources” vs “targets” config. dry_runthreading: Most operations accept adry_run: boolthat skips filesystem writes but still counts what would change. Results report the same counts either way.- Atomic writes: Repository policy, profiles, project configuration, local settings, the manifest, and
tome.lockuse checked temp-file-plus-rename writes. - Plan/render/execute:
add,remove,reassign,relocate,ejectbuild an explicit plan, render it for the user, and only then execute. Dry-run is free; tests can assert plan structure without touching the filesystem. - Newtypes at boundaries:
SkillName,DirectoryName,ContentHash,TomePathsvalidate at construction so downstream code doesn’t have to. The sharedvalidate_identifierrejects empty names, path separators,., and... - Error handling:
anyhowfor the application;.with_context()adds path context to every fs error. Missing sources/paths produce stderr warnings rather than hard errors. Symlink operations always verify the link points into the library before deleting. - Layered ownership: Shared Git sources live in repository policy. Machine-wide paths and routes live in the selected profile. The nearest project
.tome.tomladds project-only targets and routes. Localsettings.tomlselects the profile and stores runtime consent. - Tags separate provenance from routing: Sources explain where a skill came from. Manifest tags classify it, and destination-owned routes decide where it is linked.
Library-canonical model
The library at ~/.tome/library/ is the single source of truth for every
skill on the machine — managed AND local. Both kinds are stored as real
directory copies; neither is a symlink into a marketplace cache.
What changed in v0.10 (vs. v0.9): Pre-v0.10, managed skills (Claude
plugins, git clones) lived in the library as symlinks pointing back at the
package manager’s cache. Updating a plugin updated the library transparently
via the symlink. The trade-off was that removing a source erased every skill
it provided, and shipping the library across machines was impossible because
the symlink targets weren’t portable. v0.10 inverts the relationship:
consolidate_managed performs a recursive copy on first sync (and on every
update afterward via the marketplace adapter), so the library on disk is
fully self-contained.
Why this matters:
- Cross-machine portability —
~/.tome/can be committed to dotfiles and cloned onto a fresh machine. Pair withtome.lockfor exact-version reproducibility (see Lockfile-authoritative reconciliation below). See Cross-machine sync for the end-to-end walkthrough (Machine A source-of-truth → Machine B fresh-machine bootstrap). - Source removal preserves content — removing a
[directories.*]entry fromtome.toml(or runningtome remove dir <name>) no longer erases the skills it provided. Their manifest entries transition to Unowned (source_name: None); library content stays in place (LIB-04). - Vanished plugins stay usable — if a marketplace removes a plugin,
tome syncwarns but keeps using the preserved library copy. - Drift basis is
content_hash, not version (Phase 11 D-08). Reconcile comparescontent_hash(library/<skill>)against the lockfile entry; the version string is display-only in diff output (e.g.plugin X: 5.0.5 → 5.0.7). Because the upstreamclaude plugin installcommand doesn’t accept--version, true version pinning is upstream future work.
Lockfile-authoritative reconciliation
tome.lock is the cross-machine state contract. Cargo.lock-shaped: each
managed skill records (name, version, content_hash, source_name, previous_source, registry_id, git_commit_sha). On every tome sync,
reconcile.rs::reconcile_lockfile classifies each managed skill into one
of four buckets:
- Match —
content_hash(library/<skill>) == lockfile.content_hash. Nothing to do. - Drift —
content_hashdiffers OR the lockfile expects a version the adapter no longer provides. Renders a per-skill diff (plugin X: 5.0.5 → 5.0.7); applies the install/update via the marketplace adapter; verifies the resulting librarycontent_hashmatches the lockfile entry. - Vanished —
adapter.available()returns false (the marketplace no longer offers the plugin). Stderr warning, distribution continues from the preserved library copy (RECON-04). - Edited-in-library —
managed: trueand the librarycontent_hashdiverges from the lockfile in a way that looks like an in-place user edit rather than upstream drift. See “Edit-in-library detection” below.
Managed-plugin consent — local
~/.config/tome/settings.toml::managed_plugin_install stores always, ask,
or never. The --no-install flag overrides it for one invocation.
Edit-in-library detection (RECON-05) — when a managed skill’s library
content_hash diverges from the lockfile, the user is prompted with three
choices: fork (default — promote to local via the existing tome fork
machinery), revert (overwrite from marketplace), skip (warn and
don’t touch this entry this sync). In --no-input mode the default is
skip with warning so edited content is never silently overwritten.
previous_source breadcrumb — when a managed skill forks in-place
(Drift → fork), the manifest entry records the old source_name in
previous_source before flipping to local. This closes the Phase 13 D-13
“lossy fork-in-place” gap; tome status and tome doctor show the
last-known source so the user can re-anchor cleanly later via
tome reassign <skill> --to <dir>.
Partial-failure surfacing (ADP-04) — adapter install/update errors
aggregate into Vec<InstallFailure> and render as a grouped ⚠ N install operations failed summary (matches the v0.8 SAFE-01 RemoveFailure
pattern). Library distribution still completes for skills whose adapter
calls succeeded; sync exits non-zero on partial failure.
Marketplace adapter trait
marketplace.rs defines the MarketplaceAdapter trait that isolates
install / update / availability logic per marketplace:
#![allow(unused)]
fn main() {
pub trait MarketplaceAdapter {
fn id(&self) -> &str;
fn current_version(&self, plugin_id: &str) -> Result<Option<String>>;
fn install(&self, plugin_id: &str) -> Result<()>;
fn update(&self, plugin_id: &str) -> Result<()>;
fn list_installed(&self) -> Result<Vec<InstalledPlugin>>;
fn available(&self, plugin_id: &str) -> Result<bool>;
}
}
v0.10 ships two production adapters and a feature-gated test mock:
ClaudeMarketplaceAdapter(ADP-02) — Shells out toclaude plugin install,claude plugin update,claude plugin list --json. Caches the parsedlistoutput inRefCell<Option<Vec<InstalledPlugin>>>; the cache auto-invalidates onOkinstall/update calls. Missingclaudeon PATH surfaces as a clear actionable error message naming the binary. Upstream constraint:claude plugin installdoesn’t accept--version, so the adapter installs “latest” only; the lockfile records the actual installed version and surfaces drift on subsequent syncs.GitAdapter(ADP-03) — Thin shim overcrates/tome/src/git.rs; behavior for existing git directories is byte-for-byte unchanged from v0.9.MockMarketplaceAdapter— Lives inmarketplace::testingbehind thetest-supportfeature. Used by integration tests to inject deterministic install/update/availability behavior without invoking real subprocesses.
Failure aggregation: InstallFailure + InstallOp + InstallFailureKind
- a
Kind::ALLexhaustive sentinel mirror theremove.rs::FailureKindpattern (POLISH-04). Adding a new failure kind without updatingALLis a compile error.
Unowned lifecycle
A skill’s manifest entry has source_name: Option<DirectoryName> (LIB-03).
Some(<dir>) = Owned (the directory in tome.toml provides the source);
None = Unowned (the library copy is canonical with no upstream source).
Transitions to Unowned:
- Cleanup orphan — when a source
[directories.*]entry is removed from its owning repository policy or profile (manually edited or viatome remove dir <name>), every manifest entry whosesource_namepointed at the removed directory transitions tosource_name: Noneon the nexttome sync. Library content preserved (LIB-04). This is Bucket A in the cleanup output — see Sync Pipeline step 5. tome remove dir <name>— explicitly transitions all manifest entries owned by<name>to Unowned and preserves library content (Phase 11 D-10).- Fork-in-place (managed → local during reconcile drift) —
source_namestays the same value (it points at the now-local directory), butprevious_sourcerecords the original managedsource_nameso the user can re-anchor.
Whenever the manifest transitions an entry to Unowned, previous_source
captures the old source_name value (Phase 14 D-C1). tome status and
tome doctor use this value to render the LAST-KNOWN SOURCE column.
CLI verbs (Phase 14 D-API-1 / D-API-2 vocabulary merge):
- Re-anchor —
tome reassign <skill> --to <dir>. Accepts Unowned input. The originally-proposedtome adoptwas folded into existingtome reassignmachinery; the work is identical (copy content into<dir>, update manifestsource_name). - Delete —
tome remove skill <name>. Confirmation prompt defaults to no;--yes/-yskips. Cleans manifest entry + library directory + distribution symlinks + lockfile entry. Refuses on Owned skills with a hint to runtome remove dirfirst (D-B2).
Surfacing — tome status and tome doctor show an
Unowned skills (N): section with NAME / LAST-KNOWN SOURCE / SYNCED
columns. JSON output includes the new unowned (status) /
unowned_skills (doctor) field. Per Phase 14 D-D3, the unowned set is
informational and does NOT contribute to tome doctor’s total_issues();
exit code is unaffected.
Observability (v0.11)
Sync/reconcile/consolidate/distribute/cleanup chatter routes through
tracing::{info,warn,debug}! (OBS-01). Wizard prompts (dialoguer), TUI
browse output, and user-facing summary tables (tome status/list/doctor
tables, tome sync final summary) stay on direct stdout — tracing is for
log-like output only.
The LogLevel enum (HARD-07) maps to a tracing_subscriber::EnvFilter
(OBS-02):
- Default level:
info. --verboseraises todebug.--quietlowers towarn.TOME_LOG=tome::sync=debug,tome::reconcile=info(or anyEnvFilterstring) overrides the flag-derived level (D-ENV-1).
tome sync --verbose emits one span per pipeline step (discover,
reconcile, consolidate, distribute, cleanup) with an elapsed_ms
field on span close (OBS-03). Spans nest under a top-level sync span so
a single run produces a hierarchical trace.
When consolidate / distribute re-emits a skill, the cause field on
the info! event names why — one of hash changed, previously failed, newly added, or directory now allowed (OBS-04). The final
sync summary block includes a reconcile classification line
(reconcile: N match · M drift · K vanished · L missing-from-machine,
OBS-05) above the cleanup buckets.
PreviouslyFailed and DirectoryNowAllowed causes are documented but
deferred to a future schema bump — the substrate is in place, the emit
sites need a per-skill failure-history field on SkillEntry.
Testing
Unit tests are co-located with each module (#[cfg(test)] mod tests). Integration tests live in crates/tome/tests/ and exercise the binary via assert_cmd — post-HARD-13 (v0.10) the original cli.rs was split into per-domain files (cli_sync.rs, cli_doctor.rs, cli_status.rs, cli_init.rs, cli_make_release.rs, etc.) with shared helpers under tests/common/. Snapshot tests use insta (filtered for tmpdir paths). Tests use tempfile::TempDir and assert_fs::TempDir for filesystem isolation — no cleanup needed.
CI
GitHub Actions runs on both ubuntu-latest and macos-latest: fmt check, clippy with -D warnings, tests, and release build.
AI Coding Tool Landscape
Research into agent file formats (skills, rules, memory, hooks, agents, plugins), invocation methods, context loading strategies, and format differences across AI coding tools — informing tome’s connector architecture.
Last updated: March 2026
1. The Full Taxonomy
AI coding tools have up to seven layers of configuration. Most discussions focus on the first three, but the extended structures (hooks, agents, plugins, MCP) are where the real divergence happens.
| Layer | Purpose | Portable? | Who Has It |
|---|---|---|---|
| Skills | Reusable instructions activated on demand | Yes (SKILL.md standard, 30+ tools) | Claude, Codex, Copilot, Antigravity, Gemini CLI, Cursor, OpenCode, Amp, Goose |
| Rules | Always-on project/global conventions | Partially (markdown, but different filenames/formats) | All tools |
| Memory | Learned context persisted across sessions | No (completely tool-specific) | Claude, Codex, Cursor, Windsurf, Copilot, OpenClaw |
| Hooks | Lifecycle event handlers | No (tool-specific JSON/config) | Claude (12 events), Codex, Windsurf, Amp |
| Agents | Isolated subagents with custom tools/model | No (tool-specific markdown/YAML) | Claude, Codex, Copilot, Cursor, Antigravity |
| Plugins | Bundles of skills + agents + hooks + MCP | No (tool-specific manifests) | Claude, Cursor, Amp |
| MCP Servers | External tool integrations via protocol | Yes (MCP is an open standard) | All major tools |
Key insight: Skills and MCP are the two truly portable layers. Everything else is tool-specific.
2. Tool-by-Tool Breakdown
Claude Code
Vendor: Anthropic | Type: CLI agent | SKILL.md: Full standard + extensions
| Aspect | Details |
|---|---|
| Instruction file | CLAUDE.md (project root, ~/.claude/CLAUDE.md global) |
| Skills | SKILL.md with extended frontmatter (disable-model-invocation, context: fork, agent, hooks, argument-hint) |
| Rules | .claude/rules/ directory (markdown files) |
| Memory | .claude/memory/MEMORY.md (auto-loaded), additional topic files |
| Other files | Plugins (plugin.json), Agents (.claude/agents/*.md), Hooks (hooks.json) |
| Skill discovery | Personal (~/.claude/skills/), Project (.claude/skills/), Plugin, Enterprise, nested .claude/skills/ in subdirectories |
| Invocation | /skill-name (slash command), Skill(skill: "name") (tool call), implicit model invocation |
| Context loading | Description always in context (2% of window budget); full content on invocation; context: fork runs in subagent |
Unique skill extensions beyond the standard:
disable-model-invocation: true— user-only invocationuser-invocable: false— model-only (background knowledge)context: fork+agent: Explore— run skill in isolated subagent`!command`syntax — inject shell output into skill content before sending to model$ARGUMENTS,$0,$1— argument substitutionhooks— lifecycle hooks scoped to the skill
Extended structures:
- Hooks — 12 lifecycle events (SessionStart, PreToolUse, PostToolUse, Stop, etc.) with 3 hook types:
command,prompt,agent. Configured insettings.jsonat global/project/local levels. - Agents —
.claude/agents/*.mdwith YAML frontmatter (11+ fields:tools,model,maxTurns,hooks,mcpServers,permissionMode, etc.). Isolated subagents with own context/tools/model. - Plugins —
plugin.jsonmanifest bundling skills + agents + hooks + MCP + LSP servers + output styles. Marketplace discovery via/plugin. Three install scopes: user/project/local. - Commands —
.claude/commands/*.md(legacy, superseded by skills but still supported). Simple markdown, no frontmatter. - Settings — Three-level hierarchy:
~/.claude/settings.json→.claude/settings.json→.claude/settings.local.json. Permissions, hooks, MCP servers. JSON schema available. - MCP —
.mcp.jsonat project root or in settings. Supports stdio/http/sse. Env var expansion:${VAR},${VAR:-default}.
Codex CLI
Vendor: OpenAI | Type: CLI agent | SKILL.md: Standard + agents/openai.yaml
| Aspect | Details |
|---|---|
| Instruction file | AGENTS.md (project root), AGENTS.override.md takes priority |
| Skills | SKILL.md (standard) + optional agents/openai.yaml for UI metadata and invocation policy |
| Rules | Via AGENTS.md content |
| Memory | Session transcripts in ~/.codex/history.jsonl. Resume subcommand. TUI: /m_update, /m_drop. Initial plumbing in v0.97.0 (Feb 2026). |
| Hooks | “Notify” system — external programs on lifecycle events (e.g., agent-turn-complete). Simpler than Claude’s 12 events. |
| Security | Dual-layer: OS-level sandbox (what’s possible) + approval policy (when to ask). Modes: suggest, auto-edit, full-auto. |
| Skill discovery | 6 levels: CWD .agents/skills/ → parent → repo root → $HOME/.agents/skills/ → /etc/codex/skills/ → built-in |
| Invocation | /skills menu, $skill-name inline mention, implicit matching |
| Context loading | Metadata (name, description, file path) at start; full SKILL.md only when activated |
| Telemetry | OpenTelemetry full lifecycle tracking with event metadata |
agents/openai.yaml adds Codex-specific configuration:
interface:
display_name: "User-facing name"
icon_small: "./assets/logo.svg"
brand_color: "#3B82F6"
policy:
allow_implicit_invocation: false # Disable auto-matching
dependencies:
tools:
- type: "mcp"
value: "toolName"
url: "https://example.com"
Antigravity
Vendor: Google | Type: IDE agent | SKILL.md: Standard
| Aspect | Details |
|---|---|
| Instruction file | GEMINI.md (shared with Gemini CLI) |
| Skills | SKILL.md (standard). Skills directory-based with scripts/, references/, assets/ |
| Rules | Via GEMINI.md content |
| Memory | .gemini/antigravity/brain/ directory for knowledge base |
| Agents | Agent Manager dispatches up to 5 agents simultaneously. Multi-model: Gemini 3 Pro, Claude Sonnet 4.5, GPT-OSS. |
| MCP | MCP Hub with 1,500+ pre-configured servers. UI-driven setup. |
| Skill discovery | Skills directory; semantic matching against descriptions |
| Invocation | Implicit via semantic engine matching prompts to skill descriptions |
| Context loading | Progressive disclosure — registers name + description at start, hydrates full instructions on match |
| Context window | 1M tokens (Gemini 3 Pro backend) |
Key pattern: Antigravity emphasizes narrow, precise descriptions with explicit “do not use” clauses to reduce false activation.
Cursor
Vendor: Anysphere | Type: IDE | SKILL.md: Adopted via agentskills.io (2026)
| Aspect | Details |
|---|---|
| Instruction file | None (rules serve this purpose) |
| Skills | Adopted SKILL.md standard (2026) |
| Rules | .cursor/rules/*.mdc — Markdown Component files with frontmatter |
| Memory | .cursor/rules/learned-memories.mdc for project-specific knowledge. Prompt-level persistence. |
| Agents | .cursor/agents/ — up to 8 parallel subagents via Git worktree isolation |
| Notepads | Persistent context notes referenced with @notepad-name, survive across sessions (beta) |
| Plugins | Marketplace with 10,000+ tools (Agnxi.com). Packages skills, agents, MCP, hooks, rules. |
| MCP | .cursor/mcp.json — separate from other settings |
| Rule format | YAML frontmatter: description, globs (file patterns), alwaysApply (boolean) |
| Limits | 6000 chars per rule file; 12000 chars combined |
| Legacy | .cursorrules single file (deprecated, still supported) |
.mdc rule example:
---
description: Python API conventions
globs: ["*.py", "src/**/*.py"]
alwaysApply: false
---
Use type hints on all function signatures...
Evolution: .cursorrules (2023) → .cursor/ folder with index.mdc (2024) → Multi-file .cursor/rules/*.mdc (2025) → Context-aware rules with MCP integration (2026)
Windsurf
Vendor: Codeium | Type: IDE | SKILL.md: Not documented
| Aspect | Details |
|---|---|
| Instruction file | global_rules.md (global), .windsurf/rules/ (workspace) |
| Skills | No native SKILL.md support documented |
| Rules | .windsurf/rules/ directory with 4 activation modes |
| Memory | Cascade Memories: dual system (auto-generated + user-created). Auto-memories don’t consume credits. Storage: ~/.codeium/windsurf/memories/ |
| Hooks | Cascade Hooks: shell commands at workflow lifecycle points. JSON stdin context. Enterprise distribution via cloud dashboard + MDM deployment (Feb 2026). |
| Legacy | .windsurfrules → .windsurf/rules/rules.md |
| Limits | 6000 chars per rule; 12000 chars combined (global + workspace) |
Activation modes:
| Mode | Behavior |
|---|---|
| Always On | Applied to every interaction |
| Manual | Activated via @-mention |
| Model Decision | AI decides based on natural language description |
| Auto | Applied based on file context |
OpenCode
Vendor: SST (open source) | Type: CLI agent | SKILL.md: Via standard
| Aspect | Details |
|---|---|
| Instruction file | AGENTS.md (project), ~/.config/opencode/AGENTS.md (global) |
| Skills | SKILL.md via Agent Skills standard |
| Rules | Via AGENTS.md |
| Legacy compat | Reads CLAUDE.md as fallback (disable via OPENCODE_DISABLE_CLAUDE_CODE=1) |
| External refs | opencode.json instructions array supports globs: ["docs/*.md", "packages/*/AGENTS.md"] |
| Custom commands | Markdown files in designated directories; filename becomes command ID |
OpenClaw
Vendor: Open source | Type: Autonomous agent | SKILL.md: Supported
| Aspect | Details |
|---|---|
| Instruction file | AGENTS.md (primary instructions) |
| Skills | SKILL.md (compatible with Claude Code / Cursor conventions) |
| Identity | SOUL.md (personality, values, behavior), IDENTITY.md (presentation) |
| User context | USER.md (info about the user) |
| Tools | TOOLS.md (capability declarations) |
| Memory | MEMORY.md + memory/YYYY-MM-DD.md dated files |
| Lifecycle | HEARTBEAT.md (periodic task checklist), BOOTSTRAP.md (startup) |
| Config format | JSON5 (openclaw.json) allowing comments |
OpenClaw has the richest file taxonomy — 8 separate config files loaded at session start into the system prompt. This gives fine-grained control but means more files for tome to discover and potentially sync.
Nanobot (HKUDS)
Vendor: HKUDS (open source) | Type: Lightweight CLI agent | SKILL.md: Via OpenClaw compat
| Aspect | Details |
|---|---|
| Instruction file | AGENTS.md |
| Identity | SOUL.md, USER.md, TOOLS.md, IDENTITY.md |
| Lifecycle | HEARTBEAT.md (checked every 30 min) |
| Memory | memory/MEMORY.md + memory/HISTORY.md |
| Size | ~4000 lines of core code (99% smaller than OpenClaw) |
Nanobot is essentially an OpenClaw-compatible agent in a fraction of the code. Same file conventions, same workspace structure.
PicoClaw
Vendor: Open source | Type: Ultra-lightweight agent | SKILL.md: Not documented
| Aspect | Details |
|---|---|
| Runtime | Single Go binary, <10MB RAM, runs on $10 RISC-V hardware |
| Interface | picoclaw agent -m "prompt" one-shot or interactive mode |
| Config | Minimal — focuses on LLM backend configuration |
| MCP | Supported for tool integration |
PicoClaw prioritizes extreme minimalism. For tome, it would likely be an MCP target rather than a skill directory target.
Gemini CLI
Vendor: Google | Type: CLI agent | SKILL.md: Standard
| Aspect | Details |
|---|---|
| Instruction file | GEMINI.md (plain markdown, no frontmatter required) |
| Discovery | Global (~/.gemini/GEMINI.md) → project root → parent dirs up to .git → subdirectories |
| Imports | @file.md syntax for referencing external content |
| Ignore | Respects .gitignore and .geminiignore |
| Custom naming | settings.json → context.fileName allows alternative file names |
| Memory | /memory show, /memory refresh, /memory add commands |
Extensions (2026): gemini-extension.json packaging prompts, MCP servers, and commands. Extension settings allow user-prompted configuration on install with env var mapping.
Shell execution: !{command} syntax for shell injection with auto-escaping of {{args}}. Argument substitution via {{args}} (not $ARGUMENTS).
Gemini CLI is the simplest format for instructions — plain markdown files concatenated into context. No frontmatter, no structured fields. The @file.md import syntax and !{command} execution are unique.
Skills (2026): Gemini CLI now supports SKILL.md directory scanning. Personal skills at ~/.gemini/skills/ and the portable ~/.agents/skills/ path. For tome, Gemini CLI is a Symlink target via ~/.gemini/skills/.
VS Code Copilot
Vendor: GitHub (Microsoft) | Type: IDE agent | SKILL.md: Full standard (since Jan 2026)
| Aspect | Details |
|---|---|
| Instruction file | .github/copilot-instructions.md (project), %HOME%/copilot-instructions.md (personal) |
| Skills | SKILL.md (full standard since v1.108+). Primary location: .github/skills/, also reads .claude/skills/. Personal: ~/.copilot/skills/. |
| Rules | .github/instructions/*.instructions.md — YAML frontmatter with description (1-500 chars) and applyTo (glob). excludeAgent for targeting. |
| Memory | Copilot Memories (early access, Pro/Pro+ only). Repository-level, auto-deleted after 28 days unless renewed. Includes citations to code locations. |
| Agents | .github/agents/ with tools, prompts, MCP. Two built-in types: coding-agent, code-review. |
| Extensions | Two flavors: Skillsets (lightweight: tools + prompts) and Full agents (autonomous: multi-step, GitHub App). Built via Copilot API. |
| Chat participants | @workspace, @terminal, custom participants via VS Code Extension API. |
| Invocation | /init generates instruction file. Skills matched semantically. |
| Context loading | Conditional: glob match on applyTo, semantic match on descriptions. |
Copilot Workspace (GitHub Next): Running coding agents via GitHub Actions — agent workflows as CI/CD.
Amp
Vendor: Sourcegraph | Type: CLI/IDE agent | SKILL.md: Standard (migrating to)
| Aspect | Details |
|---|---|
| Instruction file | Unknown |
| Skills | SKILL.md standard. Replacing deprecated custom commands and toolboxes (Jan 2026). |
| Hooks | "amp.hooks" settings with events like "tool:post-execute" |
| Migration | .agents/commands/*.md → .agents/skills/*/SKILL.md |
| Key feature | On-demand skill loading — zero tokens until needed (vs toolbox overhead) |
Amp is a useful case study — their migration from custom commands to Agent Skills demonstrates the industry consolidation trend.
Goose
Vendor: Block (Square) | Type: Autonomous agent | SKILL.md: Standard
| Aspect | Details |
|---|---|
| Skills | SKILL.md standard. Scans 6 directories: ~/.config/goose/skills/, ~/.config/agents/skills/, ~/.claude/skills/, and project-level equivalents. |
| Extensions | Six types: Stdio (MCP via pipes), HTTP (MCP via SSE), Builtin (Rust). |
| MCP | Core mechanism — 100+ servers in toolkit catalog. Auto-OAuth on HTTP 401. |
| Config | TOML at ~/.config/goose/ |
Goose now supports SKILL.md directory scanning alongside its MCP-centric extension model. For tome, Goose is a Symlink target via ~/.config/goose/skills/.
Aider
Vendor: Open source | Type: CLI pair programmer | SKILL.md: Not documented
| Aspect | Details |
|---|---|
| Config | .aider.conf.yml in home/repo root/current dir (loaded in order, last wins) |
| Rules | Via config file content |
| Git | --no-verify flag, commit behavior. Known issue: pre-commit hooks not respected. |
Aider is minimal — no skills, no hooks, no agents. Pure configuration-driven.
3. Instruction Files (Rules)
Each tool reads project-level instructions from a differently-named markdown file. The content is plain markdown (no frontmatter) and is always loaded into context.
| Tool | File Name | Global Location | Project Location | Discovery |
|---|---|---|---|---|
| Claude Code | CLAUDE.md | ~/.claude/CLAUDE.md | Project root | Root → parent dirs → global |
| Codex CLI | AGENTS.md | ~/.agents/AGENTS.md | Project root | Root → parent dirs → ~/.agents/ → /etc/codex/ |
| VS Code Copilot | copilot-instructions.md | %HOME%/copilot-instructions.md | .github/copilot-instructions.md | Workspace root only |
| Antigravity | GEMINI.md | ~/.gemini/GEMINI.md | Project root | Root → parent dirs → .git boundary |
| Gemini CLI | GEMINI.md | ~/.gemini/GEMINI.md | Project root | Root → parent dirs → subdirs |
| OpenCode | AGENTS.md | ~/.config/opencode/AGENTS.md | Project root | Falls back to CLAUDE.md |
| OpenClaw | AGENTS.md | — | Workspace dir | + SOUL.md, IDENTITY.md, TOOLS.md, etc. |
| Cursor | (rules only) | — | .cursor/rules/*.mdc | Glob + activation mode |
| Windsurf | global_rules.md | ~/.windsurf/ | .windsurf/rules/ | Activation mode per rule |
What this means for tome
A “rule” that should apply everywhere needs to exist as up to 5 different files:
CLAUDE.md(Claude Code)AGENTS.md(Codex, OpenCode, OpenClaw)GEMINI.md(Antigravity, Gemini CLI).github/copilot-instructions.md(VS Code Copilot).cursor/rules/*.mdcor.windsurf/rules/*.md(IDE-specific)
Symlinks can unify the markdown-based ones, but Cursor/Windsurf require format transforms.
AGENTS.md as open standard
AGENTS.md has emerged as an open instruction-file standard under the Linux Foundation / Agentic AI Foundation. It is adopted by Codex, OpenCode, OpenClaw, and configurable in Gemini CLI — the instruction-file equivalent of the SKILL.md skills standard. The portable path ~/.agents/ (and its skills/ subdirectory) is scanned by Codex, Goose, Gemini CLI, OpenCode, Amp, and Cursor.
4. SKILL.md Standard (agentskills.io)
The Agent Skills format originated at Anthropic in late 2025 and was released as an open standard. It defines a portable way to package reusable instructions, scripts, and resources for AI coding agents. As of February 2026, 27+ tools have adopted it.
Who supports it
| Tool | SKILL.md Support | Extensions Beyond Standard |
|---|---|---|
| Claude Code | Full + extensions | disable-model-invocation, context: fork, agent, hooks, !command, $ARGUMENTS |
| Codex CLI | Standard + openai.yaml | agents/openai.yaml (UI metadata, invocation policy, tool deps) |
| VS Code Copilot | Full (since Jan 2026) | excludeAgent field for targeting coding-agent vs code-review |
| Antigravity | Standard | Semantic matching emphasis |
| Cursor | Adopted (2026) | — |
| OpenCode | Standard | — |
| OpenClaw | Compatible | — |
| Gemini CLI | Standard | Scans ~/.gemini/skills/ and ~/.agents/skills/ |
| Goose | Standard | Scans 6 dirs including ~/.config/goose/skills/, ~/.config/agents/skills/, ~/.claude/skills/ |
| Amp | Standard (migrating to) | Scans ~/.config/amp/skills/, ~/.config/agents/skills/, .claude/skills/ |
| Windsurf | Not documented | Uses native rules format |
Invocation methods
| Tool | Invocation | Implicit | Explicit | Extra Config |
|---|---|---|---|---|
| Claude Code | Slash + Tool | Yes (description matching) | /name, Skill(skill: "name") | Plugins, hooks, agents |
| Codex CLI | Menu + Mention | Yes (unless disabled) | /skills, $name | agents/openai.yaml |
| VS Code Copilot | Semantic | Yes (description matching) | Via chat | .github/agents/, Extensions |
| Antigravity | Semantic | Yes (semantic matching) | Not documented | Agent Manager |
| Cursor | Unknown | Unknown | Unknown | Notepads, plugins |
| Windsurf | — | — | — | Cascade hooks |
| OpenCode | Unknown | Unknown | Unknown | opencode.json |
Required frontmatter
---
name: my-skill # 1-64 chars, lowercase + hyphens, must match directory name
description: | # 1-1024 chars. When to use this skill.
What it does and when the agent should activate it.
---
Optional frontmatter
license: Apache-2.0
metadata:
author: example-org
version: "1.0"
compatibility: Requires poppler-utils
allowed-tools: Read Grep Bash(git:*)
Skill directory structure
skill-name/
├── SKILL.md # Required — instructions + frontmatter
├── scripts/ # Optional — executable code
├── references/ # Optional — detailed docs loaded on demand
└── assets/ # Optional — templates, data files
Discovery paths
| Tool | Personal Skills | Project Skills |
|---|---|---|
| Claude Code | ~/.claude/skills/ | .claude/skills/ + nested subdirs |
| Codex CLI | $HOME/.agents/skills/ | .agents/skills/ → parent → repo root |
| VS Code Copilot | ~/.copilot/skills/ | .github/skills/ + .claude/skills/ |
| Antigravity | ~/.gemini/antigravity/skills/ | .gemini/skills/, .agents/skills/ |
| Gemini CLI | ~/.gemini/skills/ | ~/.agents/skills/ |
| Goose | ~/.config/goose/skills/ | ~/.config/agents/skills/, ~/.claude/skills/ |
| Amp | ~/.config/amp/skills/ | ~/.config/agents/skills/, .claude/skills/ |
| OpenCode | ~/.config/opencode/skills/ | ~/.claude/skills/, ~/.agents/skills/ |
5. Parsing Differences (The Details That Break Things)
5.1 YAML Frontmatter
Delimiters: All tools require --- (three hyphens) at start and end.
Unknown fields: Silently ignored by all tools following the Agent Skills standard. Claude Code has occasionally thrown errors on unexpected keys in non-standard positions.
Case sensitivity: All field names are case-sensitive and must be lowercase. SKILL.md filename must be exact uppercase — skill.md won’t be discovered.
Multiline descriptions — MAJOR GOTCHA:
Claude Code’s YAML parser breaks on Prettier-formatted multiline descriptions:
# BROKEN — Claude Code can't parse this (Prettier-wrapped):
---
description: This is a long description that Prettier
wraps across multiple lines without a block scalar
---
# WORKS — single line:
---
description: This is a long description kept on one line # prettier-ignore
---
# WORKS — explicit block scalar:
---
description: |
This is a long description using
a YAML block scalar indicator.
---
Other tools (Codex, Cursor, Windsurf, Gemini CLI) handle standard YAML multiline correctly.
Workaround: Keep descriptions single-line, or use # prettier-ignore comment, or disable Prettier’s proseWrap for SKILL.md files.
5.2 Markdown Body
Code blocks: All tools prefer triple backticks with language tags. Indented code blocks (4 spaces) work but lack syntax highlighting.
XML tags: Claude is fine-tuned to recognize XML tags (<example>, <system-reminder>, etc.) as structural elements. No other tool does this. Skills that rely on XML structure for Claude won’t parse the same way in Codex/Copilot.
Shell execution in content:
| Syntax | Tool | Behavior |
|---|---|---|
`!command` | Claude Code | Executes bash, injects output into skill content |
!{command} | Gemini CLI | Executes shell with auto-escaping of {{args}} |
| — | All others | No shell execution in skill content |
Argument substitution:
| Syntax | Tool |
|---|---|
$ARGUMENTS, $0, $1 | Claude Code |
{{args}} | Gemini CLI |
| — | All others (no substitution) |
Claude Code parser bug: ! inside inline code backticks can be misinterpreted as a bash command. Avoid ! in code spans within SKILL.md files meant for Claude Code.
5.3 Rules Formats (Cursor & Windsurf)
Cursor .mdc files:
---
description: Python API conventions
globs: ["*.py", "src/**/*.py"]
alwaysApply: false
---
Use type hints on all function signatures...
Four activation modes:
| Mode | Frontmatter | When Applied |
|---|---|---|
| Always | alwaysApply: true | Every interaction |
| Auto-Attach | globs defined | When active file matches glob |
| Agent Requested | description only | AI decides based on description |
| Manual | None | Must be @-mentioned |
Windsurf rules:
Four activation modes: Manual (@-mention), Model Decision (AI decides), Glob (file pattern), Always On.
Limits: Both Cursor and Windsurf enforce 6,000 chars per rule file, 12,000 chars combined. Content beyond the limit is silently truncated.
5.4 VS Code Copilot .instructions.md
---
description: 'Purpose of these instructions (1-500 chars)'
applyTo: '**/*.py'
---
Natural language instructions here...
descriptionandapplyToare the main frontmatter fieldsexcludeAgent: "code-review"or"coding-agent"for agent targeting- No char limit documented, but recommended to stay under 2 pages
- Glob patterns in
applyTouse standard glob syntax
5.5 File Encoding
UTF-8: All tools assume UTF-8. Claude Code has documented bugs with UTF-8 corruption (especially CJK characters via MultiEdit tool). Non-UTF-8 files (Windows-1252) get silently corrupted.
BOM: Use UTF-8 without BOM. VS Code can handle BOM but other tools may not.
Line endings: Use LF (\n). Cursor has a known bug converting CRLF → LF. Enforce via .gitattributes.
Skill names: Must be [a-z0-9-]+ (lowercase alphanumeric + hyphens). No emoji, no unicode, no uppercase.
6. Memory & Persistence
Memory is the least portable layer — every tool has its own mechanism with zero interoperability.
Claude Code
| Aspect | Details |
|---|---|
| Location | ~/.claude/projects/<project-hash>/memory/ |
| Auto-loaded | First 200 lines of MEMORY.md injected into system prompt every session |
| Topic files | Additional *.md files in memory dir, loaded on demand |
| Who writes | Both the agent (auto-memory) and user (manual edits) |
| Opt-in | Set CLAUDE_CODE_DISABLE_AUTO_MEMORY=0 to enable |
Codex CLI
| Aspect | Details |
|---|---|
| Location | ~/.codex/history.jsonl |
| Mechanism | Session transcripts, resume subcommand |
| TUI commands | /m_update, /m_drop for memory management |
| Status | Initial memory plumbing in v0.97.0 (Feb 2026) — still evolving |
Cursor
| Aspect | Details |
|---|---|
| Location | .cursor/rules/learned-memories.mdc |
| Mechanism | Rules-based — .mdc files with YAML frontmatter |
| Persistence | Prompt-level, not true cross-session memory |
| Known issue | Different LLMs interpret .mdc rules inconsistently |
Windsurf
| Aspect | Details |
|---|---|
| Location | ~/.codeium/windsurf/memories/ |
| Mechanism | Dual: auto-generated (Cascade AI) + user-created |
| Auto-memories | Don’t consume credits — major advantage |
| Retrieval | Cascade AI decides what’s relevant per conversation |
Antigravity
| Aspect | Details |
|---|---|
| Location | .gemini/antigravity/brain/ |
| Mechanism | Knowledge base directory, multi-agent sharing |
| Context window | 1M tokens (Gemini 3 Pro backend) |
VS Code Copilot
| Aspect | Details |
|---|---|
| Feature | Copilot Memories (early access, Pro/Pro+ only) |
| Scope | Repository-level (not user-specific) |
| Lifecycle | Auto-deleted after 28 days unless renewed by use |
| Citations | Each memory references specific code locations |
OpenClaw / Nanobot
| Aspect | Details |
|---|---|
| Location | memory/MEMORY.md + memory/YYYY-MM-DD.md dated files |
| HEARTBEAT.md | Periodic task checklist (safe to run every 30 min) |
| Design | Prevents cross-agent collection clobbering with dated files |
Summary Table
| Tool | Storage | Auto-Load | Who Writes | Cross-Session |
|---|---|---|---|---|
| Claude Code | memory/MEMORY.md | First 200 lines | Agent + user | Yes |
| Codex CLI | history.jsonl | N/A | System | Partial (resume) |
| Cursor | .mdc rules | By activation mode | User | Prompt-level |
| Windsurf | Cascade Memories | AI-selected | AI + user | Yes |
| Antigravity | brain/ directory | Knowledge base | Unknown | Unknown |
| VS Code Copilot | Copilot Memories | AI-selected | AI | Yes (28-day expiry) |
| OpenClaw | memory/*.md | Optional | Agent + user | Yes |
7. Context Loading Strategies
How each tool manages token budget:
| Tool | Strategy | Session Start Cost | On-Demand | Token Budget |
|---|---|---|---|---|
| Claude Code | Progressive disclosure | ~100 tokens/skill (name + description only) | Full SKILL.md on invocation | 2% of window for skill metadata |
| Codex CLI | Progressive disclosure | ~50-100 tokens/skill metadata | Full SKILL.md on activation | Unknown |
| VS Code Copilot | Conditional loading | Matching instructions only | Skills on semantic match | Unknown |
| Antigravity | Register → hydrate | Name + description | Full SKILL.md on semantic match | ~100 tokens/skill |
| Cursor | Glob-based loading | All matching rules fully loaded | — | 12k chars total |
| Windsurf | Mode-based loading | “Always On” rules fully loaded | Manual/Model rules on trigger | 12k chars total |
| Gemini CLI | All-at-once | All GEMINI.md files concatenated | — | Variable |
| OpenClaw | All-at-once | All 8 config files loaded | Skills on demand | Variable |
The key difference: SKILL.md-based tools use progressive disclosure (metadata → body → resources), while rules-based tools (Cursor, Windsurf) front-load everything up to their char limits.
Progressive Disclosure Flow
Skills use a three-tier loading strategy to minimize context window consumption:
| Tier | What loads | When | Token cost |
|---|---|---|---|
| Metadata | name + description from frontmatter | Session start, for all skills | ~100 tokens per skill |
| Instructions | Full SKILL.md body | When skill is activated | <5000 tokens recommended |
| Resources | Files in scripts/, references/, assets/ | Only when referenced during execution | Variable |
graph LR
subgraph "Session Start (~100 tokens/skill)"
A["Scan skill directories"]
B["Read frontmatter only<br/>(name + description)"]
end
subgraph "Task Matching"
C{"User prompt matches<br/>skill description?"}
D["Skill stays dormant"]
end
subgraph "Activation (<5000 tokens)"
E["Load full SKILL.md body"]
F["Execute instructions"]
end
subgraph "On Demand (variable)"
G["Load references/<br/>scripts/ assets/"]
end
A --> B --> C
C -- No --> D
C -- Yes --> E --> F
F -. "if needed" .-> G
8. MCP vs Skills: Efficiency
The Token Problem
MCP servers add tool definitions to context at session start. Each tool includes its name, description, parameter schema, and usage hints — all in natural language so the model understands when and how to use them.
| Metric | MCP Servers | Skills |
|---|---|---|
| Session start overhead | ~55,000 tokens (typical 2-3 servers) | ~100 tokens per skill (metadata only) |
| Per-tool cost | Full schema always in context | Full instructions only when activated |
| Scaling | Degrades at 2-3 servers (accuracy drops) | Hundreds of skills with minimal overhead |
| Cost multiplier | Baseline | ~3x cheaper for equivalent functionality |
When to Use Which
| Use Case | Best Approach | Why |
|---|---|---|
| External API calls | MCP | Skills can’t make HTTP requests; MCP servers can |
| Database queries | MCP | Requires authenticated connections |
| Coding conventions | Skills | Pure instructions, no external calls needed |
| Deployment workflows | Skills | Step-by-step instructions + shell scripts |
| File format knowledge | Skills | Reference material loaded on demand |
| Real-time data | MCP | Needs live connections |
They’re complementary, not competitive. MCP provides capabilities (tools the agent can call). Skills provide knowledge (instructions the agent follows). A skill can even declare MCP tool dependencies in its frontmatter.
Progressive Disclosure is the Key
The fundamental difference: skills let agents load context incrementally based on what’s actually needed, while MCP front-loads everything. For a library of 50 skills, progressive disclosure means ~5000 tokens at session start vs. potentially hundreds of thousands for equivalent MCP tool definitions.
9. Hooks & Lifecycle Events
Hooks let tools run shell commands or logic at specific points in the agent lifecycle. This is the fastest-growing area of divergence.
Claude Code — 12 Events, 3 Hook Types
Location: ~/.claude/settings.json, .claude/settings.json, .claude/settings.local.json
Events:
| Event | When | Common Use |
|---|---|---|
SessionStart | Session begins | Load environment, log start |
PreToolUse | Before any tool executes | Validate, block dangerous commands |
PostToolUse | After tool completes | Lint, format, log |
PostToolUseFailure | Tool execution fails | Error reporting |
PermissionRequest | Permission dialog appears | Auto-approve/deny patterns |
UserPromptSubmit | User submits prompt | Pre-process, inject context |
Notification | Agent needs attention | Desktop notifications |
Stop | Agent finishes responding | Summarize, commit |
SubagentStart | Subagent spawns | Track agent tree |
SubagentStop | Subagent finishes | Collect results |
PreCompact | Before context compaction | Save state |
SessionEnd | Session ends | Cleanup, log |
Hook types:
| Type | Mechanism | Use Case |
|---|---|---|
command | Run shell command, receive JSON on stdin | Linting, formatting, git hooks |
prompt | Send prompt to Claude for evaluation | Policy enforcement, content review |
agent | Spawn subagent with tools (Read, Grep, Glob) | Complex validation, code analysis |
Matchers target specific tools:
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash(npm run *)",
"type": "command",
"command": "echo 'npm command detected'"
}]
}
}
Patterns support: exact ("Bash"), specifier ("Bash(npm run lint)"), wildcards ("Bash(curl *)"), regex-like ("mcp__.*__write.*").
Exit codes: 0 = success, 2 = block action (stderr becomes error message).
Codex CLI — Notify Hooks
Location: Configuration or CLI flags
Codex has a simpler hook system called “notify”:
- Executes external programs on lifecycle events (e.g.,
agent-turn-complete) - Less granular than Claude’s 12 events
- Focused on notification rather than validation/blocking
Windsurf — Cascade Hooks
Location: Settings/configuration
- Shell commands at workflow lifecycle points
- Receives JSON context via stdin (similar to Claude)
- Supports user prompt events and policy violation blocking
- Enterprise distribution via cloud dashboard + MDM deployment (Feb 2026)
Amp — Tool Execution Hooks
Location: Settings ("amp.hooks")
{
"amp.hooks": {
"tool:post-execute": "npm run lint"
}
}
- Event format:
"tool:post-execute" - Simpler than Claude’s matcher system
Other Tools
| Tool | Hooks? | Notes |
|---|---|---|
| VS Code Copilot | No | Extensions serve a similar role |
| Cursor | No | Plugin system handles automation |
| Antigravity | No | Agent Manager handles orchestration |
| Gemini CLI | No | Extension settings provide some lifecycle config |
| OpenClaw | No | HEARTBEAT.md is the closest analogue (periodic, not event-driven) |
| Aider | Partial | Git pre-commit hooks, but not agent lifecycle hooks |
| Goose | No | Extension system handles tool integration |
Cross-Tool Hook Comparison
| Feature | Claude Code | Codex CLI | Windsurf | Amp |
|---|---|---|---|---|
| Events | 12 | Few (notify) | Several | tool:post-execute |
| Can block actions | Yes (exit 2) | No | Yes (policy) | No |
| JSON stdin | Yes | Unknown | Yes | Unknown |
| Tool matchers | Wildcards + regex | No | Unknown | No |
| Hook types | command, prompt, agent | command | command | command |
| Scope | Global + project + local | Unknown | Global + enterprise | Settings |
10. Agents & Subagents
Agents are isolated execution contexts with their own tools, model, and permissions. This is distinct from skills (which provide instructions within the main context).
Claude Code — Most Mature Agent System
Location: ~/.claude/agents/*.md (global), .claude/agents/*.md (project)
Format: YAML frontmatter + markdown body
---
name: code-reviewer
description: Reviews code for quality and best practices
tools: [Read, Glob, Grep]
model: sonnet
maxTurns: 10
---
You are a code reviewer focused on...
Frontmatter fields (11+):
| Field | Purpose |
|---|---|
name | Agent identifier (required) |
description | What the agent does (required) |
tools | Allowlist of tools |
disallowedTools | Denylist of tools |
model | sonnet, opus, haiku, or inherit |
permissionMode | Permission behavior for this agent |
mcpServers | MCP servers to enable |
hooks | Hooks active only while agent runs |
maxTurns | Maximum conversation turns |
skills | Skills available to the agent |
memory | Memory scope: user, project, or local |
Key difference from skills: Agents run in isolated context with their own model and tool restrictions. Skills inject instructions into the current context.
VS Code Copilot — Custom Agents
Location: .github/agents/
GitHub Copilot supports custom agents with:
- Custom tools and prompts
- MCP server access
- Agent targeting via
excludeAgentfield in instructions - Two built-in agent types:
coding-agentandcode-review
Cursor — Parallel Subagents
Location: .cursor/agents/
- Up to 8 parallel agents via Git worktree isolation
- Agents get their own worktree branch for conflict-free parallel work
- Configured similarly to Claude agents
Antigravity — Agent Manager
- Dispatches up to 5 agents simultaneously on separate features
- Multi-model support (Gemini 3 Pro, Claude Sonnet 4.5, GPT-OSS)
- Agent Manager UI for orchestration (not file-based configuration)
- Claims 5-10x productivity from parallel agent execution
Codex CLI — Sandbox Agents
Codex takes a security-first approach:
- Dual-layer security: OS-level sandbox (what’s possible) + approval policy (when to ask)
- Three approval modes:
suggest(read-only),auto-edit(edits approved, commands need approval),full-auto - Agents run within sandbox constraints
OpenClaw/Nanobot — Workspace Files as “Agent Personality”
Rather than defining subagents, OpenClaw defines the main agent’s personality via 8 workspace files:
| File | Purpose |
|---|---|
AGENTS.md | Primary instructions (equivalent to CLAUDE.md) |
SOUL.md | Behavioral core — personality, ethics, communication style |
IDENTITY.md | Structured profile — name, role, goals |
TOOLS.md | Environment quirks, path conventions, risky commands |
USER.md | Info about the human user |
MEMORY.md | Persistent learned context |
HEARTBEAT.md | Periodic maintenance rituals (configurable cadence, e.g., every 30 min) |
BOOTSTRAP.md | First-run interview script |
This is philosophically different — OpenClaw treats the AI as an entity with personality and rituals, rather than a tool with configurations.
Cross-Tool Agent Comparison
| Feature | Claude Code | Copilot | Cursor | Antigravity | Codex |
|---|---|---|---|---|---|
| Agent config format | YAML + MD | YAML + MD | YAML + MD | UI-based | Sandbox policy |
| Parallel execution | Yes (Task tool) | Yes | 8 agents (worktrees) | 5 agents | Unknown |
| Model selection | Per-agent | No | Unknown | Multi-model | No (GPT only) |
| Tool restrictions | Per-agent | Per-agent | Unknown | Unknown | Sandbox-level |
| Isolated context | Yes | Yes | Yes (worktree) | Yes | Yes (sandbox) |
| File location | .claude/agents/ | .github/agents/ | .cursor/agents/ | UI | N/A |
11. Plugins & Extensions
Plugins bundle multiple configuration objects (skills, agents, hooks, MCP servers) into a single installable package.
Claude Code — Plugin Ecosystem
Location: .claude-plugin/plugin.json at plugin root
Manifest format:
{
"name": "my-plugin",
"version": "1.0.0",
"description": "Plugin description",
"author": { "name": "Author", "email": "dev@example.com" },
"commands": "./commands/",
"agents": "./agents/",
"skills": ["skill1", "skill2"],
"hooks": "./hooks.json",
"mcpServers": "./.mcp.json",
"lspServers": "./.lsp.json",
"outputStyles": "./styles/"
}
What plugins can contain: Skills, agents, hooks, commands (legacy), MCP servers, LSP servers, output styles.
Discovery: /plugin command → Discover tab. Official + community marketplaces. Three installation scopes: user (default), project, local.
Note: Manifest is optional — Claude Code auto-discovers components if absent.
Cursor — Plugin Marketplace
- Packages skills, subagents, MCP servers, hooks, rules into single install
- 10,000+ tools on Agnxi.com marketplace
- 1,800+ MCP servers available
VS Code Copilot — Extensions
Two flavors:
- Skillsets — lightweight: tools, prompts, knowledge
- Full agents — autonomous: multi-step workflows, GitHub App integration
Built as GitHub Apps using the Copilot API. Chat participants (@workspace, @terminal) are built-in extensions.
Gemini CLI — Extensions
Location: Extension directory with gemini-extension.json
{
"name": "my-extension",
"prompts": ["./prompts/"],
"mcpServers": { ... },
"commands": ["./commands/"]
}
Extension settings (2026): User-prompted configuration on install with environment variable mapping.
Goose — Six Extension Types
| Type | Mechanism | Lifecycle |
|---|---|---|
| Stdio | MCP via stdio pipes | Goose manages |
| HTTP | MCP via SSE | External process |
| Builtin | Rust compiled into binary | Always available |
100+ MCP servers in toolkit catalog. Auto-OAuth on 401 for HTTP extensions.
Amp — Skills Migration
Amp (Sourcegraph) is actively consolidating:
- Deprecated (Jan 2026): Custom commands, toolboxes
- Replacing with: Agent Skills (SKILL.md standard)
- Migration path:
.agents/commands/*.md→.agents/skills/*/SKILL.md - Key motivation: on-demand loading (zero tokens until needed) vs toolbox overhead
Cross-Tool Plugin Comparison
| Feature | Claude Code | Cursor | Copilot | Gemini CLI | Goose |
|---|---|---|---|---|---|
| Format | plugin.json | Unknown | GitHub App | gemini-extension.json | TOML config |
| Marketplace | Yes | Yes (10k+) | GitHub Marketplace | No | Toolkit catalog |
| Contains skills | Yes | Yes | Yes (skillsets) | Yes (prompts) | No |
| Contains agents | Yes | Yes | Yes | No | No |
| Contains hooks | Yes | Unknown | No | No | No |
| Contains MCP | Yes | Yes | No (separate) | Yes | Core mechanism |
| Install scopes | user/project/local | Unknown | Org/repo | User | User |
12. MCP Server Configuration
MCP (Model Context Protocol) is the most universally supported integration mechanism — every major tool supports it.
Configuration Formats
| Tool | Config File | Location | Transport |
|---|---|---|---|
| Claude Code | .mcp.json | Project root or ~/.claude/ settings | stdio, http, sse |
| Codex CLI | Config / CLI flags | Unknown | stdio, http |
| VS Code Copilot | Settings | .vscode/settings.json or mcp.json | stdio, http |
| Cursor | .cursor/mcp.json | Project .cursor/ dir | stdio, sse |
| Windsurf | Settings | Windsurf settings | stdio |
| Antigravity | MCP Hub | Settings panel | stdio, http |
| Gemini CLI | settings.json | ~/.gemini/settings.json | stdio, http |
| OpenClaw | openclaw.json | JSON5 config | stdio |
| Goose | Config | ~/.config/goose/ | stdio, http (SSE) |
Claude Code MCP Config
{
"mcpServers": {
"server-name": {
"command": "node",
"args": ["path/to/server.js"],
"env": {
"API_KEY": "${API_KEY}"
}
}
}
}
Environment variable expansion: ${VAR} (required), ${VAR:-default} (optional), ${CLAUDE_PLUGIN_ROOT} (plugin-relative).
Key Differences
- Antigravity: MCP Hub with 1,500+ pre-configured servers — UI-driven setup
- Goose: MCP is the primary extension mechanism (not just an add-on)
- Claude Code: Most flexible — supports project, global, and plugin-scoped MCP configs
- Cursor: Stored in
.cursor/mcp.jsonseparate from other settings
13. Settings & Permission Systems
Claude Code — Three-Level Settings
Hierarchy (last wins): ~/.claude/settings.json → .claude/settings.json → .claude/settings.local.json
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": ["Bash(npm run lint)", "Read(~/.zshrc)"],
"ask": ["Bash(curl *)"],
"deny": ["Read(./.env)", "Edit(.env*)"]
},
"hooks": { ... },
"mcpServers": { ... },
"model": "sonnet",
"maxTurns": 25
}
Permission modes: ask (default), acceptEdits, plan, bypassPermissions (“YOLO”).
Automatic timestamped backups (5 most recent retained).
Codex CLI — Dual-Layer Security
| Layer | Controls | Options |
|---|---|---|
| Sandbox | What’s possible | OS-level isolation, network restrictions |
| Approval | When to ask | suggest (read-only), auto-edit, full-auto |
Cursor — Settings in .cursor/
.cursor/rules/*.mdcfor rules (covered in section 5.3).cursor/mcp.jsonfor MCP servers.cursor/agents/for agent definitions- Notepads: persistent context notes referenced with
@, survive across sessions (beta)
Windsurf — Enterprise Distribution
- Cloud dashboard for enterprise hook/rule distribution
- MDM deployment support (Feb 2026)
- Policy enforcement via Cascade hooks
Gemini CLI — Extension Settings
~/.gemini/settings.json:
{
"context": { "fileName": "GEMINI.md" },
"mcpServers": { ... }
}
Supports custom naming for context files. Extension settings (2026) allow user-prompted configuration on install.
14. Unique Structures by Tool
Some tools have first-class configuration objects that exist nowhere else.
OpenClaw’s Behavioral Workspace
OpenClaw’s 8-file system is philosophically unique — it treats the AI agent as having personality and rituals:
| File | Analogue in Other Tools | What Makes It Unique |
|---|---|---|
SOUL.md | None | Personality, ethics, communication style |
IDENTITY.md | None | Name, role, goals as structured profile |
HEARTBEAT.md | Cron job / hook | Periodic maintenance rituals with configurable cadence |
BOOTSTRAP.md | None | First-run interview script |
TOOLS.md | Settings permissions | Environment quirks, risky command warnings |
USER.md | Memory | Structured info about the human user |
Cursor Notepads (Beta)
Persistent context notes that:
- Are referenced with
@notepad-namein chat - Survive across sessions
- Act like pinned context without consuming always-on token budget
- Distinct from rules (which activate automatically) and skills (which activate on match)
Copilot Workspace (GitHub Next)
Running coding agents via GitHub Actions — agent workflows as CI/CD:
- Agent gets a PR, makes changes, runs tests
- Operates in GitHub’s infrastructure, not local machine
- Distinct from Copilot Chat / VS Code integration
Goose Auto-OAuth
HTTP extensions automatically handle OAuth flows on 401 responses — no manual token management.
Antigravity Multi-Model
Agent Manager supports dispatching agents on different LLM backends simultaneously:
- Gemini 3 Pro, Claude Sonnet 4.5, GPT-OSS
- Choose model per agent based on task characteristics
15. Full Cross-Tool Comparison Matrix
| Structure | Claude Code | Codex CLI | Copilot | Cursor | Windsurf | Antigravity | Gemini CLI | OpenClaw | Amp | Goose | Aider |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Skills (SKILL.md) | Full+ | Std+ | Full | Adopted | — | Std | — | Compat | Std | — | — |
| Instruction file | CLAUDE.md | AGENTS.md | copilot-instructions.md | — | global_rules.md | GEMINI.md | GEMINI.md | AGENTS.md | — | — | — |
| Rules dir | .claude/rules/ | — | .github/instructions/ | .cursor/rules/ | .windsurf/rules/ | — | — | — | — | — | — |
| Memory | MEMORY.md | history.jsonl | Copilot Memories | learned-memories.mdc | Cascade | brain/ | /memory | MEMORY.md + dated | — | — | — |
| Hooks | 12 events | notify | — | — | Cascade hooks | — | — | HEARTBEAT.md | tool:post-execute | — | — |
| Agents | .claude/agents/ | sandbox | .github/agents/ | .cursor/agents/ | — | Agent Manager | — | SOUL.md etc. | — | — | — |
| Plugins | plugin.json | — | Extensions | Marketplace | — | — | gemini-extension.json | — | — | Extensions | — |
| MCP | .mcp.json | Supported | Supported | .cursor/mcp.json | Supported | MCP Hub | settings.json | openclaw.json | Supported | Core | — |
| Settings | settings.json | CLI flags | VS Code settings | .cursor/ | Settings | Settings | settings.json | JSON5 config | Settings | TOML | .aider.conf.yml |
| Unique | Output styles, LSP | Sandbox policy, OTel | Chat participants, Workspace | Notepads | Enterprise MDM | Multi-model | @file imports | SOUL/HEARTBEAT/BOOTSTRAP | — | Auto-OAuth | Git integration |
Legend: Full+ = standard with extensions, Std+ = standard with extra config, Std = standard, Compat = compatible, Adopted = recently added, — = not supported
16. Diagrams
Format Family Tree
graph TD
Standard["Agent Skills Standard<br/>(agentskills.io)"]
subgraph "SKILL.md Family"
CC["Claude Code<br/>(standard + extensions)"]
Codex["Codex CLI<br/>(standard + openai.yaml)"]
AG["Antigravity<br/>(standard)"]
OC_skill["OpenCode<br/>(standard)"]
Cursor_skill["Cursor<br/>(adopted 2026)"]
Copilot_skill["VS Code Copilot<br/>(full, Jan 2026)"]
Amp_skill["Amp<br/>(migrating to)"]
end
subgraph "AGENTS.md Family"
Codex_agents["Codex CLI"]
OC_agents["OpenCode<br/>(CLAUDE.md fallback)"]
OClaw["OpenClaw<br/>(+ SOUL.md, IDENTITY.md, ...)"]
Nano["Nanobot<br/>(OpenClaw subset)"]
end
subgraph "Custom Rules"
Cursor_rules["Cursor<br/>(.mdc with globs)"]
Windsurf_rules["Windsurf<br/>(4 activation modes)"]
Copilot_rules["VS Code Copilot<br/>(.instructions.md with applyTo)"]
end
subgraph "Plain Markdown"
Claude_md["Claude Code<br/>(CLAUDE.md)"]
Gemini_md["Gemini CLI<br/>(GEMINI.md + @imports)"]
Copilot_md["VS Code Copilot<br/>(copilot-instructions.md)"]
end
subgraph "MCP-Only"
Goose_mcp["Goose<br/>(6 extension types)"]
Pico_mcp["PicoClaw"]
end
Standard --> CC
Standard --> Codex
Standard --> AG
Standard --> OC_skill
Standard --> Cursor_skill
Standard --> Copilot_skill
Standard --> Amp_skill
OClaw --> Nano
tome Connector Mapping
graph LR
subgraph "Source Connectors"
S1["Claude Plugins<br/>(installed_plugins.json)"]
S2["SKILL.md directories"]
S3["Cursor .mdc rules"]
S4["Windsurf rules"]
S5["OpenClaw workspace"]
S6["Copilot .instructions.md"]
end
subgraph "tome Library"
L["Canonical format<br/>(SKILL.md standard)"]
end
subgraph "Target Connectors"
T1["Symlink targets<br/>(Claude, Codex, Antigravity,<br/>OpenClaw, Copilot, OpenCode, Amp)"]
T2["MCP targets<br/>(Goose, PicoClaw)"]
T3["Format transform targets<br/>(Cursor .mdc, Windsurf rules,<br/>Copilot .instructions.md)"]
end
S1 --> L
S2 --> L
S3 -. "transform<br/>.mdc → SKILL.md" .-> L
S4 -. "transform<br/>rules → SKILL.md" .-> L
S5 --> L
S6 -. "transform<br/>.instructions.md → SKILL.md" .-> L
L --> T1
L --> T2
L -. "transform<br/>SKILL.md → native" .-> T3
17. Guidelines for Writing Portable Skills
Do
- Keep descriptions single-line to avoid Claude Code’s YAML multiline parser bug
- Stay under 5,000 tokens per SKILL.md body (recommended by agentskills.io)
- Stay under 6,000 chars if you also target Cursor/Windsurf
- Use
[a-z0-9-]+for skill names — lowercase, hyphens only, matching directory name - Use triple-backtick code blocks with language tags
- Use UTF-8 without BOM, LF line endings
- Include trigger keywords in descriptions so semantic matching works across tools
- Move detailed content to
references/for progressive disclosure - Version control your skills — they’re the most portable artifact
- Stick to standard frontmatter fields:
name,description,license,metadata,compatibility,allowed-tools
Don’t
- Don’t rely on XML tags for structure — only Claude parses them
- Don’t use
!commandor$ARGUMENTSin skills meant for multiple tools - Don’t put emoji or unicode in skill names (descriptions are fine)
- Don’t assume multiline YAML works — test across tools
- Don’t put secrets in skills/rules — they’re version-controlled markdown
- Don’t use tool-specific frontmatter (
disable-model-invocation,agents/openai.yaml,globs,alwaysApply) in cross-platform skills — move these to tool-specific config - Don’t exceed 200 lines for auto-loaded memory files (Claude truncates beyond that)
The Portability Hierarchy
Most portable ──────────────────────────── Least portable
SKILL.md Instruction files Memory
(agentskills.io) (CLAUDE.md, etc.) (tool-specific)
20+ tools Symlink across 3-4 Zero interop
Same format Cursor/Windsurf need Every tool different
Same directory format transforms File, DB, or API
structure
Tool-Specific Features to Use Sparingly
| Feature | Tool | Portable Alternative |
|---|---|---|
context: fork | Claude Code | None — unique to Claude |
agents/openai.yaml | Codex CLI | Standard SKILL.md metadata |
globs / alwaysApply | Cursor | Description-based semantic matching |
| Activation modes | Windsurf | Description-based semantic matching |
@file imports | Gemini CLI | references/ directory |
!command execution | Claude Code | scripts/ directory |
$ARGUMENTS | Claude Code | Agent-level argument handling |
excludeAgent | VS Code Copilot | None — unique to Copilot |
SOUL.md, HEARTBEAT.md | OpenClaw | SKILL.md + memory |
18. Common Pitfalls
Dead Rules
Path globs break after refactoring. Renamed directories cause rules to silently stop matching. Audit regularly.
Memory Poisoning
Auto-generated memories can be manipulated (prompt injection via committed files). Review auto-memory content before trusting it.
Size Bloat
Auto-memories grow unbounded. Large instruction files consume context budget, leaving less room for actual conversation. Claude Code’s 200-line auto-load limit is a safeguard.
LLM Inconsistency
Cursor rules behave differently depending on which LLM backend is active. The same .mdc rule may work with Claude but fail with GPT-4. Agent Skills are more consistent because the SKILL.md body is pure natural language.
Migration Pain
No tool provides automatic format conversion. Moving from .cursorrules to SKILL.md, or from Windsurf rules to anything else, requires manual work. This is the gap tome aims to fill.
19. What This Means for tome
Format Families to Support
Based on this research, tome’s connector architecture needs to handle four format families:
| Family | Tools | Distribution Method | Translation Needed |
|---|---|---|---|
| SKILL.md standard | Claude Code, Codex, Copilot, Antigravity, OpenClaw, OpenCode, Amp | Symlink (same format) | No — canonical format |
| Custom rules | Cursor (.mdc), Windsurf (activation modes), Copilot (.instructions.md) | Copy with transform | Yes — SKILL.md ↔ native rules |
| MCP-only | Goose, PicoClaw | MCP config injection | No transform, just config entry |
| Config-only | Aider | Config injection | Minimal (YAML config entry) |
Syncable Structures (Today)
| Structure | How to Sync | Complexity |
|---|---|---|
| Skills (SKILL.md) | Symlink — same format everywhere | Low |
| Instruction files | Symlink with rename (CLAUDE.md → AGENTS.md → GEMINI.md) | Low |
| MCP config | Config injection (write entry into tool’s .mcp.json) | Medium |
Syncable with Transforms (Future)
| Structure | Transform Needed |
|---|---|
| Cursor rules | SKILL.md ↔ .mdc (add/strip globs, alwaysApply) |
| Windsurf rules | SKILL.md ↔ .md with activation mode |
| Copilot instructions | SKILL.md ↔ .instructions.md (add/strip applyTo) |
Not Syncable (Tool-Specific)
| Structure | Why |
|---|---|
| Hooks | Fundamentally different event models, different config formats |
| Agents | Different frontmatter fields, capability models, isolation strategies |
| Plugins | Different manifest formats, different bundling conventions |
| Memory | Different storage, different lifecycle, different retrieval |
| Settings/Permissions | Different security models entirely |
Connector Design Recommendations
-
SKILL.md as canonical format — The library stores everything in Agent Skills standard format. This is already what most tools natively understand. As of Feb 2026, 7+ major tools read SKILL.md natively.
-
Symlink-first for SKILL.md tools — Claude Code, Codex, Copilot, Antigravity, OpenCode, and Amp all read SKILL.md natively. Symlinks from library to target skill directory are zero-cost and keep everything in sync.
-
Transform pipeline for custom rules — Three tools need format transforms:
- Cursor: Generate
.mdcfiles withdescription,globs, andalwaysApplyfrontmatter from SKILL.md metadata - Windsurf: Generate rules with appropriate activation mode from skill description
- Copilot: Generate
.instructions.mdwithdescriptionandapplyTofrontmatter
- Cursor: Generate
-
MCP config for tool-based targets — Tools that consume skills via MCP get a config entry pointing at the tome MCP server rather than direct file access. Goose is the primary MCP-only target.
-
OpenClaw/Nanobot as special cases — Their 8-file workspace model means a connector needs to map skills into the appropriate slot (AGENTS.md for instructions, TOOLS.md for capabilities, etc.) or just target their skills directory.
What’s Portable vs. What’s Not
| Layer | Portable? | Details |
|---|---|---|
| Skills | Yes | SKILL.md standard fields translate across 7+ tools |
| MCP | Yes | Open standard, every major tool supports it |
| Instruction files | Partially | Same markdown content, different filenames — symlinkable |
| Rules | Partially | Need format transforms for Cursor (.mdc), Windsurf, Copilot (.instructions.md) |
| Hooks | No | 4 tools have hooks, all with incompatible formats and event models |
| Agents | No | 5 tools have agents, all with different frontmatter, capabilities, isolation |
| Plugins | No | 3 tools have plugin systems, all with different manifests |
| Memory | No | 7 tools have memory, all with different storage, lifecycle, retrieval |
Tool-specific skill extensions are lost in translation — tome should preserve them in metadata when syncing between tools of the same type, but can safely drop them when translating to a different format family.
The Convergence Trend
As of Feb 2026, the industry is consolidating around:
- Agent Skills (SKILL.md) for portable instructions — the clear winner
- MCP for portable tool integrations — universal adoption
- Markdown instruction files for project rules — same concept, different filenames
Everything else (hooks, agents, plugins, memory) remains fragmented with no signs of standardization. For tome, this means the v1 focus on skills + MCP + instruction files covers the portable surface area. Extended structures would require per-tool connectors with no format translation possible.
20. Skill Installers: npx skills (Vercel Labs)
npx skills is a JavaScript-based skill installer with a polished interactive CLI. It supports 41 agent targets and uses a two-tier architecture remarkably similar to tome’s library model.
Registry: skills.sh — browsable skill registry with per-skill detail pages.
Architecture
Canonical copies are stored in .agents/skills/<name>/ (the emerging universal path) or tool-specific directories. Distribution to individual tools uses symlinks from their native skill dirs back to the canonical location.
Install flow: clone repo → select skills → select targets → choose scope (project/global) → choose method (symlink/copy) → security assessment → install.
.skill-lock.json (v3)
Lockfile at .agents/.skill-lock.json tracks installed skills with provenance and content hashes:
{
"version": 3,
"skills": {
"skill-name": {
"source": "owner/repo",
"sourceType": "github",
"sourceUrl": "https://github.com/owner/repo.git",
"skillPath": "skills/skill-name/SKILL.md",
"skillFolderHash": "c2f31172b6f256272305a5e6e7228b258446899f",
"installedAt": "2026-03-06T12:49:32.629Z",
"updatedAt": "2026-03-06T12:49:32.629Z"
}
},
"dismissed": { ... },
"lastSelectedAgents": ["amp", "cline", "codex", "cursor", "..."]
}
Key fields: sourceType + sourceUrl for provenance, skillFolderHash for content-based idempotency (similar to tome’s SHA-256 manifest hashes), installedAt/updatedAt timestamps.
Agent Targets (41 total)
Universal agents (share .agents/skills/ as project-scoped path):
| Agent | Global Path |
|---|---|
| Amp | $XDG_CONFIG_HOME/agents/skills |
| Cline | ~/.agents/skills |
| Codex | $CODEX_HOME/skills |
| Cursor | ~/.cursor/skills |
| Gemini CLI | ~/.gemini/skills |
| GitHub Copilot | ~/.copilot/skills |
| Kimi Code CLI | $XDG_CONFIG_HOME/agents/skills |
| OpenCode | $XDG_CONFIG_HOME/opencode/skills |
| Replit | $XDG_CONFIG_HOME/agents/skills |
Additional agents (tool-specific paths):
| Agent | Project Path | Global Path |
|---|---|---|
| Adal | .adal/skills | ~/.adal/skills |
| Antigravity | .agent/skills | ~/.gemini/antigravity/skills |
| Augment | .augment/skills | ~/.augment/skills |
| Claude Code | .claude/skills | $CLAUDE_HOME/skills |
| CodeBuddy | .codebuddy/skills | ~/.codebuddy/skills |
| Command Code | .commandcode/skills | ~/.commandcode/skills |
| Continue | .continue/skills | ~/.continue/skills |
| Cortex | .cortex/skills | ~/.snowflake/cortex/skills |
| Crush | .crush/skills | $XDG_CONFIG_HOME/crush/skills |
| Droid | .factory/skills | ~/.factory/skills |
| Goose | .goose/skills | $XDG_CONFIG_HOME/goose/skills |
| iFlow CLI | .iflow/skills | ~/.iflow/skills |
| Junie | .junie/skills | ~/.junie/skills |
| Kilo | .kilocode/skills | ~/.kilocode/skills |
| Kiro CLI | .kiro/skills | ~/.kiro/skills |
| Kode | .kode/skills | ~/.kode/skills |
| MCPJam | .mcpjam/skills | ~/.mcpjam/skills |
| Mistral Vibe | .vibe/skills | ~/.vibe/skills |
| Mux | .mux/skills | ~/.mux/skills |
| Neovate | .neovate/skills | ~/.neovate/skills |
| OpenClaw | skills | (custom) |
| OpenHands | .openhands/skills | ~/.openhands/skills |
| Pi | .pi/skills | ~/.pi/agent/skills |
| Pochi | .pochi/skills | ~/.pochi/skills |
| Qoder | .qoder/skills | ~/.qoder/skills |
| Qwen Code | .qwen/skills | ~/.qwen/skills |
| Roo | .roo/skills | ~/.roo/skills |
| Trae | .trae/skills | ~/.trae/skills |
| Trae CN | .trae/skills | ~/.trae-cn/skills |
| Windsurf | .windsurf/skills | ~/.codeium/windsurf/skills |
| Zencoder | .zencoder/skills | ~/.zencoder/skills |
CLI Commands
| Command | Purpose |
|---|---|
npx skills add <url> | Install skills from a git repo |
npx skills find <query> | Search the skills.sh registry |
npx skills list | List installed skills |
npx skills check | Verify skill integrity |
npx skills update | Update installed skills |
npx skills remove | Remove installed skills |
npx skills init | Initialize skills in a project |
Security Assessment
The installer integrates security risk assessment with three providers:
| Provider | Assessment |
|---|---|
| Gen | Safe / Unsafe |
| Socket | Alert count |
| Snyk | Risk level |
Each skill gets a security rating before installation, with a link to details on skills.sh.
Implications for tome
.agents/skills/is the emerging universal path — 9 agents converge on it. Tome’sDirectorysource type can discover skills there today.- Lockfile as prior art for
tome.lock—.skill-lock.jsonv3 tracks the same concepts tome needs: content hashes for idempotency, source provenance, install timestamps. - Symlink vs copy choice —
npx skillsoffers both, recommending symlink. Tome already uses this model (library copies + symlink distribution). - Security assessment — interesting prior art for a future
tome auditcommand. - 41-agent coverage — significantly expands the known agent landscape beyond tome’s current connector list.
Sources
Standards & Specifications
- Agent Skills Open Standard — format specification
- Agent Skills Specification
- Model Context Protocol — tool integration standard
Claude Code
- Skills Docs — full frontmatter reference
- Memory Docs
- Hooks Reference — lifecycle events
- Hooks Guide — hook types and matchers
- Subagents — agent configuration
- Plugins Reference — plugin manifest
- MCP Configuration — MCP server setup
- Settings — permission system
- GitHub Issues: #10589, #11322, #17119, #13932, #2154
Codex CLI
- Skills — discovery and invocation
- CLI Features — hooks, sandbox, telemetry
- AGENTS.md Guide — instruction file format
VS Code Copilot
- Custom Instructions — instruction files
- Agent Skills — SKILL.md support
- Agent Mode — agents
- Copilot Memories — memory system
- Building Extensions — plugin system
Cursor & Windsurf
- Cursor Rules Guide — .mdc format and activation modes
- Windsurf Rules
- Windsurf Cascade Memories — rules and activation
- Windsurf Cascade Hooks — lifecycle events
Gemini CLI & Antigravity
- Gemini CLI Context Files
- Gemini CLI GEMINI.md — context files
- Gemini CLI Extensions — extension system
- Antigravity MCP Integration
OpenClaw, Amp, Goose, Aider, Others
- OpenCode Rules — AGENTS.md format
- OpenClaw Memory Files — SOUL.md, HEARTBEAT.md, etc.
- Amp Skills Migration — commands → skills
- Goose Extensions — MCP-based extensions
- Aider Configuration — YAML config
- Nanobot (HKUDS) — OpenClaw-compatible agent
- PicoClaw — ultra-lightweight agent
Skill Installers
- npx skills (Vercel Labs) — 41-agent skill installer with lockfile and security assessment
- skills.sh — skill registry with per-skill detail pages and security ratings
Analysis & Security
- Skills Are More Context-Efficient Than MCP — token comparison
- MCP Token Problem — efficiency analysis
- Claude Skills vs MCP — technical comparison
- Why Cursor Rules Failed and Claude Skills Succeeded — format comparison
- The Memory Manipulation Problem
- Hidden Unicode Backdoors in Agent Skills
Frontmatter Compatibility
SKILL.md files use YAML frontmatter to declare metadata. The base standard comes from the Agent Skills spec, but each platform extends it with its own fields. This page documents the current state of compatibility across tools.
Base Standard (agentskills.io)
| Field | Required | Constraints |
|---|---|---|
name | Yes | Max 64 chars. Lowercase letters, numbers, hyphens only. Must match directory name. |
description | Yes | Max 1024 chars. Non-empty. |
license | No | License name or reference. |
compatibility | No | Max 500 chars. Environment requirements. |
metadata | No | Arbitrary key-value map. |
allowed-tools | No | Space-delimited tool list. (Experimental) |
Platform Extensions
These fields are valid on their respective platforms but will be silently ignored (or warned about) elsewhere.
| Field | Platform | Purpose |
|---|---|---|
disable-model-invocation | Claude Code | User-only invocation (no auto-trigger) |
user-invocable | Claude Code | false = model-only background knowledge |
argument-hint | Claude Code | Hint for argument parsing |
context | Claude Code | fork = run in isolated subagent |
agent | Claude Code | Specify subagent type (e.g., Explore) |
hooks | Claude Code | Lifecycle hooks scoped to the skill |
excludeAgent | VS Code Copilot | Target coding-agent vs code-review |
Codex uses a separate agents/openai.yaml file instead of extending SKILL.md frontmatter.
Non-Standard Fields Found in the Wild
These appear in community skills but are not part of any spec. They will be silently ignored by standard-compliant tools.
| Field | Issue | Recommendation |
|---|---|---|
version | Not in any spec | Move to metadata.version |
category | Not in any spec | Move to metadata.category |
tags | Not in any spec | Move to metadata.tags |
last-updated | Not in any spec | Move to metadata.last-updated |
model | Agent frontmatter field, not SKILL.md | Remove or move to agent config |
Known Bugs & Gotchas
VSCode validator flags valid fields
The VS Code Copilot extension’s skill validator has an outdated schema that flags allowed-tools as unsupported, even though it’s part of the base spec. This is a known issue.
Multiline YAML descriptions break on Claude Code
Claude Code’s SKILL.md parser does not handle implicit YAML folding (Prettier-style wrapped lines). Descriptions that span multiple lines without an explicit block scalar will be silently truncated.
Breaks:
---
description: This is a long description that has been
wrapped by Prettier across multiple lines
---
Works:
---
description: This is a long description on a single line
---
Also works (explicit block scalar):
---
description: |
This is a long description that uses
an explicit block scalar indicator
---
Unknown fields are silently ignored
All standard-compliant tools silently ignore unknown frontmatter fields. The VS Code extension is an exception — it shows warnings for unrecognized fields. This means non-standard fields won’t cause errors but also won’t do anything.
Case sensitivity
- All field names must be lowercase
- The filename must be exactly
SKILL.md(uppercase)
Platform Limits
| Constraint | Limit | Platform |
|---|---|---|
name length | 64 chars | All (base spec) |
description length | 1024 chars | All (base spec) |
description length | 500 chars | VS Code Copilot (stricter) |
compatibility length | 500 chars | All (base spec) |
| Skill body size | ~6000 chars | Windsurf |
| Skill body size | ~5000 tokens | General recommendation |
How tome Uses This
tome currently symlinks skill directories as-is without parsing frontmatter. The v0.3.x release will add:
- Frontmatter parsing during discovery
tome lintcommand with tiered validation (errors, warnings, info)tome doctorfrontmatter health checkstome statusmetadata summary per skill
See the Roadmap for details.
Vercel Skills Comparison
Research into vercel-labs/skills (npx skills) — the closest comparable project to tome. Both manage AI coding skills across multiple tools. This doc catalogs features and tooling patterns tome is missing to inform roadmap decisions.
Last updated: March 2026
1. Overview
| tome | Vercel Skills | |
|---|---|---|
| Language | Rust (edition 2024) | TypeScript (Node.js 18+) |
| Install | cargo install tome / Homebrew | npx skills (zero-install) |
| Version | v0.3.1 | v1.4.5 |
| Architecture | Library-first: discover → consolidate → distribute | Installer-first: fetch → install (symlink/copy) |
| Scope | Multi-machine library manager with lockfile sync | Single-machine skill installer with remote sources |
Core philosophical difference: Tome treats the library as the source of truth — skills are consolidated into a local library, then distributed to targets. Vercel Skills is an installer — it fetches from remote sources and symlinks directly into agent directories. There’s no intermediate “library” abstraction.
2. Feature Comparison
| Feature | tome | Vercel Skills | Notes |
|---|---|---|---|
| Local directory sources | ✅ | ✅ | Both scan local paths for SKILL.md dirs |
| Claude plugin sources | ✅ | ✅ | Tome reads installed_plugins.json; Vercel reads .claude-plugin/marketplace.json |
| GitHub remote sources | ✅ | ✅ | Tome stores Git sources once in shared repository policy |
| GitLab remote sources | ✅ | ✅ | Full URL support |
| Well-known HTTP providers | ❌ | ✅ | RFC 8615 /.well-known/skills/index.json endpoints |
| npm/node_modules sync | ❌ | ✅ (experimental) | Crawls node_modules for skills |
| Symlink distribution | ✅ | ✅ | Both use symlinks as primary distribution method |
| MCP distribution | ❌ (removed) | ❌ | Was removed — all tools now scan SKILL.md dirs natively |
| Copy fallback | ❌ | ✅ | Vercel falls back to copy when symlinks fail |
| Lockfile | ✅ tome.lock | ✅ .skill-lock.json v3 | Both track content hashes and provenance |
| Persistent destination routing | ✅ profile/project routes | ❌ | Tome OR-matches shared skill tags and supports explicit destination exclusions |
| Multi-machine sync | ✅ tome sync | ❌ | Lockfile diffing with interactive triage |
| Library consolidation | ✅ | ❌ | Tome’s two-tier model; Vercel installs directly |
| Interactive browse | ✅ tome browse | ❌ | TUI with fuzzy search (ratatui + nucleo) |
| Skill scaffolding | ❌ | ✅ skills init | Generates SKILL.md template |
| Public search/registry | ❌ | ✅ skills find | API-backed search at skills.sh with install counts |
| Remote update checking | ✅ tome sync | ✅ skills check | Tome synchronizes repository-owned Git sources under local consent |
| Agent auto-detection | 🔜 (wizard only) | ✅ | Async detection of 50+ installed agents |
| Format transforms | 🔜 v0.4 | ❌ | Planned: SKILL.md ↔ .mdc ↔ .instructions.md |
| Frontmatter validation | 🔜 v0.4 | Partial | Vercel parses name/description/metadata.internal |
| Doctor/diagnostics | ✅ tome doctor | ❌ | Orphan detection, manifest repair, symlink health |
| MCP server | ❌ (removed) | ❌ | Was removed — no known consumers |
| Dry-run mode | ✅ | ❌ | Preview changes without filesystem writes |
| Git commit integration | ✅ | ❌ | Auto-offers commit after sync when library is a git repo |
| Telemetry | ❌ | ✅ | Anonymous usage tracking (disabled in CI) |
| Known agent targets | 7 | 50+ | Significant coverage gap |
3. Notable Features Tome Lacks
3.1 Remote Git Sources
Vercel’s source parser accepts multiple formats:
skills add owner/repo # GitHub shorthand
skills add owner/repo@skill-name # specific skill from repo
skills add owner/repo/tree/main/skills/ # subpath targeting
skills add https://gitlab.com/org/repo # GitLab
skills add git@github.com:owner/repo.git # SSH
skills add ./local-path # local directory
Branch/tag targeting via /tree/<ref> syntax. Subpath extraction lets users install a single skill from a multi-skill repo.
Tome status: Implemented. tome add accepts GitHub slugs, full URLs,
/tree/<ref>/<subdir> shortcuts, explicit ref pins, and subdirectories. Git
sources are shared repository policy and do not accept a destination --to.
3.2 Skill Scaffolding (skills init)
npx skills init my-skill
Generates a SKILL.md template with frontmatter boilerplate. Low complexity, high convenience for skill authors.
Tome status: Not on roadmap. Would be a simple addition — tome new <name> that creates <name>/SKILL.md with a frontmatter template. Consider adding as a quick win.
3.3 Public Search & Registry
skills find [query] provides:
- Interactive terminal UI with keyboard navigation
- API-backed search at
https://skills.sh/(top 10 results, sorted by install count) - Debounced queries with formatted output
The registry at skills.sh acts as a public directory of community skills. This creates a discovery loop: authors publish, users search, install counts drive ranking.
Tome status: Not on roadmap. A public registry is a significant undertaking. However, integrating with skills.sh as a read-only source could be a lighter-weight option — tome could query the same API without building its own registry.
3.4 Remote Update Checking
skills check POSTs to a backend API with current lockfile state, compares GitHub tree SHAs to detect available updates. skills update then fetches and replaces.
Tome status: tome sync can synchronize repository-owned Git sources and
reconcile managed state. Local git_sync = "always" | "ask" | "never"
controls shared-repository synchronization.
3.5 Well-Known Providers
Vercel supports RFC 8615 /.well-known/skills/index.json endpoints — any HTTP server can advertise available skills by hosting a JSON manifest at a well-known URL. This enables decentralized skill distribution without a central registry.
Tome status: Not on roadmap. Novel approach worth considering for the connector architecture. Could be a lightweight alternative to a full registry.
3.6 Agent Target Coverage (50+)
Vercel supports 50+ agents. Their agents.ts defines per-agent configuration including:
- Project and global skill paths
- Whether the agent shares the universal
.agents/skills/directory - Installation detection method
Agents in Vercel not in tome’s KnownTarget list:
| Agent | Skills Path | Notes |
|---|---|---|
| Cline | .cline/skills/ | VS Code extension |
| Warp | .warp/skills/ | Terminal-native |
| OpenCode | .agents/skills/ | Universal path |
| CodeBuddy | .codebuddy/skills/ | |
| Goose | .goose/skills/ | |
| Amp | .amp/skills/ | |
| Aider | .aider/skills/ | |
| Kilo Code | .kilo-code/skills/ | |
| RooCode | .roo-code/skills/ | |
| Zed | .zed/skills/ | |
| Trae | .trae/skills/ | |
| Melty | .melty/skills/ | |
| otto-eng | .otto/skills/ | |
| Pear | .pear/skills/ | |
| Sourcegraph Cody | .sourcegraph-cody/skills/ | |
| Void | .void/skills/ | |
| Junie | .junie/skills/ | |
| Augment | .augment/skills/ | |
| Aide | .aide/skills/ | |
| Blackbox AI | .blackbox-ai/skills/ | |
| Qodo | .qodo/skills/ | |
| Tabnine | .tabnine/skills/ | |
| GitHub Spark | .spark/skills/ |
Many share the universal .agents/skills/ path. Tome’s data-driven target config already supports arbitrary agents, but expanding KnownTarget auto-discovery would improve the wizard experience.
Notable exception — OpenClaw: Unlike most tools that have a single skills path, OpenClaw has a two-level structure: a shared .openclaw/skills/ directory across all agents plus per-agent skills/ directories under each agent’s workspace. This may require a multi-path target model or an OpenClaw-specific connector extension.
Persistent destination selection: Vercel’s --agent flag filters which
agents receive a skill at install time, but the assignment is not persisted in
its lockfile. Tome persists classification and routing separately: shared tags
live in .tome-manifest.json, while the profile or project that owns a
destination stores its route.
# machines/work.toml or a project .tome.toml
[routes.codex]
tags = ["portable", "coding"]
exclude = ["claude-only-skill"]
Any selected tag can match; an explicit exclusion wins. Newly imported skills are untagged and remain library-only for routed destinations. This keeps source provenance independent from destination choice and avoids changing skill frontmatter.
3.7 npm/node_modules Sync
skills experimental_sync scans node_modules/ for packages containing skills. This supports distributing skills as npm packages — a novel distribution channel.
Tome status: Not on roadmap. Low priority given the Rust ecosystem focus, but the concept of “skills as packages” in language-specific package managers is worth noting.
3.8 Plugin Manifest Compatibility
Vercel reads .claude-plugin/marketplace.json and .claude-plugin/plugin.json to discover skills bundled with Claude plugins. This enables compatibility with the Claude plugin marketplace ecosystem.
Tome status: Tome reads installed_plugins.json from the Claude plugin cache directory (a different integration point). The .claude-plugin/ manifest format is not currently parsed. Both approaches achieve plugin-sourced skill discovery, but through different mechanisms.
4. Tooling & DX Patterns
Source Parser
Vercel’s source-parser.ts normalizes diverse input formats into a unified ParsedSource type:
type ParsedSource = {
owner: string;
repo: string;
provider: 'github' | 'gitlab' | 'local';
ref?: string; // branch/tag
subpath?: string; // path within repo
skillName?: string; // specific skill
}
This decouples source resolution from installation logic. When tome implements git sources, a similar parser would be valuable.
Lockfile Versioning
Vercel’s lockfile has a version field (currently v3). When an old-format lockfile is detected, it’s wiped entirely — users must reinstall. This aggressive migration strategy avoids complex upgrade code at the cost of user inconvenience.
Tome’s tome.lock doesn’t yet have a version migration strategy. Worth adding a version field early to avoid future pain.
Agent Auto-Detection
Vercel detects installed agents asynchronously by checking for agent-specific markers (config directories, binaries). This enables smart defaults during installation — only install to agents the user actually has.
Tome’s wizard does basic path existence checks for known source/target locations, but doesn’t detect agents as a first-class concept. The wizard could benefit from a richer detection step.
Security: Path Sanitization
Vercel’s sanitizeName() prevents directory traversal via skill names, and isSubpathSafe() rejects .. segments. Tome’s SkillName type rejects path separators (/, \) at parse time, achieving the same goal through the type system. Tome’s approach is arguably stronger — invalid names can’t even be constructed.
5. Architectural Differences
| Aspect | tome | Vercel Skills |
|---|---|---|
| Data flow | Sources → Library → Targets | Remote → Agent directories |
| Canonical location | Library dir (~/.tome/skills/) | Agent skills dirs (.agents/skills/) |
| Multi-machine | Shared policy + profiles + manifest + lockfile | Single-machine only |
| Offline support | Full (library is local) | Partial (needs network for remote sources) |
| Update model | Diff-based triage (tome sync) | Replace-based (skills update) |
| Cleanup | Automated stale removal with interactive confirm | Manual skills remove |
| Diagnostics | tome doctor with repair | None |
Key takeaway: Tome’s library abstraction adds complexity but enables features Vercel can’t easily replicate (multi-machine sync, lockfile diffing, automated cleanup, diagnostics). Vercel’s installer model is simpler but single-machine.
6. Recommendations
Prioritized by effort-to-value ratio, mapped to existing roadmap items where applicable.
Quick Wins (small effort, immediate value)
-
Expand KnownTarget list — Add 15–20 more agents from Vercel’s list to wizard auto-discovery. Data-only change in
wizard.rs. (Extends #248) -
tome new <name>scaffolding — Generate a<name>/SKILL.mdtemplate with standard frontmatter. Simple new command. (New issue) -
Lockfile version field — Add
"version": 1totome.locknow, before we need migration logic. (New issue)
Medium-Term (aligns with existing roadmap)
-
Route-management ergonomics — Build on the implemented profile/project tag routes with better inspection and bulk operations. Vercel’s
--agentflag remains install-time-only, while Tome persists routes. -
Source parser extensions — Tome already supports GitHub shorthand and
/tree/<ref>/<subdir>; evaluate single-skill selectors and other provider conventions only if users need them. -
Remote update checking — Extend
tome syncto check remote sources, not just local lockfile diffs. (After v0.6) -
Agent auto-detection — Upgrade wizard to detect installed agents dynamically rather than just checking path existence. (Enhancement to wizard)
Future Consideration (worth watching)
-
Well-known providers — RFC 8615 skill endpoints could complement git sources as a lightweight discovery mechanism. Novel and decentralized.
-
skills.sh integration — Read-only integration with Vercel’s public registry as a discovery source. Avoids building our own registry while providing discoverability.
-
Copy fallback — Vercel supports copy when symlinks fail. Tome is Unix-only and symlink-only. Worth considering if Windows support ever becomes a goal.
Test Setup
tome has two layers of tests: unit tests co-located with each module, and integration tests that exercise the compiled binary end-to-end. All tests run in CI on both Ubuntu and macOS.
Test Architecture
graph TB
subgraph CI["GitHub Actions CI (ubuntu + macos)"]
FMT["cargo fmt --check"]
CLIP["cargo clippy -D warnings"]
TEST["cargo test --all"]
BUILD["cargo build --release"]
FMT --> CLIP --> TEST --> BUILD
end
subgraph TEST_SUITE["cargo test --all"]
UNIT["Unit Tests<br/><i>~825 across 25+ modules (v0.11)</i>"]
INTEG["Integration Tests<br/><i>~197 across cli_*.rs files (v0.11)</i>"]
end
TEST --> TEST_SUITE
Two Test Types
Unit Tests (co-located, #[cfg(test)])
Each module has a mod tests block that tests its public functions in isolation. These tests create temporary directories with tempfile::TempDir and never touch the real filesystem.
Integration Tests (crates/tome/tests/cli_*.rs)
These compile the tome binary and run it as a subprocess using assert_cmd. They verify the full CLI flow: argument parsing, config loading, pipeline execution, and output formatting. Post-HARD-13 (v0.10), the original tests/cli.rs was split into per-domain files (cli_sync.rs, cli_doctor.rs, cli_status.rs, cli_init.rs, cli_make_release.rs, etc.) with shared helpers under tests/common/ — the module-level tables below are a point-in-time snapshot from pre-split and will drift; run cargo test -p tome -- --list for the live breakdown.
graph LR
subgraph Integration["tests/cli.rs"]
CMD["assert_cmd<br/>spawns tome binary"]
TMP["assert_fs::TempDir<br/>isolated filesystem"]
PRED["predicates<br/>stdout assertions"]
CMD --> TMP
CMD --> PRED
end
subgraph Unit["#[cfg(test)] modules"]
TEMP["tempfile::TempDir<br/>isolated filesystem"]
SYML["unix_fs::symlink<br/>real symlink ops"]
TEMP --> SYML
end
Module-by-Module Breakdown
Note: Test counts below reflect a point-in-time snapshot. Run
cargo testfor current counts.
graph TB
subgraph unit_tests["Unit Tests (~825 — counts drift, run cargo test --list)"]
CONFIG["config.rs<br/>─────────<br/>25 tests"]
DISCOVER["discover.rs<br/>─────────<br/>17 tests"]
LIBRARY["library.rs<br/>─────────<br/>31 tests"]
DISTRIBUTE["distribute.rs<br/>─────────<br/>12 tests"]
CLEANUP["cleanup.rs<br/>─────────<br/>8 tests"]
DOCTOR["doctor.rs<br/>─────────<br/>20 tests"]
STATUS["status.rs<br/>─────────<br/>18 tests"]
LOCKFILE["lockfile.rs<br/>─────────<br/>15 tests"]
MANIFEST["manifest.rs<br/>─────────<br/>8 tests"]
MACHINE["machine.rs<br/>─────────<br/>12 tests"]
UPDATE["update.rs<br/>─────────<br/>8 tests"]
WIZARD["wizard.rs<br/>─────────<br/>6 tests"]
PATHS["paths.rs<br/>─────────<br/>8 tests"]
BROWSE["browse/<br/>─────────<br/>14 tests"]
LIB["lib.rs<br/>─────────<br/>12 tests"]
end
subgraph integration_tests["Integration Tests (~197 across cli_*.rs)"]
CLI["tests/cli_*.rs<br/>─────────<br/>18 files post-HARD-13"]
end
style CONFIG fill:#e8f4e8
style DISCOVER fill:#e8f4e8
style LIBRARY fill:#e8f4e8
style DISTRIBUTE fill:#e8f4e8
style CLEANUP fill:#e8f4e8
style DOCTOR fill:#e8f4e8
style STATUS fill:#e8f4e8
style LOCKFILE fill:#e8f4e8
style MANIFEST fill:#e8f4e8
style MACHINE fill:#e8f4e8
style UPDATE fill:#e8f4e8
style WIZARD fill:#e8f4e8
style PATHS fill:#e8f4e8
style BROWSE fill:#e8f4e8
style LIB fill:#e8f4e8
style CLI fill:#e8e4f4
config.rs — 25 tests
Tests config loading, serialization, tilde expansion, validation, and target parsing.
| Test | What it verifies |
|---|---|
expand_tilde_expands_home | ~/foo becomes /home/user/foo |
expand_tilde_leaves_absolute_unchanged | /absolute/path passes through |
expand_tilde_leaves_relative_unchanged | relative/path passes through |
default_config_has_empty_sources | Config::default() has no sources or exclusions |
config_loads_defaults_when_file_missing | Missing file returns default config (no error) |
config_roundtrip_toml | Serialize -> deserialize preserves all fields |
config_load_fails_on_malformed_toml | Malformed TOML returns Err |
config_parses_full_toml | Full config string with sources + targets parses correctly |
config_parses_arbitrary_target_name | Custom target names work in BTreeMap |
config_parses_claude_target_from_toml | Claude-specific target fields parse correctly |
config_roundtrip_claude_target | Claude target serialization roundtrip |
load_or_default_errors_when_parent_dir_missing | Missing parent dir returns error |
load_or_default_returns_defaults_when_parent_exists | Existing parent dir with no file returns defaults |
target_config_roundtrip_symlink | Symlink target serialization roundtrip |
targets_iter_includes_claude | Claude target included in iterator |
try_from_raw_rejects_unknown_method | Unknown method string rejected |
try_from_raw_rejects_symlink_without_skills_dir | Symlink target requires skills_dir field |
validate_passes_for_valid_config | Valid config passes validation |
validate_rejects_duplicate_source_names | Duplicate source names rejected |
validate_rejects_empty_source_name | Empty source name rejected |
validate_rejects_library_dir_that_is_a_file | Library dir pointing to a file rejected |
target_name_accepts_valid | Valid target names pass validation |
target_name_rejects_empty | Empty target name rejected |
target_name_rejects_path_separator | Target names with / rejected |
target_name_deserialize_rejects_empty | Empty target name rejected during deserialization |
discover.rs — 17 tests
Tests skill discovery from both Directory and ClaudePlugins source types, plus skill name validation.
| Test | What it verifies |
|---|---|
discover_directory_finds_skills | Finds */SKILL.md dirs, ignores dirs without SKILL.md |
discover_directory_warns_on_missing_path | Missing source path returns empty vec (no crash) |
discover_directory_skips_skill_md_at_source_root | SKILL.md directly in source root is ignored |
discover_all_deduplicates_first_wins | Same skill name in two sources -> first source wins |
discover_all_applies_exclusions | Excluded skill names are filtered out |
discover_all_collects_dedup_warnings | Deduplication produces warnings |
discover_all_collects_naming_warnings | Naming issues produce warnings |
discover_all_with_partial_config_returns_skills | Works with incomplete config |
discover_claude_plugins_reads_json | v1 format: flat array with installPath |
discover_claude_plugins_reads_v2_json | v2 format: { plugins: { "name@reg": [...] } } |
discover_claude_plugins_unknown_format | Unrecognized JSON structure returns empty vec |
discover_claude_plugins_deduplicates_within_source | Same plugin listed twice in JSON -> deduplicated |
discover_claude_plugins_v1_no_provenance | v1 format skills have no provenance metadata |
skill_name_accepts_valid | Valid skill names pass validation |
skill_name_rejects_empty | Empty name rejected |
skill_name_rejects_path_separator | Names with / rejected |
skill_name_conventional_check | Naming convention warnings |
library.rs — 31 tests
Tests the consolidation step — copying local skills and symlinking managed skills into the library.
| Test | What it verifies |
|---|---|
consolidate_copies_skills | Local skill -> copied into library |
consolidate_copies_nested_subdirectories | Nested dirs within skills are preserved |
consolidate_idempotent | Same skill twice -> unchanged == 1, no filesystem change |
consolidate_dry_run_no_changes | dry_run=true reports counts but creates nothing |
consolidate_dry_run_doesnt_create_dir | Library dir not created during dry run |
consolidate_dry_run_no_manifest_written | Manifest not written during dry run |
consolidate_dry_run_manifest_reflects_would_be_state | Dry run manifest shows expected state |
consolidate_updates_changed_source | Changed source content -> library copy updated |
consolidate_detects_content_change | Content hash change triggers re-copy |
consolidate_skips_unmanaged_collision | Existing non-managed dir not overwritten |
consolidate_force_recopies | force=true re-copies even if unchanged |
consolidate_local_manifest_reflects_update | Manifest updated after local skill change |
consolidate_manifest_persisted | Manifest written to disk |
consolidate_symlinks_managed_skill | Managed skill -> symlinked into library |
consolidate_managed_idempotent | Managed skill symlink is idempotent |
consolidate_managed_path_changed | Source path change -> symlink updated |
consolidate_managed_dry_run_no_symlink_created | Managed dry run creates no symlinks |
consolidate_managed_force_recreates_symlink | Force recreates managed symlinks |
consolidate_managed_skips_non_manifest_dir_collision | Non-manifest dir collision handled |
consolidate_managed_manifest_records_managed_flag | Manifest records managed flag |
consolidate_managed_repairs_stale_directory | Stale directory state repaired to symlink |
consolidate_migrates_v01_symlink | v0.1 symlinks migrated to copies |
consolidate_migrates_v01_symlink_records_discovered_source | Migration records source provenance |
consolidate_migrates_v01_symlink_with_broken_target | Broken v0.1 symlink migrated gracefully |
consolidate_strategy_transition_local_to_managed | Local -> managed strategy transition |
consolidate_strategy_transition_managed_to_local | Managed -> local strategy transition |
gitignore_lists_managed_skills | .gitignore lists managed skill dirs |
gitignore_does_not_list_local_skills | .gitignore excludes local skills |
gitignore_idempotent | Repeated gitignore writes are idempotent |
gitignore_always_ignores_tmp_files | .gitignore includes *.tmp pattern |
distribute.rs — 12 tests
Tests the distribution step — pushing skills from library to target tools.
| Test | What it verifies |
|---|---|
distribute_symlinks_creates_links | Symlink method creates links in target dir |
distribute_symlinks_idempotent | Second run -> linked=0, unchanged=1 |
distribute_symlinks_force_recreates_links | Force recreates all links |
distribute_symlinks_updates_stale_link | Stale link pointing elsewhere updated |
distribute_symlinks_skips_non_symlink_collision | Regular file at target path -> skipped |
distribute_symlinks_skips_manifest_file | .tome-manifest.json not distributed |
distribute_symlinks_dry_run_doesnt_create_dir | Target dir not created during dry run |
distribute_symlinks_dry_run_with_nonexistent_library | Dry run works with missing library |
distribute_disabled_target_is_noop | enabled: false -> no work done |
distribute_skips_disabled_skills | Machine-disabled skills not distributed |
distribute_skips_skills_originating_from_target_dir | Skills from target’s own dir skipped |
distribute_idempotent_with_canonicalized_paths | Idempotent with canonicalized paths |
cleanup.rs — 8 tests
Tests stale symlink and manifest cleanup from library and targets.
| Test | What it verifies |
|---|---|
cleanup_removes_stale_manifest_entries | Manifest entries for missing skills removed |
cleanup_removes_broken_legacy_symlinks | Broken legacy symlinks cleaned up |
cleanup_removes_managed_symlink | Stale managed symlinks removed |
cleanup_preserves_current_skills | Active skills preserved during cleanup |
cleanup_dry_run_preserves_stale | Dry run counts but doesn’t delete |
cleanup_target_removes_stale_links | Broken target links removed |
cleanup_target_dry_run_preserves_stale_links | Target dry run preserves links |
cleanup_target_preserves_external_symlinks | Links pointing outside library preserved |
doctor.rs — 20 tests
Tests library diagnostics and repair.
| Test | What it verifies |
|---|---|
check_healthy_library_returns_no_issues | Clean library has no issues |
check_detects_orphan_directory | Orphan dir (not in manifest) detected |
check_detects_missing_source_path | Missing source path flagged |
check_library_no_issues | Healthy library check passes |
check_library_orphan_directory | Orphan directory in library detected |
check_library_missing_manifest_entry | Missing manifest entry detected |
check_library_broken_legacy_symlink | Broken legacy symlink detected |
check_library_missing_dir | Missing library dir handled |
check_config_valid_sources | Valid source config passes |
check_config_missing_source | Missing source config flagged |
check_target_dir_stale_symlink | Stale target symlink detected |
check_target_dir_missing_dir | Missing target dir handled |
check_target_dir_ignores_external_symlinks | External symlinks ignored |
check_unconfigured_returns_not_configured | Unconfigured state detected |
diagnose_shows_init_prompt_when_unconfigured | Shows init prompt when no config |
repair_library_healthy_is_noop | Repair on healthy library is no-op |
repair_library_removes_orphan_manifest_entry | Repair removes orphan manifest entries |
repair_library_removes_broken_legacy_symlink | Repair removes broken legacy symlinks |
repair_library_removes_broken_managed_symlink | Repair removes broken managed symlinks |
lockfile.rs — 15 tests
Tests lockfile generation, loading, and serialization.
| Test | What it verifies |
|---|---|
generate_empty_manifest | Empty manifest produces empty lockfile |
generate_managed_skill_with_provenance | Managed skills include provenance |
generate_local_skill_no_provenance | Local skills omit registry fields |
generate_discovered_skill_not_in_manifest | Discovered skill without manifest entry handled |
generate_manifest_entry_without_discovered_skill | Manifest entry without discovered skill handled |
generate_mixed_skills | Mix of managed and local skills |
deterministic_output | Output is deterministic (sorted) |
roundtrip_serialization | Serialize -> deserialize roundtrip |
save_creates_file | Save creates lockfile on disk |
save_does_not_leave_tmp_file | Atomic write cleans up temp file |
load_missing_file_returns_none | Missing lockfile returns None |
load_valid_file_returns_some | Valid lockfile loads successfully |
load_corrupt_file_returns_error | Corrupt lockfile returns error |
empty_version_string_becomes_none | Empty version string normalized to None |
local_skill_omits_registry_fields_in_json | Local skills omit registry fields in JSON |
machine.rs — 12 tests
Tests per-machine preferences loading, saving, and disabled skill/target tracking.
| Test | What it verifies |
|---|---|
default_prefs_has_empty_disabled | Default prefs have empty disabled set |
is_disabled_checks_set | is_disabled() checks the disabled set |
load_missing_file_returns_defaults | Missing file returns defaults |
load_malformed_toml_returns_error | Malformed TOML returns error |
save_load_roundtrip | Save -> load roundtrip preserves state |
save_creates_parent_directories | Save creates parent dirs if needed |
save_does_not_leave_tmp_file | Atomic write cleans up temp file |
toml_format_is_readable | Serialized TOML is human-readable |
Run
cargo test -p tome -- machine::tests --listfor the full current list.
manifest.rs — 8 tests
Tests library manifest operations and content hashing.
| Test | What it verifies |
|---|---|
load_missing_manifest_returns_empty | Missing manifest returns empty map |
load_corrupt_json_returns_error | Corrupt JSON returns error |
manifest_roundtrip | Save -> load roundtrip |
hash_directory_deterministic | Same content produces same hash |
hash_directory_changes_with_content | Changed content produces different hash |
hash_directory_different_filenames_different_hashes | Different filenames produce different hashes |
hash_directory_includes_subdirs | Subdirectory contents included in hash |
now_iso8601_format | Timestamp format is ISO 8601 |
status.rs — 18 tests
Tests status gathering and health checks.
| Test | What it verifies |
|---|---|
count_entries_counts_directories | Counts directories in library |
count_entries_empty_dir | Empty dir returns 0 |
count_entries_ignores_hidden_directories | Hidden dirs (.foo) excluded |
count_entries_ignores_regular_files | Regular files excluded from count |
count_health_issues_empty_dir | Empty dir has no health issues |
count_health_issues_ignores_hidden_dirs | Hidden dirs excluded from health check |
count_health_issues_detects_orphan_directory | Orphan directory detected |
count_health_issues_detects_manifest_disk_mismatch | Manifest/disk mismatch detected |
gather_unconfigured_returns_not_configured | Unconfigured state detected |
gather_with_library_dir_counts_skills | Library dir skill count |
gather_with_sources_marks_configured | Sources marked as configured |
gather_with_targets_populates_target_status | Target status populated |
gather_health_detects_orphan | Health check detects orphan dirs |
status_shows_init_prompt_when_unconfigured | Shows init prompt when unconfigured |
status_shows_tables_with_configured_sources_and_targets | Full status output with tables |
status_warns_when_library_missing_but_sources_configured | Warning when library dir missing |
update.rs — 8 tests
Tests lockfile diffing and triage logic used by tome sync.
| Test | What it verifies |
|---|---|
diff_empty_lockfiles | Two empty lockfiles produce no changes |
diff_identical_lockfiles | Identical lockfiles produce no changes |
diff_added_skill | New skill detected as added |
diff_removed_skill | Missing skill detected as removed |
diff_changed_skill | Changed hash detected as changed |
diff_same_hash_different_source_is_unchanged | Same hash with different source is unchanged |
diff_mixed_changes | Mix of added/removed/changed/unchanged |
diff_detects_managed_skill | Managed skills flagged in diff |
wizard.rs — 6 tests
Tests wizard auto-discovery and overlap detection.
| Test | What it verifies |
|---|---|
find_known_sources_in_discovers_existing_dirs | Auto-discovers known source paths |
find_known_sources_in_empty_home_returns_empty | Empty home returns no sources |
find_known_sources_in_skips_files_with_same_name | Files with source dir names skipped |
detects_source_target_overlap | Source/target path overlap detected |
detects_claude_source_target_overlap | Claude-specific overlap detected |
no_overlap_when_paths_differ | Distinct paths pass overlap check |
lib.rs — 12 tests
Tests orchestration-level functions (disabled skill cleanup, commit message generation, tome home resolution).
| Test | What it verifies |
|---|---|
cleanup_disabled_removes_library_symlink | Disabled skill symlink removed from target |
cleanup_disabled_preserves_external_symlink | Non-library symlinks preserved |
cleanup_disabled_skips_non_symlink | Regular files not removed |
cleanup_disabled_dry_run_preserves_symlink | Dry run preserves symlinks |
cleanup_disabled_nonexistent_dir_returns_zero | Missing dir returns 0 |
commit_message_all_changes | Commit message with all change types |
commit_message_created_only | Commit message with creates only |
commit_message_no_changes | Commit message with no changes |
resolve_tome_home_absolute_path_returns_parent | Absolute path resolves to parent |
resolve_tome_home_none_returns_default | None returns default home |
resolve_tome_home_relative_path_returns_error | Relative path rejected |
resolve_tome_home_bare_filename_returns_error | Bare filename rejected |
tests/cli_*.rs — ~197 integration tests across 18 files
Each test compiles and runs the tome binary in a temp directory with a custom config. The table below is a pre-HARD-13 snapshot from when all integration tests lived in a single tests/cli.rs (32 tests); post-v0.10 they’re split across cli_sync.rs, cli_doctor.rs, cli_status.rs, cli_init.rs, cli_make_release.rs, cli_migrate_library.rs, cli_overrides.rs, cli_reassign.rs, cli_remove.rs, cli_browse.rs, cli_backup.rs, cli_add.rs, cli_config.rs, cli_eject.rs, cli_lint.rs, cli_list.rs, cli_misc.rs, and cli_sync_reconcile.rs with shared helpers under tests/common/.
| Test | Command | What it verifies |
|---|---|---|
help_shows_usage | --help | Prints usage text |
version_shows_version | --version | Prints version from Cargo.toml |
list_with_no_sources_shows_message | list | “No skills found” with empty config |
list_shows_discovered_skills | list | Skill names + count in output |
list_json_outputs_valid_json | list --json | Valid JSON array output |
list_json_with_no_skills_outputs_empty_array | list --json | Empty array when no skills |
list_json_with_quiet_still_outputs_json | list --json -q | JSON output even in quiet mode |
sync_dry_run_makes_no_changes | --dry-run sync | “Dry run” in output, library empty |
sync_copies_skills_to_library | sync | Skills copied to library dir |
sync_creates_lockfile | sync | tome.lock created |
sync_dry_run_does_not_create_lockfile | --dry-run sync | No lockfile in dry run |
sync_distributes_to_symlink_target | sync | Symlinks created in target dir |
sync_idempotent | sync (x2) | Second run: 0 created, 1 unchanged |
sync_updates_changed_source | sync (x2) | Changed source content triggers update |
sync_force_recreates_all | sync --force | Force re-copies all skills |
sync_migrates_v01_symlinks | sync | Legacy v0.1 symlinks migrated |
sync_lifecycle_cleans_up_removed_skills | sync (x2) | Removed source -> cleaned up |
sync_respects_machine_disabled | sync | Disabled skills not distributed |
sync_respects_machine_disabled_targets | sync | Disabled targets skipped during sync |
sync_dry_run_skips_git_commit | --dry-run sync | No git commit in dry run |
sync_quiet_skips_git_commit | -q sync | No git commit in quiet mode |
sync_skips_git_commit_without_tty | sync | No git commit without TTY |
status_shows_library_info | status | “Library:”, “Sources:”, “Targets:” in output |
status_without_config_shows_init_prompt | status | Init prompt when unconfigured |
config_path_prints_default_path | config --path | Prints path containing config.toml |
doctor_with_clean_state | doctor | “No issues found” |
doctor_detects_broken_symlinks | doctor | Issues detected with broken symlink |
doctor_without_config_shows_init_prompt | doctor | Init prompt when unconfigured |
update_shows_new_skills | update | New skills shown after initial sync |
update_dry_run_makes_no_changes | --dry-run update | Dry run preserves state |
update_with_no_lockfile_works_gracefully | update | Works without existing lockfile |
update_disable_removes_symlink | update | Disabled skill symlink removed |
Filesystem Isolation Strategy
Every test creates its own TempDir that is automatically cleaned up when the test ends. This means:
- Tests never interfere with each other (no shared state)
- Tests never touch the real
~/.tome/ - No manual cleanup is needed
- Tests can run in parallel safely
graph TB
subgraph test_env["Each Test Gets Its Own World"]
TD["TempDir::new()"]
TD --> CONFIG_FILE["config.toml<br/>(points library_dir to temp)"]
TD --> SOURCE_DIR["source/<br/>skill-a/SKILL.md<br/>skill-b/SKILL.md"]
TD --> LIBRARY_DIR["library/<br/>(copies + symlinks created here)"]
TD --> TARGET_DIR["target/<br/>(symlinks distributed here)"]
end
subgraph assertions["Assertions"]
FS["Filesystem checks<br/>is_symlink(), exists(),<br/>read_link(), read_to_string()"]
COUNTS["Result struct counts<br/>created, unchanged,<br/>updated, linked, removed"]
OUTPUT["CLI stdout<br/>predicate::str::contains()"]
end
test_env --> assertions
Test Dependencies
Defined in the workspace Cargo.toml and used via [dev-dependencies]:
| Crate | Version | Purpose |
|---|---|---|
tempfile | 3 | TempDir for filesystem isolation in unit tests |
assert_cmd | 2 | Run compiled binary as subprocess in integration tests |
assert_fs | 1 | TempDir for integration tests (compatible with assert_cmd) |
predicates | 3 | Composable stdout/stderr assertions (contains, and, etc.) |
How to Run Tests
# CLI/core tests only (default for changes under crates/tome/)
make test-core # or: cargo test -p tome
# Desktop tests only (run for crates/tome-desktop/ or shared API changes)
make test-desktop # or: cargo test -p tome-desktop
# All workspace tests
make test
# Just one crate
cargo test -p tome
# A specific test by name
cargo test test_name
# Tests in a specific module
cargo test -p tome -- discover::tests
# Only integration tests
cargo test -p tome --test cli
# With output (see println! from tests)
cargo test -- --nocapture
CI Pipeline
GitHub Actions runs on every push to main and every PR, on both ubuntu-latest and macos-latest:
graph LR
subgraph matrix["Matrix: ubuntu + macos"]
A["cargo fmt --check"] --> B["cargo clippy -D warnings"]
B --> C["cargo test --all"]
C --> D["cargo build --release"]
end
PUSH["Push to main<br/>or PR"] --> matrix
The full pipeline is defined in .github/workflows/ci.yml. Running it locally is equivalent to:
make ci # runs: fmt-check + lint + test
Roadmap
| Version | Theme | Key Features | Status |
|---|---|---|---|
| v0.1.x | Polish & UX | Wizard improvements, progress spinners, table output, GitHub Pages docs | ✓ |
| v0.2 | Scoped SOT | Library copies skills (not symlinks), git-friendly library dir | ✓ |
| v0.2.1 | Output Layer | Data struct extraction, warning collection, --json for list | ✓ |
| v0.3 | Connector Architecture | BTreeMap targets, KnownTarget registry, npm skill source research | ✓ |
| v0.3.x | Portable Library (MVP) | Per-machine preferences, tome update, lockfile | ✓ |
| v0.4.1 | Browse | tome browse (ratatui+nucleo): fuzzy search, preview, sort, actions | ✓ |
| v0.4.2 | Skill Validation | tome lint, frontmatter parsing, cross-tool compatibility checks | ✓ |
| v0.5 | Managed Sources | Auto-install, remote sync, unified tome sync | ✓ |
| v0.5.1 | Bugfix | Default library_dir from TOME_HOME, skip managed skills to own tool | ✓ |
| v0.5.2 | Bugfix | Legacy managed symlink cleanup during sync | ✓ |
| v0.5.3 | UX & CLI Polish | NO_COLOR, --no-input, grouped triage, batch cleanup, docs update | ✓ |
| v0.5.4 | Infrastructure | Config-based tool root, --json, signal handling, frontmatter, XDG config | ✓ |
| v0.6 | Unified Directory Model | Bidirectional directories, git sources, per-target skill selection | ✓ |
| v0.7 | Wizard Hardening | WIZ-01–05 invariants, find_known_directories_in coverage, circular-path detection, legacy-config detection | ✓ |
| v0.8 | Cross-Platform Polish | Partial-failure visibility, arboard clipboard, xdg-open, lockfile/save ordering hotfixes | ✓ |
| v0.9 | Cross-Machine Path Overrides | [directory_overrides.<name>] schema, override-annotated diagnostics, StatusMessage enum redesign | ✓ |
| v0.10 | Library-Canonical Core | Managed skills as real-directory copies (not symlinks), marketplace adapter, lockfile-authoritative reconcile, Unowned lifecycle, HARD-* hardening, tome migrate-library | ✓ |
| v0.11 | Polish + Observability | tracing substrate, sync diagnostics, doctor categorization, last-sync stamping, FIX-01..06 bundle | ✓ |
| v0.12 | Doctor/Status Surface | Repair categorization, status table polish, follow-up bugfixes (Phases 18–19) | ✓ |
| v0.13 | tome add UX | /tree/<ref>/<subdir> URL form, --subdir, auto-detect Claude plugin layouts | ✓ |
| v0.14 | Type+Role UX + Claim Orphan | --role override, doctor’s claim orphan-to-Unowned option | ✓ |
| v0.15 | Generic Managed Source | Directory + Managed role combo (pfw-style flat-directory package managers as first-class managed sources) | ✓ |
| v0.16 | Doctor Diagnostics Expansion | Broken-frontmatter Warning, real-dir-in-target auto-repair (ConsolidateTargetRealDirToSymlink) | ✓ |
| v1.0 | Desktop GUI (Tauri) | Cross-platform desktop app on top of the existing CLI library (drafted) | 📋 |
v0.1.x — Polish & UX
- Wizard interaction hints: Show keybinding hints in MultiSelect prompts (space to toggle, enter to confirm) — embedded in prompt text to work around
dialoguer’s limitation. - Clarify plugin cache source: Clarified in v0.4.1 (#312).
- Wizard visual polish: Color, section dividers, and summary output via
console::style()— implemented inwizard.rs. - Modern TUI with welcome ASCII art: Evaluate
ratatuivsconsole+indicatifbefore committing to a framework. → Decision: ratatui + nucleo for interactive commands (tome browse), plain text for non-interactive commands. See v0.2.1 and v0.4.1. - Progress spinners for sync (
indicatif): Spinners during discover → consolidate → distribute → cleanup steps, implemented inlib.rs. - Table-formatted output (
tabled):tabled::Tableused fortome listandtome statusoutput. - Explain symlink model in wizard: Clarify that the library uses symlinks (originals are never moved or copied), so users understand there’s no data loss risk.
- Optional git init for library: Wizard asks whether to
git initthe library directory for change tracking — implemented inwizard.rs. - Fix
installed_plugins.jsonv2 parsing: Current parser expects a flat JSON array (v1); v2 wraps plugins in{ "version": 2, "plugins": { "name@registry": [...] } }— discovery silently finds nothing. Support both formats going forward. - Finalize tool name: Decided on tome — “Cook once, serve everywhere.”
- GitHub Pages deployment: Add CI workflow to build and deploy mdBook +
cargo docto GitHub Pages.
v0.2 — Scoped SOT
Make the library the source of truth for local skills. tome sync copies skill directories into the library instead of creating symlinks back to sources. Distribution to targets still uses symlinks (target → library).
- Library as canonical home (#37): Local skills live directly in the library (real directories, not symlinks).
tome synccopies from sources into library, making the library the single source of truth. - Git-friendly library directory (#42): Library directory works as a git repo — local skills tracked in git, distribution symlinks are separate.
- Two-tier symlink model: Sources → (copy) → Library → (symlink) → Targets. Sources are read-only inputs; the library owns the canonical copies; targets get symlinks into the library.
- Idempotent copy semantics: Only copy when source content has changed (compare timestamps or content hashes). Skip unchanged skills to keep syncs fast.
Not in scope (deferred to v0.5): lockfile, tome update, per-machine preferences, managed source support, git-backed backup.
v0.2.1 — Output Layer ✓
Decouple output rendering from business logic. Prerequisite for tome browse (v0.4.1) and --json output (#167), ensuring new connectors in v0.3 get clean data separation from day one.
- Renderer trait (
ui/mod.rs): Abstract output interface for sync reporting, skill listing, status display, doctor diagnostics, warnings, and confirmations — Closed as superseded (#183). Data struct extraction was the real prerequisite; ratatui (v0.4.1) will consume data structs directly rather than going through a trait. - Data struct extraction:
status::gather() -> StatusReport,doctor::diagnose() -> DoctorReport, sync pipeline returnsSyncReport— pure computation separated from rendering - Warning collection: Replace scattered
eprintln!in discover/library/distribute withVec<Warning>returned alongside results - TerminalRenderer: Reimplements current output using
console/indicatif/tabled/dialoguer— identical user-facing behavior, routed through the trait — Superseded along with Renderer trait. - QuietRenderer: Replaces
quiet: boolparameter threading with a renderer that suppresses non-error output — Closed as superseded (#188). Not needed without the Renderer trait;quietparameter threading is sufficient. -
--jsonfortome list(#167): Trivially enabled once data structs exist — serializeVec<SkillRow>directly
v0.3 — Connector Architecture ✓
Replaced the hardcoded Targets struct with a flexible, data-driven target configuration. Originally scoped as a full connector trait architecture, but the pragmatic first step — config flexibility — shipped as the milestone deliverable.
Delivered
- Generic
[[targets]]array: Replaced the hardcodedTargetsstruct withBTreeMap<String, TargetConfig>(#175). Each target has aname,path,method(symlink/mcp), and connector-specific options. Data-drivenKnownTargetregistry in the wizard enables custom target support without code changes. - npm-based skill source research (#97): Investigated
npx skills(Vercel Labs). Confirmed: canonical copies in.agents/skills/<name>/, lockfile at.agents/.skill-lock.json(v3) with content hashes and provenance. ADirectorysource pointed at~/.agents/skills/works for basic discovery; a dedicated source type would preserve provenance metadata from the lockfile. -
.agents/skills/as emerging universal path: 9 agents converge on.agents/skills/as the project-scoped canonical skills directory. Documented in tool-landscape research.
Moved forward
- Connector trait → #192. Unified source/target interface. The BTreeMap solved config flexibility; the trait solves architectural abstraction.
- Built-in connectors → Part of #192. Claude, Codex, Antigravity, Cursor, Windsurf, Amp, Goose, etc.
- Format awareness per connector → Captured in #57 (Format Transforms).
.claude/rules/syncing → #193. Managed from~/.tome/rules/, distributed to each target’s rules dir. See Tentative — Format Transforms.- Instruction file syncing → #194. Managed from
~/.tome/instructions/, mapped to tool-specific filenames. See Tentative — Format Transforms.
v0.3.x — Portable Library (MVP) ✓
Complete the multi-machine skill management story. The lockfile (#38, shipped early) provides the diff mechanism; this milestone adds the interactive UX and per-machine control.
- Per-machine preferences (#39) (
~/.config/tome/machine.toml): Per-machine opt-in/opt-out for skills — machine A uses skills 1,2,3 while machine B only wants 1 and 3. Disabled skills stay in the library but are skipped during distribution. -
tome updatecommand (#40): Reads lockfile, diffs against local state, surfaces new/changed/removed skills interactively. Offers to disable unwanted new skills. Notification-only for managed plugins — auto-install deferred to v0.5.
v0.4.1 — Browse
Interactive skill browser. Depends on v0.2.1 output layer for clean data access.
tome browse — Interactive TUI (#162)
Full-screen interactive skill browser using ratatui for rendering and nucleo (Helix editor’s fuzzy engine) for matching. skim was ruled out because it owns the terminal and can’t be embedded in a ratatui layout.
- Basic list with fuzzy search (#164): fzf-style interactive filtering of library skills
- Preview panel (#165): Split-pane layout showing SKILL.md content alongside the list
- Sorting and grouping (#166): Sort by name/source/last synced, group by source
- Detail screen with actions (#169): Per-skill actions (view source, copy path, disable/enable)
Other v0.4.1 Items
- Enhance
tome statusdisplay (#168): Health indicators (✓/✗/⚠), tilde-collapsed paths - Clarify plugin cache source wording (#312): Clarified as “active plugins installed from Claude Code marketplace”
v0.4.2 — Skill Validation & Linting
YAML frontmatter parsing and a tome lint command that catches cross-tool compatibility issues. See Frontmatter Compatibility for the full spec comparison. Tracked in #47 and #176.
Frontmatter Parsing
- Add
serde_yamldependency - Create
SkillFrontmatterstruct with typed fields (name, description, license, compatibility, metadata, allowed-tools, Claude Code extensions) -
skill.rsmodule: extract and parse YAML frontmatter from---delimiters, capture unknown fields via#[serde(flatten)] - Parse frontmatter during discovery (enrich
DiscoveredSkill) — deferred to follow-up - Store parsed metadata for status display — deferred to follow-up
tome lint Command
-
lint.rsmodule with tiered validation (error/warning/info) -
tome lintCLI command with--format text|jsonand optionalPATHargument - Exits with code 1 on errors (CI-friendly)
- Missing
nameis a warning (Claude Code infers from directory), name mismatch is an error - Unicode Tag codepoint scanning (U+E0001–U+E007F)
- Non-standard field detection (version, category, tags, etc.)
- Platform limit warnings (description >500 chars for Copilot, body >6000 chars for Windsurf)
Enhance Existing Commands
-
tome doctor: Add frontmatter health checks alongside existing symlink diagnostics — parse all library skills and report validation results -
tome status: Show parsed frontmatter summary per skill — name, description (truncated), field count, and any validation issues inline
Target-Aware Warnings (Future)
Requires the v0.3 connector architecture. When distributing to specific targets, warn about:
- Fields unsupported by that target
- Description length exceeding target’s limit
- Body syntax incompatible with target (e.g., XML tags,
!command,$ARGUMENTS)
v0.5 — Managed Sources ✓
Auto-install managed plugins, remote sync, and unified tome sync flow. Builds on the portable library foundation from v0.3.x.
- Auto-install managed plugins (#347, #355):
tome syncdetects missing managed plugins from the lockfile, prompts to install viaclaude plugin install <registry_id>. Runs before discovery so newly installed plugins are found immediately. - Git repo scope to
~/.tome/(#348, #350): Backup git repo moved from~/.tome/skills/to~/.tome/, tracking skills,tome.toml,tome.lock, and future config. Top-level.gitignoreexcludes.tome-manifest.json. - Remote sync in
tome sync(#349, #353): Pull from remote before sync, push after commit. Fast-forward-only merges — diverged histories bail with actionable error.tome backup initoffers remote setup wizard. - Collapse
tome syncandtome update(#352):tome updateremoved (breaking).tome syncnow includes lockfile diffing and interactive triage.--no-triageflag for CI/scripts. - Claude marketplace first (#41): Managed source targeting the Claude plugin marketplace. Version pinning via version string and git commit SHA (
gitCommitSha). Lockfile recordsregistry_id,version, andgit_commit_shafor full reproducibility. - Git-backed backup & restore (#94):
tome backup init/snapshot/list/restore/diffwith optionalauto_snapshotpre-sync snapshots via[backup]config section. - Portable config paths: Wizard writes
~/-prefixed paths intome.tomlfor portability across machines. - Shell completions (#208):
tome completions <shell>for bash, zsh, fish, PowerShell viaclap_complete - Demote lockfile write failure to warning (#224): Lockfile write failures demoted to warning
- Skill lifecycle (#252): Forking, evaluation, and publishing workflow — unscoped, deferred
v0.5.1 — Bugfix ✓
- Default
library_dirfrom TOME_HOME (#383):library_dirdefaults toTOME_HOME/skillsinstead of hardcoded~/.tome/skills - Skip managed skills to own tool (#385): Managed plugin skills (e.g., from
~/.claude/plugins) are no longer distributed to their own tool’s skills directory, preventing duplicates
v0.5.2 — Bugfix ✓
- Legacy symlink cleanup (#385):
tome syncremoves legacy managed skill symlinks from targets on first run after upgrading
v0.5.3 — UX & CLI Polish ✓
- NO_COLOR support (#371):
consolecrate respectsNO_COLORenv var — colors disabled in non-TTY and whenNO_COLOR=1 - Semantic exit codes (#375): Exit code 2 for invalid arguments (via clap), exit code 1 for runtime errors
-
--no-inputflag (#376): Global flag to suppress all interactive prompts (cleanup, triage, install, doctor). Implies--no-triagefor sync. Errors ontome init. - Keybinding hints (#381): “(space to toggle, enter to confirm)” on triage MultiSelect prompt
- Managed skill counts (#389): Sync output shows
skipped_managedcount per target (e.g., “216 skipped (managed)”) - Group triage by source (#380): Changes grouped under source headers with +/~/- indicators
- Batch stale messaging (#382): Cleanup shows all stale skills grouped by previous source, confirms once
- Subcommand help examples (#378): Every subcommand has usage examples in
--help - Docs update (#368): README and commands.md updated with all commands and new flags
v0.5.4 — Infrastructure ✓
- Config-based tool root detection (#390): Derive tool root from source/target config paths instead of hardcoded
TOOL_DIRS. Falls back gracefully when paths can’t be resolved. - Lockfile write = error (#394): Lockfile write failure now blocks sync instead of just warning
-
--jsonfor status/doctor (#374): Structured JSON output withCountOrErrortype for clean API shape - Signal handling (#373): Graceful Ctrl-C via
ctrlccrate — clean exit with code 130 - Frontmatter in discovery (#393): Parse frontmatter during
tome syncdiscovery; warnings on parse failures - XDG config for tome_home (#369):
~/.config/tome/config.tomlwithtome_homefield — no shell env var needed - Closed: Merge lockfile/manifest (#370) — not planned, separation is by design
- Deferred: Init consolidation (#362) — moved to v0.6 (unified directory model)
v0.6 — Unified Directory Model
Replaces separate [[sources]] / [targets.*] config with a unified [directories.*] concept. Each directory declares its relationship to tome (managed, synced, library-only, target-only). See #396 for the full design.
- Unified directory config (#396): Replace sources/targets with bidirectional directories
- Git sources (#58): Remote skill repos with clone/pull, branch/tag/SHA pinning, private repo support
- Standalone SKILL.md import (#92): Import from arbitrary GitHub repos without plugin.json
- Per-target skill selection (#253): Control which skills are distributed to which targets
-
tome remove(#392): CLI to remove sources/targets from config - Change skill source (#395): Switch a skill’s source (local → git) without re-adding
- Browse TUI polish (#365): Theming, match highlighting, scrollbar, markdown preview
v0.7 – v0.16 — see .planning/ROADMAP.md
Detailed milestone tracking moved to .planning/ROADMAP.md and per-milestone documents under .planning/milestones/. The summary table at the top of this file lists the shipped themes; the CHANGELOG is the authoritative per-release log.
Originally-planned v0.7 Skill Composition (“Wolpertinger”) — multi-source skill synthesis via LLM — was deferred indefinitely and moved to Future Ideas. v0.7 instead shipped wizard hardening (WIZ-01..05).
Tentative — Per-Target Skill Management
Convenient UX for managing which skills are active per target, and whether per-target config should live centrally or locally. Builds on #253 (per-target skill selection in machine.toml).
- Target skill management commands: Convenient CLI for adding/removing active skills per target without editing TOML by hand. E.g.
tome target claude enable my-skill,tome target codex disable my-skill, or interactive viatome browseactions. - Package-level toggling: Enable/disable all skills from a package at once (e.g.
tome target codex disable --package axiom-ios-skills). Requires the package/repo label fromSkillProvenance.registry_id. Also support glob patterns (e.g.asc-*). Inmachine.toml, this could bedisabled_packages = [...]alongside the existingdisabledskill set. - Local per-target config: Investigate whether per-target config should live in the target folder itself (e.g.
~/.claude/tome.toml) instead of only centrally. Trade-offs:- Central (
~/.tome/tome.toml): single source of truth, easy to version-control, but needs namespacing for per-target overrides - Local (e.g.
~/.claude/tome.toml): self-contained per tool, discoverable where the tool lives, but scattered across filesystem - Hybrid: local overrides central if present — local file wins for that target’s skill selection, central file is the default. Central config would need a
[targets.<name>.skills]section or similar namespacing. - Current leaning: local replaces central for simplicity — if a local
tome.tomlexists in the target folder, it fully owns that target’s skill selection. No merge semantics to reason about. - Remaining question: How does this interact with
machine.tomlper-machine preferences?
- Central (
Tentative — Format Transforms
Not yet scheduled. Needs more design work before committing to a milestone.
- Rules syncing (#193): Manage tool-specific rule files from
~/.tome/rules/, distributed via symlinks to each target’s rules directory (.claude/rules/,.cursor/rules/, etc.) - Instruction file syncing (#194): Manage root-level instruction files (CLAUDE.md, AGENTS.md, GEMINI.md, .cursorrules) from
~/.tome/instructions/. High complexity — each tool expects a different filename and format; needs a mapping layer and conflict handling. - Connector trait (#192): Unified source/target interface as an architectural abstraction over the existing
BTreeMapconfig. - Pluggable transform pipeline: Connectors declare input/output formats; the pipeline resolves the translation chain. Preserves original format — transforms are output-only.
- Copilot
.instructions.mdformat: Copilot’s.instructions.mdas a transform target alongside Cursor.mdcand Windsurf rules. - Deprecate
DistributionMethod::Mcp: Removed in #262. No known targets used MCP distribution — all major AI coding tools read SKILL.md files from disk via symlinks. Thetome-mcpbinary,tome servecommand, andTargetMethod::Mcpdistribution path were removed along with thermcpandtokiodependencies. MCP support can be re-added if a concrete use case emerges.
Tentative — Expand Wizard Auto-Discovery
Scope needs clarifying before committing. The question: which global home-dir skill paths exist for tools not yet covered by the wizard (e.g. ~/.cursor/skills/, Windsurf’s equivalent, etc.)? Per-project paths (.github/skills/, .cursor/rules/) are explicitly out of scope — only global home-dir paths qualify.
- Audit which global home-dir paths exist across all major tools
- Add any confirmed paths to
KNOWN_SOURCESinwizard.rs
Tentative — Watch Mode
Not yet scheduled. Low priority until core sync pipeline stabilizes.
tome watchfor auto-sync on filesystem changes (#59)- Debounced fsnotify-based watcher
- Optional desktop notification on sync
Future — Companion macOS App
Native macOS skill manager app (inspired by CodexSkillManager):
- Browse & manage library: View all skills in the tome library with rendered Markdown previews using swift-markdown-ui
- Visual skill editing: Edit skill frontmatter and body with live preview
- Sync trigger: Run
tome syncfrom the GUI with status feedback - Source & target management: Configure sources and targets visually instead of editing
tome.toml - Health dashboard: Surface
tome doctorandtome statusdiagnostics in a native UI - Import/export: Import skills from folders or zip files; export skills for sharing
- Tech stack: SwiftUI (macOS 15+), swift-markdown-ui for rendering, invokes
tomeCLI under the hood
Future Ideas
- Plugin registry: Browse and install community skill packs (precursor to Skill Composition / “Wolpertinger”)
- Skill Composition / “Wolpertinger”: Originally planned for v0.7 (deferred). Multi-source skill synthesis (#267), ACP-based authentication, skill evaluation/creation companion skill (#268),
tome lintstandard validation extension. - Conflict resolution UI: Interactive merge when skills collide
Shell completions: Shipped in v0.4.1 (#208)Homebrew formula: Shipped via cargo-dist (brew install MartinP7r/tap/tome)- Backup snapshots: Moved to v0.5 as git-backed backup (#94)
- Token budget estimation: Show estimated token cost per skill per target tool in
tome statusoutput - Security audit command:
tome auditto scan skills for prompt injection vectors, hidden unicode, and suspicious patterns - Portable memory extraction: Suggest MEMORY.md entries that could be promoted to reusable skills (
tome suggest-skills) - Plugin output generation: Package the skill library as a distributable Claude plugin, Cursor plugin, etc.
- Publish on crates.io: Make
tomeinstallable viacargo install tomefrom the crates.io registry - Improve doc comments for
cargo doc: Module-level//!coverage is uneven across modules; no# Examplessections. Low priority polish. - Syntax highlighting in browse preview: Render SKILL.md with markdown/YAML syntax highlighting in the
tome browsedetail panel (e.g. viasyntectortree-sitter-highlight). Low priority polish. - Package/repo label for skills: Surface the plugin name (e.g.
martinp7r/axiom-ios-skills) or git repo slug as a searchablepackagefield in browse. CurrentlySkillProvenance.registry_idstores this for marketplace skills but it doesn’t reach the browse UI or fuzzy search. Would also enable “group by package” in browse. : Shipped in v0.3.7tome relocate(#333): Shipped in v0.3.7tome eject(#334)- Library inside a parent git repo: Superseded by the “git repo scope” item in v0.5. Open design question: scope git to just skills, or broader
~/.tome/home including hooks/commands/agents. - Plugin marketplace discovery (#309): Make tome skills discoverable in the Claude Code marketplace
- Vercel skills.sh format compatibility (#304): Evaluate mapping tome lockfile to/from Vercel’s
skills-lock.jsonfor cross-ecosystem compatibility - Central library architecture (#306): Source skills should not be used directly — always go through the library as single source of truth
- Skill-scribe extraction (#307): Extract format conversion into a standalone
skill-scribepackage. See also format transform pipeline (#57)
API Reference
The full Rust API documentation is generated by cargo doc and hosted alongside these docs.
Key public types
For a v1.0 GUI / library consumer, the most important types to know about:
SyncReport— return shape of the fullsync()pipeline (reconcile → discover → consolidate → distribute → cleanup → save). Primary data source for any “what happened this sync” surface.reconcile::ReconcileReport— outcome of one reconcile pass (Match / Drift / Vanished / Missing classifications plus edit-in-library user decisions).marketplace::MarketplaceAdapter— pluggable trait for managed-skill install/update/availability. Two production implementations ship (ClaudeMarketplaceAdapter,GitAdapter); third-party adapters can implement the trait directly (sealing is tracked as a v1.0 follow-up in #518).CleanupResult— bucket-by-bucket cleanup outcomes (removed-from-config / missing-from-disk / now-in-exclude-list). Accessors are read-only; the renderer owns the user-facing surface.status::StatusReport+status::DirectoryStatus—tome status --jsonshape. Since v0.12.0,DirectoryStatus.roleis the typedDirectoryRoleenum (with the human-readable description in a separaterole_descriptionfield).doctor::DoctorReport—tome doctor --jsonshape, includingIssueCategory(Library / Directory / Config / Foreign-symlink) groupings.
The architecture narrative — how these types fit together, why the library is canonical, how reconcile interacts with the manifest and lockfile — lives in Architecture.
Newtypes
Domain-specific wrappers with validation at construction:
SkillName— validated skill identifierconfig::DirectoryName— validated directory entry namevalidation::ContentHash— SHA-256 of a skill directory, normalized to lowercase hexpaths::TomePaths— bundle oftome_home/library_dir/config_dirto prevent parameter-order bugs