@lssm-tech/integration.runtime
Website: https://contractspec.io
Runtime integration with secret management.
Declaration generation uses tsconfig.build.json to omit test sources from published artifacts. Development typechecking and bun test retain the cross-package governed-workspace integration tests.
What It Provides
- Layer: integration.
- Consumers:
providers-impls, bundles, apps that need secrets or channel routing.
- Related ContractSpec packages include
@lssm-tech/lib.contracts-integrations, @lssm-tech/lib.contracts-spec, @lssm-tech/lib.logger, @lssm-tech/tool.bun, @lssm-tech/tool.typescript.
Installation
npm install @lssm-tech/integration.runtime
or
bun add @lssm-tech/integration.runtime
Usage
Import the root entrypoint from @lssm-tech/integration.runtime, or choose a documented subpath when you only need one part of the package surface.
The channel runtime keeps policy evaluation deterministic and auditable:
- Signature-invalid events are rejected before processing.
MessagingPolicyEngine can be replaced by a contract-backed policy evaluator through ChannelRuntimeService.
ChannelApprovalService exposes a generic approval queue for CLI, API, web, or custom operator surfaces via the shared channel store.
ControlPlaneSkillRegistryService verifies, installs, lists, and disables signed skill artifacts against an allowlisted trust policy.
- Compiled plans now carry deterministic plan and step IDs, DAG dependency metadata, typed step I/O schema refs, actor audit context, and approval timeout fallback state.
- Capability grants are intended to be bound by the hosting application, for example through
CHANNEL_RUNTIME_DEFAULT_CAPABILITY_GRANTS, rather than trusted from inbound event payload metadata.
- Hosting applications should also bind a server-side actor via
actorResolver so runtime approvals and execution are attributed to the authenticated service, operator, or agent principal rather than raw inbound channel claims.
- Telemetry now carries
traceId, sessionId, and workflowId when callers provide them in inbound metadata.
- Trace services now persist stage-level trace events so operators can inspect the full intent -> plan -> policy -> action -> outcome chain.
- Tracked approval migrations preserve historical ledger IDs through
006, add reviewer-runtime issuer/nonce/RLS support in 006a, and require explicit public-metadata authority provisioning before materialization or enrollment; reusable schema source contains no operator identity or implicit admin enrollment.
- Historical reviewer-grant migration statements remain internal implementation files consumed by the existing migration composition; export generation does not expose a separate
reviewer-grant-decision-migration package subpath.
Notion delta binding
NotionDeltaSync accepts the owning NotionDeltaProvider adapter port with
queryDatabase and search methods. Existing project-management Notion providers remain assignable; no provider SDK or reverse dependency is required by the runtime. Complete provider objects remain the change payloads. Cursor paging, timestamp filtering, storage keys and checkpoint defaults are preserved. Provider/storage failures propagate, and the host retains provider authority.
Run the credential-free paging/payload/checkpoint fixtures with
bun --no-env-file test src/delta/notion.test.ts from this package. The explicit
tsgo --project tsconfig.notion-delta-compat.json gate checks actual concrete provider assignability and rejects malformed payloads; it is separate from production declaration emission.
Use @lssm-tech/integration.runtime/agent-platform to compose an exact, digest-bound deployment plan from portable capabilities and provider profiles. Built-in candidate profiles cover Vercel and Railway as deployment platforms, Supabase as a managed data/auth/realtime/queue/scheduler service, and Docker as an isolation and packaging substrate. Consumers can replace or combine them without changing the agent, collaboration, improvement, or maintenance domain contracts.
The same subpath exposes:
- an authenticated collaboration gateway with durable replay and best-effort realtime signalling;
- fail-closed production qualification against the exact plan, profile, environment, required suites, loss acceptance, and enterprise controls; and
- stable profile and plan digests for evidence, audit, and release promotion.
Every composition also requires five provider-independent baseline gates: governance/security, supply-chain security, observability export, load/resilience, and clean-consumer release. Provider-specific suites extend these gates; they cannot replace them. The complete suite set is stored in the digest-bound plan, and qualification recomputes it from pinned profiles before execution.
Built-in profiles are intentionally candidate. A provider marketing claim or local unit test never promotes a plan; the target environment must produce a passing qualification report.
The Postgres execution-lane store implements the optional team transaction boundary with a short row-locking transaction and monotonic revision CAS. Independent replicas cannot both lease or finalize the same team state, and stale full-state writes fail closed. The managed CompanyOS schema keeps FORCE RLS and adds the revision column through forward migration 0060. Lost commit acknowledgements raise an explicit unknown-outcome error so callers must reconcile durable state before retrying.
Provider OAuth handlers and credential custody
The ./oauth subpaths (github, github-app, notion, slack, teams) call the provider token endpoints and return raw credentials. They keep no state: storage, refresh and revocation belong to the host.
- Persist every returned token only through a
SecretProvider that encrypts at rest, such as GcpSecretManagerProvider or the AES-GCM Postgres provider in
@lssm-tech/integration.communication-os-persistence. Database rows keep the secret reference only. Never put a token in a plaintext column, a configuration object, a URL, a log line, a telemetry attribute or an error message, and never log or serialize a whole exchange result.
SlackOAuth2Handler.exchangeCode posts the code form-encoded to
oauth.v2.access, the only body Slack reads for OAuth methods. It returns the bot token (accessToken, xoxb-) and, when user scopes were requested, the installing user's token in authedUser.accessToken (xoxp-). A user-scope-only install has no accessToken; exchangeCodeForBotToken
rejects such an install with missing_bot_token, and an exchange without any token rejects with missing_access_token. The user token acts as that person with every granted user scope, so it is a second credential: store it as the
userToken field of the messaging.slack secret payload next to botToken, and discard the authedUser tokens when the host has no user-scoped feature.
incomingWebhook.url is also a credential, because anyone holding it can post to the channel.
- Slack token rotation is not supported yet. The
messaging.slack secret schema declares no refresh-token field and no runtime refreshes Slack tokens, so keep token rotation off for Slack apps that use this handler. If an exchange still returns refreshToken or authedUser.refreshToken, discard them: do not persist them ad hoc in another secret field, a column or a configuration object until the contract declares refresh fields.
- On disconnect, call
revokeToken for the bot token and for any stored user token. It throws SlackOAuthError when Slack refuses, so a failed revocation is never reported as success.
GitHubAppHandler accepts the PKCS#1 key GitHub downloads (BEGIN RSA PRIVATE KEY) as well as PKCS#8, with real line breaks or with literal \n escapes as in a one-line environment variable. Load it from a
SecretProvider. An unreadable key rejects with a fixed GitHubAppError message, with no key material and no underlying cause, before any request to GitHub.
SlackOAuthError, GitHubOAuthError and GitHubAppError carry only the provider's error code or message. They never include client secrets, authorization codes, tokens, app JWTs or private keys;
test/oauth/credential-redaction.test.ts locks this and checks that the handlers write nothing to the console.
Architecture
src/channel is part of the package's public or composition surface.
src/agent-platform composes provider profiles, authenticated multiplayer transport, and production qualification.
src/health.ts is part of the package's public or composition surface.
src/index.ts is the root public barrel and package entrypoint.
src/runtime.health.test.ts is part of the package's public or composition surface.
src/runtime.ts is part of the package's public or composition surface.
src/secrets is part of the package's public or composition surface.
src/transport is part of the package's public or composition surface.
Public Entry Points
- Export
. resolves through ./src/index.ts.
- Export
./agent-platform resolves through ./src/agent-platform/index.ts.
- Export
./agent-platform/baseline-suites resolves through
./src/agent-platform/baseline-suites.ts.
- Export
./channel resolves through ./src/channel/index.ts.
- Export
./channel/approval resolves through ./src/channel/approval.ts.
- Export
./channel/authorization resolves through ./src/channel/authorization.ts.
- Export
./channel/base-types resolves through ./src/channel/base-types.ts.
- Export
./channel/dispatcher resolves through ./src/channel/dispatcher.ts.
- Export
./channel/github resolves through ./src/channel/github.ts.
- Export
./channel/memory-store resolves through ./src/channel/memory-store.ts.
- Export
./channel/plan-types resolves through ./src/channel/plan-types.ts.
- Export
./channel/plan-utils resolves through ./src/channel/plan-utils.ts.
- Export
./channel/planner resolves through ./src/channel/planner.ts.
- Export
./channel/planner-types resolves through ./src/channel/planner-types.ts.
- Export
./channel/policy resolves through ./src/channel/policy.ts.
- Export
./channel/postgres-queries resolves through ./src/channel/postgres-queries.ts.
- Export
./channel/postgres-schema resolves through ./src/channel/postgres-schema.ts.
- Export
./channel/postgres-store resolves through ./src/channel/postgres-store.ts.
- Export
./channel/replay-fixtures resolves through ./src/channel/replay-fixtures.ts.
- Export
./channel/service resolves through ./src/channel/service.ts.
- Export
./channel/slack resolves through ./src/channel/slack.ts.
- Export
./channel/store resolves through ./src/channel/store.ts.
- Export
./channel/telegram resolves through ./src/channel/telegram.ts.
- Export
./channel/telemetry resolves through ./src/channel/telemetry.ts.
- Export
./channel/trace resolves through ./src/channel/trace.ts.
- Export
./channel/types resolves through ./src/channel/types.ts.
- Export
./channel/whatsapp-meta resolves through ./src/channel/whatsapp-meta.ts.
- Export
./channel/whatsapp-twilio resolves through ./src/channel/whatsapp-twilio.ts.
- Export
./health resolves through ./src/health.ts.
- Export
./runtime resolves through ./src/runtime.ts.
- Export
./secrets resolves through ./src/secrets/index.ts.
- Export
./secrets/env-secret-provider resolves through ./src/secrets/env-secret-provider.ts.
- Export
./secrets/gcp-secret-manager resolves through ./src/secrets/gcp-secret-manager.ts.
- Export
./secrets/manager resolves through ./src/secrets/manager.ts.
- Export
./secrets/provider resolves through ./src/secrets/provider.ts.
- Export
./transport resolves through ./src/transport/index.ts.
- Export
./transport/auth-resolver resolves through ./src/transport/auth-resolver.ts.
- Export
./transport/transport-factory resolves through ./src/transport/transport-factory.ts.
- Export
./transport/version-negotiator resolves through ./src/transport/version-negotiator.ts.
- The package publishes 130 total export subpaths; keep docs aligned with
package.json.
Local Commands
bun run dev — contractspec-bun-build dev
bun run build — contractspec-bun-build build
bun run test — bun test --pass-with-no-tests
bun run lint — bun lint:fix
bun run lint:check — biome check .
bun run lint:fix — biome check --write --unsafe --only=nursery/useSortedClasses . && biome check --write .
bun run typecheck — tsgo --noEmit
bun run publish:pkg — bun publish --tolerate-republish --ignore-scripts --verbose
bun run publish:pkg:canary — bun publish:pkg --tag canary
bun run clean — rimraf dist .turbo
bun run build:bundle — contractspec-bun-build transpile
bun run build:types — contractspec-bun-build types
bun run prebuild — contractspec-bun-build prebuild
Recent Updates
- Replace eslint+prettier by biomejs to optimize speed.
- Resolve lint, build, and type errors across nine packages.
- Add Composio universal fallback, fix provider-ranking types, and expand package exports.
- Add first-class transport, auth, versioning, and BYOK support across all integrations.
- Add monorepo-aware environment resolution helpers that materialize framework aliases and redact secret values in reports.
- Upgrade dependencies.
- Stabilize lint gate and runtime contract typing.
- Add provider-adaptable enterprise agent-platform composition and fail-closed live qualification for Vercel, Railway, Supabase, Docker, and custom profiles.
Notes
- Secret providers must implement the
provider interface; never read secrets directly.
- Environment resolution reports must stay redacted; secret and sensitive values are never serialized into examples, reports, telemetry, or errors.
- Channel stores (memory, postgres) are swappable; do not couple to a specific backend.
- Never import from apps or bundles.
Internal Builder filesystem integration now stages replacements and explicit new files, checks all preimage hashes before mutation, rejects symlinks/hardlinks and duplicate paths, and restores replacements on caught failures. It requires an exclusively owned checkout. Creation requires create: true with preimageHash absent and never overwrites. The exported workspace adapter still requires production qualification: durable crash recovery, Git worktree lifecycle and artifact retention remain to be implemented.
Internal Git checkout support clones only an exact commit from a host-owned local repository, avoids object hardlinks, removes the source remote and discards ambient Git credentials/config. Hook and fsmonitor execution are disabled. The returned checkout is distinct from dirty source files and owns its cleanup directory. This is a trusted-host checkout primitive, not a sandbox for hostile repositories or concurrent agents; durable lease/recovery and full patch-port integration remain.
The internal Git patch workspace composes exact-commit checkout and staged edits behind BuilderPatchWorkspacePort. It rejects dirty/stale workspaces, creates a candidate commit, and persists a patch, Git bundle and digest receipt before checkout disposal. Changes are conservatively classified unknown for review. Its additive /builder export enables host composition; durable restart reconciliation and full authority/provider/check integration remain required. Artifact directories are host-owned and must be kept outside provider-writable execution roots.
Artifact and checkout roots must be disjoint after realpath resolution. The adapter reserves each artifact directory exclusively before mutation and flushes the bundle plus receipt directory before returning a candidate. Dirty workspaces are rejected before edits and never receive a success receipt. Restart recovery is still not qualified; these checks do not imply crash-consistent completion.
The internal workspace journal writes immutable created/applying/disposed markers in the host-owned artifact directory. Creation is recorded before its deterministic checkout allocation; applying is recorded before file effects. Read-only restart inspection distinguishes prepared, effect_unknown, candidate_unverified and disposed states. It never executes a stored path or infers success from a partial receipt. This enables reconciliation, not automatic resumption or cleanup; artifact digest verification and process-exclusion proofs remain required.
Read-only candidate verification compares patch and Git-bundle bytes with the host receipt after checkout disposal. It uses bounded streaming reads, rejects symlink/hardlink artifacts and detects changed files. Receipt scope must match the creation journal. Integrity verification is not code review, Git semantic validation, execution authority or release approval.
The governed-workspace integration test runs the existing governed patch service against real Git checkouts and retained artifacts, enforcing pre-mutation then post-diff authority before checks. Provider/signature/store behavior is a test fixture; this is not live provider or durable authority qualification.
The integration proof also passes through workspace-ai's file-proposal bridge, using a real checkout snapshot and rejecting provider path metadata as authority. The agent response remains deterministic test data; no external model run is implied.
Internal reconciliation can dispose prepared or integrity-verified candidate checkouts only inside a host coordinator callback that excludes execution for the whole operation. Unknown effects are retained for review. Paths are derived from the configured checkout root and validated ID, never used directly from journal content. The runtime coordinator must supply real exclusion; test callbacks are not production process-fencing evidence.
A prepared marker alone cannot authorize deletion of a non-empty checkout: reconciliation retains those contents for review. Candidate cleanup is exercised against a real Git patch and bundle using only its persisted journal and artifacts, without the original adapter map. Host executor exclusion is still required.
The Git patch adapter now excludes overlapping apply and disposal calls for each workspace within one adapter instance. Disposal cannot remove an actively written checkout; the lock releases only after the operation settles. Failed apply remains non-replayable. This is local lifecycle exclusion, not cross-process claim fencing.
The canonical /builder barrel exports createBuilderGitPatchWorkspace and
verifyBuilderPatchArtifact. These are additive compatibility surfaces for trusted host composition; exports do not qualify hostile-code isolation or grant authority.
Vercel hosted-preview observation
The Builder barrel exposes createVercelPreviewDeploymentReader, a read-only implementation of the existing Vercel discovery driver for one exact deployment, and createVercelBuilderPreviewHost, which composes persisted release bindings, provider metadata and a fresh health request. Team/project/deployment mismatches, unsafe URLs, failed health and binding revocation fail closed. Provider responses are byte-bounded and reduced to public deployment fields; health requests never receive API credentials. The Builder runtime separately validates the canonical deployment receipt before persisting ready.
Authentication supports scoped SecretProvider references or a distinct host-authenticated transport. The September 8 pilot read was live-qualified using Vercel CLI authentication; this does not qualify long-lived SecretProvider credentials, provisioning, a canonical release receipt, or the entire Vercel provider lifecycle. The host requires authorized persisted bindings; it does not create deployment authority or manufacture missing source/artifact evidence.
API shape reference: https://vercel.com/docs/rest-api/reference/endpoints/deployments/get-a-deployment
Preview discovery consumes the shared library-owned provider port directly. There is no runtime-to-Vercel-integration dependency; the Vercel adapter and this read-only host specialize one shared contract rather than importing sibling integrations.
Railway hosted-preview observation
createRailwayPreviewDeploymentReader implements the shared library discovery port for one exact project/environment/service/deployment tuple. Its fixed GraphQL query requests identity, status, static URL and active deployment IDs, never deployment messages, metadata, variables, or inferred source revisions. Project-token and bearer-token authentication are explicit SecretProvider modes; a host-authenticated transport remains a separate qualification mode.
createRailwayBuilderPreviewHost requires canonical release binding and fresh health. A shared service URL qualifies only when the expected deployment is the sole active deployment, checked before and after the health request. Health reads carry no provider credentials. Binding revocation, routing change, GraphQL errors, missing source/artifact receipt evidence, unsafe URLs and cancellation fail closed. Readers and host observations are bounded to twenty seconds. No provisioning or mutation is implemented by this observer.
Official endpoint/authentication reference: https://docs.railway.com/integrations/api
Retained candidate artifacts can be read through BuilderRetainedPatchArtifactReadPort. The local createBuilderRetainedPatchArtifactReader binds a protected project artifact root and checks the exact work order, base/head revisions and patch hash. It verifies both retained patch and bundle bytes after checkout disposal, rejects ambiguous matches and fails explicitly when its bounded inventory is exceeded. Cancellation returns no artifact. This is read-only artifact evidence, not member authorization, deployment authority or a hosted preview.
Durable local Builder authoring
openLocalBuilderAuthoring(absolutePrivateDirectory) lazily opens file-backed PGlite with the existing Builder PostgreSQL schema and PostgresBuilderStore. The directory must be private and cannot be a symlink. One exclusive owner lock prevents concurrent opens; confirmed close releases the lock. An interrupted process leaves the lock for operator reconciliation rather than guessing that another owner is dead. No in-memory fallback or new domain tables are introduced.
Always await close before reopening. This storage adapter does not authenticate users or authorize execution; local API startup still needs current AuthOS sessions and scoped Connect authority. PGlite is loaded only when opening the local store, not when importing the shared Builder entry point.