| name | new-env |
| description | Add a new environment variable to the project end-to-end, keeping the typed config struct, env file samples, and documentation in sync. Touches `internal/config/envspec.go` (Loader field), `internal/config/model.go` (Config struct + private field), `internal/config/config.go` (New() mapping + getter method), `internal/config/config_testing_mock.go` (expected value + mock setter), `env/.env.{local,ci,dev,stg,prd}` (and `.env` if used) for per-environment values, and `env/README.{md,ja.md}` (table row in the matching subsystem). The subsystem (envPrefix → struct), Go type mapping, and naming conventions are derived from the existing `envspec.go` / `model.go` at runtime — the skill hardcodes no subsystem list. Confirms variable name, type, description (en + ja), required vs default, and per-environment values via `AskUserQuestion` before writing. Does NOT auto-add a testing setter helper in `config_testing_setter.go` (the file explicitly limits additions); offers it only on explicit request. Verifies with `make fix` + `make test` at the end. |
New Env
Adds a new environment variable to the project end-to-end. The variable is read by the Loader struct, mapped into the typed Config, exposed via a getter, set in each per-environment sample env file, and documented in env/README.md.
A Japanese reference translation of this skill is available at SKILL.ja.md in the same directory (not loaded as a skill; for human reference only).
When to Use
Use this skill when:
- A new env var is needed (new feature flag, tunable timeout, external service URL, etc.).
- Multiple files need to stay in sync and you want them updated consistently.
Do NOT use this skill for:
- Renaming an existing env var (different workflow — rename across all places).
- Removing an existing env var (deletion is reverse-direction and safer to do by hand).
- Adding a whole new subsystem (e.g., a new
RedisConfig group). This skill assumes the subsystem already exists. For a new subsystem, do the first variable manually then use this skill for subsequent additions.
What This Skill Reads / Writes
Reads (always):
internal/config/envspec.go — Loader subsystem inventory (envPrefix → struct mapping).
internal/config/model.go — Config subsystem inventory (private field naming).
internal/config/config.go — New() body for mapping pattern; existing getters for naming convention.
internal/config/config_testing_mock.go — expected value variables and mock setter patterns.
env/.env.local, .env.ci, .env.dev, .env.stg, .env.prd, .env — per-environment value placement.
env/README.md, env/README.ja.md — table format and subsystem section names.
Writes (only with confirmation):
- The 9 files listed above. Per-file edits are minimal (one insertion in the correct location each).
Never touches:
config_testing_setter.go unless the user explicitly asks (file is intentionally curated).
- Any code under
internal/ outside config/.
- Generated files.
First Step: Gather the Spec
This skill MUST call AskUserQuestion immediately after invocation. Ask in batches (multiple questions per call) to collect the spec:
Question 1: Variable name and subsystem
- Question: 「環境変数名(
{PREFIX}_{NAME} 形式)を入力してください。例: APP_FEATURE_X / DB_READ_REPLICA_HOST」
- Free-text input. The skill then:
- Splits at the first
_ to get the prefix.
- Looks up the prefix in the live
envspec.go (each subsystem struct has envPrefix:"XXX_").
- If matched: shows "推定サブシステム:
Application (envPrefix APP_)" and asks for confirmation.
- If not matched: surfaces the candidates and asks the user to either pick a different prefix, or stop and add a new subsystem manually first.
Question 2: Go type and required/default
Ask the user (single AskUserQuestion with 4 options):
- Question: 「型と必須・デフォルトを選んでください」
- Options:
- 「string, required」
- 「string, default あり(値を後で指定)」
- 「int / bool / duration, required(型は後で指定)」
- 「int / bool / duration, default あり(型と値を後で指定)」
Follow up with free-text for the concrete type (int / bool / time.Duration / []string / etc.) and default value when applicable.
Question 3: Description
Free-text. The user provides EITHER English OR Japanese (or both). The skill auto-fills the missing side via inline translation so both READMEs stay in sync without forcing the user to write twice.
- 「説明(日本語または英語のどちらか)」 — written into the matching language's README directly
- Notes column(任意) — Secret management / 環境依存等の注記。Provided in the same language as the description; the skill translates for the other.
Resolution rules:
- If only Japanese provided → skill writes Japanese to
env/README.ja.md row, then translates to English for env/README.md row.
- If only English provided → reverse direction.
- If both provided → use as-is, no translation.
- Translations are kept short and direct (single-line, technical register matching surrounding rows). If the description is non-trivial or domain-specific, surface the proposed translation in the Step 2 plan summary for user review before writing.
Question 4: Per-environment values
Single AskUserQuestion:
- Question: 「環境別の値を指定しますか?」
- Options:
- 「全環境同じ値(または default で OK)」
- 「local だけ別の値を入れる」
- 「prd だけ別の値を入れる」
- 「環境ごとに個別指定する(追加質問)」
Based on choice, collect per-env values. For prd-specific, surface that the value is typically a placeholder commented out (# DB_HOST style) and ask whether to follow that convention.
Question 5: Mock / setter
- Question: 「テストヘルパーをどこまで追加しますか?」
- Options:
- 「mock のみ(config_testing_mock.go の expected 値 + mock setter)」(推奨)
- 「mock + setter(config_testing_setter.go にも追加)」 — only when the user has a clear testing need
- 「テストヘルパーは追加しない」
Step 1. Plan the Insertion Points
For each touch point, compute the exact insertion location by reading existing patterns:
envspec.go
Find the matched subsystem struct. Append the new field at the end (preserve struct field order). Field tag format:
- Required:
env:"NAME,required"
- With default:
env:"NAME" default:"value"
Field type matches the Go type (string / int / bool / time.Duration / []string).
model.go
In the matching Config sub-struct (e.g., ApplicationConfig), append the private field with the camelCase name corresponding to the env name (e.g., APP_FEATURE_X → featureX).
config.go
Two changes:
- In
New(), find the matching subsystem block and append the field mapping (fieldName: cfg.Sub.FieldName,).
- Append a getter method on the sub-struct:
func (a *ApplicationConfig) FeatureX() T { return a.featureX }. Use the existing getters in the same sub-struct as the formatting template (single-line or multi-line, doc comment style).
config_testing_mock.go
- Append an expected value variable (
expectedSubsystemFieldName = ...).
- Append a setter on the mock sub-struct (
func (a *ApplicationConfig) SetFeatureX(...)).
- Update the mock initializer if there is one to include the new field.
Test updates (mandatory — coverage must not regress)
The internal/config package is currently 100% covered. Adding a field without updating the matching tests breaks coverage. Update three test files in lockstep with the production changes:
| Test file | What to update |
|---|
internal/config/config_test.go | In TestNewConfig, add the new field to the expected &Config{...} literal under the matching sub-struct, using the expected* variable defined in config_testing_mock.go. |
internal/config/model_test.go | In TestGetterMethods, add a t.Run("FieldName", func(t *testing.T) { t.Parallel(); require.Equal(t, expectedValue, sub.FieldName()) }) block under the matching subsystem t.Run. |
internal/config/config_testing_mock_test.go | In TestMockConfigForTest, add the new field to the expected &Config{...} literal under the matching sub-struct. |
The expected* variable comes from the config_testing_mock.go addition (Question-5 mock scope). If the user opted out of mock additions, the test updates also must be skipped — surface this trade-off explicitly in Step 2 plan: "テストヘルパー追加なし → カバレッジ維持テストもスキップ。100% から下がる可能性あり".
env files
For each of env/.env.local, .env.ci, .env.dev, .env.stg, .env.prd, .env:
- Locate the section comment (e.g.,
# Application).
- Append the new var line under the matching section, preserving alignment.
- For prd, default to the commented placeholder convention (
# APP_FEATURE_X) unless the user supplied an explicit prd value.
env/README.md and README.ja.md
In the matching subsystem table (e.g., ### Application), append a row:
|APP_FEATURE_X|<description>|<type>|<example>|<notes>|
The Japanese README gets the Japanese description and notes.
Step 2. Show the Plan and Confirm
Display the full set of proposed changes as a Japanese summary:
追加する環境変数: APP_FEATURE_X
サブシステム: Application (envPrefix "APP_")
型: bool
required / default: required
英語説明: Enable experimental X feature
日本語説明: 試験的な機能 X を有効化
notes (en): 開発環境のみ true 推奨
per-env 値: local=true / ci=true / dev=false / stg=false / prd=false
テストヘルパー: mock のみ
修正対象 (12 ファイル):
- internal/config/envspec.go (Application 構造体に 1 行追加)
- internal/config/model.go (ApplicationConfig 構造体に 1 行追加)
- internal/config/config.go (New() マッピング + Getter 追加)
- internal/config/config_testing_mock.go (expected 値 + setter 追加)
- internal/config/config_test.go (TestNewConfig 期待値構造体に 1 行追加)
- internal/config/model_test.go (TestGetterMethods に t.Run 追加)
- internal/config/config_testing_mock_test.go (TestMockConfigForTest 期待値構造体に 1 行追加)
- env/.env.local, .env.ci, .env.dev, .env.stg, .env.prd (各 1 行追加)
- env/README.md, env/README.ja.md (Application 表に行追加)
説明の補完:
- 入力: 日本語のみ供与
- 英語訳(自動生成、レビュー対象): "Enable the experimental X feature"
Confirm with AskUserQuestion:
- Question: 「以上の内容で適用しますか?」
- Options: 「適用する」 / 「修正したい箇所を指摘する」 / 「キャンセル」
Step 3. Apply Changes
For each file, use the Edit tool with exact anchor strings derived from the read context (the last existing field in the target struct / section). Stage changes in this order:
envspec.go
model.go
config.go (mapping + getter)
config_testing_mock.go (expected value variable + mock setter)
config_test.go (TestNewConfig literal — coverage maintenance)
model_test.go (TestGetterMethods t.Run — coverage maintenance)
config_testing_mock_test.go (TestMockConfigForTest literal — coverage maintenance)
- env files (one Edit per file:
env/.env.local, .env.ci, .env.dev, .env.stg, .env.prd, .env)
env/README.md then env/README.ja.md
After each file edit, verify the edit landed (the Edit tool reports success or failure — if any fails, stop and report).
Step 4. Verify
Run:
make fix
make test
If make test fails, surface the failure and stop. Do NOT roll back the edits; the user decides whether to fix forward.
If make fix modifies anything beyond the just-edited files, surface the diff.
Coverage check
After make test succeeds, confirm the internal/config package's coverage line in the test output. Expected: go-boilerplate/internal/config <time> coverage: 100.0% of statements. If coverage dropped below 100%:
- Identify which new code path lacks a test (typically the new getter or the new
New() mapping line).
- Verify the Step-3 test updates (
config_test.go, model_test.go, config_testing_mock_test.go) all included the new field.
- If any was missed, add it and re-run
make test.
Do NOT mark the skill complete with reduced coverage unless the user explicitly opted out of mock + test updates (Question 5).
Step 5. Closing
- Print a 1-line summary:
<VAR_NAME> を追加。<N> ファイル更新。make test OK。
- The skill does NOT commit. Use
/commit after reviewing.
- If the user also wants the corresponding documentation in
internal/config/README.md to be refreshed (rare — internal/config/README.md describes the package, not individual vars), recommend /sync-readme.
AI Modification Scope
Per the "Exception: Skill Execution" clause in CLAUDE.md / AGENTS.md, the AI modification scope is relaxed during this skill's run, scoped to:
- The 9 files listed above (or the subset the user confirmed).
Remains protected:
internal/config/config_testing_setter.go unless the user explicitly opts in (file comment intentionally limits additions).
- All other code outside
internal/config/.
- Generated files.
Constraints
- ❌ Hardcode the subsystem list — always derive from live
envspec.go
- ❌ Add a
config_testing_setter.go helper without explicit user opt-in
- ❌ Modify env files outside the listed 6 set
- ❌ Skip the spec-confirmation
AskUserQuestion
- ❌ Apply changes without showing the full plan first
- ❌ Touch code unrelated to the new var
- ✅ Japanese user-facing output
- ✅ Preserve formatting in env files (column alignment, comment style)
- ✅ Preserve formatting in README tables (column count and order)
- ✅ Run
make fix + make test after the writes
- ✅ Surface any verification failure; do not auto-rollback
Checklist
Before reporting completion, confirm: