NAME
Skilletor::Targets - Which agent harnesses a sync installs for (detection and the targets merge)
VERSION
version 0.001
SYNOPSIS
use Skilletor::Targets qw( default_markers detect_harnesses select_targets );
my $markers = default_markers( $home, $ENV{CODEX_HOME} );
my $sel = select_targets(
{ user => $config->user->{targets}, project => $config->project && $config->project->{targets} },
detect_harnesses($markers),
$markers,
);
# { user => ['claude'], project => ['claude'], warnings => [] }
DESCRIPTION
The detection and target selection of the reference's targets.ts (spec §14.1). A harness is detected by markers it creates itself, never by ~/.claude alone.
It also holds the reference's layout table (LAYOUTS, spec §14.2, §16.2): where each harness reads each item type in each scope, how a lock key names its harness, which types install as .local. files. The Perl port writes for Claude Code alone; the table is whole because the managed blocks list every harness's roots and lock keys of every harness are parsed, kept and reported as the reference does.
A root context ($rc) is { base, scope, codex_home?, hermes_home? }: the scope's base (the home or the project root), $CODEX_HOME and the Hermes home, either empty for its default.
default_markers
default_markers( $home, $codex_home );
{ claude => [...], codex => [...] }: the paths whose existence means the harness is in use.
detect_harnesses
The detected harnesses, in the order claude, codex.
select_targets
select_targets( { user => $u, project => $p }, $detected, $markers );
{ user => [...], project => [...], warnings => [...] }; throws Skilletor::Error::Target when no harness applies.
default_hermes_home
default_hermes_home( $home, $platform, \%env );
lock_key
lock_key( codex => 'skills/foo' ); # codex:skills/foo
supports
True when the harness has a place for the type.
root_of
root_of( $rc, $harness, $type ); # undef when the harness takes no such type
root_of_key
The root a lock key's files live under; undef for an unknown prefix or type.
served_via
served_via( $active, $harness, $type, $scope );
The other active harness whose copy serves this one (Hermes reads a project skill through the Codex copy), or undef.
receivers
receivers( $active, $type, $scope ); # [ the harnesses that get a copy of their own ]
is_block_type
is_local_type
all_roots
my @roots = all_roots($rc);
Every distinct root of a scope that can hold a .gitignore block, in the reference's order; never a Hermes root.
target_gaps
target_gaps( $keys, $active, $scope ); # [ { key }, { key, missing } ]
place_output
place_output( claude => agent => [ [ 'agents/x.md', $bytes ] ] );
# { output => [ [ 'agents/.local.x.md', $bytes ] ], claims => [ 'agents/x.md' ] }
lacks_local_prefix
True when an item of a .local. type owns a file without the prefix.
DETECTED
The harnesses detection looks for: claude, codex.
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.