Nobody likes writing documentation. But everyone agrees it is necessary. What if you could point a tool at your codebase and get comprehensive documentation automatically?
In this tutorial, youβll build a documentation generator that reads your code and produces README files, API docs, and inline comments. No API keys, no cloud calls, everything runs on your machine.
How It Works
- You point the tool at your codebase
- AI reads functions, classes, and modules
- It generates documentation explaining what each part does
- You get markdown files ready to publish
Prerequisites
- Ollama installed
- Python 3.10+
Step 1: Pull the model
ollama pull qwen2.5-coder:7b
Step 2: Create the docs generator
#!/usr/bin/env python3
"""AI documentation generator using Ollama."""
import subprocess
import sys
import json
import urllib.request
import os
import ast
from pathlib import Path
OLLAMA_URL = "http://localhost:11434/api/generate"
MODEL = "qwen2.5-coder:7b"
PROMPT_TEMPLATE = """Generate comprehensive documentation for this code.
File: {filename}
Code:
```{language}
{code}
Generate:
- Module-level documentation (what this file does)
- Function/method documentation with parameters and return values
- Usage examples
- Common patterns and gotchas
Output markdown format. Be thorough but concise."""
def extract_python_info(filepath): """Extract Python code structure.""" with open(filepath, βrβ) as f: content = f.read()
try:
tree = ast.parse(content)
except SyntaxError:
return content
info = {
"functions": [],
"classes": [],
"imports": []
}
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
info["functions"].append({
"name": node.name,
"args": [arg.arg for arg in node.args.args],
"docstring": ast.get_docstring(node) or ""
})
elif isinstance(node, ast.ClassDef):
info["classes"].append({
"name": node.name,
"docstring": ast.get_docstring(node) or ""
})
return content
def generate_docs(filename, code, language=βpythonβ): """Generate documentation for a file.""" payload = json.dumps({ βmodelβ: MODEL, βpromptβ: PROMPT_TEMPLATE.format( filename=filename, language=language, code=code[:4000] # Truncate large files ), βstreamβ: False, βoptionsβ: {βtemperatureβ: 0.3, βnum_predictβ: 2000} }).encode()
req = urllib.request.Request(
OLLAMA_URL,
data=payload,
headers={"Content-Type": "application/json"}
)
with urllib.request.urlopen(req, timeout=120) as resp:
response = json.loads(resp.read())["response"].strip()
# Remove code block if present
if response.startswith("```markdown"):
response = response[11:]
if response.startswith("```"):
response = response[3:]
if response.endswith("```"):
response = response[:-3]
return response.strip()
def generate_readme(project_dir, files_info): """Generate a README for the project.""" file_list = β\nβ.join([fβ- {f}β for f in files_info.keys()])
prompt = f"""Generate a README.md for this project.
Files in the project: {file_list}
Generate:
- Project title and description
- Installation instructions
- Quick start guide
- API reference summary
- Configuration options
- Contributing guidelines
Output markdown format."""
payload = json.dumps({
"model": MODEL,
"prompt": prompt,
"stream": False,
"options": {"temperature": 0.3, "num_predict": 2000}
}).encode()
req = urllib.request.Request(
OLLAMA_URL,
data=payload,
headers={"Content-Type": "application/json"}
)
with urllib.request.urlopen(req, timeout=120) as resp:
return json.loads(resp.read())["response"].strip()
def scan_directory(directory): """Scan directory for code files.""" code_files = {} for ext in [β.pyβ, β.jsβ, β.tsβ, β.goβ, β.javaβ, β.rsβ]: for filepath in Path(directory).rglob(fβ*{ext}β): if βnode_modulesβ not in str(filepath) and βpycacheβ not in str(filepath): code_files[str(filepath)] = ext return code_files
if name == βmainβ: directory = input(βDirectory to document [./src]: β).strip() or β./srcβ
print(f"Scanning {directory} for code files...")
files = scan_directory(directory)
if not files:
print("No code files found.")
sys.exit(0)
print(f"Found {len(files)} code files")
docs_dir = f"{directory}/docs"
os.makedirs(docs_dir, exist_ok=True)
for filepath, ext in files.items():
print(f"Documenting {filepath}...")
code = open(filepath).read()
language = ext[1:] # Remove dot
docs = generate_docs(filepath, code, language)
# Save docs
doc_filename = Path(filepath).stem + ".md"
doc_path = os.path.join(docs_dir, doc_filename)
with open(doc_path, "w") as f:
f.write(docs)
print(f" Saved to {doc_path}")
# Generate README
print("Generating README...")
readme = generate_readme(directory, files)
readme_path = os.path.join(directory, "README.md")
with open(readme_path, "w") as f:
f.write(readme)
print(f"README saved to {readme_path}")
print(f"\nDocumentation generated in {docs_dir}")
## Step 3: Run it
```bash
python docs_writer.py
Under the Hood
The generator reads your code files and sends them to the AI with a documentation prompt. The AI generates:
- Module documentation: What the file does
- Function docs: Parameters, return values, usage
- Examples: How to use the code
- Gotchas: Common mistakes and edge cases
The AI understands programming patterns and generates appropriate documentation for each language.
What Gets Documented
| Code Element | What the AI Generates |
|---|---|
| Functions | Description, parameters, return value, examples |
| Classes | Purpose, methods, attributes, usage patterns |
| Modules | Overview, exports, dependencies |
| APIs | Endpoints, parameters, responses |
| Config files | Options, defaults, examples |
Limitations
- Generated docs need review for accuracy
- Complex algorithms may need manual explanation
- External dependencies may not be documented correctly
- Very large files may need chunking
Real-World Use Cases
Open source projects. Generate comprehensive documentation for your open source project. Good docs increase adoption and reduce support requests.
Onboarding new developers. Auto-generate docs for your codebase so new team members can understand the code faster.
API documentation. Generate documentation for your REST or GraphQL APIs from the code itself.
Legacy code understanding. Generate documentation for old codebases to understand what the code does before refactoring.
Client deliverables. Include auto-generated documentation with client projects to reduce support burden.
Tips for Better Docs
- Document incrementally. Generate docs for new code as you write it.
- Review and refine. Use the generated docs as a starting point, then add context.
- Include examples. Ask for usage examples in the prompt.
- Update regularly. Re-run the tool when code changes to keep docs current.
Variations
- Inline comments: Add comments directly to code files
- API docs: Generate OpenAPI specs from code
- Tutorial generation: Create step-by-step tutorials
- Changelog generation: Document changes between versions
My Take
This tool eliminates the blank-page problem of documentation. Instead of staring at an empty README, you get a complete draft in minutes. The AI captures most of what needs documenting, and you refine the details.
Rating: 8/10 β Saves hours on documentation. The generated docs are a solid starting point.
Related Articles
- Ollama: How to Install and Run Local AI Models
- Best AI Models for Coding Locally
- Aider Setup Guide
- Continue.dev: The Open-Source AI Coding Assistant
- Best AI Coding Tools in 2026
FAQ
How accurate is the generated documentation?
Very accurate for standard code (functions, classes, APIs). The AI understands programming patterns and generates appropriate documentation. For complex algorithms, add manual explanations.
Can I customize the documentation style?
Yes. Modify the prompt to specify your preferred style: Google style docstrings, NumPy style, or your custom format.
Does this work with other languages?
Yes. The tool supports Python, JavaScript, TypeScript, Go, Java, and Rust. The AI adjusts documentation style for each language.
Can I generate docs for existing projects?
Yes. Point the tool at any codebase and it will generate documentation for all code files.
Related: Documentation Best Practices Β· API Documentation Guide Β· Ollama Complete Guide