smithery/jeremylongshore

mistral-local-dev-loop

Configure Mistral AI local development with hot reload, testing, and mocking. Use when setting up a development environment, configuring test workflows, or establishing a fast iteration cycle with Mistral AI. Trigger with phrases like "mistral dev setup", "mistral local development", "mistral dev environment", "develop with mistral". '

Installation

$ npx skills add smithery/jeremylongshore --skill mistral-local-dev-loop

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/jeremylongshore · top by installs.

npx skills add smithery/jeremylongshore

Browse all from smithery/jeremylongshore

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.13.0
LicenseMIT
CompatibilityDesigned for Claude Code
Allowed toolsRead, Write, Edit, Bash(npm:*), Bash(pnpm:*), Grep
Declared agents claude-code

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 7,849 B
  • docs SUMMARY.md 359 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Mistral AI Local Dev Loop

Overview

Set up a fast, reproducible local development workflow for Mistral AI integrations: project scaffold, environment config, hot reload with tsx, unit tests with Vitest mocking, and integration tests against the live API.

Prerequisites

  • Completed mistral-install-auth setup
  • Node.js 18+ with npm/pnpm
  • MISTRALAPIKEY set in environment

Instructions

Step 1: Project Structure

my-mistral-project/
├── src/
│   ├── mistral/
│   │   ├── client.ts       # Singleton client
│   │   ├── config.ts       # Config with Zod validation
│   │   └── types.ts        # TypeScript types
│   └── index.ts
├── tests/
│   ├── unit/
│   │   └── mistral.test.ts
│   └── integration/
│       └── mistral.integration.test.ts
├── .env.local              # Local secrets (git-ignored)
├── .env.example            # Template for team
├── tsconfig.json
├── vitest.config.ts
└── package.json

Step 2: Package Configuration

package.json

{
  "type": "module",
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc",
    "test": "vitest run",
    "test:watch": "vitest",
    "test:integration": "vitest run tests/integration/",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@mistralai/mistralai": "^1.0.0"
  },
  "devDependencies": {
    "@types/node": "^20.0.0",
    "dotenv": "^16.0.0",
    "tsx": "^4.0.0",
    "typescript": "^5.0.0",
    "vitest": "^1.0.0"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Step 3: Environment Setup

# Create environment template
cat > .env.example << 'EOF'
MISTRAL_API_KEY=your-api-key-here
MISTRAL_MODEL=mistral-small-latest
LOG_LEVEL=debug
EOF

cp .env.example .env.local
echo '.env.local' >> .gitignore
echo '.env' >> .gitignore

Step 4: Client Module

// src/mistral/client.ts
import { Mistral } from '@mistralai/mistralai';
import 'dotenv/config';

let instance: Mistral | null = null;

export function getMistralClient(): Mistral {
  if (!instance) {
    const apiKey = process.env.MISTRAL_API_KEY;
    if (!apiKey) throw new Error('MISTRAL_API_KEY not set');
    instance = new Mistral({ apiKey, timeoutMs: 30_000 });
  }
  return instance;
}

export function resetClient(): void {
  instance = null;
}

Step 5: Unit Tests with Mocking

vitest.config.ts

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,
    environment: 'node',
    include: ['tests/**/*.test.ts'],
    coverage: { provider: 'v8', reporter: ['text', 'json'] },
  },
});

tests/unit/mistral.test.ts

import { describe, it, expect, vi, beforeEach } from 'vitest';

// Mock the entire SDK
vi.mock('@mistralai/mistralai', () => ({
  Mistral: vi.fn().mockImplementation(() => ({
    chat: {
      complete: vi.fn().mockResolvedValue({
        id: 'test-id',
        model: 'mistral-small-latest',
        choices: [{
          index: 0,
          message: { role: 'assistant', content: 'Mocked response' },
          finishReason: 'stop',
        }],
        usage: { promptTokens: 10, completionTokens: 5, totalTokens: 15 },
      }),
      stream: vi.fn().mockImplementation(async function* () {
        yield { data: { choices: [{ delta: { content: 'Streamed ' } }] } };
        yield { data: { choices: [{ delta: { content: 'response' } }] } };
      }),
    },
    embeddings: {
      create: vi.fn().mockResolvedValue({
        data: [{ embedding: new Array(1024).fill(0.1) }],
        usage: { totalTokens: 5 },
      }),
    },
    models: {
      list: vi.fn().mockResolvedValue({ data: [{ id: 'mistral-small-latest' }] }),
    },
  })),
}));

describe('Mistral Client', () => {
  beforeEach(() => { vi.clearAllMocks(); });

  it('should complete chat', async () => {
    const { Mistral } = await import('@mistralai/mistralai');
    const client = new Mistral({ apiKey: 'test' });

    const response = await client.chat.complete({
      model: 'mistral-small-latest',
      messages: [{ role: 'user', content: 'Test' }],
    });

    expect(response.choices?.[0]?.message?.content).toBe('Mocked response');
    expect(response.usage?.totalTokens).toBe(15);
  });

  it('should generate embeddings', async () => {
    const { Mistral } = await import('@mistralai/mistralai');
    const client = new Mistral({ apiKey: 'test' });

    const response = await client.embeddings.create({
      model: 'mistral-embed',
      inputs: ['test text'],
    });

    expect(response.data[0].embedding).toHaveLength(1024);
  });
});

Step 6: Integration Test (Live API)

// tests/integration/mistral.integration.test.ts
import { describe, it, expect } from 'vitest';
import { Mistral } from '@mistralai/mistralai';

const apiKey = process.env.MISTRAL_API_KEY;

describe.skipIf(!apiKey)('Mistral Integration', () => {
  const client = new Mistral({ apiKey: apiKey! });

  it('should list models', async () => {
    const models = await client.models.list();
    expect(models.data?.length).toBeGreaterThan(0);
  }, 10_000);

  it('should complete chat', async () => {
    const response = await client.chat.complete({
      model: 'mistral-small-latest',
      messages: [{ role: 'user', content: 'Reply with "ok"' }],
      maxTokens: 10,
      temperature: 0,
    });
    expect(response.choices?.[0]?.message?.content).toBeTruthy();
  }, 15_000);

  it('should generate embeddings', async () => {
    const response = await client.embeddings.create({
      model: 'mistral-embed',
      inputs: ['test'],
    });
    expect(response.data[0].embedding).toHaveLength(1024);
  }, 10_000);
});

Output

  • Working dev environment with hot reload (tsx watch)
  • Unit tests with full SDK mocking
  • Integration tests against live API (skip when no key)
  • Environment variable management with .env.local

Error Handling

Error Cause Solution
Module not found Missing dependency Run npm install
Env not loaded Missing .env.local Copy from .env.example
Integration timeout Slow API response Increase test timeout
Mock type errors SDK interface changed Update mock to match current SDK

Examples

Separate deterministic and paid checks

Run the mocked Vitest suite on every local change and CI pull request. Enable the integration suite only in a protected environment that supplies MISTRALAPIKEY; it should skip—not fail—when that secret is intentionally absent from an untrusted pull request.

Resources

Next Steps

See mistral-sdk-patterns for production-ready code patterns.