> ## Documentation Index
> Fetch the complete documentation index at: https://docs.morphllm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# WarpGrep API

> Agentic code search subagent that explores repositories in ~6 seconds

## Overview

WarpGrep is a code search agent that uses a multi-turn conversation to explore repositories. The model has its tools (`grep_search`, `read`, `list_directory`, `glob`, `finish`) **built in** — you do not need to pass a `tools` array in your requests.

## Model

Use `morph-warp-grep-v2.1` as the model identifier.

## Message Format

WarpGrep uses a structured format in the initial user message with **flat absolute paths**:

```xml theme={null}
<repo_structure>
/home/user/myproject
/home/user/myproject/README.md
/home/user/myproject/package.json
/home/user/myproject/src
/home/user/myproject/src/auth
/home/user/myproject/src/auth/login.py
/home/user/myproject/src/db
/home/user/myproject/src/utils
/home/user/myproject/tests
/home/user/myproject/config.py
/home/user/myproject/main.py
</repo_structure>

<search_string>
Find where user authentication is implemented
</search_string>
```

### Format Components

* **`<repo_structure>`**: Flat list of absolute paths — repo root first, then all files/directories to depth 2. No indentation, no tree characters, no trailing `/` on directories.
* **`<search_string>`**: Natural language description of what code to find

## Example Request

<CodeGroup>
  ```typescript TypeScript theme={null}
  import OpenAI from "openai";

  const openai = new OpenAI({
    apiKey: "YOUR_API_KEY",
    baseURL: "https://api.morphllm.com/v1",
  });

  const repoRoot = "/home/user/myapp";
  const repoStructure = `${repoRoot}
  ${repoRoot}/src
  ${repoRoot}/src/auth
  ${repoRoot}/src/api
  ${repoRoot}/src/models
  ${repoRoot}/tests
  ${repoRoot}/package.json`;

  const searchQuery = "Find where JWT tokens are validated";

  const response = await openai.chat.completions.create({
    model: "morph-warp-grep-v2.1",
    messages: [
      {
        role: "user",
        content: `<repo_structure>\n${repoStructure}\n</repo_structure>\n\n<search_string>\n${searchQuery}\n</search_string>`
      }
    ],
    temperature: 0.0,
    max_tokens: 2048
  });

  // Response has tool_calls — execute locally and continue the loop
  const toolCalls = response.choices[0].message.tool_calls;
  ```

  ```python Python theme={null}
  from openai import OpenAI

  client = OpenAI(
      api_key="YOUR_API_KEY",
      base_url="https://api.morphllm.com/v1"
  )

  repo_root = "/home/user/myapp"
  repo_structure = f"""{repo_root}
  {repo_root}/src
  {repo_root}/src/auth
  {repo_root}/src/api
  {repo_root}/src/models
  {repo_root}/tests
  {repo_root}/package.json"""

  search_query = "Find where JWT tokens are validated"

  response = client.chat.completions.create(
      model="morph-warp-grep-v2.1",
      messages=[
          {
              "role": "user",
              "content": f"<repo_structure>\n{repo_structure}\n</repo_structure>\n\n<search_string>\n{search_query}\n</search_string>"
          }
      ],
      temperature=0.0,
      max_tokens=2048,
  )

  # Response has tool_calls — execute locally and continue the loop
  tool_calls = response.choices[0].message.tool_calls
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.morphllm.com/v1/chat/completions" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "morph-warp-grep-v2.1",
      "messages": [
        {
          "role": "user",
          "content": "<repo_structure>\n/home/user/myapp\n/home/user/myapp/src\n/home/user/myapp/src/auth\n</repo_structure>\n\n<search_string>\nFind where JWT tokens are validated\n</search_string>"
        }
      ],
      "temperature": 0.0,
      "max_tokens": 2048
    }'
  ```
</CodeGroup>

<Note>See [Direct API Access](/sdk/components/warp-grep/direct) for the full protocol details including tool execution and multi-turn flow.</Note>

## Multi-Turn Conversation

WarpGrep uses built-in tool calling (up to 6 turns). The agent will:

1. **Turn 1**: Analyze your search query and call tools (`grep_search`, `list_directory`, `glob`) to explore
2. **Turns 2-5**: Refine search based on results, read specific files
3. **Final turn**: Call `finish` with code locations

You execute tool calls locally and return results as `{role: "tool", tool_call_id: "...", content: "..."}` messages.

## Request Parameters

| Parameter     | Type   | Required | Description                                  |
| ------------- | ------ | -------- | -------------------------------------------- |
| `model`       | string | Yes      | Must be `morph-warp-grep-v2.1`               |
| `messages`    | array  | Yes      | Array of conversation messages               |
| `temperature` | number | No       | Recommended: `0.0` for deterministic results |
| `max_tokens`  | number | No       | Recommended: `2048`                          |

<Note>Tools are built into the model — you do **not** need to pass a `tools` parameter. The model will return `tool_calls` automatically.</Note>

## Response Format

The agent responds with structured `tool_calls`:

```json theme={null}
{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1234567890,
  "model": "morph-warp-grep-v2.1",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {"id": "chatcmpl-tool-abc123", "type": "function", "function": {"name": "grep_search", "arguments": "{\"pattern\": \"jwt|JWT\"}"}},
        {"id": "chatcmpl-tool-def456", "type": "function", "function": {"name": "list_directory", "arguments": "{\"command\": \"ls src/auth\"}"}}
      ]
    },
    "finish_reason": "tool_calls"
  }],
  "usage": {
    "prompt_tokens": 1180,
    "total_tokens": 1245,
    "completion_tokens": 65
  }
}
```

After you execute tools and return results, the agent continues until it calls `finish`.

<Note>
  On tool-call turns the assistant `content` is `null`. Read only the `tool_calls` array.
</Note>

## Available Tools

WarpGrep uses five tools:

* **`grep_search`**: Search for regex patterns across files. Case-insensitive by default.
* **`read`**: Read file contents with optional line ranges
* **`list_directory`**: Explore directory structure
* **`glob`**: Find files by name/extension pattern (sorted by mtime)
* **`finish`**: Submit final answer with code locations. Paths are **absolute**, matching the paths from the repo structure.

See the [Direct API Guide](/sdk/components/warp-grep/direct) for complete tool specifications.

<Warning>
  Implement your tools to tolerate loose argument types. The model may send `limit` or `case_sensitive` as strings (`"50"`, `"false"`), and `grep_search` may emit undocumented arguments such as `output_lines` (an alias for `limit`) or `output_context_lines`. Coerce known keys and ignore unrecognized ones rather than erroring. See the [Direct API Guide](/sdk/components/warp-grep/direct#tool-definitions) for the full schema and robustness rules.
</Warning>

## SDK Integration

For easier integration, use the WarpGrep SDK components:

* **[TypeScript Tool](/sdk/components/warp-grep/tool)**: Drop-in tool for AI SDKs
* **[Python Guide](/guides/warp-grep-python)**: Complete Python implementation

## Error Codes

<Table>
  <TableHead>
    <TableRow>
      <TableHeader>HTTP Status</TableHeader>
      <TableHeader>Description</TableHeader>
    </TableRow>
  </TableHead>

  <TableBody>
    <TableRow>
      <TableCell>
        <code>200</code>
      </TableCell>

      <TableCell>Success - chat completion response with tool\_calls</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>
        <code>400</code>
      </TableCell>

      <TableCell>Bad request - malformed request or parameters</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>
        <code>401</code>
      </TableCell>

      <TableCell>Authentication error - invalid API key</TableCell>
    </TableRow>
  </TableBody>
</Table>

<CardGroup cols={2}>
  <Card title="Direct API Guide" icon="code" href="/sdk/components/warp-grep/direct">
    Build your own WarpGrep harness
  </Card>

  <Card title="Python Implementation" icon="book" href="/guides/warp-grep-python">
    Complete Python guide with examples
  </Card>
</CardGroup>


## OpenAPI

````yaml POST /v1/chat/completions
openapi: 3.1.0
info:
  title: Morph API
  version: 1.1.0
  description: >-
    The Morph public API at api.morphllm.com: OpenAI- and Anthropic-compatible
    inference (chat completions, messages), Fast Apply code editing, Compact
    context compression, Reflex classification, and fine-tuning. Model ids,
    prices, and context windows are served live at
    https://www.morphllm.com/api/models/json.
  contact:
    name: Morph
    url: https://morphllm.com
    email: info@morphllm.com
  license:
    name: Proprietary
    url: https://morphllm.com/privacy/tos
servers:
  - url: https://api.morphllm.com
    description: Production
security: []
tags:
  - name: chat
    description: >-
      OpenAI- and Anthropic-compatible chat inference, including Fast Apply and
      WarpGrep models.
  - name: compact
    description: Context compression for long agent conversations.
  - name: reflex
    description: 'Per-turn classifiers: realtime prediction and batches.'
  - name: fine-tuning
    description: Reflex fine-tuning job lifecycle.
  - name: models
    description: Model listing and management.
  - name: telemetry
    description: Usage reporting hooks.
paths:
  /v1/chat/completions:
    post:
      tags:
        - chat
      summary: Create a chat completion
      description: >-
        Apply changes from big models into your files. Find your [API
        key](https://morphllm.com/dashboard). The endpoint is OpenAI-compatible
        and serves two request shapes, selected by `model`: Morph Apply
        (`morph-v3-fast`, `morph-v3-large`, `auto`) merges an edit snippet into
        an original file, and Warp Grep (`morph-warp-grep-v1`) runs an agentic
        repository search. Set `stream: true` to receive the completion as a
        `text/event-stream` of `chat.completion.chunk` deltas; the 200 response
        below documents the non-streaming shape.
      operationId: createChatCompletion
      requestBody:
        description: Chat completion request for Apply or Warp Grep (OpenAI-compatible)
        required: true
        content:
          application/json:
            example:
              model: morph-v3-fast
              messages:
                - role: user
                  content: |-
                    <instruction>I will add error handling</instruction>
                    <code>function divide(a, b) {
                      return a / b;
                    }</code>
                    <update>function divide(a, b) {
                      if (b === 0) throw new Error('Division by zero');
                      return a / b;
                    }</update>
              stream: false
              max_tokens: 150
              temperature: 0
            schema:
              anyOf:
                - $ref: '#/components/schemas/ChatCompletionRequest'
                - $ref: '#/components/schemas/WarpGrepRequest'
              description: >-
                Either a Morph Apply request or a Warp Grep request,
                discriminated by `model`.
              example:
                model: morph-v3-fast
                messages:
                  - role: user
                    content: |-
                      <instruction>I will add error handling</instruction>
                      <code>function divide(a, b) {
                        return a / b;
                      }</code>
                      <update>function divide(a, b) {
                        if (b === 0) throw new Error('Division by zero');
                        return a / b;
                      }</update>
                stream: false
                max_tokens: 150
                temperature: 0
      responses:
        '200':
          description: Chat completion response
          content:
            application/json:
              example:
                id: chatcmpl-123
                object: chat.completion
                created: 1677652288
                choices:
                  - index: 0
                    message:
                      role: assistant
                      content: |

                        def calculate_total(items):
                            total = 0
                            for item in items:
                                total += item.price
                            return total * 1.1  # Add 10% tax
                    finish_reason: stop
                usage:
                  prompt_tokens: 25
                  completion_tokens: 32
                  total_tokens: 57
              schema:
                $ref: '#/components/schemas/ChatCompletionResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - bearerAuth: []
components:
  schemas:
    ChatCompletionRequest:
      type: object
      properties:
        model:
          type: string
          enum:
            - morph-v3-fast
            - morph-v3-large
            - auto
          default: morph-v3-fast
          description: ID of the Apply model to use, or `auto` to let the router choose
          example: morph-v3-fast
        messages:
          type: array
          items:
            $ref: '#/components/schemas/Message'
          default:
            - role: user
              content: |-
                <instruction>I will add error handling</instruction>
                <code>function divide(a, b) {
                  return a / b;
                }</code>
                <update>function divide(a, b) {
                  if (b === 0) throw new Error('Division by zero');
                  return a / b;
                }</update>
          description: >-
            Array containing a single user message with structured content using
            instruction-guided format
          example:
            - role: user
              content: |-
                <instruction>I will add error handling</instruction>
                <code>function divide(a, b) {
                  return a / b;
                }</code>
                <update>function divide(a, b) {
                  if (b === 0) throw new Error('Division by zero');
                  return a / b;
                }</update>
        stream:
          type: boolean
          default: false
          description: >-
            Enable streaming response. When true the response is a
            `text/event-stream` of OpenAI-style `chat.completion.chunk` deltas
            terminated by `data: [DONE]`.
          example: false
        max_tokens:
          type: integer
          description: Maximum number of tokens the Apply model may generate
          example: 150
        temperature:
          type: number
          default: 0
          description: >-
            Sampling temperature for the Apply request (0.0 for deterministic
            output)
          example: 0
      required:
        - model
        - messages
      title: Morph Apply
      description: >-
        Apply request — merges an edit snippet into the original file with a
        Morph Apply model.
      example:
        model: morph-v3-fast
        messages:
          - role: user
            content: |-
              <instruction>I will add error handling</instruction>
              <code>function divide(a, b) {
                return a / b;
              }</code>
              <update>function divide(a, b) {
                if (b === 0) throw new Error('Division by zero');
                return a / b;
              }</update>
        stream: false
        max_tokens: 150
        temperature: 0
    WarpGrepRequest:
      type: object
      properties:
        model:
          type: string
          enum:
            - morph-warp-grep-v1
          default: morph-warp-grep-v1
          description: ID of the Warp Grep model
          example: morph-warp-grep-v1
        messages:
          type: array
          items:
            $ref: '#/components/schemas/WarpGrepMessage'
          description: >-
            Multi-turn conversation with system prompt, user queries, assistant
            tool calls, and tool results
          example:
            - role: system
              content: You are a code search agent...
            - role: user
              content: |-
                <repo_structure>
                myapp/
                  src/
                    auth/
                </repo_structure>

                <search_string>
                Find JWT validation
                </search_string>
        temperature:
          type: number
          default: 0
          description: Sampling temperature (0.0 recommended for deterministic search)
          example: 0
        max_tokens:
          type: integer
          description: Maximum tokens per response
          default: 2048
          example: 2048
      required:
        - model
        - messages
      title: Warp Grep
      description: >-
        Warp Grep request — an agentic repository search turn driven by XML tool
        calls.
      example:
        model: morph-warp-grep-v1
        messages:
          - role: system
            content: You are a code search agent...
          - role: user
            content: |-
              <repo_structure>
              myapp/
                src/
                  auth/
              </repo_structure>

              <search_string>
              Find JWT validation
              </search_string>
        temperature: 0
        max_tokens: 2048
    ChatCompletionResponse:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/ResponseId'
        object:
          $ref: '#/components/schemas/ResponseObject'
        created:
          $ref: '#/components/schemas/ResponseCreated'
        choices:
          $ref: '#/components/schemas/ResponseChoices'
        usage:
          $ref: '#/components/schemas/ResponseUsage'
      required:
        - id
        - object
        - created
        - choices
        - usage
      description: Completion returned by a Morph chat model.
      example:
        id: chatcmpl-123
        object: chat.completion
        created: 1677652288
        choices:
          - index: 0
            message:
              role: assistant
              content: |

                def calculate_total(items):
                    total = 0
                    for item in items:
                        total += item.price
                    return total * 1.1  # Add 10% tax
            finish_reason: stop
        usage:
          prompt_tokens: 25
          completion_tokens: 32
          total_tokens: 57
    Message:
      type: object
      properties:
        role:
          type: string
          enum:
            - system
            - user
            - assistant
          description: Which participant produced this chat message
          example: user
        content:
          type: string
          description: >-
            The content of the message, containing code and update snippets. An
            Apply message uses the format: <instruction>First-person
            description</instruction><code>Complete original file
            content</code><update>Code snippet with // ... existing code ...
            markers</update>
          example: |-
            <instruction>I will add logic to add 10% tax</instruction>
            <code>def calculate_total(items):
                total = 0
                for item in items:
                    total += item.price
                return total</code>
            <update>def calculate_total(items):
                total = 0
                for item in items:
                    total += item.price
                return total * 1.1  # Add 10% tax</update>
      required:
        - role
        - content
      description: A single chat message.
      example:
        role: user
        content: |-
          <instruction>I will add logic to add 10% tax</instruction>
          <code>def calculate_total(items):
              total = 0
              for item in items:
                  total += item.price
              return total</code>
          <update>def calculate_total(items):
              total = 0
              for item in items:
                  total += item.price
              return total * 1.1  # Add 10% tax</update>
    WarpGrepMessage:
      type: object
      properties:
        role:
          type: string
          enum:
            - system
            - user
            - assistant
          description: Which participant produced this Warp Grep turn
          example: user
        content:
          type: string
          description: >-
            Message content. User messages use <repo_structure> and
            <search_string> XML. Assistant messages contain <think> reasoning
            and XML tool calls (<grep>, <read>, <list_directory>, <finish>).
          example: |-
            <repo_structure>
            myapp/
              src/
                auth/
            </repo_structure>

            <search_string>
            Find where JWT tokens are validated
            </search_string>
      required:
        - role
        - content
      description: A single turn in a Warp Grep search conversation.
      example:
        role: user
        content: |-
          <repo_structure>
          myapp/
            src/
              auth/
          </repo_structure>

          <search_string>
          Find where JWT tokens are validated
          </search_string>
    ResponseId:
      type: string
      description: Unique identifier for the completion
      example: chatcmpl-123
    ResponseObject:
      type: string
      description: Always `chat.completion`
      example: chat.completion
    ResponseCreated:
      type: integer
      description: Unix timestamp of when the completion was created
      example: 1677652288
    ResponseChoices:
      type: array
      items:
        $ref: '#/components/schemas/Choice'
      description: List of completion choices
      example:
        - index: 0
          message:
            role: assistant
            content: |

              def calculate_total(items):
                  total = 0
                  for item in items:
                      total += item.price
                  return total * 1.1  # Add 10% tax
          finish_reason: stop
    ResponseUsage:
      type: object
      properties:
        prompt_tokens:
          type: integer
          description: Number of tokens in the prompt
          example: 25
        completion_tokens:
          type: integer
          description: Number of tokens in the completion
          example: 32
        total_tokens:
          type: integer
          description: Total number of tokens used
          example: 57
      description: Usage statistics for the completion request
      example:
        prompt_tokens: 25
        completion_tokens: 32
        total_tokens: 57
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              example: invalid_request_error
              description: Machine-readable error code.
            message:
              type: string
              example: The request body is missing the `model` field.
              description: Human-readable explanation of the failure.
          required:
            - code
            - message
      required:
        - error
      description: Standard error envelope returned by every non-2xx response.
      example:
        error:
          code: invalid_request_error
          message: The request body is missing the `model` field.
    Choice:
      type: object
      properties:
        index:
          type: integer
          description: Index of the choice in the list
          example: 0
        message:
          type: object
          properties:
            role:
              type: string
              description: Author of the generated message, always `assistant`
              example: assistant
            content:
              type: string
              description: Text generated by the model for this choice
              example: |

                def calculate_total(items):
                    total = 0
                    for item in items:
                        total += item.price
                    return total * 1.1  # Add 10% tax
          description: The message generated by the model
          example:
            role: assistant
            content: |

              def calculate_total(items):
                  total = 0
                  for item in items:
                      total += item.price
                  return total * 1.1  # Add 10% tax
        finish_reason:
          type: string
          description: The reason the model stopped generating tokens
          example: stop
      required:
        - index
        - message
        - finish_reason
      description: A single completion choice returned by the model.
      example:
        index: 0
        message:
          role: assistant
          content: |

            def calculate_total(items):
                total = 0
                for item in items:
                    total += item.price
                return total * 1.1  # Add 10% tax
        finish_reason: stop
  responses:
    BadRequest:
      description: Malformed request — missing or invalid fields.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: invalid_request_error
              message: The request body is missing the `model` field.
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: unauthorized
              message: Invalid API key provided.
    RateLimited:
      description: Rate limited — retry after the interval in the Retry-After header.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: rate_limited
              message: Too many requests. Retry in 12 seconds.
    InternalError:
      description: Internal error — safe to retry with backoff.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: internal_error
              message: Something went wrong on our side.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: opaque
      description: >-
        Morph API key, passed as `Authorization: Bearer sk-...`. Create keys at
        https://www.morphllm.com/dashboard/api-keys.

````