Skip to content
Merged
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
102 changes: 102 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What This Is

Continuous Claude is a persistent, learning, multi-agent development environment built on Claude Code. It transforms Claude Code into a continuously learning system that maintains context across sessions via handoffs, orchestrates specialized agents, and reduces token usage through TLDR code analysis.

**Mantra: Compound, don't compact.** Extract learnings automatically, then start fresh with full context.

## Project Layout

- **`opc/`** - Python backend (pyproject.toml lives here, all `uv` commands run from here)
- `scripts/setup/wizard.py` - Installation wizard (12 steps)
- `scripts/core/` - Core utilities (recall_learnings.py, store_learning.py)
- `scripts/tldr/` - TLDR code analysis CLI
- `docker/` - Docker Compose for PostgreSQL (pgvector)
- **`.claude/`** - Claude Code integration layer
- `hooks/src/` - TypeScript hook sources (compiled to `dist/` via esbuild)
- `hooks/*.py` and `hooks/*.sh` - Python/shell hooks
- `skills/` - 109 skill definitions (SKILL.md files)
- `agents/` - 32 agent definitions (.md and .json)
- `rules/` - Project rules loaded into context
- `settings.json` - Hook registrations and configuration
- **`proofs/`** - Lean 4 theorem proving files
- **`docker/`** - Docker Compose + init-schema.sql for PostgreSQL

## Build & Development Commands

### Python (from `opc/` directory)
```bash
cd opc
uv sync # Install dependencies
uv sync --extra dev # Install with dev tools
uv run pytest tests/ -v # Run all tests
uv run pytest tests/unit/ -x -v # Run unit tests, stop on first failure
uv run ruff check . # Lint
uv run ruff format . # Format
uv run mypy src/ # Type check
```

### TypeScript Hooks (from `.claude/hooks/`)
```bash
cd .claude/hooks
npm install # Install dependencies
npm run build # Build hooks (esbuild → dist/*.mjs)
npm run check # Type check (tsc --noEmit)
npm test # Run tests (vitest)
npm run dev # Build + type check
```

### Setup Wizard
```bash
cd opc
uv run python -m scripts.setup.wizard # Install
uv run python -m scripts.setup.wizard --uninstall # Uninstall
```

### Docker (PostgreSQL with pgvector)
```bash
docker compose -f docker/docker-compose.yml up -d
# Default: postgresql://claude:claude_dev@localhost:5432/continuous_claude
```

## Architecture

### Three-Layer System

1. **Skills** (`.claude/skills/`) - Modular capabilities triggered by natural language or `/slash-commands`. Meta-skills like `/fix`, `/build`, `/tdd` orchestrate multi-step workflows that chain agents together.

2. **Agents** (`.claude/agents/`) - Specialized sub-sessions spawned via the Task tool. Key agents: scout (codebase exploration), oracle (external research), kraken (implementation), arbiter (testing), phoenix (refactoring analysis), sleuth (debugging).

3. **Hooks** (`.claude/hooks/`) - Intercept Claude Code lifecycle events (SessionStart, PreToolUse, PostToolUse, UserPromptSubmit, PreCompact, Stop, SessionEnd). Registered in `.claude/settings.json`. TypeScript hooks are bundled with esbuild (zero runtime deps except better-sqlite3).

### Data Layer

- **PostgreSQL + pgvector**: 4 tables - `sessions` (cross-terminal awareness), `file_claims` (file locking), `archival_memory` (learnings with 1024-dim BGE embeddings), `handoffs` (session state)
- **File system**: `thoughts/ledgers/` (continuity ledgers), `thoughts/shared/handoffs/*.yaml` (session handoffs), `thoughts/shared/plans/*.md` (implementation plans)
- **TLDR cache**: `.tldr/` directory for code analysis artifacts

### Continuity Loop

SessionStart loads continuity ledger + recalls memories + warms TLDR cache. During work, hooks track file changes and index handoffs. PreCompact auto-generates YAML handoffs. SessionEnd triggers a daemon that extracts learnings into `archival_memory`. On `/clear`, fresh context starts with preserved state.

### Hook Pipeline

Hooks are the nervous system. Key hooks by lifecycle:
- **PreToolUse**: path-rules (enforce file boundaries), file-claims (cross-terminal locking), tldr-read-enforcer (suggest TLDR over raw reads), edit-context-inject (add surrounding code context)
- **PostToolUse**: compiler-in-the-loop (run pyright/ruff after edits), import-validator, typescript-preflight
- **UserPromptSubmit**: skill-activation-prompt (suggests relevant skills/agents), memory-awareness (surfaces past learnings), impact-refactor (warn about high-impact changes)
- **PreCompact**: auto-handoff generation
- **Stop**: auto-handoff-stop, compiler-in-the-loop-stop

## Key Conventions

- Python requires **Python 3.12+** and uses `uv` as package manager
- TypeScript hooks use **ESM** (`"type": "module"`) and build to `.mjs` files
- Hooks read JSON from stdin and output JSON to stdout
- Agent definitions use frontmatter (name, description, model, tools) followed by a system prompt
- Skills are defined in `SKILL.md` files and registered in `skill-rules.json` for trigger matching
- Environment variables go in `.env` (see `.env.example`); the canonical DB var is `CONTINUOUS_CLAUDE_DB_URL`
- The `thoughts/` directory is gitignored - it holds per-session state (ledgers, handoffs, plans)
16 changes: 10 additions & 6 deletions opc/scripts/setup/claude_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -842,10 +842,11 @@ def find_latest_backup(claude_dir: Path) -> Path | None:

# Files to preserve during uninstall (user data accumulated since install)
PRESERVE_FILES = [
"history.jsonl", # Command history
"mcp_config.json", # MCP server configs
".env", # API keys and settings
"projects.json", # Project configs
"history.jsonl", # Command history
"mcp_config.json", # MCP server configs
".env", # API keys and settings
"projects.json", # Project configs
"settings.local.json", # User's custom permissions and overrides
]

PRESERVE_DIRS = [
Expand Down Expand Up @@ -948,8 +949,8 @@ def uninstall_opc_integration(
else:
shutil.copy2(archived_src, dest)
result["preserved"].append(name)
except Exception:
pass # Best effort
except Exception as e:
result.setdefault("preserve_warnings", []).append(f"{name}: {e}")

# Build summary message
msg_parts = ["Uninstalled successfully."]
Expand All @@ -960,6 +961,9 @@ def uninstall_opc_integration(
msg_parts.append(" No backup found (created empty .claude)")
if result["preserved"]:
msg_parts.append(f" Preserved user data: {', '.join(result['preserved'])}")
if result.get("preserve_warnings"):
for warning in result["preserve_warnings"]:
msg_parts.append(f" [WARN] Could not preserve {warning}")

result["message"] = "\n".join(msg_parts)
result["success"] = True
Expand Down
39 changes: 39 additions & 0 deletions opc/scripts/setup/wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,45 @@ async def run_uninstall_wizard() -> None:
console.print(f"\n[green]SUCCESS[/green]\n{result['message']}")
else:
console.print(f"\n[red]FAILED[/red]\n{result['message']}")
return

# Additional cleanup: shell config
console.print("\n[bold]Additional cleanup:[/bold]")

# Remove CLAUDE_OPC_DIR from shell config
for shell_config in [Path.home() / ".zshrc", Path.home() / ".bashrc", Path.home() / ".config" / "fish" / "config.fish"]:
if shell_config.exists():
content = shell_config.read_text()
if "CLAUDE_OPC_DIR" in content:
lines = content.splitlines()
cleaned = [
line for line in lines
if "CLAUDE_OPC_DIR" not in line
and "Continuous-Claude OPC directory" not in line
]
shell_config.write_text("\n".join(cleaned) + "\n")
console.print(f" [green]OK[/green] Removed CLAUDE_OPC_DIR from {shell_config.name}")

# Offer to remove TLDR CLI
if shutil.which("tldr"):
if Confirm.ask("\n Remove TLDR CLI tool?", default=False):
import subprocess

try:
remove_result = subprocess.run(
["uv", "tool", "uninstall", "llm-tldr"],
capture_output=True,
text=True,
timeout=30,
)
if remove_result.returncode == 0:
console.print(" [green]OK[/green] TLDR removed")
else:
console.print(" [yellow]WARN[/yellow] Could not remove TLDR")
console.print(" Remove manually: uv tool uninstall llm-tldr")
except (subprocess.TimeoutExpired, OSError) as e:
console.print(f" [yellow]WARN[/yellow] Could not remove TLDR: {e}")
console.print(" Remove manually: uv tool uninstall llm-tldr")


async def main():
Expand Down