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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
- 🔧 **Configurable** — YAML config file with project-level defaults
- 🪝 **Git Hooks** — Pre-commit integration for instant feedback
- 📊 **Exit Codes** — Non-zero exit on critical findings for pipeline gating
- 🧠 **Deterministic Reviews** — Temperature 0 by default: same diff always produces the same issues
- 💾 **Diff-Hash Caching** — Reviews cached by diff hash in `~/.cache/cora/reviews/` — skip repeat reviews with `--no-cache`
- 🎯 **Custom System Prompts** — Override review/scan prompts via config or file path
- 🛡️ **Anti-Hallucination** — File path injection and post-parse filtering keep LLM output grounded
- 🌡️ **Configurable LLM Params** — Tune temperature, max tokens, timeout, and cache TTL per project

## 📦 Installation

Expand Down Expand Up @@ -141,6 +146,9 @@ cora review --severity major

# Quiet mode (machine-readable)
cora review --quiet

# Skip cached reviews
cora review --no-cache
```

### `cora scan`
Expand Down Expand Up @@ -232,13 +240,31 @@ provider:
model: gpt-4o-mini
base_url: https://api.openai.com/v1 # Override for custom/self-hosted endpoints

# LLM parameters
llm:
temperature: 0 # Default: 0 (deterministic — same diff = same issues)
max_tokens: 4096 # Default: 4096
timeout: 120 # Default: 120 (seconds)
cache_ttl: 1440 # Default: 1440 (minutes) — diff-hash cache TTL

# Focus areas for review (empty = all)
focus:
- security
- performance
- bugs
- best_practice

# Review options
review:
system_prompt: "You are a senior Rust code reviewer."
# system_prompt_file: ./review-prompt.md # Load prompt from file
response_format: json_object # Opt-in structured JSON output

# Scan options
# scan:
# system_prompt: "Focus on security vulnerabilities."
# system_prompt_file: ./scan-prompt.md

# Custom rules
rules:
- "no unwrap"
Expand Down Expand Up @@ -278,6 +304,7 @@ output:
| `CORA_CONFIG` | Path to config file | `.cora.yaml` |
| `CORA_FORMAT` | Output format (`pretty`, `json`, `compact`, `sarif`) | `pretty` |
| `CORA_NO_COLOR` | Disable colored output | — |
| `CORA_NO_CACHE` | Skip diff-hash cache (same as `--no-cache`) | — |

### Authentication

Expand Down
30 changes: 30 additions & 0 deletions website/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,36 @@
<p class="mt-2 text-sm text-[var(--accent)]">Your code stays yours</p>
<p class="mt-2 text-sm text-[var(--muted-foreground)] leading-relaxed">Runs entirely on your machine. No cloud, no telemetry, no data leaving your network. Perfect for Gitea and air-gapped environments.</p>
</div>

<!-- Feature 7: Deterministic Reviews -->
<div class="glass-card scroll-reveal [transition-delay:600ms]">
<div class="feature-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>
</div>
<h3 class="mt-4 text-lg font-semibold text-[var(--foreground)]">Deterministic Reviews</h3>
<p class="mt-2 text-sm text-[var(--accent)]">Same diff, same issues</p>
<p class="mt-2 text-sm text-[var(--muted-foreground)] leading-relaxed">Temperature defaults to 0. Identical diffs always produce identical findings — perfect for CI reproducibility.</p>
</div>

<!-- Feature 8: Diff-Hash Caching -->
<div class="glass-card scroll-reveal [transition-delay:700ms]">
<div class="feature-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
</div>
<h3 class="mt-4 text-lg font-semibold text-[var(--foreground)]">Smart Caching</h3>
<p class="mt-2 text-sm text-[var(--accent)]">Never review the same diff twice</p>
<p class="mt-2 text-sm text-[var(--muted-foreground)] leading-relaxed">Reviews are cached by diff hash in <code class="text-[var(--accent)]">~/.cache/cora/reviews/</code>. Re-reviewing an unchanged diff returns cached results instantly. Use <code class="text-[var(--accent)]">--no-cache</code> to bypass.</p>
</div>

<!-- Feature 9: Custom Prompts + Anti-Hallucination -->
<div class="glass-card scroll-reveal [transition-delay:800ms]">
<div class="feature-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 12l2 2 4-4"/></svg>
</div>
<h3 class="mt-4 text-lg font-semibold text-[var(--foreground)]">Custom Prompts &amp; Anti-Hallucination</h3>
<p class="mt-2 text-sm text-[var(--accent)]">Control the review, trust the output</p>
<p class="mt-2 text-sm text-[var(--muted-foreground)] leading-relaxed">Override system prompts for review and scan. File path injection and post-parse filtering ensure the LLM only reports issues that exist in your actual diff.</p>
</div>
</div>
</section>

Expand Down
113 changes: 109 additions & 4 deletions website/src/routes/docs/configuration/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@
<span class="syntax-flag">model:</span> <span class="syntax-string">gpt-4o</span>
<span class="syntax-flag">base_url:</span> <span class="syntax-string">https://api.openai.com/v1</span>

<span class="syntax-highlight">llm:</span>
<span class="syntax-flag">temperature:</span> <span class="text-[var(--foreground)]">0</span>
<span class="syntax-flag">max_tokens:</span> <span class="text-[var(--foreground)]">4096</span>
<span class="syntax-flag">timeout:</span> <span class="text-[var(--foreground)]">120</span>
<span class="syntax-flag">cache_ttl:</span> <span class="text-[var(--foreground)]">1440</span>

<span class="syntax-highlight">review:</span>
<span class="syntax-flag">system_prompt:</span> <span class="syntax-string">"You are a senior code reviewer."</span>
<span class="syntax-comment"># system_prompt_file: ./review-prompt.md</span>
<span class="syntax-flag">response_format:</span> <span class="syntax-string">json_object</span>

<span class="syntax-highlight">focus:</span> <span class="syntax-string">security, performance, bugs</span>

<span class="syntax-highlight">hook:</span>
Expand Down Expand Up @@ -128,10 +139,14 @@
<td><code class="syntax-highlight">CORA_FORMAT</code></td>
<td>Output format (pretty, json, compact, sarif)</td>
</tr>
<tr>
<td><code class="syntax-highlight">CORA_NO_COLOR</code></td>
<td>Disable colored output</td>
</tr>
<tr>
<td><code class="syntax-highlight">CORA_NO_COLOR</code></td>
<td>Disable colored output</td>
</tr>
<tr>
<td><code class="syntax-highlight">CORA_NO_CACHE</code></td>
<td>Skip diff-hash review cache (same as <code class="syntax-highlight">--no-cache</code>)</td>
</tr>
<tr>
<td><code class="syntax-highlight">GITHUB_TOKEN</code></td>
<td>GitHub token for SARIF upload</td>
Expand Down Expand Up @@ -184,4 +199,94 @@
</div>
</div>
</section>

<!-- Caching Behavior -->
<section class="docs-section scroll-reveal">
<h2 class="flex items-center gap-2">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
Diff-Hash Caching
</h2>
<p class="text-[var(--muted-foreground)] mb-4">cora caches review results by diff hash in <code class="syntax-highlight">~/.cache/cora/reviews/</code>. If you re-review the same diff, the cached result is returned instantly.</p>
<div class="glass-card p-4 mb-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<div class="text-xs font-semibold text-[var(--foreground)] mb-1">Config</div>
<div class="text-sm text-[var(--muted-foreground)]">
<code class="syntax-highlight">llm.cache_ttl</code> — TTL in minutes (default: 1440 / 24h)
</div>
</div>
<div>
<div class="text-xs font-semibold text-[var(--foreground)] mb-1">CLI / Env</div>
<div class="text-sm text-[var(--muted-foreground)]">
<code class="syntax-highlight">--no-cache</code> or <code class="syntax-highlight">CORA_NO_CACHE=1</code> to bypass
</div>
</div>
</div>
</div>
</section>

<!-- Custom System Prompts -->
<section class="docs-section scroll-reveal">
<h2 class="flex items-center gap-2">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 013 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
Custom System Prompts
</h2>
<p class="text-[var(--muted-foreground)] mb-4">Override the default system prompt for <code class="syntax-highlight">review</code> or <code class="syntax-highlight">scan</code> commands to match your project's coding standards and review criteria.</p>
<div class="docs-terminal">
<div class="terminal-bar">
<span class="terminal-dot terminal-dot-red"></span>
<span class="terminal-dot terminal-dot-yellow"></span>
<span class="terminal-dot terminal-dot-green"></span>
<span class="terminal-title">.cora.yaml</span>
</div>
<div class="terminal-body">
<pre class="whitespace-pre"><span class="syntax-highlight">review:</span>
<span class="syntax-flag">system_prompt:</span> <span class="syntax-string">"Focus on Rust idioms and error handling."</span>
<span class="syntax-comment"># Or load from a file:</span>
<span class="syntax-flag">system_prompt_file:</span> <span class="syntax-string">./prompts/review.md</span>

<span class="syntax-highlight">scan:</span>
<span class="syntax-flag">system_prompt:</span> <span class="syntax-string">"Check for OWASP Top 10 vulnerabilities."</span>
<span class="syntax-flag">system_prompt_file:</span> <span class="syntax-string">./prompts/scan.md</span></pre>
</div>
</div>
<p class="text-[var(--muted-foreground)] mt-3 text-sm">If both <code class="syntax-highlight">system_prompt</code> and <code class="syntax-highlight">system_prompt_file</code> are set, the file takes precedence.</p>
</section>

<!-- Response Format -->
<section class="docs-section scroll-reveal">
<h2 class="flex items-center gap-2">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
Response Format (JSON Mode)
</h2>
<p class="text-[var(--muted-foreground)] mb-4">Opt into structured JSON output from the LLM by setting <code class="syntax-highlight">review.response_format</code> to <code class="syntax-highlight">json_object</code>. This instructs the LLM to return valid JSON, enabling machine-readable parsing and pipeline integration.</p>
<div class="docs-terminal">
<div class="terminal-bar">
<span class="terminal-dot terminal-dot-red"></span>
<span class="terminal-dot terminal-dot-yellow"></span>
<span class="terminal-dot terminal-dot-green"></span>
<span class="terminal-title">.cora.yaml</span>
</div>
<div class="terminal-body">
<pre class="whitespace-pre"><span class="syntax-highlight">review:</span>
<span class="syntax-flag">response_format:</span> <span class="syntax-string">json_object</span></pre>
</div>
</div>
<p class="text-[var(--muted-foreground)] mt-3 text-sm">Requires provider support for structured output. Works with OpenAI, Anthropic, and compatible APIs.</p>
</section>

<!-- Anti-Hallucination -->
<section class="docs-section scroll-reveal">
<h2 class="flex items-center gap-2">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
Anti-Hallucination
</h2>
<p class="text-[var(--muted-foreground)] mb-4">cora uses two mechanisms to prevent the LLM from fabricating findings:</p>
<div class="glass-card p-4">
<ul class="text-sm text-[var(--muted-foreground)] space-y-2 list-none pl-0">
<li><span class="text-[var(--accent)] font-semibold">File path injection</span> — Actual file paths are embedded in the prompt, anchoring the LLM to real files in the diff.</li>
<li><span class="text-[var(--accent)] font-semibold">Post-parse filtering</span> — After parsing, any reported file paths or line numbers that don't exist in the actual diff are discarded.</li>
</ul>
</div>
</section>
</div>
Loading