From 9cc2b949cc03d1442fab620598761d375d3828e1 Mon Sep 17 00:00:00 2001 From: aseembits93 Date: Tue, 17 Mar 2026 15:54:05 -0700 Subject: [PATCH 1/4] docs: add comprehensive documentation for codeflash-cc-plugin Six documents covering getting started, usage, configuration, architecture, hook lifecycle, and troubleshooting for the Claude Code plugin. Co-Authored-By: Claude Opus 4.6 --- docs/architecture.md | 133 ++++++++++++++++++++++++++++++++++++ docs/configuration.md | 117 ++++++++++++++++++++++++++++++++ docs/getting-started.md | 79 ++++++++++++++++++++++ docs/hook-lifecycle.md | 145 ++++++++++++++++++++++++++++++++++++++++ docs/troubleshooting.md | 123 ++++++++++++++++++++++++++++++++++ docs/usage-guide.md | 92 +++++++++++++++++++++++++ 6 files changed, 689 insertions(+) create mode 100644 docs/architecture.md create mode 100644 docs/configuration.md create mode 100644 docs/getting-started.md create mode 100644 docs/hook-lifecycle.md create mode 100644 docs/troubleshooting.md create mode 100644 docs/usage-guide.md diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 000000000..d4761a523 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,133 @@ +# Architecture + +This document describes the plugin's components, data flow, and internal protocols. + +## Data flow + +``` +User types /optimize User commits code + | | + v v + SKILL.md hooks.json + (fork context) (Stop event, * matcher) + | | + v v + optimizer agent suggest-optimize.sh + (15 turns, inherited model) (bash, 30s timeout) + | | + v v + Verify env & config Detect new commits + | with .py/.js/.ts files + v | + codeflash CLI v + (background, 10min timeout) Block Claude's stop + | with suggestion message + v | + Results reported Claude acts on suggestion + to user (install / configure / run) +``` + +## Component inventory + +| File | Type | Purpose | +|------|------|---------| +| `.claude-plugin/plugin.json` | Manifest | Plugin identity, version, metadata | +| `.claude-plugin/marketplace.json` | Manifest | Marketplace listing, owner info | +| `skills/optimize/SKILL.md` | Skill | `/optimize` slash command definition | +| `commands/setup.md` | Command | `/setup` slash command for auto-permissions | +| `agents/optimizer.md` | Agent | Background optimization agent with full workflow | +| `hooks/hooks.json` | Hook config | Registers the Stop hook | +| `scripts/suggest-optimize.sh` | Hook script | Commit detection, dedup, project discovery | +| `scripts/find-venv.sh` | Helper script | Python venv auto-discovery | + +## Skill format + +Skills use YAML frontmatter in a Markdown file: + +```yaml +--- +name: optimize +description: Optimize Python, JavaScript, or TypeScript code for performance using Codeflash +user-invocable: true +argument-hint: "[--file] [--function] [--subagent]" +context: fork # Forks context so optimization doesn't pollute main conversation +agent: codeflash:optimizer # Delegates to the optimizer agent +allowed-tools: Task +--- +``` + +The `context: fork` setting means the skill runs in a forked context -- the optimizer agent gets its own conversation branch, keeping the main session clean. + +## Agent format + +Agents use YAML frontmatter followed by a system prompt: + +```yaml +--- +name: optimizer +description: | + Optimizes Python and JavaScript/TypeScript code for performance... +model: inherit # Uses the same model as the parent conversation +maxTurns: 15 # Maximum number of agent turns +color: cyan # Status line color +tools: Read, Glob, Grep, Bash, Write, Edit +--- +``` + +The agent body contains the full workflow: project detection, environment verification, configuration setup, running codeflash, and error handling. + +## Hook system + +### `hooks.json` structure + +```json +{ + "hooks": { + "Stop": [ + { + "matcher": "*", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/suggest-optimize.sh", + "timeout": 30 + } + ] + } + ] + } +} +``` + +- **Event**: `Stop` -- fires every time Claude finishes a response +- **Matcher**: `*` -- matches all stops (no filtering by tool or content) +- **Timeout**: 30 seconds for the hook script to complete +- **`${CLAUDE_PLUGIN_ROOT}`**: Resolved by Claude Code to the plugin's install directory + +### Hook stdin/stdout protocol + +**Input** (JSON on stdin): +```json +{ + "stop_hook_active": false, + "transcript_path": "/path/to/transcript.jsonl" +} +``` + +**Output** (JSON on stdout): +```json +{"decision": "block", "reason": "message for Claude to act on"} +``` + +Or no output / exit 0 to allow the stop (no blocking). + +The `decision` field can be: +- `"block"` -- prevents Claude from stopping, injects `reason` as a new prompt for Claude to act on +- Absent / script exits 0 without output -- allows the stop + +## State files + +| File | Purpose | Lifetime | +|------|---------|----------| +| `/tmp/codeflash-hook-debug.log` | Debug output from the hook script (`set -x` stderr) | Persists across sessions until manually cleared | +| `$TRANSCRIPT_DIR/codeflash-seen` | SHA-256 hashes of already-processed commit sets | Per-session (lives alongside the transcript file) | diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 000000000..950771c0b --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,117 @@ +# Configuration + +This document covers all configuration surfaces: plugin manifests, project-level codeflash config, and Claude Code permissions. + +## Plugin manifests + +These files live in `.claude-plugin/` and define the plugin for Claude Code's plugin system. You generally don't need to modify them. + +### `plugin.json` + +```json +{ + "name": "codeflash", + "description": "Run codeflash as a background agent to optimize code for performance", + "version": "0.1.10", + "author": { "name": "Codeflash", "url": "https://codeflash.ai" }, + "repository": "https://github.com/codeflash-ai/codeflash-cc-plugin", + "license": "MIT", + "keywords": ["python", "javascript", "typescript", "optimization", "performance"] +} +``` + +### `marketplace.json` + +Defines the plugin for the Claude Code marketplace. Contains owner info, metadata, and a `plugins` array with the same fields as `plugin.json` plus `source` (relative path) and `category`. + +## Python project configuration + +Codeflash reads its configuration from `[tool.codeflash]` in `pyproject.toml`. + +### Full reference + +```toml +[tool.codeflash] +# All paths are relative to this pyproject.toml's directory. +module-root = "src" # Root of your Python module (where tests import from) +tests-root = "tests" # Directory containing your test files +ignore-paths = [] # Paths to exclude from optimization +formatter-cmds = ["disabled"] # Formatter commands, or ["disabled"] to skip formatting +``` + +### Fields + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `module-root` | Yes | -- | Relative path to the module root. If your tests do `from mypackage import ...`, then `mypackage/` is the module root | +| `tests-root` | Yes | -- | Relative path to the tests directory | +| `ignore-paths` | No | `[]` | List of paths to exclude from optimization | +| `formatter-cmds` | No | `["disabled"]` | List of formatter commands. Each can include flags, e.g. `"black --line-length 88 {file}"`. Use `["disabled"]` to skip formatting | + +### Auto-discovery + +When configuration is missing, the optimizer agent discovers values automatically: + +- **module-root**: Uses Glob and Read to find the Python package directory (the one tests import from) +- **tests-root**: Looks for directories named `tests` or `test`, or folders containing `test_*.py` files. Falls back to `tests` (creates it if needed) + +## JS/TS project configuration + +Codeflash reads its configuration from a `"codeflash"` key at the root level of `package.json`. + +### Full reference + +```json +{ + "codeflash": { + "moduleRoot": "src", + "testsRoot": "tests", + "formatterCmds": ["disabled"], + "ignorePaths": ["dist", "**/node_modules", "**/__tests__"] + } +} +``` + +### Fields + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `moduleRoot` | Yes | -- | Relative path to the JS/TS module root (e.g. `.` or `src`) | +| `testsRoot` | Yes | -- | Relative path to the tests directory | +| `formatterCmds` | No | `["disabled"]` | Formatter commands. Use `npx` prefix for project-local tools, e.g. `"npx prettier --write {file}"` | +| `ignorePaths` | No | `[]` | Glob patterns to exclude from optimization | + +### Auto-discovery + +When configuration is missing, the optimizer agent: + +- **moduleRoot**: Inspects the project structure; typically `.` or `src` +- **testsRoot**: Looks for `tests`, `test`, `__tests__`, or directories with `*.test.js`/`*.spec.ts` files. Falls back to `tests` + +## Claude Code permissions + +To allow codeflash to run without permission prompts, add the following to `.claude/settings.json` in your project root: + +```json +{ + "permissions": { + "allow": [ + "Bash(*codeflash*)" + ] + } +} +``` + +This can be set up automatically by running `/setup`. + +### Scope options + +The permission can be placed at different levels: + +| File | Scope | +|------|-------| +| `.claude/settings.json` | Project-wide, shared with team (committed to git) | +| `.claude/settings.local.json` | Project-wide, personal (gitignored) | +| `~/.claude/settings.json` | User-wide, all projects | + +The stop hook checks `.claude/settings.json` in the repo root to determine if auto-allow is already configured. If the `permissions.allow` array contains any entry matching `codeflash`, the hook skips adding auto-allow instructions to its suggestions. diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 000000000..755583985 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,79 @@ +# Getting Started + +This guide walks you through installing the Codeflash Claude Code plugin and running your first optimization. + +## Prerequisites + +- **Claude Code** v2.1.38 or later +- **Python projects**: [codeflash](https://pypi.org/project/codeflash/) installed in a virtual environment +- **JS/TS projects**: [codeflash](https://www.npmjs.com/package/codeflash) installed as a dev dependency + +## Installation + +### 1. Add the marketplace and install + +```bash +/plugin marketplace add codeflash-ai/codeflash-cc-plugin +/plugin install codeflash +``` + +Or from a local clone: + +```bash +git clone https://github.com/codeflash-ai/codeflash-cc-plugin.git +/plugin marketplace add ./codeflash-cc-plugin +/plugin install codeflash +``` + +### 2. Choose installation scope + +By default, plugins install at the **user** level (available across all projects). You can change this: + +| Scope | Flag | Effect | +|-------|------|--------| +| User (default) | _(none)_ | Available in all your projects | +| Project | `--scope project` | Shared with team via `.claude/settings.json` | +| Local | `--scope local` | This project only, gitignored | + +```bash +/plugin install codeflash --scope project +``` + +### 3. Verify installation + +Run `/plugin` to open the plugin manager. Confirm **codeflash** appears under the **Installed** tab. + +## First optimization + +Run the `/optimize` skill with a target file: + +``` +/optimize src/utils.py +``` + +What happens behind the scenes: + +1. The skill forks a background **optimizer agent** +2. The agent walks upward from CWD to the git root, looking for `pyproject.toml` (Python) or `package.json` (JS/TS) +3. It verifies codeflash is installed and configured +4. If configuration is missing, it auto-discovers your module root and tests directory and writes the config for you +5. It runs `codeflash --subagent` in the background with a 10-minute timeout +6. Results are reported when optimization completes + +You can continue working while codeflash optimizes in the background. + +## Set up auto-permissions + +Run `/setup` to allow codeflash to execute automatically without permission prompts: + +``` +/setup +``` + +This adds `Bash(*codeflash*)` to the `permissions.allow` array in `.claude/settings.json`. After this, the post-commit hook can trigger optimizations without asking each time. + +## Next steps + +- [Usage Guide](usage-guide.md) -- all commands, flags, and workflows +- [Configuration](configuration.md) -- config reference for Python and JS/TS projects +- [Troubleshooting](troubleshooting.md) -- common problems and fixes diff --git a/docs/hook-lifecycle.md b/docs/hook-lifecycle.md new file mode 100644 index 000000000..6973a9364 --- /dev/null +++ b/docs/hook-lifecycle.md @@ -0,0 +1,145 @@ +# Hook Lifecycle + +Deep dive into `scripts/suggest-optimize.sh` -- the Stop hook that detects commits and suggests optimizations. + +## When the hook fires + +The hook fires on **every Claude stop** (every time Claude finishes a response). This is configured in `hooks/hooks.json` with a `*` matcher, meaning it runs unconditionally regardless of what Claude just did. + +## Decision tree + +The hook evaluates a series of conditions and takes the first matching exit path: + +``` +1. stop_hook_active == true? + YES -> exit 0 (allow stop, prevent infinite loop) + +2. Not inside a git repo? + YES -> exit 0 + +3. No transcript_path or file doesn't exist? + YES -> exit 0 + +4. Session start time unavailable? + YES -> exit 0 + +5. No commits with .py/.js/.ts/.jsx/.tsx files since session start? + YES -> exit 0 + +6. Commit hash set already seen (in codeflash-seen)? + YES -> exit 0 + +7. JS/TS project with JS changes? + 7a. Not configured -> block: set up config (+ install if needed) + 7b. Configured, not installed -> block: install codeflash + 7c. Configured + installed -> block: run codeflash + +8. No Python changes? + YES -> exit 0 + +9. Python project, no venv found? + YES -> block: create venv, install, configure, run + +10. Python project with venv: + 10a. Not configured -> block: set up config (+ install if needed) + 10b. Configured, not installed -> block: install codeflash + 10c. Configured + installed -> block: run codeflash +``` + +Every `block` decision also appends auto-allow instructions if `Bash(*codeflash*)` is not yet in `.claude/settings.json`. + +## Infinite loop prevention + +When the hook blocks Claude's stop with a suggestion, Claude acts on it (e.g., runs codeflash). When Claude finishes that response, the hook fires again. To prevent an infinite loop: + +1. Claude sets `stop_hook_active: true` in the hook input when it's responding to a previous hook block +2. The hook checks this flag first and immediately exits if true + +This means the hook only triggers once per "natural" Claude stop, not on stops caused by responding to hook suggestions. + +## Session boundary detection + +The hook needs to know when the current session started to find only commits made during this session. + +1. It reads `transcript_path` from the hook input JSON +2. It gets the transcript file's **birth time** (creation timestamp) using `stat`: + - **macOS**: `stat -f %B ` (birth time) + - **Linux**: `stat -c %W ` (birth time), falls back to `stat -c %Y` (modification time) if birth time is unavailable +3. This timestamp becomes `SESSION_START`, used in `git log --after=@$SESSION_START` + +## Commit detection + +```bash +git log --after="@$SESSION_START" --name-only --diff-filter=ACMR \ + --pretty=format: -- '*.py' '*.js' '*.ts' '*.jsx' '*.tsx' +``` + +- `--after=@$SESSION_START` -- only commits after session start (Unix timestamp) +- `--diff-filter=ACMR` -- Added, Copied, Modified, Renamed files only +- `--pretty=format:` -- suppress commit metadata, show only file names +- File patterns filter to Python and JS/TS extensions + +The results are sorted and deduplicated. The hook also determines which language families have changes (`HAS_PYTHON_CHANGES`, `HAS_JS_CHANGES`) by grepping the file list for extension patterns. + +## Deduplication + +The hook prevents suggesting optimization for the same set of commits twice: + +1. It computes the commit hashes of all matching commits: + ```bash + git log --after="@$SESSION_START" --pretty=format:%H -- '*.py' '*.js' '*.ts' '*.jsx' '*.tsx' + ``` +2. It hashes the full list with SHA-256: + ```bash + ... | shasum -a 256 | cut -d' ' -f1 + ``` +3. It checks this hash against `$TRANSCRIPT_DIR/codeflash-seen` +4. If found, the hook exits (already processed) +5. If not found, appends the hash and continues + +The seen-marker file lives in the transcript directory, so it's scoped to the current session/project. + +## Project detection (`detect_project`) + +The `detect_project` function walks from `$PWD` upward to `$REPO_ROOT`: + +1. At each directory level, check for `pyproject.toml` first, then `package.json` +2. The **first** config file found determines the project type +3. It records: + - `PROJECT_TYPE`: `"python"` or `"js"` + - `PROJECT_DIR`: directory containing the config file + - `PROJECT_CONFIG_PATH`: full path to the config file + - `PROJECT_CONFIGURED`: `"true"` if codeflash config section exists + +For Python, it checks for `[tool.codeflash]` in `pyproject.toml`. For JS/TS, it checks for a `"codeflash"` key in `package.json` using `jq`. + +The walk stops at `$REPO_ROOT` -- it never searches above the git repository root. + +## Auto-allow suggestion + +Every `block` decision checks whether codeflash is already auto-allowed: + +```bash +SETTINGS_JSON="$REPO_ROOT/.claude/settings.json" +jq -e '.permissions.allow // [] | any(test("codeflash"))' "$SETTINGS_JSON" +``` + +If no matching entry exists, the block message appends instructions to add `Bash(*codeflash*)` to `permissions.allow`. This means after the first optimization, future runs won't need permission prompts. + +## Debug logging + +The hook writes all debug output to `/tmp/codeflash-hook-debug.log`: + +```bash +LOGFILE="/tmp/codeflash-hook-debug.log" +exec 2>>"$LOGFILE" +set -x +``` + +All stderr (including bash trace output from `set -x`) is appended to this file. To debug hook issues: + +```bash +tail -f /tmp/codeflash-hook-debug.log +``` + +The log persists across sessions and is not automatically cleaned up. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 000000000..d0ce66c2e --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,123 @@ +# Troubleshooting + +## Plugin not appearing after install + +**Symptom**: `/plugin` doesn't show codeflash in the Installed tab. + +**Fix**: +1. Verify the marketplace was added: `/plugin marketplace add codeflash-ai/codeflash-cc-plugin` +2. Install again: `/plugin install codeflash` +3. Check you're running Claude Code v2.1.38 or later + +## `/optimize` does nothing + +**Symptom**: Running `/optimize` produces no output or immediately returns. + +**Possible causes**: +- No project config found. The agent walks from CWD to the git root looking for `pyproject.toml` or `package.json`. Make sure you're inside a git repository. +- Codeflash CLI not installed. For Python: `pip install codeflash` in your venv. For JS/TS: `npm install --save-dev codeflash`. +- The agent is running in the background. Check if you see "Codeflash is optimizing in the background" -- results appear when the background task completes. + +## Permission prompts every time + +**Symptom**: Claude asks for permission to run codeflash on every invocation. + +**Fix**: Run `/setup` to add `Bash(*codeflash*)` to `.claude/settings.json`. Or add it manually: + +```json +{ + "permissions": { + "allow": [ + "Bash(*codeflash*)" + ] + } +} +``` + +## No venv found (Python) + +**Symptom**: Hook or agent reports "No Python virtual environment was found." + +**Fix**: +1. Create a venv: `python3 -m venv .venv` +2. Activate it: `source .venv/bin/activate` +3. Install codeflash: `pip install codeflash` +4. Restart Claude Code from within the activated venv + +The plugin searches for venvs in this order: +1. `/.venv` +2. `/venv` +3. `/.venv` +4. `/venv` + +## Codeflash not installed (JS/TS) + +**Symptom**: `npx codeflash --version` fails or package not found. + +**Fix**: +```bash +npm install --save-dev codeflash +``` + +Run this in the directory containing your `package.json`. + +## Hook not triggering after commits + +**Symptom**: You commit Python/JS/TS files but don't see optimization suggestions. + +**Check**: +1. Verify the hook is registered: look for `hooks/hooks.json` in the plugin directory +2. Check the debug log: `cat /tmp/codeflash-hook-debug.log` +3. Ensure commits touch `.py`, `.js`, `.ts`, `.jsx`, or `.tsx` files +4. The hook only detects commits made **during the current session** (after the transcript file was created). Commits from before starting Claude Code won't trigger it. + +## Hook triggering repeatedly + +**Symptom**: The hook keeps suggesting optimization for the same commits. + +This shouldn't happen due to deduplication (the hook tracks seen commit hashes in `$TRANSCRIPT_DIR/codeflash-seen`). If it does: + +1. Check the seen-marker file exists in the transcript directory +2. Look at `/tmp/codeflash-hook-debug.log` for the dedup logic trace +3. If commit hashes changed (e.g., amended commits), the hook treats them as new + +## "Attempting to repair broken tests..." + +This is **normal codeflash behavior**, not an error. Codeflash generates tests and sometimes needs to fix them. Let it continue. + +## 10-minute timeout exceeded + +**Symptom**: Codeflash background task times out. + +This can happen on large projects or with `--all`. Options: +- Optimize specific files instead of the entire project: `/optimize src/specific_file.py` +- Target individual functions: `/optimize src/utils.py my_function` +- The `--all` flag scans every function, which naturally takes longer + +## Formatter errors + +**Symptom**: Codeflash fails with formatter-related errors. + +**Check**: +1. Read the `formatter-cmds` (Python) or `formatterCmds` (JS/TS) in your config +2. Verify each formatter is installed: + - Python: `which black` (or whichever formatter) + - JS/TS: `npx prettier --version` (or whichever formatter) +3. Set `formatter-cmds = ["disabled"]` or `"formatterCmds": ["disabled"]` to skip formatting entirely + +## Debugging the hook script manually + +Run the hook script directly to test it: + +```bash +echo '{"stop_hook_active": false, "transcript_path": "/path/to/transcript.jsonl"}' | \ + bash /path/to/codeflash-cc-plugin/scripts/suggest-optimize.sh +``` + +Check the debug log for detailed trace output: + +```bash +tail -100 /tmp/codeflash-hook-debug.log +``` + +The log includes every variable and branch taken (via `set -x`), making it straightforward to trace why the hook did or didn't trigger. diff --git a/docs/usage-guide.md b/docs/usage-guide.md new file mode 100644 index 000000000..ecbe4a2f1 --- /dev/null +++ b/docs/usage-guide.md @@ -0,0 +1,92 @@ +# Usage Guide + +## The `/optimize` skill + +`/optimize` is the primary command. It spawns a background optimizer agent that runs the codeflash CLI on your code. + +### Syntax + +``` +/optimize [file] [function] [flags] +``` + +### Examples + +| Command | Effect | +|---------|--------| +| `/optimize` | Let codeflash detect changed files automatically | +| `/optimize src/utils.py` | Optimize all functions in `src/utils.py` | +| `/optimize src/utils.py my_function` | Optimize only `my_function` in that file | +| `/optimize --all` | Optimize the entire project | +| `/optimize src/utils.py --no-pr` | Optimize without creating a PR | +| `/optimize src/utils.py --effort high` | Set optimization effort level to high | + +Flags can be combined: `/optimize src/utils.py my_function --no-pr --effort high` + +### What happens behind the scenes + +1. The skill (defined in `skills/optimize/SKILL.md`) forks context and spawns the **optimizer agent** +2. The agent locates your project config (`pyproject.toml` or `package.json`) +3. It verifies the codeflash CLI is installed and the project is configured +4. It runs `codeflash --subagent` as a **background task** with a 10-minute timeout +5. You're notified when optimization completes with results + +The agent has up to **15 turns** to complete its work (install codeflash, configure the project, run optimization). + +## The `/setup` command + +`/setup` configures auto-permissions so codeflash runs without prompting. + +### What it does + +1. Finds `.claude/settings.json` in your project root +2. Checks if `Bash(*codeflash*)` is already in `permissions.allow` +3. If not, adds it (creating the file and directory if needed) +4. Preserves any existing settings + +Running `/setup` multiple times is safe -- it's idempotent. If permissions are already configured, it reports "No changes needed." + +## Automatic post-commit suggestions + +After every Claude response (the **Stop** hook), the plugin checks whether you committed Python, JS, or TS files during the current session. If so, it suggests running `/optimize`. + +### How commit detection works + +1. The hook determines the session start time from the transcript file's creation timestamp +2. It queries `git log --after=@` for commits touching `*.py`, `*.js`, `*.ts`, `*.jsx`, `*.tsx` files +3. It deduplicates so the same commits don't trigger suggestions twice +4. If new commits are found, it blocks Claude's stop and injects a suggestion + +The suggestion varies depending on the project state: + +| State | Suggestion | +|-------|------------| +| Configured + installed | Run `codeflash --subagent` in the background | +| Configured, not installed | Install codeflash first, then run | +| Not configured | Auto-discover config, write it, then run | +| No venv (Python) | Create venv, install codeflash, configure, then run | + +If `Bash(*codeflash*)` is not yet in `.claude/settings.json`, the suggestion also includes adding it for auto-permissions. + +## Python-specific workflow + +For Python projects, the optimizer agent: + +1. Checks for an active virtual environment (`$VIRTUAL_ENV`) +2. If none, searches for `.venv` or `venv` directories in the project dir and repo root +3. Verifies `codeflash` is installed in the venv (`$VIRTUAL_ENV/bin/codeflash --version`) +4. Reads `[tool.codeflash]` from `pyproject.toml` for configuration +5. Runs: `source $VIRTUAL_ENV/bin/activate && codeflash --subagent [flags]` + +The agent also checks `formatter-cmds` in the config and verifies formatters are installed. + +## JS/TS-specific workflow + +For JavaScript/TypeScript projects, the optimizer agent: + +1. Checks codeflash is available via `npx codeflash --version` +2. Reads the `"codeflash"` key from `package.json` for configuration +3. Always runs from the project root (the directory containing `package.json`) +4. Runs: `npx codeflash --subagent [flags]` + +No virtual environment is needed -- JS/TS projects use `npx`/`npm` directly. From 95d4863ff245e49656eb0d07d6a114df08e6392c Mon Sep 17 00:00:00 2001 From: aseembits93 Date: Tue, 17 Mar 2026 15:59:03 -0700 Subject: [PATCH 2/4] docs: convert to Mintlify .mdx format with navigation Move docs into claude-code-plugin/ subdirectory as .mdx files with Mintlify frontmatter (title, description, icon, sidebarTitle). Add Claude Code Plugin group to docs.json navigation. Co-Authored-By: Claude Opus 4.6 --- .../architecture.mdx} | 21 +++++--- .../configuration.mdx} | 19 ++++--- .../getting-started.mdx} | 30 ++++++++--- .../hook-lifecycle.mdx} | 50 +++++++++++-------- .../troubleshooting.mdx} | 12 ++++- .../usage-guide.mdx} | 13 +++-- docs/docs.json | 11 ++++ 7 files changed, 108 insertions(+), 48 deletions(-) rename docs/{architecture.md => claude-code-plugin/architecture.mdx} (87%) rename docs/{configuration.md => claude-code-plugin/configuration.mdx} (87%) rename docs/{getting-started.md => claude-code-plugin/getting-started.mdx} (72%) rename docs/{hook-lifecycle.md => claude-code-plugin/hook-lifecycle.mdx} (76%) rename docs/{troubleshooting.md => claude-code-plugin/troubleshooting.mdx} (93%) rename docs/{usage-guide.md => claude-code-plugin/usage-guide.mdx} (90%) diff --git a/docs/architecture.md b/docs/claude-code-plugin/architecture.mdx similarity index 87% rename from docs/architecture.md rename to docs/claude-code-plugin/architecture.mdx index d4761a523..ee5a46537 100644 --- a/docs/architecture.md +++ b/docs/claude-code-plugin/architecture.mdx @@ -1,6 +1,9 @@ -# Architecture - -This document describes the plugin's components, data flow, and internal protocols. +--- +title: "Architecture" +description: "Plugin components, data flow, and internal protocols" +icon: "sitemap" +sidebarTitle: "Architecture" +--- ## Data flow @@ -56,7 +59,7 @@ allowed-tools: Task --- ``` -The `context: fork` setting means the skill runs in a forked context -- the optimizer agent gets its own conversation branch, keeping the main session clean. +The `context: fork` setting means the skill runs in a forked context — the optimizer agent gets its own conversation branch, keeping the main session clean. ## Agent format @@ -99,14 +102,15 @@ The agent body contains the full workflow: project detection, environment verifi } ``` -- **Event**: `Stop` -- fires every time Claude finishes a response -- **Matcher**: `*` -- matches all stops (no filtering by tool or content) +- **Event**: `Stop` — fires every time Claude finishes a response +- **Matcher**: `*` — matches all stops (no filtering by tool or content) - **Timeout**: 30 seconds for the hook script to complete - **`${CLAUDE_PLUGIN_ROOT}`**: Resolved by Claude Code to the plugin's install directory ### Hook stdin/stdout protocol **Input** (JSON on stdin): + ```json { "stop_hook_active": false, @@ -115,6 +119,7 @@ The agent body contains the full workflow: project detection, environment verifi ``` **Output** (JSON on stdout): + ```json {"decision": "block", "reason": "message for Claude to act on"} ``` @@ -122,8 +127,8 @@ The agent body contains the full workflow: project detection, environment verifi Or no output / exit 0 to allow the stop (no blocking). The `decision` field can be: -- `"block"` -- prevents Claude from stopping, injects `reason` as a new prompt for Claude to act on -- Absent / script exits 0 without output -- allows the stop +- `"block"` — prevents Claude from stopping, injects `reason` as a new prompt for Claude to act on +- Absent / script exits 0 without output — allows the stop ## State files diff --git a/docs/configuration.md b/docs/claude-code-plugin/configuration.mdx similarity index 87% rename from docs/configuration.md rename to docs/claude-code-plugin/configuration.mdx index 950771c0b..f164a6db8 100644 --- a/docs/configuration.md +++ b/docs/claude-code-plugin/configuration.mdx @@ -1,6 +1,9 @@ -# Configuration - -This document covers all configuration surfaces: plugin manifests, project-level codeflash config, and Claude Code permissions. +--- +title: "Configuration" +description: "Configuration reference for plugin manifests, project config, and Claude Code permissions" +icon: "gear" +sidebarTitle: "Configuration" +--- ## Plugin manifests @@ -43,8 +46,8 @@ formatter-cmds = ["disabled"] # Formatter commands, or ["disabled"] to skip for | Field | Required | Default | Description | |-------|----------|---------|-------------| -| `module-root` | Yes | -- | Relative path to the module root. If your tests do `from mypackage import ...`, then `mypackage/` is the module root | -| `tests-root` | Yes | -- | Relative path to the tests directory | +| `module-root` | Yes | — | Relative path to the module root. If your tests do `from mypackage import ...`, then `mypackage/` is the module root | +| `tests-root` | Yes | — | Relative path to the tests directory | | `ignore-paths` | No | `[]` | List of paths to exclude from optimization | | `formatter-cmds` | No | `["disabled"]` | List of formatter commands. Each can include flags, e.g. `"black --line-length 88 {file}"`. Use `["disabled"]` to skip formatting | @@ -76,8 +79,8 @@ Codeflash reads its configuration from a `"codeflash"` key at the root level of | Field | Required | Default | Description | |-------|----------|---------|-------------| -| `moduleRoot` | Yes | -- | Relative path to the JS/TS module root (e.g. `.` or `src`) | -| `testsRoot` | Yes | -- | Relative path to the tests directory | +| `moduleRoot` | Yes | — | Relative path to the JS/TS module root (e.g. `.` or `src`) | +| `testsRoot` | Yes | — | Relative path to the tests directory | | `formatterCmds` | No | `["disabled"]` | Formatter commands. Use `npx` prefix for project-local tools, e.g. `"npx prettier --write {file}"` | | `ignorePaths` | No | `[]` | Glob patterns to exclude from optimization | @@ -114,4 +117,6 @@ The permission can be placed at different levels: | `.claude/settings.local.json` | Project-wide, personal (gitignored) | | `~/.claude/settings.json` | User-wide, all projects | + The stop hook checks `.claude/settings.json` in the repo root to determine if auto-allow is already configured. If the `permissions.allow` array contains any entry matching `codeflash`, the hook skips adding auto-allow instructions to its suggestions. + diff --git a/docs/getting-started.md b/docs/claude-code-plugin/getting-started.mdx similarity index 72% rename from docs/getting-started.md rename to docs/claude-code-plugin/getting-started.mdx index 755583985..5f1afd7fe 100644 --- a/docs/getting-started.md +++ b/docs/claude-code-plugin/getting-started.mdx @@ -1,4 +1,9 @@ -# Getting Started +--- +title: "Getting Started" +description: "Install the Codeflash Claude Code plugin and run your first optimization" +icon: "rocket" +sidebarTitle: "Getting Started" +--- This guide walks you through installing the Codeflash Claude Code plugin and running your first optimization. @@ -10,7 +15,7 @@ This guide walks you through installing the Codeflash Claude Code plugin and run ## Installation -### 1. Add the marketplace and install +### Add the marketplace and install ```bash /plugin marketplace add codeflash-ai/codeflash-cc-plugin @@ -25,7 +30,7 @@ git clone https://github.com/codeflash-ai/codeflash-cc-plugin.git /plugin install codeflash ``` -### 2. Choose installation scope +### Choose installation scope By default, plugins install at the **user** level (available across all projects). You can change this: @@ -39,7 +44,7 @@ By default, plugins install at the **user** level (available across all projects /plugin install codeflash --scope project ``` -### 3. Verify installation +### Verify installation Run `/plugin` to open the plugin manager. Confirm **codeflash** appears under the **Installed** tab. @@ -74,6 +79,17 @@ This adds `Bash(*codeflash*)` to the `permissions.allow` array in `.claude/setti ## Next steps -- [Usage Guide](usage-guide.md) -- all commands, flags, and workflows -- [Configuration](configuration.md) -- config reference for Python and JS/TS projects -- [Troubleshooting](troubleshooting.md) -- common problems and fixes + + + All commands, flags, and workflows + + + Config reference for Python and JS/TS projects + + + Common problems and fixes + + + How the plugin works internally + + diff --git a/docs/hook-lifecycle.md b/docs/claude-code-plugin/hook-lifecycle.mdx similarity index 76% rename from docs/hook-lifecycle.md rename to docs/claude-code-plugin/hook-lifecycle.mdx index 6973a9364..6a3093c06 100644 --- a/docs/hook-lifecycle.md +++ b/docs/claude-code-plugin/hook-lifecycle.mdx @@ -1,6 +1,11 @@ -# Hook Lifecycle +--- +title: "Hook Lifecycle" +description: "Deep dive into the Stop hook: commit detection, deduplication, and decision tree" +icon: "arrows-rotate" +sidebarTitle: "Hook Lifecycle" +--- -Deep dive into `scripts/suggest-optimize.sh` -- the Stop hook that detects commits and suggests optimizations. +Deep dive into `scripts/suggest-optimize.sh` — the Stop hook that detects commits and suggests optimizations. ## When the hook fires @@ -12,41 +17,43 @@ The hook evaluates a series of conditions and takes the first matching exit path ``` 1. stop_hook_active == true? - YES -> exit 0 (allow stop, prevent infinite loop) + YES → exit 0 (allow stop, prevent infinite loop) 2. Not inside a git repo? - YES -> exit 0 + YES → exit 0 3. No transcript_path or file doesn't exist? - YES -> exit 0 + YES → exit 0 4. Session start time unavailable? - YES -> exit 0 + YES → exit 0 5. No commits with .py/.js/.ts/.jsx/.tsx files since session start? - YES -> exit 0 + YES → exit 0 6. Commit hash set already seen (in codeflash-seen)? - YES -> exit 0 + YES → exit 0 7. JS/TS project with JS changes? - 7a. Not configured -> block: set up config (+ install if needed) - 7b. Configured, not installed -> block: install codeflash - 7c. Configured + installed -> block: run codeflash + 7a. Not configured → block: set up config (+ install if needed) + 7b. Configured, not installed → block: install codeflash + 7c. Configured + installed → block: run codeflash 8. No Python changes? - YES -> exit 0 + YES → exit 0 9. Python project, no venv found? - YES -> block: create venv, install, configure, run + YES → block: create venv, install, configure, run 10. Python project with venv: - 10a. Not configured -> block: set up config (+ install if needed) - 10b. Configured, not installed -> block: install codeflash - 10c. Configured + installed -> block: run codeflash + 10a. Not configured → block: set up config (+ install if needed) + 10b. Configured, not installed → block: install codeflash + 10c. Configured + installed → block: run codeflash ``` + Every `block` decision also appends auto-allow instructions if `Bash(*codeflash*)` is not yet in `.claude/settings.json`. + ## Infinite loop prevention @@ -74,9 +81,9 @@ git log --after="@$SESSION_START" --name-only --diff-filter=ACMR \ --pretty=format: -- '*.py' '*.js' '*.ts' '*.jsx' '*.tsx' ``` -- `--after=@$SESSION_START` -- only commits after session start (Unix timestamp) -- `--diff-filter=ACMR` -- Added, Copied, Modified, Renamed files only -- `--pretty=format:` -- suppress commit metadata, show only file names +- `--after=@$SESSION_START` — only commits after session start (Unix timestamp) +- `--diff-filter=ACMR` — Added, Copied, Modified, Renamed files only +- `--pretty=format:` — suppress commit metadata, show only file names - File patterns filter to Python and JS/TS extensions The results are sorted and deduplicated. The hook also determines which language families have changes (`HAS_PYTHON_CHANGES`, `HAS_JS_CHANGES`) by grepping the file list for extension patterns. @@ -87,7 +94,8 @@ The hook prevents suggesting optimization for the same set of commits twice: 1. It computes the commit hashes of all matching commits: ```bash - git log --after="@$SESSION_START" --pretty=format:%H -- '*.py' '*.js' '*.ts' '*.jsx' '*.tsx' + git log --after="@$SESSION_START" --pretty=format:%H \ + -- '*.py' '*.js' '*.ts' '*.jsx' '*.tsx' ``` 2. It hashes the full list with SHA-256: ```bash @@ -113,7 +121,7 @@ The `detect_project` function walks from `$PWD` upward to `$REPO_ROOT`: For Python, it checks for `[tool.codeflash]` in `pyproject.toml`. For JS/TS, it checks for a `"codeflash"` key in `package.json` using `jq`. -The walk stops at `$REPO_ROOT` -- it never searches above the git repository root. +The walk stops at `$REPO_ROOT` — it never searches above the git repository root. ## Auto-allow suggestion diff --git a/docs/troubleshooting.md b/docs/claude-code-plugin/troubleshooting.mdx similarity index 93% rename from docs/troubleshooting.md rename to docs/claude-code-plugin/troubleshooting.mdx index d0ce66c2e..71c139d47 100644 --- a/docs/troubleshooting.md +++ b/docs/claude-code-plugin/troubleshooting.mdx @@ -1,4 +1,9 @@ -# Troubleshooting +--- +title: "Troubleshooting" +description: "Common problems and fixes for the Codeflash Claude Code plugin" +icon: "wrench" +sidebarTitle: "Troubleshooting" +--- ## Plugin not appearing after install @@ -16,7 +21,7 @@ **Possible causes**: - No project config found. The agent walks from CWD to the git root looking for `pyproject.toml` or `package.json`. Make sure you're inside a git repository. - Codeflash CLI not installed. For Python: `pip install codeflash` in your venv. For JS/TS: `npm install --save-dev codeflash`. -- The agent is running in the background. Check if you see "Codeflash is optimizing in the background" -- results appear when the background task completes. +- The agent is running in the background. Check if you see "Codeflash is optimizing in the background" — results appear when the background task completes. ## Permission prompts every time @@ -55,6 +60,7 @@ The plugin searches for venvs in this order: **Symptom**: `npx codeflash --version` fails or package not found. **Fix**: + ```bash npm install --save-dev codeflash ``` @@ -83,7 +89,9 @@ This shouldn't happen due to deduplication (the hook tracks seen commit hashes i ## "Attempting to repair broken tests..." + This is **normal codeflash behavior**, not an error. Codeflash generates tests and sometimes needs to fix them. Let it continue. + ## 10-minute timeout exceeded diff --git a/docs/usage-guide.md b/docs/claude-code-plugin/usage-guide.mdx similarity index 90% rename from docs/usage-guide.md rename to docs/claude-code-plugin/usage-guide.mdx index ecbe4a2f1..598b9a2e8 100644 --- a/docs/usage-guide.md +++ b/docs/claude-code-plugin/usage-guide.mdx @@ -1,4 +1,9 @@ -# Usage Guide +--- +title: "Usage Guide" +description: "Commands, flags, and workflows for the Codeflash Claude Code plugin" +icon: "book" +sidebarTitle: "Usage Guide" +--- ## The `/optimize` skill @@ -44,7 +49,9 @@ The agent has up to **15 turns** to complete its work (install codeflash, config 3. If not, adds it (creating the file and directory if needed) 4. Preserves any existing settings -Running `/setup` multiple times is safe -- it's idempotent. If permissions are already configured, it reports "No changes needed." + +Running `/setup` multiple times is safe — it's idempotent. If permissions are already configured, it reports "No changes needed." + ## Automatic post-commit suggestions @@ -89,4 +96,4 @@ For JavaScript/TypeScript projects, the optimizer agent: 3. Always runs from the project root (the directory containing `package.json`) 4. Runs: `npx codeflash --subagent [flags]` -No virtual environment is needed -- JS/TS projects use `npx`/`npm` directly. +No virtual environment is needed — JS/TS projects use `npx`/`npm` directly. diff --git a/docs/docs.json b/docs/docs.json index fe0c23098..4e9a42fa2 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -65,6 +65,17 @@ "editor-plugins/vscode/configuration", "editor-plugins/vscode/troubleshooting" ] + }, + { + "group": "Claude Code Plugin", + "pages": [ + "claude-code-plugin/getting-started", + "claude-code-plugin/usage-guide", + "claude-code-plugin/configuration", + "claude-code-plugin/architecture", + "claude-code-plugin/hook-lifecycle", + "claude-code-plugin/troubleshooting" + ] } ] } From a6560223720020b2c5be488c86fb713750b870e2 Mon Sep 17 00:00:00 2001 From: aseembits93 Date: Thu, 19 Mar 2026 17:15:04 -0700 Subject: [PATCH 3/4] cleaning up --- docs/claude-code-plugin/architecture.mdx | 138 ------------------ docs/claude-code-plugin/configuration.mdx | 122 ---------------- docs/claude-code-plugin/getting-started.mdx | 4 +- docs/claude-code-plugin/hook-lifecycle.mdx | 153 -------------------- docs/claude-code-plugin/troubleshooting.mdx | 17 --- docs/claude-code-plugin/usage-guide.mdx | 56 +------ 6 files changed, 7 insertions(+), 483 deletions(-) delete mode 100644 docs/claude-code-plugin/architecture.mdx delete mode 100644 docs/claude-code-plugin/configuration.mdx delete mode 100644 docs/claude-code-plugin/hook-lifecycle.mdx diff --git a/docs/claude-code-plugin/architecture.mdx b/docs/claude-code-plugin/architecture.mdx deleted file mode 100644 index ee5a46537..000000000 --- a/docs/claude-code-plugin/architecture.mdx +++ /dev/null @@ -1,138 +0,0 @@ ---- -title: "Architecture" -description: "Plugin components, data flow, and internal protocols" -icon: "sitemap" -sidebarTitle: "Architecture" ---- - -## Data flow - -``` -User types /optimize User commits code - | | - v v - SKILL.md hooks.json - (fork context) (Stop event, * matcher) - | | - v v - optimizer agent suggest-optimize.sh - (15 turns, inherited model) (bash, 30s timeout) - | | - v v - Verify env & config Detect new commits - | with .py/.js/.ts files - v | - codeflash CLI v - (background, 10min timeout) Block Claude's stop - | with suggestion message - v | - Results reported Claude acts on suggestion - to user (install / configure / run) -``` - -## Component inventory - -| File | Type | Purpose | -|------|------|---------| -| `.claude-plugin/plugin.json` | Manifest | Plugin identity, version, metadata | -| `.claude-plugin/marketplace.json` | Manifest | Marketplace listing, owner info | -| `skills/optimize/SKILL.md` | Skill | `/optimize` slash command definition | -| `commands/setup.md` | Command | `/setup` slash command for auto-permissions | -| `agents/optimizer.md` | Agent | Background optimization agent with full workflow | -| `hooks/hooks.json` | Hook config | Registers the Stop hook | -| `scripts/suggest-optimize.sh` | Hook script | Commit detection, dedup, project discovery | -| `scripts/find-venv.sh` | Helper script | Python venv auto-discovery | - -## Skill format - -Skills use YAML frontmatter in a Markdown file: - -```yaml ---- -name: optimize -description: Optimize Python, JavaScript, or TypeScript code for performance using Codeflash -user-invocable: true -argument-hint: "[--file] [--function] [--subagent]" -context: fork # Forks context so optimization doesn't pollute main conversation -agent: codeflash:optimizer # Delegates to the optimizer agent -allowed-tools: Task ---- -``` - -The `context: fork` setting means the skill runs in a forked context — the optimizer agent gets its own conversation branch, keeping the main session clean. - -## Agent format - -Agents use YAML frontmatter followed by a system prompt: - -```yaml ---- -name: optimizer -description: | - Optimizes Python and JavaScript/TypeScript code for performance... -model: inherit # Uses the same model as the parent conversation -maxTurns: 15 # Maximum number of agent turns -color: cyan # Status line color -tools: Read, Glob, Grep, Bash, Write, Edit ---- -``` - -The agent body contains the full workflow: project detection, environment verification, configuration setup, running codeflash, and error handling. - -## Hook system - -### `hooks.json` structure - -```json -{ - "hooks": { - "Stop": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "${CLAUDE_PLUGIN_ROOT}/scripts/suggest-optimize.sh", - "timeout": 30 - } - ] - } - ] - } -} -``` - -- **Event**: `Stop` — fires every time Claude finishes a response -- **Matcher**: `*` — matches all stops (no filtering by tool or content) -- **Timeout**: 30 seconds for the hook script to complete -- **`${CLAUDE_PLUGIN_ROOT}`**: Resolved by Claude Code to the plugin's install directory - -### Hook stdin/stdout protocol - -**Input** (JSON on stdin): - -```json -{ - "stop_hook_active": false, - "transcript_path": "/path/to/transcript.jsonl" -} -``` - -**Output** (JSON on stdout): - -```json -{"decision": "block", "reason": "message for Claude to act on"} -``` - -Or no output / exit 0 to allow the stop (no blocking). - -The `decision` field can be: -- `"block"` — prevents Claude from stopping, injects `reason` as a new prompt for Claude to act on -- Absent / script exits 0 without output — allows the stop - -## State files - -| File | Purpose | Lifetime | -|------|---------|----------| -| `/tmp/codeflash-hook-debug.log` | Debug output from the hook script (`set -x` stderr) | Persists across sessions until manually cleared | -| `$TRANSCRIPT_DIR/codeflash-seen` | SHA-256 hashes of already-processed commit sets | Per-session (lives alongside the transcript file) | diff --git a/docs/claude-code-plugin/configuration.mdx b/docs/claude-code-plugin/configuration.mdx deleted file mode 100644 index f164a6db8..000000000 --- a/docs/claude-code-plugin/configuration.mdx +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: "Configuration" -description: "Configuration reference for plugin manifests, project config, and Claude Code permissions" -icon: "gear" -sidebarTitle: "Configuration" ---- - -## Plugin manifests - -These files live in `.claude-plugin/` and define the plugin for Claude Code's plugin system. You generally don't need to modify them. - -### `plugin.json` - -```json -{ - "name": "codeflash", - "description": "Run codeflash as a background agent to optimize code for performance", - "version": "0.1.10", - "author": { "name": "Codeflash", "url": "https://codeflash.ai" }, - "repository": "https://github.com/codeflash-ai/codeflash-cc-plugin", - "license": "MIT", - "keywords": ["python", "javascript", "typescript", "optimization", "performance"] -} -``` - -### `marketplace.json` - -Defines the plugin for the Claude Code marketplace. Contains owner info, metadata, and a `plugins` array with the same fields as `plugin.json` plus `source` (relative path) and `category`. - -## Python project configuration - -Codeflash reads its configuration from `[tool.codeflash]` in `pyproject.toml`. - -### Full reference - -```toml -[tool.codeflash] -# All paths are relative to this pyproject.toml's directory. -module-root = "src" # Root of your Python module (where tests import from) -tests-root = "tests" # Directory containing your test files -ignore-paths = [] # Paths to exclude from optimization -formatter-cmds = ["disabled"] # Formatter commands, or ["disabled"] to skip formatting -``` - -### Fields - -| Field | Required | Default | Description | -|-------|----------|---------|-------------| -| `module-root` | Yes | — | Relative path to the module root. If your tests do `from mypackage import ...`, then `mypackage/` is the module root | -| `tests-root` | Yes | — | Relative path to the tests directory | -| `ignore-paths` | No | `[]` | List of paths to exclude from optimization | -| `formatter-cmds` | No | `["disabled"]` | List of formatter commands. Each can include flags, e.g. `"black --line-length 88 {file}"`. Use `["disabled"]` to skip formatting | - -### Auto-discovery - -When configuration is missing, the optimizer agent discovers values automatically: - -- **module-root**: Uses Glob and Read to find the Python package directory (the one tests import from) -- **tests-root**: Looks for directories named `tests` or `test`, or folders containing `test_*.py` files. Falls back to `tests` (creates it if needed) - -## JS/TS project configuration - -Codeflash reads its configuration from a `"codeflash"` key at the root level of `package.json`. - -### Full reference - -```json -{ - "codeflash": { - "moduleRoot": "src", - "testsRoot": "tests", - "formatterCmds": ["disabled"], - "ignorePaths": ["dist", "**/node_modules", "**/__tests__"] - } -} -``` - -### Fields - -| Field | Required | Default | Description | -|-------|----------|---------|-------------| -| `moduleRoot` | Yes | — | Relative path to the JS/TS module root (e.g. `.` or `src`) | -| `testsRoot` | Yes | — | Relative path to the tests directory | -| `formatterCmds` | No | `["disabled"]` | Formatter commands. Use `npx` prefix for project-local tools, e.g. `"npx prettier --write {file}"` | -| `ignorePaths` | No | `[]` | Glob patterns to exclude from optimization | - -### Auto-discovery - -When configuration is missing, the optimizer agent: - -- **moduleRoot**: Inspects the project structure; typically `.` or `src` -- **testsRoot**: Looks for `tests`, `test`, `__tests__`, or directories with `*.test.js`/`*.spec.ts` files. Falls back to `tests` - -## Claude Code permissions - -To allow codeflash to run without permission prompts, add the following to `.claude/settings.json` in your project root: - -```json -{ - "permissions": { - "allow": [ - "Bash(*codeflash*)" - ] - } -} -``` - -This can be set up automatically by running `/setup`. - -### Scope options - -The permission can be placed at different levels: - -| File | Scope | -|------|-------| -| `.claude/settings.json` | Project-wide, shared with team (committed to git) | -| `.claude/settings.local.json` | Project-wide, personal (gitignored) | -| `~/.claude/settings.json` | User-wide, all projects | - - -The stop hook checks `.claude/settings.json` in the repo root to determine if auto-allow is already configured. If the `permissions.allow` array contains any entry matching `codeflash`, the hook skips adding auto-allow instructions to its suggestions. - diff --git a/docs/claude-code-plugin/getting-started.mdx b/docs/claude-code-plugin/getting-started.mdx index 5f1afd7fe..a951939b8 100644 --- a/docs/claude-code-plugin/getting-started.mdx +++ b/docs/claude-code-plugin/getting-started.mdx @@ -69,10 +69,10 @@ You can continue working while codeflash optimizes in the background. ## Set up auto-permissions -Run `/setup` to allow codeflash to execute automatically without permission prompts: +Run `/codeflash:setup` to allow codeflash to execute automatically without permission prompts: ``` -/setup +/codeflash:setup ``` This adds `Bash(*codeflash*)` to the `permissions.allow` array in `.claude/settings.json`. After this, the post-commit hook can trigger optimizations without asking each time. diff --git a/docs/claude-code-plugin/hook-lifecycle.mdx b/docs/claude-code-plugin/hook-lifecycle.mdx deleted file mode 100644 index 6a3093c06..000000000 --- a/docs/claude-code-plugin/hook-lifecycle.mdx +++ /dev/null @@ -1,153 +0,0 @@ ---- -title: "Hook Lifecycle" -description: "Deep dive into the Stop hook: commit detection, deduplication, and decision tree" -icon: "arrows-rotate" -sidebarTitle: "Hook Lifecycle" ---- - -Deep dive into `scripts/suggest-optimize.sh` — the Stop hook that detects commits and suggests optimizations. - -## When the hook fires - -The hook fires on **every Claude stop** (every time Claude finishes a response). This is configured in `hooks/hooks.json` with a `*` matcher, meaning it runs unconditionally regardless of what Claude just did. - -## Decision tree - -The hook evaluates a series of conditions and takes the first matching exit path: - -``` -1. stop_hook_active == true? - YES → exit 0 (allow stop, prevent infinite loop) - -2. Not inside a git repo? - YES → exit 0 - -3. No transcript_path or file doesn't exist? - YES → exit 0 - -4. Session start time unavailable? - YES → exit 0 - -5. No commits with .py/.js/.ts/.jsx/.tsx files since session start? - YES → exit 0 - -6. Commit hash set already seen (in codeflash-seen)? - YES → exit 0 - -7. JS/TS project with JS changes? - 7a. Not configured → block: set up config (+ install if needed) - 7b. Configured, not installed → block: install codeflash - 7c. Configured + installed → block: run codeflash - -8. No Python changes? - YES → exit 0 - -9. Python project, no venv found? - YES → block: create venv, install, configure, run - -10. Python project with venv: - 10a. Not configured → block: set up config (+ install if needed) - 10b. Configured, not installed → block: install codeflash - 10c. Configured + installed → block: run codeflash -``` - - -Every `block` decision also appends auto-allow instructions if `Bash(*codeflash*)` is not yet in `.claude/settings.json`. - - -## Infinite loop prevention - -When the hook blocks Claude's stop with a suggestion, Claude acts on it (e.g., runs codeflash). When Claude finishes that response, the hook fires again. To prevent an infinite loop: - -1. Claude sets `stop_hook_active: true` in the hook input when it's responding to a previous hook block -2. The hook checks this flag first and immediately exits if true - -This means the hook only triggers once per "natural" Claude stop, not on stops caused by responding to hook suggestions. - -## Session boundary detection - -The hook needs to know when the current session started to find only commits made during this session. - -1. It reads `transcript_path` from the hook input JSON -2. It gets the transcript file's **birth time** (creation timestamp) using `stat`: - - **macOS**: `stat -f %B ` (birth time) - - **Linux**: `stat -c %W ` (birth time), falls back to `stat -c %Y` (modification time) if birth time is unavailable -3. This timestamp becomes `SESSION_START`, used in `git log --after=@$SESSION_START` - -## Commit detection - -```bash -git log --after="@$SESSION_START" --name-only --diff-filter=ACMR \ - --pretty=format: -- '*.py' '*.js' '*.ts' '*.jsx' '*.tsx' -``` - -- `--after=@$SESSION_START` — only commits after session start (Unix timestamp) -- `--diff-filter=ACMR` — Added, Copied, Modified, Renamed files only -- `--pretty=format:` — suppress commit metadata, show only file names -- File patterns filter to Python and JS/TS extensions - -The results are sorted and deduplicated. The hook also determines which language families have changes (`HAS_PYTHON_CHANGES`, `HAS_JS_CHANGES`) by grepping the file list for extension patterns. - -## Deduplication - -The hook prevents suggesting optimization for the same set of commits twice: - -1. It computes the commit hashes of all matching commits: - ```bash - git log --after="@$SESSION_START" --pretty=format:%H \ - -- '*.py' '*.js' '*.ts' '*.jsx' '*.tsx' - ``` -2. It hashes the full list with SHA-256: - ```bash - ... | shasum -a 256 | cut -d' ' -f1 - ``` -3. It checks this hash against `$TRANSCRIPT_DIR/codeflash-seen` -4. If found, the hook exits (already processed) -5. If not found, appends the hash and continues - -The seen-marker file lives in the transcript directory, so it's scoped to the current session/project. - -## Project detection (`detect_project`) - -The `detect_project` function walks from `$PWD` upward to `$REPO_ROOT`: - -1. At each directory level, check for `pyproject.toml` first, then `package.json` -2. The **first** config file found determines the project type -3. It records: - - `PROJECT_TYPE`: `"python"` or `"js"` - - `PROJECT_DIR`: directory containing the config file - - `PROJECT_CONFIG_PATH`: full path to the config file - - `PROJECT_CONFIGURED`: `"true"` if codeflash config section exists - -For Python, it checks for `[tool.codeflash]` in `pyproject.toml`. For JS/TS, it checks for a `"codeflash"` key in `package.json` using `jq`. - -The walk stops at `$REPO_ROOT` — it never searches above the git repository root. - -## Auto-allow suggestion - -Every `block` decision checks whether codeflash is already auto-allowed: - -```bash -SETTINGS_JSON="$REPO_ROOT/.claude/settings.json" -jq -e '.permissions.allow // [] | any(test("codeflash"))' "$SETTINGS_JSON" -``` - -If no matching entry exists, the block message appends instructions to add `Bash(*codeflash*)` to `permissions.allow`. This means after the first optimization, future runs won't need permission prompts. - -## Debug logging - -The hook writes all debug output to `/tmp/codeflash-hook-debug.log`: - -```bash -LOGFILE="/tmp/codeflash-hook-debug.log" -exec 2>>"$LOGFILE" -set -x -``` - -All stderr (including bash trace output from `set -x`) is appended to this file. To debug hook issues: - -```bash -tail -f /tmp/codeflash-hook-debug.log -``` - -The log persists across sessions and is not automatically cleaned up. diff --git a/docs/claude-code-plugin/troubleshooting.mdx b/docs/claude-code-plugin/troubleshooting.mdx index 71c139d47..911d795de 100644 --- a/docs/claude-code-plugin/troubleshooting.mdx +++ b/docs/claude-code-plugin/troubleshooting.mdx @@ -112,20 +112,3 @@ This can happen on large projects or with `--all`. Options: - Python: `which black` (or whichever formatter) - JS/TS: `npx prettier --version` (or whichever formatter) 3. Set `formatter-cmds = ["disabled"]` or `"formatterCmds": ["disabled"]` to skip formatting entirely - -## Debugging the hook script manually - -Run the hook script directly to test it: - -```bash -echo '{"stop_hook_active": false, "transcript_path": "/path/to/transcript.jsonl"}' | \ - bash /path/to/codeflash-cc-plugin/scripts/suggest-optimize.sh -``` - -Check the debug log for detailed trace output: - -```bash -tail -100 /tmp/codeflash-hook-debug.log -``` - -The log includes every variable and branch taken (via `set -x`), making it straightforward to trace why the hook did or didn't trigger. diff --git a/docs/claude-code-plugin/usage-guide.mdx b/docs/claude-code-plugin/usage-guide.mdx index 598b9a2e8..12d5ba25d 100644 --- a/docs/claude-code-plugin/usage-guide.mdx +++ b/docs/claude-code-plugin/usage-guide.mdx @@ -23,24 +23,22 @@ sidebarTitle: "Usage Guide" | `/optimize src/utils.py` | Optimize all functions in `src/utils.py` | | `/optimize src/utils.py my_function` | Optimize only `my_function` in that file | | `/optimize --all` | Optimize the entire project | -| `/optimize src/utils.py --no-pr` | Optimize without creating a PR | -| `/optimize src/utils.py --effort high` | Set optimization effort level to high | -Flags can be combined: `/optimize src/utils.py my_function --no-pr --effort high` +Flags can be combined: `/optimize src/utils.py my_function` ### What happens behind the scenes 1. The skill (defined in `skills/optimize/SKILL.md`) forks context and spawns the **optimizer agent** -2. The agent locates your project config (`pyproject.toml` or `package.json`) +2. The agent locates your project config (`pyproject.toml` or `package.json` or `codeflash.toml`) 3. It verifies the codeflash CLI is installed and the project is configured 4. It runs `codeflash --subagent` as a **background task** with a 10-minute timeout 5. You're notified when optimization completes with results The agent has up to **15 turns** to complete its work (install codeflash, configure the project, run optimization). -## The `/setup` command +## The `/codeflash:setup` command -`/setup` configures auto-permissions so codeflash runs without prompting. +`/codeflash:setup` configures auto-permissions so codeflash runs without prompting. ### What it does @@ -50,50 +48,6 @@ The agent has up to **15 turns** to complete its work (install codeflash, config 4. Preserves any existing settings -Running `/setup` multiple times is safe — it's idempotent. If permissions are already configured, it reports "No changes needed." +Running `/codeflash:setup` multiple times is safe — it's idempotent. If permissions are already configured, it reports "No changes needed." -## Automatic post-commit suggestions - -After every Claude response (the **Stop** hook), the plugin checks whether you committed Python, JS, or TS files during the current session. If so, it suggests running `/optimize`. - -### How commit detection works - -1. The hook determines the session start time from the transcript file's creation timestamp -2. It queries `git log --after=@` for commits touching `*.py`, `*.js`, `*.ts`, `*.jsx`, `*.tsx` files -3. It deduplicates so the same commits don't trigger suggestions twice -4. If new commits are found, it blocks Claude's stop and injects a suggestion - -The suggestion varies depending on the project state: - -| State | Suggestion | -|-------|------------| -| Configured + installed | Run `codeflash --subagent` in the background | -| Configured, not installed | Install codeflash first, then run | -| Not configured | Auto-discover config, write it, then run | -| No venv (Python) | Create venv, install codeflash, configure, then run | - -If `Bash(*codeflash*)` is not yet in `.claude/settings.json`, the suggestion also includes adding it for auto-permissions. - -## Python-specific workflow - -For Python projects, the optimizer agent: - -1. Checks for an active virtual environment (`$VIRTUAL_ENV`) -2. If none, searches for `.venv` or `venv` directories in the project dir and repo root -3. Verifies `codeflash` is installed in the venv (`$VIRTUAL_ENV/bin/codeflash --version`) -4. Reads `[tool.codeflash]` from `pyproject.toml` for configuration -5. Runs: `source $VIRTUAL_ENV/bin/activate && codeflash --subagent [flags]` - -The agent also checks `formatter-cmds` in the config and verifies formatters are installed. - -## JS/TS-specific workflow - -For JavaScript/TypeScript projects, the optimizer agent: - -1. Checks codeflash is available via `npx codeflash --version` -2. Reads the `"codeflash"` key from `package.json` for configuration -3. Always runs from the project root (the directory containing `package.json`) -4. Runs: `npx codeflash --subagent [flags]` - -No virtual environment is needed — JS/TS projects use `npx`/`npm` directly. From 36e5f932ab5bcfcd38b56d6940825021961a28fb Mon Sep 17 00:00:00 2001 From: aseembits93 Date: Thu, 19 Mar 2026 17:22:11 -0700 Subject: [PATCH 4/4] removing unused md files --- docs/FRICTIONLESS_SETUP_PLAN.md | 1 - docs/JS_PROMPT_PARITY_RECOMMENDATIONS.md | 1 - docs/configuration.mdx | 26 - docs/docs.json | 3 - docs/install.md | 167 ---- docs/java-support-architecture.md | 1095 ---------------------- 6 files changed, 1293 deletions(-) delete mode 100644 docs/FRICTIONLESS_SETUP_PLAN.md delete mode 100644 docs/JS_PROMPT_PARITY_RECOMMENDATIONS.md delete mode 100644 docs/configuration.mdx delete mode 100644 docs/install.md delete mode 100644 docs/java-support-architecture.md diff --git a/docs/FRICTIONLESS_SETUP_PLAN.md b/docs/FRICTIONLESS_SETUP_PLAN.md deleted file mode 100644 index 8b1378917..000000000 --- a/docs/FRICTIONLESS_SETUP_PLAN.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/JS_PROMPT_PARITY_RECOMMENDATIONS.md b/docs/JS_PROMPT_PARITY_RECOMMENDATIONS.md deleted file mode 100644 index 8b1378917..000000000 --- a/docs/JS_PROMPT_PARITY_RECOMMENDATIONS.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/configuration.mdx b/docs/configuration.mdx deleted file mode 100644 index 29506b952..000000000 --- a/docs/configuration.mdx +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: "Manual Configuration" -description: "Configure Codeflash for your project" -icon: "gear" -sidebarTitle: "Manual Configuration" -keywords: - [ - "configuration", - "setup", - "settings", - ] ---- - -# Manual Configuration - -Codeflash is installed and configured on a per-project basis. -`codeflash init` should guide you through the configuration process, but if you need to manually configure Codeflash or set advanced settings, follow the guide for your language: - - - - Configure via `pyproject.toml` - - - Configure via `package.json` - - \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index 4e9a42fa2..8fc5ddde8 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -71,9 +71,6 @@ "pages": [ "claude-code-plugin/getting-started", "claude-code-plugin/usage-guide", - "claude-code-plugin/configuration", - "claude-code-plugin/architecture", - "claude-code-plugin/hook-lifecycle", "claude-code-plugin/troubleshooting" ] } diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index f2afff145..000000000 --- a/docs/install.md +++ /dev/null @@ -1,167 +0,0 @@ -# Codeflash Installation Guide - -I need to install and configure Codeflash for my project to enable AI-powered performance optimization. - -## Objective - -Install Codeflash CLI and configure it for either Python or JavaScript/TypeScript project with proper test data serialization and GitHub integration. - -## Success Condition - -Codeflash is successfully installed, configured with API key, connected to GitHub, and can run optimization commands without errors. - -## TODO - -1. Install Codeflash CLI for your language -2. Run initialization and configuration -3. Generate and configure API key -4. Install GitHub App -5. Verify installation - -## Installation Steps - -### For Python Projects - -**Prerequisites:** -- Python 3.9 or above -- Virtual environment activated -- Project dependencies installed - -**Commands:** - -```bash -# Activate virtual environment -source venv/bin/activate # Linux/Mac -# or -venv\Scripts\activate # Windows - -# Install Codeflash -pip install codeflash - -# Or as dev dependency with modern tools -uv add --dev codeflash -# or -poetry add codeflash@latest --group dev - -# Initialize configuration -cd /path/to/project/root -codeflash init -``` - -**Configuration prompts:** -1. Enter Codeflash API key -2. Specify Python module to optimize (e.g., `my_module`) -3. Specify test location (e.g., `tests/`) -4. Select code formatter (black/ruff/other/disabled) -5. Select git remote for PRs -6. Opt-in to anonymous usage data -7. Install GitHub app -8. Install GitHub actions - -### For JavaScript/TypeScript Projects - -**Prerequisites:** -- Node.js 16 or above -- Package manager (npm/yarn/pnpm/bun) -- Project dependencies installed - -**Commands:** - -```bash -# Verify Node.js version -node --version # Should be v16.0.0+ - -# Install Codeflash as dev dependency -npm install --save-dev codeflash -# or -yarn add --dev codeflash -# or -pnpm add --save-dev codeflash -# or -bun add --dev codeflash - -# Or install globally -npm install -g codeflash - -# Initialize configuration -cd /path/to/project/root -codeflash init -``` - -**Configuration prompts:** -1. Enter Codeflash API key -2. Specify JavaScript/TypeScript module (e.g., `src/`) -3. Specify test location (e.g., `tests/`, `__tests__/`, `*.test.js`) -4. Select test framework (jest/vitest/mocha/ava/other) -5. Select code formatter (prettier/eslint/biome/disabled) -6. Select git remote for PRs -7. Opt-in to anonymous usage data -8. Install GitHub app -9. Install GitHub actions - -**Serialization Strategy:** -JavaScript/TypeScript projects use V8 serialization automatically for optimal test data capture: -- Binary storage format -- Perfect type preservation (Date, Map, Set, TypedArrays, BigInt, etc.) -- 2-3x faster than alternatives -- Framework agnostic (React, Vue, Angular, Svelte, etc.) - -### API Key Generation - -**Steps:** -1. Visit https://app.codeflash.ai/ -2. Sign up with GitHub account (free tier available) -3. Navigate to https://app.codeflash.ai/app/apikeys -4. Generate new API key -5. Copy and paste when prompted during `codeflash init` - -### GitHub App Installation - -**Steps:** -1. Visit https://github.com/apps/codeflash-ai/installations/select_target -2. Select the repository to install Codeflash -3. Grant necessary permissions -4. Confirm installation - -## Verification - -**Test the installation:** - -```bash -# Python - Optimize single function -codeflash --file path/to/file.py --function function_name - -# JavaScript/TypeScript - Optimize single function -codeflash --file path/to/file.js --function functionName - -# Optimize entire codebase (both languages) -codeflash --all - -# Verbose output for debugging -codeflash optimize --verbose -``` - -## Configuration Files - -**Python:** -- Configuration stored in `pyproject.toml` -- Serialization: SQLite + pickle - -**JavaScript/TypeScript:** -- Configuration stored in `codeflash.config.js` -- Serialization: V8 binary format - -## Framework Support - -**Python:** -- All Python projects with pytest, unittest, or similar - -**JavaScript/TypeScript:** -- Frontend: React, Vue, Angular, Svelte, Solid.js -- Backend: Express, NestJS, Fastify, Koa, Hono -- Testing: Jest, Vitest, Mocha, AVA, Playwright, Cypress -- Runtimes: Node.js (✅ Recommended), Bun/Deno (Coming soon) - -## Execute Installation - -Run the commands above for your specific language and answer the configuration prompts to complete Codeflash installation. \ No newline at end of file diff --git a/docs/java-support-architecture.md b/docs/java-support-architecture.md deleted file mode 100644 index 25ab0d003..000000000 --- a/docs/java-support-architecture.md +++ /dev/null @@ -1,1095 +0,0 @@ -# Java Language Support Architecture for CodeFlash - -## Executive Summary - -Adding Java support to CodeFlash requires implementing the `LanguageSupport` protocol with Java-specific components for parsing, test discovery, context extraction, and test execution. The existing architecture is well-designed for multi-language support, and Java can follow the established patterns from Python and JavaScript/TypeScript. - ---- - -## 1. Architecture Overview - -### Current Language Support Stack - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ Core Optimization Pipeline │ -│ (language-agnostic: optimizer.py, function_optimizer.py) │ -└───────────────────────────────┬─────────────────────────────────┘ - │ - ┌───────────▼───────────┐ - │ LanguageSupport │ - │ Protocol │ - └───────────┬───────────┘ - │ - ┌───────────────────────┼───────────────────────┐ - ▼ ▼ ▼ -┌───────────────┐ ┌─────────────────┐ ┌─────────────────┐ -│ PythonSupport │ │JavaScriptSupport│ │ JavaSupport │ -│ (mature) │ │ (functional) │ │ (NEW) │ -├───────────────┤ ├─────────────────┤ ├─────────────────┤ -│ - libcst │ │ - tree-sitter │ │ - tree-sitter │ -│ - pytest │ │ - jest │ │ - JUnit 5 │ -│ - Jedi │ │ - npm/yarn │ │ - Maven/Gradle │ -└───────────────┘ └─────────────────┘ └─────────────────┘ -``` - -### Proposed Java Module Structure - -``` -codeflash/languages/java/ -├── __init__.py # Module exports, register language -├── support.py # JavaSupport class (main implementation) -├── parser.py # Tree-sitter Java parsing utilities -├── discovery.py # Function/method discovery -├── context_extractor.py # Code context extraction -├── import_resolver.py # Java import/dependency resolution -├── instrument.py # Test instrumentation -├── test_runner.py # JUnit test execution -├── comparator.py # Test result comparison -├── build_tools.py # Maven/Gradle integration -├── formatter.py # Code formatting (google-java-format) -└── line_profiler.py # JProfiler/async-profiler integration -``` - ---- - -## 2. Core Components - -### 2.1 Language Registration - -```python -# codeflash/languages/java/support.py - -from codeflash.languages.base import Language, LanguageSupport -from codeflash.languages.registry import register_language - -@register_language -class JavaSupport: - @property - def language(self) -> Language: - return Language.JAVA # Add to Language enum - - @property - def file_extensions(self) -> tuple[str, ...]: - return (".java",) - - @property - def test_framework(self) -> str: - return "junit" - - @property - def comment_prefix(self) -> str: - return "//" -``` - -### 2.2 Language Enum Extension - -```python -# codeflash/languages/base.py - -class Language(Enum): - PYTHON = "python" - JAVASCRIPT = "javascript" - TYPESCRIPT = "typescript" - JAVA = "java" # NEW -``` - ---- - -## 3. Component Implementation Details - -### 3.1 Parsing (tree-sitter-java) - -**File: `codeflash/languages/java/parser.py`** - -Tree-sitter has excellent Java support. Key node types to handle: - -| Java Construct | Tree-sitter Node Type | -|----------------|----------------------| -| Class | `class_declaration` | -| Interface | `interface_declaration` | -| Method | `method_declaration` | -| Constructor | `constructor_declaration` | -| Static block | `static_initializer` | -| Lambda | `lambda_expression` | -| Anonymous class | `anonymous_class_body` | -| Annotation | `annotation` | -| Generic type | `type_parameters` | - -```python -class JavaParser: - """Tree-sitter based Java parser.""" - - def __init__(self): - self.parser = Parser() - self.parser.set_language(tree_sitter_java.language()) - - def find_methods(self, source: str) -> list[MethodNode]: - """Find all method declarations.""" - tree = self.parser.parse(source.encode()) - return self._walk_for_methods(tree.root_node) - - def find_classes(self, source: str) -> list[ClassNode]: - """Find all class/interface declarations.""" - ... - - def get_method_signature(self, node: Node) -> MethodSignature: - """Extract method signature including generics.""" - ... -``` - -### 3.2 Function Discovery - -**File: `codeflash/languages/java/discovery.py`** - -Java-specific considerations: -- Methods are always inside classes (no top-level functions) -- Need to handle: instance methods, static methods, constructors -- Interface default methods -- Annotation processing (`@Override`, `@Test`, etc.) -- Inner classes and nested methods - -```python -def discover_functions( - file_path: Path, - criteria: FunctionFilterCriteria | None = None -) -> list[FunctionInfo]: - """ - Discover optimizable methods in a Java file. - - Returns methods that are: - - Public or protected (can be tested) - - Not abstract - - Not native - - Not in test files - - Not trivial (getters/setters unless specifically requested) - """ - parser = JavaParser() - source = file_path.read_text(encoding="utf-8") - - methods = [] - for class_node in parser.find_classes(source): - for method in class_node.methods: - if _should_include_method(method, criteria): - methods.append(FunctionInfo( - name=method.name, - file_path=file_path, - start_line=method.start_line, - end_line=method.end_line, - parents=(ParentInfo( - name=class_node.name, - type="ClassDeclaration" - ),), - is_async=method.has_annotation("Async"), - is_method=True, - language=Language.JAVA, - )) - return methods -``` - -### 3.3 Code Context Extraction - -**File: `codeflash/languages/java/context_extractor.py`** - -Java context extraction must handle: -- Full class context (methods often depend on fields) -- Import statements (crucial for compilation) -- Package declarations -- Type hierarchy (extends/implements) -- Inner classes -- Static imports - -```python -def extract_code_context( - function: FunctionInfo, - project_root: Path, - module_root: Path | None = None -) -> CodeContext: - """ - Extract code context for a Java method. - - Context includes: - 1. Full containing class (target method needs class context) - 2. All imports from the file - 3. Helper classes from same package - 4. Superclass/interface definitions (read-only) - """ - source = function.file_path.read_text(encoding="utf-8") - parser = JavaParser() - - # Extract package and imports - package_name = parser.get_package(source) - imports = parser.get_imports(source) - - # Get the containing class - class_source = parser.extract_class_containing_method( - source, function.name, function.start_line - ) - - # Find helper classes (same package, used by target class) - helper_classes = find_helper_classes( - function.file_path.parent, - class_source, - imports - ) - - return CodeContext( - target_code=class_source, - target_file=function.file_path, - helper_functions=helper_classes, - read_only_context=get_superclass_context(imports, project_root), - imports=imports, - language=Language.JAVA, - ) -``` - -### 3.4 Import/Dependency Resolution - -**File: `codeflash/languages/java/import_resolver.py`** - -Java import resolution is more complex: -- Explicit imports (`import com.foo.Bar;`) -- Wildcard imports (`import com.foo.*;`) -- Static imports (`import static com.foo.Bar.method;`) -- Same-package classes (implicit) -- Standard library vs external dependencies - -```python -class JavaImportResolver: - """Resolve Java imports to source files.""" - - def __init__(self, project_root: Path, build_tool: BuildTool): - self.project_root = project_root - self.build_tool = build_tool - self.source_roots = self._find_source_roots() - self.classpath = build_tool.get_classpath() - - def resolve_import(self, import_stmt: str) -> ResolvedImport: - """ - Resolve an import to its source location. - - Returns: - - Source file path (if in project) - - JAR location (if external dependency) - - None (if JDK class) - """ - ... - - def find_same_package_classes(self, package: str) -> list[Path]: - """Find all classes in the same package.""" - ... -``` - -### 3.5 Test Discovery - -**File: `codeflash/languages/java/support.py` (part of JavaSupport)** - -Java test discovery for JUnit 5: - -```python -def discover_tests( - self, - test_root: Path, - source_functions: list[FunctionInfo] -) -> dict[str, list[TestInfo]]: - """ - Discover JUnit tests that cover target methods. - - Strategy: - 1. Find test files by naming convention (*Test.java, *Tests.java) - 2. Parse test files for @Test annotated methods - 3. Analyze test code for method calls to target methods - 4. Match tests to source methods - """ - test_files = self._find_test_files(test_root) - test_map: dict[str, list[TestInfo]] = defaultdict(list) - - for test_file in test_files: - parser = JavaParser() - source = test_file.read_text() - - for test_method in parser.find_test_methods(source): - # Find which source methods this test calls - called_methods = parser.find_method_calls(test_method.body) - - for source_func in source_functions: - if source_func.name in called_methods: - test_map[source_func.qualified_name].append(TestInfo( - test_name=test_method.name, - test_file=test_file, - test_class=test_method.class_name, - )) - - return test_map -``` - -### 3.6 Test Execution - -**File: `codeflash/languages/java/test_runner.py`** - -JUnit test execution with Maven/Gradle: - -```python -class JavaTestRunner: - """Run JUnit tests via Maven or Gradle.""" - - def __init__(self, project_root: Path): - self.build_tool = detect_build_tool(project_root) - self.project_root = project_root - - def run_tests( - self, - test_classes: list[str], - timeout: int = 60, - capture_output: bool = True - ) -> TestExecutionResult: - """ - Run specified JUnit tests. - - Uses: - - Maven: mvn test -Dtest=ClassName#methodName - - Gradle: ./gradlew test --tests "ClassName.methodName" - """ - if self.build_tool == BuildTool.MAVEN: - return self._run_maven_tests(test_classes, timeout) - else: - return self._run_gradle_tests(test_classes, timeout) - - def _run_maven_tests(self, tests: list[str], timeout: int) -> TestExecutionResult: - cmd = [ - "mvn", "test", - f"-Dtest={','.join(tests)}", - "-Dmaven.test.failure.ignore=true", - "-DfailIfNoTests=false", - ] - result = subprocess.run(cmd, cwd=self.project_root, ...) - return self._parse_surefire_reports() - - def _parse_surefire_reports(self) -> TestExecutionResult: - """Parse target/surefire-reports/*.xml for test results.""" - ... -``` - -### 3.7 Code Instrumentation - -**File: `codeflash/languages/java/instrument.py`** - -Java instrumentation for behavior capture: - -```python -class JavaInstrumenter: - """Instrument Java code for behavior/performance capture.""" - - def instrument_for_behavior( - self, - source: str, - target_methods: list[str] - ) -> str: - """ - Add instrumentation to capture method inputs/outputs. - - Adds: - - CodeFlash.captureInput(args) before method body - - CodeFlash.captureOutput(result) before returns - - Exception capture in catch blocks - """ - parser = JavaParser() - tree = parser.parse(source) - - # Insert capture calls using tree-sitter edit operations - edits = [] - for method in parser.find_methods_by_name(tree, target_methods): - edits.append(self._create_input_capture(method)) - edits.append(self._create_output_capture(method)) - - return apply_edits(source, edits) - - def instrument_for_benchmarking( - self, - test_source: str, - target_method: str, - iterations: int = 1000 - ) -> str: - """ - Add timing instrumentation to test code. - - Wraps test execution in timing loop with warmup. - """ - ... -``` - -### 3.8 Build Tool Integration - -**File: `codeflash/languages/java/build_tools.py`** - -Maven and Gradle support: - -```python -class BuildTool(Enum): - MAVEN = "maven" - GRADLE = "gradle" - -def detect_build_tool(project_root: Path) -> BuildTool: - """Detect whether project uses Maven or Gradle.""" - if (project_root / "pom.xml").exists(): - return BuildTool.MAVEN - elif (project_root / "build.gradle").exists() or \ - (project_root / "build.gradle.kts").exists(): - return BuildTool.GRADLE - raise ValueError("No Maven or Gradle build file found") - -class MavenIntegration: - """Maven build tool integration.""" - - def __init__(self, project_root: Path): - self.pom_path = project_root / "pom.xml" - self.project_root = project_root - - def get_source_roots(self) -> list[Path]: - """Get configured source directories.""" - # Default: src/main/java, src/test/java - ... - - def get_classpath(self) -> list[Path]: - """Get full classpath including dependencies.""" - result = subprocess.run( - ["mvn", "dependency:build-classpath", "-q", "-DincludeScope=test"], - cwd=self.project_root, - capture_output=True - ) - return [Path(p) for p in result.stdout.decode().split(":")] - - def compile(self, include_tests: bool = True) -> bool: - """Compile the project.""" - cmd = ["mvn", "compile"] - if include_tests: - cmd.append("test-compile") - return subprocess.run(cmd, cwd=self.project_root).returncode == 0 - -class GradleIntegration: - """Gradle build tool integration.""" - # Similar implementation for Gradle - ... -``` - -### 3.9 Code Replacement - -**File: `codeflash/languages/java/support.py`** - -```python -def replace_function( - self, - source: str, - function: FunctionInfo, - new_source: str -) -> str: - """ - Replace a method in Java source code. - - Challenges: - - Method might have annotations - - Javadoc comments should be preserved/updated - - Overloaded methods need exact signature matching - """ - parser = JavaParser() - - # Find the exact method by line number (handles overloads) - method_node = parser.find_method_at_line(source, function.start_line) - - # Include Javadoc if present - start = method_node.javadoc_start or method_node.start - end = method_node.end - - # Replace the method - return source[:start] + new_source + source[end:] -``` - -### 3.10 Code Formatting - -**File: `codeflash/languages/java/formatter.py`** - -```python -def format_code(source: str, file_path: Path | None = None) -> str: - """ - Format Java code using google-java-format. - - Falls back to built-in formatter if google-java-format not available. - """ - try: - result = subprocess.run( - ["google-java-format", "-"], - input=source.encode(), - capture_output=True, - timeout=30 - ) - if result.returncode == 0: - return result.stdout.decode() - except FileNotFoundError: - pass - - # Fallback: basic indentation normalization - return normalize_indentation(source) -``` - ---- - -## 4. Test Result Comparison - -### 4.1 Behavior Verification - -For Java, test results comparison needs to handle: -- Object equality (`.equals()` vs reference equality) -- Collection ordering (Lists vs Sets) -- Floating point comparison with epsilon -- Exception messages and types -- Side effects (mocked interactions) - -```python -# codeflash/languages/java/comparator.py - -def compare_test_results( - original_results: Path, - candidate_results: Path, - project_root: Path -) -> tuple[bool, list[TestDiff]]: - """ - Compare behavior between original and optimized code. - - Uses a Java comparison utility (run via the build tool) - that handles Java-specific equality semantics. - """ - # Run Java-based comparison tool - result = subprocess.run([ - "java", "-cp", get_comparison_jar(), - "com.codeflash.Comparator", - str(original_results), - str(candidate_results) - ], capture_output=True) - - diffs = json.loads(result.stdout) - return len(diffs) == 0, [TestDiff(**d) for d in diffs] -``` - ---- - -## 5. AI Service Integration - -The AI service already supports language parameter. For Java: - -```python -# Called from function_optimizer.py -response = ai_service.optimize_code( - source_code=code_context.target_code, - dependency_code=code_context.read_only_context, - trace_id=trace_id, - language="java", - language_version="17", # or "11", "21" - n_candidates=5, -) -``` - -Java-specific optimization prompts should consider: -- Stream API optimizations -- Collection choice (ArrayList vs LinkedList, HashMap vs TreeMap) -- Concurrency patterns (CompletableFuture, parallel streams) -- Memory optimization (primitive vs boxed types) -- JIT-friendly patterns - ---- - -## 6. Configuration Detection - -**File: `codeflash/languages/java/config.py`** - -```python -def detect_java_version(project_root: Path) -> str: - """Detect Java version from build configuration.""" - build_tool = detect_build_tool(project_root) - - if build_tool == BuildTool.MAVEN: - # Check pom.xml for maven.compiler.source - pom = ET.parse(project_root / "pom.xml") - version = pom.find(".//maven.compiler.source") - if version is not None: - return version.text - - elif build_tool == BuildTool.GRADLE: - # Check build.gradle for sourceCompatibility - build_file = project_root / "build.gradle" - if build_file.exists(): - content = build_file.read_text() - match = re.search(r"sourceCompatibility\s*=\s*['\"]?(\d+)", content) - if match: - return match.group(1) - - # Fallback: detect from JAVA_HOME - return detect_jdk_version() - -def detect_source_roots(project_root: Path) -> list[Path]: - """Find source code directories.""" - standard_paths = [ - project_root / "src" / "main" / "java", - project_root / "src", - ] - return [p for p in standard_paths if p.exists()] - -def detect_test_roots(project_root: Path) -> list[Path]: - """Find test code directories.""" - standard_paths = [ - project_root / "src" / "test" / "java", - project_root / "test", - ] - return [p for p in standard_paths if p.exists()] -``` - ---- - -## 7. Runtime Library - -CodeFlash needs a Java runtime library for instrumentation: - -``` -codeflash-runtime-java/ -├── pom.xml -├── src/main/java/com/codeflash/ -│ ├── CodeFlash.java # Main capture API -│ ├── Capture.java # Input/output capture -│ ├── Comparator.java # Result comparison -│ ├── Timer.java # High-precision timing -│ └── Serializer.java # Object serialization for comparison -``` - -```java -// CodeFlash.java -package com.codeflash; - -public class CodeFlash { - public static void captureInput(String methodId, Object... args) { - // Serialize and store inputs - } - - public static T captureOutput(String methodId, T result) { - // Serialize and store output - return result; - } - - public static void captureException(String methodId, Throwable e) { - // Store exception info - } - - public static long startTimer() { - return System.nanoTime(); - } - - public static void recordTime(String methodId, long startTime) { - long elapsed = System.nanoTime() - startTime; - // Store timing - } -} -``` - ---- - -## 8. Implementation Phases - -### Phase 1: Foundation (MVP) - -1. Add `Language.JAVA` to enum -2. Implement tree-sitter Java parsing -3. Basic method discovery (public methods in classes) -4. Build tool detection (Maven/Gradle) -5. Simple context extraction (single file) -6. Test discovery (JUnit 5 `@Test` methods) -7. Test execution via Maven/Gradle - -### Phase 2: Full Pipeline - -1. Import resolution and dependency tracking -2. Multi-file context extraction -3. Test result capture and comparison -4. Code instrumentation for behavior verification -5. Benchmarking instrumentation -6. Code formatting integr.ation - -### Phase 3: Advanced Features - -1. Line profiler integration (JProfiler/async-profiler) -2. Generics handling in optimization -3. Lambda and stream optimization support -4. Concurrency-aware benchmarking -5. IDE integration (Language Server) - ---- - -## 9. Key Challenges & Considerations - -### 9.1 Java-Specific Challenges - -| Challenge | Solution | -|-----------|----------| -| **No top-level functions** | Always include class context | -| **Overloaded methods** | Use full signature for identification | -| **Compilation required** | Compile before running tests | -| **Build tool complexity** | Abstract via `BuildTool` interface | -| **Static typing** | Ensure type compatibility in replacements | -| **Generics** | Preserve type parameters in optimization | -| **Checked exceptions** | Maintain throws declarations | -| **Package visibility** | Handle package-private methods | - -### 9.2 Performance Considerations - -- **JVM Warmup**: Java needs JIT warmup before benchmarking -- **GC Noise**: Account for garbage collection in timing -- **Classloading**: First run is always slower - -```python -def run_benchmark_with_warmup( - test_method: str, - warmup_iterations: int = 100, - benchmark_iterations: int = 1000 -) -> BenchmarkResult: - """Run benchmark with proper JVM warmup.""" - # Warmup phase (results discarded) - run_tests(test_method, iterations=warmup_iterations) - - # Force GC before measurement - subprocess.run(["jcmd", str(pid), "GC.run"]) - - # Actual benchmark - return run_tests(test_method, iterations=benchmark_iterations) -``` - -### 9.3 Test Framework Support - -| Framework | Priority | Notes | -|-----------|----------|-------| -| JUnit 5 | High | Primary target, most modern | -| JUnit 4 | Medium | Still widely used | -| TestNG | Low | Different annotation model | -| Mockito | High | Mocking support needed | -| AssertJ | Medium | Fluent assertions | - ---- - -## 10. File Changes Summary - -### New Files to Create - -``` -codeflash/languages/java/ -├── __init__.py -├── support.py (~800 lines) -├── parser.py (~400 lines) -├── discovery.py (~300 lines) -├── context_extractor.py (~400 lines) -├── import_resolver.py (~350 lines) -├── instrument.py (~500 lines) -├── test_runner.py (~400 lines) -├── comparator.py (~200 lines) -├── build_tools.py (~350 lines) -├── formatter.py (~100 lines) -├── line_profiler.py (~300 lines) -└── config.py (~150 lines) -Total: ~4,250 lines -``` - -### Existing Files to Modify - -| File | Changes | -|------|---------| -| `codeflash/languages/base.py` | Add `JAVA` to `Language` enum | -| `codeflash/languages/__init__.py` | Import java module | -| `codeflash/cli_cmds/init.py` | Add Java project detection | -| `codeflash/api/aiservice.py` | No changes (already supports `language` param) | -| `requirements.txt` / `pyproject.toml` | Add `tree-sitter-java` | - -### External Dependencies - -```toml -# pyproject.toml additions -tree-sitter-java = "^0.21.0" -``` - ---- - -## 11. Testing Strategy - -### Unit Tests - -```python -# tests/languages/java/test_parser.py -def test_discover_methods_in_class(): - source = ''' - public class Calculator { - public int add(int a, int b) { - return a + b; - } - } - ''' - methods = JavaParser().find_methods(source) - assert len(methods) == 1 - assert methods[0].name == "add" - -# tests/languages/java/test_discovery.py -def test_discover_functions_filters_tests(): - # Test that test methods are excluded - ... -``` - -### Integration Tests - -```python -# tests/languages/java/test_integration.py -def test_full_optimization_pipeline(java_test_project): - """End-to-end test with a real Java project.""" - support = JavaSupport() - - functions = support.discover_functions( - java_test_project / "src/main/java/Example.java" - ) - - context = support.extract_code_context(functions[0], java_test_project) - - # Verify context is compilable - assert compile_java(context.target_code) -``` - ---- - -## 12. LanguageSupport Protocol Reference - -All methods that `JavaSupport` must implement: - -### Properties - -```python -@property -def language(self) -> Language: ... - -@property -def file_extensions(self) -> tuple[str, ...]: ... - -@property -def test_framework(self) -> str: ... - -@property -def comment_prefix(self) -> str: ... -``` - -### Discovery Methods - -```python -def discover_functions( - self, - file_path: Path, - criteria: FunctionFilterCriteria | None = None -) -> list[FunctionInfo]: ... - -def discover_tests( - self, - test_root: Path, - source_functions: list[FunctionInfo] -) -> dict[str, list[TestInfo]]: ... -``` - -### Code Analysis - -```python -def extract_code_context( - self, - function: FunctionInfo, - project_root: Path, - module_root: Path | None = None -) -> CodeContext: ... - -def find_helper_functions( - self, - function: FunctionInfo, - project_root: Path -) -> list[HelperFunction]: ... -``` - -### Code Transformation - -```python -def replace_function( - self, - source: str, - function: FunctionInfo, - new_source: str -) -> str: ... - -def format_code( - self, - source: str, - file_path: Path | None = None -) -> str: ... - -def normalize_code(self, source: str) -> str: ... -``` - -### Test Execution - -```python -def run_behavioral_tests( - self, - test_paths: list[Path], - test_env: dict[str, str], - cwd: Path, - timeout: int, - ... -) -> tuple[Path, Any, Path | None, Path | None]: ... - -def run_benchmarking_tests( - self, - test_paths: list[Path], - test_env: dict[str, str], - cwd: Path, - timeout: int, - ... -) -> tuple[Path, Any]: ... -``` - -### Instrumentation - -```python -def instrument_for_behavior( - self, - source: str, - functions: list[str] -) -> str: ... - -def instrument_for_benchmarking( - self, - test_source: str, - target_function: str -) -> str: ... - -def instrument_existing_test( - self, - test_path: Path, - call_positions: list[tuple[int, int]], - ... -) -> tuple[bool, str | None]: ... -``` - -### Validation - -```python -def validate_syntax(self, source: str) -> bool: ... -``` - -### Result Comparison - -```python -def compare_test_results( - self, - original_path: Path, - candidate_path: Path, - project_root: Path -) -> tuple[bool, list[TestDiff]]: ... -``` - ---- - -## 13. Data Flow Diagram - -``` -┌──────────────────────────────────────────────────────────────────────────┐ -│ Java Optimization Flow │ -└──────────────────────────────────────────────────────────────────────────┘ - -User runs: codeflash optimize Example.java - │ - ▼ - ┌───────────────────────────────┐ - │ Detect Build Tool │ - │ (Maven pom.xml / Gradle) │ - └───────────────┬───────────────┘ - │ - ▼ - ┌───────────────────────────────┐ - │ Discover Methods │ - │ (tree-sitter-java parsing) │ - │ Filter: public, non-test │ - └───────────────┬───────────────┘ - │ - ▼ - ┌───────────────────────────────┐ - │ Extract Code Context │ - │ - Full class with imports │ - │ - Helper classes (same pkg) │ - │ - Superclass definitions │ - └───────────────┬───────────────┘ - │ - ▼ - ┌───────────────────────────────┐ - │ Discover Tests │ - │ - Find *Test.java files │ - │ - Parse @Test annotations │ - │ - Match to source methods │ - └───────────────┬───────────────┘ - │ - ▼ - ┌───────────────────────────────┐ - │ Run Baseline │ - │ - Compile (mvn/gradle) │ - │ - Execute JUnit tests │ - │ - Capture behavior + timing │ - └───────────────┬───────────────┘ - │ - ▼ - ┌───────────────────────────────┐ - │ AI Optimization │ - │ - Send to AI service │ - │ - language="java" │ - │ - Receive N candidates │ - └───────────────┬───────────────┘ - │ - ┌───────────┴───────────┐ - ▼ ▼ -┌───────────────┐ ┌───────────────┐ -│ Candidate 1 │ ... │ Candidate N │ -└───────┬───────┘ └───────┬───────┘ - │ │ - └───────────┬───────────┘ - │ - ▼ - ┌───────────────────────────────┐ - │ For Each Candidate: │ - │ 1. Replace method in source │ - │ 2. Compile project │ - │ 3. Run behavior tests │ - │ 4. Compare outputs │ - │ 5. If correct: benchmark │ - └───────────────┬───────────────┘ - │ - ▼ - ┌───────────────────────────────┐ - │ Select Best Candidate │ - │ - Correctness verified │ - │ - Best speedup │ - │ - Account for JVM warmup │ - └───────────────┬───────────────┘ - │ - ▼ - ┌───────────────────────────────┐ - │ Apply Optimization │ - │ - Update source file │ - │ - Create PR (optional) │ - │ - Report results │ - └───────────────────────────────┘ -``` - ---- - -## 14. Conclusion - -This architecture provides a comprehensive roadmap for adding Java support to CodeFlash. The modular design mirrors the existing JavaScript/TypeScript implementation pattern, making it straightforward to implement incrementally while maintaining consistency with the rest of the codebase. - -Key success factors: -1. **Leverage tree-sitter** for consistent parsing approach -2. **Abstract build tools** to support both Maven and Gradle -3. **Handle JVM specifics** (warmup, GC) in benchmarking -4. **Reuse existing infrastructure** where possible (AI service, result types) -5. **Implement incrementally** following the phased approach \ No newline at end of file