cleaning up

This commit is contained in:
aseembits93 2026-03-19 17:15:04 -07:00
parent 95d4863ff2
commit a656022372
6 changed files with 7 additions and 483 deletions

View file

@ -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) |

View file

@ -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 |
<Note>
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.
</Note>

View file

@ -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.

View file

@ -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
```
<Note>
Every `block` decision also appends auto-allow instructions if `Bash(*codeflash*)` is not yet in `.claude/settings.json`.
</Note>
## 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 <file>` (birth time)
- **Linux**: `stat -c %W <file>` (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.

View file

@ -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.

View file

@ -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
<Info>
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."
</Info>
## 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=@<session_start>` 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.