Magic Docs
- Entity ID:
ent-20260410-28702b2eb098 - Type:
service - Scope:
shared - Status:
active - Aliases: magic-docs
Description
Magic Docs is a background service that automatically maintains markdown documentation files as a conversation progresses. Any file whose first line matches the pattern # MAGIC DOC: [title] is detected and registered for continuous updates. A constrained Sonnet child agent rewrites the document in the background to incorporate new learnings from the conversation, without the user or primary agent needing to do anything. The feature is gated to Anthropic employees only (USER_TYPE === 'ant').
How it works
Detection and registration
Magic Docs hooks into the FileReadTool. When any file is read during a session, a registered listener (registerFileReadListener) inspects the content for a header matching the regex /^#\s*MAGIC\s+DOC:\s*(.+)$/im. If the header is found, the file path is added to an in-memory trackedMagicDocs map. Each file is registered at most once per session.
An optional instructions line can follow the header: an italicized line (wrapped in _ or *) immediately after the # MAGIC DOC: header (with at most one blank line between). This line provides document-specific update instructions that take priority over the general update rules.
Example:
# MAGIC DOC: Architecture Overview
_Focus on high-level module boundaries, skip implementation details_
Update trigger: post-sampling hook
Updates do not run on a timer. The service registers a post-sampling hook (registerPostSamplingHook) that fires after every model sampling round. The hook applies three guards before updating:
- Source check -- only runs when
querySource === 'repl_main_thread'(ignores sub-agents, compaction, and other internal queries). - Idle check -- only runs when the last assistant turn contains no tool calls (i.e., the conversation is idle, not mid-execution).
- Tracked docs exist -- skips if the
trackedMagicDocsmap is empty.
When all three pass, the hook iterates over every tracked doc and updates them sequentially. The sequential() wrapper prevents concurrent update runs from racing.
The update agent
Each tracked document is updated by a forked sub-agent with these constraints:
| Property | Value |
|---|---|
| Agent type | magic-docs (built-in) |
| Model | sonnet |
| Allowed tools | Edit only (FILE_EDIT_TOOL_NAME) |
| File scope | canUseTool callback restricts Edit to the specific magic doc path -- all other tool calls are denied |
| Query source | magic_docs |
| Async | true (runs without blocking the main thread) |
| Context | Receives a fork of the full conversation messages, system prompt, and user/system context |
The agent operates on a cloned FileStateCache with the doc's entry deleted, forcing a fresh read of the file content (bypassing FileReadTool's dedup that would otherwise return a file_unchanged stub).
Before invoking the agent, the service re-reads the file. If the file has been deleted, is inaccessible, or no longer contains the magic doc header, it is silently removed from tracking.
The update prompt
The prompt (src/services/MagicDocs/prompts.ts) instructs the Sonnet agent to:
- Incorporate new learnings from the conversation into the document
- Keep the document current (not a changelog -- update in-place, remove outdated info)
- Preserve the
# MAGIC DOC:header and any instructions line exactly as-is - Fix errors, clean up irrelevant sections, maintain good organization
- Only update when there is substantial new information; otherwise do nothing
- Follow a "terse, high signal" documentation philosophy: focus on architecture, entry points, design rationale, and non-obvious patterns; skip implementation details that are obvious from reading source code
The prompt explicitly warns the agent not to leak references to "documentation updates" or "magic docs" into the document content.
Custom prompts
Users can override the default update prompt by placing a file at ~/.claude/magic-docs/prompt.md. The custom prompt supports {{variable}} substitution with four variables: {{docContents}}, {{docPath}}, {{docTitle}}, and {{customInstructions}}. If the custom prompt file doesn't exist or fails to load, the built-in template is used silently.
Session lifecycle
- Tracked magic docs are cleared on
/clearand session resume (clearTrackedMagicDocs()called fromclearSessionCaches). - Documents are re-detected naturally as they are read again in the new session.
Key claims
- Detection is passive and opportunistic: files are only registered when read, not scanned proactively
- Updates are event-driven (post-sampling hook), not timer-based -- they fire after every idle model turn
- The child agent is sandboxed to a single tool (Edit) scoped to a single file path
- The
sequential()wrapper serializes updates, preventing concurrent magic doc writes from racing - A file that loses its
# MAGIC DOC:header or gets deleted is automatically deregistered
Relations
rel-20260410-magic-housekeeping: startBackgroundHousekeeping --[initializes]--> Magic Docs (initMagicDocs()called at startup)rel-20260410-magic-fileread: FileReadTool --[notifies]--> Magic Docs (viaregisterFileReadListener)rel-20260410-magic-postsampling: post-sampling hooks --[triggers]--> Magic Docs update cyclerel-20260410-magic-agent: Magic Docs --[spawns]--> Sonnet sub-agent (viarunAgent, constrained to Edit tool)
Sources
src-20260409-e9925330d110, source code at src/services/MagicDocs/