1. Requirements and the Systems Life Cycle
Key Points
- Functional requirements describe what the system does (task, quality bar, tone, output contract, permitted actions, safety policy); infrastructure requirements describe how it runs (auth, rate limits, pooling, monitoring, cost, retention).
- Solution architecture bridges requirements to a concrete design: pick the building block (API SDK → Agent SDK → MCP servers) that fits.
- Prefer predictable workflows (fixed control flow) and escalate to dynamic agents only when the task is novel or open-ended — complexity is a cost, not a feature.
- Five composable workflow patterns: prompt chaining, routing, parallelization, orchestrator–worker, evaluator–optimizer.
- The systems life cycle (develop → implement → operate → maintain) keeps token budgets, injection defenses, and dual observability in their proper phases.
A functional requirement is anything you can phrase as "the system shall…" — the observable behavior a stakeholder cares about. An infrastructure requirement is the operational scaffolding the user never sees but that decides whether the product survives production. Think of functional requirements as the restaurant menu and infrastructure requirements as the kitchen and plumbing: a great menu backed by a broken kitchen fails just as surely as a working kitchen with a menu nobody wants.
| Functional requirements (what) | Infrastructure requirements (how) |
| The task and its quality bar | Authentication (IdP integration) |
| Tone and voice | Rate limits (RPM / TPM) |
| Structured-output contract | Retry logic and backoff |
| Permitted tools and actions | Connection pooling / request queuing |
| Safety and compliance policy | Monitoring and observability |
| — | Cost budgets and data retention |
Solution architecture turns requirements into components, control flow, and integration patterns. Anthropic's "Building Effective Agents" guidance draws a sharp line: workflows use a predefined control flow (testable, predictable), while agents let the LLM dynamically decide the next step (flexible, suited to open-ended tasks). The core recommendation: start with workflows and graduate to agents only when the task genuinely requires dynamic routing or open-ended exploration.
Within the workflow family, five composable patterns combine like building blocks: prompt chaining, routing, parallelization, orchestrator–worker, and evaluator–optimizer. Overarching principles: keep it simple, build modularly, and make reasoning visible. Production guidance adds progressive disclosure, per-tenant system prompts with clear isolation, and connection pooling plus request queuing for traffic spikes.
flowchart TD
A["Business need + requirements"] --> B{"Is the task structure known in advance?"}
B -->|Yes| C["Workflow: predefined control flow (testable, predictable)"]
C --> D["Compose five patterns: prompt chaining, routing, parallelization, orchestrator-worker, evaluator-optimizer"]
B -->|"No: novel / open-ended / adaptive"| E["Agent: LLM dynamically decides next step"]
D --> F["Start simple, build modularly, make reasoning visible"]
E --> F
The systems life cycle is the end-to-end sequence a Claude application moves through. Develop: choose the building block, define the output contract and tools, engineer prompts, design state, and budget tokens and rate limits here. Implement: wire auth via IdP, add input sanitization and injection defenses, red-team before go-live, establish CI/CD security. Operate: deploy behind rate-limit handling, retries with backoff, and pooling, with dual observability (traditional latency/error signals plus AI-specific quality signals). Maintain: monitor for injection and quality drift, track cost/ROI, manage model migration deliberately, and rotate/scope secrets.
stateDiagram-v2
direction LR
[*] --> Develop
Develop --> Implement
Implement --> Operate
Operate --> Maintain
Maintain --> Develop: iterate on prompts, filters, model migration
Develop: Develop — Building block, output contract, prompts, state design, token budget
Implement: Implement — Auth via IdP, input sanitization, red-teaming, CI/CD security
Operate: Operate — Rate limits, retries+backoff, pooling, dual observability
Maintain: Maintain — Monitor injection and drift, cost/ROI, secret rotation
Animation slot: an interactive decision tree that walks from "Is the task structure known?" through the workflow vs. agent branch, then loops through the four life-cycle phases.
2. Instruction Interpretation Across Interfaces
Key Points
- A system prompt is plain-language instructions delivered before any conversation, sitting at the top of the context window — but where it comes from differs by surface.
- claude.ai / mobile auto-load an Anthropic-authored, date-stamped system prompt plus organization and individual instructions, and manage context on a rolling FIFO basis.
- The Claude API supplies no default system prompt and no org/individual instructions; it is stateless, so you resend full history each turn, and the
system parameter is your primary control surface.
- Claude Code ships a large built-in preset (~600 tokens) weighing "reversibility and blast radius"; the Agent SDK opts in via the
claude_code preset (which does not auto-load CLAUDE.md).
- Safety guardrails are uniform at the model level everywhere — behavior differences come from the instruction layer, not from the model relaxing its rules.
An interface is a distinct Claude surface — claude.ai and mobile, the Claude API, the Agent SDK, Claude Code, and Claude Cowork/Desktop — each with its own convention for where instructions live. On claude.ai, Anthropic automatically loads a full, date-stamped system prompt at the start of every conversation and layers organization and individual instructions on top. The Messages API gets none of that: the published claude.ai updates do not apply, the org/individual instructions live only inside claude.ai, and the API is stateless, so you must resend the full instruction set and history every request.
Claude Code ships its own extensive built-in prompt geared toward agentic coding, instructing Claude to weigh the "reversibility and blast radius" of every action. On the Agent SDK you opt into this with systemPrompt: { type: "preset", preset: "claude_code" } — but note the gotcha: the preset does not auto-load CLAUDE.md; you must set settingSources: ['project'] for those instructions to load.
| Surface | Default system prompt? | Org / individual instructions? | State | Primary control surface |
| claude.ai / mobile | Yes — Anthropic-authored, auto-loaded, date-stamped | Yes | Managed (rolling FIFO) | Anthropic + account settings |
| Claude API | None | No | Stateless — resend each turn | Developer's system parameter |
| Agent SDK | Optional claude_code preset | Via settings sources | Developer-managed | systemPrompt config |
| Claude Code | Yes — large built-in (~600 tokens) | Via CLAUDE.md (if enabled) | Session-managed | Built-in preset + CLAUDE.md |
| Cowork / Desktop | Inherited base behavior | Custom instructions | Session-managed | Model + custom instructions |
The exam-relevant theme: safety guardrails are applied uniformly at the model level across all surfaces, but the system-prompt layer differs. A useful mental model is that claude.ai is a furnished apartment (lights, appliances, and house rules pre-installed) while the API is a bare shell where you supply every fixture yourself. Never assume a prototype that "just works" in claude.ai will behave identically on the API.
Animation slot: a side-by-side "furnished apartment vs. bare shell" panel that toggles between surfaces, lighting up which layers (default prompt, org instructions, state) are present on each.
3. Content Boundaries and Schema Design
Key Points
- Content boundaries keep trusted instructions (system prompt, genuine user request) separate from untrusted third-party content (web pages, emails, docs, tool results).
- Two threat models: jailbreaks / direct injection (the user is the adversary) and indirect injection (the user is trusted, but adversarial content arrives from elsewhere).
- Put untrusted content only in labeled, JSON-encoded
tool_result blocks; state an <untrusted_content_policy> in the system prompt; apply least privilege; screen inputs with a lightweight model; red-team and monitor.
- Structured outputs have two halves: JSON outputs (
output_config.format) control what Claude says; strict tool use (strict: true) validates how Claude calls functions.
- Constrained decoding compiles the schema into a grammar that restricts generation, making the schema an enforceable contract — not a hope.
Content boundaries are the design decisions that separate trusted instructions from untrusted content. Claude is inherently resilient (Anthropic hardens it via RL that exposes it to injections during training), but application-level design is still required. Documented techniques: put untrusted content only in tool_result blocks (never in system or plain user text); label the content's nature and source; state an untrusted-content policy in the system prompt; JSON-encode third-party strings so escaping gives unambiguous delimiters; keep your own instructions out of tool results; apply least privilege; screen inputs and outputs with a lightweight model (e.g., Haiku 4.5) constrained to a boolean verdict; and red-team before deploying while monitoring continuously.
Think of it like a newsroom: the editor's standards (your system prompt) are trusted, and a tip that arrives in the mail (an untrusted tool result) might contain useful facts — but a professional newsroom reports on the tip; it never lets an anonymous letter rewrite editorial policy.
flowchart TD
subgraph Trusted["Trusted zone — instructions to obey"]
SP["System prompt (incl. untrusted-content policy)"]
UR["User's genuine request (user text block)"]
end
subgraph Untrusted["Untrusted zone — data to report, never obey"]
TR["tool_result blocks: web pages, emails, docs, OCR, search results"]
end
TR -->|"labeled + JSON-encoded"| CLAUDE["Claude reads with skepticism"]
SP --> CLAUDE
UR --> CLAUDE
CLAUDE --> OUT["Reports on untrusted content; never lets it override system prompt or user request"]
Schema design defines explicit, machine-checkable structures for inputs and outputs. On the output side, structured outputs constrain responses to a specific schema. JSON outputs control what Claude says; strict tool use (strict: true) validates how Claude calls your functions. The mechanism underneath is constrained decoding: the schema is compiled into a grammar that restricts token generation during inference — structurally stronger than just asking for valid JSON.
With additionalProperties: false and constrained decoding, an app can call JSON.parse with confidence and route on a field like category without defensive retry logic. Best practices: avoid recursive schemas, use additionalProperties: false, write descriptive field names/descriptions, set generous max_tokens buffers, and monitor stop_reason for refusals or truncation. Expect a small overhead (~50–200 tokens, ~2–3% cost at scale) — more than offset by eliminating retry code. A schema is a contract between Claude and the rest of the system, enforceable at generation time.
Animation slot: a live "context window" panel where dragging an untrusted document into the system-prompt zone triggers a warning, and dropping it into a labeled JSON-encoded tool_result block turns it safe.
4. Session Hygiene and Plugins
Key Points
- The Messages API is stateless: resend the full message array each turn; roles
user/assistant must alternate, starting with user.
- Everything counts toward the context window — system prompt, all messages, tool defs, and generated output (including extended thinking).
- Context rot: as token count grows, accuracy and recall degrade, so curating context matters as much as raw capacity (up to 1M tokens on some models; 200k on others like Sonnet 4.5).
- Hygiene toolkit: server-side compaction (beta), context editing (clear tool results/thinking), context awareness/task budgets, and the token counting API to estimate before sending.
- In Claude Code, plugins extend the tool via marketplaces (add then install). Treat each as a dependency with a trust level and a context cost; per-tenant isolation and least-privilege secrets prevent state leakage.
Because the Messages API is stateless, sustaining a multi-turn conversation means resending the entire message array each turn, with user and assistant roles alternating and starting with user. Session hygiene is the discipline of keeping that accumulating state clean, relevant, and bounded — it matters because everything counts toward the context window. Capacity is not the whole story: as token count grows, accuracy and recall degrade, a phenomenon called context rot. The context window is a whiteboard, not a filing cabinet: once it fills, stale scribbles must be erased or you run out of room mid-thought.
The hygiene toolkit: server-side compaction (beta) summarizes earlier turns; context editing clears tool results and thinking blocks; context awareness and explicit task budgets help the model pace long tasks; and the token counting API estimates size before sending. Overflow before generation returns a 400 invalid_request_error; overflow during generation on 4.5+ models stops with stop_reason: "model_context_window_exceeded".
flowchart TD
A["Context window (bounded budget): system prompt + all messages + tool defs + generated output"] --> B{"Approaching token limit?"}
B -->|No| C["Continue conversation"]
B -->|Yes| D["Apply hygiene toolkit"]
D --> E["Server-side compaction: summarize earlier turns"]
D --> F["Context editing: clear tool results / thinking"]
D --> G["Token counting API: estimate before sending"]
E --> C
F --> C
G --> C
B -->|"Overflow anyway"| H["400 invalid_request_error or stop_reason: model_context_window_exceeded"]
C --> I["Guards against context rot and state leakage"]
In Claude Code, plugins extend the tool with skills, agents, hooks, MCP servers, and LSP servers, and marketplaces are catalogs of plugins. Using one is two steps: add the marketplace (registers the catalog, installs nothing), then install individual plugins. The /plugin manager (Discover, Installed, Marketplaces, Errors) shows a context-cost estimate per plugin — a direct tie back to session hygiene. Install scopes are user, project, local, and managed. Security is central: plugins can execute arbitrary code with the user's privileges, so install only from trusted sources; organizations can restrict marketplaces via managed settings (strictKnownMarketplaces, extraKnownMarketplaces, pluginSuggestionMarketplaces).
Since the API is stateless, the developer owns the boundaries between sessions. Two practices prevent state leakage: per-tenant system prompts with clear isolation (so tenant A's history never shares a window with tenant B's), and session hygiene tooling (clearing tool results, compacting old turns, starting fresh message arrays). Statelessness is a gift here — nothing persists automatically, so leakage only happens if you carry it over.
Animation slot: a "whiteboard" that fills with turns until it hits the limit, then lets the learner apply compaction or context editing to reclaim space and watch recall recover.