> 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.

# ESLint Plugin

**Package**: `@mima-ai/eslint-plugin-mima` · **Version**: 0.1.x

The ESLint plugin catches AI library calls that are not wrapped with
`mima.attest()` at lint time — before the guard can detect them at runtime,
and before the TypeScript SDK can wrap them.

It answers the question: *"Do I have unattested AI calls in my TypeScript/JavaScript code?"*

---

## Install

```bash
npm install --save-dev @mima-ai/eslint-plugin-mima
```

---

## Configure

### ESLint flat config (recommended, ESLint 8+)

```javascript
// eslint.config.js
import mima from '@mima-ai/eslint-plugin-mima';

export default [
  {
    plugins: { mima },
    rules: {
      'mima/no-unattested-ai-call': 'error',
    },
  },
];
```

### Legacy `.eslintrc`

```json
{
  "plugins": ["@mima-ai/mima"],
  "rules": {
    "@mima-ai/mima/no-unattested-ai-call": "error"
  }
}
```

---

## Rule: `no-unattested-ai-call`

Flags direct calls to AI library methods that are not inside a `mima.wrap()`
or `mima.push()` call.

### What it detects

```typescript
// Error — unattested OpenAI call
const response = await openai.chat.completions.create({ ... });

// Error — unattested Anthropic call
const msg = await anthropic.messages.create({ ... });
```

### What it allows

```typescript
// OK — wrapped with mima
const generate = mima.wrap('generate', async (prompt: string) => {
  return await openai.chat.completions.create({ ... });
});

// OK — explicit push handles attestation separately
const result = await pipeline.run(input);
await mima.push('pipeline', inputHash, outputHash);
```

---

## AI libraries detected

| Library                         | Methods flagged                                                |
| ------------------------------- | -------------------------------------------------------------- |
| `openai`                        | `chat.completions.create`, `completions.create`                |
| `@anthropic-ai/sdk`             | `messages.create`, `messages.stream`                           |
| `@google/generative-ai`         | `generateContent`, `generateContentStream`                     |
| `@azure/openai`                 | `getChatCompletions`, `streamChatCompletions`                  |
| `ai` (Vercel AI SDK)            | `generateText`, `streamText`, `generateObject`, `streamObject` |
| `langchain` / `@langchain/core` | `invoke`, `stream`, `batch`                                    |
| `cohere-ai`                     | `chat`, `generate`, `embed`                                    |
| `@mistralai/mistralai`          | `chat`, `chatStream`                                           |

---

## Severity levels

```javascript
// Warn in development, error in CI:
'mima/no-unattested-ai-call': process.env.CI ? 'error' : 'warn'
```

---

## Inline disable

When you intentionally make an unattested call (e.g. a health-check ping):

```typescript
// eslint-disable-next-line mima/no-unattested-ai-call
const ping = await openai.models.list();
```

---

## CI integration

Add to your CI pipeline to block merges with unattested AI calls:

```yaml
# .github/workflows/lint.yml
- name: Lint
  run: npx eslint src --ext .ts,.tsx
```

The rule reports a non-zero exit code on violations, blocking the merge.

---

## Relationship to the runtime guard

| Layer                    | When it runs             | What it catches                              |
| ------------------------ | ------------------------ | -------------------------------------------- |
| ESLint plugin            | At lint time / in editor | Statically detectable unattested calls       |
| Python OTEL guard        | At runtime               | All unattested calls, including dynamic ones |
| TypeScript `mima.wrap()` | At the call site         | Forces wrapping at the source                |

Use all three for defence-in-depth. The ESLint plugin is the earliest
signal; the runtime guard catches what static analysis misses.