working-with-dist-zilla
Use when working in a Perl repo containing a dist.ini file, or when the user mentions dzil, Dist::Zilla, or @Author::* PluginBundles.
What this skill does
# Working with Dist::Zilla Repositories
## Overview
`Dist::Zilla` (`dzil`) is a meta-tool that builds CPAN distributions from a `dist.ini` declaration. Many of its behaviors are stable across projects but invisible to anyone who hasn't been bitten — there's no "the docs say so" moment, you just learn by getting them wrong. This skill captures those patterns so you apply them on the first pass instead of discovering each one in an implementer/reviewer loop.
**Worked example that surfaced these patterns in sequence:** [oalders/lwp-consolelogger#56](https://github.com/oalders/lwp-consolelogger/pull/56) (Code::TidyAll → precious migration).
## When to Use
Use this skill when:
- The repo contains a `dist.ini` file at its root
- The user mentions `dzil`, `Dist::Zilla`, `@Author::*` bundles, `cpanfile`, or `META.json`
- You are editing prereqs, swapping plugins, or preparing a release
- A `dzil build` output is producing diff noise or unexpected warnings
Don't use when:
- The repo is a plain `ExtUtils::MakeMaker` / `Module::Build` distribution with no `dist.ini`
- Work is unrelated to packaging (e.g. editing only `lib/` source code without touching prereqs or build config)
## Workflow
```dot
digraph dzil {
"Repo orientation" [shape=box];
"Editing prereqs?" [shape=diamond];
"Decide PluginRemover vs RemovePrereqs" [shape=box];
"Apply edits to dist.ini" [shape=box];
"Run dzil build" [shape=box];
"Decide commit vs revert" [shape=box];
"Run dzil test --release --author" [shape=box];
"Tests pass?" [shape=diamond];
"Fix warnings (e.g. .mailmap)" [shape=box];
"Commit" [shape=box];
"Repo orientation" -> "Editing prereqs?";
"Editing prereqs?" -> "Decide PluginRemover vs RemovePrereqs" [label="yes"];
"Editing prereqs?" -> "Run dzil build" [label="no"];
"Decide PluginRemover vs RemovePrereqs" -> "Apply edits to dist.ini";
"Apply edits to dist.ini" -> "Run dzil build";
"Run dzil build" -> "Decide commit vs revert";
"Decide commit vs revert" -> "Run dzil test --release --author";
"Run dzil test --release --author" -> "Tests pass?";
"Tests pass?" -> "Fix warnings (e.g. .mailmap)" [label="warnings"];
"Fix warnings (e.g. .mailmap)" -> "Run dzil build";
"Tests pass?" -> "Commit" [label="clean"];
}
```
## 1. Repo orientation: read the bundle source
`dist.ini` usually starts with a single `[@Author::Foo]` line. The bundle's plugin and prereq-block names are what you'll need to reference for `-remove`. Find the bundle source:
```bash
perldoc -lm Dist::Zilla::PluginBundle::Author::OALDERS
```
Read the `configure` / `bundle_config` sub. The strings you can `-remove` against come from there — both plugin instance names (e.g. `Test::TidyAll`) and named Prereqs blocks (e.g. `'Prereqs' => 'Modules for use with tidyall'`).
## 2. Editing prereqs: PluginRemover vs RemovePrereqs
`Dist::Zilla::Role::PluginBundle::PluginRemover` matches `-remove` values against the plugin **instance name** or the **expanded class**. Class-name removes (`-remove = Test::TidyAll`) work reliably because they match `Dist::Zilla::Plugin::Test::TidyAll` — that string is stable. Instance-name removes against a **named Prereqs block** like:
```perl
[ 'Prereqs' => 'Modules for use with tidyall' => { ... } ]
```
…require you to know the exact moniker the bundle assigned. Bundle authors pick these names ad-hoc, so the same conceptual block is called `'Modules for use with tidyall'` in `@Author::OALDERS` but might be `'TidyAll prereqs'` in another bundle. The moniker may also include spaces, slashes, or the `@Bundle/` prefix, none of which is documented anywhere except the bundle source. **Prefer module-level removal via `[RemovePrereqs]` (next section) — it sidesteps the moniker-guessing problem entirely.**
**Decision tree:**
| Target | Use |
|--------|-----|
| A plugin (e.g. `Test::TidyAll`) | `[@Author::Foo]` with `-remove = Test::TidyAll` |
| Individual modules from a bundle's prereqs | `[RemovePrereqs]` (see below) |
| A named `[Prereqs / NAME]` block | `[RemovePrereqs]` — `-remove` is unreliable |
## 3. `[RemovePrereqs]` syntax: `remove =`, not `-remove =`
`[RemovePrereqs]` uses `remove =` (no leading dash). Using `-remove =` raises `multiple values given for property -remove` from `Config::MVP`. This contradicts the muscle-memory pattern from PluginBundle `-remove`. Correct usage:
```ini
[RemovePrereqs]
remove = Code::TidyAll
remove = Code::TidyAll::Plugin::SortLines::Naturally
remove = Parallel::ForkManager
remove = Test::Vars
```
## 4. Re-adding prereqs: `[Prereqs / PHASE]`
After stripping bundle prereqs, re-add what you still need with a phase-scoped block. The slash syntax sets the phase + relationship in one shot:
```ini
[Prereqs / DevelopRequires]
App::perlvars = 0
[Prereqs / TestRequires]
Test::Deep = 0
```
Use `RuntimeRequires`, `TestRequires`, `DevelopRequires`, `ConfigureRequires` as appropriate.
## 5. What to commit vs revert: the `CopyFilesFromBuild` rule
`dzil build` regenerates `META.json`, `Makefile.PL`, `README.md` (and sometimes others) via `[CopyFilesFromBuild]`. These files are tracked at the repo root but are essentially **snapshots of the last release**. When a feature PR touches `dist.ini`, the regenerated copies show up as ~100-line diffs of prereq lists, MakeMaker plugin version bumps, and dist-version increments — noise without semantic content.
**Rule:** For non-release PRs, commit ONLY `dist.ini` and `cpanfile`. Revert the rest and remove the build dir:
```bash
git checkout -- META.json Makefile.PL README.md
rm -rf <dist-name>-*/ <dist-name>-*.tar.gz
```
The next release commit regenerates them cleanly.
**Caveat:** If the PR IS a release (version bump in `dist.ini` + `Changes` update), then those files SHOULD ship in the commit.
## 6. `cpanfile` sync is automatic
`[CopyFilesFromBuild]` copies whatever filenames the bundle explicitly lists — it doesn't intrinsically know about `cpanfile`. But most modern bundles configure `[CopyFilesFromBuild] copy = cpanfile` (often alongside `META.json`, `Makefile.PL`, etc.), so the `cpanfile` at the repo root is regenerated automatically after `dzil build`. You usually don't need to `cp` manually. Verify with:
```bash
diff -u cpanfile <Dist>-*/cpanfile
```
If they differ, run `dzil build` again — your edit hasn't been reflected yet.
## 7. Keep developer-only tooling configs out of the dist
Linter/formatter config and dev hook scripts matter only to contributors working in the repo; they add nothing to an installed dist. Unless excluded, `[Git::GatherDir]` (which gathers from `git ls-files`) sweeps them into the tarball and ships them to CPAN, where they are dead weight.
**Canonical file list** — the dev-only configs that should never reach the dist:
- `precious.toml`
- `.perltidyrc` / `perltidyrc`
- `.perlcriticrc`
- `perlimports.toml`
- `.tidyallrc` / `tidyall.ini` (legacy `Code::TidyAll`)
- lint / pre-commit hook scripts (e.g. `scripts/pre-commit`)
**Two mechanisms** — pick by whether the file should ever enter the manifest:
| Mechanism | Syntax | What it does | Reach for it when |
|-----------|--------|--------------|-------------------|
| `[Git::GatherDir]` (or `[GatherDir]`) | `exclude_filename = <name>` | Keeps the file out of the gather step entirely — it never enters the manifest | Files that never need to be in the dist (the root config files above) |
| `[PruneFiles]` | `filename = <name>` or `match = <regex>` | Drops a file that was already gathered | Tracked files contributors need locally but that must not ship (e.g. `scripts/pre-commit`, which contributors symlink as a git hook — see the `tune-precious` skill's T6) |
**Practical caveat:** `exclude_filename` only works on a `[Git::GatherDir]` block you actually control in `dist.ini`. When `[Git::GatherDir]` is supplied by an `[@Author::*]` PluginBundle (the common case), you usually can't pass `exclude_filename` to it from `dist.ini` — use the bundle's documeRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.