skills/operad-task-decomposition/SKILL.md
Use operads to formally model hierarchical task decomposition for multi-agent systems. Covers typed composition, wiring diagrams, and the relationship to DAG-of-agents architectures. Use when decomposing complex tasks for multi-agent execution, designing DAG topologies, validating decomposition type-safety, or building compositional agent workflows. NOT for runtime scheduling, individual skill authoring, or generic category-theory tutoring.
npx skillsauth add curiositech/windags-skills operad-task-decompositionInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
An operad formalizes "a complex thing decomposes into simpler things, and the decomposition itself composes." Each operation has typed inputs and a typed output. Composition is hierarchical: you can plug the output of one operation into the input of another, provided the types match. The composition laws (associativity and identity) guarantee that decomposition is well-defined regardless of the order you assemble the pieces.
This is the mathematical structure underlying DAG-of-agents architectures, WinDAGs, and any system where tasks decompose into subtasks with explicit interface contracts.
flowchart TD
A[Incoming request for Operad Task Decomposition] --> B{Within this skill's scope?}
B -->|No| C[Redirect using NOT-for boundaries]
B -->|Yes| D[Assess inputs, constraints, and current state]
D --> E{Which path fits best?}
E -->|Plan or design| F[Choose the simplest viable pattern]
E -->|Migration or change| G[Protect compatibility and rollout safety]
E -->|Debug or evaluate| H[Localize the failing boundary first]
F --> I[Apply the domain-specific guidance below]
G --> I
H --> I
I --> J[Validate against the quality gates]
Use this as the first-pass routing model:
An operad O consists of:
In plain English: An operad is a collection of "ways to combine things" where:
The key insight: A task decomposition IS an element of an operad.
Consider a task T that decomposes into subtasks S_1, S_2, S_3. This decomposition is an operation:
decompose_T : (S_1_output, S_2_output, S_3_output) --> T_output
The operation says: "Given the results of subtasks S_1, S_2, and S_3, here is how to combine them into the result of task T."
Each subtask S_i may itself decompose further:
decompose_S1 : (S_1a_output, S_1b_output) --> S_1_output
Composition in the operad gives you the full decomposition:
decompose_T . (decompose_S1, id_S2, id_S3) :
(S_1a_output, S_1b_output, S_2_output, S_3_output) --> T_output
Associativity guarantees: It doesn't matter whether you first decompose T into (S_1, S_2, S_3) and then decompose S_1 into (S_1a, S_1b), or whether you directly decompose T into (S_1a, S_1b, S_2, S_3). The result is the same.
Why this matters for multi-agent systems: Associativity means subtask delegation is safe. An agent can delegate a subtask to another agent, who further delegates, and the overall composition is correct as long as types match at every boundary.
A colored operad (also called a multicategory) is an operad where the types (colors) carry semantic meaning. In task decomposition:
Type examples for an agent workflow:
Types:
ProblemDescription -- natural language task specification
DomainAnalysis -- structured analysis of the problem domain
DAGTopology -- a validated directed acyclic graph of subtasks
AgentOutput -- raw output from a single agent execution
QualityReport -- evaluation of an agent's output
SynthesizedResult -- combined output from multiple agents
FinalDeliverable -- the completed, reviewed work product
Typed operations:
analyze : (ProblemDescription) --> DomainAnalysis
decompose : (DomainAnalysis) --> DAGTopology
execute_node : (ProblemDescription, DAGTopology) --> AgentOutput
evaluate : (AgentOutput, ProblemDescription) --> QualityReport
synthesize : (AgentOutput, AgentOutput, ...) --> SynthesizedResult
finalize : (SynthesizedResult, QualityReport) --> FinalDeliverable
Type-checking a decomposition: Before executing a DAG, verify that every edge's source type matches the target node's expected input type. This is a static check -- no agent needs to run. If types don't match, the decomposition is invalid and must be revised.
Spivak's operad of wiring diagrams (2013) provides a visual and formal language for system composition:
┌──────────────────────────────────────┐
│ Outer Box │
│ ┌──────┐ ┌──────┐ │
│ │ Box A │──out──>│ Box B │──out──>─┤──> final output
│ └──────┘ └──────┘ │
│ ^ │
├──>────┘ │
│ input │
└──────────────────────────────────────┘
This IS the WinDAGs architecture:
The operad structure guarantees: Any valid wiring diagram can be composed with any other valid wiring diagram (at matching ports), and the result is again a valid wiring diagram. This is the formal basis for "DAGs of DAGs" -- hierarchical agent orchestration.
In an operad, the monoidal product (tensor product) models parallel execution:
f : (A, B) --> C -- sequential: f needs both A and B to produce C
g : (D) --> E -- independent operation
f tensor g : (A, B, D) --> (C, E) -- f and g run in parallel
For DAG scheduling:
Practical implication: The operad structure tells you the MAXIMUM parallelism possible in a decomposition. If your DAG scheduler achieves less parallelism, it's leaving performance on the table. If it attempts more, it will produce type errors (using outputs before they're available).
Types in an operad can reference objects in an olog. If you have an olog defining your domain (types = "a customer", "an order", "a product"), then the operad's colors can be the objects of that olog.
An operation in the operad like:
process_order : (Customer, OrderDetails, InventoryStatus) --> FulfillmentPlan
has its input and output types grounded in the olog's type system. This means:
List every distinct kind of artifact that flows between agents or between stages of the task.
Test: Two artifacts have the same type if and only if they can be used interchangeably as input to any downstream operation. If artifact A can substitute for artifact B in every context, they have the same type. If there exists ANY operation that accepts A but not B, they have different types.
Common mistake: Too few types. Using "string" or "text" for everything defeats the purpose. Types should carry semantic meaning: "CodeReview" is different from "TestResults" even if both are strings.
For each task or subtask, specify:
Format: operation_name : (InputType1, InputType2, ...) --> OutputType
Test for completeness: Can you chain the operations to get from the initial input types to the final output type? If there's a gap (no operation produces a type that a downstream operation needs), you're missing an operation.
For each pair of operations where one's output type matches another's input type, verify that composition is well-defined:
For deterministic operations: Associativity is automatic. For nondeterministic operations (LLM calls): Associativity is approximate. Document the degree of variability.
Group operations by their data dependencies:
This gives you the DAG topology:
Wave 1: {operations with only initial inputs} -- all in parallel
Wave 2: {operations depending on Wave 1 outputs} -- all in parallel
Wave 3: {operations depending on Wave 2 outputs} -- all in parallel
...
Final: {operation producing the final deliverable}
Represent an operad for a task decomposition as a JSON schema:
interface OperadType {
name: string;
description: string;
schema?: object; // JSON Schema for the type's instances
}
interface OperadOperation {
name: string;
inputs: { name: string; type: string }[]; // references OperadType.name
output: { type: string }; // references OperadType.name
agent?: string; // which agent/skill executes this
parallelizable_with?: string[]; // operations that can run in parallel
}
interface TaskOperad {
types: OperadType[];
operations: OperadOperation[];
composition_order: string[][]; // waves: each inner array runs in parallel
}
Example:
{
"types": [
{ "name": "ProblemDescription", "description": "Natural language task spec" },
{ "name": "DomainAnalysis", "description": "Structured domain breakdown" },
{ "name": "CodePatch", "description": "A diff that modifies source code" },
{ "name": "TestResults", "description": "Pass/fail with coverage report" },
{ "name": "FinalDeliverable", "description": "Reviewed, tested code change" }
],
"operations": [
{
"name": "analyze",
"inputs": [{ "name": "problem", "type": "ProblemDescription" }],
"output": { "type": "DomainAnalysis" },
"agent": "windags-sensemaker"
},
{
"name": "implement",
"inputs": [
{ "name": "analysis", "type": "DomainAnalysis" },
{ "name": "problem", "type": "ProblemDescription" }
],
"output": { "type": "CodePatch" },
"agent": "code-architecture"
},
{
"name": "test",
"inputs": [{ "name": "patch", "type": "CodePatch" }],
"output": { "type": "TestResults" },
"agent": "test-automation-expert"
},
{
"name": "finalize",
"inputs": [
{ "name": "patch", "type": "CodePatch" },
{ "name": "tests", "type": "TestResults" }
],
"output": { "type": "FinalDeliverable" },
"agent": "windags-evaluator"
}
],
"composition_order": [
["analyze"],
["implement"],
["test"],
["finalize"]
]
}
Type-checking algorithm:
For each operation op in topological order:
For each input (name, type) of op:
Find the upstream operation that produces this type
Verify it exists and appears in an earlier wave
Verify the type names match exactly
If any check fails: INVALID decomposition. Report the type mismatch.
The WinDAGs architecture is an instantiation of the operad of wiring diagrams:
| Operad Concept | WinDAGs Equivalent | |---|---| | Type (color) | Node output schema | | Operation | Agent node with skill assignment | | Composition | Edge connecting nodes | | Identity | Pass-through node | | Monoidal product | Wave (parallel execution group) | | Wiring diagram | The DAG itself | | Nested wiring diagram | Sub-DAG (hierarchical decomposition) | | Associativity | "Decompose T into sub-DAGs, or directly into leaves -- same result" |
The WinDAGs Decomposer agent is performing operad construction: Given a problem description, it produces a wiring diagram (DAG topology) where each box (node) has typed inputs and outputs, and the wiring (edges) respects type compatibility.
The WinDAGs Mutator is performing operad substitution: When a node fails and the DAG needs restructuring, the mutator replaces an operation with a different operation of the same type signature, or decomposes it into sub-operations. The operad structure guarantees the replacement is type-safe.
Use the anti-pattern catalog below as the operational failure-mode checklist for this skill. During execution, explicitly look for these failure patterns before you ship a recommendation or implementation.
Novice: Builds a DAG where every edge carries "text" or "any". Nodes accept whatever the previous node produced. Type errors surface only at runtime when an agent receives input it can't process. Expert: Every edge in a DAG should have a named, documented type. Type-checking is free (it's a static analysis) and catches integration errors before any agent runs. If you can't name the type, you don't understand the interface. Define a schema for each type. Timeline: This is the default in most LLM-based agent frameworks. The cure is adding even minimal type annotations. Start with named string types; graduate to JSON schemas.
Novice: A single operation takes 15 inputs and produces a complex output. The operation is a monolith that can't be decomposed further. Expert: If an operation has more than 4-5 inputs, it almost certainly decomposes into sub-operations. Apply the operad composition recursively: find intermediate types that split the megaoperation into stages. Each stage should have 2-3 inputs. This mirrors the "small functions" principle in software engineering, but with formal type-theoretic backing. Timeline: Common when the decomposer agent is given too little guidance about granularity. Fix by setting a max-inputs constraint on the decomposer.
Novice: Defines types that no operation produces or consumes. The type exists in the schema but has no role in the decomposition. Expert: Every type must appear as the output of at least one operation AND the input of at least one operation (except for initial input types and the final output type). Phantom types indicate either missing operations or over-specified type systems. Remove them or add the operations that connect them. Timeline: Happens when copying type lists from ologs without checking which types participate in the task workflow.
Novice: Creates a "decomposition" where operation A's output feeds B, and B's output feeds back to A. "It's iterative refinement!" Expert: Operads are acyclic by construction. Iteration is NOT composition -- it's a fixed-point computation. Model iteration as a SEPARATE operation: iterate(f, convergence_criterion) that internally applies f repeatedly until convergence. The iterate operation itself has typed inputs and outputs and participates in the operad normally. The cycle lives INSIDE the iterate box, not in the operad's wiring. Timeline: Very common in agent systems that do "revise until good." The fix is always to encapsulate the loop.
"Operads are just DAGs" -- No. A DAG is a graph. An operad is an algebraic structure with composition laws. The key difference: an operad tells you not just the topology but also the TYPE CONSTRAINTS at every connection point, and it guarantees that composition is associative. A DAG can have arbitrary, unchecked connections.
"Why not just use function types?" -- Operad operations are multi-input, single-output. Function types (in the lambda calculus sense) are single-input, single-output (you curry multi-input functions). The operad formalism avoids currying, which means the parallelism structure is explicit: if an operation takes (A, B, C), you know A, B, and C can be computed in parallel. With curried functions f: A -> B -> C -> D, the parallelism is hidden.
"Associativity doesn't matter in practice" -- It matters enormously for hierarchical delegation. If agent X decomposes a task and delegates subtask S to agent Y, who further decomposes S and delegates sub-subtask S' to agent Z, associativity guarantees that the overall result is the same as if X had directly decomposed to the leaf level. Without associativity, delegation introduces path-dependent bugs.
"How is this different from a type system?" -- An operad IS a type system, but one specifically designed for hierarchical composition. A general type system (like TypeScript's) lets you compose functions but doesn't distinguish between sequential and parallel composition. The operad's monoidal product makes parallelism a first-class citizen.
When deeper detail is needed:
You have a valid task operad when:
data-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.