diff --git a/docs/config.md b/docs/config.md index 10b7786..15b45af 100644 --- a/docs/config.md +++ b/docs/config.md @@ -117,7 +117,7 @@ | `HIVE_URL` | str | `""` | Hive registry address (e.g. `http://192.168.1.168:8087`). Empty = standalone navi, no announcements. | | `ANNOUNCE_INTERVAL_SEC` | int | `120` | How often this navi re-announces itself to the hive. | | `SWARM_KEY_FILE` | str | `.swarm-key` | Shared PSK file (gitignored, 0600, generated by `deploy/install.sh`). | -| `INSTANCE_FILE` | str | `instance.json` | This navi's identity for the swarm: generated name (adjective-animal) + instance id. Rename = edit the file, restart. | +| `INSTANCE_FILE` | str | `instance.json` | This navi's identity for the swarm: generated name (two female names from Japanese/American/Spanish pools) + instance id. Rename = edit the file, restart. | | `PEER_ASK_PROFILE` | str | `server_admin` | Which profile answers incoming `/peer/ask` questions (one-shot agent run). | | `PEER_ASK_TIMEOUT_SEC` | int | `120` | Hard ceiling for a single peer ask — the LLM turn inside `/peer/ask`. | diff --git a/navi/identity.py b/navi/identity.py index d21e7fb..bc38b48 100644 --- a/navi/identity.py +++ b/navi/identity.py @@ -1,10 +1,11 @@ """Instance identity — a stable, human-friendly name for this Navi install. Every deployed Navi carries ``instance.json`` in its working directory -(gitignored): ``{"name": "quiet-otter", "instance_id": "", "created_at": "..."}``. -The name is generated once (adjective + animal — readable, speakable, collision- -free at household-network scale) and is meant to be renamed by hand if the owner -wants. The instance_id is the technical identity for audit and peer pinning. +(gitignored): ``{"name": "yuki-grace", "instance_id": "", "created_at": "..."}``. +The name is generated once (two female names from different cultures — +Japanese, American, Spanish; readable, speakable, collision-free at swarm +scale: 50×50×3 picks) and is meant to be renamed by hand if the owner wants. +The instance_id is the technical identity for audit and peer pinning. Rename = edit the file, restart the server. Nothing else reads the name as long-lived state, so this is safe. @@ -18,26 +19,39 @@ from datetime import datetime, timezone from pathlib import Path -_ADJECTIVES = [ - "quiet", "amber", "hollow", "silver", "brisk", "cobalt", "dawn", "ember", - "frost", "gentle", "harbor", "ivory", "jasper", "keen", "lucid", "mellow", - "nimble", "opal", "pale", "quartz", "rapid", "soft", "tidal", "umber", - "velvet", "wan", "crimson", "golden", "misty", "noble", "olive", "plum", - "royal", "slate", "topaz", "vivid", "wild", "yellow", "zesty", "bold", - "calm", "deep", "eager", "flint", "gray", "hasty", "iron", "jolly", - "kind", "lunar", +_JAPANESE = [ + "yuki", "sakura", "hana", "aki", "miku", "rin", "mei", "yui", "sana", + "nao", "kaori", "mika", "rika", "emi", "haruka", "asuka", "rei", "airi", + "kana", "honoka", "mitsuki", "natsumi", "sayuri", "suzume", "tamaki", + "tomoe", "ayame", "chiyo", "fumiko", "himari", "kaede", "kanna", "mai", + "mariko", "midori", "momoka", "natsuki", "noriko", "riko", "saori", + "shiori", "suzuka", "tsukiko", "umeko", "yoshiko", "yuzuki", "kirie", + "jun", "motoko", "satchiko", ] -_ANIMALS = [ - "otter", "falcon", "heron", "moth", "badger", "cormorant", "dingo", "elk", - "fox", "grouse", "hare", "ibex", "jackal", "koi", "lynx", "marten", - "newt", "osprey", "puffin", "quail", "raven", "stoat", "tapir", "urchin", - "vole", "wren", "yak", "zephyr", "beagle", "caribou", "dolphin", "ermine", - "ferret", "gecko", "haddock", "ibis", "jaguar", "kestrel", "lemur", "mink", - "narwhal", "ocelot", "penguin", "quokka", "robin", "seal", "thrush", - "umbra", "vicuna", "wallaby", +_AMERICAN = [ + "emma", "olivia", "ava", "mia", "chloe", "grace", "lily", "hannah", + "nora", "ruby", "alice", "clara", "daisy", "hazel", "iris", "jade", + "june", "leah", "lucy", "pearl", "rose", "sage", "stella", "violet", + "willa", "zoe", "amber", "brooke", "faith", "harmony", "josephine", + "katherine", "lydia", "madeline", "natalie", "paige", "riley", "scarlett", + "tessa", "trinity", "vivian", "abigail", "bethany", "delilah", "everly", + "jenna", "leona", "melody", "serenity", "tiffany", ] +_SPANISH = [ + "sofia", "lucia", "valentina", "camila", "daniela", "carmen", "elena", + "gabriela", "ines", "lola", "marisol", "paulina", "raquel", "rosalia", + "serena", "teresa", "ximena", "alba", "bonita", "carlota", "esperanza", + "juanita", "mirta", "noelia", "paloma", "rosita", "adela", "belen", + "candela", "dolores", "estrella", "flor", "guadalupe", "jimena", "laura", + "miriam", "pilar", "rocio", "veronica", "yolanda", "catalina", "dalia", + "emilia", "fernanda", "gisela", "nayeli", "renata", "salma", "ursula", + "vanesa", +] + +_NAME_POOLS = [_JAPANESE, _AMERICAN, _SPANISH] + IDENTITY_FILE = "instance.json" @@ -49,10 +63,16 @@ def generate_name() -> str: - """Random adjective-animal pair, e.g. ``quiet-otter``.""" + """Two female names from different cultures, e.g. ``yuki-grace``. + + Single names would collide across a swarm (the peer channel addresses + machines by name); a mixed pair gives 7500×2 ordered combinations while + still reading as a pretty hyphenated female name. + """ import secrets - return f"{secrets.choice(_ADJECTIVES)}-{secrets.choice(_ANIMALS)}" + pools = secrets.SystemRandom().sample(_NAME_POOLS, 2) + return f"{secrets.choice(pools[0])}-{secrets.choice(pools[1])}" def load_identity(path: str | Path = IDENTITY_FILE) -> InstanceIdentity: diff --git a/navi/tools/peer.py b/navi/tools/peer.py index d934c87..5b1c7df 100644 --- a/navi/tools/peer.py +++ b/navi/tools/peer.py @@ -60,7 +60,7 @@ "· ask — ask a peer a question; its agent investigates " "on ITS machine and returns a text answer. Use for anything this peer " "can check better than you: its services, files, hardware, local state.\n\n" - "Address the peer by its swarm name (e.g. 'quiet-otter'). " + "Address the peer by its swarm name (e.g. 'yuki-grace'). " "Answers can take up to a couple of minutes - the peer runs a real agent " "turn. Do not ask peers about this machine's state; check it locally." ) diff --git a/tests/unit/test_identity.py b/tests/unit/test_identity.py index 9959afe..9072c7f 100644 --- a/tests/unit/test_identity.py +++ b/tests/unit/test_identity.py @@ -11,14 +11,37 @@ load_identity, ) +_ALL_NAMES = { + n + for pool in ( # from navi/identity.py + "yuki sakura hana aki miku rin mei yui sana nao kaori mika rika emi " + "haruka asuka rei airi kana honoka mitsuki natsumi sayuri suzume " + "tamaki tomoe ayame chiyo fumiko himari kaede kanna mai mariko " + "midori momoka natsuki noriko riko saori shiori suzuka tsukiko umeko " + "yoshiko yuzuki kirie jun motoko satchiko", + "emma olivia ava mia chloe grace lily hannah nora ruby alice clara " + "daisy hazel iris jade june leah lucy pearl rose sage stella violet " + "willa zoe amber brooke faith harmony josephine katherine lydia " + "madeline natalie paige riley scarlett tessa trinity vivian abigail " + "bethany delilah everly jenna leona melody serenity tiffany", + "sofia lucia valentina camila daniela carmen elena gabriela ines " + "lola marisol paulina raquel rosalia serena teresa ximena alba " + "bonita carlota esperanza juanita mirta noelia paloma rosita adela " + "belen candela dolores estrella flor guadalupe jimena laura miriam " + "pilar rocio veronica yolanda catalina dalia emilia fernanda gisela " + "nayeli renata salma ursula vanesa", + ) + for n in pool.split() +} -def test_generated_name_is_adjective_animal(): + +def test_generated_name_is_two_female_names(): for _ in range(50): name = generate_name() - assert "-" in name - adj, animal = name.split("-", 1) - assert adj.isalpha() and animal.isalpha() - assert adj == adj.lower() + first, second = name.split("-") + assert first in _ALL_NAMES + assert second in _ALL_NAMES + assert first != second def test_generated_names_vary():