dsh-ecc-skills 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +99 -0
- package/cordis.patch.yml +5 -0
- package/lib/index.js +195 -0
- package/package.json +46 -0
- package/skills/accessibility/SKILL.md +147 -0
- package/skills/agent-architecture-audit/SKILL.md +257 -0
- package/skills/agent-eval/SKILL.md +147 -0
- package/skills/agent-harness-construction/SKILL.md +74 -0
- package/skills/agent-introspection-debugging/SKILL.md +154 -0
- package/skills/agent-payment-x402/SKILL.md +225 -0
- package/skills/agent-self-evaluation/SKILL.md +182 -0
- package/skills/agent-sort/SKILL.md +216 -0
- package/skills/agentic-engineering/SKILL.md +64 -0
- package/skills/agentic-os/SKILL.md +388 -0
- package/skills/ai-first-engineering/SKILL.md +52 -0
- package/skills/ai-regression-testing/SKILL.md +386 -0
- package/skills/android-clean-architecture/SKILL.md +340 -0
- package/skills/angular-developer/SKILL.md +155 -0
- package/skills/api-connector-builder/SKILL.md +121 -0
- package/skills/api-design/SKILL.md +524 -0
- package/skills/architecture-decision-records/SKILL.md +180 -0
- package/skills/article-writing/SKILL.md +80 -0
- package/skills/automation-audit-ops/SKILL.md +143 -0
- package/skills/autonomous-agent-harness/SKILL.md +274 -0
- package/skills/autonomous-loops/SKILL.md +611 -0
- package/skills/backend-patterns/SKILL.md +562 -0
- package/skills/benchmark/SKILL.md +95 -0
- package/skills/benchmark-methodology/SKILL.md +191 -0
- package/skills/benchmark-optimization-loop/SKILL.md +71 -0
- package/skills/blender-motion-state-inspection/SKILL.md +165 -0
- package/skills/blueprint/SKILL.md +106 -0
- package/skills/brand-discovery/SKILL.md +145 -0
- package/skills/brand-voice/SKILL.md +98 -0
- package/skills/browser-qa/SKILL.md +105 -0
- package/skills/bun-runtime/SKILL.md +85 -0
- package/skills/canary-watch/SKILL.md +108 -0
- package/skills/carrier-relationship-management/SKILL.md +212 -0
- package/skills/cisco-ios-patterns/SKILL.md +164 -0
- package/skills/ck/SKILL.md +148 -0
- package/skills/claude-devfleet/SKILL.md +112 -0
- package/skills/click-path-audit/SKILL.md +245 -0
- package/skills/clickhouse-io/SKILL.md +445 -0
- package/skills/code-tour/SKILL.md +254 -0
- package/skills/codebase-onboarding/SKILL.md +234 -0
- package/skills/codehealth-mcp/SKILL.md +167 -0
- package/skills/coding-standards/SKILL.md +551 -0
- package/skills/competitive-platform-analysis/SKILL.md +214 -0
- package/skills/competitive-report-structure/SKILL.md +162 -0
- package/skills/compose-multiplatform-patterns/SKILL.md +300 -0
- package/skills/config-gc/SKILL.md +120 -0
- package/skills/configure-ecc/SKILL.md +206 -0
- package/skills/connections-optimizer/SKILL.md +190 -0
- package/skills/content-engine/SKILL.md +132 -0
- package/skills/content-hash-cache-pattern/SKILL.md +162 -0
- package/skills/context-budget/SKILL.md +136 -0
- package/skills/continuous-agent-loop/SKILL.md +46 -0
- package/skills/contract-first/SKILL.md +287 -0
- package/skills/cost-aware-llm-pipeline/SKILL.md +184 -0
- package/skills/cost-tracking/SKILL.md +97 -0
- package/skills/council/SKILL.md +204 -0
- package/skills/council-multi-model/SKILL.md +167 -0
- package/skills/cpp-coding-standards/SKILL.md +724 -0
- package/skills/cpp-testing/SKILL.md +325 -0
- package/skills/crosspost/SKILL.md +112 -0
- package/skills/csharp-testing/SKILL.md +322 -0
- package/skills/customer-billing-ops/SKILL.md +141 -0
- package/skills/customs-trade-compliance/SKILL.md +263 -0
- package/skills/dart-flutter-patterns/SKILL.md +564 -0
- package/skills/dashboard-builder/SKILL.md +109 -0
- package/skills/data-scraper-agent/SKILL.md +765 -0
- package/skills/data-throughput-accelerator/SKILL.md +74 -0
- package/skills/database-migrations/SKILL.md +430 -0
- package/skills/deep-research/SKILL.md +160 -0
- package/skills/defi-amm-security/SKILL.md +167 -0
- package/skills/delivery-gate/SKILL.md +126 -0
- package/skills/deployment-patterns/SKILL.md +428 -0
- package/skills/design-system/SKILL.md +83 -0
- package/skills/dev-team/SKILL.md +203 -0
- package/skills/django-celery/SKILL.md +458 -0
- package/skills/django-patterns/SKILL.md +735 -0
- package/skills/django-security/SKILL.md +644 -0
- package/skills/django-tdd/SKILL.md +730 -0
- package/skills/django-verification/SKILL.md +470 -0
- package/skills/dmux-workflows/SKILL.md +192 -0
- package/skills/docker-patterns/SKILL.md +520 -0
- package/skills/documentation-lookup/SKILL.md +91 -0
- package/skills/dotnet-patterns/SKILL.md +322 -0
- package/skills/dynamic-workflow-mode/SKILL.md +124 -0
- package/skills/e2e-testing/SKILL.md +327 -0
- package/skills/ecc-tools-cost-audit/SKILL.md +161 -0
- package/skills/email-ops/SKILL.md +122 -0
- package/skills/energy-procurement/SKILL.md +228 -0
- package/skills/enterprise-agent-ops/SKILL.md +51 -0
- package/skills/error-handling/SKILL.md +377 -0
- package/skills/eval-harness/SKILL.md +271 -0
- package/skills/evm-token-decimals/SKILL.md +131 -0
- package/skills/exa-search/SKILL.md +108 -0
- package/skills/fal-ai-media/SKILL.md +289 -0
- package/skills/fastapi-patterns/SKILL.md +514 -0
- package/skills/finance-billing-ops/SKILL.md +128 -0
- package/skills/flox-environments/SKILL.md +497 -0
- package/skills/flutter-dart-code-review/SKILL.md +436 -0
- package/skills/foundation-models-on-device/SKILL.md +243 -0
- package/skills/frontend-a11y/SKILL.md +446 -0
- package/skills/frontend-design-direction/SKILL.md +93 -0
- package/skills/frontend-patterns/SKILL.md +657 -0
- package/skills/fsharp-testing/SKILL.md +281 -0
- package/skills/gan-style-harness/SKILL.md +279 -0
- package/skills/generating-python-installer/SKILL.md +820 -0
- package/skills/git-workflow/SKILL.md +716 -0
- package/skills/github-ops/SKILL.md +145 -0
- package/skills/golang-patterns/SKILL.md +676 -0
- package/skills/golang-testing/SKILL.md +721 -0
- package/skills/google-workspace-ops/SKILL.md +96 -0
- package/skills/growth-log/SKILL.md +128 -0
- package/skills/healthcare-cdss-patterns/SKILL.md +246 -0
- package/skills/healthcare-emr-patterns/SKILL.md +160 -0
- package/skills/healthcare-eval-harness/SKILL.md +208 -0
- package/skills/healthcare-phi-compliance/SKILL.md +146 -0
- package/skills/hermes-imports/SKILL.md +89 -0
- package/skills/hexagonal-architecture/SKILL.md +277 -0
- package/skills/hipaa-compliance/SKILL.md +79 -0
- package/skills/homelab-network-readiness/SKILL.md +170 -0
- package/skills/homelab-network-setup/SKILL.md +130 -0
- package/skills/homelab-pihole-dns/SKILL.md +275 -0
- package/skills/homelab-vlan-segmentation/SKILL.md +312 -0
- package/skills/homelab-wireguard-vpn/SKILL.md +306 -0
- package/skills/hookify-rules/SKILL.md +128 -0
- package/skills/inherit-legacy-style/SKILL.md +157 -0
- package/skills/intent-driven-development/SKILL.md +360 -0
- package/skills/inventory-demand-planning/SKILL.md +247 -0
- package/skills/investor-materials/SKILL.md +97 -0
- package/skills/investor-outreach/SKILL.md +92 -0
- package/skills/ios-icon-gen/SKILL.md +158 -0
- package/skills/iterative-retrieval/SKILL.md +212 -0
- package/skills/ito-baskets/SKILL.md +263 -0
- package/skills/ito-compute/SKILL.md +151 -0
- package/skills/ito-inference/SKILL.md +119 -0
- package/skills/ito-training/SKILL.md +123 -0
- package/skills/java-coding-standards/SKILL.md +384 -0
- package/skills/jira-integration/SKILL.md +303 -0
- package/skills/jpa-patterns/SKILL.md +152 -0
- package/skills/knowledge-ops/SKILL.md +155 -0
- package/skills/kotlin-coroutines-flows/SKILL.md +285 -0
- package/skills/kotlin-exposed-patterns/SKILL.md +720 -0
- package/skills/kotlin-ktor-patterns/SKILL.md +690 -0
- package/skills/kotlin-patterns/SKILL.md +712 -0
- package/skills/kotlin-testing/SKILL.md +825 -0
- package/skills/kubernetes-patterns/SKILL.md +756 -0
- package/skills/laravel-patterns/SKILL.md +416 -0
- package/skills/laravel-plugin-discovery/SKILL.md +230 -0
- package/skills/laravel-security/SKILL.md +948 -0
- package/skills/laravel-tdd/SKILL.md +675 -0
- package/skills/laravel-verification/SKILL.md +180 -0
- package/skills/latency-critical-systems/SKILL.md +75 -0
- package/skills/lead-intelligence/SKILL.md +322 -0
- package/skills/liquid-glass-design/SKILL.md +279 -0
- package/skills/living-docs-governance/SKILL.md +137 -0
- package/skills/llm-trading-agent-security/SKILL.md +147 -0
- package/skills/logistics-exception-management/SKILL.md +222 -0
- package/skills/loop-design-check/SKILL.md +143 -0
- package/skills/mailtrap-email-integration/SKILL.md +77 -0
- package/skills/make-interfaces-feel-better/SKILL.md +152 -0
- package/skills/manim-video/SKILL.md +90 -0
- package/skills/market-research/SKILL.md +76 -0
- package/skills/marketing-campaign/SKILL.md +114 -0
- package/skills/mcp-server-patterns/SKILL.md +70 -0
- package/skills/messages-ops/SKILL.md +105 -0
- package/skills/ml-adoption-playbook/SKILL.md +57 -0
- package/skills/mle-workflow/SKILL.md +348 -0
- package/skills/motion-advanced/SKILL.md +597 -0
- package/skills/motion-foundations/SKILL.md +300 -0
- package/skills/motion-patterns/SKILL.md +435 -0
- package/skills/motion-ui/SKILL.md +576 -0
- package/skills/mysql-patterns/SKILL.md +413 -0
- package/skills/nanoclaw-repl/SKILL.md +34 -0
- package/skills/nasiko-control-plane/SKILL.md +49 -0
- package/skills/nestjs-patterns/SKILL.md +231 -0
- package/skills/netmiko-ssh-automation/SKILL.md +174 -0
- package/skills/network-bgp-diagnostics/SKILL.md +168 -0
- package/skills/network-config-validation/SKILL.md +211 -0
- package/skills/network-interface-health/SKILL.md +153 -0
- package/skills/nextjs-turbopack/SKILL.md +58 -0
- package/skills/nodejs-keccak256/SKILL.md +103 -0
- package/skills/nutrient-document-processing/SKILL.md +168 -0
- package/skills/nuxt4-patterns/SKILL.md +101 -0
- package/skills/opensource-pipeline/SKILL.md +256 -0
- package/skills/orch-add-feature/SKILL.md +45 -0
- package/skills/orch-build-mvp/SKILL.md +49 -0
- package/skills/orch-change-feature/SKILL.md +43 -0
- package/skills/orch-fix-defect/SKILL.md +43 -0
- package/skills/orch-pipeline/SKILL.md +121 -0
- package/skills/orch-refine-code/SKILL.md +44 -0
- package/skills/parallel-execution-optimizer/SKILL.md +74 -0
- package/skills/perl-patterns/SKILL.md +505 -0
- package/skills/perl-security/SKILL.md +504 -0
- package/skills/perl-testing/SKILL.md +476 -0
- package/skills/plan-canvas/SKILL.md +196 -0
- package/skills/plankton-code-quality/SKILL.md +237 -0
- package/skills/postgres-patterns/SKILL.md +148 -0
- package/skills/prediction-market-oracle-research/SKILL.md +64 -0
- package/skills/prediction-market-risk-review/SKILL.md +61 -0
- package/skills/prisma-patterns/SKILL.md +401 -0
- package/skills/product-capability/SKILL.md +142 -0
- package/skills/product-lens/SKILL.md +93 -0
- package/skills/production-audit/SKILL.md +207 -0
- package/skills/production-scheduling/SKILL.md +238 -0
- package/skills/project-flow-ops/SKILL.md +112 -0
- package/skills/prompt-optimizer/SKILL.md +398 -0
- package/skills/python-patterns/SKILL.md +751 -0
- package/skills/python-testing/SKILL.md +817 -0
- package/skills/pytorch-patterns/SKILL.md +397 -0
- package/skills/quality-nonconformance/SKILL.md +260 -0
- package/skills/quarkus-patterns/SKILL.md +723 -0
- package/skills/quarkus-security/SKILL.md +468 -0
- package/skills/quarkus-tdd/SKILL.md +812 -0
- package/skills/quarkus-verification/SKILL.md +481 -0
- package/skills/ralphinho-rfc-pipeline/SKILL.md +68 -0
- package/skills/react-native-patterns/SKILL.md +326 -0
- package/skills/react-patterns/SKILL.md +342 -0
- package/skills/react-performance/SKILL.md +575 -0
- package/skills/react-testing/SKILL.md +424 -0
- package/skills/recsys-pipeline-architect/SKILL.md +115 -0
- package/skills/recursive-decision-ledger/SKILL.md +81 -0
- package/skills/redis-patterns/SKILL.md +404 -0
- package/skills/regex-vs-llm-structured-text/SKILL.md +221 -0
- package/skills/remotion-video-creation/SKILL.md +43 -0
- package/skills/repo-scan/SKILL.md +170 -0
- package/skills/research-ops/SKILL.md +113 -0
- package/skills/returns-reverse-logistics/SKILL.md +240 -0
- package/skills/rules-distill/SKILL.md +265 -0
- package/skills/rust-patterns/SKILL.md +500 -0
- package/skills/rust-testing/SKILL.md +501 -0
- package/skills/safety-guard/SKILL.md +76 -0
- package/skills/santa-method/SKILL.md +307 -0
- package/skills/scientific-db-pubmed-database/SKILL.md +176 -0
- package/skills/scientific-db-uspto-database/SKILL.md +178 -0
- package/skills/scientific-pkg-gget/SKILL.md +167 -0
- package/skills/scientific-thinking-literature-review/SKILL.md +193 -0
- package/skills/scientific-thinking-scholar-evaluation/SKILL.md +161 -0
- package/skills/search-first/SKILL.md +183 -0
- package/skills/security-bounty-hunter/SKILL.md +100 -0
- package/skills/security-scan/SKILL.md +166 -0
- package/skills/seo/SKILL.md +155 -0
- package/skills/skill-scout/SKILL.md +141 -0
- package/skills/skill-stocktake/SKILL.md +195 -0
- package/skills/social-graph-ranker/SKILL.md +155 -0
- package/skills/social-publisher/SKILL.md +130 -0
- package/skills/springboot-patterns/SKILL.md +315 -0
- package/skills/springboot-security/SKILL.md +273 -0
- package/skills/springboot-tdd/SKILL.md +159 -0
- package/skills/springboot-verification/SKILL.md +232 -0
- package/skills/swift-actor-persistence/SKILL.md +144 -0
- package/skills/swift-concurrency-6-2/SKILL.md +216 -0
- package/skills/swift-protocol-di-testing/SKILL.md +191 -0
- package/skills/swiftui-patterns/SKILL.md +259 -0
- package/skills/taste/SKILL.md +264 -0
- package/skills/tdd-workflow/SKILL.md +583 -0
- package/skills/team-agent-orchestration/SKILL.md +111 -0
- package/skills/team-builder/SKILL.md +169 -0
- package/skills/terminal-opener/SKILL.md +55 -0
- package/skills/terminal-ops/SKILL.md +110 -0
- package/skills/tinystruct-patterns/SKILL.md +279 -0
- package/skills/token-budget-advisor/SKILL.md +134 -0
- package/skills/ui-demo/SKILL.md +466 -0
- package/skills/ui-to-vue/SKILL.md +135 -0
- package/skills/uncloud/SKILL.md +344 -0
- package/skills/unified-memory/SKILL.md +170 -0
- package/skills/unified-notifications-ops/SKILL.md +188 -0
- package/skills/verification-loop/SKILL.md +129 -0
- package/skills/video-editing/SKILL.md +311 -0
- package/skills/videodb/SKILL.md +375 -0
- package/skills/vite-patterns/SKILL.md +450 -0
- package/skills/vue-patterns/SKILL.md +471 -0
- package/skills/windows-desktop-e2e/SKILL.md +888 -0
- package/skills/workspace-surface-audit/SKILL.md +126 -0
- package/skills/x-api/SKILL.md +235 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orch-refine-code
|
|
3
|
+
description: Orchestrate a behavior-preserving refactor — confirm tests are green, restructure without changing behavior, keep tests green, review, and gated commit. Use when the structure should improve but behavior must not change.
|
|
4
|
+
metadata:
|
|
5
|
+
origin: ECC
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# orch-refine-code
|
|
9
|
+
|
|
10
|
+
Actor · action · target: **orch · refine · code**. Thin wrapper over the shared
|
|
11
|
+
engine in [`orch-pipeline`](../orch-pipeline/SKILL.md).
|
|
12
|
+
|
|
13
|
+
## When to Use
|
|
14
|
+
|
|
15
|
+
- Same behavior, **better structure**: extract modules, remove duplication, kill
|
|
16
|
+
dead code, reduce nesting, rename for clarity.
|
|
17
|
+
- Distinguish from siblings: if behavior is meant to change at all, this is the
|
|
18
|
+
wrong skill (`orch-change-feature` / `orch-fix-defect`).
|
|
19
|
+
|
|
20
|
+
## Operation settings
|
|
21
|
+
|
|
22
|
+
- **Default size floor:** standard — restructures touch multiple files.
|
|
23
|
+
- **Phase mask:** 0 → 2 (plan the restructure) → 4 (keep green) → 5 → 6. No new
|
|
24
|
+
behavior tests are written — the existing suite is the safety net.
|
|
25
|
+
- **First move (phase 4):** confirm the relevant tests exist and are **green
|
|
26
|
+
before** touching code; if coverage is thin, add characterization tests first.
|
|
27
|
+
Then restructure in small steps, re-running tests after each.
|
|
28
|
+
|
|
29
|
+
## How It Works
|
|
30
|
+
|
|
31
|
+
1. Run the `orch-pipeline` engine with the settings above.
|
|
32
|
+
2. For dead-code / duplication sweeps, delegate to the `refactor-cleaner` agent
|
|
33
|
+
(it runs knip / depcheck / ts-prune and removes safely).
|
|
34
|
+
3. Stop at **Gate 1** (restructure plan) and **Gate 2** (pre-commit).
|
|
35
|
+
4. Commit as `refactor:` — the diff must be behavior-neutral.
|
|
36
|
+
|
|
37
|
+
## Example
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
orch-refine-code: extract the NWS HTTP client out of poller.py
|
|
41
|
+
→ confirm tests green → plan extraction [GATE 1: approve]
|
|
42
|
+
→ move in small steps, tests green throughout → code-review
|
|
43
|
+
→ commit refactor: [GATE 2: confirm]
|
|
44
|
+
```
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: parallel-execution-optimizer
|
|
3
|
+
description: Use when the user wants a task done much faster through parallel work, concurrent agents, batched tool calls, isolated worktrees, or many independent verification lanes without losing correctness.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
origin: ECC
|
|
7
|
+
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Parallel Execution Optimizer
|
|
11
|
+
|
|
12
|
+
Use this skill when speed comes from doing independent work at the same time:
|
|
13
|
+
repo inspection, file reads, API checks, browser checks, build/test lanes,
|
|
14
|
+
deploy readbacks, or multi-worktree implementation passes.
|
|
15
|
+
|
|
16
|
+
## Core Pattern
|
|
17
|
+
|
|
18
|
+
Turn urgency into a dependency graph before acting.
|
|
19
|
+
|
|
20
|
+
1. Define the objective and done signal.
|
|
21
|
+
2. Split work into lanes.
|
|
22
|
+
3. Mark each lane as parallel, sequential, or gated.
|
|
23
|
+
4. Run independent reads/checks together.
|
|
24
|
+
5. Keep writes isolated by file, worktree, branch, service, or dataset.
|
|
25
|
+
6. Merge only after evidence shows the lanes are compatible.
|
|
26
|
+
7. End with a verification table, not a vague speed claim.
|
|
27
|
+
|
|
28
|
+
## Lane Matrix
|
|
29
|
+
|
|
30
|
+
Before a large push, write a compact matrix:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
Lane | Can run in parallel? | Write surface | Risk | Verification
|
|
34
|
+
Repo scan | yes | none | low | rg/git status outputs
|
|
35
|
+
Backend patch | maybe | src/api | medium | unit tests
|
|
36
|
+
Frontend patch | maybe | app/components | medium | browser screenshot
|
|
37
|
+
Deploy readback | after build | remote service | high | live URL + logs
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Only run lanes in parallel when their write surfaces do not collide.
|
|
41
|
+
|
|
42
|
+
## Execution Rules
|
|
43
|
+
|
|
44
|
+
- Batch file reads, searches, status checks, and metadata queries.
|
|
45
|
+
- Use isolated worktrees for large unrelated implementation lanes.
|
|
46
|
+
- Start long-running tests, builds, backfills, and deploys in separate sessions,
|
|
47
|
+
then poll them deliberately.
|
|
48
|
+
- If a lane discovers a blocker that changes the plan, pause dependent lanes
|
|
49
|
+
and update the matrix.
|
|
50
|
+
- Never let a background process outlive the turn unless the user explicitly
|
|
51
|
+
asked for a continuing service.
|
|
52
|
+
- Do not parallelize destructive commands, migrations, writes to the same table,
|
|
53
|
+
or live customer-impacting deploys without an explicit gate.
|
|
54
|
+
|
|
55
|
+
## Output Shape
|
|
56
|
+
|
|
57
|
+
Use this when reporting:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
Parallel execution result:
|
|
61
|
+
- Lanes run: 5
|
|
62
|
+
- Lanes completed: 4
|
|
63
|
+
- Blocked lane: deploy readback, waiting on DNS propagation
|
|
64
|
+
- Fast path found: batched repo scan + focused tests
|
|
65
|
+
- Verification: lint pass, unit pass, live smoke pass
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Failure Modes
|
|
69
|
+
|
|
70
|
+
- More concurrency that creates conflicting edits.
|
|
71
|
+
- Benchmarking the tool instead of the task.
|
|
72
|
+
- Treating "fast" as done before correctness is proven.
|
|
73
|
+
- Forgetting to poll running sessions.
|
|
74
|
+
- Hiding skipped checks behind a success summary.
|
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: perl-patterns
|
|
3
|
+
description: Modern Perl 5.36+ idioms, best practices, and conventions for building robust, maintainable Perl applications. Use when writing or reviewing modern Perl 5.36+ code.
|
|
4
|
+
metadata:
|
|
5
|
+
origin: ECC
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Modern Perl Development Patterns
|
|
9
|
+
|
|
10
|
+
Idiomatic Perl 5.36+ patterns and best practices for building robust, maintainable applications.
|
|
11
|
+
|
|
12
|
+
## When to Activate
|
|
13
|
+
|
|
14
|
+
- Writing new Perl code or modules
|
|
15
|
+
- Reviewing Perl code for idiom compliance
|
|
16
|
+
- Refactoring legacy Perl to modern standards
|
|
17
|
+
- Designing Perl module architecture
|
|
18
|
+
- Migrating pre-5.36 code to modern Perl
|
|
19
|
+
|
|
20
|
+
## How It Works
|
|
21
|
+
|
|
22
|
+
Apply 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.
|
|
23
|
+
|
|
24
|
+
## Core Principles
|
|
25
|
+
|
|
26
|
+
### 1. Use `v5.36` Pragma
|
|
27
|
+
|
|
28
|
+
A single `use v5.36` replaces the old boilerplate and enables strict, warnings, and subroutine signatures.
|
|
29
|
+
|
|
30
|
+
```perl
|
|
31
|
+
# Good: Modern preamble
|
|
32
|
+
use v5.36;
|
|
33
|
+
|
|
34
|
+
sub greet($name) {
|
|
35
|
+
say "Hello, $name!";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Bad: Legacy boilerplate
|
|
39
|
+
use strict;
|
|
40
|
+
use warnings;
|
|
41
|
+
use feature 'say', 'signatures';
|
|
42
|
+
no warnings 'experimental::signatures';
|
|
43
|
+
|
|
44
|
+
sub greet {
|
|
45
|
+
my ($name) = @_;
|
|
46
|
+
say "Hello, $name!";
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Subroutine Signatures
|
|
51
|
+
|
|
52
|
+
Use signatures for clarity and automatic arity checking.
|
|
53
|
+
|
|
54
|
+
```perl
|
|
55
|
+
use v5.36;
|
|
56
|
+
|
|
57
|
+
# Good: Signatures with defaults
|
|
58
|
+
sub connect_db($host, $port = 5432, $timeout = 30) {
|
|
59
|
+
# $host is required, others have defaults
|
|
60
|
+
return DBI->connect("dbi:Pg:host=$host;port=$port", undef, undef, {
|
|
61
|
+
RaiseError => 1,
|
|
62
|
+
PrintError => 0,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Good: Slurpy parameter for variable args
|
|
67
|
+
sub log_message($level, @details) {
|
|
68
|
+
say "[$level] " . join(' ', @details);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Bad: Manual argument unpacking
|
|
72
|
+
sub connect_db {
|
|
73
|
+
my ($host, $port, $timeout) = @_;
|
|
74
|
+
$port //= 5432;
|
|
75
|
+
$timeout //= 30;
|
|
76
|
+
# ...
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 3. Context Sensitivity
|
|
81
|
+
|
|
82
|
+
Understand scalar vs list context — a core Perl concept.
|
|
83
|
+
|
|
84
|
+
```perl
|
|
85
|
+
use v5.36;
|
|
86
|
+
|
|
87
|
+
my @items = (1, 2, 3, 4, 5);
|
|
88
|
+
|
|
89
|
+
my @copy = @items; # List context: all elements
|
|
90
|
+
my $count = @items; # Scalar context: count (5)
|
|
91
|
+
say "Items: " . scalar @items; # Force scalar context
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 4. Postfix Dereferencing
|
|
95
|
+
|
|
96
|
+
Use postfix dereference syntax for readability with nested structures.
|
|
97
|
+
|
|
98
|
+
```perl
|
|
99
|
+
use v5.36;
|
|
100
|
+
|
|
101
|
+
my $data = {
|
|
102
|
+
users => [
|
|
103
|
+
{ name => 'Alice', roles => ['admin', 'user'] },
|
|
104
|
+
{ name => 'Bob', roles => ['user'] },
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
# Good: Postfix dereferencing
|
|
109
|
+
my @users = $data->{users}->@*;
|
|
110
|
+
my @roles = $data->{users}[0]{roles}->@*;
|
|
111
|
+
my %first = $data->{users}[0]->%*;
|
|
112
|
+
|
|
113
|
+
# Bad: Circumfix dereferencing (harder to read in chains)
|
|
114
|
+
my @users = @{ $data->{users} };
|
|
115
|
+
my @roles = @{ $data->{users}[0]{roles} };
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 5. The `isa` Operator (5.32+)
|
|
119
|
+
|
|
120
|
+
Infix type-check — replaces `blessed($o) && $o->isa('X')`.
|
|
121
|
+
|
|
122
|
+
```perl
|
|
123
|
+
use v5.36;
|
|
124
|
+
if ($obj isa 'My::Class') { $obj->do_something }
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Error Handling
|
|
128
|
+
|
|
129
|
+
### eval/die Pattern
|
|
130
|
+
|
|
131
|
+
```perl
|
|
132
|
+
use v5.36;
|
|
133
|
+
|
|
134
|
+
sub parse_config($path) {
|
|
135
|
+
my $content = eval { path($path)->slurp_utf8 };
|
|
136
|
+
die "Config error: $@" if $@;
|
|
137
|
+
return decode_json($content);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Try::Tiny (Reliable Exception Handling)
|
|
142
|
+
|
|
143
|
+
```perl
|
|
144
|
+
use v5.36;
|
|
145
|
+
use Try::Tiny;
|
|
146
|
+
|
|
147
|
+
sub fetch_user($id) {
|
|
148
|
+
my $user = try {
|
|
149
|
+
$db->resultset('User')->find($id)
|
|
150
|
+
// die "User $id not found\n";
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
warn "Failed to fetch user $id: $_";
|
|
154
|
+
undef;
|
|
155
|
+
};
|
|
156
|
+
return $user;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Native try/catch (5.40+)
|
|
161
|
+
|
|
162
|
+
```perl
|
|
163
|
+
use v5.40;
|
|
164
|
+
|
|
165
|
+
sub divide($x, $y) {
|
|
166
|
+
try {
|
|
167
|
+
die "Division by zero" if $y == 0;
|
|
168
|
+
return $x / $y;
|
|
169
|
+
}
|
|
170
|
+
catch ($e) {
|
|
171
|
+
warn "Error: $e";
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Modern OO with Moo
|
|
178
|
+
|
|
179
|
+
Prefer Moo for lightweight, modern OO. Use Moose only when its metaprotocol is needed.
|
|
180
|
+
|
|
181
|
+
```perl
|
|
182
|
+
# Good: Moo class
|
|
183
|
+
package User;
|
|
184
|
+
use Moo;
|
|
185
|
+
use Types::Standard qw(Str Int ArrayRef);
|
|
186
|
+
use namespace::autoclean;
|
|
187
|
+
|
|
188
|
+
has name => (is => 'ro', isa => Str, required => 1);
|
|
189
|
+
has email => (is => 'ro', isa => Str, required => 1);
|
|
190
|
+
has age => (is => 'ro', isa => Int, default => sub { 0 });
|
|
191
|
+
has roles => (is => 'ro', isa => ArrayRef[Str], default => sub { [] });
|
|
192
|
+
|
|
193
|
+
sub is_admin($self) {
|
|
194
|
+
return grep { $_ eq 'admin' } $self->roles->@*;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
sub greet($self) {
|
|
198
|
+
return "Hello, I'm " . $self->name;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
1;
|
|
202
|
+
|
|
203
|
+
# Usage
|
|
204
|
+
my $user = User->new(
|
|
205
|
+
name => 'Alice',
|
|
206
|
+
email => 'alice@example.com',
|
|
207
|
+
roles => ['admin', 'user'],
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
# Bad: Blessed hashref (no validation, no accessors)
|
|
211
|
+
package User;
|
|
212
|
+
sub new {
|
|
213
|
+
my ($class, %args) = @_;
|
|
214
|
+
return bless \%args, $class;
|
|
215
|
+
}
|
|
216
|
+
sub name { return $_[0]->{name} }
|
|
217
|
+
1;
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Moo Roles
|
|
221
|
+
|
|
222
|
+
```perl
|
|
223
|
+
package Role::Serializable;
|
|
224
|
+
use Moo::Role;
|
|
225
|
+
use JSON::MaybeXS qw(encode_json);
|
|
226
|
+
requires 'TO_HASH';
|
|
227
|
+
sub to_json($self) { encode_json($self->TO_HASH) }
|
|
228
|
+
1;
|
|
229
|
+
|
|
230
|
+
package User;
|
|
231
|
+
use Moo;
|
|
232
|
+
with 'Role::Serializable';
|
|
233
|
+
has name => (is => 'ro', required => 1);
|
|
234
|
+
has email => (is => 'ro', required => 1);
|
|
235
|
+
sub TO_HASH($self) { { name => $self->name, email => $self->email } }
|
|
236
|
+
1;
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Native `class` Keyword (5.38+, Corinna)
|
|
240
|
+
|
|
241
|
+
```perl
|
|
242
|
+
use v5.38;
|
|
243
|
+
use feature 'class';
|
|
244
|
+
no warnings 'experimental::class';
|
|
245
|
+
|
|
246
|
+
class Point {
|
|
247
|
+
field $x :param;
|
|
248
|
+
field $y :param;
|
|
249
|
+
method magnitude() { sqrt($x**2 + $y**2) }
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
my $p = Point->new(x => 3, y => 4);
|
|
253
|
+
say $p->magnitude; # 5
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Regular Expressions
|
|
257
|
+
|
|
258
|
+
### Named Captures and `/x` Flag
|
|
259
|
+
|
|
260
|
+
```perl
|
|
261
|
+
use v5.36;
|
|
262
|
+
|
|
263
|
+
# Good: Named captures with /x for readability
|
|
264
|
+
my $log_re = qr{
|
|
265
|
+
^ (?<timestamp> \d{4}-\d{2}-\d{2} \s \d{2}:\d{2}:\d{2} )
|
|
266
|
+
\s+ \[ (?<level> \w+ ) \]
|
|
267
|
+
\s+ (?<message> .+ ) $
|
|
268
|
+
}x;
|
|
269
|
+
|
|
270
|
+
if ($line =~ $log_re) {
|
|
271
|
+
say "Time: $+{timestamp}, Level: $+{level}";
|
|
272
|
+
say "Message: $+{message}";
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# Bad: Positional captures (hard to maintain)
|
|
276
|
+
if ($line =~ /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\[(\w+)\]\s+(.+)$/) {
|
|
277
|
+
say "Time: $1, Level: $2";
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Precompiled Patterns
|
|
282
|
+
|
|
283
|
+
```perl
|
|
284
|
+
use v5.36;
|
|
285
|
+
|
|
286
|
+
# Good: Compile once, use many
|
|
287
|
+
my $email_re = qr/^[A-Za-z0-9._%+-]+\@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
|
|
288
|
+
|
|
289
|
+
sub validate_emails(@emails) {
|
|
290
|
+
return grep { $_ =~ $email_re } @emails;
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Data Structures
|
|
295
|
+
|
|
296
|
+
### References and Safe Deep Access
|
|
297
|
+
|
|
298
|
+
```perl
|
|
299
|
+
use v5.36;
|
|
300
|
+
|
|
301
|
+
# Hash and array references
|
|
302
|
+
my $config = {
|
|
303
|
+
database => {
|
|
304
|
+
host => 'localhost',
|
|
305
|
+
port => 5432,
|
|
306
|
+
options => ['utf8', 'sslmode=require'],
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
# Safe deep access (returns undef if any level missing)
|
|
311
|
+
my $port = $config->{database}{port}; # 5432
|
|
312
|
+
my $missing = $config->{cache}{host}; # undef, no error
|
|
313
|
+
|
|
314
|
+
# Hash slices
|
|
315
|
+
my %subset;
|
|
316
|
+
@subset{qw(host port)} = @{$config->{database}}{qw(host port)};
|
|
317
|
+
|
|
318
|
+
# Array slices
|
|
319
|
+
my @first_two = $config->{database}{options}->@[0, 1];
|
|
320
|
+
|
|
321
|
+
# Multi-variable for loop (experimental in 5.36, stable in 5.40)
|
|
322
|
+
use feature 'for_list';
|
|
323
|
+
no warnings 'experimental::for_list';
|
|
324
|
+
for my ($key, $val) (%$config) {
|
|
325
|
+
say "$key => $val";
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## File I/O
|
|
330
|
+
|
|
331
|
+
### Three-Argument Open
|
|
332
|
+
|
|
333
|
+
```perl
|
|
334
|
+
use v5.36;
|
|
335
|
+
|
|
336
|
+
# Good: Three-arg open with autodie (core module, eliminates 'or die')
|
|
337
|
+
use autodie;
|
|
338
|
+
|
|
339
|
+
sub read_file($path) {
|
|
340
|
+
open my $fh, '<:encoding(UTF-8)', $path;
|
|
341
|
+
local $/;
|
|
342
|
+
my $content = <$fh>;
|
|
343
|
+
close $fh;
|
|
344
|
+
return $content;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
# Bad: Two-arg open (shell injection risk, see perl-security)
|
|
348
|
+
open FH, $path; # NEVER do this
|
|
349
|
+
open FH, "< $path"; # Still bad — user data in mode string
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Path::Tiny for File Operations
|
|
353
|
+
|
|
354
|
+
```perl
|
|
355
|
+
use v5.36;
|
|
356
|
+
use Path::Tiny;
|
|
357
|
+
|
|
358
|
+
my $file = path('config', 'app.json');
|
|
359
|
+
my $content = $file->slurp_utf8;
|
|
360
|
+
$file->spew_utf8($new_content);
|
|
361
|
+
|
|
362
|
+
# Iterate directory
|
|
363
|
+
for my $child (path('src')->children(qr/\.pl$/)) {
|
|
364
|
+
say $child->basename;
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Module Organization
|
|
369
|
+
|
|
370
|
+
### Standard Project Layout
|
|
371
|
+
|
|
372
|
+
```text
|
|
373
|
+
MyApp/
|
|
374
|
+
├── lib/
|
|
375
|
+
│ └── MyApp/
|
|
376
|
+
│ ├── App.pm # Main module
|
|
377
|
+
│ ├── Config.pm # Configuration
|
|
378
|
+
│ ├── DB.pm # Database layer
|
|
379
|
+
│ └── Util.pm # Utilities
|
|
380
|
+
├── bin/
|
|
381
|
+
│ └── myapp # Entry-point script
|
|
382
|
+
├── t/
|
|
383
|
+
│ ├── 00-load.t # Compilation tests
|
|
384
|
+
│ ├── unit/ # Unit tests
|
|
385
|
+
│ └── integration/ # Integration tests
|
|
386
|
+
├── cpanfile # Dependencies
|
|
387
|
+
├── Makefile.PL # Build system
|
|
388
|
+
└── .perlcriticrc # Linting config
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Exporter Patterns
|
|
392
|
+
|
|
393
|
+
```perl
|
|
394
|
+
package MyApp::Util;
|
|
395
|
+
use v5.36;
|
|
396
|
+
use Exporter 'import';
|
|
397
|
+
|
|
398
|
+
our @EXPORT_OK = qw(trim);
|
|
399
|
+
our %EXPORT_TAGS = (all => \@EXPORT_OK);
|
|
400
|
+
|
|
401
|
+
sub trim($str) { $str =~ s/^\s+|\s+$//gr }
|
|
402
|
+
|
|
403
|
+
1;
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## Tooling
|
|
407
|
+
|
|
408
|
+
### perltidy Configuration (.perltidyrc)
|
|
409
|
+
|
|
410
|
+
```text
|
|
411
|
+
-i=4 # 4-space indent
|
|
412
|
+
-l=100 # 100-char line length
|
|
413
|
+
-ci=4 # continuation indent
|
|
414
|
+
-ce # cuddled else
|
|
415
|
+
-bar # opening brace on same line
|
|
416
|
+
-nolq # don't outdent long quoted strings
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### perlcritic Configuration (.perlcriticrc)
|
|
420
|
+
|
|
421
|
+
```ini
|
|
422
|
+
severity = 3
|
|
423
|
+
theme = core + pbp + security
|
|
424
|
+
|
|
425
|
+
[InputOutput::RequireCheckedSyscalls]
|
|
426
|
+
functions = :builtins
|
|
427
|
+
exclude_functions = say print
|
|
428
|
+
|
|
429
|
+
[Subroutines::ProhibitExplicitReturnUndef]
|
|
430
|
+
severity = 4
|
|
431
|
+
|
|
432
|
+
[ValuesAndExpressions::ProhibitMagicNumbers]
|
|
433
|
+
allowed_values = 0 1 2 -1
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Dependency Management (cpanfile + carton)
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
cpanm App::cpanminus Carton # Install tools
|
|
440
|
+
carton install # Install deps from cpanfile
|
|
441
|
+
carton exec -- perl bin/myapp # Run with local deps
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
```perl
|
|
445
|
+
# cpanfile
|
|
446
|
+
requires 'Moo', '>= 2.005';
|
|
447
|
+
requires 'Path::Tiny';
|
|
448
|
+
requires 'JSON::MaybeXS';
|
|
449
|
+
requires 'Try::Tiny';
|
|
450
|
+
|
|
451
|
+
on test => sub {
|
|
452
|
+
requires 'Test2::V0';
|
|
453
|
+
requires 'Test::MockModule';
|
|
454
|
+
};
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## Quick Reference: Modern Perl Idioms
|
|
458
|
+
|
|
459
|
+
| Legacy Pattern | Modern Replacement |
|
|
460
|
+
|---|---|
|
|
461
|
+
| `use strict; use warnings;` | `use v5.36;` |
|
|
462
|
+
| `my ($x, $y) = @_;` | `sub foo($x, $y) { ... }` |
|
|
463
|
+
| `@{ $ref }` | `$ref->@*` |
|
|
464
|
+
| `%{ $ref }` | `$ref->%*` |
|
|
465
|
+
| `open FH, "< $file"` | `open my $fh, '<:encoding(UTF-8)', $file` |
|
|
466
|
+
| `blessed hashref` | `Moo` class with types |
|
|
467
|
+
| `$1, $2, $3` | `$+{name}` (named captures) |
|
|
468
|
+
| `eval { }; if ($@)` | `Try::Tiny` or native `try/catch` (5.40+) |
|
|
469
|
+
| `BEGIN { require Exporter; }` | `use Exporter 'import';` |
|
|
470
|
+
| Manual file ops | `Path::Tiny` |
|
|
471
|
+
| `blessed($o) && $o->isa('X')` | `$o isa 'X'` (5.32+) |
|
|
472
|
+
| `builtin::true / false` | `use builtin 'true', 'false';` (5.36+, experimental) |
|
|
473
|
+
|
|
474
|
+
## Anti-Patterns
|
|
475
|
+
|
|
476
|
+
```perl
|
|
477
|
+
# 1. Two-arg open (security risk)
|
|
478
|
+
open FH, $filename; # NEVER
|
|
479
|
+
|
|
480
|
+
# 2. Indirect object syntax (ambiguous parsing)
|
|
481
|
+
my $obj = new Foo(bar => 1); # Bad
|
|
482
|
+
my $obj = Foo->new(bar => 1); # Good
|
|
483
|
+
|
|
484
|
+
# 3. Excessive reliance on $_
|
|
485
|
+
map { process($_) } grep { validate($_) } @items; # Hard to follow
|
|
486
|
+
my @valid = grep { validate($_) } @items; # Better: break it up
|
|
487
|
+
my @results = map { process($_) } @valid;
|
|
488
|
+
|
|
489
|
+
# 4. Disabling strict refs
|
|
490
|
+
no strict 'refs'; # Almost always wrong
|
|
491
|
+
${"My::Package::$var"} = $value; # Use a hash instead
|
|
492
|
+
|
|
493
|
+
# 5. Global variables as configuration
|
|
494
|
+
our $TIMEOUT = 30; # Bad: mutable global
|
|
495
|
+
use constant TIMEOUT => 30; # Better: constant
|
|
496
|
+
# Best: Moo attribute with default
|
|
497
|
+
|
|
498
|
+
# 6. String eval for module loading
|
|
499
|
+
eval "require $module"; # Bad: code injection risk
|
|
500
|
+
eval "use $module"; # Bad
|
|
501
|
+
use Module::Runtime 'require_module'; # Good: safe module loading
|
|
502
|
+
require_module($module);
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**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.
|