TLDR
Claude is one model family reached through several host surfaces, claude.ai/Desktop, Claude Code, and the raw Messages API/SDKs, and each supplies a different (or absent) scaffold: system prompt, persistent instructions, session hygiene, plugin infrastructure. The Messages API is a blank slate by default: Anthropic states its host system-prompt updates "do not apply to the Claude API," so every convenience a prototype enjoyed in claude.ai must be built explicitly at the API layer. Anthropic: system-prompts release notes
What it is
A Claude application is designed against whichever host surface it runs on, and the surfaces do not behave identically. claude.ai and Desktop inject a versioned system prompt into every conversation (today's date, Markdown-for-code conventions, guardrails); Claude Code auto-loads project memory from CLAUDE.md at the start of every session; a raw messages.create() call gets no default system prompt at all unless you pass your own system parameter. Designing a Claude application means knowing precisely what the host supplies for free and what has to be built explicitly once you leave that host.
This matters most at the boundary where a team prototypes in one surface and ships in another. A prompt tuned inside claude.ai or Claude Code is quietly relying on that surface's injected system prompt, session conventions, and persistent-memory file, none of which travel with the prompt text itself when it moves to POST /v1/messages.
How it works
System prompts are host-specific, not model-inherent. claude.ai/mobile ship a versioned system prompt per conversation; Anthropic is explicit that "these system prompt updates do not apply to the Claude API." A bare Messages API call starts with nothing until you set system yourself, request by request.
Persistent instructions are a Claude Code convention, not an API primitive. CLAUDE.md files "are loaded into the context window at the start of every session, consuming tokens alongside your conversation." The API has no equivalent auto-load: persistent instructions must be re-sent in system or the first message on every single request, or built into your own harness.
Session hygiene is a Claude Code UX layer. /clear resets stale context between unrelated tasks; /compact [focus instructions] summarizes history near context limits and is steerable from CLAUDE.md; /context and /mcp show what is consuming the window. Anthropic recommends keeping CLAUDE.md "under 200 lines," pushing workflow detail into on-demand Skills instead. The API's analogous unit is the message list you build per call plus prompt caching; there is no built-in /compact equivalent, that logic is yours to write.
Plugin management is Claude Code-specific infrastructure. A plugin is a directory containing .claude-plugin/plugin.json plus any of skills/, commands/, agents/, hooks/hooks.json, .mcp.json, .lsp.json, bin/, and settings.json at the plugin root (never inside .claude-plugin/). A plugin's MCP servers auto-start when the plugin is enabled, no manual startup step. Manage plugins via /plugin, add a marketplace with /plugin marketplace add owner/repo, and skills namespace as /plugin-name:skill so two plugins never collide on the same command name.
Schema design and content boundaries live at the API layer as two independent, combinable controls. output_config.format (a JSON Schema) constrains the *response text itself*; strict: true on a tool definition constrains *tool-call arguments* via grammar-constrained sampling, applied per tool. Both support basic types, enum, const, required, additionalProperties: false, select string formats, and minItems of 0 or 1; neither supports minimum/maximum, minLength/maxLength, recursive schemas, or external $ref. Compliance is not guaranteed when stop_reason is "refusal" (the refusal message overrides the schema) or "max_tokens" (the output is simply cut off mid-schema).

Where you'll see it
Internal code-review plugin
A team packages a repeatable code-review workflow as a Claude Code plugin (skills + hooks + an MCP server) and distributes it via an internal marketplace instead of leaving it in one developer's .claude/ directory.
Guaranteed-shape extraction service
A data-extraction endpoint on messages.create() uses output_config.format for the response schema, since no host scaffold like claude.ai's system prompt exists at the API layer to make the output shape trustworthy on its own.
Side-by-side
| Interface | System prompt | Persistent instructions | Session hygiene | Structured output control |
|---|---|---|---|---|
| claude.ai / Desktop | Host-injected, versioned per conversation | Project custom instructions + knowledge base | Host-managed (rolling, chat UI) | None; conversational output only |
| Claude Code | Harness-level, not a per-app system prompt | CLAUDE.md auto-loaded every session | /clear, /compact, /context, /mcp | N/A; agentic coding, not schema-bound output |
| Messages API / SDKs | None; blank slate unless you set system | Must be re-sent every request, no auto-memory | You build it: message list + prompt caching | output_config.format (response) or tool strict: true (args) |
Decision tree
Are you inside a host surface (claude.ai/Desktop or Claude Code), or calling the raw Messages API?
system, persistent instructions, and session logic explicitly.Do you need Claude's output to guarantee a schema?
output_config.format, or a tool's arguments with strict: true, these are independent, combinable controls, not the same knob.Are you building a capability meant to be reused by a whole Claude Code team, not just you?
skills/, hooks/hooks.json, .mcp.json) distributed via a marketplace, not left in one developer's personal .claude/ directory.Is context ballooning toward the window limit?
/compact [focus]; on the API, you implement your own summarization/prompt-caching strategy, there is no server-side /compact.Question patterns

A developer prototypes a data-extraction prompt in claude.ai and gets clean, well-formatted answers. They port the identical prompt text to `messages.create()` and the output becomes inconsistent prose. What's the most likely cause?
system at all. Named distractor: "the API model is a weaker version of the claude.ai model", wrong, it's the same model family, the missing scaffold is the system prompt and formatting convention, not model capability.A team builds a useful internal code-review workflow (a skill plus a hook plus an MCP server) inside one engineer's personal `.claude/` directory. Another team member wants to reuse it. What should the team do?
.claude-plugin/plugin.json plus skills/, hooks/hooks.json, .mcp.json) and distribute it via a marketplace so it installs as /plugin-name:skill for everyone. Named distractor: "have everyone copy the .claude/ folder manually", that's exactly the un-versioned, un-governed pattern plugins exist to replace.A pipeline needs Claude's response text to strictly match a JSON Schema for downstream ingestion, and separately needs one tool's arguments to be schema-conformant before execution. How many controls are needed, and which?
output_config.format constrains the response text; strict: true on the tool definition constrains that tool's arguments. Named distractor: "strict: true on the tool also enforces the final response schema"`, wrong, it only governs tool-call arguments, not the model's prose output.A structured-output pipeline occasionally returns text that doesn't match the configured JSON Schema even though the schema itself is valid. What two `stop_reason` values explain this, and why?
"refusal" (the refusal message takes precedence over schema constraints) and "max_tokens" (the output was cut off mid-schema). Named distractor: "the schema was silently ignored by the model", wrong, schema compliance is enforced except in these two documented edge cases, which the caller must check for explicitly.A `CLAUDE.md` file has grown to 600 lines covering every possible workflow, and sessions now start slower and burn more tokens before any work happens. What's the recommended fix?
CLAUDE.md under roughly 200 lines and push on-demand workflow detail into Skills, which load only when relevant rather than being injected into every session's context. Named distractor: "switch to a model with a larger context window to absorb it", that treats the symptom (token cost) while leaving the root cause (always-loaded, rarely-needed detail) in place.Frequently asked
Does claude.ai's injected system prompt apply to API calls?
messages.create() call has no default system prompt unless you set system yourself.Do a plugin's MCP servers need to be started manually?
Work this with your AI
Work this concept hands-on with Claude Code, Codex, or claude.ai. Copy a prompt, paste it into your assistant, and practise in tandem. Each one keeps you active (explain it back, get drilled, or build) rather than just reading.
- Drill it like the exam (scenario MCQs)Practice in the exam's scenario-MCQ format with trap awareness.
- Explain it back (Feynman)Build durable, transferable understanding of a concept you can half-state.
- Test me, adapting the difficultyActive recall practice on a concept you think you know.
- Check my prerequisites firstBefore studying a concept that keeps not sticking.
- Find the high-leverage 20%When a domain feels too big and you are short on time.
