Appearance
SDK Guide
@giggle-ai/runtime-sdk is a thin, fully typed TypeScript client. Every method is one request/response round trip against the engine's REST API — no policy, risk, or state-machine logic is duplicated client-side.
Three clients, not one
As of Milestone 2D the SDK is split into three classes, one per credential plane the engine actually enforces server-side (see Security). A credential minted for one plane is rejected by the routes another plane's client calls — this isn't just an API convenience, it mirrors a real authorization boundary:
| Client | Credential | Talks to |
|---|---|---|
CarcManagementClient | a tenant principal's management-api-key/service-account-key | /runtime/* tenant-facing routes (Agent Registry, Sessions, Agent Runs, Provider Connections, Execution Profiles, Policies, Decision Records/Replay, Metrics, and the tenant-facing slice of Integration Governance) |
CarcAdminClient | a platform_admin principal's credential | every /admin/* route — ManagementPrincipal/TenantMembership/PrincipalCredential lifecycle, Organization Verification, and the full admin side of Integration Governance (integrations, environments, agent bindings, certifications, credential bindings, audit) |
CarcRuntimeClient | an opaque IntegrationCredentialBinding reference (never a management credential) | only POST /runtime/agents/:id/execute — the machine-to-machine execution gateway |
If your integration only ever calls tenant-facing routes, you only ever need CarcManagementClient. If it also administers platform-wide state (rare — usually only the platform team itself) or executes agents as the machine-to-machine integration runtime (the actual production traffic path once your integration is certified and active), construct the other two clients as well — see examples/openai-clinical-agent/ in this monorepo for a worked example that genuinely needs all three side by side.
Installing
bash
npm install @giggle-ai/runtime-sdkInside this monorepo, it's already a workspace package — build it (and its dependencies) with npm run build:packages.
CarcManagementClient
ts
import { CarcManagementClient } from "@giggle-ai/runtime-sdk";
const runtime = new CarcManagementClient({
baseUrl: process.env.CARC_RUNTIME_API_URL!,
managementCredential: process.env.CARC_MANAGEMENT_CREDENTIAL!, // see Security — required once MANAGEMENT_AUTH_MODE=enforced
tenantId: "tenant_acme_health", // optional selection hint among your principal's own active memberships
timeoutMs: 30_000, // default; set 0 to disable
});| Field | Required | Notes |
|---|---|---|
baseUrl | yes | No trailing slash required. |
managementCredential | in enforced mode | Sent as Authorization: Bearer <managementCredential>. Issued via CarcAdminClient.issuePrincipalCredential — see Security and Integration Governance & Identity. |
tenantId | no | Sent as X-Tenant-ID — only ever a selection hint among your principal's own active memberships in enforced mode, never a way to grant yourself a different tenant. |
headers | no | Extra headers merged into every request. |
timeoutMs | no | Aborts a request after this many ms. |
fetch | no | Override the fetch implementation (mocking, polyfills). |
Timeout configuration
Every request is wrapped in an AbortController timing out after timeoutMs (default 30000). A timeout surfaces as RuntimeNetworkError.
Correlation IDs
Every request automatically sends a generated X-Correlation-ID (or reuses whatever the engine echoes back). Read the most recent one via runtime.getLastCorrelationId(), or .correlationId on any thrown SDK error — include it when filing an issue about a specific request. All three clients share this behavior identically.
Error handling
Every failure across all three clients is a subclass of the same RuntimeApiError hierarchy:
ts
import { RuntimeConflictError, RuntimeNotFoundError } from "@giggle-ai/runtime-sdk";
try {
await runtime.activateAgent("some-agent");
} catch (err) {
if (err instanceof RuntimeConflictError) {
console.log(`Cannot activate: ${err.message} (correlation: ${err.correlationId})`);
} else if (err instanceof RuntimeNotFoundError) {
console.log("Agent not registered.");
} else {
throw err;
}
}See Errors for the full hierarchy and retryable/non-retryable guidance.
Agent Registry methods
ts
await runtime.listDomains(); // installed domain packs, with their roles and task types
await runtime.listCases(); // synthetic cases across every domain
await runtime.registerAgent({ agentId, name, owner, version, domain, subdomain, allowedTasks, capabilities, modelProvider, modelVersion, riskTier });
await runtime.listAgents({ status: "active" });
await runtime.getAgent(agentId);
await runtime.updateAgent(agentId, { version: "1.1.0" });
await runtime.activateAgent(agentId);
await runtime.suspendAgent(agentId);
await runtime.deprecateAgent(agentId);Session methods
ts
await runtime.createSession({ caseId, agentId, taskType, userRole });
await runtime.listSessions({ state: "waiting_for_human_review" });
await runtime.getSession(sessionId);
await runtime.getSessionTimeline(sessionId);
await runtime.pauseSession(sessionId, { reason });
await runtime.resumeSession(sessionId);
await runtime.cancelSession(sessionId, { reason });
await runtime.approveSession(sessionId, { reviewerId, notes });
await runtime.rejectSession(sessionId, { reviewerId, notes });
await runtime.retrySession(sessionId, { reviewerId, notes });Agent Run methods
ts
await runtime.submitAgentRun({ agentId, caseId, taskType, agentOutput, sourceReferences, modelProvider, modelVersion, submittedBy });
await runtime.listAgentRuns({ agentId, executionOrigin: "external" });
await runtime.getAgentRun(runId);Provider Connection methods
Initiative 2 — tenant-owned connections to external model providers. See Provider Connections for the full architecture. credential is write-only and never returned by any of these methods. Contains no model/execution configuration — see Execution Profile methods below for that.
ts
const connection = await runtime.createProviderConnection({
provider: "openai",
displayName: "Acme Health — OpenAI Production",
credential: process.env.ACME_OPENAI_API_KEY!,
});
await runtime.validateProviderConnection(connection.connection_id);
await runtime.listProviderConnections({ status: "valid" });
await runtime.getProviderConnection(connection.connection_id);
await runtime.updateProviderConnection(connection.connection_id, { displayName: "Renamed" });
await runtime.rotateProviderConnectionCredential(connection.connection_id, newApiKey);
await runtime.disableProviderConnection(connection.connection_id);
await runtime.enableProviderConnection(connection.connection_id);
await runtime.deleteProviderConnection(connection.connection_id);Execution Profile methods
Initiative 3 — the canonical execution contract (model, inference parameters, timeouts/retries). See Execution Profiles for the full architecture and resolution order.
ts
const profile = await runtime.createExecutionProfile({
displayName: "GPT-5 Structured Review",
provider: "openai",
adapterId: "openai-responses-adapter",
providerConnectionId: connection.connection_id,
model: "gpt-5",
temperature: 0.2,
maxOutputTokens: 2048,
});
await runtime.activateExecutionProfile(profile.profile_id);
await runtime.listExecutionProfiles({ status: "active" });
await runtime.getExecutionProfile(profile.profile_id);
await runtime.updateExecutionProfile(profile.profile_id, { temperature: 0.1 });
await runtime.disableExecutionProfile(profile.profile_id);
await runtime.deleteExecutionProfile(profile.profile_id);Set the resulting profile_id on an agent before calling CarcRuntimeClient.executeRegisteredAgent (below):
ts
await runtime.updateAgent(agentId, {
executionProfileId: profile.profile_id,
});Integration Governance methods (tenant-facing)
The limited, tenant-facing slice of Integration Governance — see Integration Governance & Identity for the full lifecycle and everything intentionally NOT reachable here (sandbox/ production approval, certification pass/fail, activation — all platform-admin-only, on CarcAdminClient instead):
ts
const integration = await runtime.createIntegration({ name, integration_type, owner_team, technical_contact });
await runtime.updateIntegration(integration.id, { description: "Updated description" });
await runtime.submitIntegration(integration.id);
await runtime.listIntegrations();
await runtime.getIntegration(integration.id);
await runtime.listIntegrationEnvironments(integration.id);
await runtime.listEnvironmentCertifications(environmentId);
await runtime.listEnvironmentAgentBindings(environmentId);
await runtime.rotateIntegrationCredential(credentialBindingId, { raw_credential, reason });Decision record methods
ts
await runtime.getDecisionRecord(decisionId);
await runtime.listDecisionRecords(status);Replay methods
ts
await runtime.getDecisionReplay(decisionId); // single-run replay
await runtime.getSessionReplay(sessionId); // full multi-run "flight recorder"Metrics methods
ts
await runtime.getMetrics({ agent_id, task_type, from, to });Policy methods
ts
await runtime.listPolicies({ enabledOnly: true });
await runtime.getPolicy(policyId);Health and identity methods
ts
await runtime.getHealth();
await runtime.getReadiness();
await runtime.getVersion();
await runtime.whoami(); // the authenticated principal's own identity — principal_id, principal_type, tenant_id, roles, environmentCarcAdminClient
Platform-admin-only — construct with an adminCredential (a platform_admin principal's credential), never a tenant management credential:
ts
import { CarcAdminClient } from "@giggle-ai/runtime-sdk";
const admin = new CarcAdminClient({
baseUrl: process.env.CARC_RUNTIME_API_URL!,
adminCredential: process.env.CARC_ADMIN_CREDENTIAL!,
});Unlike CarcManagementClient, there is no client-level tenantId — every governance-admin method takes an explicit tenantId as its first parameter and sends it as a per-call X-Tenant-ID override, since a platform admin routinely acts across many different tenants in the same session.
ts
// Adapter methods (moved here from CarcManagementClient in Milestone 2D)
await admin.listAdapters();
await admin.getAdapter(adapterId);
await admin.validateAdapter(adapterId);
// Identity
await admin.whoami();
await admin.getBootstrapStatus();
await admin.createManagementPrincipal({ principal_type: "tenant_user", display_name: "Acme Ops" });
await admin.activateManagementPrincipal(principalId);
await admin.createTenantMembership(principalId, { tenant_id: "tenant_acme", role: "tenant_owner" });
await admin.issuePrincipalCredential(principalId, { credential_type: "management-api-key", environment: "production" });
// Integration Governance (admin) — see /integration-governance for the
// full lifecycle
await admin.submitOrganizationVerification({ tenant_id, legal_name, registration_number, country_code });
await admin.approveOrganizationVerification(verificationId, { reviewed_by });
await admin.approveSandbox(tenantId, integrationId);
await admin.requestIntegrationCertificationStage(tenantId, integrationId);
await admin.approveProduction(tenantId, integrationId, { approved_by });
await admin.activateIntegration(tenantId, integrationId);
await admin.createIntegrationEnvironment(tenantId, integrationId, { environment: "production" });
await admin.bindIntegrationCredential(tenantId, environmentId, { credential_type: "api-key", raw_credential });
await admin.rotateIntegrationCredentialBinding(tenantId, credentialBindingId, { raw_credential, reason });
// The unified audit timeline's two source streams (see /integration-governance)
await admin.listIntegrationGovernanceAuditEvents(tenantId, { integration_id: integrationId });
await admin.listPrincipalAuditEvents({ principal_id: principalId });CarcRuntimeClient
The narrowest client — exactly two public methods, constructed with an integrationCredential (an opaque IntegrationCredentialBinding reference, never a management credential):
ts
import { CarcRuntimeClient } from "@giggle-ai/runtime-sdk";
const runtimeExec = new CarcRuntimeClient({
baseUrl: process.env.CARC_RUNTIME_API_URL!,
integrationCredential: process.env.CARC_INTEGRATION_CREDENTIAL!,
});
const result = await runtimeExec.executeRegisteredAgent("openai-discharge-summary-agent", {
caseId: "case_demo_001",
taskType: "discharge_summary",
subjectType: "patient",
subjectContext,
sourceReferences,
instructions: "Draft a discharge summary.",
});
runtimeExec.getLastCorrelationId();A management credential presented here is rejected (credential_not_bound, 403) — never silently treated as "no credential presented". See Model Provider Adapters for the full managed- execution architecture this method drives, and Integration Governance & Identity for what must be true (active integration, active environment, active agent binding, active unexpired credential binding, current unexpired certification) before this call succeeds at all.
Examples in the monorepo
packages/runtime-sdk/examples/admin-principal-lifecycle.ts— a fullCarcAdminClientwalkthrough: create a principal, grant a tenant membership, issue/rotate/revoke a credential.packages/runtime-sdk/examples/runtime-execute.ts— aCarcRuntimeClientwalkthrough, including thecredential_not_bounderror path.examples/quickstart-external-agent/— the full Quickstart flowexamples/reference-integrations/— three distinct end-to-end scenarios (see Reference Integrations)examples/openai-clinical-agent/— genuinely needs all three clients side by side (adapter reads, agent registry, and managed execution) — the concrete illustration of why they're separate classes, not one.