[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DAHFX861DQMKM2JZ2G59FR":3,"skill-same:01M6DAHFX861DQMKM2JZ2G59FR":57},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":25,"linkOnly":26,"markdownContent":27,"markdownBody":28,"frontMatter":29,"refName":31,"commitSha":32,"skillDirectory":33,"forksCount":14,"repositoryHtmlUrl":34,"repositoryHomepageUrl":6,"ownerHtmlUrl":35,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":36,"install":37,"resources":50},"01M6DAHFX861DQMKM2JZ2G59FR","perl-patterns",null,"Modern Perl 5.36+ idioms, best practices, and conventions for building robust, maintainable Perl applications.","Prekzursil\u002Fagent-skills-toolchain","Prekzursil","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F54636077?v=4","01M6DACZ1PCQHD99SCR1YXG28B","Andrei Mihai Visalon","01M6DACZ670WZF535V3WYYSS4Z",0,"MIT","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Flibrary\u002Fskills\u002Fperl-patterns\u002FSKILL.md",[],[19,20,21,22,23,24],"perl patterns","patterns","best practices","applications","idioms","conventions","2026-11-10 10:12:30",false,"---\nname: perl-patterns\ndescription: Modern Perl 5.36+ idioms, best practices, and conventions for building robust, maintainable Perl applications.\norigin: ECC\n---\n\n# Modern Perl Development Patterns\n\nIdiomatic Perl 5.36+ patterns and best practices for building robust, maintainable applications.\n\n## When to Activate\n\n- Writing new Perl code or modules\n- Reviewing Perl code for idiom compliance\n- Refactoring legacy Perl to modern standards\n- Designing Perl module architecture\n- Migrating pre-5.36 code to modern Perl\n\n## How It Works\n\nApply these patterns as a bias toward modern Perl 5.36+ defaults: signatures, explicit modules, focused error handling, and testable boundaries. The examples below are meant to be copied as starting points, then tightened for the actual app, dependency stack, and deployment model in front of you.\n\n## Core Principles\n\n### 1. Use `v5.36` Pragma\n\nA single `use v5.36` replaces the old boilerplate and enables strict, warnings, and subroutine signatures.\n\n```perl\n# Good: Modern preamble\nuse v5.36;\n\nsub greet($name) {\n    say \"Hello, $name!\";\n}\n\n# Bad: Legacy boilerplate\nuse strict;\nuse warnings;\nuse feature 'say', 'signatures';\nno warnings 'experimental::signatures';\n\nsub greet {\n    my ($name) = @_;\n    say \"Hello, $name!\";\n}\n```\n\n### 2. Subroutine Signatures\n\nUse signatures for clarity and automatic arity checking.\n\n```perl\nuse v5.36;\n\n# Good: Signatures with defaults\nsub connect_db($host, $port = 5432, $timeout = 30) {\n    # $host is required, others have defaults\n    return DBI->connect(\"dbi:Pg:host=$host;port=$port\", undef, undef, {\n        RaiseError => 1,\n        PrintError => 0,\n    });\n}\n\n# Good: Slurpy parameter for variable args\nsub log_message($level, @details) {\n    say \"[$level] \" . join(' ', @details);\n}\n\n# Bad: Manual argument unpacking\nsub connect_db {\n    my ($host, $port, $timeout) = @_;\n    $port    \u002F\u002F= 5432;\n    $timeout \u002F\u002F= 30;\n    # ...\n}\n```\n\n### 3. Context Sensitivity\n\nUnderstand scalar vs list context — a core Perl concept.\n\n```perl\nuse v5.36;\n\nmy @items = (1, 2, 3, 4, 5);\n\nmy @copy  = @items;            # List context: all elements\nmy $count = @items;            # Scalar context: count (5)\nsay \"Items: \" . scalar @items; # Force scalar context\n```\n\n### 4. Postfix Dereferencing\n\nUse postfix dereference syntax for readability with nested structures.\n\n```perl\nuse v5.36;\n\nmy $data = {\n    users => [\n        { name => 'Alice', roles => ['admin', 'user'] },\n        { name => 'Bob',   roles => ['user'] },\n    ],\n};\n\n# Good: Postfix dereferencing\nmy @users = $data->{users}->@*;\nmy @roles = $data->{users}[0]{roles}->@*;\nmy %first = $data->{users}[0]->%*;\n\n# Bad: Circumfix dereferencing (harder to read in chains)\nmy @users = @{ $data->{users} };\nmy @roles = @{ $data->{users}[0]{roles} };\n```\n\n### 5. The `isa` Operator (5.32+)\n\nInfix type-check — replaces `blessed($o) && $o->isa('X')`.\n\n```perl\nuse v5.36;\nif ($obj isa 'My::Class') { $obj->do_something }\n```\n\n## Error Handling\n\n### eval\u002Fdie Pattern\n\n```perl\nuse v5.36;\n\nsub parse_config($path) {\n    my $content = eval { path($path)->slurp_utf8 };\n    die \"Config error: $@\" if $@;\n    return decode_json($content);\n}\n```\n\n### Try::Tiny (Reliable Exception Handling)\n\n```perl\nuse v5.36;\nuse Try::Tiny;\n\nsub fetch_user($id) {\n    my $user = try {\n        $db->resultset('User')->find($id)\n            \u002F\u002F die \"User $id not found\\n\";\n    }\n    catch {\n        warn \"Failed to fetch user $id: $_\";\n        undef;\n    };\n    return $user;\n}\n```\n\n### Native try\u002Fcatch (5.40+)\n\n```perl\nuse v5.40;\n\nsub divide($x, $y) {\n    try {\n        die \"Division by zero\" if $y == 0;\n        return $x \u002F $y;\n    }\n    catch ($e) {\n        warn \"Error: $e\";\n        return;\n    }\n}\n```\n\n## Modern OO with Moo\n\nPrefer Moo for lightweight, modern OO. Use Moose only when its metaprotocol is needed.\n\n```perl\n# Good: Moo class\npackage User;\nuse Moo;\nuse Types::Standard qw(Str Int ArrayRef);\nuse namespace::autoclean;\n\nhas name  => (is => 'ro', isa => Str, required => 1);\nhas email => (is => 'ro', isa => Str, required => 1);\nhas age   => (is => 'ro', isa => Int, default  => sub { 0 });\nhas roles => (is => 'ro', isa => ArrayRef[Str], default => sub { [] });\n\nsub is_admin($self) {\n    return grep { $_ eq 'admin' } $self->roles->@*;\n}\n\nsub greet($self) {\n    return \"Hello, I'm \" . $self->name;\n}\n\n1;\n\n# Usage\nmy $user = User->new(\n    name  => 'Alice',\n    email => 'alice@example.com',\n    roles => ['admin', 'user'],\n);\n\n# Bad: Blessed hashref (no validation, no accessors)\npackage User;\nsub new {\n    my ($class, %args) = @_;\n    return bless \\%args, $class;\n}\nsub name { return $_[0]->{name} }\n1;\n```\n\n### Moo Roles\n\n```perl\npackage Role::Serializable;\nuse Moo::Role;\nuse JSON::MaybeXS qw(encode_json);\nrequires 'TO_HASH';\nsub to_json($self) { encode_json($self->TO_HASH) }\n1;\n\npackage User;\nuse Moo;\nwith 'Role::Serializable';\nhas name  => (is => 'ro', required => 1);\nhas email => (is => 'ro', required => 1);\nsub TO_HASH($self) { { name => $self->name, email => $self->email } }\n1;\n```\n\n### Native `class` Keyword (5.38+, Corinna)\n\n```perl\nuse v5.38;\nuse feature 'class';\nno warnings 'experimental::class';\n\nclass Point {\n    field $x :param;\n    field $y :param;\n    method magnitude() { sqrt($x**2 + $y**2) }\n}\n\nmy $p = Point->new(x => 3, y => 4);\nsay $p->magnitude;  # 5\n```\n\n## Regular Expressions\n\n### Named Captures and `\u002Fx` Flag\n\n```perl\nuse v5.36;\n\n# Good: Named captures with \u002Fx for readability\nmy $log_re = qr{\n    ^ (?\u003Ctimestamp> \\d{4}-\\d{2}-\\d{2} \\s \\d{2}:\\d{2}:\\d{2} )\n    \\s+ \\[ (?\u003Clevel> \\w+ ) \\]\n    \\s+ (?\u003Cmessage> .+ ) $\n}x;\n\nif ($line =~ $log_re) {\n    say \"Time: $+{timestamp}, Level: $+{level}\";\n    say \"Message: $+{message}\";\n}\n\n# Bad: Positional captures (hard to maintain)\nif ($line =~ \u002F^(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})\\s+\\[(\\w+)\\]\\s+(.+)$\u002F) {\n    say \"Time: $1, Level: $2\";\n}\n```\n\n### Precompiled Patterns\n\n```perl\nuse v5.36;\n\n# Good: Compile once, use many\nmy $email_re = qr\u002F^[A-Za-z0-9._%+-]+\\@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$\u002F;\n\nsub validate_emails(@emails) {\n    return grep { $_ =~ $email_re } @emails;\n}\n```\n\n## Data Structures\n\n### References and Safe Deep Access\n\n```perl\nuse v5.36;\n\n# Hash and array references\nmy $config = {\n    database => {\n        host => 'localhost',\n        port => 5432,\n        options => ['utf8', 'sslmode=require'],\n    },\n};\n\n# Safe deep access (returns undef if any level missing)\nmy $port = $config->{database}{port};           # 5432\nmy $missing = $config->{cache}{host};           # undef, no error\n\n# Hash slices\nmy %subset;\n@subset{qw(host port)} = @{$config->{database}}{qw(host port)};\n\n# Array slices\nmy @first_two = $config->{database}{options}->@[0, 1];\n\n# Multi-variable for loop (experimental in 5.36, stable in 5.40)\nuse feature 'for_list';\nno warnings 'experimental::for_list';\nfor my ($key, $val) (%$config) {\n    say \"$key => $val\";\n}\n```\n\n## File I\u002FO\n\n### Three-Argument Open\n\n```perl\nuse v5.36;\n\n# Good: Three-arg open with autodie (core module, eliminates 'or die')\nuse autodie;\n\nsub read_file($path) {\n    open my $fh, '\u003C:encoding(UTF-8)', $path;\n    local $\u002F;\n    my $content = \u003C$fh>;\n    close $fh;\n    return $content;\n}\n\n# Bad: Two-arg open (shell injection risk, see perl-security)\nopen FH, $path;            # NEVER do this\nopen FH, \"\u003C $path\";        # Still bad — user data in mode string\n```\n\n### Path::Tiny for File Operations\n\n```perl\nuse v5.36;\nuse Path::Tiny;\n\nmy $file = path('config', 'app.json');\nmy $content = $file->slurp_utf8;\n$file->spew_utf8($new_content);\n\n# Iterate directory\nfor my $child (path('src')->children(qr\u002F\\.pl$\u002F)) {\n    say $child->basename;\n}\n```\n\n## Module Organization\n\n### Standard Project Layout\n\n```text\nMyApp\u002F\n├── lib\u002F\n│   └── MyApp\u002F\n│       ├── App.pm           # Main module\n│       ├── Config.pm        # Configuration\n│       ├── DB.pm            # Database layer\n│       └── Util.pm          # Utilities\n├── bin\u002F\n│   └── myapp                # Entry-point script\n├── t\u002F\n│   ├── 00-load.t            # Compilation tests\n│   ├── unit\u002F                # Unit tests\n│   └── integration\u002F         # Integration tests\n├── cpanfile                 # Dependencies\n├── Makefile.PL              # Build system\n└── .perlcriticrc            # Linting config\n```\n\n### Exporter Patterns\n\n```perl\npackage MyApp::Util;\nuse v5.36;\nuse Exporter 'import';\n\nour @EXPORT_OK   = qw(trim);\nour %EXPORT_TAGS = (all => \\@EXPORT_OK);\n\nsub trim($str) { $str =~ s\u002F^\\s+|\\s+$\u002F\u002Fgr }\n\n1;\n```\n\n## Tooling\n\n### perltidy Configuration (.perltidyrc)\n\n```text\n-i=4        # 4-space indent\n-l=100      # 100-char line length\n-ci=4       # continuation indent\n-ce         # cuddled else\n-bar        # opening brace on same line\n-nolq       # don't outdent long quoted strings\n```\n\n### perlcritic Configuration (.perlcriticrc)\n\n```ini\nseverity = 3\ntheme = core + pbp + security\n\n[InputOutput::RequireCheckedSyscalls]\nfunctions = :builtins\nexclude_functions = say print\n\n[Subroutines::ProhibitExplicitReturnUndef]\nseverity = 4\n\n[ValuesAndExpressions::ProhibitMagicNumbers]\nallowed_values = 0 1 2 -1\n```\n\n### Dependency Management (cpanfile + carton)\n\n```bash\ncpanm App::cpanminus Carton   # Install tools\ncarton install                 # Install deps from cpanfile\ncarton exec -- perl bin\u002Fmyapp  # Run with local deps\n```\n\n```perl\n# cpanfile\nrequires 'Moo', '>= 2.005';\nrequires 'Path::Tiny';\nrequires 'JSON::MaybeXS';\nrequires 'Try::Tiny';\n\non test => sub {\n    requires 'Test2::V0';\n    requires 'Test::MockModule';\n};\n```\n\n## Quick Reference: Modern Perl Idioms\n\n| Legacy Pattern | Modern Replacement |\n|---|---|\n| `use strict; use warnings;` | `use v5.36;` |\n| `my ($x, $y) = @_;` | `sub foo($x, $y) { ... }` |\n| `@{ $ref }` | `$ref->@*` |\n| `%{ $ref }` | `$ref->%*` |\n| `open FH, \"\u003C $file\"` | `open my $fh, '\u003C:encoding(UTF-8)', $file` |\n| `blessed hashref` | `Moo` class with types |\n| `$1, $2, $3` | `$+{name}` (named captures) |\n| `eval { }; if ($@)` | `Try::Tiny` or native `try\u002Fcatch` (5.40+) |\n| `BEGIN { require Exporter; }` | `use Exporter 'import';` |\n| Manual file ops | `Path::Tiny` |\n| `blessed($o) && $o->isa('X')` | `$o isa 'X'` (5.32+) |\n| `builtin::true \u002F false` | `use builtin 'true', 'false';` (5.36+, experimental) |\n\n## Anti-Patterns\n\n```perl\n# 1. Two-arg open (security risk)\nopen FH, $filename;                     # NEVER\n\n# 2. Indirect object syntax (ambiguous parsing)\nmy $obj = new Foo(bar => 1);            # Bad\nmy $obj = Foo->new(bar => 1);           # Good\n\n# 3. Excessive reliance on $_\nmap { process($_) } grep { validate($_) } @items;  # Hard to follow\nmy @valid = grep { validate($_) } @items;           # Better: break it up\nmy @results = map { process($_) } @valid;\n\n# 4. Disabling strict refs\nno strict 'refs';                        # Almost always wrong\n${\"My::Package::$var\"} = $value;         # Use a hash instead\n\n# 5. Global variables as configuration\nour $TIMEOUT = 30;                       # Bad: mutable global\nuse constant TIMEOUT => 30;              # Better: constant\n# Best: Moo attribute with default\n\n# 6. String eval for module loading\neval \"require $module\";                  # Bad: code injection risk\neval \"use $module\";                      # Bad\nuse Module::Runtime 'require_module';    # Good: safe module loading\nrequire_module($module);\n```\n\n**Remember**: Modern Perl is clean, readable, and safe. Let `use v5.36` handle the boilerplate, use Moo for objects, and prefer CPAN's battle-tested modules over hand-rolled solutions.\n","# Modern Perl Development Patterns\n\nIdiomatic Perl 5.36+ patterns and best practices for building robust, maintainable applications.\n\n## When to Activate\n\n- Writing new Perl code or modules\n- Reviewing Perl code for idiom compliance\n- Refactoring legacy Perl to modern standards\n- Designing Perl module architecture\n- Migrating pre-5.36 code to modern Perl\n\n## How It Works\n\nApply these patterns as a bias toward modern Perl 5.36+ defaults: signatures, explicit modules, focused error handling, and testable boundaries. The examples below are meant to be copied as starting points, then tightened for the actual app, dependency stack, and deployment model in front of you.\n\n## Core Principles\n\n### 1. Use `v5.36` Pragma\n\nA single `use v5.36` replaces the old boilerplate and enables strict, warnings, and subroutine signatures.\n\n```perl\n# Good: Modern preamble\nuse v5.36;\n\nsub greet($name) {\n    say \"Hello, $name!\";\n}\n\n# Bad: Legacy boilerplate\nuse strict;\nuse warnings;\nuse feature 'say', 'signatures';\nno warnings 'experimental::signatures';\n\nsub greet {\n    my ($name) = @_;\n    say \"Hello, $name!\";\n}\n```\n\n### 2. Subroutine Signatures\n\nUse signatures for clarity and automatic arity checking.\n\n```perl\nuse v5.36;\n\n# Good: Signatures with defaults\nsub connect_db($host, $port = 5432, $timeout = 30) {\n    # $host is required, others have defaults\n    return DBI->connect(\"dbi:Pg:host=$host;port=$port\", undef, undef, {\n        RaiseError => 1,\n        PrintError => 0,\n    });\n}\n\n# Good: Slurpy parameter for variable args\nsub log_message($level, @details) {\n    say \"[$level] \" . join(' ', @details);\n}\n\n# Bad: Manual argument unpacking\nsub connect_db {\n    my ($host, $port, $timeout) = @_;\n    $port    \u002F\u002F= 5432;\n    $timeout \u002F\u002F= 30;\n    # ...\n}\n```\n\n### 3. Context Sensitivity\n\nUnderstand scalar vs list context — a core Perl concept.\n\n```perl\nuse v5.36;\n\nmy @items = (1, 2, 3, 4, 5);\n\nmy @copy  = @items;            # List context: all elements\nmy $count = @items;            # Scalar context: count (5)\nsay \"Items: \" . scalar @items; # Force scalar context\n```\n\n### 4. Postfix Dereferencing\n\nUse postfix dereference syntax for readability with nested structures.\n\n```perl\nuse v5.36;\n\nmy $data = {\n    users => [\n        { name => 'Alice', roles => ['admin', 'user'] },\n        { name => 'Bob',   roles => ['user'] },\n    ],\n};\n\n# Good: Postfix dereferencing\nmy @users = $data->{users}->@*;\nmy @roles = $data->{users}[0]{roles}->@*;\nmy %first = $data->{users}[0]->%*;\n\n# Bad: Circumfix dereferencing (harder to read in chains)\nmy @users = @{ $data->{users} };\nmy @roles = @{ $data->{users}[0]{roles} };\n```\n\n### 5. The `isa` Operator (5.32+)\n\nInfix type-check — replaces `blessed($o) && $o->isa('X')`.\n\n```perl\nuse v5.36;\nif ($obj isa 'My::Class') { $obj->do_something }\n```\n\n## Error Handling\n\n### eval\u002Fdie Pattern\n\n```perl\nuse v5.36;\n\nsub parse_config($path) {\n    my $content = eval { path($path)->slurp_utf8 };\n    die \"Config error: $@\" if $@;\n    return decode_json($content);\n}\n```\n\n### Try::Tiny (Reliable Exception Handling)\n\n```perl\nuse v5.36;\nuse Try::Tiny;\n\nsub fetch_user($id) {\n    my $user = try {\n        $db->resultset('User')->find($id)\n            \u002F\u002F die \"User $id not found\\n\";\n    }\n    catch {\n        warn \"Failed to fetch user $id: $_\";\n        undef;\n    };\n    return $user;\n}\n```\n\n### Native try\u002Fcatch (5.40+)\n\n```perl\nuse v5.40;\n\nsub divide($x, $y) {\n    try {\n        die \"Division by zero\" if $y == 0;\n        return $x \u002F $y;\n    }\n    catch ($e) {\n        warn \"Error: $e\";\n        return;\n    }\n}\n```\n\n## Modern OO with Moo\n\nPrefer Moo for lightweight, modern OO. Use Moose only when its metaprotocol is needed.\n\n```perl\n# Good: Moo class\npackage User;\nuse Moo;\nuse Types::Standard qw(Str Int ArrayRef);\nuse namespace::autoclean;\n\nhas name  => (is => 'ro', isa => Str, required => 1);\nhas email => (is => 'ro', isa => Str, required => 1);\nhas age   => (is => 'ro', isa => Int, default  => sub { 0 });\nhas roles => (is => 'ro', isa => ArrayRef[Str], default => sub { [] });\n\nsub is_admin($self) {\n    return grep { $_ eq 'admin' } $self->roles->@*;\n}\n\nsub greet($self) {\n    return \"Hello, I'm \" . $self->name;\n}\n\n1;\n\n# Usage\nmy $user = User->new(\n    name  => 'Alice',\n    email => 'alice@example.com',\n    roles => ['admin', 'user'],\n);\n\n# Bad: Blessed hashref (no validation, no accessors)\npackage User;\nsub new {\n    my ($class, %args) = @_;\n    return bless \\%args, $class;\n}\nsub name { return $_[0]->{name} }\n1;\n```\n\n### Moo Roles\n\n```perl\npackage Role::Serializable;\nuse Moo::Role;\nuse JSON::MaybeXS qw(encode_json);\nrequires 'TO_HASH';\nsub to_json($self) { encode_json($self->TO_HASH) }\n1;\n\npackage User;\nuse Moo;\nwith 'Role::Serializable';\nhas name  => (is => 'ro', required => 1);\nhas email => (is => 'ro', required => 1);\nsub TO_HASH($self) { { name => $self->name, email => $self->email } }\n1;\n```\n\n### Native `class` Keyword (5.38+, Corinna)\n\n```perl\nuse v5.38;\nuse feature 'class';\nno warnings 'experimental::class';\n\nclass Point {\n    field $x :param;\n    field $y :param;\n    method magnitude() { sqrt($x**2 + $y**2) }\n}\n\nmy $p = Point->new(x => 3, y => 4);\nsay $p->magnitude;  # 5\n```\n\n## Regular Expressions\n\n### Named Captures and `\u002Fx` Flag\n\n```perl\nuse v5.36;\n\n# Good: Named captures with \u002Fx for readability\nmy $log_re = qr{\n    ^ (?\u003Ctimestamp> \\d{4}-\\d{2}-\\d{2} \\s \\d{2}:\\d{2}:\\d{2} )\n    \\s+ \\[ (?\u003Clevel> \\w+ ) \\]\n    \\s+ (?\u003Cmessage> .+ ) $\n}x;\n\nif ($line =~ $log_re) {\n    say \"Time: $+{timestamp}, Level: $+{level}\";\n    say \"Message: $+{message}\";\n}\n\n# Bad: Positional captures (hard to maintain)\nif ($line =~ \u002F^(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})\\s+\\[(\\w+)\\]\\s+(.+)$\u002F) {\n    say \"Time: $1, Level: $2\";\n}\n```\n\n### Precompiled Patterns\n\n```perl\nuse v5.36;\n\n# Good: Compile once, use many\nmy $email_re = qr\u002F^[A-Za-z0-9._%+-]+\\@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$\u002F;\n\nsub validate_emails(@emails) {\n    return grep { $_ =~ $email_re } @emails;\n}\n```\n\n## Data Structures\n\n### References and Safe Deep Access\n\n```perl\nuse v5.36;\n\n# Hash and array references\nmy $config = {\n    database => {\n        host => 'localhost',\n        port => 5432,\n        options => ['utf8', 'sslmode=require'],\n    },\n};\n\n# Safe deep access (returns undef if any level missing)\nmy $port = $config->{database}{port};           # 5432\nmy $missing = $config->{cache}{host};           # undef, no error\n\n# Hash slices\nmy %subset;\n@subset{qw(host port)} = @{$config->{database}}{qw(host port)};\n\n# Array slices\nmy @first_two = $config->{database}{options}->@[0, 1];\n\n# Multi-variable for loop (experimental in 5.36, stable in 5.40)\nuse feature 'for_list';\nno warnings 'experimental::for_list';\nfor my ($key, $val) (%$config) {\n    say \"$key => $val\";\n}\n```\n\n## File I\u002FO\n\n### Three-Argument Open\n\n```perl\nuse v5.36;\n\n# Good: Three-arg open with autodie (core module, eliminates 'or die')\nuse autodie;\n\nsub read_file($path) {\n    open my $fh, '\u003C:encoding(UTF-8)', $path;\n    local $\u002F;\n    my $content = \u003C$fh>;\n    close $fh;\n    return $content;\n}\n\n# Bad: Two-arg open (shell injection risk, see perl-security)\nopen FH, $path;            # NEVER do this\nopen FH, \"\u003C $path\";        # Still bad — user data in mode string\n```\n\n### Path::Tiny for File Operations\n\n```perl\nuse v5.36;\nuse Path::Tiny;\n\nmy $file = path('config', 'app.json');\nmy $content = $file->slurp_utf8;\n$file->spew_utf8($new_content);\n\n# Iterate directory\nfor my $child (path('src')->children(qr\u002F\\.pl$\u002F)) {\n    say $child->basename;\n}\n```\n\n## Module Organization\n\n### Standard Project Layout\n\n```text\nMyApp\u002F\n├── lib\u002F\n│   └── MyApp\u002F\n│       ├── App.pm           # Main module\n│       ├── Config.pm        # Configuration\n│       ├── DB.pm            # Database layer\n│       └── Util.pm          # Utilities\n├── bin\u002F\n│   └── myapp                # Entry-point script\n├── t\u002F\n│   ├── 00-load.t            # Compilation tests\n│   ├── unit\u002F                # Unit tests\n│   └── integration\u002F         # Integration tests\n├── cpanfile                 # Dependencies\n├── Makefile.PL              # Build system\n└── .perlcriticrc            # Linting config\n```\n\n### Exporter Patterns\n\n```perl\npackage MyApp::Util;\nuse v5.36;\nuse Exporter 'import';\n\nour @EXPORT_OK   = qw(trim);\nour %EXPORT_TAGS = (all => \\@EXPORT_OK);\n\nsub trim($str) { $str =~ s\u002F^\\s+|\\s+$\u002F\u002Fgr }\n\n1;\n```\n\n## Tooling\n\n### perltidy Configuration (.perltidyrc)\n\n```text\n-i=4        # 4-space indent\n-l=100      # 100-char line length\n-ci=4       # continuation indent\n-ce         # cuddled else\n-bar        # opening brace on same line\n-nolq       # don't outdent long quoted strings\n```\n\n### perlcritic Configuration (.perlcriticrc)\n\n```ini\nseverity = 3\ntheme = core + pbp + security\n\n[InputOutput::RequireCheckedSyscalls]\nfunctions = :builtins\nexclude_functions = say print\n\n[Subroutines::ProhibitExplicitReturnUndef]\nseverity = 4\n\n[ValuesAndExpressions::ProhibitMagicNumbers]\nallowed_values = 0 1 2 -1\n```\n\n### Dependency Management (cpanfile + carton)\n\n```bash\ncpanm App::cpanminus Carton   # Install tools\ncarton install                 # Install deps from cpanfile\ncarton exec -- perl bin\u002Fmyapp  # Run with local deps\n```\n\n```perl\n# cpanfile\nrequires 'Moo', '>= 2.005';\nrequires 'Path::Tiny';\nrequires 'JSON::MaybeXS';\nrequires 'Try::Tiny';\n\non test => sub {\n    requires 'Test2::V0';\n    requires 'Test::MockModule';\n};\n```\n\n## Quick Reference: Modern Perl Idioms\n\n| Legacy Pattern | Modern Replacement |\n|---|---|\n| `use strict; use warnings;` | `use v5.36;` |\n| `my ($x, $y) = @_;` | `sub foo($x, $y) { ... }` |\n| `@{ $ref }` | `$ref->@*` |\n| `%{ $ref }` | `$ref->%*` |\n| `open FH, \"\u003C $file\"` | `open my $fh, '\u003C:encoding(UTF-8)', $file` |\n| `blessed hashref` | `Moo` class with types |\n| `$1, $2, $3` | `$+{name}` (named captures) |\n| `eval { }; if ($@)` | `Try::Tiny` or native `try\u002Fcatch` (5.40+) |\n| `BEGIN { require Exporter; }` | `use Exporter 'import';` |\n| Manual file ops | `Path::Tiny` |\n| `blessed($o) && $o->isa('X')` | `$o isa 'X'` (5.32+) |\n| `builtin::true \u002F false` | `use builtin 'true', 'false';` (5.36+, experimental) |\n\n## Anti-Patterns\n\n```perl\n# 1. Two-arg open (security risk)\nopen FH, $filename;                     # NEVER\n\n# 2. Indirect object syntax (ambiguous parsing)\nmy $obj = new Foo(bar => 1);            # Bad\nmy $obj = Foo->new(bar => 1);           # Good\n\n# 3. Excessive reliance on $_\nmap { process($_) } grep { validate($_) } @items;  # Hard to follow\nmy @valid = grep { validate($_) } @items;           # Better: break it up\nmy @results = map { process($_) } @valid;\n\n# 4. Disabling strict refs\nno strict 'refs';                        # Almost always wrong\n${\"My::Package::$var\"} = $value;         # Use a hash instead\n\n# 5. Global variables as configuration\nour $TIMEOUT = 30;                       # Bad: mutable global\nuse constant TIMEOUT => 30;              # Better: constant\n# Best: Moo attribute with default\n\n# 6. String eval for module loading\neval \"require $module\";                  # Bad: code injection risk\neval \"use $module\";                      # Bad\nuse Module::Runtime 'require_module';    # Good: safe module loading\nrequire_module($module);\n```\n\n**Remember**: Modern Perl is clean, readable, and safe. Let `use v5.36` handle the boilerplate, use Moo for objects, and prefer CPAN's battle-tested modules over hand-rolled solutions.\n",{"name":5,"origin":30,"description":7},"ECC","main","a298c929b6cbd662e1fce54302ce520d5ceea1a5",".agents\u002Flibrary\u002Fskills\u002Fperl-patterns","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain","https:\u002F\u002Fgithub.com\u002FPrekzursil","2026-11-02 14:30:57",{"source":8,"skillName":5,"commands":38,"prompt":48,"zipAvailable":49},[39,42,45],{"tool":40,"command":41},"npx","npx skills add Prekzursil\u002Fagent-skills-toolchain --skill perl-patterns",{"tool":43,"command":44},"bunx","bunx skills add Prekzursil\u002Fagent-skills-toolchain --skill perl-patterns",{"tool":46,"command":47},"pnpm","pnpm dlx skills add Prekzursil\u002Fagent-skills-toolchain --skill perl-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Flibrary\u002Fskills\u002Fperl-patterns\u002FSKILL.md",true,[51],{"path":52,"resourceType":53,"resourceTypeDesc":54,"sizeBytes":55,"sourceHtmlUrl":56},"agents\u002Fopenai.yaml","REFERENCE","参考文档",82,"https:\u002F\u002Fgithub.com\u002Fnexuslinkproductions\u002Fyuri-os\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fgsap-scrolltrigger\u002Fagents\u002Fopenai.yaml",[58,80,111,138,152,168],{"skillNo":59,"name":60,"nameZh":6,"description":61,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":62,"categories":63,"keywords":64,"publishedAt":25},"01M6DF7D7478R55P46REYH4QAC","clarify-requirements","Resolve genuine pre-execution ambiguity by scanning repo context, generating 1-6 grounded options, and asking 1-3 focused questions via AskUserQuestion. NOT for mid-task use (injection risk); NOT when the goal is already unambiguous; use to disambiguate vague prompts before any file edits.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fworkspace-hooks\u002Fskills\u002Fclarify-requirements\u002FSKILL.md",[],[65,66,67,68,69,70,71,72,73,74,75,76,77,78,79],"clarify requirements","clarify","requirements","risk","options","task","prompts","goal","scanning","use","context","repo","injection","execution","file",{"skillNo":81,"name":82,"nameZh":6,"description":83,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":84,"categories":85,"keywords":91,"publishedAt":25},"01M6DF79CA4BHJS66J8EZDBPWJ","openmm-md","Run FREE, open-source, Windows-native GPU molecular dynamics via the openmm-md MCP (OpenMM + CUDA on the local NVIDIA GPU). Use for protein \u002F protein-ligand MD when you want a free stack or are on Windows without a Schrodinger license. Covers the full workflow (prepare, solvate, minimize, equilibrate, production, analyze, mmgbsa) AND an honest decision guide vs Schrodinger Desmond, including how to run Desmond legitimately on Linux or a cloud GPU with a real license. This is a deliberately LESSER free alternative and does NOT replace the schrodinger MCP tools. Do NOT use it to pick a free tool when a validated FEP+, WaterMap, IFD-MD, or Prime MM-GBSA result is actually required.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fmcp\u002Fopenmm-md-mcp\u002Fskill\u002Fopenmm-md\u002FSKILL.md",[86],{"categoryNo":87,"categoryName":88,"taxonomyType":89,"taxonomyTypeDesc":90},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[92,93,94,95,96,97,98,99,100,101,102,103,104,105,74,106,107,108,109,110],"openmm md","how","decision","pick","linux","analyze","tool","stack","open","NVIDIA","gpu","license","workflow","windows","free","molecular dynamics","local","do","MCP",{"skillNo":112,"name":113,"nameZh":6,"description":114,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":123,"publishedAt":25},"01M6DF76C1MG85VEWP8VZCBNMN","visual-review","Take screenshots of web pages and UI using Playwright for visual review and iteration","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fvisual-review\u002FSKILL.md",[117,120],{"categoryNo":118,"categoryName":119,"taxonomyType":89,"taxonomyTypeDesc":90},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":121,"categoryName":122,"taxonomyType":89,"taxonomyTypeDesc":90},"01JBSEEDCAT000000000000008","测试与质量",[124,125,126,127,128,129,130,131,132,133,93,134,135,136,137],"review","visual","visual review","pages","web","false","iteration","take","check","slides","ui","screenshot","playwright","screenshots",{"skillNo":139,"name":140,"nameZh":6,"description":141,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":142,"categories":143,"keywords":144,"publishedAt":25},"01M6DF73AQVCBZKEN0YXEX9FXP","status","Diagnostic status report — shows metaswarm installation state, project setup, and potential issues","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstatus\u002FSKILL.md",[],[140,145,146,147,148,149,150,151],"setup","report","project","installation","project setup","issues","state",{"skillNo":153,"name":154,"nameZh":6,"description":155,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":156,"categories":157,"keywords":159,"publishedAt":25},"01M6DF6X6C2XB0P6GX76P7TTYV","start","Use when starting work on any task, when the user mentions metaswarm, or when the user wants to begin tracked development work","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstart\u002FSKILL.md",[158],{"categoryNo":87,"categoryName":88,"taxonomyType":89,"taxonomyTypeDesc":90},[154,160,70,161,162,163,74,164,165,166,167],"start issue","issue","ready","work on issue","user","work","work on","development",{"skillNo":169,"name":145,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":173,"publishedAt":25},"01M6DF6QMJ9AJKFKHHKRT005PQ","Interactive project setup — detects your project, configures metaswarm, writes project-local files","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fsetup\u002FSKILL.md",[],[145,147,108,174,149,175],"files","interactive"]