# Add Config

> Add config.yml handling to a Minecraft plugin — a bundled default config, saveDefaultConfig() in onEnable, a typed settings accessor, and a reload path. Use this whenever the user wants configurable settings, options, a config file, tunable values, messages the admin can edit, a /reload command, or 'read this from config instead of hardcoding it' in their Bukkit/Paper plugin. Reads the target stack from .mcplugin/config.yml.

- Skill: `itamarb2010-jpg/add-config` (Agent Skill)
- Install (CLI): `npx skillmds@latest add itamarb2010-jpg/add-config`
- Raw SKILL.md: https://api.skillmd.com/api/skills/itamarb2010-jpg/add-config/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: itamarb2010-jpg (https://skillmd.com/u/itamarb2010-jpg)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/itamarb2010-jpg/add-config

---


# Add config.yml handling

Wire up first-run defaults, typed reads, and a reload path, matching the project's stack and
conventions. Follow the collaborative rule: propose the design, show the code, then write after
the user approves.

## Phase 1: Load context

- Read `.mcplugin/config.yml` (the **project** descriptor) for `platform`, `mc_version`,
  `package`, `main_class`, `plugin_name`. If it's missing, tell the user to run
  `/setup-platform` (and `/scaffold`) first. Note: this is different from the plugin's own
  runtime `config.yml` you're about to create under `src/main/resources`.
- Read the reference and pitfalls (relative to this skill; `Glob` as fallback):
  - `../../references/api/persistence-config.md` — `getConfig()`, defaults, save/reload
  - `../../references/pitfalls.md` — the "Config" section
- Look at existing source to match style: `Glob` `src/main/java/**/*.java`, read the main class
  and check whether a `src/main/resources/config.yml` already exists (extend it, don't clobber).

## Phase 2: Clarify the settings

Ask (AskUserQuestion or plain text) only what you can't infer:
- **Which settings** are needed, their **types** (int, double, boolean, String, list, section),
  and a sensible **default** for each.
- **Grouping** — flat keys vs. nested sections (e.g. `messages.no-permission`).
- **Messages** — if any user-facing text is configurable, note it (on Paper these can be
  deserialized to Adventure `Component` via MiniMessage; on Spigot they stay `String`).
- **Reload** — how should an admin reload without restarting? A `/<plugin> reload` subcommand,
  a dedicated admin command, or none. Offer to wire it.

## Phase 3: Choose the accessor shape

Decide from the stack and explain the pick briefly:
- **Direct `getConfig().getX(...)` calls** — fine for one or two values; simplest.
- **A typed settings holder** (recommended for several values) — a small class that reads all
  keys once into typed fields on load/reload, so the rest of the code reads plain fields instead
  of stringly-typed config paths. Fewer typos, one place for defaults, cheap reads in hot paths.
- **Nested sections** — for grouped keys use `getConfig().getConfigurationSection("messages")`
  and read within it; iterate `getKeys(false)` for map-like config (e.g. a set of named warps).
- **Lists** — `getStringList(path)` / `getIntegerList(path)` return an empty list (not null)
  when the key is absent, so they're safe to iterate directly.

## Phase 4: Implement

Generate, in the project's package and resources:
1. **`src/main/resources/config.yml`** — every setting with its default value and a short
   comment. This bundled file is what ships inside the jar.
2. In the main class `onEnable`, call **`saveDefaultConfig()`** so the file is written to the
   data folder on first run (`getConfig()` reads the on-disk copy).
3. **A typed accessor / settings holder** that reads each key with a default and is null-safe —
   `getConfig().getInt(path, default)` style, never assuming a key is present. Validate ranges
   where it matters (e.g. clamp a negative radius) and log a warning on bad values.
4. **A reload path** if requested: a subcommand/admin command that calls `reloadConfig()` then
   re-reads into the settings holder, with a permission check and a confirmation message. (Use
   `saveConfig()` only when the plugin itself writes values back — don't call it on pure reads,
   as it can strip comments.)

Note that `saveDefaultConfig()` will **not** overwrite an existing on-disk `config.yml`, so new
keys you add in a later version won't appear for existing servers — read them with defaults (so
they still work), and if the shape changes materially, add a `config-version` key and migrate.

Show the new/edited files (`config.yml`, the settings class, the `onEnable` diff, any reload
command wiring) and get approval before writing.

## Phase 5: Verify + hand off

- Re-check the pitfalls: bundled `config.yml` present in resources, `saveDefaultConfig()` called
  in `onEnable`, every read has a **default** and is null-safe, reload path calls
  `reloadConfig()` **before** re-reading, and in-memory settings are refreshed after reload.
- Suggest next steps: "`/build` to compile, then `/run-server`; edit `config.yml` and reload to
  confirm values take effect."

Do not fabricate APIs for a Minecraft version newer than `../../references/api/VERSION.md`
documents — if unsure a method exists in the target version, say so and verify.

