MCP Server / skylos
skylos
Open-source Python, TypeScript, and Go SAST with dead code detection. Finds secrets, exploitable flows, and AI regressions. VS Code extension, GitHub Action, and MCP server for AI agents.
Transport
Tools (20)
Goal
Command
Skylos
Vulture
644
Yes
No
Yes
No
Yes
No
Yes
No
Yes
No
Objective
Command
Objective
Command
Check
Severity
no-dangerous-sink
Critical
untrusted-input-to-prompt
Critical
output-validation
High
prompt-delimiter
High
rag-context-isolation
High
output-pii-filter
High
model-pinned
Medium
input-length-limit
Low
logging-present
Medium
Dokumentation
📖 Website · Documentation · Blog · GitHub Action · VS Code Extension · MCP Server
English | 中文
What is Skylos?
Skylos is an open-source static analysis tool and PR gate for Python, TypeScript, and Go. It helps teams detect dead code, hardcoded secrets, exploitable flows, and AI-generated security regressions before they land in main.
If you use Vulture for dead code, Bandit for security checks, or Semgrep/CodeQL for CI enforcement, Skylos combines those workflows with framework-aware dead code detection and diff-aware regression detection for AI-assisted refactors.
The core use case is straightforward: run it locally, add it to CI, and gate pull requests on real findings with GitHub annotations and review comments. Advanced features like AI defense, remediation agents, VS Code, MCP, and cloud upload are available, but you do not need any of them to get value from Skylos.
Best for
- Python teams that want dead code detection with fewer false positives than Vulture
- Repositories using Cursor, Copilot, Claude Code, or other AI coding assistants
- CI/CD pull request gates with GitHub annotations and review comments
- Python LLM applications that need OWASP LLM Top 10 checks
Available as
- CLI for local scans and CI/CD workflows
- GitHub Action for pull request gating and annotations
- VS Code extension for in-editor findings and AI-assisted fixes
- MCP server for AI agents and coding assistants
Start here
| Goal | Command | What you get |
|:---|:---|:---|
| Scan a repo | skylos . -a | Dead code, risky flows, secrets, and code quality findings |
| Gate pull requests | skylos cicd init | A GitHub Actions workflow with a quality gate and inline annotations |
| Audit an LLM app | skylos defend . | Optional AI defense checks for Python LLM integrations |
Why teams adopt it
- Better dead code signal on real frameworks: Skylos understands FastAPI, Django, Flask, pytest, Next.js, React, and more, so dynamic code produces less noise.
- Diff-aware AI regression detection: Skylos can catch removed auth decorators, CSRF, rate limiting, validation, logging, and other controls that disappear during AI-assisted refactors.
- One workflow instead of three tools: Dead code, security scanning, and PR gating live in the same CLI and CI flow.
- Local-first by default: You can keep scans on your machine and add optional AI or cloud features later if you need them.
- Self-explaining output: Every table prints a legend explaining what each column and number means — no manual required.
Why Skylos over Vulture for Python dead code detection?
| | Skylos | Vulture | |:---|:---|:---| | Recall | 98.1% (51/52) | 84.6% (44/52) | | False Positives | 220 | 644 | | Framework-aware (FastAPI, Django, pytest) | Yes | No | | Security scanning (secrets, SQLi, SSRF) | Yes | No | | AI-powered analysis | Yes | No | | CI/CD quality gates | Yes | No | | TypeScript + Go support | Yes | No |
Benchmarked on 9 popular Python repos (350k+ combined stars) + TypeScript (consola). Every finding manually verified. Full case study →
🚀 New to Skylos? Start with CI/CD Integration
# Generate a GitHub Actions workflow in 30 seconds
skylos cicd init
# Commit and push to activate
git add .github/workflows/skylos.yml && git push
What you get:
- Automatic dead code detection on every PR
- Security vulnerability scanning (SQLi, secrets, dangerous patterns)
- Quality gate that fails builds on critical issues
- Inline PR review comments with file:line links
- GitHub Annotations visible in the "Files Changed" tab
No configuration needed - works out of the box with sensible defaults. See CI/CD section for customization.
Table of Contents
- What is Skylos?
- Quick Start
- Technical Debt Hotspots
- Key Capabilities
- Installation
- Skylos vs Vulture
- Projects Using Skylos
- How It Works
- Advanced Workflows
- CI/CD
- MCP Server
- Baseline Tracking
- Gating
- VS Code Extension
- Integration and Ecosystem
- Auditing and Precision
- Coverage Integration
- Filtering
- Release Automation
- Release Workflow Runbook
- CLI Options
- FAQ
- Limitations and Troubleshooting
- Contributing
- Roadmap
- License
- Contact
Quick Start
If you are evaluating Skylos, start with the core workflow below. The LLM and AI defense commands are optional.
Core Workflow
| Objective | Command | Outcome |
| :--- | :--- | :--- |
| First scan | skylos . | Dead code findings with confidence scoring |
| Audit risk and quality | skylos . -a | Dead code, risky flows, secrets, quality, and SCA findings |
| Higher-confidence dead code | skylos . --trace | Cross-reference static findings with runtime activity |
| Review only changed lines | skylos . --diff origin/main | Focus findings on active work instead of legacy debt |
| Gate locally | skylos --gate | Fail on findings before code leaves your machine |
| Set up CI/CD | skylos cicd init | Generate a GitHub Actions workflow in 30 seconds |
| Gate in CI | skylos cicd gate --input results.json | Fail builds when issues cross your threshold |
Optional Workflows
| Objective | Command | Outcome |
| :--- | :--- | :--- |
| Detect Unused Pytest Fixtures | skylos . --pytest-fixtures | Find unused @pytest.fixture across tests + conftest |
| AI-Powered Analysis | skylos agent scan . --model gpt-4.1 | Fast static + LLM file review with dead-code verification available on demand |
| Dead Code Verification | skylos agent verify . --model gpt-4.1 | Dead-code-only second pass: static findings reviewed by the LLM |
| Security Audit | skylos agent scan . --security | Deep LLM security review with interactive file selection |
| Auto-Remediate | skylos agent remediate . --auto-pr | Scan, fix, test, and open a PR — end to end |
| Code Cleanup | skylos agent remediate . --standards | LLM-guided code quality cleanup against coding standards |
| PR Review | skylos agent scan . --changed | Analyze only git-changed files |
| PR Review (JSON) | skylos agent scan . --changed --format json -o results.json | LLM review with code-level fix suggestions |
| Local LLM | skylos agent scan . --base-url http://localhost:11434/v1 --model codellama | Use Ollama/LM Studio (no API key needed) |
| PR Review (CI) | skylos cicd review -i results.json | Post inline comments on PRs |
| AI Defense: Discover | skylos discover . | Map all LLM integrations in your codebase |
| AI Defense: Defend | skylos defend . | Check LLM integrations for missing guardrails |
| AI Defense: CI Gate | skylos defend . --fail-on critical --min-score 70 | Block PRs with critical AI defense gaps |
| Whitelist | skylos whitelist 'handle_*' | Suppress known dynamic patterns |
Technical Debt Hotspots
Use skylos debt <path> to rank structural debt hotspots without collapsing everything into a single urgency number.
scoreis the project-level structural debt score.priorityis the hotspot triage score used for ordering fix candidates.--changedlimits the visible hotspot list to changed files, but keeps the structural debt score anchored to the whole project.
# Full project debt scan
skylos debt .
# Review only changed hotspots without distorting the project score
skylos debt . --changed
# Compare the current project against a saved debt baseline
skylos debt . --baseline
# Save a repo-level debt baseline
skylos debt . --save-baseline
Debt policy files such as skylos-debt.yaml are discovered from the scan target upward, and explicit CLI flags like --top override policy defaults.
Demo
Backup (GitHub): https://github.com/duriantaco/skylos/discussions/82
Key Capabilities
The core product is dead code detection, security scanning, and PR gating. The AI-focused features below are optional layers on top of that baseline workflow.
Security Scanning (SAST)
- Taint Analysis: Traces untrusted input from API endpoints to databases to prevent SQL Injection and XSS.
- Secrets Detection: Hunts down hardcoded API keys (AWS, Stripe, OpenAI) and private credentials before commit.
- Vulnerability Checks: Flags dangerous patterns like
eval(), unsafepickle, and weak cryptography.
AI-Generated Code Guardrails
Skylos can also flag common AI-generated code mistakes. Every finding includes vibe_category and ai_likelihood (high/medium/low) metadata so you can filter them separately if you want.
- Phantom Call Detection: Catches calls to security functions (
sanitize_input,validate_token,check_permission, etc.) that are never defined or imported — AI hallucinates these constantly.hallucinated_reference, high - Phantom Decorator Detection: Catches security decorators (
@require_auth,@rate_limit,@authenticate, etc.) that are never defined or imported.hallucinated_reference, high - Unfinished Generation: Detects functions with only
pass,..., orraise NotImplementedError— AI-generated stubs that silently do nothing in production.incomplete_generation, medium - Undefined Config: Flags
os.getenv("ENABLE_X")referencing feature flags that are never defined anywhere in the project.ghost_config, medium - Stale Mock Detection: Catches
mock.patch("app.email.send_email")wheresend_emailno longer exists — AI renames functions but leaves tests pointing at the old name.stale_reference, medium - Security TODO Scanners: Flags
# TODO: add authplaceholders that AI left behind and nobody finished. - Disabled Security Controls: Detects
verify=False,@csrf_exempt,DEBUG=True, andALLOWED_HOSTS=["*"]. - Credential & Randomness Checks: Catches hardcoded passwords and
random.choice()used for security-sensitive values like tokens and OTPs.
Prompt Injection and Content Scanning
These checks run under --danger and look for prompt injection patterns or obfuscated instructions in repository content.
- Multi-File Prompt Injection Scanner: Scans Python, Markdown, YAML, JSON, TOML, and
.envfiles for hidden instruction payloads — instruction overrides ("ignore previous instructions"), role hijacking ("you are now"), AI-targeted suppression ("do not flag", "skip security"), data exfiltration prompts, and AI-targeting phrases. - Text Canonicalization Engine: NFKC normalization, whitespace folding, and confusable replacement neutralize obfuscation before pattern matching.
- Zero-Width & Invisible Unicode: Detects zero-width spaces, joiners, BOM, and bidi overrides (U+200B–U+202E) that hide payloads from human reviewers.
- Base64 Obfuscation Detection: Automatically decodes base64-encoded strings and re-scans for injection content.
- Homoglyph / Mixed-Script Detection: Flags Cyrillic and Greek characters mixed with Latin text (e.g., Cyrillic 'а' in
password) that bypass visual review. - Location-Aware Severity: Findings in README files, HTML comments, and YAML prompt fields get elevated severity. Test files are automatically skipped.
Advanced: AI Defense for LLM Apps
Static analysis for AI application security that maps every LLM call in your Python codebase and checks for missing guardrails. Python only (TypeScript/Go support planned).
# Discover all LLM integrations
skylos discover .
# Check defenses and get a scored report
skylos defend .
# CI gate: fail on critical gaps, require 70% defense score
skylos defend . --fail-on critical --min-score 70
# JSON output for dashboards and pipelines
skylos defend . --json -o defense-report.json
# Filter by OWASP LLM Top 10 category
skylos defend . --owasp LLM01,LLM04
13 checks across defense and ops:
| Check | Severity | OWASP | What it detects |
|:---|:---|:---|:---|
| no-dangerous-sink | Critical | LLM02 | LLM output flowing to eval/exec/subprocess |
| untrusted-input-to-prompt | Critical | LLM01 | Raw user input in prompt with no processing |
| tool-scope | Critical | LLM04 | Agent tools with dangerous system calls |
| tool-schema-present | Critical | LLM04 | Agent tools without typed schemas |
| output-validation | High | LLM02 | LLM output used without structured validation |
| prompt-delimiter | High | LLM01 | User input in prompts without delimiters |
| rag-context-isolation | High | LLM01 | RAG context injected without isolation |
| output-pii-filter | High | LLM06 | No PII filtering on user-facing LLM output |
| model-pinned | Medium | LLM03 | Model version not pinned (floating alias) |
| input-length-limit | Low | LLM01 | No input length check before LLM call |
| logging-present | Medium | Ops | No logging around LLM calls |
| cost-controls | Medium | Ops | No max_tokens set on LLM calls |
| rate-limiting | Medium | Ops | No rate limiting on LLM endpoints |
Defense and ops scores are tracked separately — adding logging won't inflate your security score.
Custom policy via skylos-defend.yaml:
rules:
model-pinned:
severity: critical # Upgrade severity
input-length-limit:
enabled: false # Disable check
gate:
min_score: 70
fail_on: high
Supports OpenAI, Anthropic, Google Gemini, Cohere, Mistral, Ollama, Together AI, Groq, Fireworks, Replicate, LiteLLM, LangChain, LlamaIndex, CrewAI, and AutoGen.
Dead Code Detection & Cleanup
- Find Unused Code: Identifies unreachable functions, orphan classes, and unused imports with confidence scoring.
- Smart Tracing: Distinguishes between truly dead code and dynamic frameworks (Flask/Django routes, Pytest fixtures).
- Safe Pruning: Uses LibCST to safely remove dead code without breaking syntax.
Advanced: Agents, Reviews, and Remediation
- Context-aware audits: Combines static analysis speed with LLM reasoning to validate findings and filter noise.
- Remediation workflow:
skylos agent remediatecan scan, generate fixes, run tests, and optionally open a PR. - Local model support: Supports Ollama and other OpenAI-compatible local endpoints if you want code to stay on your machine.
CI/CD and PR Gating
- 30-Second Workflow Setup:
skylos cicd initgenerates GitHub Actions workflows with sensible defaults. - Diff-Aware Enforcement: Gate only the lines that changed, fail on severity thresholds, and keep legacy debt manageable with baselines.
- PR-Native Feedback: GitHub annotations, inline review comments, and optional dashboard upload keep findings where teams already work.
- Corpus Guard: Require the
Corpus Guardworkflow on PRs to catch dead-code precision regressions against curated framework and language fixtures.
Safe Cleanup and Workflow Controls
- CST-safe removals: Uses LibCST to remove selected imports or functions (handles multiline imports, aliases, decorators, async etc..)
- Logic Awareness: Deep integration for Python frameworks (Django, Flask, FastAPI) and TypeScript (Tree-sitter) to identify active routes and dependencies.
- Granular Filtering: Skip lines tagged with
# pragma: no skylos,# pragma: no cover, or# noqa
Operational Governance & Runtime
- Coverage Integration: Auto-detects
.skylos-tracefiles to verify dead code with runtime data - Quality Gates: Enforces hard thresholds for complexity, nesting, and security risk via
pyproject.tomlto block non-compliant PRs - Interactive CLI: Manually verify and remove/comment-out findings through an
inquirer-based terminal interface - Security-Audit Mode: Leverages an independent reasoning loop to identify security vulnerabilities
Pytest Hygiene
- Unused Fixture Detection: Finds unused
@pytest.fixturedefinitions intest_*.pyandconftest.py - Cross-file Resolution: Tracks fixtures used across modules, not just within the same file
Multi-Language Support
| Language | Parser | Dead Code | Security | Quality | |----------|--------|-----------|----------|---------| | Python | AST | ✅ | ✅ | ✅ | | TypeScript/TSX | Tree-sitter | ✅ | ✅ | ✅ | | Java | Tree-sitter | ✅ | ✅ | ✅ | | Go | Standalone binary | ✅ | - | - |
Languages are auto-detected by file extension. Mixed-language repos work out of the box. No Node.js or JDK required — all parsers are built-in via Tree-sitter.
TypeScript Rules
| Rule | ID | What It Catches |
|------|-----|-----------------|
| Dead Code | | |
| Functions | - | Unused functions, arrow functions, and overloads |
| Classes | - | Unused classes, interfaces, enums, and type aliases |
| Imports | - | Unused named, default, and namespace imports |
| Methods | - | Unused methods (lifecycle methods excluded) |
| Security | | |
| eval() | SKY-D201 | eval() usage |
| Dynamic exec | SKY-D202 | exec(), new Function(), setTimeout with string |
| XSS | SKY-D226 | innerHTML, outerHTML, document.write(), dangerouslySetInnerHTML |
| SQL injection | SKY-D211 | Template literal / f-string in SQL query |
| Command injection | SKY-D212 | child_process.exec(), os.system() |
| SSRF | SKY-D216 | fetch()/axios with variable URL |
| Open redirect | SKY-D230 | res.redirect() with variable argument |
| Weak hash | SKY-D207/D208 | MD5 / SHA1 usage |
| Prototype pollution | SKY-D510 | __proto__ access |
| Dynamic require | SKY-D245 | require() with variable argument |
| JWT bypass | SKY-D246 | jwt.decode() without verification |
| CORS wildcard | SKY-D247 | cors({ origin: '*' }) |
| Internal URL | SKY-D248 | Hardcoded localhost/127.0.0.1 URLs |
| Insecure random | SKY-D250 | Math.random() for security-sensitive ops |
| Sensitive logs | SKY-D251 | Passwords/tokens passed to console.log() |
| Insecure cookie | SKY-D252 | Missing httpOnly/secure flags |
| Timing attack | SKY-D253 | ===/== comparison of secrets |
| Storage tokens | SKY-D270 | Sensitive data in localStorage/sessionStorage |
| Error disclosure | SKY-D271 | error.stack/.sql sent in HTTP response |
| Secrets | SKY-S101 | Hardcoded API keys + high-entropy strings |
| Quality | | |
| Complexity | SKY-Q301 | Cyclomatic complexity exceeds threshold |
| Nesting depth | SKY-Q302 | Too many nested levels |
| Function length | SKY-C304 | Function exceeds line limit |
| Too many params | SKY-C303 | Function has too many parameters |
| Duplicate condition | SKY-Q305 | Identical condition in if-else-if chain |
| Await in loop | SKY-Q402 | await inside for/while loop |
| Unreachable code | SKY-UC002 | Code after return/throw/break/continue |
Framework-aware: Next.js convention exports (page.tsx, layout.tsx, route.ts, middleware.ts), config exports (getServerSideProps, generateMetadata, revalidate), React patterns (memo, forwardRef), and exported custom hooks (use*) are automatically excluded from dead code reports.
TypeScript dead code detection tracks: callbacks, type annotations, generics, decorators, inheritance (extends), object shorthand, spread, re-exports, and typeof references. Benchmarked at 95% recall with 0 false positives on alive code.
Installation
Basic Installation
## from pypi
pip install skylos
## with LLM-powered features (agent verify, agent remediate, etc.)
pip install skylos[llm]
## with Rust-accelerated analysis (up to 63x faster)
pip install skylos[fast]
## both
pip install skylos[llm,fast]
## or from source
git clone https://github.com/duriantaco/skylos.git
cd skylos
pip install .
skylos[fast]installs an optional Rust backend that accelerates clone detection (63x), file discovery (5x), coupling analysis, and cycle detection. Same results, just faster. Pure Python works fine without it — the Rust module is auto-detected at runtime.
skylos[llm]installslitellmfor LLM-powered features (skylos agent verify,skylos agent remediate,--llm). Core static analysis works without it.
🎯 What's Next?
After installation, we recommend:
-
Set up CI/CD (30 seconds):
skylos cicd init git add .github/workflows/skylos.yml && git pushThis will automatically scan every PR for dead code and security issues.
-
Run your first scan:
skylos . # Dead code only skylos . --danger --secrets # Include security checks -
Keep scans focused on active work:
skylos . --diff origin/main -
Try advanced workflows only if you need them:
skylos agent review . --model gpt-4.1 skylos defend .
See all commands in the Quick Start table
Skylos vs. Vulture Benchmark
We benchmarked Skylos against Vulture on 9 of the most popular Python repositories on GitHub — 350k+ combined stars, covering HTTP clients, web frameworks, CLI tools, data validation, terminal UIs, and progress bars. Every single finding was manually verified against the source code. No automated labelling, no cherry-picking.
Why These 9 Repos?
We deliberately chose projects that stress-test dead code detection in different ways:
| Repository | Stars | What It Tests |
|:---|---:|:---|
| psf/requests | 53k | __init__.py re-exports, Sphinx conf, pytest classes |
| pallets/click | 17k | IO protocol methods (io.RawIOBase subclasses), nonlocal closures |
| encode/starlette | 10k | ASGI interface params, polymorphic dispatch, public API methods |
| Textualize/rich | 51k | __rich_console__ protocol, sentinel vars via f_locals, metaclasses |
| encode/httpx | 14k | Transport/auth protocol methods, zero dead code (pure FP test) |
| pallets/flask | 69k | Jinja2 template globals, Werkzeug protocol methods, extension hooks |
| pydantic/pydantic | 23k | Mypy plugin hooks, hypothesis @resolves, __getattr__ config |
| fastapi/fastapi | 82k | 100+ OpenAPI spec model fields, Starlette base class overrides |
| tqdm/tqdm | 30k | Keras/Dask callbacks, Rich column rendering, pandas monkey-patching |
No repo was excluded for having unfavorable results. We include repos where Vulture beats Skylos (click, starlette, tqdm).
Results
| Repository | Dead Items | Skylos TP | Skylos FP | Vulture TP | Vulture FP | |:---|---:|---:|---:|---:|---:| | psf/requests | 6 | 6 | 35 | 6 | 58 | | pallets/click | 7 | 7 | 8 | 6 | 6 | | encode/starlette | 1 | 1 | 4 | 1 | 2 | | Textualize/rich | 13 | 13 | 14 | 10 | 8 | | encode/httpx | 0 | 0 | 6 | 0 | 59 | | pallets/flask | 7 | 7 | 12 | 6 | 260 | | pydantic/pydantic | 11 | 11 | 93 | 10 | 112 | | fastapi/fastapi | 6 | 6 | 30 | 4 | 102 | | tqdm/tqdm | 1 | 0 | 18 | 1 | 37 | | Total | 52 | 51 | 220 | 44 | 644 |
| Metric | Skylos | Vulture | |:---|:---|:---| | Recall | 98.1% (51/52) | 84.6% (44/52) | | False Positives | 220 | 644 | | Dead items found | 51 | 44 |
Skylos finds 7 more dead items than Vulture with 3x fewer false positives.
Why Skylos Produces Fewer False Positives
Vulture uses flat name matching — if the bare name X appears anywhere as a string or identifier, all definitions named X are considered used. This works well for simple cases but drowns in noise on framework-heavy codebases:
- Flask (260 Vulture FP): Vulture flags every Jinja2 template global, Werkzeug protocol method, and Flask extension hook. Skylos recognizes Flask/Werkzeug patterns.
- Pydantic (112 Vulture FP): Vulture flags all config class annotations,
TYPE_CHECKINGimports, and mypy plugin hooks. Skylos understands Pydantic model fields and__getattr__dynamic access. - FastAPI (102 Vulture FP): Vulture flags 100+ OpenAPI spec model fields (Pydantic
BaseModelattributes likemaxLength,exclusiveMinimum). Skylos recognizes these as schema definitions. - httpx (59 Vulture FP): Vulture flags every transport and auth protocol method. Skylos suppresses interface implementations.
Where Skylos Still Loses (Honestly)
- click (8 vs 6 FP): IO protocol methods (
readable,readinto) onio.RawIOBasesubclasses — called by Python's IO stack, not by direct call sites. - starlette (4 vs 2 FP): Instance method calls across files (
obj.method()) not resolved back to class definitions. - tqdm (18 vs 37 FP, 0 vs 1 TP): Skylos misses 1 dead function in
__init__.pybecause it suppresses__init__.pydefinitions as potential re-exports.
Reproduce any benchmark:
cd real_life_examples/{repo} && python3 ../benchmark_{repo}.pyFull methodology and per-repo breakdowns in the skylos-demo repository.
Skylos vs. Knip (TypeScript)
We also benchmarked Skylos against Knip on a real-world TypeScript library:
| | unjs/consola (7k stars, 21 files, ~2,050 LOC) |
|:---|:---|
| Dead items | 4 (entire orphaned src/utils/format.ts module) |
| Metric | Skylos | Knip | |:---|:---|:---| | Recall | 100% (4/4) | 100% (4/4) | | Precision | 36.4% | 7.5% | | F1 Score | 53.3% | 14.0% | | Speed | 6.83s | 11.08s |
Both tools find all dead code. Skylos has ~5x better precision — Knip incorrectly flags package entry points as dead files (its package.json exports point to dist/ not src/) and reports public API re-exports as unused.
Reproduce:
cd real_life_examples/consola && python3 ../benchmark_consola.py
Projects Using Skylos
If you use Skylos in a public repository, open an issue and add it here. This list is based on self-submissions, so it will stay small until more teams opt in publicly.
| Project | Description | |---------|-------------| | Skylos | Uses Skylos on itself for dead code, security, and CI gating | | Your project here | Add yours |
How It Works
Skylos builds a reference graph of your entire codebase - who defines what, who calls what, across all files.
Parse all files -> Build definition map -> Track references -> Find orphans (zero refs = dead)
High Precision & Confidence Scoring
Static analysis often struggles with Python's dynamic nature (e.g., getattr, pytest.fixture). Skylos minimizes false positives through:
- Confidence Scoring: Grades findings (High/Medium/Low) so you only see what matters.
- Hybrid Verification: Uses LLM reasoning to double-check static findings before reporting.
- Runtime Tracing: Optional
--tracemode validates "dead" code against actual runtime execution.
| Confidence | Meaning | Action | |------------|---------|--------| | 100 | Definitely unused | Safe to delete | | 60 | Probably unused (default threshold) | Review first | | 40 | Maybe unused (framework helpers) | Likely false positive | | 20 | Possibly unused (decorated/routes) | Almost certainly used | | 0 | Show everything | Debug mode |
skylos . -c 60 # Default: high-confidence findings only
skylos . -c 30 # Include framework helpers
skylos . -c 0 # Everything
Framework Detection
When Skylos sees Flask, Django, FastAPI, Next.js, or React imports, it adjusts scoring automatically:
| Pattern | Handling |
|---------|----------|
| @app.route, @router.get | Entry point → marked as used |
| app.add_url_rule(...), app.add_api_route(...), app.add_route(...), app.register_listener(...), app.register_middleware(...) | Imperative route or lifecycle registration → marked as used |
| @pytest.fixture | Treated as a pytest entrypoint, but can be reported as unused if never referenced |
| @pytest.hookimpl, @hookimpl | Plugin hook implementation → marked as used |
| @celery.task | Entry point → marked as used |
| getattr(mod, "func") | Tracks dynamic reference |
| getattr(mod, f"handle_{x}") | Tracks pattern handle_* |
| Next.js page.tsx, layout.tsx, route.ts | Default/named exports → marked as used |
| Next.js getServerSideProps, generateMetadata | Config exports → marked as used |
| React.memo(), forwardRef() | Wrapped components → marked as used |
| Exported use* hooks | Custom hooks → marked as used |
Test File Exclusion
Tests call code in weird ways that look like dead code. By default, Skylos excludes:
| Detected By | Examples |
|-------------|----------|
| Path | /tests/, /test/, *_test.py |
| Imports | pytest, unittest, mock |
| Decorators | @pytest.fixture, @patch |
# These are auto-excluded (confidence set to 0)
/project/tests/test_user.py
/project/test/helper.py
# These are analyzed normally
/project/user.py
/project/test_data.py # Doesn't end with _test.py
Want test files included? Use --include-folder tests.
Philosophy
When ambiguous, we'd rather miss dead code than flag live code as dead.
Framework endpoints are called externally (HTTP, signals). Name resolution handles aliases. When things get unclear, we err on the side of caution.
Precision Regression Guard
Skylos ships a curated corpus of small fixtures that encode framework contracts and important Python runtime patterns we must not regress on.
Run it locally when you change analysis behavior:
python3 scripts/corpus_ci.py --manifest corpus/manifest.json
In GitHub, keep the Corpus Guard workflow required in branch protection. When you fix a confirmed false positive, add a focused fixture and expectation to the corpus in the same change.
Unused Pytest Fixtures
Skylos can detect pytest fixtures that are defined but never used.
skylos . --pytest-fixtures
This includes fixtures inside conftest.py, since conftest.py is the standard place to store shared test fixtures.
Advanced Workflows
These commands are optional. Use them when you want LLM-assisted review, remediation, or AI defense on top of the core scanner and CI gate.
Skylos uses a hybrid architecture that combines static analysis with LLM reasoning:
Why Hybrid?
| Approach | Recall | Precision | Logic Bugs | |----------|--------|-----------|------------| | Static only | Low | High | ❌ | | LLM only | High | Medium | ✅ | | Hybrid | Highest | High | ✅ |
Research shows LLMs find vulnerabilities that static analysis misses, while static analysis validates LLM suggestions. However, LLMs are prone to false positives in dead code if they are asked to invent findings from raw source alone.
Skylos now splits agent workflows into a fast review lane and a slower verification lane.
For dead code, Skylos uses a stricter contract:
- static analysis generates the candidate list
- repo facts and graph evidence are gathered around each candidate
skylos agent verifyis the dedicated dead-code adjudication passskylos agent scan --verify-dead-codeadds that slower verifier back into the review pipeline when you explicitly want it- deterministic suppressors still exist, and in
judge_allmode they are attached as evidence instead of silently deciding the outcome
Use --verification-mode production if you want the cheaper deterministic-first path for agent verify.
Agent Commands
| Command | Description |
|---------|-------------|
| skylos agent scan PATH | Fast hybrid review: static findings plus one-pass LLM security/quality review |
| skylos agent scan PATH --verify-dead-code | Same review path, plus the slower dead-code verification pass |
| skylos agent scan PATH --no-fixes | Same review pipeline, skip fix suggestions (faster) |
| skylos agent scan PATH --changed | Analyze only git-changed files |
| skylos agent scan PATH --security | Security-only LLM audit with interactive file selection |
| skylos agent verify PATH | Dead-code-only verification pass over static findings |
| skylos agent verify PATH --fix --pr | Verify, generate removal patches, create branch and commit |
| skylos agent remediate PATH | End-to-end: scan, fix, test, and create PR |
| skylos agent remediate PATH --standards | LLM-guided cleanup with built-in standards (or --standards custom.md) |
| skylos agent triage suggest | Show auto-triage candidates from learned patterns |
| skylos agent triage dismiss ID | Dismiss a finding from the queue |
Provider Configuration
Skylos supports cloud and local LLM providers:
# Cloud - OpenAI (auto-detected from model name)
skylos agent scan . --model gpt-4.1
# Cloud - Anthropic (auto-detected from model name)
skylos agent scan . --model claude-sonnet-4-20250514
# Local - Ollama
skylos agent scan . \
--provider openai \
--base-url http://localhost:11434/v1 \
--model qwen2.5-coder:7b
# Cheaper dead-code verification path
skylos agent verify . \
--model claude-sonnet-4-20250514 \
--verification-mode production
Note: You can use the --model flag to specify the model that you want. We support Gemini, Groq, Anthropic, ChatGPT and Mistral.
Keys and configuration
Skylos can use API keys from (1) skylos key, or (2) environment variables.
Recommended (interactive)
skylos key
# opens a menu:
# - list keys
# - add key (openai / anthropic / google / groq / mistral / ...)
# - remove key
Environment Variables
Set defaults to avoid repeating flags:
# API Keys
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
# Default to local Ollama
export SKYLOS_LLM_PROVIDER=openai
export SKYLOS_LLM_BASE_URL=http://localhost:11434/v1
LLM PR Review
skylos agent scan --changed analyzes git-changed files, runs static analysis, then uses the LLM for fast file review and code-level fix suggestions. Dead-code verification is optional and not on the critical path by default.
# Run LLM review and output JSON
skylos agent scan . --changed --model claude-sonnet-4-20250514 --format json -o llm-results.json
# Use with cicd review to post inline comments on PRs
skylos cicd review --input results.json --llm-input llm-results.json
The hybrid pipeline runs in stages:
- Static analysis — finds security, quality, and dead code issues
- LLM review — one-pass file or diff review for security, logic, quality, and performance issues static analysis may miss
- Optional dead-code verification — when requested, the LLM judges static dead-code candidates using graph evidence, repo facts, and surrounding context
- Code fix generation — for each reported finding, generates the problematic code snippet and a corrected version
Each PR comment shows the exact vulnerable lines and a drop-in replacement fix.
What LLM Analysis Detects
| Category | Examples | |----------|----------| | Hallucinations | Calls to functions that don't exist | | Logic bugs | Off-by-one, incorrect conditions, missing edge cases | | Business logic | Auth bypasses, broken access control | | Context issues | Problems requiring understanding of intent |
Local LLM Setup (Ollama)
# Install Ollama
curl -fsSL https://ollama.com/install.sh | sh
# Pull a code model
ollama pull qwen2.5-coder:7b
# Use with Skylos
skylos agent scan ./src \
--provider openai \
--base-url http://localhost:11434/v1 \
--model qwen2.5-coder:7b
Remediation Agent
The remediation agent automates the full fix lifecycle. It scans your project, prioritizes findings, generates fixes via the LLM, validates each fix by running your test suite, and optionally opens a PR.
# Preview what would be fixed (safe, no changes)
skylos agent remediate . --dry-run
# Fix up to 5 critical/high issues, validate with tests
skylos agent remediate . --max-fixes 5 --severity high
# Full auto: fix, test, create PR
skylos agent remediate . --auto-pr --model gpt-4.1
# Use a custom test command
skylos agent remediate . --test-cmd "pytest test/ -x"
Safety guardrails:
- Dry run by default — use
--dry-runto preview without touching files - Fixes that break tests are automatically reverted
- Low-confidence fixes are skipped
- After applying a fix, Skylos re-scans to confirm the finding is actually gone
--auto-pralways works on a new branch, never touches main--max-fixesprevents runaway changes (default 10)
Recommended Models
| Model | Provider | Use Case |
|-------|----------|----------|
| gpt-4.1 | OpenAI | Best accuracy |
| claude-sonnet-4-20250514 | Anthropic | Best reasoning |
| qwen2.5-coder:7b | Ollama | Fast local analysis |
| codellama:13b | Ollama | Better local accuracy |
CI/CD
Run Skylos in your CI pipeline with quality gates, GitHub annotations, and PR review comments.
Quick Start (30 seconds)
# Auto-generate a GitHub Actions workflow
skylos cicd init
# Commit and activate
git add .github/workflows/skylos.yml && git push
That's it! Your next PR will have:
- Dead code detection
- Security scanning (SQLi, SSRF, secrets)
- Quality checks
- Inline PR comments with clickable file:line links
- Quality gate that fails builds on critical issues
Want AI-powered code fixes on PRs?
skylos cicd init --llm --model claude-sonnet-4-20250514
This adds an LLM step that generates code-level fix suggestions — showing the vulnerable code and the corrected version inline on your PR.
Optional GitHub Secrets
For the default skylos cicd init workflow, you do not need any Skylos-specific secrets. Add these only if you enable the matching feature in GitHub Actions (Settings > Secrets and variables > Actions):
| Secret | When needed | Description |
|--------|-------------|-------------|
| ANTHROPIC_API_KEY | If using Claude models | Your Anthropic API key |
| OPENAI_API_KEY | If using GPT models | Your OpenAI API key |
| SKYLOS_API_KEY | For Skylos Cloud features | Get from skylos.dev |
| SKYLOS_TOKEN | If using --upload | Upload token from skylos.dev/dashboard/settings |
GH_TOKEN is automatically provided by GitHub Actions — no setup needed for PR comments.
Release Automation
Skylos uses a split release workflow:
.github/workflows/release-please.ymlupdatesCHANGELOG.md, bumpspyproject.toml, and opens or updates the release PR..github/workflows/publish.ymlpublishes from an immutable release tag, either automatically onv*tag pushes or manually viaworkflow_dispatch.- For protected repos, prefer a dedicated
RELEASE_PLEASE_TOKENsecret so bot-authored release PRs can satisfy required PR checks.
First-time bootstrap (already configured in this repo)
Release Please is bootstrapped with:
tools/release/.release-please-manifest.jsonset to4.2.1tools/release/release-please-config.jsonset withbootstrap-shaat the commit that prepared4.2.1(a498b27b6902b34e469acfddac1068635aae8122)
This prevents backfilling old history and starts automated releases from the current baseline.
Normal release flow
- Merge conventional commits into
main(for example:feat: ...,fix: ...). - Release Please opens/updates the release PR.
- Merge the release PR to
main. - Release Please creates the GitHub release tag (
vX.Y.Z). - The tag push triggers
.github/workflows/publish.yml. - Skylos builds and publishes to PyPI from that tag using
PYPI_TOKEN.
Manual build/publish checks
If you need to validate packaging before a release:
python -m pip install --upgrade pip
python -m pip install "build>=1.2.2" "twine>=6.1.0"
python -m build --sdist --wheel --outdir dist
python -m twine check dist/*
If you need to manually run the fallback publish workflow, use Actions -> Build and publish -> Run workflow and set ref to the exact release tag (for example v4.2.1). Do not use a branch name.
PR title types used for release semantics
Skylos validates semantic PR titles via .github/workflows/pr-title.yml with these allowed types:
featfixdocsrefactortestchoreperfstyleciinfrarevert
For complete release ownership, guardrails, and recovery steps, see RELEASE_WORKFLOW.md.
Release Workflow Runbook
Release roles, prerequisites, branch protection guidance, semantic type policy, and incident recovery steps are documented in RELEASE_WORKFLOW.md.
Command Reference
Core Analysis
| Command | Description |
|---------|-------------|
| skylos <path> | Dead code, security, and quality analysis |
| skylos debt <path> | Technical debt hotspot analysis with baseline-aware prioritization |
| skylos discover <path> | Map LLM/AI integrations in your codebase |
| skylos defend <path> | Check LLM integrations for missing defenses |
AI Agent
| Command | Description |
|---------|-------------|
| skylos agent scan <path> | Fast hybrid static + LLM review |
| skylos agent verify <path> | LLM-verify dead code (100% accuracy) |
| skylos agent remediate <path> | Auto-fix issues and create PR |
| skylos agent watch <path> | Continuous repo monitoring with optional triage pattern learning |
| skylos agent pre-commit <path> | Analyze staged files (git hook) |
| skylos agent triage | Manage finding triage (dismiss/snooze) |
CI/CD
| Command | Description |
|---------|-------------|
| skylos cicd init | Generate GitHub Actions workflow |
| skylos cicd gate | Quality gate (CI exit code) |
| skylos cicd annotate | Emit GitHub Actions annotations |
| skylos cicd review | Post inline PR review comments |
Account
| Command | Description |
|---------|-------------|
| skylos login | Connect to Skylos Cloud |
| skylos whoami | Show connected account info |
| skylos key | Manage API keys |
| skylos credits | Check credit balance |
Utility
| Command | Description |
|---------|-------------|
| skylos init | Initialize config in pyproject.toml |
| skylos baseline <path> | Save current findings as baseline |
| skylos whitelist <pattern> | Manage whitelisted symbols |
| skylos badge | Get badge markdown for README |
| skylos rules | Install/manage community rule packs |
| skylos doctor | Check installation health |
| skylos clean | Remove cache and state files |
| skylos tour | Guided tour of capabilities |
| skylos commands | List all commands (flat) |
Run skylos <command> --help for detailed usage of any command.
Commands (Detailed)
skylos cicd init
Generates a ready-to-use GitHub Actions workflow.
skylos cicd init
skylos cicd init --triggers pull_request schedule
skylos cicd init --analysis security quality
skylos cicd init --python-version 3.11
skylos cicd init --llm --model gpt-4.1
skylos cicd init --upload # include --upload step + SKYLOS_TOKEN env
skylos cicd init --upload --llm --model claude-sonnet-4-20250514 # upload + LLM
skylos cicd init --defend # add AI Defense check step
skylos cicd init --defend --upload # defend + upload results to cloud
skylos cicd init --no-baseline
skylos cicd init -o .github/workflows/security.yml
skylos cicd gate
Checks findings against your quality gate. Exits 0 (pass) or 1 (fail). Uses the same check_gate() as skylos . --gate.
skylos . --danger --quality --secrets --json > results.json 2>/dev/null
skylos cicd gate --input results.json
skylos cicd gate --input results.json --strict
skylos cicd gate --input results.json --summary
You can also use the main CLI directly:
skylos . --gate --summary
Configure thresholds in pyproject.toml:
[tool.skylos.gate]
fail_on_critical = true
max_critical = 0
max_high = 5
max_security = 10
max_quality = 10
skylos cicd annotate
Emits GitHub Actions annotations (::error, ::warning, ::notice). Uses the same _emit_github_annotations() as skylos . --github, with sorting and a 50-annotation cap.
skylos cicd annotate --input results.json
skylos cicd annotate --input results.json --severity high
skylos cicd annotate --input results.json --max 30
skylos . --github
skylos cicd review
Posts inline PR review comments and a summary via gh CLI. Only comments on lines changed in the PR.
skylos cicd review --input results.json
skylos cicd review --input results.json --pr 20
skylos cicd review --input results.json --summary-only
skylos cicd review --input results.json --max-comments 10
skylos cicd review --input results.json --diff-base origin/develop
# With LLM-generated code fixes (vulnerable code → fixed code)
skylos cicd review --input results.json --llm-input llm-results.json
When --llm-input is provided, each inline comment shows the problematic code and the corrected version:
🔴 CRITICAL SKY-D211
Possible SQL injection: tainted or string-built query.
Why: User input is concatenated directly into the SQL query string.
Vulnerable code:
results = conn.execute(f"SELECT * FROM users WHERE name LIKE '%{q}%'").fetchall()
Fixed code:
results = conn.execute("SELECT * FROM users WHERE name LIKE ?", (f"%{q}%",)).fetchall()
In GitHub Actions, PR number and repo are auto-detected. Requires GH_TOKEN.
How It Fits Together
The gate and annotation logic lives in the core Skylos modules (gatekeeper.py and cli.py). The cicd commands are convenience wrappers that read from a JSON file and call the same functions:
| skylos cicd command | Calls |
|-----------------------|-------|
| gate | gatekeeper.run_gate_interaction(summary=True) |
| annotate | cli._emit_github_annotations(max_annotations=50) |
| review | New — cicd/review.py (PR comments via gh api) |
| init | New — cicd/workflow.py (YAML generation) |
Tips
- Run analysis once, consume many times — use
--json > results.json 2>/dev/nullthen pass--input results.jsonto each subcommand. - Baseline — run
skylos baseline .to snapshot existing findings, then--baselinein CI to only flag new issues. - Local testing — all commands work locally.
gateandannotateprint to stdout.reviewrequiresghCLI.
MCP Server
mcp-name: io.github.duriantaco/skylos
Skylos exposes its analysis capabilities as an MCP (Model Context Protocol) server, allowing AI assistants like Claude Desktop to scan your codebase directly.
Setup
pip install skylos
Add to your Claude Desktop config (~/.config/claude/claude_desktop_config.json on Linux, ~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"skylos": {
"command": "python",
"args": ["-m", "skylos_mcp.server"]
}
}
}
Available Tools
| Tool | Description |
|------|-------------|
| analyze | Dead code detection (unused functions, imports, classes, variables) |
| security_scan | Security vulnerability scan (--danger equivalent) |
| quality_check | Code quality and complexity analysis (--quality equivalent) |
| secrets_scan | Hardcoded secrets detection (--secrets equivalent) |
| remediate | End-to-end: scan, generate LLM fixes, validate with tests |
| generate_fix | Generate removal patches for confirmed dead code |
| verify_dead_code | LLM-verify dead code findings (reduce false positives) |
| learn_triage | Record a triage decision for pattern learning |
| get_triage_suggestions | Get auto-triage candidates from learned patterns |
Available Resources
| Resource | URI | Description |
|----------|-----|-------------|
| Latest result | skylos://results/latest | Most recent analysis run |
| Result by ID | skylos://results/{run_id} | Specific analysis