@fourier-labs/harbour-contracts

中文文档
0.106.3发布于 2026/11/13UNLICENSEDTypeScriptES Module零依赖近 30 天下载 9073

Single source of truth for every data shape that crosses a boundary between Isomorph components.

原始使用文档
文档目录6 节
  1. Layout
  2. The schemas
  3. Workflow
  4. Changing a shape
  5. Consuming
  6. Notes

harbour-contracts

The single source of truth for every data shape that crosses a boundary between Isomorph components. Schema-first: hand-written JSON Schema in schema/ is the source; the Go package (gen-go/) and TypeScript package (gen-ts/ → @fourier-labs/harbour-contracts) are generated and committed. No handler, infra stack, or MCP op is built against a shape that does not exist here first.

Layout

PathWhat
schema/*.jsonJSON Schema (draft-07). The only files you hand-edit.
gen-go/Generated Go package contracts (import github.com/Fourier-Labs-AI/harbour-contracts/gen-go).
gen-ts/Generated TS sources; published as @fourier-labs/harbour-contracts.
contract-release.jsonGenerated release/version plus aggregate and per-file schema, AI-fixture, Go-source and TypeScript-source digests for strict consumer pins.
tools/gen/gen.mjsThe single codegen driver (Node). Validates every schema, then emits Go + TS.
docs/adr/Decision records (e.g. 0001-t1-ratified.md).

The schemas

FileShapeLLD
deploy-request.schema.jsonMCP deploy(app, {commit, branch}) payload; new preview deploys default to branch_select unless sequential is explicit§7
error-envelope.schema.jsonThe failure envelope emitted once per FAILED transition§2.1
error-category.enum.jsonClosed failure-category enum + per-category retryable registry§2.2
artifact-contract.schema.jsonBuild output contract (the provider-portability seam), including the digest-pinned well-defined app manifest reference§3
well-defined-app-manifest.schema.jsonVersioned runtime wiring for static, full-stack, and browser-first apps: workloads, schedules, queues, service bindings, language runtime, browser capabilities, and route authenticationWell-defined apps P0
version-state.schema.jsonState machine T1a — states, legal transitions, versionId format§1
env-bindings.schema.jsonEnvBindings / Target / Binding (BYOC-complete)§4.2.2
kvs-routing-entry.schema.jsonCloudFront KVS routing value ({static, api})§8
ai-composite-policy-digest.schema.jsonOrdered composite-policy digest identity and generated Go/TS helpersAI governance §5.1
ai-classification-stamp.schema.jsonImmutable exact-version classification evidenceAI governance §5.2
ai-deployment-gate-decision.schema.jsonAppend-only explicit deployment gate decisionAI governance §5.2
ai-governance-decision.schema.jsonAI governance decision, including value-free descriptors for reviewed OpenAI-compatible client configuration boundariesAI governance §5
ai-gateway-key-lifecycle-event.schema.jsonValue-free version-key lifecycle evidenceAI governance §7
ai-runtime-binding.schema.jsonPlatform-neutral workload identity/secret bindingAI governance §5.8
binding-classification-subject.schema.jsonComplete value-free binding-name classification before version allocationAI governance §5.7 / SEC-UP-01
sanitized-binding-evidence.schema.jsonExact-version sanitized runtime-binding allocation receiptAI governance §5.7 / SEC-UP-02
ai-pricing-revision, ai-metering-policy, ai-budget-ledger-event, ai-trace-event-v2Additive metering v2 records, including media dimensions and P5 trace attribution; v1 records remain readableAI governance §9
app-integrations-declaration.schema.jsonCommitted .isomorph/integrations.json (isomorph.app-integrations/2.0): closed eighty-one-operation set (Slack read/post/update/delete/DM/lookup, Gmail list/thread/read/send/attachment — ADR 0018; Basecamp project/to-do list/to-do/message/comment/people lists, to-do create and complete, message, comment and Campfire posts — ADR 0022; SharePoint list/item/drive/file lists, file search and read, item create and update, file upload — ADR 0024; phone SMS list — ADR 0028; phone number read — ADR 0029; Google Calendar, Drive, Docs and Sheets and Outlook, OneDrive, Excel and Teams reads and writes as the signed-in person — ADR 0032; warehouse view read and table append, the view mapping saying `access: readappend — ADR 0028; service request) with fixed or declared identity modes (gmail.message.send` declared since 0.102.0 — ADR 0045; the four Gmail reads since 0.106.0 — ADR 0049); owns the shared operation/identity/environment enums
integration-execute-request, integration-execute-result, integration-connect-result, integration-error-detailsApp SDK integrations wire contract on /_harbour/integrations/*: per-operation input bounds (a warehouse read filters, groups, aggregates and sorts in the warehouse and says when it was truncated — ADR 0017; Slack and Gmail reads page, posts thread, mail carries HTML and attachments — ADR 0018; a development warehouse read may carry the app's sampleRows and the result says sample — ADR 0021; Basecamp lists page by pageToken, ids are digit strings, writes answer {id, appUrl} — ADR 0022; SharePoint lists page by a Graph $skiptoken, ids are Graph ids, fields is a bounded record, writes answer {id, webUrl} — ADR 0024; a warehouse append takes rows, a bounded list of records, and a phone SMS list takes since/from — ADR 0028; a phone number read takes no input — ADR 0029; calendar events take RFC 3339 start/end, Sheets and Excel take values, a bounded matrix of cells, Docs take replacements, and the event read, document read, values and worksheet results have their own shapes — ADR 0032), the per-operation result shapes, consent states and the closed details.code reason setDev kit §4, §8
saas-connection.schema.json, data-grant-v2.schema.jsonTenant SaaS connection record (one installation and channel map per tenant and provider; IT's optional oauthClient, userModeApproval, directMessages, externalRecipients — ADR 0018; a Basecamp connection's pinned account and project ids in channels — ADR 0022; a SharePoint connection's pinned Microsoft 365 tenant in account and site ids in channels — ADR 0024; up to 20 approvers who may approve access requests beside the tenant admins — ADR 0026; a phone connection's E.164 numbers in channels — ADR 0028, which an app reads back by alias — ADR 0029; eight Google Workspace and Microsoft 365 providers, user-consent only, a Teams connection's pinned tenant and <teamId>/<channelId> channel map — ADR 0032; optional startedBy when a builder's first request created the connection — ADR 0034; a Gmail connection's installation is the company mailbox IT connected, botName its address — ADR 0045) and the additive harbour.data-grant/2.0 grant record with structured resources and provisioning lease/cleanup (status machine generated; legacy data-grant untouched)Dev kit §5
kit-bundle-manifest.schema.json, kit-lock.schema.jsonPublished kit bundle identity (SDK tarball digest plus optional sdk.version and https sdk.url download location) and the committed .isomorph/kit.lock.json the CodeBuild SDK-vendoring gate compares againstDev kit §3
deploy-response.schema.json202 Accepted body for POST /v1/tenants/{tenant}/apps/{app}/deployments, returned only after the authoritative QUEUED version exists and its SQS message is accepted—
deployment-source.schema.jsonCredential-free source in the DeployRequest body: provider is github or gitlab, repositoryUrl is shape-only and the deployment control plane checks the host against the tenant's source connection (ADR 0023); credentials are resolved internally by MaterializeSource—
deployment-environment.schema.jsonPublic environment accepted by the preview APIs (preview only; production is reachable only through promotion)—
api-error-response.schema.jsonSafe JSON error body for Deploy/Status Lambda 4xx/5xx responses; distinct from the internal ErrorEnvelope—
deployment-status-request.schema.jsonValidated path parameters for GET /v1/tenants/{tenant}/apps/{app}/deployments/{versionId}—
deployment-status-response.schema.json200 OK body for GET status: that exact immutable version, with the progress trail, deployTarget and diagnosticRef—
deployment-status-failure.schema.jsonFrontend-safe failure projection nested in a failed status response; a digest-bound diagnosticRef locates the redacted diagnostic—
promotion-request.schema.jsonBody for POST /v1/tenants/{tenant}/apps/{app}/promotions; repository identity comes from stored records, not the callerADR 0003
promotion-response.schema.json202 Accepted body returned once the production version and its durable idempotency binding existADR 0003
transform-report.schema.jsonStructured output an agent must return from one transformation attempt; handed to the agent as its output schema and re-validated by the control plane—
transform-parked-result.schema.jsonSequential-preview result after a durable checkpoint when builder input is required; not a successful report—
builder-input-proposal.schema.jsonValue-free proposal emitted when sequential preview cannot continue without builder-owned input—
deployment-continuation.schema.jsonImmutable reference admitting one child deployment from a parked input request; never credential values—
security-scan-input-v2.schema.jsonInput to the Security Assurance machine (harbour.security-scan-input/2.0, replaces v1): one package validated at source intake, scanned in the tenant's execution accountADR 0014
security-verdict.schema.jsonSecurity Assurance decision; BLOCKED surfaces as the non-retryable gate.security-scan categoryADR 0014
data-source.schema.jsonAdmin-registered external data source; credentialRef is a secretref URI and the credential never crosses this boundary; optional development/preview copies under environments, production is the top-level endpoint; connectors include trino (ADR 0021) and clickhouse (ADR 0030)Data-Access MVP
data-dependency.schema.jsonOne external data dependency of an app, declared or detected, classified against the tenant's data-source inventoryData-Access MVP
secret-reference.schema.jsonNamed secret slot an app depends on; only the reference and its lifecycle cross, never the valueSecret-Manager MVP
ai-callsite-inventory.schema.jsonImmutable, sanitized AI call-site discovery for one exact deployment version (detection only)AI governance
ai-runtime-contract.schema.jsonImmutable runtime contract derived by an AI Governance PLAN decision; scoped configuration plus a Secrets Manager referenceAI governance
ai-policy-snapshot.schema.jsonImmutable, content-addressed AI policy snapshot consumed by the AI GatewayAI governance
ai-gateway-key-lookup.schema.jsonValue-free Gateway authentication metadata for one version-scoped Isomorph keyAI governance
ai-trace-event.schema.jsonValue-free asynchronous AI Gateway trace metadata (v1); raw prompts and responses never enter the queueAI governance
ai-transform-event.schema.jsonChecksum-bound deterministic AI interception task input carrying the ordered PLAN interception planAI governance
ai-transform-result.schema.jsonBounded deterministic interception result: descriptors and digest evidence onlyAI governance
ai-verification-evidence.schema.jsonBounded, value-free evidence submitted by deployment verification for one governed versionAI governance

Runtime resource profiles are a closed contract shared by transformation, artifacts, and well-defined application manifests. The supported profiles are standard, memory-1g, and memory-2g; consumers must reject unrecognized raw CPU or memory overrides.

Two schemas carry logic beyond structural types, generated into helpers:

  • error-category.enum.json → IsRetryable(category) (Go) / isRetryable(category) (TS), handling both concrete categories and family prefixes (storage.unsupported-engine.<engine>). Unknown categories fail closed (non-retryable).
  • version-state.schema.json → CanTransition(environment, from, to) / IsTerminal(state) (Go) and canTransition / isTerminal (TS), driven by the x-transitions edge list — so control-plane and any consumer agree on legality from one source.
  • binding-classification-subject.schema.json and sanitized-binding-evidence.schema.json → canonical length-prefixed SHA-256 preimage/digest helpers plus exact-name, requested-mapping and allocation-receipt validators in Go and TypeScript.
  • integration-execute-request.schema.json → IntegrationExecuteInputRules + validateIntegrationExecuteInput(operation, input) (TS) / ValidateIntegrationExecuteInput (Go), derived from each operation's then-block (propertyNames.enum, required, per-field maximum/default). The governance execute route, the app SDK and the kit's local check all refuse a request with the same sentence (limit must be an integer between 1 and 15); the SDK vendors the TypeScript file because it ships with no dependencies.

Workflow

make gen       # regenerate gen-go/ + gen-ts/ from schema/ (Node only — no Go needed)
make verify    # regenerate, then fail if git shows a diff  ← the staleness gate (CI runs this)
make build     # compile-check the generated Go + TS (needs go + local tsc)
make test      # generator determinism + contract-logic tests (Node; Go when installed)

Codegen is Node-only so make gen is reproducible anywhere; a Go toolchain and tsc are used solely to compile-check the output (make build), not to generate it.

Changing a shape

  1. Edit the schema in schema/. The category enum and state machine are closed — extend them only by PR to this repo (that PR is where consumers are notified).
  2. make gen and commit gen-go/ + gen-ts/ alongside the schema change.
  3. CI (make verify) fails any PR whose committed generated code does not match its schema.
  4. Do not edit VERSION, package.json's version or CHANGELOG.md: the release version comes from the vX.Y.Z tag pushed after merge (ADR 0050).
  5. A shape change is a (contracts) change: it lands via /review + /code-review ultra → /ship.

Consumers should pin both the three-part publish version and the schemasDigest/aiFixturesDigest in contract-release.json. Their CI should validate the canonical fixtures against the pinned generated types or schemas; it must not silently skip validation when the contracts checkout is absent. The npm artifact contains schema/, fixtures/ai/, gen-ts/ and the release manifest, so every TypeScript byte named by the manifest is available from the same release. Go source remains available through the tagged Go module.

generatedGo and generatedTypeScript seal every .go/.ts file in their package directories. gen-go/contract_release.go and gen-ts/contract-release.ts are the only exclusions: those generated files embed the aggregate digests themselves, so including them would create a self-reference with no finite digest. The manifest names both exclusions and their reason; tests reject any different exclusion set and independently recompute every included file and aggregate.

Platform-neutral workload and secret references are identifiers, not general URLs. They use scheme://authority/path with a reviewed additive scheme registry (aws-sm, iam-role, k8s-sa, secretref, spiffe, vault, vault-v2). A new platform extends that registry in a contracts release. Userinfo, ports, percent encoding, query strings, fragments and empty path segments are deliberately unrepresentable, preventing reference fields from becoming a credential or arbitrary-value transport.

The v2 metering schemas are projections linked to existing v1 policy/trace identities. During migration, consumers dual-read v1 and v2 and may dual-write both. Old records are never rewritten; corrections are append-only adjustment or superseding records. Removal of v1 writes requires separately recorded consumer cutover evidence.

Consuming

  • Go: go get github.com/Fourier-Labs-AI/harbour-contracts/[email protected]

    Two things make this work, and the second is not the obvious one.

    The publish tag must be 3-part semver. Go and npm require MAJOR.MINOR.PATCH, while this repository records MAJOR.MINOR.PATCH.MICRO. A publishable release therefore requires MICRO to be zero and maps deterministically: repository 0.9.0.0 → package 0.9.0 → publish tag v0.9.0. The optional four-part bookkeeping tag v0.9.0.0 may point at the same commit but does not publish. CI verifies this mapping, the changelog heading and either tag form.

    The repo is private, and Go fetches it from a global cache. Set this once per machine:

    go env -w GOPRIVATE=github.com/Fourier-Labs-AI/*
    git config --global credential."https://github.com/Fourier-Labs-AI".helper '!gh auth git-credential'
    git config --global credential."https://github.com/Fourier-Labs-AI".useHttpPath true
    

    The credential config has to be global and URL-scoped, and that combination is not incidental:

    • It cannot be folder-scoped (includeIf gitdir:…). Go runs git ls-remote inside ~/go/pkg/mod/cache/vcs/…, not inside your repo, so a per-directory helper never applies. This fails identically from /tmp and from inside an Isomorph repo, which makes it look like a bad tag rather than an auth problem.
    • Scoping by URL prefix keeps it off your other GitHub accounts: only github.com/Fourier-Labs-AI/* uses this credential.
    • An SSH insteadOf rewrite is the usual advice and is wrong here unless your SSH key belongs to an account with Fourier org access. Check with ssh -T [email protected] before reaching for it.

    Without the above, go get fails with Repository not found — which reads as a missing tag, not as missing access.

  • TS: npm i @fourier-labs/harbour-contracts — published from the tag by CI. The hand-written AI policy resolver (resolver/index.ts) ships in the same package as the @fourier-labs/harbour-contracts/resolver subpath export (package.json exports).

Notes

gen.mjs produces both languages deterministically from Node. Go struct field alignment is not gofmt-normalized by the generator (gofmt is optional hygiene via make fmt); this never affects compilation, and the staleness gate compares raw generator output, so it stays green.

版本与发布记录

@fourier-labs/harbour-contracts 共发布 85 个版本,首次发布于 2026/08/04;过去 12 个月发布了 85 个版本。

版本发布日期距今
0.106.3latest2026/11/133 天前
0.106.22026/11/123 天前
0.106.12026/11/114 天前
0.106.02026/11/114 天前
0.105.02026/11/114 天前
0.104.02026/11/114 天前

关于 @fourier-labs/harbour-contracts 的常见问题

@fourier-labs/harbour-contracts 是什么?

Single source of truth for every data shape that crosses a boundary between Isomorph components.

如何安装 @fourier-labs/harbour-contracts?

在项目目录运行 npm install @fourier-labs/harbour-contracts,或使用 pnpm add / yarn add / bun add。

@fourier-labs/harbour-contracts 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@fourier-labs/harbour-contracts 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@fourier-labs/harbour-contracts 可以商用吗?

@fourier-labs/harbour-contracts 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@fourier-labs/harbour-contracts 的下载量有多少?

根据 npm 官方下载统计,@fourier-labs/harbour-contracts 在 2026/10/16 – 2026/11/14 这 30 天内被下载 9,073 次,日均约 302 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@fourier-labs/harbour-contracts 还在维护吗?

最新版本 0.106.3 发布于 2026/11/13(3 天前);至今共发布 85 个版本,其中过去 12 个月发布了 85 个;首次发布于 2026/08/04。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。