fix(cli): replace hardcoded VALID_DOMAINS with live /domains/ API lookup

The custodian CLI had a static VALID_DOMAINS list used as argparse
choices= and for in-process domain validation, preventing any domain
added after v0.5 from being used. Now fetches active domains from the
API at runtime. Also fixes t.get("domain") → t.get("domain_slug")
in two topic lookup sites.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 15:39:34 +01:00
parent b6ec7c2ecb
commit 6730720ce4

View File

@@ -26,12 +26,6 @@ API_BASE = os.environ.get("API_BASE", "http://127.0.0.1:8000")
TEMPLATE = STATE_HUB_DIR / "scripts" / "project_claude_md.template"
PATCH_CWD = STATE_HUB_DIR / "scripts" / "patch_mcp_cwd.py"
VALID_DOMAINS = [
"custodian", "railiance", "markitect",
"coulomb_social", "personhood", "foerster_capabilities",
]
# ── Helpers ────────────────────────────────────────────────────────────────────
def _api_get(path: str) -> object:
@@ -88,6 +82,7 @@ def cmd_register(args: argparse.Namespace) -> None:
# ── Step 2: Domain ─────────────────────────────────────────────────────────
domain = args.domain
valid_domains = [d["slug"] for d in _api_get("/domains/?status=active")]
if not domain:
print("==> Auto-detecting domain from project charter ...")
domain = _detect_domain(project_path)
@@ -95,17 +90,17 @@ def cmd_register(args: argparse.Namespace) -> None:
print(f" Detected: {domain}")
else:
print(f"ERROR: Could not auto-detect domain. Pass --domain explicitly.")
print(f" Valid: {', '.join(VALID_DOMAINS)}")
print(f" Valid: {', '.join(valid_domains)}")
sys.exit(1)
if domain not in VALID_DOMAINS:
print(f"ERROR: Unknown domain '{domain}'. Valid: {', '.join(VALID_DOMAINS)}")
if domain not in valid_domains:
print(f"ERROR: Unknown domain '{domain}'. Valid: {', '.join(valid_domains)}")
sys.exit(1)
# ── Step 3: Topic ID lookup ────────────────────────────────────────────────
print(f"==> Looking up topic for domain '{domain}' ...")
topics = _api_get("/topics/?status=active")
match = next((t for t in topics if t.get("domain") == domain), None)
match = next((t for t in topics if t.get("domain_slug") == domain), None)
if not match:
print(f"ERROR: No active topic found for domain '{domain}'.")
sys.exit(1)
@@ -167,7 +162,7 @@ def cmd_create_workstream(args: argparse.Namespace) -> None:
# Resolve topic_id from domain
topics = _api_get("/topics/?status=active")
match = next((t for t in topics if t.get("domain") == args.domain), None)
match = next((t for t in topics if t.get("domain_slug") == args.domain), None)
if not match:
print(f"ERROR: No active topic for domain '{args.domain}'.")
sys.exit(1)
@@ -274,9 +269,8 @@ def main() -> None:
reg = sub.add_parser("register-project", help="Register a project with the State Hub")
reg.add_argument(
"--domain",
choices=VALID_DOMAINS,
default=None,
help="Project domain (auto-detected from charter if omitted)",
help="Project domain slug (auto-detected from charter if omitted)",
)
reg.add_argument(
"--path",
@@ -286,7 +280,7 @@ def main() -> None:
# create-workstream
cws = sub.add_parser("create-workstream", help="Create a workstream under a domain topic")
cws.add_argument("--domain", choices=VALID_DOMAINS, required=True, help="Domain to create the workstream under")
cws.add_argument("--domain", required=True, help="Domain slug to create the workstream under")
cws.add_argument("--title", required=True, help="Workstream title")
cws.add_argument("--slug", default=None, help="URL slug (auto-generated from title if omitted)")
cws.add_argument("--owner", default=None, help="Owner name")