random_name_generator 4.0.0 → 4.0.1
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.
- checksums.yaml +4 -4
- data/.claude/skills/lang-gen/SKILL.md +140 -0
- data/Gemfile.lock +1 -1
- data/README.md +63 -11
- data/docs/superpowers/plans/2026-07-18-lang-gen-skill.md +320 -0
- data/docs/superpowers/specs/2026-07-18-lang-gen-skill-design.md +122 -0
- data/docs/superpowers/specs/2026-07-19-lang-gen-portable-prompt.md +124 -0
- data/exe/random_name_generator +2 -0
- data/lib/languages/experimental/german-curse.txt +139 -0
- data/lib/random_name_generator/version.rb +1 -1
- data/lib/random_name_generator.rb +1 -0
- metadata +6 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f728099d28460a59f2c78c3d43ca48deed8588040141a0ba14fc52b0c8285185
|
|
4
|
+
data.tar.gz: 32174e3c901a12ab6da5eaf23a4ebf6671f07679869e061b953e0460326f8a67
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0bd991d716f21b3fd88d62766d8afbfe9dd8edc086dd14577ab5ad7f87fbd04d9b45fc2eb689cc8e54d6cb062cc34bb414f6602e8538c2f28f17e7cd7584dd2d
|
|
7
|
+
data.tar.gz: a78b01b414bbf735775449d67a7888c41f8193158cd8b3314a62b65459a609c1e3e8782c1672371880f36a4cb50fb9b5e666a528fe33778ec79c639fd687aa05
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lang-gen
|
|
3
|
+
description: Generate a new random_name_generator language from a free-text theme (e.g. "german curse words") — assembles flagged pre/mid/sur syllable collections, registers the File constant, adds a smoke spec and README entry, and samples names to verify. Use when asked to create, generate, or add a new language, dialect, or syllable file for the name generator.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# lang-gen
|
|
7
|
+
|
|
8
|
+
Turn a free-text theme into a fully integrated `random_name_generator`
|
|
9
|
+
language file. This workflow is written to be model-agnostic: any assistant
|
|
10
|
+
that can edit files and run commands can follow it.
|
|
11
|
+
|
|
12
|
+
## The language-file DSL
|
|
13
|
+
|
|
14
|
+
Authoritative source: `lib/random_name_generator/syllable.rb`. Each line of a
|
|
15
|
+
language `.txt` is one syllable:
|
|
16
|
+
|
|
17
|
+
- Leading `-` → **prefix** (pre) bucket — a name beginning.
|
|
18
|
+
- Leading `+` → **suffix** (sur) bucket — a name ending.
|
|
19
|
+
- No sign → **middle** (mid) bucket — an interior fragment.
|
|
20
|
+
|
|
21
|
+
Optional whitespace-separated flags after the syllable constrain adjacency:
|
|
22
|
+
|
|
23
|
+
- `+v` — the NEXT syllable must start with a vowel.
|
|
24
|
+
- `+c` — the NEXT syllable must start with a consonant.
|
|
25
|
+
- `-v` — THIS syllable may only follow one ending in a vowel.
|
|
26
|
+
- `-c` — THIS syllable may only follow one ending in a consonant.
|
|
27
|
+
|
|
28
|
+
A name needs all three buckets non-empty. `Generator#compose` picks a prefix,
|
|
29
|
+
fills with middles, ends with a suffix, honoring the flags.
|
|
30
|
+
|
|
31
|
+
## Workflow
|
|
32
|
+
|
|
33
|
+
Follow these steps in order. Do not skip verification.
|
|
34
|
+
|
|
35
|
+
### 1. Parse the theme and derive names
|
|
36
|
+
|
|
37
|
+
From the argument string derive and then **show the user for confirmation**:
|
|
38
|
+
|
|
39
|
+
- **slug** — concise kebab-case, 1–2 meaningful words, drop filler ("words",
|
|
40
|
+
"generator", articles). `german curse words` → `german-curse`.
|
|
41
|
+
- **constant** — SCREAMING_SNAKE of the slug. `german-curse` → `GERMAN_CURSE`.
|
|
42
|
+
- **destination** — edgy themes (curse, insult, swear, NSFW, drunk, etc.) →
|
|
43
|
+
`lib/languages/experimental/<slug>.txt`; tame themes →
|
|
44
|
+
`lib/languages/<slug>.txt`.
|
|
45
|
+
|
|
46
|
+
Before writing anything, check for collisions: if the target `.txt` OR the
|
|
47
|
+
constant already exists, STOP and ask the user how to proceed. Never overwrite.
|
|
48
|
+
|
|
49
|
+
### 2. Author the syllable file (hybrid: seed, then extend)
|
|
50
|
+
|
|
51
|
+
1. Recall a handful of **real roots** for the theme. (German curses: `schei`,
|
|
52
|
+
`arsch`, `sau`, `verdammt`, `dreck`, `mist`, `depp`, `blöd`, …)
|
|
53
|
+
2. Slot fragments into buckets: prefixes (`-`) = natural beginnings, middles
|
|
54
|
+
(bare) = connective interiors, suffixes (`+`) = natural endings / intensifiers.
|
|
55
|
+
3. **Extend** each bucket with same-flavor **invented** syllables until each
|
|
56
|
+
holds ~20–40 entries (match `lib/languages/goblin.txt` scale).
|
|
57
|
+
4. Add `+v/+c/-v/-c` flags **only where they prevent awkward clusters** — e.g. a
|
|
58
|
+
consonant-final prefix that would collide, or a lone vowel that reads badly
|
|
59
|
+
after another vowel. Most lines carry no flag. Keep it judicious.
|
|
60
|
+
|
|
61
|
+
Write the file to the destination from step 1.
|
|
62
|
+
|
|
63
|
+
### 3. Register the constant
|
|
64
|
+
|
|
65
|
+
Edit `lib/random_name_generator.rb`. Add, next to the matching group of
|
|
66
|
+
constants (edgy → under the `# Experimental` comment; tame → with the curated
|
|
67
|
+
constants):
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
CONSTANT_NAME = File.new("#{dirname}/languages/<relative/path>.txt")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Do NOT touch `flip_mode` or `flip_mode_cyrillic` — those arrays are curated.
|
|
74
|
+
|
|
75
|
+
### 4. Add a smoke spec
|
|
76
|
+
|
|
77
|
+
Add an example to `spec/random_name_generator_spec.rb` following existing
|
|
78
|
+
conventions (see the `with languages` context). It must assert the constant is a
|
|
79
|
+
`File`, its `path` includes the expected filename, and that a `Generator` built
|
|
80
|
+
from it composes a non-empty `String`:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
it "when it has a <Theme> language" do
|
|
84
|
+
expect(RandomNameGenerator::CONSTANT_NAME).to be_a(File)
|
|
85
|
+
expect(RandomNameGenerator::CONSTANT_NAME.path).to include("languages/<relative/path>.txt")
|
|
86
|
+
name = RandomNameGenerator::Generator.new(RandomNameGenerator::CONSTANT_NAME).compose
|
|
87
|
+
expect(name).to be_a(String)
|
|
88
|
+
expect(name).not_to be_empty
|
|
89
|
+
end
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 5. Add a README entry
|
|
93
|
+
|
|
94
|
+
Add the new language to `README.md`. Edgy/experimental languages go under a
|
|
95
|
+
short "Experimental languages" note; tame ones join the curated list. Link to
|
|
96
|
+
the file, matching how the curated four are listed.
|
|
97
|
+
|
|
98
|
+
### 6. Verify — parse-check then sample
|
|
99
|
+
|
|
100
|
+
- **Parse-check:** confirm every line is a valid syllable and all three buckets
|
|
101
|
+
are non-empty. Fastest via the gem:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
bundle exec ruby -Ilib -rrandom_name_generator -e '
|
|
105
|
+
g = RandomNameGenerator::Generator.new(RandomNameGenerator::CONSTANT_NAME)
|
|
106
|
+
abort "empty pre" if g.pre_syllables.empty?
|
|
107
|
+
abort "empty mid" if g.mid_syllables.empty?
|
|
108
|
+
abort "empty sur" if g.sur_syllables.empty?
|
|
109
|
+
puts "buckets OK: #{g.pre_syllables.size}/#{g.mid_syllables.size}/#{g.sur_syllables.size}"
|
|
110
|
+
'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
- **Sample:** print ~10 composed names for the user to eyeball:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
bundle exec ruby -Ilib -rrandom_name_generator -e '
|
|
117
|
+
g = RandomNameGenerator::Generator.new(RandomNameGenerator::CONSTANT_NAME)
|
|
118
|
+
10.times { puts g.compose }
|
|
119
|
+
'
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- **Run the spec:** `bundle exec rspec spec/random_name_generator_spec.rb`
|
|
123
|
+
|
|
124
|
+
If names look broken or monotonous, iterate on the `.txt` (more variety, better
|
|
125
|
+
flags) and re-sample before finishing.
|
|
126
|
+
|
|
127
|
+
### 7. Hand off the commit
|
|
128
|
+
|
|
129
|
+
Git is manual in this workflow. Do NOT run git yourself. Surface the exact
|
|
130
|
+
command for the user:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
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"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Guardrails
|
|
137
|
+
|
|
138
|
+
- Never overwrite an existing language file or constant without confirmation.
|
|
139
|
+
- Never run state-changing git commands — always suggest them.
|
|
140
|
+
- Keep bucket sizes and flag style consistent with existing `lib/languages/*.txt`.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -30,11 +30,26 @@ gem 'random_name_generator'
|
|
|
30
30
|
|
|
31
31
|
And then execute:
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
`$❯ bundle install`
|
|
34
34
|
|
|
35
35
|
Or install it yourself as:
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
`$❯ gem install random_name_generator`
|
|
38
|
+
|
|
39
|
+
`RandomNameGenerator` also comes with a command line interface which will
|
|
40
|
+
generate a first and last name for you:
|
|
41
|
+
|
|
42
|
+
```shell
|
|
43
|
+
$> exe/random_name_generator [-egrfcxß?]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
You can also install it so that it's instantly available to you:
|
|
47
|
+
|
|
48
|
+
```shell
|
|
49
|
+
$> bundle exec rake install
|
|
50
|
+
$> random_name_generator --german-curse
|
|
51
|
+
Dummkopfischpopelsepp Schnoddmistmann
|
|
52
|
+
```
|
|
38
53
|
|
|
39
54
|
## Usage
|
|
40
55
|
|
|
@@ -79,15 +94,14 @@ You can also pass in your own syllable files. See
|
|
|
79
94
|
[Syllable.rb](https://github.com/folkengine/random_name_generator/blob/master/lib/random_name_generator/syllable.rb)
|
|
80
95
|
for the required specification.
|
|
81
96
|
|
|
82
|
-
|
|
83
|
-
generate a first and last name for you:
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
bin/random_name_generator [-efgr?]
|
|
87
|
-
```
|
|
97
|
+
### Experimental languages
|
|
88
98
|
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
Edgier, less curated syllable sets live under `lib/languages/experimental/`
|
|
100
|
+
and are opt-in via their own constants:
|
|
101
|
+
[Curse](https://github.com/folkengine/random_name_generator/blob/master/lib/languages/experimental/curse.txt)
|
|
102
|
+
(`RandomNameGenerator::CURSE`) and
|
|
103
|
+
[German Curse](https://github.com/folkengine/random_name_generator/blob/master/lib/languages/experimental/german-curse.txt)
|
|
104
|
+
(`RandomNameGenerator::GERMAN_CURSE`).
|
|
91
105
|
|
|
92
106
|
## Porting and Refactoring Notes
|
|
93
107
|
|
|
@@ -98,7 +112,7 @@ syllable, greatly simplifying the Random Name Generator code.
|
|
|
98
112
|
Part of the reason for working on this gem was to work on the following
|
|
99
113
|
goals to improve my Ruby craft:
|
|
100
114
|
|
|
101
|
-
* Code confidently in the spirit of
|
|
115
|
+
* Code confidently in the spirit of Avdi Grimm's
|
|
102
116
|
[Confident Ruby](http://www.confidentruby.com/).
|
|
103
117
|
* ~~Use
|
|
104
118
|
[Travis-CI](https://travis-ci.org/folkengine/random_name_generator)
|
|
@@ -130,6 +144,44 @@ call `$❯ rake reek`
|
|
|
130
144
|
Bug reports and pull requests are welcome on GitHub at
|
|
131
145
|
https://github.com/folkengine/random_name_generator.
|
|
132
146
|
|
|
147
|
+
## Skills
|
|
148
|
+
|
|
149
|
+
This ships with a skill designed to work with [Claude Code](https://claude.com/claude-code)
|
|
150
|
+
and other LLMs under `.claude/skills/`.
|
|
151
|
+
|
|
152
|
+
- [lang-gen](.claude/skills/lang-gen/SKILL.md) — Generate a new random_name_generator language from a free-text theme (e.g. "german curse words") — assembles flagged pre/mid/sur syllable collections, registers the File constant, adds a smoke spec and README entry, and samples names to verify.
|
|
153
|
+
|
|
154
|
+
There is also [a text version](docs/superpowers/specs/2026-07-19-lang-gen-portable-prompt.md) of the prompt that can be pasted into an LLM.
|
|
155
|
+
|
|
156
|
+
### lang-gen
|
|
157
|
+
|
|
158
|
+
Adding a language by hand means writing a `.txt` of prefix/middle/suffix
|
|
159
|
+
syllables, wiring up a `File` constant, adding a spec, and documenting it.
|
|
160
|
+
`lang-gen` does the whole flow from a plain-English theme.
|
|
161
|
+
|
|
162
|
+
Invoke it from Claude Code with the theme as the argument:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
/lang-gen Klingon words of joy
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
This will:
|
|
169
|
+
|
|
170
|
+
1. Derive a **slug** (`klingon-joy`), **constant** (`KLINGON_JOY`), and
|
|
171
|
+
destination; edgy themes land in `lib/languages/experimental/`, tame
|
|
172
|
+
ones in `lib/languages/`; and confirm before writing.
|
|
173
|
+
2. Author the syllable file, seeding real roots for the theme and extending
|
|
174
|
+
each of the three buckets (prefix `-`, middle, suffix `+`) with same-flavor
|
|
175
|
+
syllables, adding `+v`/`+c`/`-v`/`-c` adjacency flags only where needed.
|
|
176
|
+
3. Register the `File` constant in `lib/random_name_generator.rb`.
|
|
177
|
+
4. Add a smoke spec to `spec/random_name_generator_spec.rb`.
|
|
178
|
+
5. Add a README entry linking the new language.
|
|
179
|
+
6. Verify that all three buckets are non-empty, then sample
|
|
180
|
+
composed names so you can eyeball the result.
|
|
181
|
+
|
|
182
|
+
The experimental [German Curse](lib/languages/experimental/german-curse.txt)
|
|
183
|
+
language was generated this way.
|
|
184
|
+
|
|
133
185
|
## License
|
|
134
186
|
|
|
135
187
|
The gem is available as open source under the terms of the
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# /lang-gen Skill Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Build a project-local `/lang-gen` skill that turns a free-text theme (e.g. "german curse words") into a fully integrated `random_name_generator` language.
|
|
6
|
+
|
|
7
|
+
**Architecture:** The deliverable is a single prose skill file, `.claude/skills/lang-gen/SKILL.md`, that instructs Claude through a fixed workflow: parse the theme → derive slug/constant/destination → author a flagged syllable `.txt` (hybrid seeded-then-extended method) → register the constant → add a smoke spec and README entry → verify by parse-check and by sampling composed names. The skill is registered in the project README. A final end-to-end task exercises the skill against "german curse words" to prove it works.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Markdown + YAML frontmatter (skill), Ruby 3.4+ / RSpec (the gem under test), the language-file DSL defined in `lib/random_name_generator/syllable.rb`.
|
|
10
|
+
|
|
11
|
+
## Global Constraints
|
|
12
|
+
|
|
13
|
+
- **Language-file DSL (verbatim from `syllable.rb`):** one syllable per line; leading `-` = prefix bucket, leading `+` = suffix bucket, no sign = middle bucket. Flags: `+v` next-must-start-vowel, `+c` next-must-start-consonant, `-v` this-follows-vowel-ending, `-c` this-follows-consonant-ending. Order of flags is not significant; separated by whitespace.
|
|
14
|
+
- **Bucket sizing:** ~20–40 syllables per bucket (pre / mid / sur), matching `lib/languages/goblin.txt`.
|
|
15
|
+
- **Edgy-theme routing:** curse/insult/swear/NSFW/drunk themes → `lib/languages/experimental/`; tame themes → `lib/languages/`.
|
|
16
|
+
- **Git is manual:** the assistant must NOT run any state-changing git command. Every "Commit" step below is a **suggested command surfaced to the user to run themselves**, never executed by the assistant. This applies inside the skill too.
|
|
17
|
+
- **No overwrite:** never clobber an existing language file or `File.new` constant without explicit user confirmation.
|
|
18
|
+
- **flip_mode arrays are hand-curated:** do NOT add generated languages to `flip_mode` / `flip_mode_cyrillic`.
|
|
19
|
+
- **README Skills rule (project convention):** when a skill is added, link it in `README.md` under `## Skills` using the skill's `name` as link text and its `description` as the blurb.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
### Task 1: Author the `/lang-gen` SKILL.md
|
|
24
|
+
|
|
25
|
+
**Files:**
|
|
26
|
+
- Create: `.claude/skills/lang-gen/SKILL.md`
|
|
27
|
+
|
|
28
|
+
**Interfaces:**
|
|
29
|
+
- Produces: a skill named `lang-gen`, invocable via `/lang-gen <theme>`, discoverable in the skills list. No code symbols.
|
|
30
|
+
|
|
31
|
+
- [ ] **Step 1: Create the skill file with frontmatter and full workflow**
|
|
32
|
+
|
|
33
|
+
Create `.claude/skills/lang-gen/SKILL.md` with exactly this content:
|
|
34
|
+
|
|
35
|
+
````markdown
|
|
36
|
+
---
|
|
37
|
+
name: lang-gen
|
|
38
|
+
description: Generate a new random_name_generator language from a free-text theme (e.g. "german curse words") — assembles flagged pre/mid/sur syllable collections, registers the File constant, adds a smoke spec and README entry, and samples names to verify. Use when the user types /lang-gen or asks to create, generate, or add a new language, dialect, or syllable file for the name generator.
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
# lang-gen
|
|
42
|
+
|
|
43
|
+
Turn a free-text theme into a fully integrated `random_name_generator`
|
|
44
|
+
language file. Invoked as `/lang-gen <theme>`, e.g. `/lang-gen german curse words`.
|
|
45
|
+
|
|
46
|
+
## The language-file DSL
|
|
47
|
+
|
|
48
|
+
Authoritative source: `lib/random_name_generator/syllable.rb`. Each line of a
|
|
49
|
+
language `.txt` is one syllable:
|
|
50
|
+
|
|
51
|
+
- Leading `-` → **prefix** (pre) bucket — a name beginning.
|
|
52
|
+
- Leading `+` → **suffix** (sur) bucket — a name ending.
|
|
53
|
+
- No sign → **middle** (mid) bucket — an interior fragment.
|
|
54
|
+
|
|
55
|
+
Optional whitespace-separated flags after the syllable constrain adjacency:
|
|
56
|
+
|
|
57
|
+
- `+v` — the NEXT syllable must start with a vowel.
|
|
58
|
+
- `+c` — the NEXT syllable must start with a consonant.
|
|
59
|
+
- `-v` — THIS syllable may only follow one ending in a vowel.
|
|
60
|
+
- `-c` — THIS syllable may only follow one ending in a consonant.
|
|
61
|
+
|
|
62
|
+
A name needs all three buckets non-empty. `Generator#compose` picks a prefix,
|
|
63
|
+
fills with middles, ends with a suffix, honoring the flags.
|
|
64
|
+
|
|
65
|
+
## Workflow
|
|
66
|
+
|
|
67
|
+
Follow these steps in order. Do not skip verification.
|
|
68
|
+
|
|
69
|
+
### 1. Parse the theme and derive names
|
|
70
|
+
|
|
71
|
+
From the argument string derive and then **show the user for confirmation**:
|
|
72
|
+
|
|
73
|
+
- **slug** — concise kebab-case, 1–2 meaningful words, drop filler ("words",
|
|
74
|
+
"generator", articles). `german curse words` → `german-curse`.
|
|
75
|
+
- **constant** — SCREAMING_SNAKE of the slug. `german-curse` → `GERMAN_CURSE`.
|
|
76
|
+
- **destination** — edgy themes (curse, insult, swear, NSFW, drunk, etc.) →
|
|
77
|
+
`lib/languages/experimental/<slug>.txt`; tame themes →
|
|
78
|
+
`lib/languages/<slug>.txt`.
|
|
79
|
+
|
|
80
|
+
Before writing anything, check for collisions: if the target `.txt` OR the
|
|
81
|
+
constant already exists, STOP and ask the user how to proceed. Never overwrite.
|
|
82
|
+
|
|
83
|
+
### 2. Author the syllable file (hybrid: seed, then extend)
|
|
84
|
+
|
|
85
|
+
1. Recall a handful of **real roots** for the theme. (German curses: `schei`,
|
|
86
|
+
`arsch`, `sau`, `verdammt`, `dreck`, `mist`, `depp`, `blöd`, …)
|
|
87
|
+
2. Slot fragments into buckets: prefixes (`-`) = natural beginnings, middles
|
|
88
|
+
(bare) = connective interiors, suffixes (`+`) = natural endings / intensifiers.
|
|
89
|
+
3. **Extend** each bucket with same-flavor **invented** syllables until each
|
|
90
|
+
holds ~20–40 entries (match `lib/languages/goblin.txt` scale).
|
|
91
|
+
4. Add `+v/+c/-v/-c` flags **only where they prevent awkward clusters** — e.g. a
|
|
92
|
+
consonant-final prefix that would collide, or a lone vowel that reads badly
|
|
93
|
+
after another vowel. Most lines carry no flag. Keep it judicious.
|
|
94
|
+
|
|
95
|
+
Write the file to the destination from step 1.
|
|
96
|
+
|
|
97
|
+
### 3. Register the constant
|
|
98
|
+
|
|
99
|
+
Edit `lib/random_name_generator.rb`. Add, next to the matching group of
|
|
100
|
+
constants (edgy → under the `# Experimental` comment; tame → with the curated
|
|
101
|
+
constants):
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
CONSTANT_NAME = File.new("#{dirname}/languages/<relative/path>.txt")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Do NOT touch `flip_mode` or `flip_mode_cyrillic` — those arrays are curated.
|
|
108
|
+
|
|
109
|
+
### 4. Add a smoke spec
|
|
110
|
+
|
|
111
|
+
Add an example to `spec/random_name_generator_spec.rb` following existing
|
|
112
|
+
conventions (see the `with languages` context). It must assert the constant is a
|
|
113
|
+
`File`, its `path` includes the expected filename, and that a `Generator` built
|
|
114
|
+
from it composes a non-empty `String`:
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
it "when it has a <Theme> language" do
|
|
118
|
+
expect(RandomNameGenerator::CONSTANT_NAME).to be_a(File)
|
|
119
|
+
expect(RandomNameGenerator::CONSTANT_NAME.path).to include("languages/<relative/path>.txt")
|
|
120
|
+
name = RandomNameGenerator::Generator.new(RandomNameGenerator::CONSTANT_NAME).compose
|
|
121
|
+
expect(name).to be_a(String)
|
|
122
|
+
expect(name).not_to be_empty
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 5. Add a README entry
|
|
127
|
+
|
|
128
|
+
Add the new language to `README.md`. Edgy/experimental languages go under a
|
|
129
|
+
short "Experimental languages" note; tame ones join the curated list. Link to
|
|
130
|
+
the file, matching how the curated four are listed.
|
|
131
|
+
|
|
132
|
+
### 6. Verify — parse-check then sample
|
|
133
|
+
|
|
134
|
+
- **Parse-check:** confirm every line is a valid syllable and all three buckets
|
|
135
|
+
are non-empty. Fastest via the gem:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
bundle exec ruby -Ilib -rrandom_name_generator -e '
|
|
139
|
+
g = RandomNameGenerator::Generator.new(RandomNameGenerator::CONSTANT_NAME)
|
|
140
|
+
abort "empty pre" if g.pre_syllables.empty?
|
|
141
|
+
abort "empty mid" if g.mid_syllables.empty?
|
|
142
|
+
abort "empty sur" if g.sur_syllables.empty?
|
|
143
|
+
puts "buckets OK: #{g.pre_syllables.size}/#{g.mid_syllables.size}/#{g.sur_syllables.size}"
|
|
144
|
+
'
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- **Sample:** print ~10 composed names for the user to eyeball:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
bundle exec ruby -Ilib -rrandom_name_generator -e '
|
|
151
|
+
g = RandomNameGenerator::Generator.new(RandomNameGenerator::CONSTANT_NAME)
|
|
152
|
+
10.times { puts g.compose }
|
|
153
|
+
'
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
- **Run the spec:** `bundle exec rspec spec/random_name_generator_spec.rb`
|
|
157
|
+
|
|
158
|
+
If names look broken or monotonous, iterate on the `.txt` (more variety, better
|
|
159
|
+
flags) and re-sample before finishing.
|
|
160
|
+
|
|
161
|
+
### 7. Hand off the commit
|
|
162
|
+
|
|
163
|
+
Git is manual. Do NOT run git yourself. Surface the exact command for the user:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
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"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Guardrails
|
|
170
|
+
|
|
171
|
+
- Never overwrite an existing language file or constant without confirmation.
|
|
172
|
+
- Never run state-changing git commands — always suggest them.
|
|
173
|
+
- Keep bucket sizes and flag style consistent with existing `lib/languages/*.txt`.
|
|
174
|
+
````
|
|
175
|
+
|
|
176
|
+
- [ ] **Step 2: Verify the skill file is structurally valid**
|
|
177
|
+
|
|
178
|
+
Run:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
head -5 .claude/skills/lang-gen/SKILL.md && echo "---" && grep -c '^### [1-7]\.' .claude/skills/lang-gen/SKILL.md
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Expected: the frontmatter shows `name: lang-gen` and the `description:` line; the grep prints `7` (all seven workflow steps present).
|
|
185
|
+
|
|
186
|
+
- [ ] **Step 3: Commit (suggest to user — do not run)**
|
|
187
|
+
|
|
188
|
+
Surface this command for the user:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
git add .claude/skills/lang-gen/SKILL.md && git commit -m "Add /lang-gen skill"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### Task 2: Register the skill in the project README
|
|
197
|
+
|
|
198
|
+
**Files:**
|
|
199
|
+
- Modify: `README.md`
|
|
200
|
+
|
|
201
|
+
**Interfaces:**
|
|
202
|
+
- Consumes: the `name` (`lang-gen`) and `description` authored in Task 1.
|
|
203
|
+
- Produces: a `## Skills` section linking the skill, satisfying the project's README rule.
|
|
204
|
+
|
|
205
|
+
- [ ] **Step 1: Add the Skills section**
|
|
206
|
+
|
|
207
|
+
Append a `## Skills` section to `README.md` (place it before the license footer). Use exactly:
|
|
208
|
+
|
|
209
|
+
```markdown
|
|
210
|
+
## Skills
|
|
211
|
+
|
|
212
|
+
- [lang-gen](.claude/skills/lang-gen/SKILL.md) — Generate a new random_name_generator language from a free-text theme (e.g. "german curse words") — assembles flagged pre/mid/sur syllable collections, registers the File constant, adds a smoke spec and README entry, and samples names to verify.
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- [ ] **Step 2: Verify the link and file line up**
|
|
216
|
+
|
|
217
|
+
Run:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
grep -n '^## Skills' README.md && test -f .claude/skills/lang-gen/SKILL.md && echo "target exists"
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Expected: prints the `## Skills` line number and `target exists`.
|
|
224
|
+
|
|
225
|
+
- [ ] **Step 3: Commit (suggest to user — do not run)**
|
|
226
|
+
|
|
227
|
+
Surface this command for the user:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
git add README.md && git commit -m "Register /lang-gen in README Skills section"
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
### Task 3: End-to-end validation — generate the `german-curse` language
|
|
236
|
+
|
|
237
|
+
This task runs the finished skill against the motivating example to prove the
|
|
238
|
+
whole workflow produces working output. It is the plan's integration test.
|
|
239
|
+
|
|
240
|
+
**Files (produced by running the skill):**
|
|
241
|
+
- Create: `lib/languages/experimental/german-curse.txt`
|
|
242
|
+
- Modify: `lib/random_name_generator.rb` (add `GERMAN_CURSE` constant under `# Experimental`)
|
|
243
|
+
- Modify: `spec/random_name_generator_spec.rb` (add German-curse smoke example)
|
|
244
|
+
- Modify: `README.md` (experimental-languages note)
|
|
245
|
+
|
|
246
|
+
**Interfaces:**
|
|
247
|
+
- Consumes: the `.claude/skills/lang-gen/SKILL.md` workflow from Task 1.
|
|
248
|
+
- Produces: `RandomNameGenerator::GERMAN_CURSE` — a `File` at `languages/experimental/german-curse.txt`, usable via `RandomNameGenerator::Generator.new(RandomNameGenerator::GERMAN_CURSE)`.
|
|
249
|
+
|
|
250
|
+
- [ ] **Step 1: Invoke the skill**
|
|
251
|
+
|
|
252
|
+
Run `/lang-gen german curse words` and follow the SKILL.md workflow. Confirm the
|
|
253
|
+
derived slug `german-curse`, constant `GERMAN_CURSE`, destination
|
|
254
|
+
`lib/languages/experimental/german-curse.txt`.
|
|
255
|
+
|
|
256
|
+
- [ ] **Step 2: Verify buckets parse and are non-empty**
|
|
257
|
+
|
|
258
|
+
Run:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
bundle exec ruby -Ilib -rrandom_name_generator -e '
|
|
262
|
+
g = RandomNameGenerator::Generator.new(RandomNameGenerator::GERMAN_CURSE)
|
|
263
|
+
abort "empty pre" if g.pre_syllables.empty?
|
|
264
|
+
abort "empty mid" if g.mid_syllables.empty?
|
|
265
|
+
abort "empty sur" if g.sur_syllables.empty?
|
|
266
|
+
puts "buckets OK: #{g.pre_syllables.size}/#{g.mid_syllables.size}/#{g.sur_syllables.size}"
|
|
267
|
+
'
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Expected: `buckets OK: N/N/N` with each N in roughly 20–40.
|
|
271
|
+
|
|
272
|
+
- [ ] **Step 3: Sample names**
|
|
273
|
+
|
|
274
|
+
Run:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
bundle exec ruby -Ilib -rrandom_name_generator -e '
|
|
278
|
+
g = RandomNameGenerator::Generator.new(RandomNameGenerator::GERMAN_CURSE)
|
|
279
|
+
10.times { puts g.compose }
|
|
280
|
+
'
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Expected: 10 varied, pronounceable, German-flavored strings. If monotonous or broken, iterate on the `.txt` and repeat.
|
|
284
|
+
|
|
285
|
+
- [ ] **Step 4: Run the full test suite**
|
|
286
|
+
|
|
287
|
+
Run: `bundle exec rspec`
|
|
288
|
+
|
|
289
|
+
Expected: all examples pass, including the new German-curse smoke example.
|
|
290
|
+
|
|
291
|
+
- [ ] **Step 5: Commit (suggest to user — do not run)**
|
|
292
|
+
|
|
293
|
+
Surface this command for the user:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
git add lib/languages/experimental/german-curse.txt lib/random_name_generator.rb spec/random_name_generator_spec.rb README.md && git commit -m "Add German curse language via /lang-gen"
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Self-Review
|
|
302
|
+
|
|
303
|
+
**Spec coverage:**
|
|
304
|
+
- Trigger & arg parsing → Task 1 §1. ✓
|
|
305
|
+
- Slug/constant/destination derivation + confirm → Task 1 §1. ✓
|
|
306
|
+
- Edgy-theme routing → Task 1 §1 + Global Constraints. ✓
|
|
307
|
+
- Collision guard / no overwrite → Task 1 §1 + Guardrails. ✓
|
|
308
|
+
- Hybrid seeded-then-extended generation → Task 1 §2. ✓
|
|
309
|
+
- ~20–40 per bucket + smart flags → Task 1 §2 + Global Constraints. ✓
|
|
310
|
+
- Constant registration, flip_mode untouched → Task 1 §3. ✓
|
|
311
|
+
- Smoke spec → Task 1 §4. ✓
|
|
312
|
+
- README language entry → Task 1 §5. ✓
|
|
313
|
+
- Verification: parse-check + sample → Task 1 §6, exercised in Task 3. ✓
|
|
314
|
+
- Git manual → Global Constraints + every commit step + Task 1 §7. ✓
|
|
315
|
+
- Skill location `.claude/skills/lang-gen/` → Task 1. ✓
|
|
316
|
+
- README `## Skills` registration → Task 2. ✓
|
|
317
|
+
|
|
318
|
+
**Placeholder scan:** No TBD/TODO; all code, commands, and skill body are literal. ✓
|
|
319
|
+
|
|
320
|
+
**Type consistency:** `GERMAN_CURSE`, `german-curse.txt`, `languages/experimental/german-curse.txt`, and the `pre_syllables`/`mid_syllables`/`sur_syllables` reader names (from `random_name_generator.rb`) are used consistently across Tasks 1 and 3. ✓
|
|
@@ -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.
|
data/exe/random_name_generator
CHANGED
|
@@ -14,6 +14,7 @@ opts = Slop.parse do |o|
|
|
|
14
14
|
o.bool "-f", "--flipmode", "Flip mode in effect"
|
|
15
15
|
o.bool "-c", "--cyrillic", "Use Cyrillic mode"
|
|
16
16
|
o.bool "-x", "--xrated", "Generate Curse words [NEEDS WORK]"
|
|
17
|
+
o.bool "-ß", "--german-curse", "Generate German Curse words [NEEDS WORK]"
|
|
17
18
|
o.bool "-?", "--help", "How to"
|
|
18
19
|
end
|
|
19
20
|
|
|
@@ -27,6 +28,7 @@ else
|
|
|
27
28
|
lang = RandomNameGenerator::GOBLIN if opts.goblin?
|
|
28
29
|
lang = RandomNameGenerator::ROMAN if opts.roman?
|
|
29
30
|
lang = RandomNameGenerator::CURSE if opts.xrated?
|
|
31
|
+
lang = RandomNameGenerator::GERMAN_CURSE if opts.german_curse?
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
if opts.flipmode?
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
-arsch
|
|
2
|
+
-arschge
|
|
3
|
+
-blöd
|
|
4
|
+
-blöd
|
|
5
|
+
-depp
|
|
6
|
+
-deppen
|
|
7
|
+
-donner
|
|
8
|
+
-dreck
|
|
9
|
+
-drecks
|
|
10
|
+
-dumm
|
|
11
|
+
-dummkopf +v
|
|
12
|
+
-dumpf
|
|
13
|
+
-fahr
|
|
14
|
+
-flatz
|
|
15
|
+
-grantz
|
|
16
|
+
-hack
|
|
17
|
+
-himmel
|
|
18
|
+
-huren
|
|
19
|
+
-kack
|
|
20
|
+
-krott
|
|
21
|
+
-lauch
|
|
22
|
+
-leck
|
|
23
|
+
-miss
|
|
24
|
+
-mist
|
|
25
|
+
-mistkerl +v
|
|
26
|
+
-murks
|
|
27
|
+
-mutter
|
|
28
|
+
-penner
|
|
29
|
+
-pfusch
|
|
30
|
+
-quatsch
|
|
31
|
+
-sakra
|
|
32
|
+
-sau
|
|
33
|
+
-saukerl
|
|
34
|
+
-schatten
|
|
35
|
+
-schei
|
|
36
|
+
-scheiben
|
|
37
|
+
-scheiß +v
|
|
38
|
+
-schleim
|
|
39
|
+
-schnodd
|
|
40
|
+
-teufel
|
|
41
|
+
-trottel
|
|
42
|
+
-verdammt
|
|
43
|
+
-verflucht +v
|
|
44
|
+
-weich
|
|
45
|
+
-wichs
|
|
46
|
+
-wichser +v
|
|
47
|
+
-zefix
|
|
48
|
+
-zottel
|
|
49
|
+
doof
|
|
50
|
+
dreck
|
|
51
|
+
el
|
|
52
|
+
en
|
|
53
|
+
er
|
|
54
|
+
fatzke
|
|
55
|
+
fick
|
|
56
|
+
fut
|
|
57
|
+
glotz
|
|
58
|
+
gnatz
|
|
59
|
+
haft
|
|
60
|
+
herr
|
|
61
|
+
hunz
|
|
62
|
+
ig
|
|
63
|
+
isch
|
|
64
|
+
ling
|
|
65
|
+
los
|
|
66
|
+
mann
|
|
67
|
+
mist
|
|
68
|
+
mursch
|
|
69
|
+
nis
|
|
70
|
+
nutte
|
|
71
|
+
popel
|
|
72
|
+
quark
|
|
73
|
+
rotz
|
|
74
|
+
sau
|
|
75
|
+
schmodd
|
|
76
|
+
schrott -c
|
|
77
|
+
tum
|
|
78
|
+
ung
|
|
79
|
+
voll
|
|
80
|
+
wix -c
|
|
81
|
+
+aff
|
|
82
|
+
+angeber
|
|
83
|
+
+arsch
|
|
84
|
+
+backe
|
|
85
|
+
+bengel
|
|
86
|
+
+birne
|
|
87
|
+
+bock
|
|
88
|
+
+ei
|
|
89
|
+
+esel
|
|
90
|
+
+ficker
|
|
91
|
+
+flasche
|
|
92
|
+
+fotze
|
|
93
|
+
+fresse
|
|
94
|
+
+fut
|
|
95
|
+
+geburt
|
|
96
|
+
+geige
|
|
97
|
+
+gesicht
|
|
98
|
+
+gott
|
|
99
|
+
+hammel
|
|
100
|
+
+heini
|
|
101
|
+
+hirn
|
|
102
|
+
+hölle
|
|
103
|
+
+hund
|
|
104
|
+
+idiot
|
|
105
|
+
+kacke
|
|
106
|
+
+kerl
|
|
107
|
+
+kleister
|
|
108
|
+
+kopf -c
|
|
109
|
+
+kriecher
|
|
110
|
+
+lappen
|
|
111
|
+
+lecker
|
|
112
|
+
+ling
|
|
113
|
+
+loch -c
|
|
114
|
+
+made
|
|
115
|
+
+mann
|
|
116
|
+
+maul
|
|
117
|
+
+nase
|
|
118
|
+
+ochse
|
|
119
|
+
+parker
|
|
120
|
+
+pfosten
|
|
121
|
+
+ratte -v
|
|
122
|
+
+sack
|
|
123
|
+
+sau
|
|
124
|
+
+schädel
|
|
125
|
+
+scheiße
|
|
126
|
+
+scheißer
|
|
127
|
+
+schlampe
|
|
128
|
+
+schwein
|
|
129
|
+
+sepp
|
|
130
|
+
+sohn
|
|
131
|
+
+stück
|
|
132
|
+
+teufel
|
|
133
|
+
+tüte
|
|
134
|
+
+visage
|
|
135
|
+
+wetter
|
|
136
|
+
+wicht
|
|
137
|
+
+wurm
|
|
138
|
+
+ziege
|
|
139
|
+
+zwerg
|
|
@@ -33,6 +33,7 @@ module RandomNameGenerator
|
|
|
33
33
|
|
|
34
34
|
# Experimental
|
|
35
35
|
CURSE = File.new("#{dirname}/languages/experimental/curse.txt")
|
|
36
|
+
GERMAN_CURSE = File.new("#{dirname}/languages/experimental/german-curse.txt")
|
|
36
37
|
|
|
37
38
|
# Static factory method that instantiates a RandomNameGenerator in a random language.
|
|
38
39
|
def self.flip_mode
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: random_name_generator
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.0.
|
|
4
|
+
version: 4.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- folkengine
|
|
@@ -19,6 +19,7 @@ executables:
|
|
|
19
19
|
extensions: []
|
|
20
20
|
extra_rdoc_files: []
|
|
21
21
|
files:
|
|
22
|
+
- ".claude/skills/lang-gen/SKILL.md"
|
|
22
23
|
- ".codeclimate.yml"
|
|
23
24
|
- ".devcontainer/Dockerfile"
|
|
24
25
|
- ".devcontainer/devcontainer.json"
|
|
@@ -38,12 +39,16 @@ files:
|
|
|
38
39
|
- bin/run
|
|
39
40
|
- bin/setup
|
|
40
41
|
- config.reek
|
|
42
|
+
- docs/superpowers/plans/2026-07-18-lang-gen-skill.md
|
|
43
|
+
- docs/superpowers/specs/2026-07-18-lang-gen-skill-design.md
|
|
44
|
+
- docs/superpowers/specs/2026-07-19-lang-gen-portable-prompt.md
|
|
41
45
|
- exe/random_name_generator
|
|
42
46
|
- lib/languages/demonic.txt
|
|
43
47
|
- lib/languages/elven-ru.txt
|
|
44
48
|
- lib/languages/elven.txt
|
|
45
49
|
- lib/languages/experimental/curse.txt
|
|
46
50
|
- lib/languages/experimental/demonic.txt
|
|
51
|
+
- lib/languages/experimental/german-curse.txt
|
|
47
52
|
- lib/languages/fantasy-ru.txt
|
|
48
53
|
- lib/languages/fantasy.txt
|
|
49
54
|
- lib/languages/goblin-ru.txt
|