> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.mima.works/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.mima.works/_mcp/server.

# TypeScript SDK Reference

**Package**: `@mima-ai/governance` · **Version**: 0.1.x · **Node.js**: 18+

---

**Building a TypeScript AI agent?** You don't need this SDK. Configure the [MCP server](./mcp.md) in 4 lines and your agent has full governance evidence — no code changes, any language.

**Use this SDK when** your TypeScript app code calls AI APIs directly — LangChain chains, batch pipelines, CI scripts, or any workflow where you control the call site.

---

```bash
npm install @mima-ai/governance
```

Requires Node.js 18+ for native `fetch` and `crypto`. No runtime dependencies.

---

## Client setup

```typescript
import { MimaGovernance } from '@mima-ai/governance';

const mima = new MimaGovernance({
  apiKey: process.env.MIMA_API_KEY!,    // required
  systemName: 'my-ai-pipeline',          // required
  workspaceId: undefined,                // resolved from API key automatically
  baseUrl: 'https://api.mima.works',        // override for self-hosted
  agentName: undefined,                  // defaults to systemName
  signingKey: undefined,                 // 32-byte hex key for GRC signing
  authorisedBy: {
    identity: 'alice@example.com',
    role: 'ml-engineer',
  },
  onError: 'warn',                       // 'warn' | 'raise' | 'silent'
  batchFlushInterval: 30_000,            // ms
  batchMaxSize: 100,
});
```

### Environment variables

| Variable            | Purpose                              |
| ------------------- | ------------------------------------ |
| `MIMA_API_KEY`      | Alternative to passing `apiKey`      |
| `MIMA_WORKSPACE_ID` | Alternative to passing `workspaceId` |

---

## Attestation

### `mima.wrap()` — function wrapper

TypeScript's equivalent of Python's `@mima.attest()` decorator. Takes a function and returns a wrapped version that attests every call.

```typescript
const classify = mima.wrap('classify_document', async (doc: string) => {
  const resp = await anthropic.messages.create({
    model: 'claude-opus-4-6',
    messages: [{ role: 'user', content: `Classify: ${doc}` }],
  });
  return resp.content[0].type === 'text' ? resp.content[0].text : '';
});

const label = await classify(document); // attests automatically
```

**Parameters**

| Parameter              | Type                | Default        | Description                |
| ---------------------- | ------------------- | -------------- | -------------------------- |
| `toolName`             | `string`            | required       | Name of the tool / action  |
| `fn`                   | `Function`          | required       | Function to wrap           |
| `options.modelId`      | `string`            | —              | LLM model identifier       |
| `options.authorisedBy` | `AuthorisedBy`      | client default | Override for this call     |
| `options.mode`         | `'sync' \| 'batch'` | `'sync'`       | Push immediately or buffer |

The wrapped function always returns `Promise<TReturn>`. If the original function was sync, the return type becomes `Promise<OriginalReturnType>`.

---

### `mima.push()` — explicit attestation

Use when you have pre-computed hashes (e.g. from a pipeline step with its own hashing).

```typescript
import { createHash } from 'node:crypto';

const inputHash  = createHash('sha256').update(JSON.stringify(input)).digest('hex');
const outputHash = createHash('sha256').update(JSON.stringify(output)).digest('hex');

await mima.push('generate_report', inputHash, outputHash, {
  modelId: 'claude-opus-4-6',
  executedAt: new Date().toISOString(),
});
```

---

### `mima.trace()` — manual hash capture

Pass a callback. Call `ctx.setInput()` / `ctx.setOutput()` to capture hashes at the right moment.

```typescript
const result = await mima.trace('run_pipeline', async (ctx) => {
  ctx.setInput(inputDocs);
  const output = await pipeline.run(inputDocs);
  ctx.setOutput(output);
  ctx.setModelId('claude-opus-4-6');
  return output;
});
```

---

### `mima.batch()` — buffered bulk push

```typescript
await mima.batch(async (b) => {
  for (const item of workQueue) {
    const result = await processItem(item);
    b.add('process_item', { input: item, output: result });
  }
});
// All records flushed in a single batch request on exit.
```

---

## GRC evidence methods

All GRC methods are async and return `Promise<GrcResult>`:

```typescript
interface GrcResult {
  recordId: string;        // '' on failure
  recordType: RecordType;
  mappedControls: string[]; // e.g. ['EUAIA_ART9', 'ISO42001_6_1']
  detail: string;           // 'ok' on success
}
```

---

### `mima.worksRiskAssessment()`

```typescript
await mima.worksRiskAssessment(
  'loan-scorer',
  'high',
  'Automated credit scoring for consumer loans',
  {
    intendedPurpose: 'Score loan applications for human review',
    impactDomains: ['credit', 'consumer_finance'],
    art5SelfAssessment: true,   // certifies no Art.5 prohibited practices
    assessor: 'alice@example.com',
    annexIiiCategory: 'essential_services',  // required for high-risk
    environment: 'production',
    systemVersion: 'v2.1.0',
    technicalDocUrl: 'https://docs.internal/loan-scorer/annex-iv',
  },
);
```

`art5SelfAssessment: true` certifies no Art. 5 prohibited practices. Never set without explicit human confirmation.

---

### `mima.modelEvaluation()`

```typescript
await mima.modelEvaluation(
  'loan-scorer-v2.1',
  'holdout-q2-2026',
  0.94,
  {
    evaluatedBy: 'alice@example.com',
    evaluationType: 'quarterly',
    biasMetrics: { demographic_parity: 0.02, equal_opportunity: 0.01 },
    robustnessScore: 0.91,
    passedThreshold: true,
  },
);
```

---

### `mima.humanOversight()`

```typescript
await mima.humanOversight(
  'loan-app-48291',
  'approve',
  'reject',
  {
    reviewer: 'bob@example.com',
    rationale: 'Flagged for fraud indicators not in model training data',
    modelId: 'loan-scorer-v2.1',
  },
);
// override: true is inferred (approve !== reject)
```

---

### `mima.trainingDataGovernance()`

```typescript
await mima.trainingDataGovernance(
  'loan-scorer-v2.1',
  'training-set-2026-q1',
  2_400_000,
  {
    biasChecksPerformed: true,
    approvedBy: 'data-governance@example.com',
    dataSources: ['internal_originations', 'credit_bureau_x'],
    dataCategories: ['financial_history', 'demographics'],
    knownLimitations: 'Underrepresented: self-employed applicants pre-2020',
  },
);
```

---

### `mima.incidentReport()`

```typescript
await mima.incidentReport(
  'Model output hallucination on edge case inputs',
  'high',
  {
    description: 'Model returned invalid IBANs for 3 users on 2026-06-01',
    affectedSystems: ['payment-processor-ai'],
    detectedAt: '2026-06-01T14:22:00Z',
    authorityNotifiedAt: '2026-06-01T18:00:00Z',
  },
);
```

---

### `mima.accessReview()`

```typescript
await mima.accessReview(
  'contractor@external.com',
  'model-training-pipeline',
  false,
  {
    reviewedBy: 'alice@example.com',
    reviewType: 'periodic',
    reason: 'Contractor engagement ended 2026-05-31',
  },
);
```

---

### `mima.changeEvent()`

```typescript
await mima.changeEvent(
  'prompt_update',
  'alice@example.com',
  'Updated system prompt to add output format constraints',
  {
    environment: 'production',
    system: 'customer-support-ai',
    changeId: 'CHG-4821',
  },
);
```

---

### `mima.vendorRisk()`

```typescript
await mima.vendorRisk('OpenAI', 'high', {
  lastReviewed: '2026-06-01',
  findings: 2,
  contacts: ['security@openai.com'],
});
```

---

### `mima.policyAcknowledged()`

```typescript
await mima.policyAcknowledged(
  'AI Use Policy',
  'alice@example.com',
  {
    version: 'v3.1.0',
    acknowledgmentType: 'initial',
    policyUrl: 'https://internal.example.com/policies/ai-use/v3.1.0',
    channel: 'in-app',
  },
);
```

---

### `mima.modelDriftEvent()`

```typescript
await mima.modelDriftEvent(
  'loan-scorer-v2.1',
  'f1_score',
  0.94,
  0.88,
  0.90,
  {
    driftType: 'performance',
    detectedBy: 'monitoring-agent',
    actionTaken: 'Model retraining scheduled for 2026-07-01',
  },
);
```

---

### `mima.governanceReview()`

```typescript
await mima.governanceReview(
  'ciso@example.com',
  'quarterly',
  {
    frameworksReviewed: ['EU_AI_ACT', 'ISO_42001', 'SOC2'],
    overallReadiness: 78,
    actionItems: 4,
    notes: 'Three open gaps in Art.9 documentation.',
  },
);
```

---

## Lifecycle

Always call `mima.close()` at the end of a long-running process or serverless function. It flushes any buffered batch records.

```typescript
// Express / Next.js — on shutdown
process.on('SIGTERM', async () => {
  await mima.close();
  process.exit(0);
});

// Lambda / serverless — at the end of each handler
export const handler = async (event: APIGatewayEvent) => {
  try {
    return await handleRequest(event);
  } finally {
    await mima.close();
  }
};
```

The client also registers `process.once('beforeExit', ...)` as a safety net.

---

## Signing GRC records

Pass a 32-byte hex key to enable HMAC-SHA256 signing. Every GRC push includes `client_sig` and `client_sig_algo: "hmac-sha256"`.

```typescript
import { randomBytes } from 'node:crypto';
// Generate once and store in a secrets manager:
const signingKey = randomBytes(32).toString('hex');

const mima = new MimaGovernance({
  apiKey: '...',
  systemName: '...',
  signingKey,
});
```

The canonical message is cross-compatible with the Python SDK — signatures generated by either SDK verify against each other.

---

## ESM setup

The package is ESM-only. In a CommonJS project, use dynamic import:

```javascript
// CommonJS
const { MimaGovernance } = await import('@mima-ai/governance');
```

For mixed projects, add `"type": "module"` to your `package.json` and rename `.js` files to `.mjs` as needed.

---

## Error handling

### Error modes

| `onError`          | Behaviour                                                  |
| ------------------ | ---------------------------------------------------------- |
| `'warn'` (default) | `console.warn` and return an empty result (`recordId: ''`) |
| `'raise'`          | Throw `MimaAttestationError`                               |
| `'silent'`         | Swallow errors entirely, return empty result               |

### Catching errors

```typescript
import { MimaGovernance, MimaAttestationError } from '@mima-ai/governance';

const mima = new MimaGovernance({ ..., onError: 'raise' });

try {
  await mima.push('tool', inputHash, outputHash);
} catch (err) {
  if (err instanceof MimaAttestationError) {
    logger.error('Governance record failed:', err.message);
  }
}
```

### Detecting failure without raising

```typescript
const result = await mima.push('tool', inputHash, outputHash);
if (!result.recordId) {
  logger.warn('Push failed:', result.detail);
}
```

The pattern is the same for all GRC methods — `result.recordId === ''` means failure.

### Network and rate limits

| Scenario              | Behaviour                                                 |
| --------------------- | --------------------------------------------------------- |
| Network timeout       | 15 s hardcoded; triggers error mode                       |
| HTTP 429 (rate limit) | Retries after `Retry-After` header; limit is 2000 req/min |
| HTTP 401/403          | Invalid or expired API key; triggers error mode           |
| HTTP 5xx              | Server error; triggers error mode (no automatic retry)    |

### Workspace ID resolution

If you omit `workspaceId`, the SDK resolves it from your API key on first call. If resolution fails (invalid key, network error), you get:

```
MimaAttestationError: workspaceId not set and could not be resolved automatically
```

Fix: pass `workspaceId` explicitly or set `MIMA_WORKSPACE_ID`.

### Batch flush on shutdown

Call `await mima.shutdown()` before process exit. Unflushed batch records are lost if the process terminates without shutdown. `shutdown()` flushes remaining records and throws `MimaAttestationError` (in `'raise'` mode) if the final flush fails.

---

## Type reference

All types are exported from `@mima-ai/governance` and available in your editor's autocomplete.

### Result types

```typescript
interface AttestationResult {
  attestationId: string;   // unique ID, empty string on failure
  externalVerified: boolean;
  trustTier: string;       // 'verified' | 'attested' | 'observed'
  detail: string;
}

interface GrcResult {
  recordId: string;        // unique ID, empty string on failure
  recordType: RecordType;
  mappedControls: string[];  // e.g. ['EUAIA_ART9', 'ISO42001_6_1']
  detail: string;
}
```

### Configuration

```typescript
interface MimaGovernanceOptions {
  apiKey: string;
  systemName: string;
  workspaceId?: string;        // auto-resolved from API key
  baseUrl?: string;            // default: 'https://api.mima.works'
  agentName?: string;          // defaults to systemName
  signingKey?: string;         // 32-byte hex, enables HMAC-SHA256 record signing
  authorisedBy?: AuthorisedBy;
  onError?: 'warn' | 'raise' | 'silent';
  batchFlushInterval?: number; // ms, default: 30000
  batchMaxSize?: number;       // default: 100
}

interface AuthorisedBy {
  identity: string;   // email or principal ID
  role?: string;
  sessionId?: string;
}
```

### Method options

```typescript
interface WrapOptions {
  modelId?: string;
  authorisedBy?: AuthorisedBy;
  mode?: 'sync' | 'batch';  // default: 'sync'
}

interface PushOptions {
  modelId?: string;
  authorisedBy?: AuthorisedBy;
  executedAt?: string;  // ISO timestamp, defaults to now
}
```

### GRC method options

Each GRC method accepts a typed options object:

| Method                     | Options type                    | Required fields                                                      |
| -------------------------- | ------------------------------- | -------------------------------------------------------------------- |
| `accessReview()`           | `AccessReviewOptions`           | `reviewedBy`                                                         |
| `changeEvent()`            | `ChangeEventOptions`            | `environment`, `system`                                              |
| `vendorRisk()`             | `VendorRiskOptions`             | `lastReviewed`                                                       |
| `policyAcknowledged()`     | `PolicyAcknowledgedOptions`     | `version`                                                            |
| `incidentReport()`         | `IncidentReportOptions`         | `description`, `affectedSystems`                                     |
| `aiRiskAssessment()`       | `AiRiskAssessmentOptions`       | `intendedPurpose`, `impactDomains`, `art5SelfAssessment`, `assessor` |
| `trainingDataGovernance()` | `TrainingDataGovernanceOptions` | `biasChecksPerformed`, `approvedBy`, `dataSources`, `dataCategories` |
| `modelEvaluation()`        | `ModelEvaluationOptions`        | `evaluatedBy`                                                        |
| `humanOversight()`         | `HumanOversightOptions`         | `reviewer`                                                           |
| `modelDriftEvent()`        | `ModelDriftEventOptions`        | `detectedBy`                                                         |
| `governanceReview()`       | `GovernanceReviewOptions`       | `frameworksReviewed`, `overallReadiness`                             |

### RecordType union

```typescript
type RecordType =
  | 'ai_risk_assessment'
  | 'governance_review'
  | 'model_evaluation'
  | 'training_data_governance'
  | 'human_oversight'
  | 'incident_report'
  | 'change_event'
  | 'access_review'
  | 'vendor_risk'
  | 'model_drift_event'
  | 'policy_acknowledged';
```