Install
openclaw skills install thothThoth Standard -- Auto-Documentation Engine. Reads your entire project and generates README, API reference, and usage guide. Saved to .md files.
openclaw skills install thothFull project documentation in minutes. README, API reference, usage guide -- all saved to files.
pip3 install rich --break-system-packages --quiet
import os, sys, ast
from datetime import datetime
from rich.console import Console
from rich.panel import Panel
from rich.tree import Tree
from rich.table import Table
from rich import box
console = Console()
LICENSE_KEY = os.environ.get("LICENSE_KEY", "").strip()
if not LICENSE_KEY or not LICENSE_KEY.startswith("THOTH-STD-"):
console.print(Panel(
"[red bold]Thoth Standard requires a license key.[/red bold]\n\n"
"Get your key at: [bold cyan]ko-fi.com/occupythemilkyway[/bold cyan]\n\n"
"Or use the free version: [dim]openclaw skills install thoth-lite[/dim]",
title="License Required",
border_style="red"
))
sys.exit(1)
PROJECT_PATH = os.environ.get("PROJECT_PATH", "").strip()
PROJECT_NAME = os.environ.get("PROJECT_NAME", "").strip()
OUTPUT_DIR = os.environ.get("OUTPUT_DIR", "./docs").strip()
if not PROJECT_PATH or not os.path.exists(PROJECT_PATH):
console.print(Panel(f"[red]PROJECT_PATH not found: {PROJECT_PATH}[/red]", title="Error", border_style="red"))
sys.exit(1)
if not PROJECT_NAME:
PROJECT_NAME = os.path.basename(os.path.abspath(PROJECT_PATH))
os.makedirs(OUTPUT_DIR, exist_ok=True)
console.print()
console.print(Panel.fit(
f"[bold cyan]📜 Thoth Standard -- Auto-Documentation[/bold cyan]\n"
f"Project: [yellow]{PROJECT_NAME}[/yellow]\n"
f"Path: [dim]{PROJECT_PATH}[/dim]\n"
f"Output: [green]{OUTPUT_DIR}/[/green]",
border_style="cyan"
))
SKIP_DIRS = {".git", "__pycache__", "node_modules", ".venv", "venv", "dist", "build", ".next", ".pytest_cache"}
CODE_EXTS = {".py", ".js", ".ts", ".jsx", ".tsx", ".go", ".rs", ".java", ".rb", ".cs", ".cpp", ".c", ".sh"}
META_FILES = {"requirements.txt", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "setup.py", "setup.cfg"}
all_files, meta_files, functions = [], {}, []
for root, dirs, fnames in os.walk(PROJECT_PATH):
dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
for fname in fnames:
full = os.path.join(root, fname)
rel = os.path.relpath(full, PROJECT_PATH)
ext = os.path.splitext(fname)[1].lower()
if fname in META_FILES:
try:
with open(full, encoding="utf-8", errors="replace") as fh:
meta_files[fname] = fh.read(2000)
except Exception:
pass
if ext in CODE_EXTS:
all_files.append((rel, full, ext))
# Extract Python functions/classes for API reference
for rel, full, ext in all_files:
if ext == ".py":
try:
with open(full, encoding="utf-8", errors="replace") as fh:
source = fh.read()
tree = ast.parse(source)
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
doc = ast.get_docstring(node) or ""
args = []
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
args = [a.arg for a in node.args.args]
functions.append({
"file": rel, "name": node.name,
"type": "class" if isinstance(node, ast.ClassDef) else "function",
"args": args, "doc": doc[:200]
})
except Exception:
pass
tbl = Table(title=f"Project Scan: {PROJECT_NAME}", box=box.ROUNDED, border_style="cyan")
tbl.add_column("Metric", style="dim")
tbl.add_column("Value", style="yellow")
tbl.add_row("Code files", str(len(all_files)))
tbl.add_row("Python symbols", str(len(functions)))
tbl.add_row("Meta files", ", ".join(meta_files.keys()) or "none")
tbl.add_row("Output dir", OUTPUT_DIR)
console.print(tbl)
# Print file tree and contents for Claude
console.print("\n[bold]Project structure:[/bold]")
for rel, full, ext in sorted(all_files)[:30]:
print(f" {rel}")
console.print("\n[bold]File contents (for documentation):[/bold]")
for rel, full, ext in sorted(all_files)[:25]:
try:
with open(full, encoding="utf-8", errors="replace") as fh:
content = fh.read(4000)
print(f"\n=== {rel} ===\n{content}\n=== END {rel} ===")
except Exception:
pass
if functions:
console.print("\n[bold]Extracted symbols:[/bold]")
for fn in functions[:50]:
args_str = ", ".join(fn["args"]) if fn["type"] == "function" else ""
print(f" [{fn['type']}] {fn['file']}::{fn['name']}({args_str}) -- {fn['doc'][:80]}")
for name, content in meta_files.items():
print(f"\n=== META: {name} ===\n{content}\n=== END META ===")
Based on the project scan above, generate three complete documents:
# [PROJECT_NAME]
> Tagline
## Overview
What it does, why it exists, who it's for. (3-4 paragraphs, thorough)
## Features
Bullet list of all features found in the code.
## Installation
Exact install steps based on the actual meta files found.
## Quick Start
Working code example.
## Usage
Detailed usage with multiple examples.
## Configuration
All config options, env vars, or settings found.
## Project Structure
File/folder explanations.
## License
For every function, class, and method found in the scan:
# API Reference: [PROJECT_NAME]
## [module_name]
### `function_name(args)`
Description of what it does, parameters, return value, example.
Practical, real-world usage guide with worked examples from the actual code.
import os
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich import box
console = Console()
# (Claude saves the 3 files above to OUTPUT_DIR using its file tool)
readme_path = os.path.join(OUTPUT_DIR, "README.md")
api_path = os.path.join(OUTPUT_DIR, "API_REFERENCE.md")
usage_path = os.path.join(OUTPUT_DIR, "USAGE_GUIDE.md")
tbl = Table(title="Documentation Generated", box=box.SIMPLE, border_style="green")
tbl.add_column("File", style="cyan")
tbl.add_column("Description", style="dim")
tbl.add_row(readme_path, "Project overview and install")
tbl.add_row(api_path, "Full API reference")
tbl.add_row(usage_path, "Practical usage guide")
console.print()
console.print(tbl)
console.print(Panel(
"[bold green]Documentation complete![/bold green]\n\n"
"Upgrade to [magenta]Thoth Pro ($9)[/magenta] for auto-injected docstrings, git CHANGELOG, and architecture docs.\n"
"-> [cyan]ko-fi.com/occupythemilkyway[/cyan]",
border_style="green"
))
Save all three documents to OUTPUT_DIR using your file writing tool, then display the confirmation panel.