"""muse domain — hash-derived domain index tooling. Every Muse domain integer is computed from its canonical name string via:: index = int.from_bytes(sha256(name.encode("utf-8"))[:4], "big") & 0x7FFFFFFF This makes the domain namespace open and decentralised: any third-party domain derives its index without a central registry. The registry (``gabriel/muse-domains`` on MuseHub) is a human-readable annotation layer — it does not gate key derivation. Subcommands:: muse domain index Compute the index for any domain name. muse domain lookup Look up a name in the local registry. muse domain lookup --index Reverse-lookup an integer to a name. muse domain list List all locally registered domains. muse domain check Exit 0 if registered, 1 if not. Registry location ----------------- The registry is read from, in order: 1. ``$MUSE_DOMAIN_REGISTRY`` env var (path to a ``registry.json`` file). 2. ``~/.muse/domain-registry.json`` (cached copy from the hub). 3. The built-in seed registry shipped with this muse release. For air-gapped use, copy ``registry.json`` from ``gabriel/muse-domains`` and set ``MUSE_DOMAIN_REGISTRY`` to point at it. JSON schemas ------------ ``muse domain index --json``:: { "name": "muse/music", "index": 1755707987, "registered": true, "entry": { "description": "...", "owner": "gabriel", ... } } ``muse domain list --json``:: { "domains": [ { "name": "muse/identity", "index": 1660078172, ... }, ... ], "total": 8 } ``muse domain check --json``:: { "name": "acme/gaming", "registered": false } """ import argparse import json import logging import os import pathlib import sys from typing import TypedDict from muse.core.envelope import EnvelopeJson, make_envelope from muse.core.errors import ExitCode from muse.core.hdkeys import domain_index from muse.core.paths import user_domain_registry_path from muse.core.timing import start_timer from muse.core.types import load_json_file logger = logging.getLogger(__name__) class _DomainEntry(TypedDict, total=False): name: str index: int description: str owner: str registered_at: str | None # --------------------------------------------------------------------------- # Seed registry — shipped with the muse binary for offline use. # Authoritative source: gabriel/muse-domains on MuseHub. # --------------------------------------------------------------------------- _SEED_REGISTRY: list[_DomainEntry] = [ { "name": "muse/identity", "index": 1660078172, "description": "Cross-domain authentication. MSign HTTP signing, MuseHub registration, the passport key for any identity on the network.", "owner": "gabriel", "registered_at": None, }, { "name": "muse/payments", "index": 284229149, "description": "MPay claims and financial settlement.", "owner": "gabriel", "registered_at": None, }, { "name": "muse/code", "index": 678195575, "description": "Software version control. Commit provenance, code-review attestations, symbol-level semantic diffs.", "owner": "gabriel", "registered_at": None, }, { "name": "muse/music", "index": 1755707987, "description": "Stori audio production. Project signing, master ownership, stem provenance.", "owner": "gabriel", "registered_at": None, }, { "name": "muse/midi", "index": 1444628350, "description": "Maestro symbolic music. NL-to-MIDI content signing, score provenance.", "owner": "gabriel", "registered_at": None, }, { "name": "muse/blockchain", "index": 1556829714, "description": "On-chain operations. ERC-8004 identity, ERC-721 masters, ERC-1155 marketplace, AVAX settlement. secp256k1 keys via Bitcoin seed HMAC root.", "owner": "gabriel", "registered_at": None, }, { "name": "muse/generic", "index": 2023564266, "description": "Repos and entities with no registered domain plugin. First-class explicit value — never an empty string or None.", "owner": "gabriel", "registered_at": None, }, ] def _load_registry() -> list[_DomainEntry]: """Return the domain registry, preferring local overrides over the seed.""" paths = [ os.environ.get("MUSE_DOMAIN_REGISTRY", ""), str(user_domain_registry_path()), ] for p in paths: if p: data = load_json_file(pathlib.Path(p)) if isinstance(data, dict): return list(data.get("domains", [])) return _SEED_REGISTRY def _lookup_by_name(registry: list[_DomainEntry], name: str) -> _DomainEntry | None: for entry in registry: if entry.get("name") == name: return entry return None def _lookup_by_index(registry: list[_DomainEntry], idx: int) -> _DomainEntry | None: for entry in registry: if entry.get("index") == idx: return entry return None # --------------------------------------------------------------------------- # Subcommand: index # --------------------------------------------------------------------------- def _run_index(args: argparse.Namespace) -> None: elapsed = start_timer() name: str = args.name idx = domain_index(name) registry = _load_registry() entry = _lookup_by_name(registry, name) registered = entry is not None if args.json_out: out = { **make_envelope(elapsed), "name": name, "index": idx, "registered": registered, } if entry is not None: out["entry"] = entry print(json.dumps(out)) else: print(f"name: {name}") print(f"index: {idx}") print(f"registered: {registered}") if entry: print(f"owner: {entry.get('owner', '')}") print(f"desc: {entry.get('description', '')}") # --------------------------------------------------------------------------- # Subcommand: lookup # --------------------------------------------------------------------------- def _run_lookup(args: argparse.Namespace) -> None: elapsed = start_timer() registry = _load_registry() if args.index is not None: entry = _lookup_by_index(registry, args.index) if entry is None: msg = {"error": f"No domain registered with index {args.index}"} print(json.dumps(msg), file=sys.stderr) raise SystemExit(ExitCode.USER_ERROR) idx = args.index name = entry["name"] else: if not args.name: print(json.dumps({"error": "Provide or --index"}), file=sys.stderr) raise SystemExit(ExitCode.USER_ERROR) name = args.name idx = domain_index(name) entry = _lookup_by_name(registry, name) if entry is None: msg = {"error": f"Domain '{name}' not found in registry"} print(json.dumps(msg), file=sys.stderr) raise SystemExit(ExitCode.USER_ERROR) if args.json_out: print(json.dumps({**make_envelope(elapsed), **entry, "index": idx})) else: print(f"name: {name}") print(f"index: {idx}") print(f"owner: {entry.get('owner', '')}") print(f"desc: {entry.get('description', '')}") if entry.get("registered_at"): print(f"registered: {entry['registered_at']}") # --------------------------------------------------------------------------- # Subcommand: list # --------------------------------------------------------------------------- def _run_list(args: argparse.Namespace) -> None: elapsed = start_timer() registry = _load_registry() if args.json_out: print(json.dumps({ **make_envelope(elapsed), "domains": registry, "total": len(registry), })) else: for entry in registry: print(f"{entry['name']:30s} {entry['index']}") # --------------------------------------------------------------------------- # Subcommand: check # --------------------------------------------------------------------------- def _run_check(args: argparse.Namespace) -> None: elapsed = start_timer() name: str = args.name registry = _load_registry() entry = _lookup_by_name(registry, name) registered = entry is not None if args.json_out: print(json.dumps({**make_envelope(elapsed), "name": name, "registered": registered})) else: status = "registered" if registered else "not registered" print(f"{name}: {status}") if not registered: raise SystemExit(1) # --------------------------------------------------------------------------- # Registration # --------------------------------------------------------------------------- def register(subparsers: "argparse._SubParsersAction[argparse.ArgumentParser]") -> None: """Register the ``muse domain`` namespace.""" parser = subparsers.add_parser( "domain", help="Hash-derived domain index tooling — compute, lookup, list, check.", description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, ) domain_subs = parser.add_subparsers(dest="domain_subcmd", metavar="SUBCMD") domain_subs.required = True # ── index ────────────────────────────────────────────────────────── p_index = domain_subs.add_parser( "index", help="Compute the hash-derived index for a domain name.", ) p_index.add_argument("name", help="Canonical domain name, e.g. 'muse/music'.") p_index.add_argument("--json", "-j", action="store_true", dest="json_out") p_index.set_defaults(func=_run_index) # ── lookup ───────────────────────────────────────────────────────── p_lookup = domain_subs.add_parser( "lookup", help="Look up a domain name (or --index integer) in the registry.", ) p_lookup.add_argument("name", nargs="?", default=None, help="Canonical domain name to look up.") p_lookup.add_argument("--index", type=int, default=None, help="Reverse-lookup: find the name for this integer index.") p_lookup.add_argument("--json", "-j", action="store_true", dest="json_out") p_lookup.set_defaults(func=_run_lookup) # ── list ─────────────────────────────────────────────────────────── p_list = domain_subs.add_parser( "list", help="List all locally registered domains.", ) p_list.add_argument("--json", "-j", action="store_true", dest="json_out") p_list.set_defaults(func=_run_list) # ── check ────────────────────────────────────────────────────────── p_check = domain_subs.add_parser( "check", help="Exit 0 if the name is registered, 1 if not.", ) p_check.add_argument("name", help="Canonical domain name to check.") p_check.add_argument("--json", "-j", action="store_true", dest="json_out") p_check.set_defaults(func=_run_check)