---
title: Tasks
description: The building blocks of AI workflows.
icon: list-check
---

Tasks are the fundamental building blocks of AI workflows in Marvin. They represent discrete, well-defined objectives that need to be accomplished by an AI agent.

```python
import marvin

task = marvin.Task("Write the Marvin docs")
```

## What are tasks?

LLMs excel when given clear, specific instructions that allow them to focus their knowledge and capabilities on a well-defined goal. A `Task` in Marvin is a structured way to define these instructions and guide the AI's behavior. Each task represents a "checkpoint" that requires the AI to meet an observable, verifiable goal. In this way, tasks serve as a bridge between the structured world of traditional software and the more fluid, adaptive world of AI.

This task-centric approach allows you to leverage the full power of AI while maintaining precise oversight. Each task becomes a checkpoint where you can validate outputs, ensuring that the AI's work aligns with your application's requirements and constraints.

## Creating tasks

A task in Marvin typically consists of:

- Instructions: what needs to be accomplished
- Expected output: what form the result should have, including any constraints or validation
- Agent: the AI entity responsible for executing the task
- Tools: any additional capabilities needed to complete the task
- Memories: any relevant context or history that should be available to the agent

<Tip>
In practice, you will often use the `marvin.run` function to create and run a task in a single step. This is a common operation and accepts all the same arguments as creating a `Task` directly.
</Tip>

### Using the `Task` class

The most straightforward way to create a task is by using the `Task` class:

<CodeGroup>
```python Code
import marvin

task = marvin.Task(
    instructions="Write a poem about the provided topic",
    result_type=str,
    context={"topic": "AI"}
)

result = task.run()
print(result)
```

```text Result
In circuits deep and code profound,
An AI's mind begins to sound.
Electric thoughts and data streams,
Crafting worlds and shaping dreams.
```

</CodeGroup>

### Agents

The `agents` parameter specifies which AI agents are assigned to complete the task. If not provided, Marvin will use the default agent. You can provide either a single agent or a team of agents that will work together as a unit.

```python
import marvin

task = marvin.Task(
    instructions="Write a poem about AI",
    agents=[marvin.Agent(name="Marvin", model="openai:gpt-4o-mini")]
)
```

## Task properties

When creating a task, you can configure various properties to define its behavior and requirements. Here are the key configuration options:

### Instructions

The instructions of a task tell the agent what needs to be accomplished. This is the only required task configuration, as it indicates what the agent should do.

<CodeGroup>
```python Code
import marvin

poem = marvin.run(instructions="Write a poem about AI")

print(poem)
```

```text Result
In circuits deep and code profound,
An AI's mind begins to sound.
Electric thoughts and data streams,
Crafting worlds and shaping dreams.
```
</CodeGroup>

<Tip>
Instructions can be "meta", especially if you have an agent that is working on your workflow itself (e.g. monitoring progress, creating new tasks, etc.). Be creative!

<CodeGroup>
```python Code
import marvin

marvin.run("Write a poem... then fail this task.", allow_fail=True)
```

```text Result
ValueError: Task 04561cda ("Write a poem... then fail this task.")
failed: Task instructed to be marked as failed despite
no technical error
```
</CodeGroup>
</Tip>

### Result type

A task's result type indicates the type of value that the task will return. This is used to validate the task's result and to help agents understand the task's output.

A variety of different result types are supported, including:
- Builtin types: `str`, `int`, `bool`, `list`, `dict`, etc.
- `None`: sometimes a task requires agents to take actions but not return any specific value
- Builtin collections: `Tuple[int, str]`, `List[str]`, `Dict[str, int]`, etc.
- Annotated types: `Annotated[str, "a 5 digit zip code"]`
- Pydantic models
- Lists of literal values: provide a list of values to require the agent to choose one of them as its result. For example,`["book", "movie", "album"]` would require the agent to choose one of the three values.

The default result type is `str`.

Pydantic model example:
<CodeGroup>
```python Code
import marvin
from pydantic import BaseModel

class Name(BaseModel):
    first: str
    last: str

name = marvin.run("The input is 'John Doe'", result_type=Name)

print(repr(name))
```

```text Result
Name(first='John', last='Doe')
```
</CodeGroup>

Classification example:

<CodeGroup>
```python Code
import marvin

media = marvin.run(
    "Star Wars: Return of the Jedi",
    result_type=["book", "movie", "album"]
)

print(media)
```

```text Result
movie
```
</CodeGroup>

### Result validator

You can specify a custom validation function for the task's result using the task's `result_validator` parameter. This function will be called with the raw result and should return the validated result or raise an exception if the result is not valid.

```python
import marvin

def validate_even(value: int) -> int:
    if value % 2 != 0:
        raise ValueError("Value must be even")
    return value

number = marvin.run("Choose a number", result_validator=validate_even)

print(number)
```

### Context

The context of a task is a dictionary that provides additional information about the task. This information is visible to agents during execution, helping them understand the task they are working on.

<CodeGroup>
```python Code
import marvin

is_spam = marvin.run(
    "Is this email spam?",
    result_type=bool,
    context=dict(email='You just won a million dollars!'),
)

print(is_spam)
```

```text Result
True
```
</CodeGroup>

### Tools

The tools of a task are a list of tools that the task requires. These tools will be made available to the agent during execution.

<CodeGroup>
```python Code
import marvin
import random


def roll_dice(n_dice: int):
    return [random.randint(1, 6) for _ in range(n_dice)]

rolls = marvin.run(
    "Roll 3 dice",
    result_type=list[int],
    tools=[roll_dice],
)

print(rolls)
```

```text Result
[3, 1, 5]
```
</CodeGroup>

### Memories

Tasks can be configured with a list of memories that provide additional context to the agent. These memories can include relevant history, knowledge bases, or other information that helps the agent complete the task.

```python
import marvin
from marvin.memory import Memory

memory = Memory(key="documentation")
memory.add("Marvin is a powerful AI framework...")

task = marvin.Task(
    instructions="Explain what Marvin is",
    memories=[memory]
)
```

### Parent

Tasks can be configured with a parent task. Creating hierarchies of tasks can help agents understand the relationships between different tasks and to better understand the task they are working on.

### Task Planning

When a task is created with `plan=True`, the agent is given the ability to break down complex tasks into smaller, more manageable subtasks. This is particularly useful for handling large or complex objectives that benefit from being tackled incrementally.

The agent can create subtasks at any point during task execution, and these subtasks become part of the task hierarchy. Each subtask is treated as a dependency of the parent task, ensuring that all subtasks are completed before the parent task is considered finished.

```python
import marvin

task = marvin.Task(
    instructions="Write a comprehensive report about AI",
    plan=True  # Enable task planning
)
```

When planning is enabled, the agent can:
- Create one or more subtasks at any time
- Define clear, focused objectives for each subtask
- Establish dependencies between subtasks
- Monitor progress through the task hierarchy

This feature is especially valuable for:
- Breaking down complex tasks into manageable pieces
- Creating checkpoints in long-running processes
- Enabling parallel work on independent subtasks
- Maintaining clear progress tracking

### Depends on

Tasks can be configured with a list of tasks that they depend on. This information helps Marvin prioritize work and avoid running a task before its upstream dependencies are complete.

### Additional Options

Marvin tasks support several additional options to control their behavior:

- `allow_fail`: Whether the task is allowed to be marked as failed (default: False)
- `allow_skip`: Whether the task is allowed to be skipped (default: False)
- `cli`: Whether to enable CLI interaction tools for the agent (default: False)
- `plan`: Whether to enable task planning capabilities, allowing the agent to create subtasks to help complete the parent task (default: False)

## Runtime properties

The following properties of a `Task` are set during task execution, and can be examined as part of your workflow's logic.

### Status

The status of a task reflects whether an agent has started working on it, and what the ultimate outcome of that work was. Tasks are always created with a `PENDING` status, progress to a `RUNNING` status when the agent begins to work on it, and finally moves to one of a few completed statuses when the task is finished.

Agents use tools to mark tasks as `SUCCESSFUL` or `FAILED`. Successful tasks will also have a `result` property, which contains the task's final output. This is a value that satisfies the task's instructions and result type configuration. Failed tasks will have an error message as their result.

<CodeGroup>
```python Code
import marvin

task = marvin.Task("Write a poem about AI")
task.run()

print(task.status)
```

```text Result
TaskStatus.SUCCESSFUL
```
</CodeGroup>

In addition to checking the status explicitly, you can call a number of helper methods on the task:

| Method | Description |
|--------|-------------|
| `is_pending()` | Returns `True` if the task is pending. |
| `is_running()` | Returns `True` if the task is running. |
| `is_successful()` | Returns `True` if the task is successful. |
| `is_failed()` | Returns `True` if the task is failed. |
| `is_skipped()` | Returns `True` if the task is skipped. |
| `is_complete()` | Returns `True` if the task is complete (either successful, failed, or skipped) |
| `is_incomplete()` | Returns `True` if the task is incomplete (either pending or running) |
| `is_ready()` | Returns `True` if the task is ready to be worked on (i.e. all dependencies are complete but the task is incomplete) |

### Result

When a task is completed successfully, its `result` property will contain the task's final output. This is a value that satisfies the task's instructions and result type configuration.

If a task fails, its `result` property will contain an error message describing the failure.

<CodeGroup>
```python Code
import marvin

task = marvin.Task("Write a poem about AI")
task.run()

print(task.result)
```

```text Result
In circuits deep and code profound,
An AI's mind begins to sound.
Electric thoughts and data streams,
Crafting worlds and shaping dreams.
```
</CodeGroup>

### Tools and Context

Tasks in Marvin can be enhanced with tools and context:

- **Tools** are Python functions that the task can use to perform actions (like API calls or data retrieval)
- **Context** is additional information provided to help the task succeed

For example:

```python
import marvin
import datetime

def get_current_time() -> str:
    """Get the current date and time."""
    return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

task = marvin.Task(
    instructions="Tell me the current time and create a greeting appropriate for that time of day",
    tools=[get_current_time],
    context={"user_name": "Alex"}
)

result = task.run()
print(result)
```

For a comprehensive guide on working with tools and context, see the [Tools and Context](/concepts/tools-and-context) documentation.
