Planning Agents
By the Syncfusion DevTutorials team · Last updated
How a planning agent turns a feature request into a spec and tasks, with testable acceptance criteria, a dependency map, estimates and owners for other agents.
Think about planning a school play.
Someone says, "Let's put on a play about the moon landing." That is an idea, not a plan. Before anyone can start working, a planner turns the idea into tasks: write the script, design the costumes, build the set, rehearse, and hold a dress rehearsal.
Each task gets a person responsible for it, a deadline, and a clear way to know when it is finished. For example: "Costumes are complete when every actor has a costume that fits."
The planner also decides the order of the work. You cannot rehearse before the script is written. However, the costumes and the set can be created at the same time.
A planning agent does the same job for software projects.
The main idea: A planning agent reads a feature request and turns it into tasks. Each task has a clear owner, a definition of done, an estimate, and a list of dependencies. Other agents can then take those tasks and complete them.
A Real-World Example
The Brightgrid product owner submits the following feature request:
Support staff can't tell if a big export is still running. Show the export status on the ticket page: Queued, Running, Done or Failed. When it is Done, show the row count. When it Failed, show a Retry button. The backend adds
GET /tickets/:id/export.
The planning agent reads the feature request and creates 6 tasks:
| Task | Owner | Waits for |
|---|---|---|
| Write the API contract | planner | nothing |
| Design the status panel | design | nothing |
| Build the endpoint | backend | contract |
| Build the panel | frontend | contract, design |
| Write the tests | testing | endpoint, panel |
| Review the change | review | tests |
The next five lessons focus on the agents listed in the Owner column.
In simple words: A planning agent turns "what we want" into "who does what, in what order, and how we know it is done."
What You Will Learn
In this lesson, you will learn:
- How a planning agent turns a feature request into a specification and then into tasks.
- How to write acceptance criteria that can be verified by a test.
- How to create a dependency map and understand why task order matters.
- How to add estimates and priorities to tasks.
- How a completed plan is handed off to other agents.
In the Agent Lab, the planning agent has three tools: list_files, read_file, and create_task. It cannot modify code. Open the Plan tab after a run to view the tasks it created and the plan grader's evaluation.
The plan for the export status feature. Each arrow means "must be completed first". The contract and the design can begin at the same time.
From Request to Spec to Tasks
The Feature Request
A feature request describes what people need in their own words. It is often short and may be slightly unclear. That is expected because one of the planning agent's jobs is to make the request clear and actionable.
The Spec
A spec (specification) describes exactly what will be built. For the export status feature, the spec answers questions such as:
- What are the four statuses?
- What does the endpoint return?
- What should the panel display for each status?
In the Agent Lab, the first task, contract, acts as the API specification. It defines the response shape { status, rows }, allowing both the backend and frontend agents to build against the same contract.
Tasks
A task is a piece of work that one agent can complete and verify. A good task is small enough to finish within a few hours and large enough to be checked on its own.
Split a request into parts, one per owner
const request = "Show the export status on the ticket page. The backend adds GET /tickets/:id/export.";
const parts = [];
if (/GET \/\S+/.test(request)) parts.push({ id: "contract", owner: "planner" });
if (/page|panel|show/i.test(request)) parts.push({ id: "design", owner: "design" });
if (/backend|GET/.test(request)) parts.push({ id: "api", owner: "backend" });
if (/page|show/i.test(request)) parts.push({ id: "panel", owner: "frontend" });
parts.push({ id: "tests", owner: "testing" }, { id: "review", owner: "review" });
console.log(parts.length + " tasks");
for (const p of parts) console.log(p.id + " -> " + p.owner);
Expected output:
6 tasks
contract -> planner
design -> design
api -> backend
panel -> frontend
tests -> testing
review -> review
A real planning agent uses a model to understand the feature request, not simple rules or regular expressions. However, the output has the same structure: a list of tasks, with a responsible owner assigned to each one.
Acceptance Criteria
Acceptance criteria define exactly when a task is complete. If two different people read the criteria, they should reach the same conclusion about whether the task is done or not.
The Given, When, Then format makes acceptance criteria easy to test:
- Given a starting situation,
- When an action occurs,
- Then a specific result is expected.
For example:
"Given status done and 80000 rows, when the page loads, then it shows 'Done: 80,000 rows'."
This can be turned directly into a test.
A statement such as "The panel looks good" cannot be tested because it is not specific enough.
Is this acceptance criterion testable?
function testable(criteria) {
const hasAll = /\bgiven\b/i.test(criteria) && /\bwhen\b/i.test(criteria) && /\bthen\b/i.test(criteria);
return hasAll ? "testable" : "NOT testable";
}
console.log(testable("Given status done and 80000 rows, when the page loads, then it shows \"Done: 80,000 rows\"."));
console.log(testable("The panel looks good."));
console.log(testable("The endpoint works."));
Expected output:
testable
NOT testable
NOT testable
The Given, When, Then format does not automatically make an acceptance criterion good. However, it forces the writer to clearly define a situation, an action, and an expected result that can be verified. Words like "good", "fast", and "works" cannot be verified, so they should be avoided.
Dependency Maps
A dependency map shows which tasks must wait for other tasks before they can begin. You used dependencies to build waves in Lessons 6 and 12. A planning agent creates this map.
For this feature, the dependency rules are:
- The backend task depends on the contract task.
- The frontend task depends on both the contract and the design tasks.
- The testing task depends on both the backend and frontend tasks.
- The review task depends on the testing task.
If the frontend starts before the contract is defined, it may be built against the wrong data structure and the work might need to be redone.
The create_task tool also enforces one rule: a task can depend only on tasks that already exist. Because of this, the planning agent must create tasks in an order where each task comes after all the tasks it depends on.
Check the dependency rules
const tasks = [
{ id: "contract", owner: "planner", deps: [] },
{ id: "design", owner: "design", deps: [] },
{ id: "api", owner: "backend", deps: ["contract"] },
{ id: "panel", owner: "frontend", deps: ["design"] },
{ id: "tests", owner: "testing", deps: ["panel"] },
];
const rules = { backend: ["planner"], frontend: ["planner", "design"], testing: ["backend", "frontend"] };
for (const t of tasks) {
const have = t.deps.map((d) => tasks.find((x) => x.id === d).owner);
const missing = (rules[t.owner] ?? []).filter((need) => !have.includes(need));
if (missing.length) console.log(t.id + " is missing: " + missing.join(", "));
}
Expected output:
panel is missing: planner
tests is missing: backend
The panel forgot the contract. The tests forgot the backend, so they could run before the endpoint exists.
Estimates and Priority
An estimate is an expected amount of work, such as "3h". Estimates help people understand the size of the overall plan and identify tasks that are too large. If a task is estimated to take more than a day, it should usually be split into smaller tasks.
A priority shows which tasks are most important when there is not enough time to do everything. For a feature like this, the contract and the design have the highest priority because all the other tasks depend on them.
Total hours, and the longest chain
const tasks = {
contract: { h: 2, deps: [] },
design: { h: 3, deps: [] },
api: { h: 4, deps: ["contract"] },
panel: { h: 5, deps: ["contract", "design"] },
tests: { h: 3, deps: ["api", "panel"] },
review: { h: 1, deps: ["tests"] },
};
const total = Object.values(tasks).reduce((sum, t) => sum + t.h, 0);
function finish(id) {
const t = tasks[id];
return t.h + Math.max(0, ...t.deps.map(finish));
}
console.log("total work: " + total + "h");
console.log("shortest finish with enough agents: " + finish("review") + "h");
Expected output:
total work: 18h
shortest finish with enough agents: 12h
The work adds up to 18 hours. However, with one agent assigned to each owner, tasks that do not depend on each other can run at the same time.
The longest dependency chain is design → panel → tests → review, which takes 12 hours. This is the chain that needs the most attention because it determines how long the entire plan will take.
Handing Tasks to Other Agents
The owner field identifies which agent is responsible for each task. A task becomes ready when all the tasks it depends on have been completed. In the following lessons, the design, frontend, backend, review, and testing agents each take their assigned tasks from this plan.
A good handover gives the next agent everything it needs: the task description, the acceptance criteria, and links to its dependencies, such as the contract or the design. The next agent should not need to reread the entire feature request and make guesses about what is required.
Which tasks can be handed over now?
const tasks = [
{ id: "contract", owner: "planner", deps: [] },
{ id: "design", owner: "design", deps: [] },
{ id: "api", owner: "backend", deps: ["contract"] },
{ id: "panel", owner: "frontend", deps: ["contract", "design"] },
{ id: "tests", owner: "testing", deps: ["api", "panel"] },
];
function ready(done) {
return tasks.filter((t) => !done.includes(t.id) && t.deps.every((d) => done.includes(d))).map((t) => t.id + " -> " + t.owner);
}
console.log("start: " + ready([]).join(", "));
console.log("after contract: " + ready(["contract"]).join(", "));
console.log("after contract and design: " + ready(["contract", "design"]).join(", "));
Expected output:
start: contract -> planner, design -> design
after contract: design -> design, api -> backend
after contract and design: api -> backend, panel -> frontend
Each time a task is completed, additional tasks become ready, and the appropriate agent can begin working on them.
Planning Agent: Export Status
The agent reads the feature request and then creates one task for each step. Its configuration requires Given/When/Then acceptance criteria, an estimate in hours, and a rule that tasks can only be created after their dependencies exist. Open the Plan tab to see that the plan check passes.
Planning Agent with Vague Habits
This agent creates the same 6 tasks but has no planning rules. The Plan tab reports 5 problems:
- Two acceptance criteria cannot be tested: "The endpoint works." and "The panel looks good."
- One estimate is "soon".
- The panel task does not depend on the contract.
- The testing task does not depend on the backend.
Each of these issues can cause problems later: tasks that cannot be verified, plans that cannot be scheduled, or agents starting work before required dependencies exist.
Easy Way to Remember: every task needs who, when-done, how-long, and waits-for.
A planning agent should never modify code. Give it planning and read-only tools only. Its job is to create the plan, and a person should review that plan before other agents begin work.
Common Mistakes
| Mistake | Wrong Idea | Correct Idea | What Goes Wrong |
|---|---|---|---|
| Vague criteria | "Everyone knows what done means." | Use Given, When, Then criteria. | Nobody can prove that the task is finished. |
| Missing dependencies | "Everything can start immediately." | Identify what each task depends on first. | Agents build on work that does not exist yet. |
| No contract task | "Frontend and backend will agree automatically." | Create the contract first. | The frontend and backend implementations do not match. |
| No estimates | "It will take however long it takes." | Add an estimate to every task. | The plan cannot be scheduled, and large tasks go unnoticed. |
| Planner writing code | "It is faster if the planner starts coding." | Plan first, then hand the work over. | Development begins before the plan is reviewed. |
Exercises
Each exercise ends with a value on the last line. Press Check to compare it with the expected answer.
What to Remember
- A planning agent turns a feature request into a specification and then into a set of tasks.
- Every task needs four things: who will do it, when it is done, how long it should take, and what it waits for.
- Write acceptance criteria using the Given, When, Then format.
- Create the contract first so the frontend and backend build against the same specification.
- The longest dependency chain determines how long the overall plan will take.
- A planning agent creates the plan. It does not modify code.
Next: UI Design Agents, the agent that turns the design task into a wireframe that passes the accessibility check.