LEAP
LEAP builds skills through two pipelines: Branch A distills a skill from raw data, while Branch B combines multiple skills into one. It is called by the main…
Tool skill for declaring reducers on LangGraph state keys so parallel writes merge instead of crashing. Activates whenever a coder agent designs a StateGraph with parallel branches, fan-out via Send, multi-agent topologies, or whenever a run raises `InvalidUpdateError: At key
$ npx -y skills add agentsope/SkillAlchemy --skill agentsop-state-reducer --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/agentsop-state-reducerContext preview
The summary Claude sees to decide when to auto-load this skill.
Tool skill for declaring reducers on LangGraph state keys so parallel writes merge instead of crashing. Activates whenever a coder agent designs a StateGraph with parallel branches, fan-out via Send, multi-agent topologies, or whenever a run raises `InvalidUpdateError: At key
name: agentsop-state-reducer description: | Tool skill for declaring reducers on LangGraph state keys so parallel writes merge instead of crashing. Activates whenever a coder agent designs a StateGraph with parallel branches, fan-out via Send, multi-agent topologies, or whenever a run raises `InvalidUpdateError: At key '<k>': Can receive only one value per step`. Encodes the rule "every state key is single-writer or has a reducer — nothing in between." version: 0.1.0
> Scope: a single decision — for each state key, declare a reducer or > guarantee single-writer. Out of scope: checkpointers, HITL, supervisor vs. > swarm — see `langgraph-sop` for those.
---
Activate when **any** trigger fires:
or `Annotated[..., <reducer>]` typing.
multiple agents writing shared state, or a supervisor pattern where workers return concurrently.
`At key 'messages': Can receive only one value per step. Use an Annotated key to handle multiple values.`
or "do I need a reducer here?".
Do **not** activate if every key is written by exactly one node per superstep (see §6: over-reducing single-writer keys is an anti-pattern).
---
**LangGraph state is either single-writer or has a reducer. Nothing in between.**
When a node returns `{"k": v}`, LangGraph must decide how to merge `v` into existing `state["k"]`. There are exactly two legal regimes:
1. **Single-writer / "set" semantics** (default, no `Annotated`). At most one node writes the key per superstep. The new value *replaces* the old. Two concurrent writers → `InvalidUpdateError`. 2. **Reducer / "merge" semantics** (`Annotated[T, reducer_fn]`). Any number of writers may write per superstep; LangGraph folds them via `reducer_fn(current, new)`.
The reducer is *commutative-enough* algebra that lets the engine schedule parallel writes without you reasoning about interleavings. Three canonical reducers cover ~90% of real graphs:
| Reducer | Type | Behaviour | |---|---|---| | `add_messages` (from `langgraph.graph.message`) | `list[BaseMessage]` | Append; **dedupe-and-update by message `id`** (in-place edit when IDs match) | | `operator.add` | `list`, `int`, `float`, `str` | List concat / numeric sum | | Custom `(curr, new) -> merged` | anything | Domain-specific merge (keep-latest, dedupe-by-id, LLM-summarise) |
> "Reducers are mandatory, not optional, for parallel execution." > — `[cheatsheet/gotchas]`
The `add_messages` quirk that beginners miss: it is **not** plain append. If a new message shares an `id` with one in state, it overwrites in place. This is what makes HITL `interrupt() + edit-state` work — a human can edit the last AI turn and resume.
The decision is per-key, not per-schema. A schema can mix freely: one key single-writer, another with `add_messages`, another with `operator.add`.
---
Run top-down for every new or modified state schema.
For each key `k` in the state schema, list every node that returns `k` in its update dict. Be paranoid: include nodes spawned via `Send`, subgraphs whose output schema overlaps the parent, and any conditional branches.
swarm handoffs) → **must** declare a reducer. Plain `k: T` will crash.
*optional*: without one, each later write overwrites; with one, each write folds in. Choose based on intent.
> Decision gate: if you cannot answer "which nodes write this key?" in one > sentence per key, stop and redraw the graph before continuing.
Use the OP table in §4. Default ladder:
1. List of `BaseMessage` → `add_messages`. 2. Append-only list of anything else → `operator.add`. 3. Counter / accumulator → `operator.add`. 4. Anything weirder → write a custom reducer (§4 OP-5).
Before shipping, write a unit test that invokes the graph along the parallel path with deterministic node outputs and asserts state matches expectation. If the reducer is wrong (e.g., `operator.add` on dicts), this is where you find out — not in production.
def test_parallel_merge():
out = graph.invoke({"items": []})
assert sorted(out["items"]) == ["a", "b"] # both workers' contributions presentIn a docstring on the TypedDict / Pydantic model, note for each non-default key *why* it has a reducer. Future maintainers will thank you when they refactor.
---
Each op: **Trigger → Action → Output**.
edit-state, multi-agent that all append turns, ReAct loop).
from typing import Annotated, TypedDict
from langchain_core.messages import AnyMessage
from langgraph.graph.message import add_messages
class S(TypedDict):
messages: Annotated[list[AnyMessage], add_messages]in-place (enables HITL state edits).
list (e.g., one chunk per worker in a map step).
Turn people, methods, and experience into installable, reusable agent skills. SkillAlchemy is an open-world agent skill creation system that turns underspecified skill briefs and open-world sources into installable, reusable agent skills.
LEAP builds skills through two pipelines: Branch A distills a skill from raw data, while Branch B combines multiple skills into one. It is called by the main…
Lens — Add a cognitive lens to any problem. It accepts a task description and produces an enhanced description that surfaces hidden dimensions, prerequisites,…
Cross-framework enhancement overlay for choosing a multi-agent topology BEFORE writing any agent. A binary-question rubric — is single-agent + tools enough? do…
SOP for terminal-based, git-native AI pair programming with Aider (git work-tree + tree-sitter repo-map + edit-format + human-in-loop REPL). Use when editing…
Screens biomedical / life-science papers for signs of data fabrication, image manipulation, and statistical anomalies, using the detection techniques distilled…
Universal discipline for any LM-driven loop — agent retries, plan-act-observe, multi-agent handoffs, optimiser passes, test-fix cycles. Encodes the one rule…