Tutorials & Guides
How to Build a Local File-Watcher that Uses Claude to Auto-Document Your Codebase
Stop writing documentation manually. Build a lightweight Python daemon that monitors your local files and uses Claude to update your project docs in the background every time you hit save.
Updated 9/2/2026
The Documentation Debt is Real
We all know the drill. You start a project with the grandest intentions of maintaining pristine, comprehensive documentation. Three days later, you’re knee-deep in a refactoring session, your functions have mutated three times, and your markdown files are relics of a distant past.
Instead of breaking your flow to update documentation, we can automate the chore. In this tutorial, we will build a lightweight Python daemon that sits quietly in the background, watches your local directories for changes, and uses the Claude API to update your project's documentation files in real-time. It runs locally, respects your gitignore, and keeps your project’s documentation ticked over without you having to lift a finger.
Why Build a Daemon Instead of Using an IDE Extension?
IDE extensions are brilliant, but they are also incredibly noisy. They pop up suggestions when you are mid-thought, interrupt your typing, and demand immediate attention.
By building an independent background file-watcher, we separate code execution from documentation generation. You write code, hit save, and go grab a cup of tea. By the time you look at your docs/ folder, the changes have been catalogued. We will use /platforms/claude for this, as its ability to grasp codebase architecture and write structured markdown is unmatched in the current LLM landscape.
Prerequisites
To build this tool, you will need: - Python 3.10 or higher installed on your machine. - An Anthropic API key. - A clean workspace directory to test on.
First, let's install the necessary Python packages. We will use watchdog to monitor our filesystem and the official anthropic SDK to communicate with Claude.
`bash
pip install watchdog anthropic python-dotenv
`
Create a .env file in your root folder and add your credentials:
`env
ANTHROPIC_API_KEY=your_api_key_here
`
Step 1: Setting Up the File Watcher
First, we need to detect when a file has actually changed. We don’t want to trigger an API call for every single keystroke or draft autosave, so we will implement a simple debouncing mechanism. This ensures that we only call Claude after a file has stopped changing for a few seconds.
Create a file named watcher.py and write the core watchdog logic:
`python
import os
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from dotenv import load_dotenv
load_dotenv()
class CodebaseHandler(FileSystemEventHandler): def __init__(self, callback): self.callback = callback self.last_modified = {} self.debounce_interval = 3.0 # seconds
def on_modified(self, event): if event.is_directory: return # We only care about Python, JS, TS, or Rust files in this example allowed_extensions = ('.py', '.js', '.ts', '.rs') if not event.src_path.endswith(allowed_extensions): return
Ignore things in virtual environments, build folders, or git directories ignored_paths = ['venv', '.git', '__pycache__', 'node_modules', 'dist', 'build'] if any(ignored in event.src_path for ignored in ignored_paths): return
now = time.time()
filepath = event.src_path
# Check if the file was modified very recently to avoid double-triggers
if filepath in self.last_modified:
if now - self.last_modified[filepath] < self.debounce_interval:
return
self.last_modified[filepath] = now
print(f"File change detected: {filepath}. Queueing documentation run...")
self.callback(filepath)
`
Step 2: Crafting the System Prompt
Now we need to instruct Claude how to behave. We don't want conversational fluff; we want highly accurate, structured documentation that mirrors the codebase structure.
To construct solid guidelines, we can lean on some of the structural design rules found in our /prompts. We will instruct Claude to return only valid Markdown with clear headings detailing: 1. A high-level description of what the module does. 2. Key functions/classes and their arguments. 3. Dependencies and side effects.
Let's write a function in a new module, generator.py, to handle this transaction:
`python
from anthropic import Anthropic
client = Anthropic()
SYSTEM_PROMPT = """ You are a senior technical writer. Your task is to generate clean, professional technical documentation for a codebase file. Analyze the code provided and write a corresponding markdown documentation file.
Your output must be strictly markdown, following this exact structure: # [Module Name] - Overview: A 2-sentence summary of the purpose of this file. - Dependencies: Any imported libraries or external systems. - Interface: A breakdown of the classes and public functions, including their parameters, return types, and exceptions. - Developer Notes: Any architectural caveats, performance considerations, or scaling gotchas.
Do not include any conversational filler. Start directly with the markdown content. """
def generate_docs(file_path): try: with open(file_path, 'r') as f: code_content = f.read() except Exception as e: print(f"Could not read file {file_path}: {e}") return None
print(f"Sending code to Claude for generation...")
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1500,
temperature=0.2, # We want deterministic, low-creativity documentation
system=SYSTEM_PROMPT,
messages=[
{
"role": "user",
"content": f"Please document the following code file: {file_path}\n\nCode:\n`\n{code_content}\n`"
}
]
)
return response.content[0].text
`
Step 3: Mirroring the Directory and Saving the Docs
Instead of polluting your source folders with random markdown files, it is cleaner to mirror your project structure inside a dedicated docs/ directory. For example, if you edit src/utils/parser.py, the documentation should automatically write to docs/src/utils/parser.md.
Let’s implement this directory mapping logic back in our main execution pipeline inside main.py:
`python
import os
import sys
import time
from watcher import CodebaseHandler
from generator import generate_docs
from watchdog.observers import Observer
def process_file_change(file_path): # Prevent writing documentation for the documentation script itself! if os.path.basename(file_path) in ['main.py', 'watcher.py', 'generator.py']: return
docs_root = os.path.abspath('docs') project_root = os.path.abspath('.') # Get the relative path of the file from the project root relative_path = os.path.relpath(file_path, project_root) # Generate documentation content from Claude doc_content = generate_docs(file_path) if not doc_content: return # Create the mirror path in the docs folder doc_file_name = os.path.splitext(relative_path)[0] + '.md' target_path = os.path.join(docs_root, doc_file_name) # Create parent directories if they don't exist os.makedirs(os.path.dirname(target_path), exist_ok=True) with open(target_path, 'w') as f: f.write(doc_content) print(f"Successfully updated documentation at: {target_path}\n")
if __name__ == "__main__":
path_to_watch = "."
event_handler = CodebaseHandler(process_file_change)
observer = Observer()
observer.schedule(event_handler, path=path_to_watch, recursive=True)
print(f"Monitoring changes in '{path_to_watch}' recursive modes... Press Ctrl+C to stop.")
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
`
Running and Testing the Pipeline
Create a test script in your project root, say calculator.py:
`python
# calculator.py
def add(a: float, b: float) -> float:
"""Adds two numbers."""
return a + b
def divide(a: float, b: float) -> float:
"""Divides two numbers, raising an error if dividing by zero."""
if b == 0:
raise ValueError("Cannot divide by zero.")
return a / b
`
Run your daemon in one terminal window:
`bash
python main.py
`
Now, open your calculator.py file, add a new function (like subtract), and save it. Within seconds, your file-watcher will detect the modify event, hand the updated code over to Claude, and write a beautiful, structured document into docs/calculator.md.
Troubleshooting and Production Caveats
While this local script works beautifully for personal projects, there are a couple of practical limits to keep in mind when scale increases:
- Rate Limits: If you run massive refactoring commands (like a search-and-replace across 50 files), you will instantly hit Claude's rate limits. You can read up on rate limit management on the Anthropic Support Hub. Consider wrapping the
generate_docsfunction in a queue with a slight delay if you plan to batch-edit files. - Sensitive Data: If your codebase contains hardcoded credentials (which they shouldn't!) or private algorithms, be conscious of sending that data to external APIs. Always use a proper
.gitignorefile and filter out files containing key secrets before sending them off to Claude.
Now you have no excuse for stale documentation. Happy coding!
Keep going
Build something with the prompt generator, decode the jargon in the glossary, or compare the tools on our platform deep-dives.