Cookbook: Assign a Task to an Agent
Create a task, assign it to a Momental agent, wait for it to complete, and retrieve the results - full working code.
What This Recipe Does
- Creates a task in the strategy tree under an existing EPIC
- Assigns the task to Huginn (the built-in reviewer agent)
- Polls for completion every 10 seconds
- Reads the completion summary and any output artifacts
- Saves a LEARNING atom based on the outcome
Expected end-to-end time: 2–5 minutes (depending on task complexity).
Prerequisites
- A working MCP connection (see Quickstart)
- An EPIC or parent node ID to create the task under - find one with
momental_strategy_tree
Step 1: Find or Create a Parent EPIC
Tasks must be children of a strategy node. If you do not yet have an EPIC to place the task under,
create one first. For this recipe, we will use momental_strategy_tree to find an
existing EPIC.
// Browse the strategy tree to find an EPIC to work under
const tree = await momental_strategy_tree({ depth: 3 });
// Find the first EPIC node
const epic = tree.nodes.find(n => n.type === "EPIC");
console.log(`Using EPIC: ${epic.statement} (${epic.id})`);
Step 2: Create the Task
Write clear acceptance criteria. The more specific your criteria, the better the agent's output. Good acceptance criteria answer: what research is needed, what should be produced, and what "done" looks like.
const task = await momental_task_create({
statement: "Review PR #1234: add rate limiting to /api/keys",
parentId: epic.id,
description: "PR branch: feat/api-key-rate-limiting. Focus on security correctness.",
acceptanceCriteria: `
- [ ] Rate limit header format follows RFC 6585
- [ ] Default limit value is documented and matches the implementation
- [ ] No secrets or credentials visible in the diff
- [ ] Rejection error message is safe (no stack traces or internal details)
- [ ] Edge case: what happens when a key is deleted mid-request?
`
});
console.log(`Task created: ${task.id}`);
Step 3: Assign to an Agent
await momental_task_assign_agent({
taskId: task.id,
agentId: "huginn"
});
console.log("Task assigned to Huginn - waiting for pickup...");
Step 4: Poll for Completion
Momental does not push completion events over MCP. Poll momental_task_get
until the task reaches IN_REVIEW (agent submitted) or DONE (approved).
async function waitForCompletion(taskId, timeoutMs = 10 * 60 * 1000) {
const start = Date.now();
const terminalStatuses = new Set(["IN_REVIEW", "DONE", "BLOCKED"]);
while (Date.now() - start < timeoutMs) {
await new Promise(r => setTimeout(r, 10_000)); // wait 10 seconds
const task = await momental_task_get({ taskId });
console.log(`Status: ${task.status} (${task.workStatus})`);
if (terminalStatuses.has(task.status)) {
return task;
}
}
throw new Error("Timed out waiting for task completion");
}
const completed = await waitForCompletion(task.id);
Step 5: Read the Results
const result = await momental_task_get({ taskId: task.id });
// The agent's completion summary
console.log("Summary:", result.completionSummary);
// Any artifacts attached by the agent
if (result.artifacts?.length > 0) {
console.log("Artifacts:");
for (const artifact of result.artifacts) {
console.log(` - ${artifact.name}: ${artifact.url}`);
}
}
// Read the task's chat thread for the full review narrative
const topic = await momental_chat_topic_for_object({ objectId: task.id });
const messages = await momental_chat_messages_get({
topicId: topic.id,
limit: 10
});
console.log("Review findings:", messages[0].content);
Step 6: Save a Learning
After the agent completes its work, save a learning if the review surfaced anything worth remembering for future work.
// If the review found a pattern worth remembering
if (result.completionSummary.includes("RFC 6585")) {
await momental_node_create({
statement: "Rate limit headers must use HTTP-date format (RFC 6585 §4), not Unix epoch seconds",
nodeType: "PRINCIPLE",
status: "ACTIVE",
domain: "engineering",
tags: ["api", "rate-limiting", "http-headers"]
});
}
Complete Working Example
// Full recipe - assign a review task and wait for results
async function reviewPR(prNumber, epicId) {
// 1. Create task
const task = await momental_task_create({
statement: `Review PR #${prNumber}`,
parentId: epicId,
acceptanceCriteria: "Security, logic, and test coverage checked"
});
// 2. Assign to Huginn
await momental_task_assign_agent({ taskId: task.id, agentId: "huginn" });
// 3. Poll for completion (10 min timeout)
let done = false;
for (let i = 0; i < 60 && !done; i++) {
await new Promise(r => setTimeout(r, 10_000));
const current = await momental_task_get({ taskId: task.id });
done = ["IN_REVIEW", "DONE", "BLOCKED"].includes(current.status);
if (done) return current;
}
throw new Error("Review timed out");
}
const review = await reviewPR(1234, "epic_security_q2");
console.log(review.completionSummary);
Task Status Reference
| Status | Meaning |
|---|---|
PLANNED | Created, not yet started |
IN_PROGRESS | Agent has locked and is working on it |
IN_REVIEW | Agent submitted - awaiting human or reviewer approval |
DONE | Approved and complete |
BLOCKED | Agent reported a blocker - check the task thread |