# Creating a task (https://www.agentenvframework.com/docs/tasks/creating)

> Define your task as a DAG of task steps

A task is a DAG of task steps. Each step does one thing, such as deploying an env, prompting an
agent or grading what it did, and its `depends_on` names the steps it waits for. You create a task by
composing it from task steps, written as a JSON list: no code. Pick a task to see its task.json, and
follow a run of it one wave at a time:

**Agent and env: `reply-to-dana`**

```json title="task.json"
[
  {"id": "email", "type": "deploy_env", "env_id": "email", "depends_on": []},
  {"id": "inbox", "type": "load_artifact", "env_id": "email", "artifact_id": "inbox", "depends_on": [{"task_step_id": "email"}]},
  {"id": "assistant", "type": "deploy_agent", "env_ids": ["email"], "a2a_agent_id": "claude-code", "agent_name": "assistant", "depends_on": [{"task_step_id": "email"}]},
  {"id": "reply", "type": "prompt_agent", "agent_name": "assistant", "prompt_id": "reply", "prompt": "Reply to Dana.", "depends_on": [{"task_step_id": "inbox"}, {"task_step_id": "assistant"}]},
  {"id": "check", "type": "env_outcome_verifier", "env_id": "email", "file_artifact_id": "check-reply", "verifier_id": "sent", "depends_on": [{"task_step_id": "reply"}]}
]
```

1. `email` waits for nothing, so the run starts it first. `deploy_env` deploys the env `email` as a new env instance and adds it to `deployed_envs`.
2. `inbox` and `assistant` both wait only for `email`, so they start together. `inbox` loads the environment artifact `inbox`, Dana’s email, into the instance. `assistant` starts the agent `claude-code` in its own sandbox with `email`’s MCP URL.
3. `reply` waits for both. It sends “Reply to Dana.” to `assistant` and waits for the agent to finish, then stores its reply and trajectory under the `prompt_id` `reply`.
4. `check` runs the `verify()` function in the file artifact `check-reply` against `email`’s MCP URL and stores the score under `verifications.sent`: 1.0 if Dana got a reply.
5. No step is left, so the run ends. The task instance’s record keeps every step’s status and the context they built, verifications included.

**Agent and judge: `chart-q3`**

```json title="task.json"
[
  {"id": "analyst", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "analyst", "depends_on": []},
  {"id": "judge", "type": "deploy_agent", "a2a_agent_id": "my-judge", "agent_name": "judge", "depends_on": []},
  {"id": "data", "type": "load_artifact", "agent_name": "analyst", "artifact_id": "q3-data", "depends_on": [{"task_step_id": "analyst"}]},
  {"id": "chart", "type": "prompt_agent", "agent_name": "analyst", "prompt_id": "chart", "prompt": "Chart q3.csv as a bar chart, one bar per month, and save it as q3.png.", "depends_on": [{"task_step_id": "data"}]},
  {"id": "collect", "type": "collect_artifacts", "agent_name": "analyst", "artifact_paths": ["q3.png"], "depends_on": [{"task_step_id": "chart"}]},
  {"id": "handoff", "type": "load_artifact", "agent_name": "judge", "artifact_from_step_id": "collect", "depends_on": [{"task_step_id": "collect"}, {"task_step_id": "judge"}]},
  {"id": "grade", "type": "rubrics_verifier", "agent_name": "judge", "prompt_id": "chart", "verifier_id": "chart", "score_aggregator": "weighted_average", "criteria": [{"id": "bars", "criterion": "q3.png is a bar chart with one bar per month of Q3.", "weight": 6}, {"id": "labels", "criterion": "Each bar is labelled with its month and value.", "weight": 3}, {"id": "title", "criterion": "The chart has a title.", "weight": 1}], "depends_on": [{"task_step_id": "handoff"}]}
]
```

1. There is no env. `analyst` and `judge` wait for nothing, so both agents deploy at once, each in its own sandbox: the analyst from `claude-code`, the judge from `my-judge`.
2. `data` loads the file artifact universe `q3-data` into the analyst’s sandbox, so `q3.csv` is there before the analyst is asked anything.
3. `chart` prompts the analyst to chart `q3.csv`. The judge has been ready since the first wave; nothing asks it anything yet.
4. `collect` copies `q3.png` out of the analyst’s sandbox into the object store and records it under `collected_artifacts.collect`, so it outlasts the sandbox.
5. `handoff` waited for `collect` and `judge`. With `artifact_from_step_id: collect`, it copies the files `collect` stored into the judge’s sandbox.
6. `grade` has the judge grade the analyst’s `chart` trajectory against the three criteria, with `q3.png` in its sandbox to open. With `weighted_average`, missing only the title scores 0.9, stored under `verifications.chart`.
7. The run ends. The chart is a file artifact now, and the judge that graded it was a different agent from the one that made it.

**Two agents: `talk-to-dana`**

```json title="task.json"
[
  {"id": "dana", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "dana", "system_prompt": "You are Dana. You want the Q3 numbers sent to Sam Lee in finance. Answer the assistant’s questions.", "depends_on": []},
  {"id": "email", "type": "deploy_env", "env_id": "email", "depends_on": []},
  {"id": "inbox", "type": "load_artifact", "env_id": "email", "artifact_id": "inbox", "depends_on": [{"task_step_id": "email"}]},
  {"id": "assistant", "type": "deploy_agent", "env_ids": ["email"], "a2a_agent_id": "claude-code", "agent_name": "assistant", "depends_on": [{"task_step_id": "email"}]},
  {"id": "talk", "type": "prompt_agent", "agent_name": "assistant", "prompt_id": "talk", "prompt": "Dana has emailed you. Help her.", "user_agent_name": "dana", "max_conversation_turns": 6, "depends_on": [{"task_step_id": "dana"}, {"task_step_id": "inbox"}, {"task_step_id": "assistant"}]},
  {"id": "grade", "type": "rubrics_verifier", "prompt_id": "talk", "verifier_id": "conversation", "score_aggregator": "weighted_average", "criteria": [{"id": "asks", "criterion": "The assistant finds out what Dana needs.", "weight": 2}, {"id": "sends", "criterion": "Sam Lee gets the Q3 numbers.", "weight": 2}, {"id": "confirms", "criterion": "The assistant tells Dana it is done.", "weight": 1}], "depends_on": [{"task_step_id": "talk"}]}
]
```

1. `dana` and `email` wait for nothing, so they start together. Dana is an agent too, deployed with a `system_prompt` that makes her play the user. She needs no env.
2. `inbox` loads Dana’s email into the `email` instance while `assistant` deploys with `email`’s MCP URL, as in `reply-to-dana`.
3. `talk` waits for all three. With `user_agent_name: dana` and `max_conversation_turns: 6`, each of the assistant’s replies goes to Dana, and her answer comes back as the next turn. The whole exchange is stored under `a2a_conversations.talk`.
4. `grade` deploys a judge, since it names none, and has it score the conversation against the three criteria. With `weighted_average`, all but the confirmation scores 0.8, under `verifications.conversation`.
5. The run ends with one score for the whole conversation, not for a single reply.

**Two envs: `q3-to-sam`**

```json title="task.json"
[
  {"id": "email", "type": "deploy_env", "env_id": "email", "depends_on": []},
  {"id": "contacts", "type": "deploy_env", "env_id": "contacts", "depends_on": []},
  {"id": "inbox", "type": "load_artifact", "env_id": "email", "artifact_id": "inbox", "depends_on": [{"task_step_id": "email"}]},
  {"id": "writer", "type": "deploy_agent", "env_ids": ["email"], "a2a_agent_id": "claude-code", "agent_name": "writer", "depends_on": [{"task_step_id": "email"}]},
  {"id": "planner", "type": "deploy_agent", "env_ids": ["contacts"], "a2a_agent_id": "claude-code", "agent_name": "planner", "depends_on": [{"task_step_id": "contacts"}]},
  {"id": "book", "type": "load_artifact", "env_id": "contacts", "artifact_id": "address-book", "depends_on": [{"task_step_id": "contacts"}]},
  {"id": "peer", "type": "peer_agents", "peerings": [{"source_agent_name": "planner", "peer_agent_names": ["writer"]}], "depends_on": [{"task_step_id": "inbox"}, {"task_step_id": "writer"}, {"task_step_id": "planner"}, {"task_step_id": "book"}]},
  {"id": "ask", "type": "prompt_agent", "agent_name": "planner", "prompt_id": "ask", "prompt": "Get Sam Lee the Q3 numbers.", "depends_on": [{"task_step_id": "peer"}]},
  {"id": "check", "type": "env_outcome_verifier", "env_id": "email", "file_artifact_id": "check-sam", "verifier_id": "sent-to-sam", "depends_on": [{"task_step_id": "ask"}]}
]
```

1. Two envs, `email` and `contacts`, wait for nothing, so both deploy at once, each as its own env instance.
2. Four steps start together, two on each env. `inbox` loads the mail into `email` and `book` the address book into `contacts`. `writer` deploys with `email`’s tools and `planner` with `contacts`’.
3. `peer` waits for all four. It pushes the planner a routing table naming the writer, so the planner can message the writer over A2A.
4. `ask` prompts only the planner. It can look Sam up in `contacts` but can’t send email, so it has to message the writer, who can: two agents, each with its own env’s tools.
5. `check` runs `verify()` from `check-sam` against `email`, the env where the email ended up, and stores 1.0 under `verifications.sent-to-sam`.
6. The run ends. Neither agent could have done it alone: one had the contacts, the other the mail.

**A week: `inbox-week`**

```json title="task.json"
[
  {"id": "email", "type": "deploy_env", "env_id": "email", "depends_on": []},
  {"id": "inbox", "type": "load_artifact", "env_id": "email", "artifact_id": "week-of-mail", "depends_on": [{"task_step_id": "email"}]},
  {"id": "assistant", "type": "deploy_agent", "env_ids": ["email"], "a2a_agent_id": "claude-code", "agent_name": "assistant", "role": "assistant", "depends_on": [{"task_step_id": "email"}]},
  {"id": "deadline", "type": "register_env_triggers", "env_id": "email", "triggers": [{"id": "lock-send", "when": {"type": "time", "at": "2026-10-02T17:00:00Z"}, "actions": [{"type": "permission", "action": "disable", "role": "assistant", "tools": ["send"]}]}], "depends_on": [{"task_step_id": "email"}]},
  {"id": "clock", "type": "sync_env_clock", "env_id": "email", "virtual_time": "2026-09-28T09:00:00Z", "virtual_seconds_per_real_second": 3600, "depends_on": [{"task_step_id": "inbox"}, {"task_step_id": "assistant"}, {"task_step_id": "deadline"}]},
  {"id": "week", "type": "prompt_agent", "agent_name": "assistant", "prompt_id": "week", "prompt": "Work through this week’s email. Anything for finance has to go out by Friday 17:00.", "depends_on": [{"task_step_id": "clock"}]},
  {"id": "check", "type": "env_outcome_verifier", "env_id": "email", "file_artifact_id": "check-friday", "verifier_id": "sent-by-friday", "depends_on": [{"task_step_id": "week"}]},
  {"id": "snapshot", "type": "snapshot_env", "env_id": "email", "depends_on": [{"task_step_id": "week"}]}
]
```

1. `email` deploys first. Every other step in this task acts on it or on the agent that uses it.
2. Three steps start together on `email`. `inbox` loads a week of mail, `assistant` deploys with `role: assistant`, and `deadline` registers a trigger that disables `send` for that role at Friday 17:00, virtual time.
3. `clock` waits for all three, then sets the virtual clock to Monday 09:00, running 3,600 times faster: the week passes in under two minutes.
4. `week` prompts the assistant. At Friday 17:00 virtual time the trigger fires and `send` is gone, so whatever isn’t sent by then misses the deadline.
5. `check` and `snapshot` both wait only for `week`, so they run together. `check` scores what was sent by Friday; `snapshot` stores the inbox’s end state as a new environment universe.
6. The run ends, and next week’s task can start from the snapshot with `load_artifact`.

**A world: `support-world`**

```json title="task.json"
[
  {"id": "customer-1", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-1", "system_prompt": "You are customer 1. You are writing to support about a late delivery.", "depends_on": []},
  {"id": "customer-2", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-2", "system_prompt": "You are customer 2. You are writing to support about a double charge.", "depends_on": []},
  {"id": "customer-3", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-3", "system_prompt": "You are customer 3. You are writing to support about a broken item.", "depends_on": []},
  {"id": "customer-4", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-4", "system_prompt": "You are customer 4. You are writing to support about a missing refund.", "depends_on": []},
  {"id": "customer-5", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-5", "system_prompt": "You are customer 5. You are writing to support about a wrong address.", "depends_on": []},
  {"id": "customer-6", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-6", "system_prompt": "You are customer 6. You are writing to support about a late delivery.", "depends_on": []},
  {"id": "customer-7", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-7", "system_prompt": "You are customer 7. You are writing to support about a double charge.", "depends_on": []},
  {"id": "customer-8", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-8", "system_prompt": "You are customer 8. You are writing to support about a broken item.", "depends_on": []},
  {"id": "customer-9", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-9", "system_prompt": "You are customer 9. You are writing to support about a missing refund.", "depends_on": []},
  {"id": "customer-10", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-10", "system_prompt": "You are customer 10. You are writing to support about a wrong address.", "depends_on": []},
  {"id": "customer-11", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-11", "system_prompt": "You are customer 11. You are writing to support about a late delivery.", "depends_on": []},
  {"id": "customer-12", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-12", "system_prompt": "You are customer 12. You are writing to support about a double charge.", "depends_on": []},
  {"id": "customer-13", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-13", "system_prompt": "You are customer 13. You are writing to support about a broken item.", "depends_on": []},
  {"id": "customer-14", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-14", "system_prompt": "You are customer 14. You are writing to support about a missing refund.", "depends_on": []},
  {"id": "customer-15", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-15", "system_prompt": "You are customer 15. You are writing to support about a wrong address.", "depends_on": []},
  {"id": "customer-16", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-16", "system_prompt": "You are customer 16. You are writing to support about a late delivery.", "depends_on": []},
  {"id": "customer-17", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-17", "system_prompt": "You are customer 17. You are writing to support about a double charge.", "depends_on": []},
  {"id": "customer-18", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-18", "system_prompt": "You are customer 18. You are writing to support about a broken item.", "depends_on": []},
  {"id": "customer-19", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-19", "system_prompt": "You are customer 19. You are writing to support about a missing refund.", "depends_on": []},
  {"id": "customer-20", "type": "deploy_agent", "a2a_agent_id": "claude-code", "agent_name": "customer-20", "system_prompt": "You are customer 20. You are writing to support about a wrong address.", "depends_on": []},
  {"id": "office", "type": "deploy_env", "env_id": "office", "depends_on": []},
  {"id": "support-1", "type": "deploy_agent", "env_ids": ["office"], "a2a_agent_id": "claude-code", "agent_name": "support-1", "role": "support", "depends_on": [{"task_step_id": "office"}]},
  {"id": "support-2", "type": "deploy_agent", "env_ids": ["office"], "a2a_agent_id": "claude-code", "agent_name": "support-2", "role": "support", "depends_on": [{"task_step_id": "office"}]},
  {"id": "support-3", "type": "deploy_agent", "env_ids": ["office"], "a2a_agent_id": "claude-code", "agent_name": "support-3", "role": "support", "depends_on": [{"task_step_id": "office"}]},
  {"id": "company", "type": "load_artifact", "env_id": "office", "artifact_id": "company", "depends_on": [{"task_step_id": "office"}]},
  {"id": "world", "type": "deploy_agent", "env_ids": ["office"], "a2a_agent_id": "claude-code", "agent_name": "world", "role": "world", "depends_on": [{"task_step_id": "office"}]},
  {"id": "peer", "type": "peer_agents", "peerings": [{"source_agent_name": "support-1", "peer_agent_names": ["support-2", "support-3"]}, {"source_agent_name": "support-2", "peer_agent_names": ["support-1", "support-3"]}, {"source_agent_name": "support-3", "peer_agent_names": ["support-1", "support-2"]}], "depends_on": [{"task_step_id": "support-1"}, {"task_step_id": "support-2"}, {"task_step_id": "support-3"}]},
  {"id": "rules", "type": "register_env_triggers", "env_id": "office", "watch_roles": ["support"], "executor_agent_name": "world", "triggers": [{"id": "supplier-delay", "when": {"type": "time", "at": "2026-09-29T11:00:00Z"}, "actions": [{"type": "nl", "instruction": "Email support that the next shipment is two days late."}]}, {"id": "refund-review", "when": {"type": "action", "tool": "issue_refund"}, "actions": [{"type": "nl", "instruction": "As finance, reply to support about the refund they just issued."}]}], "depends_on": [{"task_step_id": "company"}, {"task_step_id": "world"}]},
  {"id": "clock", "type": "sync_env_clock", "env_id": "office", "virtual_time": "2026-09-28T09:00:00Z", "virtual_seconds_per_real_second": 3600, "depends_on": [{"task_step_id": "peer"}, {"task_step_id": "rules"}]},
  {"id": "talk-1", "type": "prompt_agent", "agent_name": "support-1", "prompt_id": "talk-1", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-1", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-1"}, {"task_step_id": "clock"}]},
  {"id": "talk-2", "type": "prompt_agent", "agent_name": "support-2", "prompt_id": "talk-2", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-2", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-2"}, {"task_step_id": "clock"}]},
  {"id": "talk-3", "type": "prompt_agent", "agent_name": "support-3", "prompt_id": "talk-3", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-3", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-3"}, {"task_step_id": "clock"}]},
  {"id": "talk-4", "type": "prompt_agent", "agent_name": "support-1", "prompt_id": "talk-4", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-4", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-4"}, {"task_step_id": "clock"}]},
  {"id": "talk-5", "type": "prompt_agent", "agent_name": "support-2", "prompt_id": "talk-5", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-5", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-5"}, {"task_step_id": "clock"}]},
  {"id": "talk-6", "type": "prompt_agent", "agent_name": "support-3", "prompt_id": "talk-6", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-6", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-6"}, {"task_step_id": "clock"}]},
  {"id": "talk-7", "type": "prompt_agent", "agent_name": "support-1", "prompt_id": "talk-7", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-7", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-7"}, {"task_step_id": "clock"}]},
  {"id": "talk-8", "type": "prompt_agent", "agent_name": "support-2", "prompt_id": "talk-8", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-8", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-8"}, {"task_step_id": "clock"}]},
  {"id": "talk-9", "type": "prompt_agent", "agent_name": "support-3", "prompt_id": "talk-9", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-9", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-9"}, {"task_step_id": "clock"}]},
  {"id": "talk-10", "type": "prompt_agent", "agent_name": "support-1", "prompt_id": "talk-10", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-10", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-10"}, {"task_step_id": "clock"}]},
  {"id": "talk-11", "type": "prompt_agent", "agent_name": "support-2", "prompt_id": "talk-11", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-11", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-11"}, {"task_step_id": "clock"}]},
  {"id": "talk-12", "type": "prompt_agent", "agent_name": "support-3", "prompt_id": "talk-12", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-12", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-12"}, {"task_step_id": "clock"}]},
  {"id": "talk-13", "type": "prompt_agent", "agent_name": "support-1", "prompt_id": "talk-13", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-13", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-13"}, {"task_step_id": "clock"}]},
  {"id": "talk-14", "type": "prompt_agent", "agent_name": "support-2", "prompt_id": "talk-14", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-14", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-14"}, {"task_step_id": "clock"}]},
  {"id": "talk-15", "type": "prompt_agent", "agent_name": "support-3", "prompt_id": "talk-15", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-15", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-15"}, {"task_step_id": "clock"}]},
  {"id": "talk-16", "type": "prompt_agent", "agent_name": "support-1", "prompt_id": "talk-16", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-16", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-16"}, {"task_step_id": "clock"}]},
  {"id": "talk-17", "type": "prompt_agent", "agent_name": "support-2", "prompt_id": "talk-17", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-17", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-17"}, {"task_step_id": "clock"}]},
  {"id": "talk-18", "type": "prompt_agent", "agent_name": "support-3", "prompt_id": "talk-18", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-18", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-18"}, {"task_step_id": "clock"}]},
  {"id": "talk-19", "type": "prompt_agent", "agent_name": "support-1", "prompt_id": "talk-19", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-19", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-19"}, {"task_step_id": "clock"}]},
  {"id": "talk-20", "type": "prompt_agent", "agent_name": "support-2", "prompt_id": "talk-20", "prompt": "A customer has opened a chat. Help them.", "user_agent_name": "customer-20", "max_conversation_turns": 8, "depends_on": [{"task_step_id": "customer-20"}, {"task_step_id": "clock"}]},
  {"id": "grade-1", "type": "rubrics_verifier", "prompt_id": "talk-1", "verifier_id": "talk-1", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-1"}]},
  {"id": "grade-2", "type": "rubrics_verifier", "prompt_id": "talk-2", "verifier_id": "talk-2", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-2"}]},
  {"id": "grade-3", "type": "rubrics_verifier", "prompt_id": "talk-3", "verifier_id": "talk-3", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-3"}]},
  {"id": "grade-4", "type": "rubrics_verifier", "prompt_id": "talk-4", "verifier_id": "talk-4", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-4"}]},
  {"id": "grade-5", "type": "rubrics_verifier", "prompt_id": "talk-5", "verifier_id": "talk-5", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-5"}]},
  {"id": "grade-6", "type": "rubrics_verifier", "prompt_id": "talk-6", "verifier_id": "talk-6", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-6"}]},
  {"id": "grade-7", "type": "rubrics_verifier", "prompt_id": "talk-7", "verifier_id": "talk-7", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-7"}]},
  {"id": "grade-8", "type": "rubrics_verifier", "prompt_id": "talk-8", "verifier_id": "talk-8", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-8"}]},
  {"id": "grade-9", "type": "rubrics_verifier", "prompt_id": "talk-9", "verifier_id": "talk-9", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-9"}]},
  {"id": "grade-10", "type": "rubrics_verifier", "prompt_id": "talk-10", "verifier_id": "talk-10", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-10"}]},
  {"id": "grade-11", "type": "rubrics_verifier", "prompt_id": "talk-11", "verifier_id": "talk-11", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-11"}]},
  {"id": "grade-12", "type": "rubrics_verifier", "prompt_id": "talk-12", "verifier_id": "talk-12", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-12"}]},
  {"id": "grade-13", "type": "rubrics_verifier", "prompt_id": "talk-13", "verifier_id": "talk-13", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-13"}]},
  {"id": "grade-14", "type": "rubrics_verifier", "prompt_id": "talk-14", "verifier_id": "talk-14", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-14"}]},
  {"id": "grade-15", "type": "rubrics_verifier", "prompt_id": "talk-15", "verifier_id": "talk-15", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-15"}]},
  {"id": "grade-16", "type": "rubrics_verifier", "prompt_id": "talk-16", "verifier_id": "talk-16", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-16"}]},
  {"id": "grade-17", "type": "rubrics_verifier", "prompt_id": "talk-17", "verifier_id": "talk-17", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-17"}]},
  {"id": "grade-18", "type": "rubrics_verifier", "prompt_id": "talk-18", "verifier_id": "talk-18", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-18"}]},
  {"id": "grade-19", "type": "rubrics_verifier", "prompt_id": "talk-19", "verifier_id": "talk-19", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-19"}]},
  {"id": "grade-20", "type": "rubrics_verifier", "prompt_id": "talk-20", "verifier_id": "talk-20", "score_aggregator": "weighted_average", "criteria": [{"id": "resolved", "criterion": "Support resolved the customer’s issue, or said honestly what happens next.", "weight": 3}, {"id": "courteous", "criterion": "Support stayed courteous throughout.", "weight": 1}], "depends_on": [{"task_step_id": "talk-20"}]},
  {"id": "closed", "type": "env_outcome_verifier", "env_id": "office", "file_artifact_id": "check-tickets", "verifier_id": "closed", "score_aggregator": "weighted_average", "depends_on": [{"task_step_id": "talk-1"}, {"task_step_id": "talk-2"}, {"task_step_id": "talk-3"}, {"task_step_id": "talk-4"}, {"task_step_id": "talk-5"}, {"task_step_id": "talk-6"}, {"task_step_id": "talk-7"}, {"task_step_id": "talk-8"}, {"task_step_id": "talk-9"}, {"task_step_id": "talk-10"}, {"task_step_id": "talk-11"}, {"task_step_id": "talk-12"}, {"task_step_id": "talk-13"}, {"task_step_id": "talk-14"}, {"task_step_id": "talk-15"}, {"task_step_id": "talk-16"}, {"task_step_id": "talk-17"}, {"task_step_id": "talk-18"}, {"task_step_id": "talk-19"}, {"task_step_id": "talk-20"}]}
]
```

1. The twenty customers need no env, so they deploy with `office`, all at once: twenty sandboxes, each with its own persona and issue in `system_prompt`.
2. Everything on `office` starts next, together. `company` loads the company’s data into every MCP server. The three support agents deploy with `role: support`, and `world` with `role: world`.
3. `peer` gives each support agent the other two as peers, so they can hand customers to each other. `rules` registers the world’s triggers, watching `role: support`, with `world` carrying out their instructions.
4. `clock` waits for both, then starts the virtual clock at Monday 09:00, 3,600 times faster, for every agent in the env at once.
5. Twenty conversations run at the same time. Each pairs a support agent with a customer through `user_agent_name`, for up to eight turns. When a support agent issues a refund, or Tuesday 11:00 arrives, a trigger fires and `world` acts.
6. Each `grade-k` waits only for its own conversation, and `closed` waits for all twenty. Twenty rubric scores go under `verifications`, one per customer. `closed`’s `verify()` returns a row per ticket, so with `weighted_average` 18 of 20 closed scores 0.9.
7. The run ends. One task, seventy steps: a small company’s week of support, simulated and graded.

## Write task.json

A task file is a JSON list with one object per step, like each task.json above. Each object has an
`id`, unique within the task, a `type`, which selects the step's class, that class's fields, and
`depends_on`, the steps it waits for. [What is a task step](https://www.agentenvframework.com/docs/tasks/task-steps.md) covers the keys
every step has. This is `reply-to-dana`:

```json title="task.json"
[
  {"id": "email", "type": "deploy_env", "env_id": "email", "depends_on": []},
  {"id": "inbox", "type": "load_artifact", "env_id": "email", "artifact_id": "inbox", "depends_on": [{"task_step_id": "email"}]},
  {"id": "assistant", "type": "deploy_agent", "env_ids": ["email"], "a2a_agent_id": "claude-code", "agent_name": "assistant", "depends_on": [{"task_step_id": "email"}]},
  {"id": "reply", "type": "prompt_agent", "agent_name": "assistant", "prompt_id": "reply", "prompt": "Reply to Dana.", "depends_on": [{"task_step_id": "inbox"}, {"task_step_id": "assistant"}]},
  {"id": "check", "type": "env_outcome_verifier", "env_id": "email", "file_artifact_id": "check-reply", "verifier_id": "sent", "depends_on": [{"task_step_id": "reply"}]}
]
```

## Create it

```bash title="Terminal"
agent-env task create task.json --id reply-to-dana --project-id <project-id>
```

The command checks the file, saves each step and then the task, and ends with
`Created task: id=reply-to-dana version=1 steps=5`. `--project-id` is required: it names the project
the task's model spend is attributed to.

1. Each entry of `task.json` is a step, and `depends_on` links it into the DAG.
2. `task create` hands each entry’s fields to the step class its `type` names.
3. Step ids are unique, and every `depends_on` edge points to an earlier step.
4. Preflight can’t load the env `email`, so create fails and saves nothing.
5. `env mcp-server put` registers `email`, the env the `deploy_env` step names.
6. The same create passes: preflight loads `email`; the other steps have none.
7. Create saves each step, then the task, as version 1 of `reply-to-dana`.
8. An edit and a second create store version 2; version 1 stays as it was.

Parts of the scene:

- **agent-env task create**: `agent-env task create task.json --id reply-to-dana --project-id <project-id>` checks the file and then saves it under the id. `--project-id` is required and is stored on the task.
- **Registering the env**: `agent-env env mcp-server put --id email --dockerfile email/Dockerfile` builds the image and registers the env `email`, which the `deploy_env` step names.
- **task.json**: A JSON list with one object per step: an `id` unique in the task, a registered `type`, that type’s fields and `depends_on`. The edit pins `"env_version": 1` in the first entry.
- **depends_on**: Each line is a `depends_on` edge, and an edge may only point back to an earlier entry. `inbox` and `assistant` wait for `email`, and `reply` waits for both.
- **deploy_env**: The one step here with a preflight: create checks that its `gateway_mode` is valid, that the env `email` loads, and that the env’s topology takes the step’s options.
- **load_artifact**: Loads the environment artifact `inbox` into `email`. It has no preflight, so create doesn’t look `inbox` up, and a missing artifact fails the run at this step.
- **deploy_agent**: Deploys the agent `claude-code` under the name `assistant`. Create doesn’t look the agent up, so a missing agent fails the run at this step.
- **prompt_agent**: Sends `Reply to Dana.` to the agent named `assistant`. Its class needs `prompt` or `parts`, so an entry with neither fails the fields check.
- **env_outcome_verifier**: Runs `verify()` from the file artifact `check-reply` against the env’s MCP URL. Create doesn’t look `check-reply` up, so a missing one fails only here, after the agent has run.
- **The fields**: Each entry’s `type` is looked up among the registered step types, and its other keys go to that class. An unknown type, a field the class doesn’t take or a missing required one stops create.
- **The DAG**: Step ids must be unique, every `depends_on` must name an earlier step, and a `retry_config` must roll back to the step or one of its ancestors.
- **Preflight**: Runs each step’s `preflight()` against the stores, deploying nothing. Among the built-in steps only `deploy_env` and `run_code` have one; a dash marks a step without. A problem stops create unless you pass `--skip-validation`.
- **Nothing was saved**: A rejected create writes neither a step nor the task. `--skip-validation` saves despite preflight problems, but a file that fails the fields or DAG check is never saved.
- **reply-to-dana, version 1**: The five steps, stored inside the task, and its project id. `agent-env task get --id reply-to-dana --version 1` prints the steps with every default filled in.
- **Version 2**: A create under an existing id adds a version, even for an unchanged file, and never changes an older one. A run takes the latest unless you pass `--version`.
- **Step documents**: Create also saves each step as its own versioned document, in a collection every task shares. A second create saves all five again, so each moves to version 2.

## Versions

Each create under an existing id stores a new version and never changes an earlier one.
`agent-env task get --id reply-to-dana --version 1` prints a stored version, and a run uses the latest
unless you pass `--version`.

## Placeholders

Any string field can hold `<name>` placeholders, which each run fills from its seed: with the seed
`{"sender": "Dana"}`, `Reply to <sender>.` runs as `Reply to Dana.`. `agent-env task run-batch` runs a
task once per row of a CSV file; see [Task run options](https://www.agentenvframework.com/docs/tasks/running.md#task-run-options).