You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
All LangGraph reference docs were verified against source code at v1.2.11 and updated accordingly. Four new detailed recipes were added to the recipes guide, and two reference pages received substantive new sections covering APIs that were previously undocumented in the guides.
Version bumps
All six reference docs updated from langgraph==1.2.2 / 1.2.4 → 1.2.11
langgraph_recipes.md updated from 1.2.10 → 1.2.11
New content in reference docs
reference-state-graph.md
Added trace_policy= row to the add_node options table (was missing despite being available since v1.2)
reference-prebuilt-nodes.md
Added a full create_react_agent reference section covering: signature table, pre_model_hook / post_model_hook patterns, dynamic model selection via a callable, and structured output with response_format=
reference-channels.md
Added Overwrite + BinaryOperatorAggregate section showing how to bypass a reducer for a single write, including all three recognised Overwrite forms (typed dataclass, sentinel-key dict {"__overwrite__": v}, JSON-serialized {"value": v, "type": "__overwrite__"})
New recipes (18–21)
#
Title
Key APIs
18
TracePolicy — Hiding Sensitive Payloads in LangSmith
- Recipe 18: import omit_payload from langgraph.types (not langgraph.tracing);
use TracePolicy(process_inputs=omit_payload, process_outputs=omit_payload)
instead of omit_payload(); add scope-limitation note (node span only, not
root graph run)
- Recipe 19: sync ToolCallStream API requires context manager (with graph.stream()
as run); plain for-loop over (mode, data) pairs does not expose run.tool_calls
- reference-prebuilt-nodes create_react_agent: state_schema must include both
messages (add_messages) AND remaining_steps: int; document this requirement
- reference-prebuilt-nodes trim_history hook: fix — returning a slice does not
remove older messages via add_messages (merges by ID); use
RemoveMessage(id=REMOVE_ALL_MESSAGES) + to_keep slice instead
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
… signature
- langgraph_recipes.md: fix remaining v1.2.10 reference in features list body
- reference-prebuilt-nodes.md: state_schema default is None (not MessagesState);
None resolves to built-in AgentState (messages + remaining_steps); update
both the signature comment and the parameter table row to reflect this
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
anonymize is a plain Python callable. The TracePolicy reference says plain function nodes are registered with trace=False and have no span, so these processors never run and this recipe does not demonstrate node-level payload redaction. Wrap the callable in a traced Runnable before attaching the policy.
Correct terminology to personally identifiable information
This unconditional two-node description is false for the response_format option documented below: v1.2.11 adds a generate_structured_response node and makes a separate final model call. Qualify the two-node description as the default case.
Document the complete v1.2.11 create_react_agent signature
This is not the v1.2.11 create_react_agent signature documented in langgraph_comprehensive_guide.md:4760-4767: state_schema defaults to None, name defaults to None, and the debug and version parameters are missing. Users cannot discover the v2/v1 selection or debug option from this reference.
Document hook return variants and ephemeral model messages
The hook contract is narrower/different than this description: pre_model_hook can return llm_input_messages for an ephemeral model-only view without mutating persisted messages, and post_model_hook can return a Command or None as well as a dict. Document these cases so callers do not assume every hook result is merged state.
- scrub_ssn processor matched keys containing "ssn" but the example
state stores PII under raw_pii; rename to scrub_pii and check a
set of known PII field names including raw_pii
- fetch_price tool emitted no output deltas so the ToolCallStream
delta loop yielded nothing; add ToolRuntime parameter and call
emit_output_delta to demonstrate actual incremental streaming
- add a concrete custom-state code example after the state_schema
parameter table showing that MessagesState must be extended with
remaining_steps: int for create_react_agent to accept it
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
add_messages cannot reorder existing messages by ID, so returning
[SystemMessage] + state["messages"] appends the system message at
the end rather than prepending it. Use llm_input_messages instead,
which controls model input directly without going through the reducer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
ToolCallStream is not the delta iterator; the documented streaming channel is output_deltas. Iterating tc_stream will not consume the emitted chunks, so use the channel explicitly.
This issue also appears on line 3288 of the same file.
Correct v1.2.11 signature options and name default
This is not the v1.2.11 signature: debug=False and version="v2" are omitted, while name defaults to None, not "LangGraph". Since this block is presented as a source-verified signature, please include the supported options and correct the default.
Use llm_input_messages to avoid persisting system prompts
Returning messages here writes the new SystemMessage through the add_messages reducer; it does not prepend it, and each loop can append another system message. Return llm_input_messages so the prompt is supplied only to this model call and is not persisted.
Correct terminology to personally identifiable information
The hook contract is broader than “return a dict”: pre_model_hook may return None, and post_model_hook may return a Command or None. The pre-hook also commonly returns llm_input_messages for an ephemeral model-only view, so the reference should document these supported forms.
Describe remaining_steps as managed RemainingSteps
remaining_steps is a managed RemainingSteps field in the built-in AgentState, not an ordinary int. Describing it as int can lead readers to model it as a normal writable state field instead of using the managed field required by create_react_agent.
Update API labels to reflect eight StreamMode values
The verification stamp is now 1.2.11, but this page still labels the API as “seven” in its front matter and section heading even though its StreamMode union contains eight values (tools is the eighth). Please update those labels as part of this refresh; otherwise the page contradicts its own API table.
The reason will be displayed to describe this comment to others. Learn more.
Declare the counter as the managed RemainingSteps type
The new follow-up example satisfies the key-name validation but declares an ordinary int channel, so LangGraph will not inject or decrement the recursion budget; when callers invoke the shown agent without supplying this field, the agent loses the built-in graceful remaining-step handling and may instead run until GraphRecursionError. Import RemainingSteps and declare this as NotRequired[RemainingSteps], matching the actual built-in AgentState.
The reason will be displayed to describe this comment to others. Learn more.
Do not claim save is the only checkpointed value
For a Functional API entrypoint, save= controls the hidden previous channel used by the next invocation, but the returned value is also written to the output channel and get_state(cfg).values exposes that latest output. Consequently this line reports TurnResult, not ThreadState, and the context_used data still occupies checkpoint state; demonstrate persistence by observing previous on the next call rather than claiming this removes the rich result from storage.
`pre_model_hook` and `post_model_hook` run inside the `agent` node, before and after the LLM call respectively. Both receive the current state and must return a dict that is merged back into state.
The reason will be displayed to describe this comment to others. Learn more.
Describe model hooks as separate graph nodes
When either hook is configured, create_react_agent adds dedicated pre_model_hook and post_model_hook nodes around the agent node rather than running both inside it. This distinction is observable in streamed updates, traces, state history, and interrupt_before/interrupt_after; documenting them as internal callbacks leads users to target the wrong node when configuring interrupts or interpreting execution.
This description is false when response_format is used: the API adds a generate_structured_response node and makes a separate structured-output model call. Since response_format is documented below, qualify the two-node statement or mention the extra node and its latency/cost.
Document complete pre- and post-model hook return types
These hook type comments are too narrow: pre_model_hook accepts dict | None, while post_model_hook also accepts Command | None (and the page's own hook guidance currently says both must return a dict). This omits supported no-op and early-routing patterns from the API reference; document the actual return unions.
Document missing parameters and correct the name default
Compared with the v1.2.11 signature documented in langgraph_comprehensive_guide.md:4760-4767, this block omits the public debug and version parameters and gives name the wrong default ("LangGraph" instead of None). Consumers using this reference cannot discover or configure those options, and the shown default is inaccurate.
Recipes 18–21 are appended below, but the guide's feature index still ends at Recipe 17. The new TracePolicy, tool-streaming, entrypoint.final, and v2 invoke topics are therefore missing from the overview; add them to the list or explicitly mark it as non-exhaustive.
Correct the phrase to personally identifiable information
- create_react_agent signature: add debug=False, version="v2", fix name
default to None (was incorrectly shown as "LangGraph")
- Custom state schema: use NotRequired[RemainingSteps] from
langgraph.managed instead of plain int; add managed-value explanation
- Pre/post model hooks: clarify they are separate graph nodes inserted
before/after the agent node, not callbacks inside it
- Recipe 20 get_state(): correct snap.values comment — returns TurnResult
(value= output), not ThreadState; note ThreadState is only accessible
as `previous` on the next call
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
- Line 1062: clarify the graph has a minimum of two nodes; when
response_format is set, a third generate_structured_response node
makes a separate structured-output LLM call (extra latency/cost);
hooks add further nodes before/after agent
- Signature and table: pre_model_hook returns dict | None (must include
messages or llm_input_messages); post_model_hook returns
Command | dict | None (Command overrides default conditional routing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
- "personal-identifiable information" → "personally identifiable
information" (standard term)
- Add Recipes 18-21 to the guide's feature index at the top so
TracePolicy, ToolRuntime delta streaming, entrypoint.final, and
GraphOutput/Durability are discoverable from the overview
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
builder already contains the anonymize node from the complete example above, so executing this alternative block as written tries to register the same node a second time and raises instead of swapping the policy. Mark this block as a replacement for the earlier registration or build a fresh graph for the alternative.
pick_model returns ChatOpenAI(...).bind_tools(...), but this factory's documented callable contract returns a BaseChatModel and the tools argument is bound by create_react_agent itself. Returning the bound runnable can be rebound or rejected when the agent selects the model; return the unbound ChatOpenAI and let the factory bind [search].
The reason will be displayed to describe this comment to others. Learn more.
Import NotRequired from typing_extensions
On Python 3.10, which this guide explicitly supports, typing.NotRequired does not exist because it was added to the standard library in Python 3.11. Readers running this custom-state example on 3.10 therefore get an ImportError; import NotRequired from typing_extensions instead.
The reason will be displayed to describe this comment to others. Learn more.
Describe v1 tool calls as batched rather than sequential
For responses containing multiple tool calls, v1 sends all calls together through one ToolNode invocation, and ToolNode executes that batch concurrently; v2 instead fans the calls out as independent Send tasks. Fresh evidence in the updated diff is this newly added signature line, which now incorrectly labels v1 as sequential and can give readers wrong concurrency and failure-isolation expectations.
- version comment: v1 batches all tool calls into a single ToolNode
invocation (ToolNode runs them concurrently internally); v2 fans each
call out as an independent Send task. "sequential" was wrong.
- NotRequired: typing.NotRequired requires Python 3.11+; use
typing_extensions.NotRequired for Python 3.10 compatibility
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
ans already embeds the full retrieval context because answer() interpolates ctx_str into it at lines 3373–3374, so saving last_answer=ans still persists all of the supposedly heavy intermediate snippets. This makes the “compact, no context snippets” checkpoint claim false; save a context-free answer or another compact representation instead.
Clarify the full return contract for both hooks:
- pre_model_hook: dict | None; llm_input_messages is ephemeral (not
checkpointed — only used as model input for that call)
- post_model_hook: Command | dict | None; Command overrides default
conditional routing
The previous one-line description said "must return a dict" which
omitted None no-ops, Command routing, and the ephemeral nature of
llm_input_messages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
The reason will be displayed to describe this comment to others. Learn more.
Do not claim Command cancels tool routing
When the last AIMessage contains pending tool calls, returning Command(goto=END) from post_model_hook does not replace the graph's conditional routing; the existing router can still schedule the tools unless the hook also removes or replaces those tool calls. The advertised short-circuit can therefore execute side-effecting tools that a guardrail intended to block, so document the required state/message update instead.
The reason will be displayed to describe this comment to others. Learn more.
Preserve tool-call pairs when trimming history
When a conversation contains tool calls, taking the last ten individual messages can retain a ToolMessage while deleting the preceding AIMessage that declared its tool_call_id. After a few tool-using turns, the next model request may therefore contain an orphan tool result and be rejected by OpenAI-compatible backends; trim complete tool-call groups or use llm_input_messages for prompt-only truncation.
durability="exit" persists when the run exits or is interrupted. Since this first invocation calls interrupt(), saying it checkpoints only when the graph exits/no mid-run persistence is inaccurate and obscures why the resume works; the durability table below repeats the same wording.
With this page now verified against 1.2.11, the statement at line 269 that all stream modes apply is followed by a seven-item list that omits tools, even though the canonical streaming reference documents it as the eighth mode. Add tools to this list or narrow the claim.
Update stream mode count and include tools in ALL_MODES
After this version bump, the page is internally inconsistent: its StreamMode union/table already include eight modes including tools (lines 67-79), but the title/frontmatter still says seven and the ALL_MODES example omits tools (line 965). Update all three so the v1.2.11 reference does not teach an incomplete set.
Qualify messages field as required only for non-empty updates
An empty dict is a supported no-op here (the example itself returns {} at line 1159, and chapter-08 documents {}/None as pass-through), so saying a dict "must include" messages or llm_input_messages is too strong. Please qualify this as required only for non-empty updates; the same wording is also repeated in the signature comment at line 1075.
This issue also appears on line 1098 of the same file.
post_model_hook_router is a separate conditional edge writer that runs
regardless of any Command.goto returned by the hook. Returning
Command(goto=END) alone does not prevent tools from firing when the
AIMessage has pending tool calls — the router reads fresh state and
routes to tools independently. Updated docs to reflect the correct
approach: clear tool_calls from the AIMessage to reroute to END.
Also fixed trim_history to drop leading ToolMessages whose parent
AIMessage was cut off by the naive last-N slice. OpenAI-compatible
backends reject orphaned ToolMessages (no matching AIMessage), so the
trim now advances the start of the kept window past any such orphans.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
When the history already starts with a system message this branch returns {}, but the hook contract documented above requires a pre_model_hook result to contain messages or llm_input_messages; this can be rejected instead of acting as a no-op. Return None for the no-op branch.
Return the unbound chat model from the callable model form
The callable model form is expected to return a BaseChatModel, and create_react_agent binds the supplied tools itself (as documented in the parameter table above). Calling bind_tools here returns a bound runnable rather than the required model and can fail dynamic-model validation or double-bind the tools; return the unbound ChatOpenAI instance.
Update StreamMode documentation to reflect eight values including tools
This version bump leaves the page internally inconsistent: StreamMode and the table enumerate eight values, including tools at lines 64–79, while the metadata and section headings still say seven. Update the description and headings to say eight and include tools in the all-modes wording so the v1.2.11 reference does not undercount the API.
The reason will be displayed to describe this comment to others. Learn more.
Replace the existing node instead of registering it again
When this recipe is run top-to-bottom, builder already contains an anonymize node and has already been compiled, so this follow-up add_node("anonymize", ...) raises a duplicate-node ValueError rather than demonstrating the custom processor. Present this as a replacement for the earlier registration, or construct and compile a fresh builder for the custom-policy variant.
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 5ef059f. The custom-processor snippet now constructs its own StateGraph (builder2) and compiles it independently, so running the recipe top-to-bottom no longer raises a duplicate-node ValueError.
Re-using the already-compiled builder raised a duplicate-node ValueError.
The custom-processor example now builds its own StateGraph (builder2)
so it is self-contained and safe to run top-to-bottom.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
This no-op branch returns {}, but the signature and parameter description above say a returned dict must include messages or llm_input_messages; the hook docs also identify None as the no-op form. Return None here (and reflect that in the helper annotation) so the example is consistent with the documented contract.
Add TracePolicy to the langgraph.types import table
This new option introduces TracePolicy as a public type, but the page's import table still omits it from the langgraph.types row at line 53 even though that table says it covers all symbols below. Add TracePolicy there so readers can discover the import path without following the separate link.
> **Deprecated since v1.0.** `create_react_agent` was moved to the separate `langchain` package (`langchain.agents.create_agent`). It remains in `langgraph.prebuilt` for backward compatibility and is scheduled for removal in v2.0.0. For new code, build a `StateGraph` with a `ToolNode` directly (as shown in the minimal example at the top of this page).
`create_react_agent` builds a ReAct-style agent graph in one call. It returns a compiled `StateGraph` with at minimum two nodes — `agent` (the LLM) and `tools` (a `ToolNode`) — wired with `tools_condition`. When `response_format` is set, a third `generate_structured_response` node is appended after `agent`/`tools`; it makes a **separate** structured-output LLM call and adds latency and cost. When hooks are provided, `pre_model_hook` and/or `post_model_hook` nodes are also inserted around `agent`.
The reason will be displayed to describe this comment to others. Learn more.
Account for tool-free agents in the node count
When tools=[], which create_react_agent supports, the factory omits the tools node and tools_condition entirely and can compile a graph containing only agent (plus any optional hook or structured-response nodes). Describing two nodes as the minimum misleads readers configuring node interrupts or interpreting streamed updates for tool-free agents.
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 50b3285. The description now lists nodes conditionally rather than claiming a fixed minimum of two. When tools=[], tool_calling_enabled is False and the factory builds a graph with only agent (plus any optional hook/response nodes), so the docs now reflect that.
| `response_format` | Pydantic model or `(system_prompt, model)` tuple for structured output on the final response. |
| `pre_model_hook` | Separate node inserted **before** `agent`. Returns `dict \| None`; must include at least `messages` or `llm_input_messages`. Returning `None` is a no-op. Use for message trimming, injecting system prompts, etc. |
| `post_model_hook` | Separate node inserted **after** `agent` (v2 only). Returns `Command \| dict \| None`. Returning a `Command` overrides the default conditional routing (tools → end). Returning `None` is a no-op. Use for guardrails, human-in-the-loop, token tracking, etc. |
| `state_schema` | Custom state schema. Default `None` resolves to the built-in `AgentState` which has both `messages` (annotated with `add_messages`) and `remaining_steps: int`. Custom schemas must include both fields — `MessagesState` alone is rejected because it lacks `remaining_steps`. |
The reason will be displayed to describe this comment to others. Learn more.
Require structured_response in custom structured-output state
When a caller combines a custom state_schema with response_format, validation also requires a structured_response field; documenting only messages and remaining_steps causes that supported combination to raise ValueError during create_react_agent. Add this conditional third requirement and show it in the custom-schema example or structured-output section.
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 50b3285. The parameter table now documents that structured_response is also required when response_format is set (verified against chat_agent_executor.py:538-545). The custom-schema example now shows both the base pattern and the response_format variant with structured_response.
… requirement
create_react_agent omits the tools node entirely when tools=[] (verified
at chat_agent_executor.py:787). The "minimum two nodes" claim was wrong;
replaced with a bullet list showing which nodes are added conditionally.
Also: when state_schema + response_format are both set, structured_response
is required (chat_agent_executor.py:540-545). Updated the parameter table
and the custom-schema example to document this and show the correct pattern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
…and table
The signature comment and parameter table both still claimed Command
overrides post_model_hook routing. Removed those claims: clarified
in both places that post_model_hook_router fires as a separate
conditional edge regardless of Command.goto, and that clearing
tool_calls on the AIMessage is the correct way to prevent tools.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
When the first message is already a system message, this hook returns {}, but pre_model_hook requires a dict containing messages or llm_input_messages (or None for a no-op). The documented example therefore fails on that valid input; return the existing messages as an explicit llm_input_messages view (or change the return annotation and use None).
When the first message is already a system message, the hook should
return None (the documented idiomatic no-op) rather than an empty dict.
Update the return type annotation to reflect dict | None.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
Recipe 20 incorrectly presents entrypoint.final as keeping the rich return value out of checkpoint state, making its central storage-saving example misleading.
Review effort: Lite Findings: None
This branch has not been deployed
No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
All LangGraph reference docs were verified against source code at v1.2.11 and updated accordingly. Four new detailed recipes were added to the recipes guide, and two reference pages received substantive new sections covering APIs that were previously undocumented in the guides.
Version bumps
langgraph==1.2.2/1.2.4→1.2.11langgraph_recipes.mdupdated from1.2.10→1.2.11New content in reference docs
reference-state-graph.mdtrace_policy=row to theadd_nodeoptions table (was missing despite being available since v1.2)reference-prebuilt-nodes.mdcreate_react_agentreference section covering: signature table,pre_model_hook/post_model_hookpatterns, dynamic model selection via a callable, and structured output withresponse_format=reference-channels.mdOverwrite+BinaryOperatorAggregatesection showing how to bypass a reducer for a single write, including all three recognisedOverwriteforms (typed dataclass, sentinel-key dict{"__overwrite__": v}, JSON-serialized{"value": v, "type": "__overwrite__"})New recipes (18–21)
TracePolicy— Hiding Sensitive Payloads in LangSmithTracePolicy,omit_payload,add_node(trace_policy=...)ToolCallTransformer— Structured Per-Tool StreamingToolCallTransformer,ToolCallStream,compile(transformers=[...]),stream_mode="tools"entrypoint.final— Decoupled Return and Checkpoint Valueentrypoint.final[R, S],@entrypoint,previousGraphOutputandDurability— v2 Invoke APIGraphOutput,Durability,version="v2",interrupt()All code examples were written from direct inspection of the v1.2.11 source at
/usr/local/lib/python3.11/dist-packages/langgraph/.🤖 Generated with Claude Code
https://claude.ai/code/session_01Kn4Hvrh7QDiJ6HoggwDWgR
Generated by Claude Code