Skip to main content
Lesson 12 of 14 · Codestral and Coding Agents: From Devstral to Vibe Code

Automated Code Pipelines

Lesson 12 of 14 Updated November 2, 2026 Developer
On this page
  1. Automating Development with Codestral and a General-Purpose Model
  2. Architecture of a Code Pipeline
  3. Step 1: Code Search with Codestral Embed
  4. Step 2: Code Generation with Codestral
  5. Step 3: Code Review with Mistral Small 4
  6. Complete Pipeline: From Ticket to PR
  7. CI/CD Integration
  8. Common Production Variations
  9. Key Takeaways

Lesson updated November 2, 2026. The review step previously relied on Devstral, which was removed from the API on July 31, 2026. It now uses Mistral Small 4 (mistral-small-2603). Source: Models.

Automating Development with Codestral and a General-Purpose Model

So far, we have introduced each Mistral AI tool individually, operating in front of a human user. Their true value emerges when you chain them together. Codestral Embed, Codestral, and a general-purpose model like Mistral Small 4 form an automated development pipeline capable of searching, generating, and reviewing code without manual intervention at every step.

Architecture of a Code Pipeline

A complete pipeline breaks down into three stages, each assigned to the model that excels at that specific task.

  1. Code Search — Find relevant code in the codebase (Codestral Embed)
  2. Code Generation — Generate or modify code (Codestral)
  3. Code Review — Verify and validate changes (Mistral Small 4)

Read the data flow from top to bottom; each block consumes the output of the previous one.

User Request
    |
[Codestral Embed] -> Relevant Files
    |
[Codestral] -> Generated/Modified Code
    |
[Mistral Small 4] -> Automated Review
    |
Pull Request / Commit

Step 1: Code Search with Codestral Embed

Generating code without knowledge of the existing codebase produces results that look nothing like the rest of the project. The first step, therefore, is to locate the relevant files using the embedding index built in the previous lesson. The function below converts the task description into a vector, compares it against every indexed file, and returns the five closest matches.

from mistralai.client import Mistral
import numpy as np

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

def search_context(task_description: str, codebase_index: list) -> list:
    """Finds relevant files for a given task."""
    response = client.embeddings.create(
        model="codestral-embed-latest",
        inputs=[task_description],
    )
    vector = np.array(response.data[0].embedding)

    scores = []
    for file in codebase_index:
        file_vec = np.array(file["embedding"])
        score = np.dot(vector, file_vec) / (
            np.linalg.norm(vector) * np.linalg.norm(file_vec)
        )
        scores.append((file, score))

    scores.sort(key=lambda x: x[1], reverse=True)
    return [f for f, s in scores[:5]]

Step 2: Code Generation with Codestral

Once you have the context, Codestral can generate code. The quality of the output depends on how you present that context: concatenate the retrieved files into the system message, accompanied by an explicit instruction to respect existing conventions. Setting temperature=0.1 keeps the output close to deterministic, which is desirable when the generated code must integrate seamlessly into a project rather than surprise its author.

def generate_code(task: str, context: list[dict]) -> str:
    """Generates code taking existing context into account."""
    context_files = "\n\n---\n\n".join([
        f"# {f['path']}\n{f['content']}"
        for f in context
    ])

    response = client.chat.complete(
        model="codestral-latest",
        messages=[
            {
                "role": "system",
                "content": f"""You are a senior developer. Here is the existing project code:

{context_files}

Respect existing code conventions (naming, style, patterns)."""
            },
            {
                "role": "user",
                "content": task
            }
        ],
        temperature=0.1,
        max_tokens=2000,
    )

    return response.choices[0].message.content

Step 3: Code Review with Mistral Small 4

Control comes last. Mistral Small 4 receives the before state, the after state, and the task description, then renders its verdict in a strict JSON format. This choice is critical: free-form prose reviews are not usable by downstream code, whereas a boolean approved field allows you to automate the next steps. The requested categories deliberately separate blocking issues, improvement suggestions, and security concerns, as these require different handling.

def review_code(original_code: str, modified_code: str, description: str) -> dict:
    """Automated code review."""
    response = client.chat.complete(
        model="mistral-small-2603",
        messages=[
            {
                "role": "system",
                "content": """You are a senior code reviewer. Analyze the diff and return JSON:
{
    "approved": true/false,
    "issues": ["list of found issues"],
    "suggestions": ["list of possible improvements"],
    "security": ["potential security issues"]
}"""
            },
            {
                "role": "user",
                "content": f"Task: {description}\n\nOriginal code:\n{original_code}\n\nModified code:\n{modified_code}"
            }
        ],
        temperature=0,
    )

    return response.choices[0].message.content

Complete Pipeline: From Ticket to PR

You can now assemble these three functions into a single chain that starts with a ticket and outputs reviewed code. Keep the interleaved print statements: in an automated pipeline, logging what was found, generated, and reviewed is your only way to understand later why a result disappointed you.

def ticket_to_code_pipeline(ticket: str, codebase_index: list) -> dict:
    """Complete pipeline: ticket -> code -> review."""

    # 1. Contextual search
    relevant_files = search_context(ticket, codebase_index)
    print(f"Files found: {[f['path'] for f in relevant_files]}")

    # 2. Code generation
    generated_code = generate_code(ticket, relevant_files)
    print(f"Generated code: {len(generated_code)} characters")

    # 3. Automated review
    review = review_code(
        original_code=relevant_files[0]["content"],
        modified_code=generated_code,
        description=ticket,
    )
    print(f"Review: {review}")

    return {
        "ticket": ticket,
        "modified_files": relevant_files,
        "code": generated_code,
        "review": review,
    }

CI/CD Integration

This mechanism reaches its full potential when connected to your CI. A GitHub Actions workflow triggered on every pull request open and update is enough to run the review on every proposed change, with no human thought required.

name: AI Code Review
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  ai-review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run AI Review
        env:
          MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
        run: |
          python scripts/ai_review.py --pr ${{ github.event.pull_request.number }}

The called script retrieves the diff, passes each modified file to review_code, and comments on the PR only when the review does not approve. This condition is essential: a bot that comments on everything becomes noise that the team learns to ignore within days.

# scripts/ai_review.py
def review_pull_request(pr_number: int):
    """Automated PR review with Mistral Small 4."""
    # 1. Retrieve PR diff
    diff = get_pr_diff(pr_number)

    # 2. Analyze each modified file
    for file in diff.files:
        review = review_code(
            original_code=file.before,
            modified_code=file.after,
            description=diff.title,
        )

        # 3. Post comment on PR
        if not review["approved"]:
            post_pr_comment(pr_number, file.path, review)

Common Production Variations

Teams that adopt this pattern adapt it to several recurring use cases. First, automatic test generation: for every new file, the pipeline produces corresponding tests, shifting the chore without eliminating the review. Next, continuous documentation, where docstrings are generated and updated with each commit rather than during an audit. Then, regression detection, where the review model analyzes diffs for likely side effects. Finally, code migration, which automates conversion between frameworks or versions—this is where the time savings are most significant, because the transformation is repetitive and the result is verifiable by existing tests.

One caveat applies to all four: automated review does not replace human review. It catches mechanical oversights and leaves judgment on what truly matters to your developers.

Key Takeaways

  • An AI code pipeline combines search (Embed), generation (Codestral), and review (Mistral Small 4)
  • Codestral Embed finds context, Codestral generates, and a general-purpose model verifies
  • CI/CD integration enables automated reviews and test generation
  • The search -> generate -> review pattern applies to many workflows
  • Automated review does not replace human review; it complements it