@sema-agent/registry-core
v0.10.21
Published
Sema Registry core — pure config contract (zod domains + effective-config + roster resolution + ref-integrity + remoteExec) shared by sema-registry, sema-server, and the TOC desktop/CLI. One source of truth. (Formerly @sema-ai/registry-core; old name rema
Maintainers
Readme
@sema-agent/registry-core
Engine-agnostic, zero-dependency contract layer for the sema stack — one source of truth for the
config domain across the center (sema-registry, the fleet admin), the server (the workers), and the
client (desktop/CLI) seams. No two copies of the schema.
- Source of truth:
github.com/sema-agent/sema-registry-core, branchmain(private org repo). - npm: published as
@sema-agent/registry-coreon the public npm registry.
The package is pure: zero next/react/server imports, zero DB drivers. Its only runtime dependency is
zod (a dependency pinned ^3.24.0 — the same range the host repos sema-registry/sema-server/CLI use, so
package managers dedup to a single shared zod instance, keeping cross-instance schema validation / instanceof
sound). npm ls --prod therefore shows only zod. Node built-ins only (node:crypto, node:fs).
What's in it
- The zod contract (
types.ts):DOMAIN_SCHEMAS(15 domains — 0.10.0 addsprojects, the project identity ledger),EffectiveConfig,EffectiveWire,ENV_NAME/K8S_QUANTITYboundaries, every domain's entry/config type. - Pure config fns (
config-fns.ts):buildEffective(deterministic —updatedAtis a required param),parseDomain,emptyEffective(epoch-seeded),statusRowsToPrune, role helpers (roleAtLeast,domainWriteRole, …),resolveActiveTiers(0.9.0 档位组→引擎RunnerDeps.tiers组存models.tierGroups+models.activeTierGroup,组切换=换表下发), and the pure data shapes (User,PublishedSnapshot, …). - Roster resolution (
resolve-roster.ts):resolveEffectiveForWorker→ the per-worker wire payload. - Ref integrity (
cross-domain.ts):refIntegrityIssues+siblingResolver(the pure half — fleet auto-placement stays in sema-registry). - Hashing (
hash.ts):stableHash(FNV-1a 64) for ETags / version detection. - Skills manifest (
skills-manifest.ts): content-addressing for the lazy-pull skill bodies. - Secret inventory (
secret-refs.ts):collectEnvRefs— every referenced env-NAME. - The narrow reader (
reader.ts):ConfigReader(3 methods) — sema-registry's fatConfigStoreextendsit; a local file source / test fixture implements it without stubbing ~32 methods. remoteExeccontract (remote-exec.ts): the execution-substrate schema mirroring the service's actual providers (e2b/k8s/ssh/adb), discriminated onprovider; every secret an env-NAME ref.- Auth wire contract (
api/auth.ts, subpath./api/auth): the/api/v1/auth/*face — RFC 8628 device flow (code / token poll / approve consent) + rotating refresh + logout, the OAuth error envelope, and the pure client helpersnormalizeUserCode/nextPollInterval. Shipped M1 shapes frozen. OpenAPI mirror:docs/openapi-auth.yaml(auth face only). - Auth bridge (
api/auth-bridge.ts, subpath./api/auth-bridge): the 鉴权桥 contract — how a worker verifies a registry-minted user JWT: RS256-only, JWKS from/api/auth/sso/jwkswith kid-miss forced refresh + ≥60s throttle, exp/nbf clock skew (60s), 24h offline grace then fail-closed;VerifierConfig/VerifiedIdentity/AuthBridgeErrorCode+ pure decision fns (shouldForceJwksRefresh,jwksWithinOfflineGrace,classifyTimeClaims,toVerifiedIdentity). The normative rules R1–R10 in its header are the service verifier's implementation spec.VerifiedIdentitycarries an optionalscope(the token's active tenant scope — seeapi/scopes). - Multi-tenant scopes (
api/scopes.ts, subpath./api/scopes): the scope contract — theScopeentity ({id,name,createdAt}, reserved default"global"always exists), per-scopeScopeMemberrows ({scopeId,principal,role}on the existing viewer<editor<publisher<admin ladder), the optional JWTscopeclaim (absent ="global", fully backward compatible; refresh tokens are never scope-bound), and the wire shapes forGET/POST /api/v1/scopes,POST /api/v1/auth/scope(scope-switch mint, OAuth-style errors) andPUT/DELETE /api/v1/scopes/{id}/members. The DECISION SEMANTICS live here as pure functions the registry imports (never re-implements):resolveTokenScope(mint-time scope binding: 1 membership → it; several incl. global → global; several without global → lexicographically first; none →{scope:"global", role:instanceRole}),canSwitchScope(member or instance admin),effectiveScopeRole(instance admin is"admin"in every scope) andtokenScopeOf(missing claim ="global"). OpenAPI mirror:docs/openapi-scopes.yaml. - Local file source (
file-store.ts,file-edit.ts):FileConfigStorereadsconfig.d/*.json→EffectiveConfig;validateDomain/writeDomainFile/listRequiredEnvNamesare the TOC's read/write/validate helpers.getEffective({tolerant:true})(0.10.12) isolates a malformed catalog-domain file (that domain falls to its schema default, the error is listed indomainErrors) instead of failing the whole read; gate domains (governance/rosters/entitlement/execution/runtime/ workers) stay fail-loud even in tolerant mode.
Secret boundary
Every secret field is an env-NAME, never a value. The ENV_NAME regex (/^[A-Z_][A-Z0-9_]*$/) rejects a
pasted credential. Values are resolved by the consumer from its own env (service env / k8s secret / the TOC
local .env). This package never carries a credential.
Local file layout (TOC)
<root>/
config.d/
models.json rosters.json skills.json mcp.json scenarios.json
collab.json runtime.json governance.json execution.json remote-exec.json
.env # secret VALUES only (KEY=value); gitignored; never read into any *.jsonFleet-only domains (workers, hosts, systems) are omitted on a single machine — they resolve to schema
defaults. Each config.d/<domain>.json is exactly that domain's zod object.
发版纪律(semver)
- 0.x 破坏性变更必 bump minor(0.7 → 0.8),不许塞 patch——
^0.7.0这类脱字号 range 在 0.x 下 会自动收 patch,把 BREAKING 塞进 patch = 未 pin 精确版的下游npm install静默拿到破坏。 - patch 只装:additive 字段、修 bug、文档/测试。commit message 的
feat!/BREAKING标记照旧, 但标记不豁免版号义务。 - 历史注记(0.7.1,2026-07-10):0.7.1 携带了两件预协调 BREAKING(撤 governance effective 双写
镜像、撤 QuotaLease 0.5
tokens别名 shim)——名义上违反本条。当时下游(center/service 1.150.0) 均已显式迁移、实际破坏面为零,PM 拍板不重发 0.8.0(纯扰动);本段即为该例外的收账与今后的规矩。 - 发布(单腿 npmjs,内网腿已废止):
npm run publish:npm;发后必须 curl 直打 npmjs 复验 shasum。
贡献指引
- 真源 =
sema-agent/sema-registry-coreorg 仓main,所有变更直接落 org main(或 PR 进 main); 不再向任何个人位/镜像位 push。 - 提交门 =
npm run build+npx vitest run;改域/契约后必跑npm run e2e(examples/toc-e2e.mjs)。 - 契约破坏面动之前先盘 center / server / CLI 三方消费点;0.x 破坏性变更必 bump minor(见上节)。
