Skip to main content
Glama

Work plan: batch a dependency graph

work_plan
Read-only

Turn a dependency graph into parallelizable task batches, respecting dependencies, priority, and optional write-path conflicts while validating malformed graphs, missing dependencies, and cycles.

Instructions

Work plan: turn a dependency graph you hand it into the batches that may run in parallel — pure computation over nodes: no file opened, no path taken, nothing mutated. Use it when the graph is in your hands (tasks with depends_on); use shiftwork_plan when the graph is a shift-work checkpoint on disk, which it reads for you under the same batching rules. Batch k holds every node whose dependencies all sit in batches below k; sequence is the batches flattened; width is the largest batch — the fan-out an orchestrator must afford. Inside a batch: priority descending, then the order the nodes were given; both halves are contract, so two implementations answer byte-identically. Empty nodes is an ANSWER (no batches, width 0), not a refusal. Four refusals, in this order, one sentence each: nodes[<i>].<field> must be ... (an id that is not a string, depends_on not a list of strings, priority not an integer — named by position, never coerced), duplicate node id <id>, node <id> depends on <dep>, which no node declares, and the graph has a cycle: <a> -> <b> -> <a>. depends_on encodes logical order, not file contention; give a node touches (repo-relative paths it will WRITE) and no batch ever holds two nodes sharing a path: inside a level, in the same order, a node whose path an admitted node already claims is held for the next batch, and the answer then carries held: [{id, batch, by, path}] (absent when no node declares touches). A path that is empty, absolute, holds a backslash or a ./../empty segment is the fifth refusal, checked with the shape: node <id> touches <json>, which is not a plain relative path.

Input Schema

NameRequiredDescriptionDefault
nodesYesThe graph: one object per task, {id, depends_on?, priority?, touches?}. The order given is the tie-break inside a batch after priority.

Output Schema

NameRequiredDescriptionDefault
heldNoPresent only when a node declares `touches`: one {id, batch, by, path} per hold, the node held out of batch `batch` because `by`, admitted there, already writes `path`.
widthNoThe largest batch length: the widest fan-out.
reasonNoWith result `error`: one sentence saying why the call was refused.
resultYes`plan` on success; `error` with `reason` for one of the four refusals.
batchesNoNode ids by wave: batch k holds every node whose dependencies all sit in batches below k.
sequenceNoThe batches flattened in order.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changedv0.38.0
    • changedInput schema / properties / nodes / description
      Previous value: -"The graph: one object per task, {id, depends_on?, priority?}. The order given is the tie-break inside a batch after priority."New value: +"The graph: one object per task, {id, depends_on?, priority?, touches?}. The order given is the tie-break inside a batch after priority."
    • addedInput schema / properties / nodes / items / properties / touches
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "Repo-relative POSIX paths this node will WRITE, compared as exact strings. Optional: absent or null claims nothing. Two nodes sharing a path never land in one batch"
      +}
    • addedOutput schema / properties / held
      Added value: +{
      +  "description": "Present only when a node declares `touches`: one {id, batch, by, path} per hold, the node held out of batch `batch` because `by`, admitted there, already writes `path`.",
      +  "items": {
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
  2. Changed3 schema fields changedv0.36.2
    • addedInput schema / properties / nodes / description
      Added value: +"The graph: one object per task, {id, depends_on?, priority?}. The order given is the tie-break inside a batch after priority."
    • addedOutput schema / properties
      Added value: +{
      +  "batches": {
      +    "description": "Node ids by wave: batch k holds every node whose dependencies all sit in batches below k.",
      +    "items": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "type": "array"
      +  },
      +  "reason": {
      +    "description": "With result `error`: one sentence saying why the call was refused.",
      +    "type": "string"
      +  },
      +  "result": {
      +    "description": "`plan` on success; `error` with `reason` for one of the four refusals.",
      +    "type": "string"
      +  },
      +  "sequence": {
      +    "description": "The batches flattened in order.",
      +    "items": {
      +      "type": "string"
      +    },
      +    "type": "array"
      +  },
      +  "width": {
      +    "description": "The largest batch length: the widest fan-out.",
      +    "type": "integer"
      +  }
      +}
    • addedOutput schema / required
      Added value: +[
      +  "result"
      +]
  3. First observedv0.36.0

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already say readOnlyHint/openWorldHint=false, and the description reinforces rather than contradicts them ('no file opened, no path taken, nothing mutated'). Beyond that it discloses the determinism contract (priority then input order, byte-identical across implementations), the `held` output with its exact shape and the condition under which it is absent, and an ordered list of five refusals with their message shapes — behavior an agent cannot infer from annotations alone.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and purity are front-loaded, and nearly every clause carries operative information (batching rule, tie-break order, refusal order, held semantics). It is dense to the point of being a wall of text, and it explains `sequence`/`width` return values despite an output schema existing, which is the main redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a single nested-graph parameter and a complex batching contract, the description covers ordering, fan-out, contention handling, and all failure modes an agent could hit. The output schema carries the return shape, so the extra prose about `sequence`/`width` is surplus rather than a gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the field-level docs are already in the schema; the description still adds real meaning by stating that `depends_on` encodes logical order rather than file contention, and that `touches` lists paths the node will WRITE, which explains why the two fields interact. It also specifies validation consequences (invalid ids/paths named by position, never coerced) that go beyond the schema's types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource — turn a dependency graph into parallel batches — and immediately bounds it as 'pure computation over `nodes`'. It names the sibling it is not (shiftwork_plan) and states the distinguishing condition (graph in hand vs. checkpoint on disk), so an agent can route between them without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use: 'Use it when the graph is in your hands (tasks with depends_on)', paired with an explicit alternative and its trigger ('use shiftwork_plan when the graph is a shift-work checkpoint on disk'). It also preempts a likely misuse by declaring empty `nodes` an answer rather than a refusal.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.