random_name_generator 4.0.0 → 4.0.2

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.
@@ -0,0 +1,122 @@
1
+ # `/lang-gen` skill — design
2
+
3
+ **Date:** 2026-07-18
4
+ **Status:** Approved, pending implementation plan
5
+
6
+ ## Context
7
+
8
+ `random_name_generator` composes fake names from small language files under
9
+ `lib/languages/`. Each file is a tiny DSL:
10
+
11
+ - One syllable per line.
12
+ - Leading `-` → **prefix** (pre) bucket; leading `+` → **suffix** (sur) bucket;
13
+ no leading sign → **middle** (mid) bucket. `Generator#push` reads these.
14
+ - Trailing flags encode phonotactics, per `lib/random_name_generator/syllable.rb`:
15
+ - `+v` — next syllable must start with a vowel.
16
+ - `+c` — next syllable must start with a consonant.
17
+ - `-v` — this syllable may only follow one ending in a vowel.
18
+ - `-c` — this syllable may only follow one ending in a consonant.
19
+
20
+ Adding a language today is a manual two-step: drop a `.txt` in `lib/languages/`
21
+ (edgy themes go in `lib/languages/experimental/`, like `curse.txt`), then wire a
22
+ `File.new(...)` constant into `lib/random_name_generator.rb`.
23
+
24
+ `/lang-gen` automates this as a **guided authoring skill**: turn a free-text
25
+ theme into a well-flagged syllable file plus its integration.
26
+
27
+ ## Goal
28
+
29
+ `/lang-gen <free text theme>` (e.g. `/lang-gen german curse words`) produces a
30
+ new, ready-to-use language: a syllable `.txt`, a registered constant, a smoke
31
+ spec, a README entry, and sample output for a quality check.
32
+
33
+ ## Decisions (from brainstorming)
34
+
35
+ | Question | Decision |
36
+ |----------|----------|
37
+ | Output scope | **Full integration** — `.txt` + constant + README entry + smoke spec |
38
+ | File destination | **experimental/ for edgy themes**; tame themes → `lib/languages/` |
39
+ | Skill location | **Project** `.claude/skills/lang-gen/SKILL.md`, committed |
40
+ | Linguistic method | **Hybrid** — seed from real roots, then extend with same-flavor invented syllables |
41
+ | Size & flags | **Match existing files** (~20–40 per bucket) **+ smart flags** |
42
+ | Verification | **Sample and show** ~10 composed names + parse-check |
43
+
44
+ ## Design
45
+
46
+ ### Trigger and argument parsing
47
+
48
+ - Invoked as `/lang-gen <free text theme>`. The whole argument string is the theme.
49
+ - Derive:
50
+ - **slug** — concise kebab-case, 1–2 meaningful words, dropping filler
51
+ ("words", "generator", articles). `german curse words` → `german-curse`.
52
+ - **constant** — SCREAMING_SNAKE of the slug. `german-curse` → `GERMAN_CURSE`.
53
+ - **destination** — edgy/NSFW/joke themes (curse, insult, swear, drunk, etc.)
54
+ → `lib/languages/experimental/`; otherwise `lib/languages/`.
55
+ - Show the derived slug / constant / destination and **confirm with the user**
56
+ before writing, so they can rename or re-route.
57
+ - Guard against collisions: if the slug file or constant already exists, stop and
58
+ ask (do not overwrite an existing language).
59
+
60
+ ### Syllable generation (hybrid, seeded-then-extended)
61
+
62
+ The skill body instructs Claude to:
63
+
64
+ 1. Recall a handful of **real theme roots** appropriate to the theme
65
+ (German curses: `schei`, `arsch`, `sau`, `verdammt`, `dreck`, `mist`, …).
66
+ 2. Slot fragments into the three buckets:
67
+ - prefixes (`-`) — natural word beginnings,
68
+ - middles (bare) — connective interior fragments,
69
+ - suffixes (`+`) — natural word endings / intensifiers.
70
+ 3. **Pad** each bucket with same-flavor **invented** syllables until each holds
71
+ roughly **20–40** entries, matching `goblin.txt` scale.
72
+ 4. Apply `+v/+c/-v/-c` flags where they prevent awkward clusters, following the
73
+ exact semantics in `syllable.rb` (e.g. a consonant-final prefix that would
74
+ clash gets a flag; a lone vowel-ending fragment gets `+c`). Flags are used
75
+ judiciously, not on every line.
76
+
77
+ ### Full integration
78
+
79
+ After the `.txt` is written:
80
+
81
+ - **Constant** — add `CONST = File.new("#{dirname}/languages/<path>")` to
82
+ `lib/random_name_generator.rb`. Edgy themes go under the existing
83
+ `# Experimental` block; tame themes alongside the curated constants. The
84
+ curated `flip_mode` arrays are **not** modified (they stay hand-picked).
85
+ - **Spec** — add a minimal RSpec smoke test following existing `spec/`
86
+ conventions: the file loads, parses, all three buckets are non-empty, and
87
+ `compose` returns a non-empty String.
88
+ - **README** — add the new language under a short experimental-languages note
89
+ (link to the file), consistent with how the curated four are listed.
90
+
91
+ ### Verification (sample and show)
92
+
93
+ Before declaring done, the skill:
94
+
95
+ - **Parse-checks**: every line is a valid syllable; pre, mid, and sur buckets are
96
+ all non-empty.
97
+ - **Samples**: loads the new constant through the gem and prints ~10 names via
98
+ `RandomNameGenerator.new(RandomNameGenerator::CONST).compose`.
99
+ - If output looks broken or monotonous, it iterates on the syllable file before
100
+ finishing.
101
+
102
+ ### Skill packaging
103
+
104
+ - Lives at `.claude/skills/lang-gen/SKILL.md` with YAML frontmatter
105
+ (`name`, `description`, trigger guidance).
106
+ - Per the project rule, add a link to `README.md` under a `## Skills` section
107
+ using the skill's `name` as link text and its `description` as the blurb.
108
+
109
+ ## Constraints / notes
110
+
111
+ - **Git is manual.** State-changing git is off-limits to the assistant; the
112
+ spec-commit and final commit are surfaced as suggested commands for the user
113
+ to run, not executed by the skill.
114
+ - **No overwrite.** The skill never clobbers an existing language file or
115
+ constant without explicit confirmation.
116
+
117
+ ## Out of scope (YAGNI)
118
+
119
+ - Editing `flip_mode` / `flip_mode_cyrillic` sampler arrays.
120
+ - Cyrillic (`-ru`) variants of generated languages.
121
+ - Bulk / batch generation of multiple themes at once.
122
+ - Programmatic scraping of external wordlists.
@@ -0,0 +1,124 @@
1
+ # Lang-Gen Portable Prompt
2
+
3
+ Use this prompt with any LLM that can edit files and run commands in the repository.
4
+
5
+ ## Goal
6
+
7
+ Generate a new `random_name_generator` language from a free-text theme such as `german curse words`. The result should be a fully integrated language file with a registered constant, a smoke spec, a README entry, and verification output.
8
+
9
+ ## Language File DSL
10
+
11
+ Authoritative source: `lib/random_name_generator/syllable.rb`.
12
+
13
+ Each line of a language `.txt` file is one syllable:
14
+
15
+ - Leading `-` = prefix bucket, a name beginning.
16
+ - Leading `+` = suffix bucket, a name ending.
17
+ - No leading sign = middle bucket, an interior fragment.
18
+
19
+ Optional whitespace-separated flags after the syllable constrain adjacency:
20
+
21
+ - `+v` = the next syllable must start with a vowel.
22
+ - `+c` = the next syllable must start with a consonant.
23
+ - `-v` = this syllable may only follow one ending in a vowel.
24
+ - `-c` = this syllable may only follow one ending in a consonant.
25
+
26
+ A valid language needs all three buckets to be non-empty. `Generator#compose` picks a prefix, fills with middles, and ends with a suffix while honoring flags.
27
+
28
+ ## Workflow
29
+
30
+ Follow these steps in order. Do not skip verification.
31
+
32
+ ### 1. Parse the theme and derive names
33
+
34
+ From the theme string, derive and show the user for confirmation:
35
+
36
+ - Slug: concise kebab-case, 1-2 meaningful words, dropping filler such as `words`, `generator`, and articles. Example: `german curse words` -> `german-curse`.
37
+ - Constant: SCREAMING_SNAKE version of the slug. Example: `german-curse` -> `GERMAN_CURSE`.
38
+ - Destination: edgy themes such as curse, insult, swear, NSFW, or drunk go in `lib/languages/experimental/<slug>.txt`; tame themes go in `lib/languages/<slug>.txt`.
39
+
40
+ Before writing anything, check for collisions. If the target `.txt` file or the constant already exists, stop and ask the user how to proceed. Never overwrite.
41
+
42
+ ### 2. Author the syllable file
43
+
44
+ 1. Recall a handful of real roots for the theme. Example for German curses: `schei`, `arsch`, `sau`, `verdammt`, `dreck`, `mist`, `depp`, `blöd`.
45
+ 2. Slot fragments into buckets: prefixes (`-`) are natural beginnings, middles are connective interiors, and suffixes (`+`) are natural endings or intensifiers.
46
+ 3. Extend each bucket with same-flavor invented syllables until each bucket has roughly 20-40 entries, matching the scale of `lib/languages/goblin.txt`.
47
+ 4. Add `+v`, `+c`, `-v`, and `-c` flags only where they prevent awkward clusters. Most lines should carry no flag.
48
+
49
+ Write the file to the destination chosen in step 1.
50
+
51
+ ### 3. Register the constant
52
+
53
+ Edit `lib/random_name_generator.rb` and add the new `File` constant next to the matching group of constants. Put edgy themes under the existing `# Experimental` comment and tame themes with the curated constants.
54
+
55
+ Use the existing pattern:
56
+
57
+ ```ruby
58
+ CONSTANT_NAME = File.new("#{dirname}/languages/<relative/path>.txt")
59
+ ```
60
+
61
+ Do not change `flip_mode` or `flip_mode_cyrillic`; those arrays are curated.
62
+
63
+ ### 4. Add a smoke spec
64
+
65
+ Add an example to `spec/random_name_generator_spec.rb` following the existing `with languages` conventions. The test should assert that the constant is a `File`, that its `path` includes the expected filename, and that a `Generator` built from it composes a non-empty `String`.
66
+
67
+ Example shape:
68
+
69
+ ```ruby
70
+ it "when it has a <Theme> language" do
71
+ expect(RandomNameGenerator::CONSTANT_NAME).to be_a(File)
72
+ expect(RandomNameGenerator::CONSTANT_NAME.path).to include("languages/<relative/path>.txt")
73
+ name = RandomNameGenerator::Generator.new(RandomNameGenerator::CONSTANT_NAME).compose
74
+ expect(name).to be_a(String)
75
+ expect(name).not_to be_empty
76
+ end
77
+ ```
78
+
79
+ ### 5. Add a README entry
80
+
81
+ Add the new language to `README.md`. Edgy or experimental languages should go under a short experimental-languages note. Tame ones should join the curated list. Link to the file using the same style as the existing entries.
82
+
83
+ ### 6. Verify
84
+
85
+ First parse-check the language file and confirm all three buckets are non-empty. Then sample about 10 composed names so the user can eyeball them. Finally, run the targeted spec.
86
+
87
+ Suggested commands:
88
+
89
+ ```bash
90
+ bundle exec ruby -Ilib -rrandom_name_generator -e '
91
+ g = RandomNameGenerator::Generator.new(RandomNameGenerator::CONSTANT_NAME)
92
+ abort "empty pre" if g.pre_syllables.empty?
93
+ abort "empty mid" if g.mid_syllables.empty?
94
+ abort "empty sur" if g.sur_syllables.empty?
95
+ puts "buckets OK: #{g.pre_syllables.size}/#{g.mid_syllables.size}/#{g.sur_syllables.size}"
96
+ '
97
+ ```
98
+
99
+ ```bash
100
+ bundle exec ruby -Ilib -rrandom_name_generator -e '
101
+ g = RandomNameGenerator::Generator.new(RandomNameGenerator::CONSTANT_NAME)
102
+ 10.times { puts g.compose }
103
+ '
104
+ ```
105
+
106
+ ```bash
107
+ bundle exec rspec spec/random_name_generator_spec.rb
108
+ ```
109
+
110
+ If names look broken or monotonous, iterate on the `.txt` file and re-sample before finishing.
111
+
112
+ ### 7. Hand off the commit
113
+
114
+ Do not run git commands yourself. Surface the exact command for the user:
115
+
116
+ ```bash
117
+ git add lib/languages README.md lib/random_name_generator.rb spec/random_name_generator_spec.rb && git commit -m "Add <Theme> language via lang-gen"
118
+ ```
119
+
120
+ ## Guardrails
121
+
122
+ - Never overwrite an existing language file or constant without confirmation.
123
+ - Never run state-changing git commands; only suggest them.
124
+ - Keep bucket sizes and flag style consistent with existing `lib/languages/*.txt` files.
@@ -11,9 +11,12 @@ opts = Slop.parse do |o|
11
11
  o.bool "-e", "--elven", "Use Elven eyllable file"
12
12
  o.bool "-g", "--goblin", "Use Goblin eyllable file"
13
13
  o.bool "-r", "--roman", "Use Roman eyllable file"
14
+ o.bool "-k", "--klingon", "Use Klingon eyllable file"
14
15
  o.bool "-f", "--flipmode", "Flip mode in effect"
15
16
  o.bool "-c", "--cyrillic", "Use Cyrillic mode"
16
17
  o.bool "-x", "--xrated", "Generate Curse words [NEEDS WORK]"
18
+ o.bool "-d", "--demonic", "Generate Demonic names"
19
+ o.bool "-ß", "--german-curse", "Generate German Curse words [NEEDS WORK]"
17
20
  o.bool "-?", "--help", "How to"
18
21
  end
19
22
 
@@ -26,7 +29,10 @@ else
26
29
  lang = RandomNameGenerator::ELVEN if opts.elven?
27
30
  lang = RandomNameGenerator::GOBLIN if opts.goblin?
28
31
  lang = RandomNameGenerator::ROMAN if opts.roman?
32
+ lang = RandomNameGenerator::KLINGON if opts.klingon?
29
33
  lang = RandomNameGenerator::CURSE if opts.xrated?
34
+ lang = RandomNameGenerator::DEMONIC if opts.demonic?
35
+ lang = RandomNameGenerator::GERMAN_CURSE if opts.german_curse?
30
36
  end
31
37
 
32
38
  if opts.flipmode?