Skeptic is an AI-assisted developer tool that cross-examines engineering decisions. It builds a deterministic index of your repository, then uses an LLM to surface the implicit assumptions your code relies on, and tracks each one through a review lifecycle until it's backed by evidence.
Confident? Prove it.
Skeptic is early (v0.1). Indexing and finding-generation are solid; the defend conversation loop is still getting refined.
Requires Python 3.11+. Skeptic isn't on PyPI yet, so install from source:
git clone https://github.com/rodp63/skeptic
cd skeptic
pip install .Skeptic talks to an LLM through one of four providers, configured in skeptic.toml:
- Ollama: everything stays on your machine.
- Gemini: requires
GOOGLE_API_KEYset in your environment. - OpenAI: requires
OPENAI_API_KEYset in your environment. - Anthropic: requires
ANTHROPIC_API_KEYset in your environment.
Three commands cover the whole workflow:
skeptic init # establish the project root and index the repo
skeptic examine # update the index and surface assumptions as findings
skeptic defend # cross-examine each open finding and record verdictsConfiguration lives in exactly one committed file, skeptic.toml:
[llm]
provider = "gemini" # ollama | gemini | openai | anthropic
model = "gemini-3.6-flash"
[index]
exclude = ["tests/"].skeptic/ holds Skeptic's project state: findings.json (your findings and
verdicts, the actual review history) and state.json (the index cache,
fully regenerable from your source). If you don't want to show the world your
private conversations with Skeptic, gitignore the .skeptic/ folder.
A shared collaboration workflow for findings is still on the roadmap. Skeptic is currently a developer tool, but potentially a CI integration in the near future.
- Assume the developer is right: findings are claims that deserve evidence, not bugs. Question decisions, never people.
- Evidence over confidence: every important engineering claim should be backed by code, tests, documentation, or an explicit decision.
- Deterministic-first: parsing, indexing, navigation, and symbol resolution never call the LLM; it's reserved for reasoning.
- Admit when convinced: once sufficient evidence exists, Skeptic accepts it and moves on.
repository -> project index -> findings -> defend -> outcomes
(deterministic) (claims) (chat) (statuses)
The project index is built deterministically from your source tree
(honoring .gitignore). It records modules, functions, classes, imports,
call relationships, and symbol locations. This lets Skeptic retrieve just the
relevant code for a claim instead of sending whole repositories to the LLM,
and keeps analysis incremental and reproducible.
Findings are generated by reasoning over the index. Each finding is a claim plus rationale, referencing indexed symbols. Here's a real one Skeptic raised about its own path-resolution code:
Wrote findings: 1 findings
New findings (1)
╭──────────────────────────────────────────────────────────── F-77c585cc ────────────────────────────────────────────────────────────╮
│ │
│ Status OPEN │
│ Claim The denominator argument `b` passed to `lb.foo` is always non-zero. │
│ Rationale The function `lb.foo` performs a division operation `a / b` directly without verifying that `b` is non-zero. If │
│ `b` evaluates to zero, the function will raise a `ZeroDivisionError`, which could cause the application to crash │
│ if not caught by the caller. │
│ References lb.foo │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Every finding moves through a lifecycle:
Open → Under review → Addressed | Accepted risk | Inaccurate
examine has two modes. Run it with no arguments and it updates the
index and reasons over what changed since the last run: already-handled
findings carry forward, so your decisions stick, and a run with nothing
changed is a no-op. A failed run (LLM error, bad key) never consumes the
pending changes, fix the issue and re-run. The second mode is passing specific file paths
instead, and it runs in isolation: it reasons about just those files and
prints the findings, but nothing is written to state.json or
findings.json: a quick gut check with no commitment.
defend cross-examines open findings. For each one, you can either set a
verdict directly, or talk it through: Skeptic's LLM can ask you for more
context, and your response is what it uses to decide whether the finding is
resolved or needs another round.
Is Skeptic a code reviewer, type checker, or bug tracker?
No. It doesn't assume anything is broken. It asks what assumptions exist, where the evidence is, and which risks are accepted. It complements code review rather than replacing it.
Do my verdicts survive a re-run of examine?
Yes, as long as you're running examine with no arguments; handled findings
are carried forward and only changed code gets re-reviewed. Findings reflect
the current state of the code, not permanent knowledge.
Why an index instead of just prompting an LLM with the repo?
The index answers structural questions deterministically (where things are defined, what calls what), so the LLM sees only relevant code, costs less, and reasons over something reproducible.
- Multi-language support beyond Python
- Git-aware reasoning (history as evidence)
- Architectural decision tracking
- Build a report from the findings
- CI/CD integration
- Team-wide reasoning history
- Contribution guidelines