My Repository Was Haunted. So I Built a CLI -"Exorcist" to Find the Spirits.
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine Exorcist: The Ghosts Hiding in Your Codebase π»
It is late. You open a repository you have not touched in months. The feature works. The tests pass. The README looks fine.
Then you notice a configuration file you do not remember adding. A dependency nobody seems to use. A scheduled job whose purpose has been lost to time. Somewhere in the repository, a secret might still be sitting in plain sight.
Nothing is necessarily on fire. That is what makes these things easy to miss. Software accumulates history. Some of that history is useful; some of it becomes residue: forgotten assumptions, stale code, suspicious configuration, and small risks that survive long after the context behind them disappears.
I wanted to build a tool for investigating that residue without asking developers to hand their source code to a cloud AI service. That became Exorcist , a local-first command-line tool that scans a repository for selected signals, then uses an open-weight model to help explain what the scanners found.
The idea behind it is simple: the scanners find the evidence; Gemma helps explain it; the developer stays in control.
What I Built
Exorcist is a Python CLI for investigating four kinds of repository βghostsβ:
- Secrets: potential credentials and sensitive strings that should not be committed.
- Dependencies: dependency declarations that may deserve a closer look.
- Dead code: code that appears unused or obsolete.
- Scheduled jobs: cron or workflow entries that may have been forgotten.
I interpreted the βGhost in the Machineβ theme as the invisible residue software leaves behind. A forgotten token, an obsolete function, or a scheduled task nobody remembers can be easy to overlook precisely because it has become part of the background.
Exorcist turns that investigation into a repeatable workflow:
- Scan locally. Run the selected checks against a repository on disk.
- Redact sensitive evidence. Mask secret-like values before they are passed into explanations or reports.
- Ask Gemma to triage, not to invent evidence. The model classifies and explains scanner findings; it does not replace the scanners.
- Validate the response. Pydantic checks structured model output. Exorcist attempts one repair if the output is invalid; if it still fails, the result can be marked for human review.
- Generate a report. Produce JSON results or an offline HTML report with findings, verdicts, redacted evidence, model metadata, and scan status.
The CLI includes commands such as doctor , scan , report , guide , rules , tracks , explain , and version . Optional integrations include tools such as Gitleaks and Vulture where appropriate.
I did not want an AI model to confidently declare a repository safe. I wanted a tool that could show its work, explain its conclusions, and be honest when something needs a human.
The first exorcism: a real local demo
For validation, I cloned a small public project, jersey-paglu , and ran Exorcist against the local checkout. The selected checks completed with zero findings . That was not a dramatic wall of red warnings, and that is worth saying plainly.
A clean result means these selected checks did not detect anything in that run. It does not prove that the repository is universally secure or that every possible issue has been ruled out.
The demo exercised the local model check, plain-text output, JSON output, and HTML report generation. During the scan and report workflow, Exorcist recorded zero network calls . Cloning the repository itself required network access; the scan and report were run against the local copy.
The terminal demo The generated report The result I care about is not just the number of findings. It is that the process can be run locally, exported in machine-readable form, and reviewed in a report without requiring a cloud inference call.
Demo
The demo was validated on a local Windows environment using gemma3:4b through Ollama.
# Check that Exorcist and the local model are available
exorcist doctor --model gemma3:4b
# Scan selected categories in a local checkout
exorcist scan ./demo/jersey-paglu \
--model gemma3:4b \
--types secrets,deps,deadcode,cron \
--plain
# Export machine-readable results
exorcist scan ./demo/jersey-paglu \
--model gemma3:4b \
--types secrets,deps,deadcode,cron \
--json
# Generate an offline HTML report
exorcist report ./demo/jersey-paglu \
--model gemma3:4b \
--out ./demo/jersey-paglu-real-report.html
Paths may vary by operating system and installation. The target repository must already be available locally before running the offline scan.
The terminal transcript and generated HTML report screenshots above are hosted on DEV.to and show the validation run.
Code Repository: Exorcist on GitHub ADITYA-KUMAR-2358 / Exorcist Exorcist Exorcist is a local-first CLI for finding and banishing possessed code secrets, vulnerable dependencies, dead code, and zombie jobs.
Quickstart
python - m pip install - e " .[dev] "
exorcist doctor
exorcist scan tests / cursed_repo -- json
exorcist report tests / cursed_repo -- out report.html
For a remote repository, clone it explicitly first:
exorcist clone https: // github.com / owner / project.git
exorcist scan .\project
This separation is intentional. clone is the only network-facing setup command. Scanning stays local and never silently contacts a Git host.
For the full terminal tutorial and command map, run exorcist guide or read docs/RUN.md . exorcist --help , exorcist -help , and exorcist help all show the complete command suite.
The scanner works without network access. When Ollama is running locally, use --model qwen2.5-coder:3b to triage findings. If it is unavailable, findings are explicitly marked needs_human_review .
Why open-source AI
Private: β¦ View on GitHub The most important design decision is the boundary between evidence and interpretation. A scanner can point to a suspicious pattern; the model can help explain why it might matter. But model-generated text should never be accepted as reliable merely because it sounds confident.
A simplified example of the kind of structured contract used to validate triage output looks like this:
from pydantic import BaseModel , Field
from typing import Literal
class FindingTriage ( BaseModel ):
verdict : Literal [ " actionable " , " needs_review " , " likely_false_positive " , ]
explanation : str = Field ( min_length = 1 )
confidence : float = Field ( ge = 0.0 , le = 1.0 )
recommended_action : str
This is an illustrative example of the validation boundary, not a claim that every internal field or enum is identical to this snippet. The important principle is that model output is parsed and validated before it is used.
The report also needs to be careful about what it repeats. If a tool is investigating a possible secret, it should not create a second place where that secret is exposed. Exorcist redacts sensitive evidence before it is included in explanations and reports.
How I Built It
Exorcist is built with a Python-first stack:
- Python 3.11+ for the CLI and scanner workflow.
- Typer for commands and options.
- Pydantic v2 for validating structured model output.
- Ollama + Google Gemma 3 4B (
gemma3:4b) for local inference. - GitPython / Git CLI for working with local repositories.
- Jinja2 for rendering the HTML report.
- pytest and Ruff for testing and code-quality checks.
- Gitleaks and Vulture as optional tools for relevant checks.
The runtime connects to the local Ollama service rather than sending repository content to a hosted LLM endpoint. The model can be selected with --model , which keeps the inference choice flexible instead of permanently coupling the tool to a single model.
The rule: scanners first, AI second
This boundary is the heart of Exorcist:
- Scanners detect. They produce the evidence a finding is based on.
- Gemma interprets. It helps classify findings and explain them in language a developer can act on.
- Pydantic validates. It prevents unstructured model text from being accepted as a reliable result.
- The developer decides. Ambiguous or invalid output can be flagged for human review instead of being silently treated as fact.
That separation matters. An LLM can produce a plausible explanation for a finding that is wrong, or miss the significance of a real issue. The tool should not confuse fluency with proof.
Exorcist is therefore not a promise that AI can guarantee security. It is a way to make scanner output easier to understand while keeping the evidence and its limitations visible.
Gemma and GitHub Copilot have different jobs
Exorcist uses Google Gemma 3 4B locally through Ollama to classify and explain findings detected by deterministic scanners. This makes the project relevant to Best Use of Gemma : Gemma is part of the product's runtime path, but it is deliberately not the source of truth for detection.
GitHub Copilot was used during development in VS Code to help implement and iterate on CLI features, scanner workflows, reports, documentation, tests, local setup, and demo validation. Copilot is a development assistant; it is not part of Exorcist's runtime product path.
The distinction is important: Gemma powers the product; Copilot supported the development workflow.
Why Does Open Innovation Matter?
A repository scanner can encounter some of a developer's most sensitive material: source code, configuration, dependency details, and accidentally committed credentials. If every explanation required uploading that material to a closed cloud API, privacy would become a prerequisite problem rather than a design choice.
Open-weight models and local inference change that trade-off. With Gemma running through Ollama, Exorcist can provide model-assisted explanations without depending on a remote inference service. Developers can inspect the workflow, choose a compatible local model, and adapt the tool to their own repositories and constraints.
The scan-and-report path can also work where cloud access is restricted or simply undesirable. Open innovation matters here for three reasons:
- Privacy and control. Source code stays on the developer's machine during the local scan and report workflow.
- Adaptability. The model can be changed through a CLI option instead of being hard-wired to a hosted endpoint.
- Inspectable boundaries. The project separates deterministic checks from model-generated interpretation, making it easier to reason about what the tool knows and what it is suggesting.
Open-weight does not mean infallible, and local does not mean every result is correct. The scanners have coverage limits, local models can make mistakes, and important findings still deserve human review. The goal is not to remove human judgment. It is to make useful AI assistance more accessible without making cloud inference a requirement.
The Spirit of It
The ghost I wanted to hunt is not supernatural. It is the tiny, forgotten decision that quietly survives in a codebase: a token copied into a config file, a dependency nobody recognizes, or a scheduled task that still runs after its original purpose has disappeared.
These things rarely announce themselves. They hide in ordinary files, between the code a developer actively maintains and the code they no longer remember.
I like the idea of a tool that treats this as an investigation rather than a verdict. It should show what was checked, explain what was found, and admit what remains uncertain. It should not send a repository away to a cloud AI service just to make its output sound more human.
Exorcist does not promise to banish every bug or prove a repository safe. It gives developers a local, explainable starting point: evidence from scanners, a model-assisted interpretation, and a report they can inspect.
For me, the best outcome is not a dramatic red warning. It is a developer understanding what was checked, what was found, what remains uncertain, and what deserves attention next.
Prize Categories
Best Use of Gemma: Exorcist uses Google Gemma 3 4B locally through Ollama to classify and explain findings detected by deterministic scanners, with zero cloud inference or scan-time network calls.
Best Use of GitHub Copilot: GitHub Copilot was used in VS Code to help build and iterate on the CLI, scanner workflow, reports, documentation, tests, local setup, and demo validation. Copilot is not part of Exorcist's runtime product path.
Built solo, slowly and steadily, by Aditya Kumar .
Comments
No comments yet. Start the discussion.