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.