name: docs-code-samples description: Use this skill when migrating inline code samples from LangChain docs (MDX files) into external, testable code files that are extracted by this repo’s snippet scripts and used as Mintlify snippets. Applies when extracting code blocks from documentation, creating runnable code samples, using snippet delineators, or wiring snippet output into MDX includes. license: MIT compatibility: LangChain docs monorepo with Mintlify. Requires Python and Make (Node.js is also required for TypeScript samples). metadata: author: langchain version: "1.0"
docs-code-samples
Overview
This skill documents the workflow for moving inline code samples from LangChain documentation into standalone, testable files that this repo extracts into snippets for use in MDX using Mintlify.
When to use
- Migrating inline Python, TypeScript/JavaScript, or Java code blocks from MDX to external files
- Creating runnable, testable code samples for documentation
- Setting up snippet extraction and Mintlify snippet includes
Directory structure
Code samples live under src/code-samples/ in folders that match the product:
langchain/— LangChain docslanggraph/— LangGraph docsdeepagents/— Deep Agents docslangsmith/— LangSmith docs
Example:
src/
├── code-samples/ # Source: testable code with snippet tags
│ ├── langchain/
│ │ ├── return-a-string.py
│ │ └── return-a-string.ts
│ ├── langgraph/
│ │ ├── langgraph-sql-agent.py
│ │ └── langgraph-sql-agent.ts
│ ├── deepagents/
│ │ └── example-skill.py
│ └── langsmith/
│ ├── trace-example.py
│ └── trace-example.java
├── code-samples-generated/ # Snippet output (gitignored)
│ ├── return-a-string.snippet.tool-return-values.py
│ ├── return-a-string.snippet.tool-return-values.ts
│ └── ...
└── snippets/
└── code-samples/ # MDX snippets for docs (all products)
├── tool-return-values-py.mdx
├── tool-return-values-js.mdx
└── ...
Prefer one file per doc page or topic: Collocate related snippets in a single code sample file whenever they belong to the same MDX page, tutorial flow, or feature (for example, setup plus invocation, or a do/don't pair). Use multiple :snippet-start: / :snippet-end: pairs in that file rather than splitting into several .py or .ts files. Reserve separate files for unrelated samples or when a page genuinely needs independent test entry points.
More than one snippet in one file: A single code sample file can contain more than one named snippet using different :snippet-start: snippet-name and :snippet-end: pairs. Each snippet must have a unique name. Shared imports, helpers, and :remove-start: test harness code live once in the file; only the fenced regions between snippet tags appear in the generated MDX snippets.
When to split TypeScript samples into separate files: Python samples can usually keep multiple snippets in one file because later definitions overwrite earlier ones at module scope. TypeScript and JavaScript cannot: make test-code-samples runs the entire .ts file, and every snippet's code executes in the same module scope. Split into separate .ts files when snippets would collide, for example:
- Duplicate
importbindings (for example two snippets bothimport { interrupt } from "@langchain/langgraph") - Duplicate
const/let/class/functiondeclarations with the same name (for example two snippets both declareconst State = ...) - Two self-contained snippets that each need their own imports and top-level setup
Keep related snippets in one Python file when possible. For TypeScript, use one file per independently runnable snippet when imports or top-level bindings would conflict. Name sibling files clearly, for example langgraph-interrupts-validate-conditional-edge-pattern.ts and langgraph-interrupts-validate-conditional-edge.ts. Put shared test-only setup in :remove-start: blocks inside each file rather than importing between sample files.
Within a single TypeScript file, :remove-start: blocks and snippet regions share the same module scope when make test-code-samples runs the file. Do not import the same binding in both places. Keep imports that appear in the docs snippet inside the snippet; limit :remove-start: imports to symbols used only by the test harness (for example Command, MemorySaver) that the snippet does not import.
Step-by-step instructions
1. Create the code sample file
Place the file under src/code-samples/ in the folder for the product: langchain/, langgraph/, deepagents/, or langsmith/ (for example, src/code-samples/langgraph/langgraph-sql-agent.py for LangGraph docs).
Use a descriptive filename, for example, return-a-string.py, return-a-string.ts, or traceable-pipeline.java. When a doc page needs several code blocks for the same feature, add them as multiple snippets in one Python file (for example, rubric-configure.py with rubric-configure-py and rubric-invoke-py) instead of creating rubric-configure.py and rubric-invoke.py. For TypeScript, use one file per snippet when module-scope imports or bindings would conflict (see When to split TypeScript samples into separate files above).
2. Add snippet delineators
Wrap the code that should appear in the docs with snippet tags:
Python:
# :snippet-start: snippet-name-py
from langchain.tools import tool
@tool
def get_weather(city: str) -> str:
"""Get weather for a city."""
return f"It is currently sunny in {city}."
# :snippet-end:
TypeScript/JavaScript:
// :snippet-start: snippet-name-js
import { tool } from "langchain";
// ... tool definition ...
// :snippet-end:
Java:
// :snippet-start: snippet-name-java
public class Example {
public static void main(String[] args) {
System.out.println("hello");
}
}
// :snippet-end:
Choose a unique snippet-name in kebab-case. All snippet names must include a language suffix: -py for Python files, -js for TypeScript/JavaScript files, -java for Java files, and -kt for Kotlin files (for example, tool-return-values-py, tool-return-values-js, traceable-pipeline-java, traceable-pipeline-kt). This becomes the base of the output filename.
3. Add runnable test code in remove blocks
Wrap any code that makes the sample executable but should not appear in docs:
Python:
# :remove-start:
if __name__ == "__main__":
result = get_weather.invoke({"city": "San Francisco"})
assert result == "It is currently sunny in San Francisco."
print("✓ Tool works as expected")
# :remove-end:
TypeScript:
// :remove-start:
async function main() {
const result = await getWeather.invoke({ city: "San Francisco" });
if (result !== "It is currently sunny in San Francisco.") {
throw new Error(`Expected "...", got "${result}"`);
}
console.log("✓ Tool works as expected");
}
main();
// :remove-end:
The extraction script strips :remove-start: / :remove-end: content when extracting snippets.
4. Test the code sample
Before extracting snippets, verify the code sample runs correctly:
# Test the file(s) you added (faster)
make test-code-samples FILES="src/code-samples/langchain/return-a-string.py"
# Or run all code samples
make test-code-samples
For multiple files: FILES="path1 path2". Fix any failures before proceeding—do not extract snippets until the samples pass.
Java files (.java) under src/code-samples/ are run using jbang. To keep CI green, Java samples must:
- Print at least one line of output so it's obvious the sample ran
- Exit successfully (code 0) when optional API keys are not set, for example:
OPENAI_API_KEYfor LLM calls
- Fail fast (non-zero exit) when a key is required for the sample to run, for example
manage-prompts-0-push.javawithoutLANGSMITH_API_KEY
make test-code-samples runs every .java file under src/code-samples/ in lexical path order (after all Python and TypeScript samples). That order is unrelated to section order in the docs. If one sample must run before another (for example creating a hub prompt before pulling it), name the source files so they sort correctly. For example, manage-prompts-pull.java runs before manage-prompts-push.java because pull sorts before push; use prefixes such as manage-prompts-0-push.java and manage-prompts-1-pull.java when you need push to run first.
Check formatting with:
make lint
Fix any ruff or mypy issues before proceeding. Run make format to auto-fix formatting.
5. Run snippet extraction
From the repo root:
make code-snippets
For LangSmith JVM samples only (faster; updates stems listed in CODE_SNIPPET_LANGSMITH_SOURCES in the Makefile):
make code-snippets-langsmith
This command:
- Runs
python scripts/extract_code_snippets.py(line-based, Bluehawk-compatible; handles/**in TS strings). Optional envCODE_SNIPPET_SOURCESlimits extraction to specific paths undersrc/code-samples/(make code-snippets-langsmithsets this). - Runs
scripts/generate_code_snippet_mdx.pyto produce MDX snippets insrc/snippets/code-samples/(always regenerates MDX from everything undersrc/code-samples-generated/)
Output files:
return-a-string.snippet.tool-return-values.py→tool-return-values-py.mdxreturn-a-string.snippet.tool-return-values.ts→tool-return-values-js.mdx
6. Update the MDX file to use the snippet
Add an import at the top of the MDX file (after frontmatter):
import ToolReturnValuesPy from '/snippets/code-samples/tool-return-values-py.mdx';
import ToolReturnValuesJs from '/snippets/code-samples/tool-return-values-js.mdx';
Replace the inline code blocks with the snippet components:
:::python
<ToolReturnValuesPy />
:::
:::js
<ToolReturnValuesJs />
:::
Naming conventions
| Element | Convention | Example |
|---|---|---|
| Code file | Descriptive, kebab-case | return-a-string.py, return-a-string.ts, traceable-pipeline.java, traceable-pipeline.kt |
| Snippet name | Kebab-case with language suffix: -py for Python, -js for JS/TS, -java for Java, -kt for Kotlin |
tool-return-values-py, tool-return-values-js, traceable-pipeline-java, traceable-pipeline-kt |
| MDX snippet (Python) | {snippet-name}.mdx (snippet name ends in -py) |
tool-return-values-py.mdx |
| MDX snippet (JS) | {snippet-name}.mdx (snippet name ends in -js) |
tool-return-values-js.mdx |
| Component name | PascalCase | ToolReturnValuesPy, ToolReturnValuesJs |
Script behavior
scripts/generate_code_snippet_mdx.py:
- Reads
*.snippet.*.pyand*.snippet.*.tsfromsrc/code-samples-generated/ - Wraps content in fenced code blocks (
```pythonor```ts) - Writes to
src/snippets/code-samples/{snippet-name}-py.mdxor-js.mdx
To support additional languages, add config entries in that script.
Guidelines
- Collocate related snippets in one code sample file per doc page or feature when possible (Python and Java). Import each generated MDX snippet separately in the MDX file (for example,
<RubricConfigurePy />then<RubricInvokePy />from the same source file). For TypeScript, split into separate.tsfiles when snippets duplicate imports or top-level bindings; still import each generated MDX snippet in the MDX file the same way. - Do not mock LangChain internals (for example
unittest.mock.patchoninit_chat_modelhelpers) so that imports resolve real chat model instances. Do not use fake chat models in docs code samples (for exampleGenericFakeChatModel,FakeListChatModel, or otherlangchain_coretesting fakes). Wire a real chat model (for exampleChatOpenAI) so snippets match what readers run;make test-code-samplesrequires a valid API key when the sample calls the model. - Do not change
pyproject.tomlwhen making code sample changes. - Always run
make test-code-samples FILES="path/to/your/file.py"beforemake code-snippetsto ensure new samples pass. - Run
make lintonce the code sample is written; fix any issues (or runmake formatto auto-fix). - Do not add code samples to linting ignore rules when making lint-related changes—fix the code instead.
src/code-samples-generated/is gitignored; regenerate withmake code-snippetsormake code-snippets-langsmithwhen iterating on LangSmith JVM files only.- Reference
CLAUDE.mdandAGENTS.mdfor docs style and rules. - Use
:::pythonand:::jsfences for language-specific content; the build produces separate Python and JavaScript doc versions. - For python tests, try to correct the type rather than adding
# type: ignore[arg-type]