package main import ( "fmt" "strings" ) // canonicalDomains lists registry domains accepted by fn_create_function. // Keep in sync with `mcp__registry__fn_list_domains` and `.claude/rules/ids_naming.md`. var canonicalDomains = map[string]bool{ "browser": true, "core": true, "cybersecurity": true, "datascience": true, "docker": true, "finance": true, "gamedev": true, "geo": true, "gfx": true, "infra": true, "metabase": true, "ml": true, "notebook": true, "pipelines": true, "shell": true, "tui": true, "ui": true, "viz": true, } // actionVerbs is the allowlist of verbs that make a function name predictable. // See .claude/rules/ids_naming.md. Add new recurring verbs here when introduced. var actionVerbs = map[string]bool{} // acronymExceptions are nouns accepted as standalone names because the registry // has historical precedent (math/stats indicators). var acronymExceptions = map[string]bool{ "sma": true, "ema": true, "rsi": true, "vwap": true, "adx": true, "macd": true, "atr": true, "obv": true, "bollinger": true, } func init() { for _, v := range []string{ "get", "set", "list", "find", "search", "show", "read", "load", "fetch", "scan", "query", "lookup", "parse", "format", "encode", "decode", "marshal", "unmarshal", "serialize", "deserialize", "validate", "check", "ensure", "verify", "audit", "diagnose", "test", "match", "filter", "map", "reduce", "sort", "group", "count", "sum", "aggregate", "compute", "calculate", "score", "rank", "cluster", "classify", "detect", "init", "create", "make", "build", "generate", "scaffold", "install", "setup", "configure", "register", "add", "insert", "append", "prepend", "update", "upsert", "modify", "edit", "patch", "replace", "delete", "remove", "clear", "drop", "prune", "clean", "copy", "move", "rename", "sync", "clone", "extract", "inject", "import", "export", "send", "post", "put", "call", "dispatch", "exec", "run", "launch", "start", "stop", "kill", "restart", "redeploy", "deploy", "open", "close", "connect", "disconnect", "login", "logout", "authenticate", "enable", "disable", "toggle", "lock", "unlock", "propose", "promote", "deprecate", "approve", "reject", "apply", "emit", "render", "draw", "paint", "serve", "host", "pull", "push", "checkout", "commit", "tag", "merge", "rebase", "watch", "monitor", "observe", "log", "trace", "profile", "benchmark", "snapshot", "backup", "restore", "archive", "compress", "decompress", "hash", "encrypt", "decrypt", "sign", "taskkill", "recopile", "recopilate", "vault", "gather", "collect", "fold", "head", "tail", "take", "chunk", "batch", "debounce", "throttle", "retry", "await", "sleep", "ping", "prime", "warm", "refresh", "invalidate", "reload", "reset", "rollback", "fork", "spawn", "daemon", "plot", "capture", "replay", "slice", "window", "split", "join", "concat", "flatten", "unflatten", "transpose", "reverse", "shuffle", "sample", "dedup", "distinct", "unique", "audit", "verify", "lint", "format", "tally", "bucket", "histogram", } { actionVerbs[v] = true } } // validateName checks that name is predictable per ids_naming.md: // - snake_case // - contains an action verb token, or is a recognized acronym // Components (kind=component) skip the verb check. func validateName(name, kind string) error { if name == "" { return fmt.Errorf("name is empty") } if !isSnakeCase(name) { return fmt.Errorf("name must be snake_case (lowercase + digits + underscores), got %q", name) } if kind == "component" || kind == "type" { return nil } tokens := strings.Split(name, "_") for _, t := range tokens { if actionVerbs[t] { return nil } } // single-token acronym exception if len(tokens) == 1 && acronymExceptions[tokens[0]] { return nil } return fmt.Errorf( "naming: name %q lacks action verb. Add a verb token (get_X, X_lookup, parse_X, ...). See .claude/rules/ids_naming.md", name, ) } // validateDomain checks that domain is in the canonical list. func validateDomain(domain string) error { if domain == "" { return fmt.Errorf("domain is empty") } if !canonicalDomains[domain] { return fmt.Errorf( "naming: domain %q not in canonical list. Allowed: browser, core, cybersecurity, datascience, docker, finance, gamedev, geo, gfx, infra, metabase, ml, notebook, pipelines, shell, tui, ui, viz. Add new domain to CLAUDE.md + apps/registry_mcp/naming.go first.", domain, ) } return nil }