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

  1. Creates a task in the strategy tree under an existing EPIC
  2. Assigns the task to Huginn (the built-in reviewer agent)
  3. Polls for completion every 10 seconds
  4. Reads the completion summary and any output artifacts
  5. Saves a LEARNING atom based on the outcome

Expected end-to-end time: 2–5 minutes (depending on task complexity).

Prerequisites

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

StatusMeaning
PLANNEDCreated, not yet started
IN_PROGRESSAgent has locked and is working on it
IN_REVIEWAgent submitted - awaiting human or reviewer approval
DONEApproved and complete
BLOCKEDAgent reported a blocker - check the task thread