Agents API: Managed Agent Lifecycle Control and Concurrent Agent Orchestration
Chapter 31: Artifacts System: Real-Time Generation and Deployment of Code, Charts, and Web Pages
31.1 What Artifacts Changed
Before Artifacts, when Claude generated code or HTML, it appeared as plain text in the conversation. Users had to manually copy it, paste it into a local editor, and run it themselves. This "output as text" model severely limited Claude's practical utility as a tool.
Artifacts transforms Claude from a "text generator" into a "runnable artifact producer." When Claude generates a React component in Claude.ai, users see it compile and run live in the preview pane — no local environment required. This is a fundamentally different experience.
For developers building products with the Claude API, Artifacts carries an additional implication: the same generation patterns that power Claude.ai's Artifact rendering can be replicated in your own application. You can build products where Claude generates interactive, deployable outputs — dashboards, tools, diagrams — directly within your UI.
31.2 The Six Artifact Types
Type 1: Code Artifacts
Code Artifacts are the foundational type: standalone, runnable code in any programming language.
When to generate:
Appropriate for Code Artifacts:
✓ "Write a Python script to read a CSV and generate a statistics report"
✓ "Implement an in-order binary tree traversal function"
✓ "Write a bash script to automatically back up a MySQL database"
Not appropriate:
✗ Explaining a concept (no artifact needed)
✗ Single one-liner code snippets
✗ Code embedded in explanatory prose
Example — CSV Analysis Script:
import csv
import statistics
from collections import defaultdict
def analyze_csv(filepath: str) -> dict:
"""
Analyze a CSV file and return column statistics.
Args:
filepath: Path to the CSV file
Returns:
Dictionary mapping column names to their statistics
"""
data = defaultdict(list)
with open(filepath, newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
for key, value in row.items():
try:
data[key].append(float(value))
except ValueError:
data[key].append(value)
results = {}
for col, values in data.items():
numeric = [v for v in values if isinstance(v, (int, float))]
if numeric:
results[col] = {
"type": "numeric",
"count": len(numeric),
"mean": statistics.mean(numeric),
"median": statistics.median(numeric),
"stdev": statistics.stdev(numeric) if len(numeric) > 1 else 0,
"min": min(numeric),
"max": max(numeric)
}
else:
unique = set(str(v) for v in values)
results[col] = {
"type": "categorical",
"count": len(values),
"unique": len(unique),
"most_common": max(unique, key=lambda x: str(values).count(x))
}
return results
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
print("Usage: python analyze.py <csv_file>")
sys.exit(1)
for col, stats in analyze_csv(sys.argv[1]).items():
print(f"\n{col}:")
for k, v in stats.items():
print(f" {k}: {v:.2f}" if isinstance(v, float) else f" {k}: {v}")
Type 2: SVG Artifacts
SVG Artifacts generate resolution-independent vector graphics that render live in the Claude.ai preview pane.
System architecture diagram example:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 500"
font-family="Arial, sans-serif" font-size="14">
<rect width="800" height="500" fill="#f8f9fa" rx="10"/>
<!-- API Gateway -->
<rect x="300" y="30" width="200" height="60" rx="8"
fill="#4285f4" stroke="#2b5dcc" stroke-width="2"/>
<text x="400" y="55" text-anchor="middle" fill="white" font-weight="bold">
API Gateway</text>
<!-- Services, databases, arrows... -->
<defs>
<marker id="arrow" markerWidth="10" markerHeight="7"
refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#666"/>
</marker>
</defs>
</svg>
Type 3: HTML Artifacts
HTML Artifacts generate complete, runnable web pages with full JavaScript interactivity, rendered in an inline browser:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sales Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, sans-serif; background: #f0f2f5; padding: 24px; }
.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 24px; }
.card { background: white; border-radius: 12px; padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
.card-value { font-size: 32px; font-weight: 700; }
.card-label { color: #666; font-size: 14px; margin-top: 4px; }
.up { color: #52c41a; font-size: 13px; } .down { color: #ff4d4f; font-size: 13px; }
.chart-box { background: white; border-radius: 12px; padding: 24px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
</style>
</head>
<body>
<h1 style="margin-bottom:24px;color:#1a1a2e">Monthly Sales Dashboard</h1>
<div class="cards">
<div class="card">
<div class="card-value">$231,800</div>
<div class="card-label">Monthly GMV</div>
<div class="up">↑ 12.3% vs last month</div>
</div>
<div class="card">
<div class="card-value">4,821</div>
<div class="card-label">Orders</div>
<div class="up">↑ 8.7% vs last month</div>
</div>
<div class="card">
<div class="card-value">$48.0</div>
<div class="card-label">Avg. Order Value</div>
<div class="down">↓ 3.2% vs last month</div>
</div>
</div>
<div class="chart-box">
<canvas id="chart"></canvas>
</div>
<script>
new Chart(document.getElementById('chart'), {
type: 'bar',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
datasets: [{
label: 'GMV ($K)',
data: [185, 172, 198, 215, 206, 231.8],
backgroundColor: 'rgba(66, 133, 244, 0.8)',
borderRadius: 6
}]
},
options: { responsive: true, scales: { y: { min: 150 } } }
});
</script>
</body>
</html>
Type 4: React Artifacts
React Artifacts are the most powerful type — compiled and executed live in the browser:
import { useState } from "react";
const PRIORITIES = ["High", "Medium", "Low"];
const COLORS = {
High: "bg-red-100 text-red-700",
Medium: "bg-yellow-100 text-yellow-700",
Low: "bg-green-100 text-green-700"
};
export default function TaskManager() {
const [tasks, setTasks] = useState([
{ id: 1, title: "Complete API documentation", priority: "High", done: false },
{ id: 2, title: "Review PR #234", priority: "Medium", done: false },
{ id: 3, title: "Update dependencies", priority: "Low", done: true },
]);
const [newTitle, setNewTitle] = useState("");
const [priority, setPriority] = useState("Medium");
const add = () => {
if (!newTitle.trim()) return;
setTasks(p => [...p, { id: Date.now(), title: newTitle.trim(), priority, done: false }]);
setNewTitle("");
};
const toggle = id => setTasks(p => p.map(t => t.id === id ? {...t, done: !t.done} : t));
const remove = id => setTasks(p => p.filter(t => t.id !== id));
const pending = tasks.filter(t => !t.done);
const done = tasks.filter(t => t.done);
return (
<div className="max-w-lg mx-auto p-6">
<h1 className="text-2xl font-bold text-gray-800 mb-6">Task Manager</h1>
<div className="flex gap-2 mb-6">
<input className="flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm"
placeholder="New task..." value={newTitle}
onChange={e => setNewTitle(e.target.value)}
onKeyDown={e => e.key === "Enter" && add()} />
<select className="border border-gray-300 rounded-lg px-3 py-2 text-sm"
value={priority} onChange={e => setPriority(e.target.value)}>
{PRIORITIES.map(p => <option key={p}>{p}</option>)}
</select>
<button onClick={add}
className="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm hover:bg-blue-600">
Add
</button>
</div>
<h2 className="text-sm font-semibold text-gray-500 mb-2">Pending ({pending.length})</h2>
{pending.map(t => (
<div key={t.id} className="flex items-center gap-3 p-3 bg-white border border-gray-200 rounded-lg mb-2">
<input type="checkbox" onChange={() => toggle(t.id)} className="w-4 h-4 cursor-pointer" />
<span className="flex-1 text-sm">{t.title}</span>
<span className={`text-xs px-2 py-1 rounded-full ${COLORS[t.priority]}`}>{t.priority}</span>
<button onClick={() => remove(t.id)} className="text-gray-400 hover:text-red-500">×</button>
</div>
))}
{done.length > 0 && (
<>
<h2 className="text-sm font-semibold text-gray-400 mt-4 mb-2">Done ({done.length})</h2>
{done.map(t => (
<div key={t.id} className="flex items-center gap-3 p-3 bg-gray-50 rounded-lg mb-2 opacity-60">
<input type="checkbox" checked readOnly className="w-4 h-4" />
<span className="flex-1 text-sm text-gray-500 line-through">{t.title}</span>
<button onClick={() => remove(t.id)} className="text-gray-300 hover:text-red-500">×</button>
</div>
))}
</>
)}
</div>
);
}
Type 5: Mermaid Artifacts
Mermaid Artifacts render technical diagrams without any design tools:
sequenceDiagram
autonumber
actor User
participant FE as Frontend
participant GW as API Gateway
participant Auth as Auth Service
participant Order as Order Service
participant DB as Database
User->>FE: Submit order
FE->>GW: POST /api/orders (Bearer token)
GW->>Auth: Validate JWT
Auth-->>GW: Valid, user_id=123
GW->>Order: Create order (user_id=123)
Order->>DB: INSERT INTO orders...
DB-->>Order: order_id=456
Order-->>GW: 201 Created {order_id: 456}
GW-->>FE: 201 Created {order_id: 456}
FE-->>User: Order #456 created successfully
Type 6: Markdown Artifacts
Markdown Artifacts produce standalone documents that can be exported and used in other systems — distinct from conversational text in that they have their own identity, version history, and can be downloaded directly.
31.3 Generating Artifacts via API
The same patterns that power Claude.ai's Artifact rendering work through the standard Messages API:
import anthropic
import re
def generate_artifact(prompt: str, artifact_type: str = "react") -> dict:
"""Generate an artifact via the Claude API"""
client = anthropic.Anthropic()
type_instructions = {
"react": """Generate a complete React component.
Requirements:
- Functional component with Hooks
- Tailwind CSS for styling
- May import from 'recharts' for charts
- Default export
- Self-contained (no external file dependencies)
Wrap output in ```react code block""",
"html": """Generate a complete HTML page.
Requirements:
- Full HTML5 document structure
- CSS in <style> tags, JS in <script> tags
- May use CDN-hosted libraries
Wrap output in ```html code block""",
"svg": """Generate an SVG graphic.
Requirements:
- Complete <svg> element with viewBox
- Professional, clear, appropriately dense
Wrap output in ```svg code block""",
"mermaid": "Generate a Mermaid diagram. Wrap in ```mermaid code block",
"python": "Generate complete runnable Python code. Wrap in ```python code block",
}
instruction = type_instructions.get(artifact_type, f"Generate {artifact_type} code")
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=4096,
system=f"You are a professional code generation assistant.\n{instruction}\nOutput only the artifact, no explanations.",
messages=[{"role": "user", "content": prompt}]
)
raw = response.content[0].text
pattern = rf"```{re.escape(artifact_type)}\n(.*?)```"
match = re.search(pattern, raw, re.DOTALL)
if not match:
match = re.search(r"```\w*\n(.*?)```", raw, re.DOTALL)
return {
"type": artifact_type,
"content": match.group(1).strip() if match else raw,
"raw": raw
}
# Example usage
result = generate_artifact(
"Create a bar chart component showing monthly sales trends using recharts",
artifact_type="react"
)
print(result["content"][:400])
31.4 Multi-Turn Artifact Iteration
Users typically need multiple rounds of refinement. Build an iterator that preserves context:
class ArtifactIterator:
"""Context-preserving multi-turn artifact editor"""
def __init__(self, artifact_type: str = "react"):
self.client = anthropic.Anthropic()
self.artifact_type = artifact_type
self.messages = []
self.current = None
self.history = []
def create(self, prompt: str) -> str:
self.messages.append({"role": "user", "content": prompt})
resp = self._call()
self._save(resp)
return self.current
def modify(self, request: str) -> str:
self.messages.append({
"role": "user",
"content": f"Modify the current {self.artifact_type}: {request}"
})
resp = self._call()
self._save(resp)
return self.current
def revert(self, steps_back: int = 1) -> str:
idx = -(steps_back + 1)
if abs(idx) <= len(self.history):
self.current = self.history[idx]
return self.current
def _call(self) -> str:
instructions = {
"react": "Generate React component with Tailwind CSS, wrap in ```react",
"html": "Generate complete HTML page, wrap in ```html",
"mermaid": "Generate Mermaid diagram, wrap in ```mermaid",
}
system = instructions.get(self.artifact_type, f"Generate {self.artifact_type} code")
response = self.client.messages.create(
model="claude-opus-4-5", max_tokens=4096,
system=system, messages=self.messages
)
text = response.content[0].text
self.messages.append({"role": "assistant", "content": text})
return text
def _save(self, text: str):
pattern = rf"```{re.escape(self.artifact_type)}\n(.*?)```"
match = re.search(pattern, text, re.DOTALL)
if match:
self.current = match.group(1).strip()
self.history.append(self.current)
# Usage
iterator = ArtifactIterator("react")
v1 = iterator.create("Create a simple counter with increment and decrement buttons")
v2 = iterator.modify("Add a reset button that sets counter back to zero")
v3 = iterator.modify("Change the background to light blue, make buttons circular")
v2_restored = iterator.revert(steps_back=1) # Go back to v2
31.5 Embedding Artifact Rendering in Your Product
# Backend: parse artifact type and content from Claude response
def parse_artifact(text: str) -> dict:
type_patterns = {
"react": r"```react\n(.*?)```",
"html": r"```html\n(.*?)```",
"svg": r"```svg\n(.*?)```",
"mermaid": r"```mermaid\n(.*?)```",
"python": r"```python\n(.*?)```",
}
for atype, pattern in type_patterns.items():
m = re.search(pattern, text, re.DOTALL)
if m:
return {"has_artifact": True, "type": atype,
"content": m.group(1).strip(),
"prose": text[:m.start()].strip()}
return {"has_artifact": False, "content": text}
// Frontend: render the appropriate component for each artifact type
function ArtifactRenderer({ artifact }) {
if (!artifact.has_artifact) return <ChatMessage text={artifact.content} />;
switch (artifact.type) {
case 'html':
return (
<iframe srcDoc={artifact.content}
sandbox="allow-scripts allow-same-origin"
className="w-full h-96 border rounded-lg" />
);
case 'mermaid':
return <MermaidDiagram code={artifact.content} />;
case 'react':
return <ReactSandbox code={artifact.content} />;
case 'svg':
return <div dangerouslySetInnerHTML={{ __html: artifact.content }} />;
default:
return <CodeBlock language={artifact.type} code={artifact.content} />;
}
}
Summary
The Artifacts system is the feature that most clearly demonstrates Claude's evolution from language model to interactive tool builder. Each type has a distinct role:
- Code Artifacts — Standalone runnable scripts in any language
- SVG Artifacts — Resolution-independent vector graphics, architecture diagrams
- HTML Artifacts — Complete interactive web pages with CDN library access
- React Artifacts — The most powerful type: live-compiled interactive components with Tailwind, recharts, shadcn/ui
- Mermaid Artifacts — Technical diagrams (sequence, ER, flowchart, Gantt) from text
- Markdown Artifacts — Exportable standalone documents
All of these patterns work through the standard Messages API, enabling any developer to embed Artifact generation capabilities in their own products. The iteration pattern — multi-turn conversation with context preservation and version history — is the key engineering pattern for building production Artifact-generation features.
The next and final chapter of this part examines Claude.ai API integration: how to extend Managed Agent capabilities through official interfaces and enterprise-grade API access patterns.