Root Claw is a multi-mode directory analysis tool powered by local or cloud LLMs via Ollama or OpenRouter.
Modes:
scan— recursive source code audit: security, vulnerabilities, architectural reviewimages— recursive image/video analysis via vision LLMs; two sub-modes: cluster tagging or per-file forensic reportssimulate— step-by-step execution simulation for a specific function/scenario
- Resilient Execution: Native timeout management for LLM requests to prevent indefinite hangs, with automatic fallback across a model chain.
- Dynamic Configuration: Hot-reloading of
config.jsonbetween file analyses, allowing on-the-fly adjustment of models, notes, and ignore patterns. - Automated Ingestion: Optional support for cloning remote Git repositories directly via configuration for immediate analysis.
- Recursive Mapping: Scans a directory and all subdirectories for specific file extensions.
- Smart Chunking: Automatically splits large files into overlapping chunks on line boundaries to fit model context windows while maintaining continuity.
- Context Retention: Passes summaries of previous findings to subsequent chunks to ensure the model understands the file state as it moves forward.
- Accuracy Levels: Adjustable intensity (1 to 3) that controls chunk size and enables additional validation passes for high-precision results.
- Fallback Logic: Configurable primary and fallback model chains for both Ollama and OpenRouter to ensure execution completes even if a specific model fails.
- Non-Destructive Outputs: Generates analysis reports alongside the original files without modifying the source code. Own output files are always excluded from re-scanning.
- Knowledge Base Injection: Place
.mdor.txtfiles underkb/<name>/and reference them in config to inject domain knowledge (OWASP, past audits, etc.) into the system prompt. - Flexible Output: Control output format, verbosity, scope, and aggregation per run via the
outputconfig block.
- Vision LLM Tagging: Each image is tagged by a vision model (Ollama or OpenRouter) using a configurable prompt.
- Progressive Clustering: Tags accumulate across all images; once a threshold is reached, the top-N tags become cluster labels and all images are sorted automatically.
- Move or Copy: Configurable — move files (default) or copy, preserving originals.
- Recursive + Multi-directory: Scans subdirectories recursively. Accepts multiple comma-separated input paths.
- Resume-safe: State persisted in
image_state.json— interrupt and restart without re-tagging already processed images. - Prompt-driven: Tag prompt lives in
prompts/image_tag.txt— edit without touching Python.
- Per-file Forensic Reports: Instead of clustering, produces one structured
.mddocument per image or video file. - MP4 / Video Support: For each video file (
.mp4,.mov,.avi), extracts N evenly-spaced frames (default5, configurable asvideo_frames) and analyzes each frame individually via the vision LLM. - Timestamped Frame Labels: Each frame report is labeled with its timestamp in seconds (e.g.
Frame 2 [12.4s]) and merged into a single document per video. - Audio Transcription: Set
audio_extensionsin config to enable.mp3/.wav/.m4aprocessing. Transcribes via Whisper (local) or OpenRouter STT and writes one transcript.mdper file. Disabled by default — zero impact if not configured. - Resume-safe: State tracked in
image_state.jsonunder ananalyzedkey — already-processed files are skipped on restart. - Separate Prompt Files: Uses
prompts/image_analysis.txtfor still images andprompts/video_frame_analysis.txtfor video frames (both editable without touching Python).
- Customizable Prompts: All prompts live in
prompts/as plain text files. - Multi-Provider Support: Switch between Ollama (local) and OpenRouter (cloud) via the
providerfield.
pip install ollamaYou must have Ollama installed and running locally.
pip install requests# Code audit
python3 root_claw.py scan <directory> <config.json>
python3 root_claw.py <directory> <config.json> # legacy, same as scan
# Image tagging and clustering
python3 root_claw.py images <directory> <config_images.json>
python3 root_claw.py images <directory> <config_images.json> <output_dir>
python3 root_claw.py images <dir1,dir2,dir3> <config_images.json> <output_dir>
# Execution simulation
python3 root_claw.py simulate <file> <config.json> <function_name> <goal>examples/ is a sample directory structure for testing the scan mode:
examples/
Test.java
Tests/
ReTest.java
safe.sol
big.sol
subscript/
script3.php
subsubscript/
script4.js
{
"extensions": [".java", ".py", ".sol"],
"ignore": ["Avoid.java", "avoid.sol"],
"ignore_file": ".gitignore",
"accuracy_intensity": 1,
"provider": "ollama",
"ollama_config": {
"model": "qwen2.5-coder:7b",
"fallback_models": ["phi4:latest"],
"validation_model": "phi4:latest",
"notes": "Project focused on security analysis and business logic consistency."
},
"openrouter_config": {
"model": "openai/gpt-4o",
"fallback_models": ["anthropic/claude-3-5-sonnet"],
"validation_model": "anthropic/claude-3-5-sonnet",
"OPENROUTER_API_KEY": "your_openrouter_api_key",
"notes": "Project focused on security analysis."
},
"output": {
"format": "md",
"mode": "full",
"scope": "all",
"per_file": true
},
"kb": ["webapp", "blockchain"],
"git_repo": "https://github.com/example/project.git"
}Determines which LLM backend to use.
| Value | Behavior |
|---|---|
"ollama" or Ollama URL |
Uses ollama_config |
"openrouter" or OpenRouter URL |
Uses openrouter_config |
| omitted | Uses whichever config block is present (openrouter_config takes priority) |
| Value | Behavior |
|---|---|
1 |
Fast. Large chunks, no validation pass. |
2 |
Balanced. Medium chunks, validation pass on each chunk. |
3 |
High precision. Small chunks, deep system prompt, validation pass. |
| Field | Values | Description |
|---|---|---|
format |
md | json | both |
Output file format |
mode |
full | vuln_only | flow | minimal |
Verbosity/focus of the report |
scope |
all | vuln_only_files |
Skip output for files with no vulnerability findings |
per_file |
true | false |
false aggregates all results into a single output file |
mirror_structure |
false | true |
true replicates the source directory tree under output/ instead of flat layout |
List of subdirectory names under kb/. All .md and .txt files in those directories are concatenated and injected into the system prompt.
kb/
webapp/
owasp_top10.md
blockchain/
past_audit.txt
All prompt templates used during analysis. Edit these to customize behavior without modifying Python code.
Scan mode prompts:
| File | Purpose |
|---|---|
system_default.txt |
System prompt for intensity 1–2 |
system_deep.txt |
System prompt for intensity 3 |
system_validation.txt |
System prompt for validation pass |
system_merge.txt |
System prompt for final merge |
chunk_analysis.txt |
Main analysis prompt per chunk |
chunk_validation.txt |
Validation critique prompt |
chunk_summary.txt |
Rolling context summary prompt |
merge.txt |
Final consolidation prompt |
Image mode prompts:
| File | Purpose |
|---|---|
image_tag.txt |
Tag prompt for image_mode: "tag" — used for every image |
image_analysis.txt |
Analysis prompt for image_mode: "analyze" — used for still images |
video_frame_analysis.txt |
Per-frame prompt for video analysis; supports {frame_index} and {total_frames} placeholders |
Image mode (image_claw) processes images and videos via a vision LLM. It runs separately from the code scan and uses its own config file. Two sub-modes are available, controlled by "image_mode" in the config.
# Install vision-capable model (local)
ollama pull gemma4:e2b
# Tag + cluster mode (default)
python3 root_claw.py images /path/to/photos config_images.json /path/to/output
# Forensic analysis mode (images + video)
python3 root_claw.py images /path/to/media config_images_analyze.json /path/to/outputTags every image and organizes them into cluster folders by dominant tag.
- Every image is tagged (5–8 comma-separated lowercase tags).
- Tags accumulate in a frequency counter across all images.
- When
cluster_thresholdimages have been tagged, the topn_clusterstags become cluster labels. - All previously tagged images are retroactively sorted into the matching cluster folder.
- Every subsequent image is assigned to its dominant cluster on arrival.
Files are moved by default ("image_action": "move"). Set to "copy" to keep originals in place.
{
"image_mode": "tag",
"image_extensions": [".jpg", ".jpeg", ".png", ".webp"],
"n_clusters": 10,
"cluster_threshold": 100,
"image_action": "move",
"output_json": false,
"prompt": "image_tag.txt",
"provider": "ollama",
"ollama_config": {
"model": "gemma4:e2b",
"fallback_models": []
},
"openrouter_config": {
"model": "openai/gpt-4o",
"fallback_models": [],
"OPENROUTER_API_KEY": "your_key"
}
}| Field | Default | Description |
|---|---|---|
image_mode |
"tag" |
Sub-mode: "tag" or "analyze" |
image_extensions |
jpg/jpeg/png/webp | Image file types to process |
n_clusters |
10 |
Number of cluster folders to create |
cluster_threshold |
100 |
Images to tag before clustering begins |
image_action |
"move" |
"move" (destructive) or "copy" (safe) |
output_json |
false |
Write image_results_[ts].json with full tag/cluster report |
prompt |
"image_tag.txt" |
Filename in prompts/ to use for tagging |
provider |
"ollama" |
"ollama" or "openrouter" |
Produces one structured .md report per file. Supports both still images and video files (.mp4, .mov, .avi). No clustering or file moving — output documents are written to the output directory.
- For each video,
Nframes are extracted at evenly-spaced intervals across the full duration (defaultvideo_frames: 5). - Each frame is analyzed individually by the vision LLM using
prompts/video_frame_analysis.txt. - Results are merged into a single
.mdfile:[timestamp]_[videoname]_analysis.md. - Each frame section is labeled with its timestamp in seconds (e.g.
## Frame 2 [12.4s]).
For still images, prompts/image_analysis.txt is used and the full response is written as-is.
{
"image_mode": "analyze",
"image_extensions": [".jpg", ".jpeg", ".png", ".webp"],
"video_extensions": [".mp4", ".mov", ".avi"],
"video_frames": 5,
"image_action": "copy",
"provider": "ollama",
"ollama_config": {
"model": "gemma4:e2b",
"fallback_models": []
},
"openrouter_config": {
"model": "openai/gpt-4o",
"fallback_models": [],
"OPENROUTER_API_KEY": "your_key"
}
}| Field | Default | Description |
|---|---|---|
image_mode |
"tag" |
Must be "analyze" to activate this sub-mode |
video_extensions |
mp4/mov/avi | Video file types to process |
video_frames |
5 |
Number of frames to extract and analyze per video |
image_action |
"move" |
"move" or "copy" — only affects image files in analyze mode |
provider |
"ollama" |
"ollama" or "openrouter" |
output_dir/
image_state.json ← resume state
20260601_120000_photo1_analysis.md ← still image report
20260601_120001_clip1_analysis.md ← video report (all frames merged)
20260601_120002_interview_analysis.md ← audio transcript
Video report structure:
# Video analysis: clip1.mp4
Frames analyzed: 5
## Frame 1 [3.2s]
...
## Frame 2 [12.4s]
...Audio transcript structure:
# Audio transcript: interview.mp3
Hello and welcome to the show...Audio transcription is opt-in: it activates only when audio_extensions is present in the config. No config key = no change in behaviour.
Supported backends:
provider |
Backend | Requirement |
|---|---|---|
"whisper" (default) |
openai-whisper Python library, runs locally |
pip install openai-whisper |
"openrouter" |
OpenRouter audio transcription REST endpoint | API key + model |
{
"image_mode": "analyze",
"audio_extensions": [".mp3", ".wav", ".m4a"],
"audio_config": {
"provider": "whisper",
"whisper_model": "base"
}
}{
"image_mode": "analyze",
"audio_extensions": [".mp3", ".wav", ".m4a"],
"audio_config": {
"provider": "openrouter",
"model": "openai/whisper-large-v3",
"OPENROUTER_API_KEY": "your_key"
}
}| Field | Default | Description |
|---|---|---|
audio_extensions |
(absent = disabled) | File extensions to treat as audio; omit to disable entirely |
audio_config.provider |
"whisper" |
"whisper" (local) or "openrouter" (cloud) |
audio_config.whisper_model |
"base" |
Whisper model size: tiny, base, small, medium, large |
audio_config.model |
"openai/whisper-large-v3" |
OpenRouter model ID (only for provider: "openrouter") |
audio_config.OPENROUTER_API_KEY |
"" |
Required when using OpenRouter |
Note: Audio is silently skipped in
image_mode: "tag". The LLM vision config (ollama_config/openrouter_config) is not used for audio — onlyaudio_configis.
Edit prompts/image_tag.txt to change what the model focuses on — no Python changes needed.
Default prompt focuses on: subjects, scene type, action, mood, setting, visual style.
Examples of domain-specific prompts:
# Fashion
List 5-8 tags: clothing style, garment type, color palette, occasion, body coverage. Comma-separated lowercase only.
# Art / illustration
List 5-8 tags: art style, medium, mood, color palette, subject, composition. Comma-separated lowercase only.
# Product photos
List 5-8 tags: product category, color, background, shot angle, lighting. Comma-separated lowercase only.
output_dir/
image_state.json ← resume state (tagged images + cluster assignments)
image_results_[ts].json ← full report (only if output_json: true)
woman/ ← cluster folder (named after dominant tag)
photo1.jpg
photo3.png
sitting/
photo2.jpg
indoor/
...
image_results_[ts].json structure:
{
"clusters": ["woman", "sitting", "indoor", ...],
"cluster_counts": {"woman": 42, "sitting": 31, ...},
"tag_frequency": {"woman": 98, "sitting": 74, "indoor": 61, ...},
"total_tagged": 110,
"images": [
{
"path": "/abs/path/to/photo.jpg",
"name": "photo.jpg",
"tags": ["woman", "sitting", "jeans"],
"cluster": "woman"
}
]
}
### Multi-directory input
Pass multiple directories as a comma-separated string:
```bash
python3 root_claw.py images /photos/batch1,/photos/batch2,/archive/old config_images.json /sortedAll directories are scanned recursively. Duplicate filenames across directories are handled safely (state key = absolute path).
| Model | Size | Notes |
|---|---|---|
gemma4:e2b |
7 GB | Best instruction following, slow |
gemma3:4b |
3 GB | Good balance, faster |
moondream:latest |
1.7 GB | Fast but limited prompt compliance |
All scan output is written to output/[timestamp]_[dir]/ relative to where the script is launched. The source directory is never modified.
[timestamp]_[filename]_rc.md(or.json): Per-file analysis report.[timestamp]_[dir]_files_rc.json: Manifest of all scanned files and run metadata.[timestamp]_[dir]_analyzed_rc.txt: List of successfully processed files.
With per_file: false, a single [timestamp]_[dir]_aggregate_rc.md (or .json) is written instead. With mirror_structure: true, the output directory replicates the source tree layout.
Root Claw implements a multi-pass approach for higher accuracy levels. At level 2 or 3, a validation model critiques each chunk's analysis before the final merge, reducing hallucinations and logical gaps.
Chunking respects line boundaries — no line is ever split mid-content. A rolling 200-character overlap between chunks preserves context continuity.
The tool always excludes its own output files (*_rc.md, *_rc.json, *_rc.txt) from re-scanning.
The quality of the final analysis is strictly dependent on the capabilities of the selected LLMs. Run a test on a single known-vulnerable file before starting a full audit. Weak or non-coding-optimized models will produce superficial findings and hallucinations.
MIT