β²
/ \
/ \
/ \
/ \
/_________\
/ \
/ \
/ \
_____/_________________\_____
Codebase Intelligence Engine
Heuristic security scanning, AI-generated code detection, and quality analysis β all from the terminal.
- What is Fuji?
- Features at a Glance
- Installation
- Usage
- Analysis Pipeline
- Analysis Modes
- Supported Languages
- Architecture
- Output Formats
- TUI Interface
- Configuration & Thresholds
- How It Works (Technical Deep Dive)
Fuji is a zero-dependency, static codebase intelligence tool written in Go. It analyzes source code repositories to surface three categories of findings:
- Security vulnerabilities β hardcoded secrets, injection risks, crypto misuse, authentication bypasses, and information disclosure.
- AI-generated code patterns β detects fingerprints of LLM-generated code using 12 weighted heuristic signals.
- Code quality issues β cyclomatic complexity, dead code, duplication, deep nesting, magic numbers, naming inconsistencies, and more.
Fuji operates entirely offline with no API calls, no cloud dependencies, and no external services. Everything runs locally through pattern matching, heuristic scoring, and static analysis.
It provides three interfaces:
- An interactive TUI (Terminal User Interface) built with Bubble Tea and Lipgloss.
- A CLI mode that outputs structured JSON or Markdown reports.
- A CI mode with semantic exit codes for pipeline integration.
| Feature | Details |
|---|---|
| Security Scanner | 25+ rules covering secrets, injections, crypto misuse, auth issues |
| AI Code Detector | 12-signal weighted scoring system (0β100%) |
| Quality Analyzer | 12 quality checks with configurable thresholds |
| Language Support | 20+ languages (Go, Python, Rust, JS, TS, Java, C, C++, Ruby, PHP, and more) |
| Git Integration | Commit churn, author tracking, last-modified dates via go-git |
| Concurrent Analysis | Semaphore-bounded goroutines (8 concurrent workers) |
| Output Formats | Interactive TUI, JSON, Markdown, CI summary |
| Shannon Entropy | Entropy-gated secret detection to reduce false positives |
| Issue Severity | 4 levels: Info, Warning, Error, Critical |
| Issue Categories | Security, Quality, AI Pattern, Performance |
| Clipboard Support | Copy results via atotto/clipboard + OSC52 terminal escape |
| File Picker | Native zenity file picker integration (Linux) |
| Zero Config | No configuration files needed β sensible defaults baked in |
git clone https://github.com/lichi/fuji.git
cd fuji
go build -o fuji .go run .sudo mv fuji /usr/local/bin/Fuji has the following Go module dependencies:
| Dependency | Purpose |
|---|---|
charmbracelet/bubbletea |
Terminal UI framework (Elm-architecture) |
charmbracelet/lipgloss |
Terminal styling and layout |
alecthomas/chroma/v2 |
Syntax highlighting engine |
go-git/go-git/v5 |
Pure Go Git implementation for history analysis |
atotto/clipboard |
System clipboard access |
aymanbagabas/go-osc52/v2 |
OSC52 terminal clipboard escape sequences |
# Launch the home screen
fuji
# Go directly to the analysis menu for a specific folder
fuji /path/to/project
# Analyze current directory
fuji .When launched without arguments, Fuji presents an interactive home screen where you can:
- Open a folder (type a path or use the
Ctrl+Bnative file picker) - View Help (full keyboard shortcut reference)
- View History (placeholder β coming soon)
After selecting a folder, you choose an analysis mode:
1β Security & Vulnerability Scan2β AI Code Detection3β Code Quality Analysis
Results are displayed in a scrollable view with severity badges, code context, and progress bars. Press Enter to copy results as Markdown to the clipboard.
# JSON output
fuji --format json /path/to/project
# Markdown report
fuji --format md /path/to/project
fuji --format markdown .JSON output includes:
- Summary statistics (files analyzed, files flagged, average complexity, total issues)
- Per-file details (path, AI probability, complexity, issues with line numbers and types)
- Only files with issues or AI probability β₯30% are included
Markdown output includes:
- Summary table with all metrics
- Issues grouped by severity (π΄ Critical, π Error, π‘ Warning, π΅ Info)
- AI-suspected files table with visual probability bars
- Generated-by footer
fuji --ci /path/to/projectCI mode outputs a plain-text summary and uses semantic exit codes:
| Exit Code | Meaning |
|---|---|
0 |
β PASS β No issues found |
1 |
|
2 |
β FAIL β Security issues detected |
Example CI output:
π» fuji β CI Report
βββββββββββββββββββ
Files analyzed: 14
Files flagged: 3
Total issues: 12
Security issues: 2
AI-suspected: 1
Avg complexity: 4.3
β FAIL β Security issues detected
fuji --version # or -v β prints "fuji v0.1.0"
fuji --help # or -h β prints usage and keyboard shortcutsFuji runs a 4-phase analysis pipeline, coordinated by the Analyzer struct in internal/analyzer/analyzer.go.
File: internal/analyzer/walker.go
The WalkDirectory function recursively walks the target directory and builds a file tree:
- Supported extensions are mapped to language names (20+ extensions β 20+ languages).
- Ignored directories are automatically skipped:
.git,node_modules,vendor,__pycache__,.venv,venv,dist,build,.idea,.vscode,target,bin,obj. - Hidden files/directories (starting with
.) are skipped. - Files are organized into a tree structure (
FileResultwithChildrenandParentpointers). - Children are sorted alphabetically with directories first.
- First-level directories are auto-expanded in the TUI.
- Line counts are computed during the walk for each supported file.
File: internal/analyzer/git.go
The AnalyzeGit function uses go-git to analyze the repository:
- Opens the repository at the root directory using
git.PlainOpen(). - Iterates through commit history starting from
HEAD(up to 500 commits for performance). - For each commit, extracts
Stats()(file-level diffs) to determine:- File churn β number of commits touching each file.
- Authors β unique list of contributors per file.
- Last modified date β most recent commit timestamp per file.
- Results are stored in a
GitAnalysisstruct with three maps keyed by relative file path. - If the directory is not a Git repository, returns empty data gracefully (no error).
After the main analysis, ApplyGitInfo maps the git data back onto FileResult objects using filepath.Rel to match paths.
The HighChurnFiles utility returns the top N files sorted by commit count (useful for identifying hotspots).
File: internal/analyzer/analyzer.go
Each file with a recognized language is analyzed concurrently:
- A semaphore limits concurrency to 8 goroutines at a time.
- Progress updates are sent through a buffered channel (
cap=100) for TUI display. - For each file, four analysis passes run sequentially:
- Complexity analysis (
AnalyzeComplexity) - AI detection (
AnalyzeAI) - Security scanning (
AnalyzeSecurity) - Quality checks (
AnalyzeQuality)
- Complexity analysis (
- File content is read once and passed to all analyzers.
- Comment ratio is computed separately via
CommentRatio.
After all files are analyzed:
-
Summary statistics are computed:
- Total files analyzed
- Files flagged (files with any issues)
- Average cyclomatic complexity
- Total issue count
- AI-suspected file count (AI score > 60%)
- Security issue count
-
Issue propagation β issues from child files are propagated up to parent directories in the tree structure (for TUI navigation).
File: internal/analyzer/security.go (386 lines, 19KB)
The security analyzer scans every line of code against four categories of rules, with context-aware filtering to reduce false positives.
Detects hardcoded secrets, credentials, and API keys:
| Secret Type | Pattern Example | Severity |
|---|---|---|
| AWS Access Key | AKIA[0-9A-Z]{16} |
π΄ Critical |
| AWS Secret Key | aws_secret_access_key = "..." |
π΄ Critical |
| GCP API Key | AIza[0-9A-Za-z\-_]{35} |
π΄ Critical |
| Azure Credential | azure_key = "..." |
π΄ Critical |
| Generic API Key | api_key = "..." |
π Error |
| Generic Secret/Password | password = "...", token = "..." |
π΄ Critical |
| Bearer Token | Bearer eyJ... |
π΄ Critical |
| Basic Auth | Basic dXNlcj... |
π Error |
| Private Key (RSA/EC/DSA/OpenSSH) | -----BEGIN PRIVATE KEY----- |
π΄ Critical |
| PGP Private Key | -----BEGIN PGP PRIVATE KEY BLOCK----- |
π΄ Critical |
| Database URL | postgres://user:pass@host/db |
π΄ Critical |
| JWT Token | eyJ... (3-part base64url) |
π Error |
| JWT Secret | jwt_secret = "..." |
π΄ Critical |
| Slack Webhook/Token | hooks.slack.com/services/... |
π Error / π΄ Critical |
| GitHub Token | ghp_..., gho_... |
π΄ Critical |
| GitLab Token | glpat-... |
π΄ Critical |
| Stripe Key | sk_live_..., sk_test_... |
π΄ Critical |
| SendGrid / Twilio Key | SG.xxx, SK[a-f0-9]{32} |
π΄ Critical / π Error |
Entropy gating: Generic patterns (API keys, secrets, passwords) use Shannon entropy to filter out low-entropy placeholders like "changeme" or "example". Only values with entropy β₯ 3.5 bits are flagged.
Test file downgrade: Secrets found in test files (_test.go, test_*.py, etc.) are automatically downgraded to Info severity.
| Injection Type | Examples | Severity |
|---|---|---|
| SQL Injection | fmt.Sprintf("SELECT ... %s"), string concat in queries, .raw(f"...") |
π΄ Critical / π Error |
| Command Injection | exec.Command(...+var), os.system(f"..."), subprocess(shell=True) |
π΄ Critical / π Error |
| XSS | innerHTML = ... +, dangerouslySetInnerHTML, template.HTML() |
π‘ Warning / π Error |
| Path Traversal | os.Open(... + userInput), ../ sequences, sendFile(... + var) |
π‘ Warning / π Error |
| SSRF | http.Get(... + var), requests.get(f"..."), net.Dial(... + var) |
π Error |
| Deserialization | pickle.loads(), yaml.load(), ObjectInputStream |
π΄ Critical |
| Issue | Detection | Severity |
|---|---|---|
| MD5 usage | md5.New(), crypto/md5, hashlib.md5() |
π Error |
| SHA-1 usage | sha1.New() |
π‘ Warning |
| DES/3DES | crypto/des, DES.new |
π Error |
| RC4 | rc4.NewCipher |
π Error |
| Blowfish | Blowfish...Encrypt |
π‘ Warning |
| ECB mode | NewECBEncrypter, MODE_ECB |
π΄ Critical |
| Hardcoded IV/nonce/salt | iv = []byte{...} |
π Error |
| Insecure random | "math/rand", random.randint() |
π‘ Warning |
| Weak RSA key | rsa.GenerateKey(..., 1024) |
π Error |
| Issue | Detection | Severity |
|---|---|---|
| Hardcoded admin check | isAdmin = true |
π‘ Warning |
| Security TODO | // TODO: fix auth |
π‘ Warning |
| CORS wildcard | cors(...AllowAll...) |
π Error |
| Sensitive data logged | fmt.Printf(password) |
π Error |
| Debug mode enabled | DEBUG = True |
π‘ Warning |
| Stack trace exposure | printStackTrace, traceback |
π‘ Warning |
| Sensitive file reference | .env, .pem, .key usage |
π΅ Info |
The security scanner applies smart filtering:
- Comment lines are skipped (detected via
//,#,/*,*,--,;prefixes). - Pattern definitions are skipped β lines containing words like
Description,Usage,MustCompile,regexp,compile,message,placeholder. - Test files are detected via patterns like
_test.go,test_*.py,.test.,.spec.,__tests__/.
File: internal/analyzer/ai.go (825 lines, 23KB)
The AI detector computes a probability score (0β100%) that a file was generated by an LLM, using a weighted combination of 12 independent signals:
| # | Signal | Weight | What It Measures |
|---|---|---|---|
| 1 | Token Diversity | 5% | Ratio of unique identifiers to total β low diversity β AI-like |
| 2 | Formatting Consistency | 5% | Indentation alignment + line length variance β high consistency β AI-like |
| 3 | Generic Naming | 8% | Usage of generic names like data, result, handler, temp β 26 built-in generic names |
| 4 | Comment Quality | 10% | Comment-to-code ratio β ratio > 50% is strongly AI-like |
| 5 | Function Uniformity | 5% | Variance of function sizes β low variance (< 10) β AI-like |
| 6 | Marker Phrases | 20% | LLM fingerprint phrases in comments (10 patterns) |
| 7 | Error Handling Boilerplate | 5% | Duplicate error handling blocks (language-specific patterns) |
| 8 | Naming Entropy | 5% | Naming convention consistency (camelCase vs snake_case) |
| 9 | Structural Fingerprint | 10% | Section headers, comment-before-code alternation patterns |
| 10 | Line Length Distribution | 5% | Gaussian distribution of line lengths β low skewness β AI-like |
| 11 | Readme-Style Comments | 12% | Comments that explain the obvious (9 patterns) |
| 12 | Repetitive Structure | 10% | Same API call pattern repeated 5+ times |
Total signal weights: 100%
These detect LLM fingerprint phrases in comment text (language-agnostic β the comment marker is stripped first):
"This function/method/class handles/implements..."β characteristic of LLM output"Here we implement/create..."β tutorial prose style"The following code/function..."β explanatory AI style"Note that..." / "Please note..."β overly formal tone"We use/need/want this to..."β tutorial-style narration"For simplicity/clarity/readability..."β AI hedging pattern"First we... Then we..."β sequential narration"Make sure to..." / "Ensure that..."β instructional advisory tone"This is a helper/utility/wrapper..."β self-describing comment"Returns a... and/or..."β verbose parameter documentation
Comments that explain what the code already says:
"Import the necessary packages/modules""Define a new variable/constant/struct""Check if the input/value is valid""Return the result/response/error""Loop through/over the items""Handle the error/exception""Open/Close/Read/Write the file/connection"- Numbered section headers (
"1. Something") - Named utility comments (
"Quick function to...","Helper to...")
Language-specific patterns for repetitive code:
| Language | Patterns Detected |
|---|---|
| Lua | vim.keymap.set(), vim.api.nvim_create_autocmd(), vim.cmd() |
| JavaScript | addEventListener(), document.querySelector() |
| Python | self.xxx = ... |
| Generic (all) | Any structural line pattern repeated 5+ times (strings normalized) |
- > 60% AI probability β file is counted as "AI-suspected" in the summary
- > 50% β file appears in the AI-suspected list in reports
- Files with fewer than 5 lines are not analyzed (returns 0%)
File: internal/analyzer/quality.go (637 lines, 20KB)
The quality analyzer performs 12 distinct checks:
File: internal/analyzer/complexity.go
Measures per-function cyclomatic complexity by counting branching constructs:
| Language | Keywords Counted |
|---|---|
| Go | if, else if, for, switch, case, select, go, defer |
| Python | if, elif, for, while, except, with |
| Rust | if, else if, for, while, match, loop |
| JavaScript / TypeScript | if, else if, for, while, switch, case, catch |
| Java | if, else if, for, while, switch, case, catch |
| Ruby | if, elsif, unless, while, until, for, rescue |
| PHP | if, elseif, for, foreach, while, switch, case, catch |
| Kotlin | if, else if, for, while, when, catch |
| Swift | if, else if, for, while, switch, case, catch |
| Shell | if, elif, for, while, case |
| Lua | if, elseif, for, while, repeat |
| Dart | if, else if, for, while, switch, case, catch |
Additionally, logical operators && and || are counted per occurrence.
Function detection uses language-specific regex patterns to identify function declarations and track their start/end lines.
Thresholds:
| Threshold | Level |
|---|---|
| Complexity β₯ 10 | π‘ Warning (moderate_complexity) |
| Complexity β₯ 20 | π Error (high_complexity) |
| Threshold | Level |
|---|---|
| > 50 lines | π‘ Warning (long_function) |
| > 100 lines AND complexity > 15 | π Error (god_function) |
| Threshold | Level |
|---|---|
| > 500 lines | π΅ Info (long_file) |
| Threshold | Level |
|---|---|
| Indentation > 4 levels (16+ spaces / 4+ tabs) | π‘ Warning (deep_nesting) |
| Threshold | Level |
|---|---|
| > 5 parameters per function | π‘ Warning (long_param_list) |
Detects unreachable code after return, break, continue, panic(), os.Exit(), sys.exit(), process.exit(), and throw. Smart enough to:
- Skip closing braces after return statements
- Skip
case/defaultlabels in switch statements - Detect and ignore returns inside closures/anonymous functions
Detects:
- Empty
catchblocks (JS/Java/C++) - Empty
exceptblocks (Python β justpass) - Empty
if err != nil {}blocks (Go)
Severity: π Error
Detects _ = someFunc() patterns where return values are discarded.
Exceptions: fmt.Fprintf, io.Copy, copy(), and range iterations are excluded.
Severity: π‘ Warning
Detects numeric literals with 3+ digits that aren't defined as constants.
Exceptions:
- HTTP status codes: 100, 200, 201, 204, 301, 302, 400, 401, 403, 404, 500
- Powers of 2: 1024, 2048, 4096, 8192
- Constants/variable definitions
- Comments and imports
- Hex color codes
- Numbers inside template literals
Severity: π΅ Info
Detects mixed naming conventions (camelCase vs snake_case) within a single file. Only flags when the minority convention exceeds 20% of identifiers.
Skipped for: Go (camelCase + PascalCase is idiomatic), C, C++.
Severity: π΅ Info
Detects imported packages whose short names don't appear in the code body (via name. pattern matching). Handles both single-line and block imports, as well as aliased imports.
Exceptions: _ (blank) and . (dot) imports.
Severity: π‘ Warning
Detects TODO:, FIXME:, HACK:, XXX:, and BUG: markers in code.
Severity: π΅ Info
Uses SHA-256 hashing of 6-line sliding windows to detect copy-pasted code blocks. Only non-empty blocks are hashed, and each duplicate pair is reported once.
Severity: π΅ Info
Fuji supports analysis of the following file types:
| Extension | Language |
|---|---|
.go |
Go |
.py |
Python |
.rs |
Rust |
.js, .jsx |
JavaScript |
.ts, .tsx |
TypeScript |
.rb |
Ruby |
.java |
Java |
.c, .h |
C |
.cpp, .hpp |
C++ |
.cs |
C# |
.php |
PHP |
.sh |
Shell |
.lua |
Lua |
.dart |
Dart |
.kt |
Kotlin |
.swift |
Swift |
.scala |
Scala |
.yaml, .yml |
YAML |
.json |
JSON |
.md |
Markdown |
.sql |
SQL |
fuji/
βββ main.go # Entry point, CLI flag parsing, mode routing
βββ go.mod # Go module definition (github.com/lichi/fuji)
βββ go.sum # Dependency checksums
βββ cmd/ # (reserved for future subcommands)
βββ internal/
βββ analyzer/
β βββ analyzer.go # Orchestrator β 4-phase pipeline, summary builder
β βββ walker.go # Directory tree walker, language detection
β βββ complexity.go # Cyclomatic complexity per function, per language
β βββ security.go # 45+ security rules: secrets, injections, crypto, auth
β βββ ai.go # 12-signal AI detection engine
β βββ quality.go # 12 quality checks: duplication, dead code, naming...
β βββ git.go # Git history analysis via go-git
βββ models/
β βββ models.go # All data structures: Issue, FileResult, Summary, etc.
βββ output/
β βββ json.go # JSON output formatter
β βββ markdown.go # Markdown report generator with tables and bars
βββ tui/
βββ app.go # Bubble Tea model: state, Init, Update, View
βββ screens.go # Screen renderers: Home, Help, PathInput, Menu, Loading
βββ results.go # Results view: Security, AI, Quality result builders
βββ theme.go # Color palette (Noir Fuji), severity badges, progress bars
The core analysis engine. Each analyzer file exposes pure functions that accept file content (as a string) plus language name and return []models.Issue or score values.
analyzer.goβAnalyzerstruct withRun()method. Creates the pipeline: Walk β Git β analyzeFiles (concurrent) β buildSummary β propagateIssues. Uses achan models.ProgressUpdatefor real-time TUI updates.walker.goβWalkDirectory()builds a*FileResulttree. Maps 22 file extensions to language names. Ignores 12 common non-source directories. Sorts children (dirs first, then alphabetical).complexity.goβAnalyzeComplexity()returns total complexity and[]FunctionInfo. Tracks function boundaries using language-specific regex patterns and brace/indent depth.security.goβAnalyzeSecurity()/AnalyzeSecurityWithPath(). Four rule sets:secretRules(18),injectionRules(10),cryptoRules(10),authRules(7). IncludesshannonEntropy()for entropy gating.ai.goβAnalyzeAI()returns a (score, issues) pair. 12 weighted signals combined into a 0β100% probability. Each signal is a pure function with its own scoring logic.quality.goβAnalyzeQuality()returns[]Issue. 12 independent checks with configurable threshold constants.git.goβAnalyzeGit()returns*GitAnalysis.ApplyGitInfo()maps git data β file results.HighChurnFiles()returns top-N most-changed files.
All shared data types:
Severityβ enum: Info (0), Warning (1), Error (2), Critical (3). HasString()andLabel()methods.Categoryβ enum: Security (0), Quality (1), AIPattern (2), Performance (3). HasString()method.Issueβ finding with Line, Column, Type, Severity, Category, Message, Fix. JSON-serializable.FunctionInfoβ per-function data: Name, StartLine, EndLine, Complexity, LineCount.GitInfoβ per-file git data: CommitCount, LastAuthor, LastModified, Authors.FileResultβ complete per-file result: Path, Language, LineCount, AIScore, Complexity, Functions, Issues, GitInfo, CommentRatio. Also contains tree navigation fields (IsDirectory, Children, Parent, Expanded, Depth).AnalysisSummaryβ aggregate stats: FilesAnalyzed, FilesFlagged, AvgComplexity, TotalIssues, AISuspected, SecurityIssues.AnalysisResultβ top-level container: Summary, Files, RootDir.ProgressUpdateβ real-time progress: Phase, Progress (0.0β1.0), Message.FileTreeNodeβ flattened tree node for TUI rendering.
json.goβWriteJSON()outputs to stdout. Filters clean files (no issues, AI < 30%). Uses customJSONOutput/JSONFile/JSONIssuestructs for a clean API.markdown.goβWriteMarkdown()/WriteMarkdownToString()/WriteMarkdownToWriter(). Generates a formatted Markdown report with tables, severity grouping, AI probability bars, and a footer. Issues are grouped into Critical β Error β Warning β Info sections.
The interactive terminal interface built on the Bubble Tea architecture:
app.goβAppstruct (the Bubble Tea model). 6 screens: Home, Help, PathInput, AnalysisMenu, Results, Loading. Handles keyboard and mouse events. IncludesopenFilePicker()(zenity integration),runAnalysis()(background goroutine), and clipboard copy (atotto + OSC52).screens.goβ Render functions for Home (ASCII art mountain + "FUJI" block title + buttons), Help (command index with key bindings), PathInput (text input with cursor + browse button), Menu (3 analysis options with descriptions), Loading (progress bar + message).results.goβ 661 lines. Three result builders:buildSecurityResults()(per-file issue cards with code context),buildAIResults()(AI score cards with progress bars and explanations),buildQualityResults()(quality score, metrics table, issue breakdown chart, per-file details). UsesgetCodeLine()to show actual source code at issue locations.theme.goβ "Noir Fuji" color palette with 15 colors.SeverityBadge()renders[CRIT],[ERR ],[WARN],[INFO]with color coding.ProgressBar()renders block-character bars.
AnalysisResult
βββ Summary (AnalysisSummary)
β βββ FilesAnalyzed: int
β βββ FilesFlagged: int
β βββ AvgComplexity: float64
β βββ TotalIssues: int
β βββ AISuspected: int
β βββ SecurityIssues: int
βββ Files: []*FileResult
β βββ Path, Language, LineCount
β βββ AIScore (0-100)
β βββ Complexity (cyclomatic)
β βββ CommentRatio
β βββ Functions: []FunctionInfo
β β βββ Name, StartLine, EndLine
β β βββ Complexity, LineCount
β βββ Issues: []Issue
β β βββ Line, Column
β β βββ Type, Severity, Category
β β βββ Message, Fix
β βββ GitInfo
β β βββ CommitCount, LastAuthor
β β βββ LastModified, Authors
β βββ Tree fields (IsDirectory, Children, Parent, Expanded, Depth)
βββ RootDir: string
{
"summary": {
"files_analyzed": 14,
"files_flagged": 3,
"avg_complexity": 4.3,
"total_issues": 12
},
"files": [
{
"path": "/path/to/file.go",
"ai_probability": 0.42,
"complexity": 8,
"issues": [
{
"line": 15,
"type": "hardcoded_secret",
"severity": "critical"
}
]
}
]
}Generates a structured report with:
- Summary table
- Issues grouped by severity (π΄π π‘π΅)
- AI-suspected files with visual progress bars (
ββββββββββ) - Generated-by footer with link
Plain-text report with emoji indicators and semantic exit codes.
| Screen | Description |
|---|---|
| Home | ASCII mountain art, "FUJI" block title, three buttons (Open, Help, History) |
| Path Input | Text input with cursor, Ctrl+B for native file picker (zenity), Enter to confirm |
| Analysis Menu | Three analysis modes with descriptions, keyboard/mouse selection |
| Loading | Animated progress bar with "INTELLIGENCE DATA ANALYSIS IN PROGRESS" message |
| Results | Scrollable results view with severity badges, code context lines, and progress bars |
| Help | Full keyboard shortcut reference organized by screen context |
| Key | Action |
|---|---|
o / 1 / Enter |
Open folder for analysis |
h / 2 |
Show help screen |
i / 3 |
View scan history |
j / k / β / β |
Navigate buttons |
Tab / Shift+Tab |
Navigate buttons |
q / Esc |
Quit |
| Key | Action |
|---|---|
Enter |
Confirm path (empty = current directory) |
Esc |
Cancel, go back to Home |
Backspace |
Delete last character |
Ctrl+U |
Clear entire input |
Ctrl+B |
Open native file picker (zenity) |
| Key | Action |
|---|---|
1 |
Run Security & Vulnerability scan |
2 |
Run AI Usage detection |
3 |
Run Code Quality analysis |
Enter |
Run focused analysis mode |
j / k / β / β |
Navigate options |
b / Esc |
Back to Home |
q |
Quit |
| Key | Action |
|---|---|
j / k / β / β |
Scroll up/down (1 line) |
d / u |
Page down/up (10 lines) |
g / G |
Jump to top/bottom |
| Mouse wheel | Scroll up/down (3 lines) |
Enter |
Copy results as Markdown to clipboard |
b / Esc |
Back to Analysis Menu |
q |
Quit |
| Key | Action |
|---|---|
Ctrl+C |
Force quit |
| Mouse click | Click any button |
Fuji uses the "Noir Fuji" color palette β a dark, technical theme inspired by OpenCode:
| Color | Hex | Usage |
|---|---|---|
| Background | #050505 |
Deep technical black |
| Surface | #121212 |
Card/panel background |
| Surface Hover | #1c1c1c |
Hover state |
| Border | #333333 |
Borders and dividers |
| Text Primary | #e0e0e0 |
Main text |
| Text Secondary | #707070 |
Muted descriptions |
| Text Dim | #404040 |
Hints, footers, disabled |
| Accent (Blue) | #00aaff |
Primary accent, buttons |
| Cyan | #00ffdd |
High-contrast highlights |
| Blue | #58a6ff |
Info badges |
| Warning (Amber) | #ffaa00 |
Warning badges |
| Error (Red) | #ff4444 |
Error/Critical badges |
| Success (Green) | #00ff77 |
Pass indicators |
| White | #ffffff |
Active/focused elements |
| Title | #ffffff |
Screen titles |
| Tagline | #808080 |
Subtitle text |
All thresholds are defined as constants in internal/analyzer/quality.go:
| Constant | Value | Description |
|---|---|---|
maxFunctionLength |
50 lines | Warning for long functions |
maxFileLength |
500 lines | Info for long files |
complexityWarning |
10 | Cyclomatic complexity warning threshold |
complexityCritical |
20 | Cyclomatic complexity error threshold |
dupMinLines |
6 | Minimum block size for duplication detection |
maxNestingDepth |
4 | Maximum recommended nesting levels |
maxParamCount |
5 | Maximum recommended parameters per function |
godFuncLines |
100 | "God function" line count threshold |
godFuncComplexity |
15 | "God function" complexity threshold |
AI detection threshold:
| Constant | Value | Location |
|---|---|---|
| AI-suspected threshold | 60% | internal/analyzer/analyzer.go (summary) |
| AI report threshold | 50% | internal/output/markdown.go (report) |
| Shannon entropy minimum | 3.5 bits | internal/analyzer/security.go (secrets) |
| Max git commits | 500 | internal/analyzer/git.go |
| Concurrency limit | 8 goroutines | internal/analyzer/analyzer.go |
| Progress channel buffer | 100 messages | internal/analyzer/analyzer.go |
The main() function parses CLI flags by hand (no flag library):
- Iterates through
os.Args[1:]looking for--format,--ci,--version/-v,--help/-h. - Any non-flag argument is treated as the target directory (defaults to
.). - Routes to one of three modes:
--format json|mdor--ciβ non-interactive: validates dir β runs analysis β outputs result.- No flags with path β opens TUI directly at the Analysis Menu screen.
- No flags, no path β opens TUI at the Home screen.
The analyzer uses a bounded semaphore pattern:
sem := make(chan struct{}, 8) // max 8 goroutines
for _, f := range files {
wg.Add(1)
sem <- struct{}{} // blocks when 8 goroutines are in-flight
go func(f *FileResult) {
defer wg.Done()
defer func() { <-sem }()
// ... analyze file
}(f)
}
wg.Wait()For generic secret patterns, Fuji computes Shannon entropy:
H(s) = -Ξ£ p(c) Γ logβ(p(c))
Where p(c) is the frequency of character c divided by string length. Values below 3.5 bits are considered low-entropy (likely placeholders like "changeme", "password123") and are not flagged.
Each of the 12 signals produces a value between 0.0 (human-like) and 1.0 (AI-like). The final score:
score = Ξ£ (signal_value Γ signal_weight) Γ 100
is then clamped to [0, 100].
Uses a sliding window of 6 lines, hashing each window with SHA-256 (first 8 bytes) and grouping by hash to find identical code blocks.
Built with Go + Bubble Tea + Lipgloss
π» Fuji β see your code from the summit.