Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,25 @@ aidocs mcp docs/ # Start MCP server for docs directory

# PDF export
aidocs export-pdf docs/page.md

# Watch mode (auto-sync on file changes)
aidocs watch # Watch docs/ and auto-chunk on changes
aidocs watch --with-vectors # Also generate embeddings
```

## Architecture

```
src/aidocs_cli/
├── __init__.py # Version and entry point
├── cli.py # Typer CLI commands (init, check, serve, rag-*, export-pdf)
├── cli.py # Typer CLI commands (init, check, serve, rag-*, export-pdf, watch)
├── installer.py # Copies templates to target project (.claude/commands/, .claude/workflows/)
├── chunker.py # Splits markdown at ## headings for RAG
├── embeddings.py # OpenAI embeddings + SQL generation for pgvector
├── server.py # MkDocs config generation and nav discovery
├── pdf_exporter.py # Markdown→HTML→PDF with Chrome/Playwright
├── mcp_server.py # MCP server exposing docs via tools (list, search, read)
├── watcher.py # File system watcher for auto-sync (watchdog + Rich Live)
└── templates/
├── commands/docs/ # Slash command definitions (*.md)
└── workflows/ # Workflow implementations per command
Expand Down Expand Up @@ -78,7 +83,7 @@ Version is defined in two places (keep in sync):

## Dependencies

Core: typer, rich, httpx, mkdocs, mkdocs-material, pyyaml, mcp
Core: typer, rich, httpx, mkdocs, mkdocs-material, pyyaml, mcp, watchdog, python-dotenv

Python 3.11+ required. Build system uses hatchling.

Expand Down
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,65 @@ Once configured, Claude Code can use these tools automatically. You can prompt:
| Empty search results | Ensure docs directory has `.md` files |
| Slow searches | Run `aidocs rag` to pre-chunk files |

### `aidocs watch`

Watch documentation directory for changes and automatically re-chunk files and regenerate embeddings.

```bash
aidocs watch # Watch docs/ with auto-embeddings
aidocs watch --with-vectors # Generate also embeddings
aidocs watch --debounce 5 # Wait 5 seconds before processing
aidocs watch docs/users # Watch specific subdirectory
```

**Options:**
| Option | Description |
|--------|-------------|
| `--with-vectors` | Include embedding generation |
| `--debounce, -d` | Seconds to wait after last change (default: 10) |
| `--table, -t` | Target table name for embeddings (default: `doc_embeddings`) |

**What it does:**
1. Monitors the docs directory for `.md` file changes
2. Debounces rapid changes (waits 10 seconds after last edit by default)
3. Re-chunks modified files automatically
4. Generates embeddings if `OPENAI_API_KEY` is set (use `--with-vectors` to enable)
5. Updates manifest and sync state

**Real-time display:**
```
╭─────────────────────────────────────────╮
│ Watching docs/ │
│ │
│ Last update: 14:32:05 │
│ Files: 12 | Chunks: 45 | Embeddings: 45 │
│ │
│ Embeddings: enabled │
│ │
│ Recent: │
│ ✓ users/index.md (3 chunks) │
│ ✓ api/auth.md (5 chunks) │
│ │
│ Press Ctrl+C to stop │
╰─────────────────────────────────────────╯
```

**Use cases:**
- Keep chunks updated while editing documentation
- Auto-sync embeddings during documentation sprints
- Run alongside `aidocs serve` for a complete dev workflow

**Example workflow:**
```bash
# Terminal 1: Watch for changes
aidocs watch

# Terminal 2: Serve documentation
aidocs serve

# Edit docs in your editor - changes auto-sync!
```

## Slash Commands

After running `aidocs init`, these commands are available in Claude Code:
Expand Down
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "aidocs"
version = "0.16.0"
version = "0.17.0"
description = "AI-powered documentation generator for web applications. Install docs commands into your Claude Code project."
readme = "README.md"
license = { text = "MIT" }
Expand All @@ -26,6 +26,8 @@ dependencies = [
"mkdocs-material>=9.5.0",
"pyyaml>=6.0",
"mcp>=1.0.0",
"watchdog>=4.0.0",
"python-dotenv>=1.0.0",
]

[project.scripts]
Expand Down
2 changes: 1 addition & 1 deletion src/aidocs_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""AI-powered documentation generator CLI for Claude Code projects."""

__version__ = "0.16.0"
__version__ = "0.17.0"

from .cli import app

Expand Down
63 changes: 63 additions & 0 deletions src/aidocs_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -843,5 +843,68 @@ def mcp_command(
asyncio.run(run_server(target_dir))


@app.command("watch")
def watch(
docs_dir: Optional[str] = typer.Argument(
"docs",
help="Directory containing documentation to watch.",
),
with_vectors: bool = typer.Option(
False,
"--with-vectors",
help="Enable embedding generation (requires OPENAI_API_KEY).",
),
debounce: float = typer.Option(
10.0,
"--debounce",
"-d",
help="Seconds to wait after last change before processing.",
),
table: str = typer.Option(
"doc_embeddings",
"--table",
"-t",
help="Target table name for embeddings.",
),
) -> None:
"""Watch documentation directory and auto-sync on changes.

Monitors the docs directory for markdown file changes and automatically:
- Re-chunks modified files
- Generates embeddings (if --with-vectors and OPENAI_API_KEY is set)
- Updates manifest and sync state

Uses debouncing to batch rapid changes (default: 10 seconds).

Examples:
aidocs watch # Watch docs/, chunk only
aidocs watch --with-vectors # Also generate embeddings
aidocs watch --debounce 5 # Wait 5 seconds before processing
aidocs watch docs/users # Watch specific subdirectory
"""
from .watcher import watch_docs

target_dir = Path(docs_dir)

if not target_dir.exists():
console.print(f"[red]Error: Directory not found: {docs_dir}[/red]")
raise typer.Exit(1)

if not target_dir.is_dir():
console.print(f"[red]Error: Not a directory: {docs_dir}[/red]")
raise typer.Exit(1)

try:
watch_docs(
target_dir,
with_vectors=with_vectors,
debounce_seconds=debounce,
table_name=table,
)
except Exception as e:
console.print(f"[red]Error: {e}[/red]")
raise typer.Exit(1)


if __name__ == "__main__":
app()
Loading