NAME
Skilletor::Resolver - What each scope resolves to – a sync's steps 1–3, stopped before anything is built
VERSION
version 0.001
SYNOPSIS
use Skilletor::Resolver;
my $r = Skilletor::Resolver->new( home => $ENV{HOME}, project_dir => $cwd );
my $report = $r->resolve( scope => 'all' );
# { scopes => [ { scope => 'user', items => [...], sources => [...], warnings => [...], trustRequests => [...] }, ... ] }
# or { scopes => [], error => '…/skilletor.json: …' }
DESCRIPTION
The port of the reference's resolveItems (engine.ts, k143): a sync's own steps 1–3 (spec §6.1) – config load and merge, trust, every needed source resolved into the shared cache, catalogs scanned, wildcards and bundles expanded with the overlap rules (spec §3, §15) – stopped before anything is built: nothing is rendered, nothing written to a target, the lock or the state's records. Like the reference it holds the sync lock ("with_lock" in Skilletor::State) while it runs and sweeps what a killed run left in the cache first. Most callers want the item lookups of Skilletor. Skilletor::Engine extends this class: a sync runs the very same scope resolution, as the reference's syncScopeRun serves both, and builds what it finds.
The report is the reference's ResolveReport, field for field, so the two compare directly (the shared conformance cases do): per scope its items, sources, warnings – the same texts – and trustRequests.
An item:
{
type => 'skill', name => 'perl-moo', source => 'shared',
declaredBy => [ 'perl-moo@shared' ], # the entries declaring it, as written
via => [ 'bundle:perl@shared' ], # only when bundles yield it too
sourceDir => '/home/me/.claude/skilletor/cache/79eb247685294166',
item => { type, name, dir?, files => [ relative paths ], description?, error? },
vars => { ... }, # source < bundle < user < project < local
}
A source: { name, state => 'resolved' | 'untrusted' | 'failed' | 'unknown', backend?, cache?, dir?, version? }.
Two differences from the reference are deliberate and switchable:
No harness needed. The reference fails a resolve, like a sync, with "no agent harness detected" on a machine with neither Claude Code nor Codex markers, although resolution does not depend on a harness. Here that check is only made with "require_harness"; without it the targets warnings (project targets not in use here) are given when a harness is known and left out otherwise.
Fetch policy. "fetch"
always(the default) resolves every source as a sync does: git fetches, url downloads, a failure falls back to the cache with a warning.missingfetches only a source with no usable cache yet,neverfetches nothing and serves what the cache holds (a source never fetched is a warning). Both read the cache the reference writes.
home
Required.
project_dir
The project; none, or the home dir itself, means no project scope.
claude_config_dir
CLAUDE_CONFIG_DIR by default; an empty value counts as unset, then <home>/.claude. Claude Code's config dir is the user scope's .claude: the user config, the lock, the Claude roots, the state dir, Claude's own marker (.claude.json) and plugin state, and the briefing lookup's skills all lie under it.
state_root
Default <claude_config_dir>/skilletor, so <home>/.claude/skilletor (trust, the sync lock).
cache_root
Default <state_root>/cache.
codex_home
$CODEX_HOME by default: where Codex's markers lie.
markers
The harness markers ("default_markers" in Skilletor::Targets).
require_harness
True: fail as the reference does when no harness is detected and the user config names no targets. Default false.
fetch
always (default), missing or never.
timeout_ms
Per-source network timeout; the backends' default without it.
lock_timeout_ms
How long to wait for another holder of the sync lock (default 5000).
resolve
$r->resolve( scope => 'user' | 'project' | 'all', throw => 0 );
The report. A config error (or, with "require_harness", a missing harness) is its error, with no scopes – or thrown with throw. An unreadable lock file and a sync lock held too long throw.
project_dir_of
The project dir in effect (undef when there is no project scope).
bundle_label
Skilletor::Resolver->bundle_label( { name => 'perl', source => 'shared' } ); # bundle:perl@shared
SUPPORT
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHOR
Torsten Raudssus <getty@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.