Changes for version 0.001 - 2026-10-24

  • Follows the reference's k145: CLAUDE_CONFIG_DIR is the user scope's .claude (config, lock, roots, state dir, markers, briefing lookup); a source's non-object vars, a lock via that is no array of strings and a truncated url tarball are errors.
  • Initial release: the Perl port of skilletor, beside the TypeScript reference in the same repository, sharing its config files, its ~/.claude/skilletor/cache and its trust.json.
  • Skilletor::Config loads the user, project and local config with the reference's merge and precedence rules (per-field source merge with origins, author mode, entries without a backend, "ref": null, vars, gitignore, claudeSettings, targets), reports the same errors in the same order, and edits a config file as `add`/`install`/`uninstall` do.
  • Skilletor::Entry parses [type:]name@source, patterns and [bundle:]name@source; Skilletor::Spec resolves `add` shorthands (forge links, scp-like and transport::address forms, probed generic hosts).
  • Sources: Skilletor::Source::Local, ::Git (shallow fetch, refs, SHA pins, offline cache reuse, repair and restore after killed runs, lock-file sweep) and ::Url (https tarball, ETag or sha256 version, staged swap, sweep). Skilletor::Cache names cache directories as the reference does, so both implementations share one fetch.
  • Skilletor::Backend picks a source's backend (author mode) for trust and fetch alike; Skilletor::State reads and writes trust.json; Skilletor::Targets detects harnesses and merges targets.
  • Skilletor::JSON parses like JSON.parse (key order, V8's messages) and writes like JSON.stringify(value, null, 2), byte for byte; Skilletor::URL, ::Gzip, ::Tar, ::JSString and ::FSUtil carry the Node behaviour that reaches a name, a byte or a message.
  • Skilletor resolves skills, agents and rules as a sync would install them, without installing: resolve_skill, resolve_agent, resolve_rule and resolve_rules give the main file in the source tree or the shared cache, resolve_item, resolve_items and items the whole record. Both scopes declaring a name follow Claude Code's precedence: the personal skill wins, the project's agent wins, rules of both scopes apply (the user's first) – resolve_rule throws Skilletor::Error::Ambiguous rather than hide one. fetch => always, missing or never picks the network use; no agent harness is needed (require_harness restores the reference's check). An item with a .njk file is flagged templated and refused as an include (Skilletor::Error::Unsupported): the port renders no templates.
  • Skilletor::Resolver ports the reference's resolveItems: trust, sources into the cache, catalogs, wildcards, bundles with their vars and entries of other sources, the overlap rules and the lock's kept offers, with the reference's warnings and report, under its sync lock.
  • Skilletor::Catalog scans a source tree (layout, plugin.json, the Claude project layout, a source's path, item errors), Skilletor::Bundles parses and expands bundle files, and Skilletor::Frontmatter reads the reference's YAML subset, with its error messages. Skilletor::Lock reads lock files.
  • Skilletor::State takes the sync lock (sync.lock/) as the reference does, so the two exclude each other; the git, url and local sources gain cached, their cache without the network.
  • Skilletor::Tar refuses a header whose size field is no non-negative number as a corrupt archive ("corrupt tar entry (size): <name>"), as the reference now does: a url source falls back to its cache.
  • Skilletor->sync, ->check and ->status (Skilletor::Engine) port the reference's commands for the Claude Code target: the same installed files and executable bits, lock, .gitignore blocks, .worktreeinclude and .claude/settings.json plugin requirement (k140), conflicts and force, removal of what is no longer declared, partial entries after a failed write, the briefing check, the same JSON reports and the same state records (render-inputs.json, sources-read.json, unreached.json), so either implementation's check accepts what the other synced. A scope targeting Codex or Hermes, or a sync where the CLI left their state, is refused with nothing touched. A .njk item is never installed unrendered: the sync warns, keeps what the CLI installed, and leaves the scope open for the CLI's next sync.
  • Skilletor::Apply, ::Render (copy only), ::Gitignore, ::ClaudeSettings, ::Briefing and ::Report port apply.ts, the copy half of render.ts, gitignore.ts, claudesettings.ts, briefing.ts and report.ts (with the CLI's status text and exit codes); Skilletor::Lock writes locks, Skilletor::State keeps the records check reads, Skilletor::Targets has the layout table, Skilletor::JSON takes a string indent.
  • t/60-conformance.t runs every step of the shared conformance cases; t/52-parity-sync.t has the reference and the port sync one machine and compares every byte they leave.
  • Tests replay oracles recorded from the reference (t/data) and, in a checkout with node, drive the reference and the port against the same remotes and cache (t/50-parity.t).

Modules

Install skills, agents and rules from remote sources – the Perl port of skilletor POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
Apply a build plan to disk – diff, atomic writes, conflicts, removal (spec §6.1–6.3) POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
Choose a source's backend (author mode) and build it – one value for trust and fetch POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
Are an installed agent's briefing skills there? (spec §6.7) POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '§6.7)'. Assuming CP1252
Bundle files (spec §15), their expansion, and name patterns POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '§15),'. Assuming CP1252
Where a git or url source is cached – the reference's cache naming POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
Scan a source tree into its installable items, bundles and source metadata
The plugin requirement in a project's committed .claude/settings.json (spec §6.8, k140) POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '§6.8,'. Assuming CP1252
Load, merge and validate the user, project and local skilletor config
sync, check and status for Claude Code – the reference's engine pipeline after the resolve POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
Install entries ([type:]name@source, patterns, bundles) and the names they hold
Exception base class of Skilletor
A lookup that would have to hide one of two items: a rule both scopes declare
A build plan that cannot be applied: an invalid item name, a path leaving its root
A bundle file is broken or cannot be expanded (the reference's BundleError)
A cache that must not be served (the reference's CacheRejected)
A source tree cannot be scanned (the reference's CatalogError)
A config file is invalid (the reference's ConfigError)
YAML frontmatter or a bundle file outside the supported subset (the reference's FrontmatterError)
A text is not JSON (JSON.parse's SyntaxError)
A scope's lock file cannot be read (the reference's LockError)
Another run held the sync lock too long (the reference's SyncLockTimeoutError)
A source backend failed to resolve or check
An add shorthand cannot be resolved (the reference's SpecError)
A url source's archive is unsafe (the reference's TarError)
No agent harness can be targeted (the reference's TargetError)
An item the Perl port cannot serve: a Nunjucks template
File and path helpers that behave as the reference's Node calls do
The reference's YAML subset – agent frontmatter and bundle files POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
The environment of every git run – without git's repository-local variables POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
Managed .gitignore and .worktreeinclude blocks, skill .gitignore files, git's view (spec §6.4) POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '§6.4)'. Assuming CP1252
gunzip and inflate as Node's zlib binding does them, with zlib's messages
JSON read and written exactly as the reference implementation does
A tied hash that keeps a JavaScript object's property order
String operations as JavaScript performs them
A scope's lock file (skilletor.lock.json) – reading, writing, its keys POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
Run a program without a shell – cwd, environment, timeout, captured output POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
Build an item in memory – the copy half of the reference's render.ts POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
The reports of sync, check and status – their shape, their text, their exit codes (spec §8) POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
What each scope resolves to – a sync's steps 1–3, stopped before anything is built POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
The interface of a source backend (local, git, url)
A git source: shallow fetch into the shared cache, refs, SHA pins, offline reuse
A source read straight from a local directory (author mode)
A url source: an https .tar.gz, conditional GET, staged swap into the shared cache
Resolve an add shorthand (owner/repo, a forge link, a URL, a path) to a source
Instance state under ~/.claude/skilletor – trust, the sync lock and the records a sync keeps POD ERRORS Hey! The above document had some coding errors, which are explained below: Around line 3: Non-ASCII character seen before =encoding in '–'. Assuming CP1252
The reference's minimal tar reader: safe file and dir entries only
Which agent harnesses a sync installs for (detection and the targets merge)
The parts of a URL as the WHATWG URL parser (Node's new URL) gives them

Provides

in lib/Skilletor/Frontmatter.pm