Skip to main content
Glama

What Is Skylos?

Skylos is an open-source (Apache-2.0) CLI and pull-request gate for Python projects that runs without an account. skylos . finds dead code: unused functions, classes, imports and empty files. Add -a to check security bugs, hard-coded secrets, vulnerable dependencies, code quality and AI-code mistakes. Findings include source locations and supporting analysis; skylos done checks whether a branch, often a coding agent's, is ready to merge.

It is built for:

  • Teams merging pull requests from AI coding agents such as Claude Code, Codex and Cursor. skylos done runs your tests and flags deleted or skipped tests, loosened CI test steps, silenced lint or type checks, and test-only special cases.

  • Python maintainers who want framework-aware dead-code, security and secrets checks. Python has the deepest coverage; other languages are listed under Language Support.

pip install skylos
skylos .                  # find dead code
skylos . -a               # add security, secrets, quality, dependency and AI-code checks
skylos done --base main   # is this branch finished? runs your tests, compares with main

Working with a coding agent? Two commands:

skylos setup   # once per repo: connects Claude Code and Codex, installs their hooks, lets Done run your tests, writes the PR check, maps the code
skylos open    # every day: diagram of your code, what changed in plain English, every check run

Your agent runs the checks itself. The tutorial walks through a real session: the agent describes the code, makes a change, gets blocked and fixes it from Skylos's fix brief.

Proof, including the misses: 10 Skylos-assisted dead-code cleanup PRs have been merged into the default branch in 9 open-source projects, including Black, NetworkX, Optuna, mitmproxy and pypdf. Real-World Results lists the 26 cleanup and quality-fix PRs in this ledger, including the ones that were closed, reverted or never reached the default branch. These are accepted cleanup PRs, not endorsements.

MCP Toplist License: Apache 2.0 codecov PyPI - Python Version PyPI version VS Code Marketplace

Website | Docs | Repo Map | Quick Start | GitHub Action | VS Code Extension | Real-World Results | Benchmarks | Roadmap | Contributing

English | Deutsch | 简体中文 | Translations

Skylos runs locally by default and can also gate pull requests in CI. Use it when you want one command to check a repo or pull request for:

  • dead code and unused files

  • security flaws and dangerous data flows

  • secrets and dependency CVEs

  • CI/CD and edge-device deployment misconfigurations

  • quality regressions such as complexity, duplicate branches, and deep nesting

  • common AI-generated code mistakes, including missing guards, fake helpers, invented package APIs, and impossible dependency versions

  • LLM app risks such as unsafe tool use and missing output validation

Skylos supports 13 languages: Python, TypeScript/JavaScript, Java, Go, PHP, Rust, Ruby, Dart, C#, C++, Kotlin, Swift and Shell. Python has the deepest coverage. TypeScript/JavaScript and Java also get dead-code, security and quality checks; PHP and Dart get dead-code and security checks (PHP security follows request data within a function or file into command and code execution, file inclusion, HTML output, SQL, SSRF, deserialization and file paths; Dart security covers command injection, path traversal and SSRF); Rust gets command-injection and path-traversal checks and experimental dead code (hidden below the default confidence threshold; --confidence 40 lists it). Go dead-code and security checks need the native skylos-go engine: from 4.50 the PyPI wheels for Linux, macOS and Windows (x86_64 and arm64) include it, the container image includes it and the GitHub Action builds it. On other platforms skylos doctor prints the command that builds it from source, and SKYLOS_GO_BIN points Skylos at a separately built engine. C# support is partial, Kotlin dead code covers only private declarations and imports (Kotlin security covers Spring, Ktor, servlet and Android WebView basics), C++ is limited to unused file-local functions, and Shell gets security checks only. Ruby adds bounded private-method liveness, literal Rails controller callbacks and explicit Kernel command checks. Swift adds syntax-aware private-code reachability and secret scanning. Public and internal APIs are retained; Swift security-flow and quality checks are not implemented. Skylos also checks CI/CD, deployment config and two Terraform/AWS declaration policies. See Language Support.

Related MCP server: loctree-mcp

Read The Results

Remember Risk, Maintainability, Dead code, Gate:

Readout

What it tells you

Risk

Highest unresolved severity and counts. One critical finding stays critical, regardless of repository size.

Maintainability

Advice counts, affected code units, and how far measurements exceed their limits.

Dead code

Removal candidates with confidence and evidence; review dynamic calls and public APIs before deleting.

Gate

Whether findings satisfy your configured limits. Passing means within policy, not zero findings.

Finding Type is separate from severity: Defect is a concrete correctness pattern, Review needs context, and Advice concerns maintainability or tooling. A Review finding can still be critical. Advice stays visible in rule groups; --expand-advice shows every location and JSON keeps complete records. Grouping cannot improve the assessment or bypass a gate.

Security findings show recorded source-to-sink evidence when available, with partial static analysis labeled. Dependency coverage names unresolved versions and the supported inputs needed to check them. Neither view claims runtime exploitability or a complete installed environment; JSON keeps the full evidence.

For uv.lock, Cargo.lock, composer.lock, Gemfile.lock and pubspec.lock, valid Git, URL, path and private-registry dependencies are shown as not checked. Skylos still queries supported public packages; the coverage gap alone does not cause exit 2. It cannot establish a clean dependency assessment. See uv source coverage.

New source scans replace the blended A–F grade with these readouts. Disabled checks are not assessed; failed checks are incomplete. Maintainability percentages use only the relevant units actually measured, with no guessed denominators or uncalibrated grades. The independent debt and defend scores keep their meanings. See the output guide.

Choose the Right Command

Each command answers a different question. The source scan requires PATH. Bracketed paths on verify, suite, defend, and clean default to the current directory. suite and defend require a directory; verify and clean also accept a file.

Question

Command

Input checked

What problems are in this source tree?

skylos PATH

Source files and project configuration; dead code by default, every main source analyzer with -a

How is this branch doing on Skylos Cloud?

skylos cloud [PATH]

Every main source analyzer, then the findings and this commit's Done receipt are uploaded and the branch's quality gate is printed with one link

Did the agent really finish this branch?

skylos done --base main

The branch's changes since its merge base with main: Skylos runs your tests (pytest automatically; other runners need test_command in [tool.skylos.done]) and compares the tests, test settings and CI steps with the base; writes a receipt to .skylos/receipts/

What does this change touch, and what should I read first?

skylos done map --base main

Each changed Python or TypeScript/JavaScript function since the merge base, with old and new code, calls added and removed, its callers and removed security checks, sorted into read first, read, skim and skip (skip only when the logic is proven the same); computed from the code, so the same commit gives the same map

Does this code contain AI-code mistakes?

skylos verify [PATH]

AI-defect checks over the selected file or tree, plus a separate Git HEAD behavior comparison for supported Python working changes

Should a model review static dead-code findings?

skylos agent verify [PATH]

LLM by default; optional Jev-only or Jev-plus-LLM review

What do I tell my CTO?

skylos report [PATH]

Every main source analyzer locally, then one self-contained HTML page (or --format md): verdict, top five risks with fixes, issue counts, coverage gaps, scan date, commit and version

What does the combined repo suite report?

skylos suite [DIRECTORY]

Static analysis, technical debt, AI app safety, and provenance; local findings are report-only by default

Does an agent implementation have deployment guardrails?

skylos defend [DIRECTORY]

Recognized Python and TypeScript/JavaScript LLM integrations; gating requires a threshold flag or policy

Which Python dead code can Skylos remove?

skylos clean [PATH] --dry-run

Python import/function cleanup candidates; --dry-run never writes

Will this exact local GPU build fit the machines we ship to?

skylos preflight [ARTIFACT]

A local built file or directory and .skylos/gpu-targets.yml; an OCI reference is identity-only and returns UNKNOWN in the CLI

What vulnerabilities are in this container image?

skylos image scan IMAGE@sha256:<digest> --platform os/arch

A remote registry image scanned by a separately installed Trivy; --fail-on turns findings into a gate

Run skylos --help for this chooser, skylos <command> --help for one command, and skylos commands for the command-family map.

The report commands have different gate and network behavior:

  • image scan requires Trivy on trusted PATH and uses Trivy's remote image source, so registry network access and any required registry credentials must already be available. Without --fail-on, a completed scan exits 0 even when it reports vulnerabilities.

  • suite runs in the local process and does not upload unless --upload is set, but its dependency scan can query OSV. Findings are report-only: the command exits 0 regardless of their count. Operational and output failures are nonzero; --upload can also fail for an upload error or Cloud quality gate.

  • defend reports guardrail findings by default. It becomes a gate with --fail-on, --min-score, or gate settings in an explicit policy.

  • clean without --dry-run or --apply is interactive and can write after the final confirmation. Its current codemods support Python imports and functions. An apply pass still exits 0 if an individual edit prints a failure, so review the completion output.

  • done exits 0 on pass, 1 when a blocking check fails or does not finish, and 2 when Skylos could not run (for example, the base is not fetched). It reads its settings from the base commit, so a change cannot loosen its own gate.

Start In 60 Seconds

pip install skylos
skylos .            # find problems; your code and findings stay on your machine
skylos cloud        # optional: track results per branch on Skylos Cloud
skylos cicd init    # add a Skylos check to every pull request

That is the whole path. When skylos . finds issues, it ends by naming the next command.

skylos cloud runs every check, shows the findings, uploads them and prints this branch's quality gate with one link to it:

✗ Quality gate on feat/login: FAILED (was PASSED on 24 Oct 15:38 UTC, 1ba9895) · 1 critical security issue
  Open: https://skylos.dev/dashboard/projects/<project>?branch=feat%2Flogin
  Sent: findings and the Done receipt (fail) · laptop upload, unverified until CI runs the workflow
  Next: fix the issues behind the failed gate, then run skylos cloud again.

The first run opens your browser to log in and pick the project for this repo. It sends findings with file paths and code snippets of up to 7 lines (none for secrets), the branch, the commit, the git author email of each flagged line, and a map of your functions and classes (names, files, lines, sizes, which calls which). Not your repository. When the repository has a committed [tool.skylos.done] table (skylos setup writes it) and the working tree is clean, it also sends this commit's Done receipt, running skylos done first when there is none; the Sent: line says what reached Skylos Cloud. Uploads from a laptop are unverified until CI runs the workflow. It exits 0 even when the Skylos Cloud gate fails; add --gate to exit 1 (use that in CI). You never need a key to pass the gate: fix the issues that fail it. See Skylos Cloud for the other Cloud commands.

Before 4.47.2, pip install skylos also installs a Dart parser that builds from source and needs a C compiler. From 4.47.2, Dart support is the optional skylos[dart] extra. If the install fails for lack of a compiler, use the container image.

Optional Rust acceleration can be built from source. The standard installation uses Python fallbacks. See the build guide for accelerated operations and possible differences in findings.

The default scan focuses on dead code. Run every main source analyzer, including security, secrets, quality, dependency, and AI-defect checks, with -a:

skylos . -a

Check whether a branch, often an AI agent's, is really finished:

skylos done --base main

skylos done compares the branch with its merge base on main and runs your tests. It flags deleted or skipped tests, loosened test settings and CI test steps, silenced lint or type checks, and code that special-cases the tests, advises on code the branch left without callers (including in files it did not touch), then writes a receipt to .skylos/receipts/. When tests fail, it reruns them on the merge base and labels each failure "introduced" or "already failing"; every failure still blocks by default. It runs pytest automatically; other test runners need one test_command line in [tool.skylos.done]. See the done gate guide for every check and its limits.

Run only evidence-backed AI defect checks with:

skylos . --ai-defects

Verify a repository, file, or range before an agent hands it to review:

skylos verify . --file src/app.py --range 40:75 --project-context

For a directory such as ., the AI-defect scan covers the selected tree. The separate behavior result models supported Python working-tree changes against Git HEAD; it is not the scope selector for the AI-defect scan. Dependency hallucination checks are enabled for path targets and can query package registries; use --no-dependency-hallucinations to disable those lookups. High/critical security findings (category: "security") and hard-coded secrets (category: "secret", value redacted) in the selected file/range also fail verification; use --no-security for the AI-code-only verdict. Interactive terminals get a human report. Redirected stdout and -o produce the versioned JSON result.

skylos verify schema version 2 returns pass, fail, or incomplete. incomplete means a requested proof could not be established, such as a missing local TS/JS import, computed namespace member, unsupported language-local API check, or parser surface that Skylos could not prove; it exits 2 unless --no-fail is set. The coverage object lists detected languages, expected checks, language support, missing checks, completed/skipped checks, checked references, and deterministic skip reasons. Declared third-party dependencies and recognized Node built-ins are outside the local TS/JS API proof; their references are counted in out_of_scope_references and do not make a clean verification incomplete. Unknown bare imports still require review.

Deterministic local/workspace API verification currently covers Python, TypeScript/JavaScript, Go, and Java without executing target code. PHP, Rust, Dart, C#, Kotlin, C++, and Shell retain their existing static-analysis coverage, but their local API proof is reported as unsupported and therefore incomplete. See AI Code Verification Coverage.

Create a local AI hallucination contract for repo-specific generated-code truth. skylos verify auto-discovers .skylos/ai-contract.yml:

skylos contract init
skylos contract inspect
skylos verify .

Test a running agent against deterministic response and tool-use scenarios:

skylos agent init
skylos agent test --allow-contract-endpoint

Create a project config with thresholds, ignores, and vibe dictionary extensions:

skylos init

Create a starter local rule pack:

skylos rules init
skylos rules validate .skylos/rules/local.yml
skylos rules list --json
skylos rules list cross --json
skylos rules list --packs --json
skylos cache stats

Scans with --quality or -a apply every .yml/.yaml pack in a .skylos/rules/ folder from the scanned file up to the repository root (the nearest pack wins for a rule ID). In PR CI, as with [tool.skylos], the packs come from the base branch, so a pull request cannot drop or edit the rules its own gate runs. A pack that cannot be read is skipped with a warning naming it.

Gate pull requests with GitHub Actions. No Skylos account or token is needed:

git checkout -b add-skylos-gate
skylos cicd init --no-upload
git add .github/workflows/skylos.yml
git commit -m "Add Skylos pull request gate"
git push -u origin add-skylos-gate
gh pr create --fill

The generated workflow reviews changed lines on pull requests and adds a skylos done job when it finds your tests. With --upload (the default once this machine is logged in with skylos login), it also uploads to Skylos Cloud with GitHub OIDC: pushes to your default branch, and pull requests to it, which Cloud then lists with their check and comment. A pull request is scanned as untrusted data in a job with no credentials and uploaded by a job that never checks out its files. Uploads fail until the Skylos GitHub App is installed on the repository. Your first Skylos-gated pull request walks through it in about 8 minutes, including making the checks required.

On GitLab CI, Jenkins, Bitbucket Pipelines, Azure Pipelines or CircleCI, the same skylos cicd init sets up a pull request gate for that CI instead; see Skylos on any CI.

The gate (skylos . --gate, skylos cicd gate, and the generated workflow) fails on any critical security issue, any secret, and any critical AI-code issue, such as an import of a package that does not exist on PyPI (SKY-D222) or a call to a function that is never defined or imported (SKY-L012). Other findings fail it only above count limits. Change the limits under [tool.skylos.gate] in pyproject.toml:

[tool.skylos.gate]
max_high = 5          # high-severity security issues allowed
max_quality = 10      # quality issues allowed
max_ai_defects = 10   # AI-code issues allowed (defaults to max_quality)
# AI-code issues at these severities fail the gate whatever max_ai_defects
# allows. Add "HIGH" to block more; [] turns the rule off.
block_ai_defect_severities = ["CRITICAL"]

max_ai_defects and block_ai_defect_severities are separate checks; the gate fails if either one fails. In a pull request, skylos cicd gate --diff-base reads this policy from the base branch, so a pull request cannot turn the rule off for itself. A gate policy synced from Skylos Cloud replaces the repository's [tool.skylos.gate] section, and the gate then checks what the Cloud gate checks: its mode (zero new issues, limits per category, per severity, or both) and its limits, which the verdict line prints. Skylos Cloud counts only new issues, so check a branch with skylos . -a --gate --diff origin/main; a full scan prints a line saying so. The .skylos/config.yaml that skylos sync pull writes applies to --diff gates while it is not committed; a copy committed only on the branch does not. A Cloud gate that is turned off leaves the built-in limits. max_critical, max_secrets and fail_on_critical = false cannot loosen the critical-issue and secret rule; a gate run prints a warning when they try, and for a rules entry that is not a rule ID.

Every gate run ends with one verdict line and the reasons behind it: Quality Gate: PASSED, Quality Gate: FAILED (exit 1), or Quality Gate: INCOMPLETE — could not decide (exit 2) when required analysis did not finish, for example a lockfile the dependency scan could not resolve. Each reason names the check that stopped, how many files or dependencies it missed, and what to change. A file that does not parse is a coverage warning under the verdict, not a reason to stop: the limits are evaluated on everything else (set require_complete = true under [tool.skylos.gate.coverage] to fail instead). --format json carries the same verdict in a top-level gate object; concise, LLM, GitHub, and GitLab output print it on stderr. See Exit Codes And Incomplete Analysis.

Need more commands? Read the CLI Reference.

Check Every Agent Edit (Claude Code, Codex, Cursor)

Install local hooks so the agent is checked while it works, not after. skylos setup installs the Claude Code and Codex hooks for a repository; the commands below install one agent at a time, or Cursor:

skylos agent install-hooks            # Claude Code (.claude/settings.json)
skylos agent install-hooks --codex    # Codex (.codex/hooks.json)
skylos agent install-hooks --cursor   # Cursor (.cursor/hooks.json)
  • After each edit: verifies only the changed lines (security, secrets, AI-code mistakes) and tells the agent what to fix.

  • Before a file read: blocks files that contain hard-coded secrets.

  • Before a package install or one-shot run (pip, uvx, npx, pnpm dlx, bunx, go run pkg@v, ...): blocks hallucinated or typosquatted packages, versions reported as malware (OSV, with the ca9 feed offline), releases younger than 48 hours (naming the older version to use instead) and npm releases that lost their provenance. npm ci, uv sync, pip install -r and other lockfile installs get the malware check over every locked package. It asks before installs it cannot verify (git and URL sources, unknown registries, failed lookups). Change the wait with [tool.skylos.supply_chain] min_release_age_hours (0 turns it off).

  • MCP servers and agent hooks: the agent hook blocks unpinned or malicious MCP servers (claude mcp add, .mcp.json edits) with the exact pinned command to use, asks before new SessionStart or folderOpen hooks, and re-checks configured servers each session.

  • skylos agent harden prints each agent's own credential-deny and pinned-MCP settings (policy and audit, not a sandbox).

  • Before a git command: blocks --no-verify, HUSKY=0 and other ways around the repository's git hooks.

  • At stop: blocks "done" while issues the agent added are still open.

Hooks fail open, but never silently: if Skylos errors, the agent and you are told the action was allowed without a check, and stop reports how many went unchecked. They log to .skylos/hook.log and merge with your existing hooks. --uninstall removes only the Skylos entries. See Agent-loop hooks for the contract, latency, and limits.

In Cursor, findings arrive at stop rather than after each edit. The hooks are not a sandbox: they check edits, file reads and package installs, not every command. See what they don't do.

Cleanup workflow

Use skylos cleanup to prioritize existing quality, AI-code and dead-code findings, retain local task history, and preview a supported patch before applying it:

skylos cleanup . --next
skylos cleanup . --task TASK_ID
skylos cleanup . --task TASK_ID --apply --test-cmd "pytest -q test/test_orders.py"

Source edits require --apply; tests run only with --test-cmd. A change stays applied_unverified when tests were skipped. --context adds bounded source context; optional --review sends it to your configured model as advisory review. Cloud's Cleanup tasks panel groups saved findings and connects existing issue ownership, work status and outcome notes. See Cleanup for supported edits, receipts, exclusions and limits.

Common Workflows

Goal

Command

What You Get

More Detail

First dead-code scan

skylos .

Finds unused functions, classes, imports, files, and framework entrypoint mistakes

Dead code docs

Deterministic cleanup preview

skylos clean . --dry-run --types import,function --confidence 80

Shows planned Python import/function removals without writing; add --apply to edit files

Dead code docs

Security and quality audit

skylos . -a

Adds dangerous flow, secrets, dependency, config, quality, and AI-defect checks

Security docs

AI double-check of issues

skylos . -a --ai-review

Unused-code issues in every language and security issues in Python files get an AI verdict: confirmed, AI disagrees, or unsure. Uses your model key, plus Jev when TYPESAFE_API_KEY is set. Nothing is hidden and blocking never changes; with skylos cloud --ai-review the verdicts show on the Cloud PR board and Issues

AI review

One-page report to share

skylos report .

Writes skylos-report.html: the verdict ("Not ready: 1 blocking issue"), the five risks to fix first with one-line fixes and docs links, counts by category, suppressed counts and what the scan did not cover; nothing is uploaded

CLI output modes

Combined repo report

skylos suite .

Reports static findings, technical debt, AI app safety, and provenance; SCA can query OSV, and findings alone exit 0

CLI Reference

Optional Python linting

pip install "skylos[lint]" && skylos lint .

Runs Ruff with its native configuration, output, fixes, and exit codes through the Skylos CLI

Python linting

Agent branch done check

skylos done --base origin/main

Runs your tests and flags deleted, skipped or weakened tests, loosened test settings and CI test steps, silenced checks, and test-only special cases; writes a receipt

Done gate

Change map for review

skylos done map --base origin/main

Old and new code of each changed Python or TypeScript/JavaScript function, calls added and removed, who calls it and whether those callers were updated, removed auth checks, breaking signatures, and what to read first, read, skim or skip, with a count of the changed lines a person has to read; --format json for a review agent. The pull request comment from skylos cicd init shows what to read first, and the Skylos Done check's summary has the full map

Change map

MCP change map

change_map MCP tool

Gives a review agent the change map as JSON before it reads the diff, including what to read first, read, skim and skip. Needs no Skylos API key and has no daily limit; the map is built on your machine

Change map

Codebase graph

skylos graph open

Every Python and TypeScript/JavaScript function and class (Go, Java, Rust and PHP as a first pass, calls matched by name), grouped into areas, what calls what, tests and their expected outputs, in a local browser view; marks changed code and says whether its logic is still the same (only claimed when proven). Plain-English descriptions come from your coding agent or your own model key; skylos graph show/impact --format json and the graph_* MCP tools (no key needed) give agents the same answers

Codebase graph

Risks that need a human approval

skylos cicd risk-review --base origin/main

Lists deleted or weakened tests, removed auth checks, added or changed dependencies, weakened CI, silenced checks, added secrets, guardrail setting edits, migration changes and very large diffs. As a required GitHub check (skylos cicd init --risk-review) it fails until a person with write access approves the head commit; bot approvals do not count. While it waits it labels the pull request skylos:needs-human, so is:pr is:open label:skylos:needs-human lists every pull request that needs a person

Risk review

PR gate

skylos cicd init --no-upload

Sets up the pull request gate for your CI. On GitHub Actions it writes a workflow that gates pull requests, runs skylos done when your tests can run and posts one comment per pull request (verdicts, what blocks, what to read first); add --upload (the default once you are logged in to Skylos Cloud) to also upload default-branch scans to Skylos Cloud with GitHub OIDC, and that job fails until the Skylos GitHub App is installed on the repository. GitLab CI, Jenkins, Bitbucket Pipelines, Azure Pipelines and CircleCI get a gate for that CI

First gated PR, Skylos on any CI

GitLab merge request report

skylos . --format gitlab -o gl-code-quality-report.json

Exports a native Code Quality report for GitLab CI artifacts

GitLab Code Quality

Offline dependency SBOM

skylos sbom . -o sbom.cdx.json

Lists supported recorded dependencies as CycloneDX 1.6 JSON without network requests

Dependency scanning

SPDX SBOM + license policy

skylos sbom . --format spdx-json / license_deny = ["GPL-*"]

SPDX 2.3 JSON with declared licenses; SKY-SCA-LIC001 flags denied licenses in -a scans

License compliance

Signed verdict deploy gate

skylos verify-verdict verdict.json --commit "$SHA" --repository github.com/org/repo --require-repository-verified --require-trusted-upload --max-age 7d --require-passed

Verifies a Skylos Cloud check verdict offline (Ed25519 DSSE, in-toto/SLSA) and fails unless it is a recent policy pass for that commit and repository; needs skylos[verdict]

Verify a signed verdict

Readable terminal report

skylos . --format pretty

Groups findings by file with severity badges, snippets, and copyable file:line locations

CLI output modes

Single-rule review

skylos . --select SKY-L012 --format concise

Enables the matching analyzer family and reports only that exact rule with its full message

CLI output modes

Selectable terminal triage

skylos . --tui

Opens a keyboard-driven category list, finding list, and detail pane

CLI output modes

IDE/test-script output

skylos --format concise src/test.py

Prints untruncated file:line RULE_ID message findings and exits non-zero when findings exist

CLI Reference

In-loop AI-code verification

skylos verify . --file src/app.py --range 40:75

Reports a narrow set of hallucinated helpers, unfinished code, stale references, disabled controls, and API/dependency hallucinations; JSON is used for redirected or -o output

AI features

AI hallucination contracts

skylos contract init && skylos verify .

Auto-discovers .skylos/ai-contract.yml and verifies generated code against repo-specific symbols, dependencies, APIs, route guards, and test requirements

AI Hallucination Contracts

Changed-lines review

skylos . -a --diff origin/main

Keeps findings focused on active work instead of legacy debt. A removed security control (SKY-L021, such as a deleted auth decorator) is still reported, even when the change only deletes the decorator line

Quality gate docs

Incumbent scanner comparison

skylos compare . --against incumbent.sarif

Runs Skylos beside the current scanner and produces a revision-aware scorecard: active overlap, raw unique findings by category, and eligible findings inside evidence-backed unused symbols, without replacing the current gate

Scanner comparison

Runtime-assisted dead-code check

skylos . --trace

Uses runtime traces to reduce dynamic-code false positives

Smart tracing

Local rule pack

skylos rules init

Scaffolds .skylos/rules/local.yml, project-specific YAML checks that --quality and -a scans apply

Custom rules

Security agent quick scan

skylos agent security-quick .

One-shot LLM security audit; compatibility alias for skylos agent scan . --security

AI features

Security agent deep scan

skylos agent security-deep .

Three-stage security workflow with threat-model context, static threat traces, discovery/validation, and remediation handoff

AI features

AI-assisted review

skylos agent scan .

Static analysis plus optional LLM review and fix suggestions

AI features

Agent harness replay

skylos agent replay .skylos/runs/<run-id>

Validates and summarizes saved agent verification phases, tool calls, decisions, and budgets

Agent harness artifacts

Runtime agent behavior test

skylos agent init && skylos agent test --allow-contract-endpoint

Checks final responses, tool selection, explicit refusals, and source IDs against a versioned contract

Agent Behavior Testing

Verification-backed remediation

skylos agent remediate .

Scans and fixes supported findings, then re-scans them and records proof-test metadata when available

AI features

Agent-loop hooks

skylos agent install-hooks [--codex|--cursor]

Verifies every agent edit, blocks secret reads, hallucinated, malicious and too-new package installs and git-hook bypasses, asks before unverifiable installs, and holds "done" while new issues are open

Agent-loop hooks

Project standards for agents

skylos agent install-standards --enforce SKY-L002

Gives Codex, Claude Code, and Cursor a project skill and selects measurable quality rules for hook and CI checks

Project standards

MCP agent verification

verify_change MCP tool

Lets Claude, Cursor, and other MCP clients verify an edited file/range with the same schema as skylos verify. Requires a free Skylos project token (SKYLOS_API_KEY). skylos verify and agent-loop hooks need no token

MCP server

LLM integration inventory

skylos discover .

Maps recognized LLM calls, agent tools, prompt sites, and input sources in Python and TypeScript/JavaScript

Agent verification

AI app safety

skylos defend . --format md -o evidence.md

Verifies agent guardrails, scores OWASP LLM/Agentic coverage, and emits an attested evidence report

Agent verification

Agent verification CI gate

skylos defend . --fail-on critical

Blocks deploys with unguarded LLM integrations; SARIF for code scanning via --format sarif

Agent verification

MCP agent pre-flight

verify_agent MCP tool

Lets coding agents statically verify the agents they build — scores, failed checks, attestation digest. Requires a free Skylos project token (SKYLOS_API_KEY). skylos defend needs no token

MCP server

Technical debt triage

skylos debt .

Ranks hotspots and debt trends

Technical debt

What Skylos Catches

Category

Examples

Why It Matters

Dead code

unused functions, classes, imports, package entrypoints, route handlers

reduces maintenance cost without breaking dynamic frameworks

Security flaws

SQL injection, XSS, SSRF, path traversal, command injection, unsafe deserialization

catches exploitable flows before code reaches main

Secrets

API keys, tokens, private credentials, high-entropy strings

prevents credentials from leaking through commits and PRs

CI/CD workflows

GitHub Actions and GitLab CI dangerous triggers, unpinned actions/includes, broad tokens, OIDC misuse, cache poisoning, mutable images

reduces CI/CD supply-chain risk before release jobs run

Edge deployment config

Docker Compose privileged device access, host networking, systemd root services, broad capabilities, missing sandboxing

catches repo-controlled settings that turn app bugs into device compromise

Kubernetes deployment exposure

Explicitly external Ingress paths reaching a sensitive FastAPI/Flask route without its deployment-required guard, Flask --debug, or an application server using --reload

reports only when the resources are in one rendered bundle and every deployment edge resolves unambiguously

GPU release compatibility

source/build contract mismatches plus built-artifact identity, selected CUDA architecture, packaged runtime, and fleet checks

catches declared intent errors early and verifies the resulting local artifact before release

Quality regressions

complexity, deep nesting, duplicate branches, long functions, inconsistent returns

keeps AI-assisted refactors from adding brittle code

AI code mistakes

phantom security calls, missing decorators, unfinished stubs, disabled controls, real packages called with invented APIs, impossible npm/Go versions

catches common hallucinated or incomplete code paths before they reach review

LLM app risks

unsafe tool use, prompt injection exposure, missing output validation, missing rate limits

helps teams ship AI features with guardrails

See the full Rules Reference.

Dependency licenses

skylos sbom . writes declared dependency licenses into CycloneDX, and skylos sbom . --format spdx-json writes an SPDX 2.3 SBOM. Licenses come from lockfiles and installed package metadata, offline. Unknown or ambiguous values (such as BSD) stay NOASSERTION rather than being guessed. --license-lookup opts in to a deps.dev query. To block licenses in -a scans, set a policy:

[tool.skylos]
license_deny = ["GPL-*", "AGPL-3.0-only"]
license_severity = "HIGH"

Violations are reported as SKY-SCA-LIC001. See License compliance.

Give Coding Agents Project Standards

Create .skylos/standards.md with the guidance you want agents to follow:

# Coding standards

- Keep functions focused and handle exceptions explicitly.
- Add a focused test when changing behavior.

Then install the project skill and choose any Skylos quality rules to enforce:

skylos agent install-standards --enforce SKY-L002
skylos agent install-hooks --codex   # use --cursor for Cursor, or omit for Claude Code
skylos agent check-standards .       # run this project-wide check in CI

The installer writes SKILL.md files for Codex, Cursor, and Claude Code. Agent skills provide guidance; the hooks and project-wide check enforce the selected built-in quality rules. See project standards for the generated files, rule selection, and coverage limits.

Verify AI Agents Before They Ship

Runtime guardrails are the WAF; Skylos is the SAST. skylos discover scans Python and TypeScript/JavaScript for recognized LLM integrations (provider SDKs, agent frameworks including the OpenAI Agents SDK, Claude Agent SDK, and Google ADK, MCP servers and their tools, direct HTTP calls to LLM APIs or OpenAI-compatible gateways, plus agent tools, prompt sites, and input sources). skylos defend checks the guardrails around those detected integrations deterministically, in the local process, with no model in the loop. It emits evidence by default and becomes a CI gate only when a threshold flag or policy supplies gate criteria.

skylos discover .                               # inventory LLM integrations and agent tools
skylos defend .                                 # score guardrails (13 weighted checks)
skylos defend . --format md -o evidence.md      # auditor evidence report + attestation
skylos defend . --format sarif -o defend.sarif  # GitHub code scanning upload
skylos defend . --fail-on critical              # CI gate: exit 1 on critical gaps
skylos defend . --owasp-framework agentic       # report against OWASP Agentic ASI Top 10

These commands do not inspect integrations in other languages. If discovery finds no supported integration, defend returns an empty inventory; do not treat the resulting score by itself as proof that an unsupported or unrecognized agent implementation has guardrails.

Per integration it verifies: dangerous output sinks (eval/exec/subprocess), agent tool scope and typed schemas, prompt-injection exposure (delimiters, untrusted input paths, RAG context isolation), output validation, PII filtering, and model pinning — plus ops checks (logging, cost controls, rate limiting) scored separately so they never inflate the security score.

  • OWASP mapping: LLM Top 10 (2024/2025) and Agentic ASI Top 10 (2026).

  • Evidence report (--format md): integration inventory, per-check results, OWASP coverage, regulatory framework evidence (EU AI Act, NIST AI RMF, ISO/IEC 42001 — "evidence toward" mappings, never compliance claims), and a remediation appendix.

  • Attestation: JSON/md/SARIF reports carry a reproducible SHA-256 digest over file contents, policy, plugin set, integration inventory, scores, and full check evidence — re-run on the same tree with the same flags and Skylos version, and the digest must match.

  • CI-native: skylos cicd init --defend generates the GitHub Actions workflow step, the skylos-defend pre-commit hook gates locally, and $GITHUB_STEP_SUMMARY gets a score summary automatically in Actions.

  • Policy as code: skylos-defend.yaml pins gate thresholds and severity overrides (--policy).

  • Agent-native: the verify_agent MCP tool lets coding agents verify the agents they build — deterministic verification, not AI checking AI.

Static pre-deployment verification complements runtime controls (gateways, policy engines, human approval flows); it does not replace them. Full guide: docs/agent-verification.md.

Test Running Agent Behavior

Skylos separates generated-code truth, static agent guardrails, and observed runtime behavior:

Command

Verification question

skylos verify

Did the agent generate valid, non-hallucinated code?

skylos defend

Does the agent implementation contain the required guardrails?

skylos agent test

Did the running agent behave according to its contract?

Create .skylos/agent-test.yml, then test a live OpenAI-compatible endpoint:

skylos agent init
skylos agent test --allow-contract-endpoint

Or evaluate captured evidence without a network call:

skylos agent test --observations agent-observations.json
skylos agent test --observations agent-observations.json \
  --format json --output agent-results.json

Version 1 deterministically checks exact response substrings, required, allowed, and forbidden tool calls, tool arguments and sequence, maximum call count, explicit refusals, and explicit source IDs. Missing typed evidence is incomplete, never pass; exit codes are 0 pass, 1 violation, and 2 incomplete/invalid. Tool selection and final-answer source-ID checks are separate one-turn scenarios: Skylos records local replayable evidence but never executes tools returned by the target agent. Offline observations are marked as unverified fixtures rather than runtime proof.

For an authenticated remote endpoint, keep the destination and secret choice in the trusted CLI invocation:

skylos agent test --endpoint https://agent.example.com/v1/chat/completions \
  --allow-remote --auth-env MY_AGENT_API_KEY

Full guide: docs/agent-behavior-testing.md.

How Skylos Fits

Skylos is not a replacement for every specialized scanner. It is a local-first repo and PR checker that puts several common review checks behind one CLI.

  • Framework-aware dead code detection: FastAPI, Django, Flask, pytest, SQLAlchemy, Next.js (App/Pages Router files and metadata routes), React, Laravel (auto-discovered commands, listeners, components, factories, seeders), Drupal (classes named in an extension's YAML, discovered plugins, OOP hooks, procedural hooks in .module/.install/.inc/.theme files, post-update functions), tool config files, package entrypoints, and common plugin patterns.

  • PR-focused output: diff scanning, CI thresholds, GitHub annotations, and baselines for existing findings.

  • Local-first operation: core analysis executes locally and does not upload source or call an LLM. Dependency/CVE checks can query OSV or package registries, and direct container scanning contacts a registry through Trivy. See What Leaves Your Machine.

  • AI-assisted change review: checks for removed validation, auth, logging, CSRF, rate limiting, timeouts, real-package API hallucinations, and other guardrails in generated or edited code.

  • Agent-loop verification: skylos verify and MCP verify_change use a versioned result schema for AI-code trust, security, and secret findings, so coding agents can self-correct before a human sees the change. The CLI renders a human report on a terminal and JSON when redirected or written with -o.

  • Evidence-backed AI defects: --ai-defects and full scans put strict AI-code failure checks under ai_defects, including phantom references, fake package APIs, nonexistent packages, impossible dependency versions, and weakened test assertions. The category/tag is ai_defect; several rules intentionally keep historical SKY-L or SKY-D IDs for suppression and baseline compatibility, while new AI-defect-only checks use SKY-A.

  • Verification-backed remediation: security fixes are checked by re-running analysis, and supported findings can include targeted regression-test proof metadata.

  • Project-specific rules: add local YAML rules and extend prompt, credential, sensitive-file, and timeout dictionaries from config.

  • One command surface: dead code, security, secrets, dependency, quality, technical debt, agent review, and pre-deployment agent verification commands share the same CLI.

What Leaves Your Machine

Skylos sends nothing to Skylos Cloud unless the command or flag you ran says it talks to Skylos Cloud: skylos cloud, --upload, skylos login, whoami, project, sync, credits, upload, ingest claude-security, verify-verdict, feedback, or the --verify scan option. A token on its own (SKYLOS_TOKEN, a saved skylos login, a CI OIDC token) never makes a command upload a scan, findings or a run summary. There is no update check and no analytics.

  • --ai-review and --verify-security never send anything to Skylos Cloud by themselves. They send the flagged file (comments removed) and the rule's message to your own model provider with your key. With TYPESAFE_API_KEY set, --ai-review also sends the unused-code candidates and a bounded copy of your first-party source (at most 64 KB) to Jev (api.typesafe.ai). The verdicts reach Skylos Cloud only with --upload or skylos cloud.

  • skylos agent verify, agent remediate and agent remediate --standards send a run summary only with --upload, and skylos agent scan --upload sends the same summary plus its findings: one POST /api/agent-runs with command, per-command counts, model, provider, duration_seconds, commit_hash, branch, actor and status. actor is SKYLOS_ACTOR, the CI-reported user, or the HEAD commit's author, else null; never your operating-system user name. No source, paths, finding text, prompts or model output.

  • Three things reach Skylos Cloud without such a command, and none sends code or findings: a scan downloads your Cloud custom rules when a token can be found (SKYLOS_CUSTOM_RULES='[]' skips it); skylos doctor checks your credit balance (--format json skips it); and the MCP server started with SKYLOS_API_KEY checks the key every 15 minutes and asks Skylos Cloud to charge each scan or remediate call. Only remediate costs credits (10 a call), and only when it calls a model; dry runs send no charge request.

  • skylos feedback makes no request itself: it opens a form on skylos.dev (or, with --github, GitHub's issue form) in your browser. The page address carries the Skylos version, OS, Python version and the last failed command with paths and secrets masked; your message is sent only when you press Send.

  • Package lookups on other hosts send package names and versions, never source: OSV for dependency checks, and PyPI, npm, the Go proxy and JSR for packages that don't exist (on by default in skylos done, skylos verify, agent scan, agent pre-commit and the agent hooks). Dependency checks can also fetch GitHub fix commits, with GITHUB_TOKEN if it is set. LLM commands send code excerpts to the model provider you configure, and skylos cicd review posts PR comments through gh.

Every request, its trigger and its off switch: docs/privacy-and-network.md.

Agent Harness Artifacts

skylos agent verify . and skylos agent test record replayable artifacts under .skylos/runs/<run-id> and print the run directory in table output. JSON output includes the same harness summary under the harness key.

Use skylos agent replay .skylos/runs/<run-id> to validate and inspect a saved run without making LLM calls. Add --format json when another agent or CI job needs machine-readable status. A valid replay exits 0; an invalid or corrupt artifact set exits 1 with issue codes. Replay output includes schema_version so CI and agents can detect artifact-contract changes. Replay checks internal consistency and corruption; artifacts are not signed and are not proof against an actor that can rewrite the entire run directory.

Each run directory contains:

  • events.jsonl: chronological run, phase, and tool-call events.

  • state.json: full observable state, including phases, tool calls, decisions, and budget usage.

  • summary.json: compact status, counts, budget, and artifact paths.

  • behavior-results.json: normalized runtime assertions, provenance, coverage, and a digest-bound evidence report for skylos agent test runs.

The current harness state is observable and replay-validated. It is not yet a resume mechanism for continuing interrupted verification runs.

Install Options

# Core static analysis
pip install skylos

# LLM-powered agent workflows
pip install "skylos[llm]"

# Ruff Python linting through `skylos lint`
pip install "skylos[lint]"

# Ed25519 verification for `skylos verify-verdict`
pip install "skylos[verdict]"

# Dart analysis, 4.47.2 and later (builds the Dart parser from source; needs a C compiler)
pip install "skylos[dart]"

# All published optional extras
pip install "skylos[all]"

Container image:

docker pull ghcr.io/duriantaco/skylos:latest
docker run --rm -v "$PWD":/work -w /work ghcr.io/duriantaco/skylos:latest . --json --no-provenance

The unqualified image uses Python 3.14. Runtime-specific tags are also published for Python 3.11 through 3.15, so container scans can match a local or CI parser exactly:

docker run --rm -v "$PWD":/work -w /work ghcr.io/duriantaco/skylos:latest-python3.15 . --json --no-provenance

If a Python file cannot be parsed, Skylos names it as not analysed, marks coverage incomplete, and reports every other finding; the file is never treated as clean. The exit code is decided on the code that was analysed; --strict exits 2 instead, and so does a scan where most of the code could not be analysed. See Exit Codes And Incomplete Analysis.

See Installation for source installs, container usage, and optional dependencies.

Configure Vibe Checks And Entrypoints

Run skylos init to add these sections to pyproject.toml:

[tool.skylos]
exclude = ["node_modules", "dist"]

[tool.skylos.vibe]
extra_phantom_names = ["verify_enterprise_auth"]
extra_phantom_decorators = ["tenant_admin_required"]
extra_credential_names = ["tenant_signing_secret"]
extra_network_timeout_calls = ["vendor_sdk.fetch"]

[tool.skylos.dead_code]
entrypoints = []

[[tool.skylos.dead_code.entrypoints]]
type = "method"
name = ["create", "pre_hook", "post_hook"]
parent = { name = "Main", base_classes = ["Application"] }
path = "src/**"
reason = "project framework lifecycle hook"

[tool.skylos.contribution]
collect_local_signals = false
contribute_public_corpus = false
structural_signatures_only = true
include_source = false

LLM prompt templates are not read from the repository: pass a trusted file with --prompt-template KIND=PATH to skylos agent scan, agent audit, agent security-quick or agent security-deep (KIND is security, quality, security_audit or review). A template extends Skylos' built-in prompt; it does not replace the JSON-only output contract or untrusted-code safety rules. Vibe dictionary extensions let teams teach Skylos about local fake-auth helpers, project credential names, sensitive files, and network calls that must set timeouts. Dead-code entrypoints let teams mark proprietary framework classes, lifecycle methods, and decorator-registered functions as live using precise rules for type, name, path, decorators, base classes, and parent classes. Rules must include a symbol selector such as name, decorators, base_classes, or parent; path and module only narrow the match. Contribution signals are off by default; when enabled, Skylos records local structural accept/dismiss/learn events under .skylos/contribution/ without raw source.

Where settings come from. Skylos walks up from the scan path to the repository root (the folder with .git) and reads, in each folder, the first of these that exists:

  1. .skylos.toml

  2. skylos.toml

  3. pyproject.toml with a [tool.skylos] table (a pyproject.toml without one is skipped, so it no longer hides the settings above it)

skylos.toml takes the same keys as [tool.skylos], at the top level, so TypeScript, Go and Java repositories need no pyproject.toml:

# skylos.toml
exclude = ["generated", "dist"]

[gate]
max_security = 0

[done]
test_command = "npm test"

In a monorepo every file found on the way up applies: the repository root is the base and the file nearest the scanned folder wins per key. A key set in a package replaces the root's value (lists are replaced, not concatenated); tables such as [gate] merge key by key. Set root = true in a package's file to ignore everything above it. skylos doctor lists the files in use, nearest first, and the ones it ignored. In PR CI, settings come from the base commit only, with the same rules, and skylos done reports an added or edited skylos.toml as a change to Skylos settings (SKY-A114). [done] and [approval] settings are read from the repository root's file.

To use one file instead of discovery, pass --config-file PATH or set SKYLOS_CONFIG_FILE; it may use [tool.skylos], [skylos], or (when named skylos.toml) top-level keys. Synced Skylos Cloud policy keeps its protected precedence over repository-controlled config. The top-level [tool.skylos].exclude list applies to the main scan and commands such as skylos debt and skylos clean; pass --exclude for command-local additions or --include-folder to override an excluded folder.

A full scan skips generated and vendored files (Django migrations, static/**/lib/**, *.min.js, *.min.css, vendored-library banners) and says how many in one line of output. Set include_generated = true under [tool.skylos] (or pass --include-generated) to scan them; see What a full scan leaves out.

Language Support

Language

Dead Code

Security

Quality

Local API Proof (verify)

Notes

Python

Yes

Yes

Yes

Supported

strongest coverage; framework-aware static analysis and optional tracing

TypeScript / JavaScript

Yes

Yes

Yes

Supported

Tree-sitter parsing, package graph reachability, framework conventions

Java

Yes

Yes

Yes

Supported

Tree-sitter parsing, structured security-flow analysis, conservative static-member proof

Go

Yes¹

Partial¹

Partial

Supported

native engine status remains separate from deterministic workspace API proof

PHP

Yes

Yes

No

Unsupported

PHP parser coverage, type and docblock references, Laravel and Drupal conventions (including .module/.install/.inc/.theme files); security follows request data (superglobals, Laravel/Symfony/PSR-7/CodeIgniter requests, Drupal Form API) within one function or file into exec/system/backticks, eval/include, echo/print/<?= ?> and Blade {!! !!} XSS by HTML context, SQL (mysqli, PDO, $wpdb, Laravel DB::raw/whereRaw, Doctrine DBAL), SSRF, unserialize, file paths, Drupal Markup::create() and inline Twig; not across functions or files, and not Twig templates

Rust

Experimental⁴

Partial

Partial

Unsupported

Rust parser coverage; command/path security checks, direct unreachable statements and duplicate branch bodies

Ruby

Partial

Partial

No

Unsupported

Tree-sitter parsing; private helpers, exact owner calls and literal Rails controller callbacks; explicit Kernel.system/exec/spawn command checks; see limits below

Dart

Yes³

Partial³

No

Unsupported

Dart parser coverage; security covers command injection, path traversal and SSRF

C#

Partial

Partial

Partial

Unsupported

C# symbols, direct-block unreachable code, ASP.NET-aware security (request sources, receiver-typed sinks, unsafe deserialization, XSS), and NuGet inventory (.csproj pins and packages.lock.json)

C++

Partial

No

No

Unsupported

conservative unused file-local functions in .cpp, .cc, .cxx; C++ headers are parsed for references

Kotlin

Partial²

Partial²

No

Unsupported

lexical symbol extraction; reports only private declarations and imports; Spring, Ktor, servlet and Android WebView security checks

Swift

Partial

No

No

Unsupported

private/fileprivate declaration reachability, owner and lexical bindings, callbacks and call cycles; runtime and unknown compiler contexts retain conservative handling

Shell

No

Partial

No

Unsupported

shell-script security checks for command injection, SSRF, and path traversal

¹ Go dead-code and security checks need the native skylos-go engine. From 4.50 the PyPI wheels for Linux, macOS and Windows (x86_64 and arm64) include it; the container image includes it and the official GitHub Action builds it. Elsewhere, skylos doctor prints the command that builds it. Without it only Go quality checks run and the Go files are reported as not analysed; see the Go engine note below.

² Kotlin dead code reports only private types and functions and unused imports; every non-private declaration is treated as used. Any use in code counts: type positions, ::foo, trailing-lambda and infix calls, string templates and KDoc links; operator-convention imports (getValue, plus, component1) are never reported. Kotlin security is lexical (no Kotlin parser): see the Kotlin paragraph below. Secret scanning covers .kt and .kts.

³ From 4.47.2, Dart checks need the optional skylos[dart] extra (pip install "skylos[dart]"); earlier releases install the Dart parser by default. The parser has no prebuilt wheels, so installing it needs a C compiler. Without it, a scan that includes .dart files reports them as not analysed (SKY-ANALYSIS-INCOMPLETE, incomplete coverage) instead of skipping them silently; skylos doctor shows whether Dart support is installed.

⁴ Rust dead code is experimental: general trait-method calls, pub items used across crates, re-exports, macro expansion and #[bench] functions are not resolved, and a previous hand-checked sample on ripgrep found no true positives. Rust candidates are capped at confidence 40, below the default threshold, so they are not listed unless you pass --confidence 40; the scan says so in one line. rustc's own unused_imports and dead_code lints cover private items.

Rust can prove selected local trait uses across ordinary, fully scanned source modules and keep repeated import aliases distinct. Cargo features, attributed module paths and general compiler type resolution remain outside that proof.

Rust quality checks cover statements after a direct return, break or continue, and duplicate multi-statement if/else bodies with a plain boolean condition. They do not expand macros or infer complete control flow.

Inline suppression works the same way in every language above: put skylos: ignore[SKY-D211] reason (only the named rules), skylos: ignore (every rule) or a skylos: ignore-start … skylos: ignore-end block in a comment on the finding's line (# in Python, Shell, PHP and Ruby; // or a one-line /* */ in the others). It covers dead code, security, quality and secrets; text inside a string literal never counts, and other tools' markers (#nosec, //nolint, NOSONAR, @SuppressWarnings) do not hide Skylos findings.

--secrets also reads shell scripts (including extensionless ones that start with a shell #! line), C and C++ sources and headers, Dockerfiles, Terraform .tf/.tfvars/.hcl, .properties, XML, Gradle, .npmrc and .pypirc.

"No" means Skylos has no built-in rules of that kind for the language.

C# dead-code findings are conservative: in a complete executable or web application scan, unreferenced public types and methods are low-confidence candidates; library APIs, protected members, and known framework or configured entry points remain externally reachable. Constructors are not reported as unused functions unless they are private, take parameters and nothing calls them (Roslyn IDE0051's rule); controller and dependency-injection constructors are called by the framework. C# source-file reachability is not implemented. Quality scanning detects statements after unconditional return, throw, break, or continue in a direct block; it is not full control-flow analysis. Security (--danger) treats ASP.NET request data as input: controller action, Razor Page handler, minimal API and [From*] parameters and Request.*, not constructor or plain service parameters, and follows it into same-file helper methods. It reports SQL injection (ADO.NET, EF raw SQL, Dapper), command injection, path traversal, SSRF (HttpClient, WebClient, WebRequest, RestSharp), open redirect (not LocalRedirect or a Url.IsLocalUrl guard), unsafe deserialization (BinaryFormatter family, Json.NET TypeNameHandling, SimpleTypeResolver) and XSS through HtmlString/Html.Raw/MarkupString and HTML responses, each with a CWE. Methods that share a sink's name (a repository's GetAsync) count only on the right receiver type. Generic secret scanning covers .cs files when --secrets or -a is enabled. .cshtml/.razor markup, flow across files and interpolated raw-string expressions are not yet followed by C# taint analysis. SCA inventories direct NuGet PackageReference entries in .csproj files. Only unconditional exact Version pins ([version]) without local Update/Remove mutations, not VersionOverride or centrally managed versions, can be checked against advisories. Ordinary NuGet version values are minimum bounds, so without a resolved lockfile their installed versions and vulnerability status remain unknown. With packages.lock.json (RestorePackagesWithLockFile), every resolved package, including transitive ones, is checked for each target framework.

Java security analysis follows directly implemented request-data helpers in same-package files or source files identified by exact imports or fully qualified names under a verified local source root. Helper reads are bounded and reject symlinks; no Java code or build scripts are executed. This is not full classpath or recursive helper analysis. Unknown helpers are not assumed to be request sources or sanitizers. Request data also includes Spring @RequestBody, @ModelAttribute and other handler parameters, JAX-RS @QueryParam-style and entity parameters, and uploaded files. Java checks cover SQL (JDBC, JPA, Hibernate, JdbcTemplate), command, path, SSRF, open redirect (including Spring "redirect:" views), XXE (SKY-D236), expression, JNDI and script injection (SKY-D237), LDAP (SKY-D239) and XPath (SKY-D229) injection, template injection, and unsafe deserializers (ObjectInputStream, XMLDecoder, XStream, SnakeYAML, Jackson default typing, Kryo). Sinks with common method names such as query, search or lookup are reported only on a receiver of the matching type.

Kotlin security analysis is lexical (Skylos has no Kotlin parser) and reuses the Java source and sink tables. Request data comes from Spring handler parameters (@RequestParam, @PathVariable, @RequestBody, @RequestHeader and unannotated non-scalar parameters of @*Mapping methods), servlet HttpServletRequest getters in call or property form, Ktor call.parameters, call.request.queryParameters, call.receive<T>() and call.receiveText(), and WebFlux ServerRequest accessors. Checks cover command execution (SKY-D212, SKY-D203), SQL including string templates (SKY-D211), path traversal (SKY-D215), SSRF through URL, OkHttp, Ktor HttpClient, RestTemplate and WebClient (SKY-D216), open redirect (SKY-D230), servlet and Ktor HTML responses (SKY-D226), ObjectInputStream and XMLDecoder (SKY-D204, SKY-D233), XXE (SKY-D236), SpEL/JNDI (SKY-D237), and Android WebView JavaScript bridges (SKY-D257) and file URL access (SKY-D258). Flow is tracked within one function or route lambda; helper calls are not followed.

C++ analysis covers .cpp, .cc, .cxx, .hpp, .hh, and .hxx. The first release reports only apparently unused file-local free functions. Without a build configuration, it cannot fully resolve templates, overloads, macros, or external usage; these findings are a conservative heuristic, not a proof of C++ deadness. Ambiguous .h files and C files are not analyzed as C++.

Ruby .rb analysis follows private helper calls with exact method owners and literal callbacks on direct Rails controller subclasses. Classes and public methods remain possible external API; dynamic dispatch keeps affected code uncertain. Generic text matches cannot prove Ruby method ownership. The first security rule covers explicit Kernel.system, Kernel.exec, Kernel.spawn and backtick interpolation with ARGV/STDIN data in a command string or shell payload. Literal commands and fixed printf with literal %s and separate data arguments have paired controls. Other executable argument semantics, visible overrides and unsupported selectors remain unresolved in analysis_summary.ruby_security_coverage. Rails SQL/request provenance, broader Ruby security rules, quality and local API verification are not supported yet.

Terraform .tf and .tf.json checks cover worldwide administrative ingress and explicitly disabled encryption on a new AWS RDS database. They read modules and literal locals without running Terraform. Unknown variables, external modules, providers and inherited encryption remain visible in analysis_summary.configuration_coverage.terraform. These checks describe source declarations, not deployed resources. See the cloud corpus and remaining evidence and capability gaps.

Java weak-hash checks also follow local algorithm variables and values loaded through java.util.Properties from literal classloader resources. Resource lookup stays within the matching src/main/resources or src/test/resources directory. Missing resources, unsupported loaders/layouts, conflicting branch values, and unresolved mutations remain unknown. Properties are used only as crypto evidence, never to prove a security guard or choose a safe branch. This does not resolve arbitrary runtime classpaths, JAR resources, or environment overrides.

TypeScript and JavaScript dead code analysis recognizes package.json entry fields, including bin. For targets under dist/ or out/, it checks the matching src/ location first, then the package root, before the declared output. This also covers dist/bin/palee.js mapping to bin/palee.ts and dist/src/index.js mapping to src/index.ts. If both source locations exist, the src/ mapping keeps priority; unrelated files are not treated as entries.

For ESM build scripts invoked by package scripts, Skylos also follows top-level esbuild calls using unchanged constants, spreads, templates, Node path helpers, and simple literal-array maps. Build scripts are never executed. Nested build calls and filesystem-generated entry lists remain unsupported and may still produce unused-file findings.

VitePress configs at .vitepress/config.* and .vitepress/config/index.* are recognised as development entrypoints for .js, .ts, .mjs and .mts. Other files in .vitepress still need a reference or another entrypoint rule. Existing directory conventions such as scripts/ work with native Windows separators too; this does not add general discovery of commands in CI workflows.

Vue single file components (.vue) are skipped by source analysis, including when passed explicitly. Skylos does not yet parse their <script> or <script setup> blocks; separate JavaScript, TypeScript and backend source files are still analyzed. Existing browser script and event references in templates are unaffected.

Go dead-code and security checks require the native skylos-go engine. If Skylos discovers Go files but cannot run that engine, it names them as not analysed, marks coverage incomplete and never reports them as clean. A few stray .go files are a coverage warning; when most of the code is Go the scan exits 2. Run skylos doctor to verify engine availability: it prints the version-matched build command, and SKYLOS_GO_BIN points Skylos at a separately built engine. The container image includes the engine and the official GitHub Action builds it automatically.

See Rules Reference for rule families and scanner scope.

Dependency Files

Dependency CVE scanning (--sca, included in -a) reads these files as data and queries OSV for the exact versions they record:

Ecosystem

Lockfiles (all recorded packages)

Manifests (exact pins only; ranges are reported as unresolved)

Named but not read

PyPI

uv.lock, poetry.lock, Pipfile.lock

requirements.txt, pyproject.toml, setup.cfg, setup.py

Pipfile without its lock

npm

package-lock.json, npm-shrinkwrap.json, pnpm-lock.yaml, yarn.lock, bun.lock

package.json

bun.lockb

Go

go.mod

go.sum before Go 1.17

Maven / Gradle

gradle.lockfile

pom.xml (properties, local parent POMs and <dependencyManagement>)

build.gradle(.kts) without gradle.lockfile

crates.io

Cargo.lock

Cargo.toml (=x.y.z)

Packagist

composer.lock

composer.json

RubyGems

Gemfile.lock

Gemfile without its lock

Pub

pubspec.lock

pubspec.yaml

NuGet

packages.lock.json

*.csproj ([x.y.z])

Git, path, SDK, private-registry and branch (dev-*) entries are listed as not checked and are never queried as public packages. See Dependency scanning.

Malware advisories (MAL-*, CWE-506, such as the hijacked chalk, debug and xrpl releases) are CRITICAL with metadata.malicious, are never demoted as dev-only, and tell you to remove the package and rotate the credentials installs could read. The same scan runs supply-chain checks through the ca9 engine: dependency confusion for your internal_packages (SKY-SCA-SRC001), Git dependencies not pinned to a commit and URL dependencies without a hash (SKY-SCA-SRC003), a pull request pointing a package at a source the repository did not use (SKY-SCA-SRC004), lockfile entries without an integrity hash (SKY-SCA-INT001), and, when you set min_release_age_hours, versions newer than that window (SKY-SCA-AGE001). JSON adds a package inventory and a supply-chain posture (lockfile committed, frozen CI installs, install scripts disabled, release-age cooldown, pinned actions, no pull_request_target checkout). See Supply-chain checks.

In pull requests (--diff or --diff-base), --sca also fails the gate when a change weakens install hardening: a cooldown removed or lowered, install scripts turned back on, packages added to pnpm allowBuilds or npm allowScripts, an action moved from a SHA to a tag (SKY-SCA-HRD001). Reviewed exceptions per package live on the base branch. With --review-upgrades (on in workflows from skylos cicd init), each npm or PyPI upgrade is downloaded old and new and compared as data: a new install hook, .pth or sitecustomize code or decode-and-exec fails the gate (SKY-SCA-UPG001); new import-time network calls or binaries are listed for review (SKY-SCA-UPG002). --danger reports committed agent and editor hooks (SKY-D365, SKY-D366: .claude/settings.json SessionStart, .vscode/tasks.json folderOpen), unpinned, hidden-path or impersonating MCP servers (SKY-D367-SKY-D369), agent base-URL overrides (SKY-D370), configs whose duplicated keys hide what runs (SKY-D377) and risky publish jobs (SKY-D371-SKY-D376). A whole-repository scan, or a baseline saved before these rules existed, lists them; a pull request that adds or changes a hook fails, and so does one that changes such files when ca9 is missing. See Agent configuration and publish-job rules.

Config And Deployment Support

Surface

Files

Security Scope

GitHub Actions

.github/workflows/*.yml, .github/workflows/*.yaml, action.yml, action.yaml

dangerous triggers, token permissions, unpinned actions, template injection, secrets, OIDC, cache, and artifact policy

GitLab CI

.gitlab-ci.yml

mutable images, unpinned includes, literal secrets, untrusted eval, Docker-in-Docker, OIDC, cache, timeout, and runner-tag policy

Agent and editor config

.claude/settings.json, .gemini/settings.json, .cursor/hooks.json, .codex/hooks.json, .vscode/tasks.json, .mcp.json and other MCP configs

committed hooks and folder-open tasks, unpinned or hidden-path MCP servers, impersonating MCP packages, and API base-URL overrides

Dockerfile

Dockerfile, Dockerfile.*, *.dockerfile

dangerous RUN commands, remote ADD without checksum, and literal build ARG / ENV secrets

Edge Docker Compose

compose*.yml, compose*.yaml, docker-compose*.yml, docker-compose*.yaml

privileged containers, broad host device/control mounts, GPU/device runtime, and host networking

Edge systemd

*.service

root edge services, mutable ExecStart paths, missing sandboxing, broad capabilities, and broad device access

Rendered Kubernetes exposure

one multi-document *.yml or *.yaml bundle plus a contracted Python source file

opt-in proof from an Ingress annotated skylos.dev/network-scope: external (or public) and skylos.dev/backend-protocol: http through its Service and workload; SKY-DEP001 checks direct top-level FastAPI/Flask routes against skylos.dev/source-file and skylos.dev/required-guards, SKY-DEP002 catches an effective Flask debugger, and SKY-DEP003 catches effective reload mode

GPU release contract

.skylos/gpu-targets.yml, Dockerfiles, CMake/CUDA build files, TensorRT source

static target-fleet checks for driver, compute-architecture, and serialized-engine compatibility; no hardware probing

With --danger or -a, a directory scan inside a Git worktree also checks that worktree's root .github/workflows/*.yml / *.yaml and .gitlab-ci.yml. For example, skylos src --danger checks the CI configuration that applies to src while keeping source, container and deployment analysis in src. Unrelated staged or unstaged edits do not narrow a full scan. Explicit diff filters still select changed configuration files; a single-file scan stays limited to that file. See scan scope.

Other Workflows

These workflows cover narrower jobs: container images, Kubernetes deployment exposure, and GPU release artifacts.

Goal

Command

What You Get

More Detail

Container-image scan

skylos image scan IMAGE@sha256:<digest> --platform linux/amd64 --fail-on high

Uses separately installed Trivy, registry network/auth, and an explicit severity gate for a pinned remote image

Container-image scanning

Container-image report import

skylos ingest trivy --input trivy.json --sarif image.sarif

Converts an existing Trivy image vulnerability report to Skylos JSON/SARIF; optional digest-bound severity check

Container-image scanning

Kubernetes exposure proof

skylos . --select SKY-DEP001,SKY-DEP002,SKY-DEP003 --format concise

Checks an explicitly external, explicitly plain-HTTP Ingress chain inside one rendered multi-document bundle; route checks compare exact framework wiring with the workload's declared source file and required guards

Deployment exposure rules

GPU source/build intent gate

skylos . --select SKY-GPU000,SKY-GPU001,SKY-GPU002,SKY-GPU003 --gate --format concise

Checks declared CUDA image, architecture, driver, and TensorRT packaging intent before the artifact is built

GPU target contract

Built GPU artifact preflight

skylos preflight build/app

Verifies the exact local artifact identity, selected CUDA architectures, packaged runtime route, and declared fleet compatibility; returns PASS, FAIL, or UNKNOWN

Release reliability

Check an Exact GPU Release Artifact

skylos preflight checks the built artifact itself against the repository's declared GPU fleet. This is separate from the SKY-GPU* source scan, which checks Dockerfiles, CUDA build settings, and TensorRT packaging intent before the artifact exists.

Declare every machine that receives the same release:

# .skylos/gpu-targets.yml
version: 1
targets:
  - name: inference-t4
    vendor: nvidia
    driver: "535.104.05"
    compute_capability: "7.5"
    platform: "linux/amd64"

The canonical filename is .skylos/gpu-targets.yml; the same schema is also accepted as .skylos/gpu-targets.yaml.

Then inspect a local build. Skylos uses a trusted system cuobjdump, takes a private snapshot, and never loads or executes the artifact:

skylos preflight build/app

To make the command argument-free in CI, bind it to a project-relative artifact with a strict release receipt:

{"version": 1, "artifact": "build/app"}

Save that file as .skylos/release.json, then run skylos preflight. For requests that reach report generation, terminal output is concise and redirected output is schema-versioned JSON. Argument or adapter errors can be plain text and exit 2.

Status

Exit

Meaning

PASS

0

Every declared target is compatible within the stated static evidence scope, and the exact artifact identity is verified

FAIL

1

Artifact evidence proves at least one declared target incompatible

UNKNOWN

2

Required evidence is missing, ambiguous, unsupported, or incomplete; it never silently becomes a pass

cuobjdump can report several code-object groups, identified by the producer label in its selected executable fatbin. Skylos requires a compatible route for every reported group. A PTX-only route stays UNKNOWN because static inspection cannot prove that the deployment driver will JIT it successfully. The overall result is FAIL if any target or required check fails; otherwise it is UNKNOWN if any result is unknown, and PASS only when all results pass.

Version 1 proves the local artifact identity, Linux ELF platform, selected executable-fatbin architecture routes, a static packaged $ORIGIN CUDA runtime route, and documented CUDA driver-family compatibility. It does not prove runtime execution, workload correctness, memory demand, performance, nonselected or relocatable fatbins, or per-kernel symbol parity. Windows PE runtime import proof is not implemented. Digest-pinned OCI references are accepted as identities but are never pulled or started, so the CLI always reports UNKNOWN for them; trusted callers can supply digest-bound inspection facts through skylos.preflight.run_preflight(...).

Benchmark Snapshot

Skylos has checked-in regression suites for dead code, security, quality, agent review and AI-code defects. They are regression gates, not independent benchmarks: we wrote the cases, so we don't quote their scores as accuracy. Case counts change as the suites grow; the manifests are the current source.

Suite

Cases

How to run

Dead code

benchmarks/dead_code/manifest.json

python scripts/dead_code_benchmark.py

Security

benchmarks/security/manifest.json

python scripts/security_benchmark.py

Quality

benchmarks/quality/manifest.json

python scripts/quality_benchmark.py; also runs in CI on every pull request

Agent review

benchmarks/agent_review/manifest.json

python scripts/agent_review_benchmark.py (needs an LLM API key)

AI-code defects

benchmarks/ai_code_defects/manifest.json

python scripts/ai_code_defect_benchmark.py

For methodology, dated results, competitor baselines and caveats, including the frozen golden-v0.2 suites, see BENCHMARK.md. The done-gate benchmark replays published agent runs and reports what the gate missed.

An experimental Jev runner can blindly score the pinned jev-1.13.0 typed decision model against the checked-in dead-code labels or the frozen skylos-benchmarks corpus. It withholds labels and review reasons from the request, retains golden label IDs locally for exact classifier comparison, and repeats the test with answer-signaling identifiers neutralized when that can be done without changing fixture semantics. An offline comparator now reports label-by-label corrections, regressions, abstentions, and unsafe removals against a frozen Skylos result. Live mode sends fixture source to TypeSafe, requires an explicit flag and a separate TYPESAFE_API_KEY; it supports bounded, resumable runs and records request versus local contract-validation latency. Normal Skylos scans need no Jev key. The paid Jev runs so far are small development runs on synthetic suites, not an independent holdout, and on some suites Jev did not improve classification. The dead-code benchmark guide and the same-run comparison report those results with their caveats.

Dead-code review is opt-in. A normal skylos . scan stays local and uses no model. skylos agent verify . uses the LLM verifier by default; choose Jev explicitly when you want it:

skylos agent verify . --format json                         # LLM only
skylos agent verify . --dead-code-review jev --format json  # Jev only
skylos agent verify . --dead-code-review jev-llm --format json  # Jev, then LLM if uncertain

Jev-only needs TYPESAFE_API_KEY, not an LLM key. Confident Jev "unused" decisions retain a static finding and confident "used" decisions suppress it; uncertain or unavailable decisions leave the finding visible as unverified. Jev-plus-LLM also needs a configured LLM provider and sends uncertain decisions to the LLM. Jev alone never authorizes --fix. If you select either Jev mode without TYPESAFE_API_KEY, Skylos stops with setup instructions instead of silently switching review modes. Get a key by signing in at the official TypeSafe console (access may require an invitation), then set TYPESAFE_API_KEY in your environment; do not put it in source control or a command-line argument.

Jev sends a bounded project source snapshot to TypeSafe (currently at most 64 KB). Check it for embedded secrets and confirm sharing is authorized; the local file guard is not a secret scanner. Oversized or unsafe snapshots cannot be judged by Jev. The older --jev-judge and --jev-precheck flags remain available for compatibility; use --dead-code-review for new workflows. See the dead-code review guide for key setup, fallback behavior, and limitations.

Real-project regression testing

liveness_primer, created and maintained by Matthew Digman, is Skylos's official real-project regression testing tool. On every PR, it compares the base and proposed merge result against the same pinned Python projects and reports which findings were added, removed, or changed.

Read the Analyzer Blast Radius check for the comparison and downloadable reports. These results complement the labeled benchmarks above; a change in finding counts alone does not establish accuracy. See the liveness_primer guide for scope, review steps, and reproduction commands.

Project Evidence

10 Skylos-assisted dead-code cleanup PRs have been merged into the default branch in 9 open-source projects, including Black, NetworkX, Optuna, mitmproxy, pypdf and pdm. Of the other 16 PRs we recorded, one was merged into a maintainer's staging branch but did not reach main (Flagsmith), one was a merged quality fix rather than dead code, one was merged and then reverted, four were closed by maintainers, seven were closed by us and two are still open. These are accepted cleanup PRs, not endorsements or adoption.

Candidates came from Skylos static analysis, were often triaged with the LLM-based skylos agent verify, and were checked by hand before each PR. Real-World Results lists the 26 recorded cleanup and quality-fix PRs with their outcomes and the maintainers' reasons.

Integrations

Integration

Link

Purpose

GitHub Action

GitHub Action

Repository PR gates or optional digest-pinned container-image gates

GitLab Code Quality

GitLab setup

merge request report artifacts; no comment-posting bot or API token

Bitbucket Pipelines / Azure Pipelines

Pipeline setup

detects pull request context for Skylos Cloud checks; --diff uses the PR target branch

Jenkins, CircleCI and any other CI

Skylos on any CI

skylos cicd init writes or prints the pull request gate for your CI; --diff uses the PR target branch

VS Code extension

VS Code extension

in-editor findings and AI-assisted fixes

Claude Code / Codex / Cursor hooks

Agent-loop hooks

check each agent edit, file read, and package install locally

MCP server

MCP setup

expose Skylos scans to AI agents and coding assistants; analyze works without a token (five calls per rolling 24 hours), other tools need a free Skylos project token; scans cost no credits, remediate costs 10 credits a call

Ruff

Python linting

optional Python linting through skylos lint

Docker image

Installation

run Skylos without a local Python install

Skylos Cloud

Skylos Cloud

skylos cloud: upload findings, see each branch's quality gate and how it changed

Set up a pull request gate from the CLI. skylos cicd init finds your CI (GitHub Actions, GitLab CI, Jenkins, Bitbucket Pipelines, Azure Pipelines, CircleCI) and writes its file, or prints the block to add when the file already exists. Other CIs get the commands to add; see Skylos on any CI.

skylos cicd init --no-upload                       # without Skylos Cloud
skylos cicd init --no-upload --scan-path apps/api  # a monorepo subproject
skylos cicd init --upload                          # with Skylos Cloud uploads
skylos cicd init --no-upload --risk-review         # plus the "Skylos risk review" check
skylos cicd init --ci jenkins                      # a Jenkinsfile pull request stage

On GitHub Actions, the generated workflow reviews changed lines on pull requests, adds a skylos done job when it finds your tests, and posts one comment per pull request with the verdicts, what blocks and what to read first. With --upload (the default when this machine is logged in to Skylos Cloud; without a login it prints how to add it) it also uploads full scans to Skylos Cloud using GitHub OIDC, from default-branch pushes and from pull requests to the default branch (pull_request_target: the pull request is scanned as data without credentials, then a job that never checks out its files uploads it). Uploads fail until the Skylos GitHub App is installed on the repository. It supports monorepo subprojects through --scan-path. See Your first Skylos-gated pull request.

To scan a built image with the composite Action, install a pinned Trivy version in the caller's job and set image to a trusted repository@sha256:<digest> build output plus image-platform. This runs an image-only scan; mode: gate uses image-fail-on (default high), while mode: scan only reports findings. See container-image scanning.

Documentation Map

Need

Read This

Install options, source install, and Docker

Installation

First scan and core workflows

Quick Start

CLI commands, flags, and examples

CLI Reference

CLI output modes, pretty reports, and TUI controls

CLI Output Modes

Optional Ruff linting through the Skylos CLI

Python Linting

Opt-in project compiler diagnostics and new versus existing type errors

Type checking

Find slow scanner phases and functions with --profile

Analysis profiling

CI setup, PR gates, annotations, and branch protection

CI/CD

GitLab merge request reports and CI example

GitLab Code Quality

Bitbucket Pipelines and Azure Pipelines pull request checks

Bitbucket and Azure Pipelines

Jenkins, CircleCI, Buildkite, Travis CI and other CIs

Skylos on any CI

Dead-code behavior and framework awareness

Dead Code Detection

Security scanning and taint analysis

Security Analysis

Dependency CVEs, uv/npm/pnpm/Poetry/Yarn lockfiles, offline SBOM, and SCA in CI

Dependency Scanning

Dependency licenses, SPDX 2.3 SBOM, and license deny/allow policy

License Compliance

Digest-pinned container-image scanning and GitHub Action setup

Container-image scanning

Source GPU contracts and built-artifact preflight

Release Reliability

Rule ID prefixes and product terminology

Rule Dictionary

Agent scan, verification, remediation, and model setup

AI Features

AI app safety checks and LLM guardrails

AI app safety checks

Claude Code, Codex, and Cursor hooks

Agent-loop hooks

Done gate for agent changes (skylos done)

Done gate

Tutorial: skylos setup, skylos open, the Pipeline view and the PR check, from a real agent session

Tutorial

What a change touches and what to read first (skylos done map)

Change map

What calls what, in plain English, and whether changed logic is still the same (skylos graph)

Codebase graph

Risks a pull request should not merge on a bot's approval (skylos cicd risk-review)

Risk review

First gated pull request with GitHub Actions

Your first gated PR

MCP server setup

MCP Server

Every Skylos-assisted cleanup PR and its outcome

Real-World Results

Baselines, filtering, suppressions, and whitelists

Configuration

Smart tracing

Smart Tracing

Rule families and language support

Rules Reference

skylos cloud, what it sends, and the other Cloud commands

Skylos Cloud

Cloud uploads and dashboard flow

CLI to Dashboard

Every network request the CLI can make, and how to turn each off

What leaves your machine

VS Code extension

VS Code Extension

Benchmarks and methodology

BENCHMARK.md

Security policy

SECURITY.md

Release process

RELEASE_WORKFLOW.md

Contribution priorities

ROADMAP.md

Contributing

CONTRIBUTING.md

Common Questions

Does Skylos replace Bandit, Semgrep, CodeQL, or Vulture?

No. Skylos can run alongside them. It focuses on framework-aware dead-code signal, PR gating, AI-era regression checks, and a combined workflow across dead code, security, secrets, quality, and AI-defect checks.

Does Skylos require an LLM?

No. Core static analysis runs locally without API keys. LLM features are optional through skylos[llm] and agent commands.

Is Skylos free?

The Skylos CLI is free and open source (Apache-2.0). Skylos Cloud has a Free plan for one project and a Workspace plan. Your first workspace gets a 14-day Workspace trial with 50 credits, no card needed. Any credit pack (from $9 for 50 credits) turns on Workspace for 12 months for up to 3 people. The Workspace pass ($990 once) has unlimited members. Prices are in USD, plus sales tax or VAT. Payments are one-time: nothing renews, and there are no seats or subscriptions. Credits never expire.

Does the MCP server need an account?

Without SKYLOS_API_KEY the MCP server exposes analyze (dead code, five calls per rolling 24 hours) and the local map tools (change_map and the graph_* tools, no limit: they read the repository on your machine and send nothing to Skylos Cloud). Every other MCP tool (verify_change, verify_agent, security_scan, secrets_scan, and so on) returns an authentication error until the server is started with SKYLOS_API_KEY set; create a free key in the Skylos Cloud dashboard settings. MCP scans (analyze, security, quality, secrets, provenance) cost no credits. remediate costs 10 credits per real run, charged when it starts generating fixes; dry runs (the default), refused calls and runs with nothing to fix are free. The CLI equivalents (skylos verify, skylos defend, skylos . -a) and skylos agent install-hooks run on your machine with no account or key; their dependency and package checks still query public registries (see What Leaves Your Machine).

Can the MCP server run in Docker or over the network?

Yes. skylos mcp --transport sse (or streamable-http) serves MCP over HTTP on MCP_BIND (default 127.0.0.1) and PORT (default 8080), and refuses to start without SKYLOS_MCP_TOKEN (at least 16 characters), the bearer token every client must send. The image built from skylos_mcp/Dockerfile sets MCP_BIND=0.0.0.0 so a published port reaches it:

export SKYLOS_MCP_TOKEN="$(openssl rand -hex 24)"
docker build -f skylos_mcp/Dockerfile -t skylos-mcp .
docker run --rm -p 8080:8080 -e SKYLOS_MCP_TOKEN skylos-mcp

Clients connect to http://localhost:8080/sse with Authorization: Bearer <token>. Behind a proxy, set SKYLOS_MCP_PUBLIC_URL to the address clients use.

Does Skylos replace Ruff?

No. skylos lint is an optional convenience entry point that delegates to Ruff. Install it with pip install "skylos[lint]"; normal Skylos scans do not run Ruff or merge Ruff violations into SKY-* findings.

Can I use it only on changed code?

Yes. Use skylos . -a --diff origin/main locally or configure CI gates to focus on new findings. A removed security control, such as a deleted auth decorator (SKY-L021), is still reported with --diff, including when the change only deletes the decorator line.

Does skylos done catch every way to fake a finished change?

No. It compares test functions (pytest, unittest, JavaScript/TypeScript), so rewriting a custom test-runner script or deleting cases from a test data file is not caught, and a test can still be weakened in ways its static assertion count cannot see. See the done gate's limits and its benchmark.

How should I handle intentional dynamic code?

Use baselines, whitelists, inline suppressions, or runtime tracing. See the configuration docs and smart tracing docs.

Contributing And Support

  • Report security issues through SECURITY.md.

  • Report a problem privately with skylos feedback, which opens a prefilled form at skylos.dev/feedback. The page address carries the Skylos version, OS, Python version and the last failed command (paths and secrets masked); your message is sent only when you press Send. No account needed.

  • Open public bugs and false-positive reports with minimal repros (skylos feedback --github prefills the issue form).

  • Check ROADMAP.md for useful contribution areas.

  • Read CONTRIBUTING.md before sending a pull request.

  • See QUALITY.md for project quality and gate expectations.

  • Join the Discord for community support.

License

Skylos is licensed under the Apache License 2.0.

Available Tools

17 tools
analyzeFind dead codeA
Read-only

Find dead code: unused functions, classes, imports, variables, parameters and files.

Use this to list cleanup candidates in a project. Returns JSON with a summary and per-category findings (file, line, name, confidence) plus _run_id; the full result is stored locally and can be read from the skylos://results/{run_id} resource. Read-only: it never edits code. Findings are candidates: before deleting one, check for dynamic use (getattr, string dispatch, entry points, framework decorators, tests). A non-empty analysis_errors means analysis or verification was incomplete; do not treat the findings as a complete scan.

Defect and Review records remain complete. Advice is grouped by default; expand_advice=True includes every Advice record. Read _result_uri for the complete saved result without rescanning.

Works without SKYLOS_API_KEY (5 calls/day); higher limits with a key.

Inputs: path (required), confidence, expand_advice, exclude_folders. Returns: result

architecture_checkCheck architectureA
Read-only

Report architecture findings for a project: module coupling, cohesion and circular dependencies.

Returns JSON with the architecture findings and _run_id. Read-only and local. Use quality_check for function-level issues.

Defect and Review records remain complete. Advice is grouped by default; expand_advice=True includes every Advice record. Read _result_uri for the complete saved result without rescanning.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required), confidence, expand_advice, exclude_folders. Returns: result

change_mapMap what a change touchesA
Read-only

Map what a code change touches, to review it: every changed Python or TypeScript/JavaScript function, method or class with its old and new code, calls added and removed, calls that only moved into a helper, its callers (with call lines, and whether each caller was updated), removed security checks and access checks, breaking or compatible signature changes, changed module values and the functions using them, and the top symbols to read first. Flags list what a person must look at.

Computed from the code, not by a model: the same commit gives the same map. Returns JSON. Read-only and local.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: base, path. Returns: result

generate_fixGenerate a dead-code removal patchA
Destructive

Build a unified-diff patch that removes (or comments out) dead code found by static analysis, after grep verification drops findings that are still referenced.

Returns the diff, patch summary, validation errors and applied status. With apply=False (default) it previews changes; with apply=True it edits files if patch validation succeeds. Refuses to run when the analysis or grep verification was incomplete. Review the diff and run trusted tests before keeping it.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required), mode, apply, min_safety. Returns: result

get_security_contextSummarize security contextA
Read-only

Summarize a project's security setup: detected web frameworks, auth decorators and middleware, security headers, rate limiting, input validation and a supported Skylos YAML policy file.

Use it before reviewing or writing security-sensitive code to learn the project's conventions. Returns JSON. Read-only and local.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required). Returns: result

get_triage_suggestionsSuggest triage decisionsA
Read-only

Suggest accept or dismiss for current findings, based on decisions recorded with learn_triage in this project.

Returns JSON suggestions with finding fingerprints, suggested actions and confidence, plus the number of learned patterns. Read-only and local.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required). Returns: result

health_scoreAssess codebase healthA
Read-only

Assess a project through separate Risk, Maintainability and Dead code readouts.

This tool retains its health_score name for compatibility but no longer creates a blended numeric grade. Gate policy remains independent. Returns assessment, coverage, finding counts and _run_id. Read-only and local. Advice is grouped by default; expand_advice=True includes every Advice record. Read _result_uri for the complete saved result.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required), confidence, expand_advice, exclude_folders, +3 more. Returns: result

learn_triageRecord a triage decisionA

Record whether a finding was accepted or dismissed so get_triage_suggestions can learn from it.

Writes the decision to the project's local Skylos state.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required), action (required), action_id (required). Returns: result

provenance_scanAttribute changes to agents or humansA
Read-only

Report available evidence of AI-agent, bot and human contributions.

Combines git signals since the base (agent bot accounts, Co-authored-by and AI declaration trailers, agent-named commit subjects) with recorded local attribution evidence. Returns JSON with per-file attribution, evidence and coverage status. Commit declarations do not establish line authorship; missing evidence remains unknown. Read-only and local.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required), diff_base. Returns: result

quality_checkCheck code qualityA
Read-only

Report code-quality issues: high complexity, deep nesting, long functions, duplicate branches and similar maintainability findings.

Returns JSON with findings (rule ID, file, line, message) and _run_id. Read-only and local.

Defect and Review records remain complete. Advice is grouped by default; expand_advice=True includes every Advice record. Read _result_uri for the complete saved result without rescanning.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required), confidence, expand_advice, exclude_folders. Returns: result

remediatePlan or apply LLM fixesA
Destructive

Plan or apply LLM-generated fixes for Skylos findings in a project.

With dry_run=True (default), static analysis returns a remediation plan without calling a model or changing files. With dry_run=False, it generates fixes and can edit files in place: this needs the skylos[llm] extra and provider configuration (including credentials when required), and sends affected code to that provider. It does not run your tests. Review every change and run trusted tests before keeping it. Costs 10 Skylos credits per real run, charged when the run starts generating fixes, right before the first model call; a run that fails after that is still charged. Dry runs, refused calls and runs with nothing to fix are free. Scan tools cost no credits.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required), model, dry_run, severity, +2 more. Returns: result

secrets_scanFind hard-coded secretsA
Read-only

Find hard-coded secrets and credentials (API keys, tokens, private keys, passwords) in source and config files.

Returns JSON with findings (provider, file, line) and _run_id. Secret values are redacted in the output. Read-only and local.

Defect and Review records remain complete. Advice is grouped by default; expand_advice=True includes every Advice record. Read _result_uri for the complete saved result without rescanning.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required), confidence, expand_advice, exclude_folders. Returns: result

security_scanScan for security issuesA
Read-only

Scan source code for security issues such as SQL and command injection, SSRF, path traversal, eval/exec and unsafe deserialization.

Returns JSON with findings (rule ID, severity, file, line, message) and _run_id. Read-only; the scan runs locally and does not upload code. Use secrets_scan for hard-coded credentials and validate_code_change to check a diff before it lands.

Defect and Review records remain complete. Advice is grouped by default; expand_advice=True includes every Advice record. Read _result_uri for the complete saved result without rescanning.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required), confidence, expand_advice, exclude_folders. Returns: result

validate_code_changeCheck a diff before it landsA
Read-only

Validate a code diff for security regressions and issues before it lands.

Takes a unified diff and checks for:

  • Security control regressions (auth, CSRF, TLS, rate limiting removal)

  • New dangerous patterns (eval, exec, SQL injection, etc.)

  • Secrets in added code

  • Hallucinated or undeclared dependencies in added imports and manifest entries (requirements*.txt, pyproject.toml, package.json, go.mod), verified against the package registries. The "registry" field reports "ok", "unreachable" or "error" (lookups incomplete — do not treat pass as clean), or "skipped".

Returns pass/fail with findings.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: diff (required), path, policy, check_dependencies. Returns: result

verify_agentVerify an AI agent's guardrailsA
Read-only

Statically verify an AI agent's guardrails before deployment.

Deterministic, local pre-deployment agent verification: inventories LLM integrations, runs the defense checks (prompt-injection exposure, dangerous sinks, tool scope, output validation, PII filtering, cost controls), and returns scores, failed checks with remediation, OWASP LLM/Agentic coverage, and a reproducible attestation digest. No model is involved in the verdict and the analysis runs locally; source code is not sent to Skylos Cloud. Optional gate: set fail_on (severity) and/or min_score (0-100).

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path, fail_on, min_score, owasp_version, +2 more. Returns: result

verify_changeVerify an edited file or rangeA
Read-only

Verify a changed file/range for AI-code defects and security bugs.

Returns a narrow, versioned JSON verdict containing AI-code trust findings such as hallucinated references, unfinished generated code, stale references, disabled controls, and dependency hallucinations (checked by default; pass include_dependency_hallucinations=False to skip the registry lookups), plus high/critical security findings (category "security") and hard-coded secrets (category "secret", values redacted) in the selected file/range. Pass include_security_findings=False to skip the security and secret checks.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: file, path, confidence, line_range, +6 more. Returns: result

verify_dead_codeVerify dead code with an LLMA
Read-only

Ask an LLM to review selected unused function, class, import and variable candidates, with its reasoning.

Use it after analyze when you need fewer false positives before deleting code. Sends code snippets and search results to the chosen model provider, so it needs the skylos[llm] extra and provider configuration, including credentials when required. Candidates outside the review limits, or whose use remains uncertain, can remain unverified. Does not edit files. Refuses to run when the static analysis was incomplete.

Requires SKYLOS_API_KEY: this tool returns an authentication error unless the MCP server is started with SKYLOS_API_KEY set. Without a key only analyze works (5 calls/day). The local CLI needs no key: skylos verify <file> and skylos agent install-hooks.

Inputs: path (required), model, confidence, max_verify, +2 more. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.8/5.0

    Scored across 17 tools

    Disambiguation3/5

    Several tools have genuinely distinct targets (analyze, security_scan, secrets_scan, quality_check, architecture_check, provenance_scan, change_map), but `validate_code_change` and `verify_change` both inspect a diff for security/dependency defects and are easy to confuse, as are `generate_fix` (deterministic dead-code patch) and `remediate` (LLM fixes). The overloaded `verify_` prefix spans three unrelated domains (dead code, AI agents, diffs), which muddies selection, and `health_score` overlaps with analyze/quality_check readouts.

    Naming Consistency3/5

    Everything is snake_case and readable, but the convention is mixed: verb_noun (verify_change, get_security_context, generate_fix, learn_triage), noun_verb (security_scan, secrets_scan, quality_check, architecture_check), and bare nouns/verbs (analyze, remediate, health_score, change_map). The result is a set where you cannot infer from the name alone whether a tool scans, verifies, or reports.

    Tool Count3/5

    17 tools is on the heavy side for one analysis server, and a few feel marginal or duplicative: health_score mostly aggregates outputs already available from analyze/quality_check, and learn_triage/get_triage_suggestions are a narrow pairing. It is justifiable for a broad static-analysis platform, but the surface is creeping toward overlap rather than crisp separation.

    Completeness4/5

    Coverage is broad: dead code, security, secrets, quality, architecture, AI-agent and provenance verification, diff validation, remediation, and triage learning, with full result retrieval documented via resources. Gaps are minor — no explicit way to manage suppressions/config (rules, ignore files) or compare against a baseline, though triage partially covers accepting/dismissing findings.

    Maintenance

    ActivityActive
    ResponsivenessUsually handled

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      F
      maintenance
      A high-performance MCP server providing lightning-fast hybrid code search using TF-IDF and vector embeddings for AI assistants. It enables real-time codebase indexing and semantic retrieval with sub-50ms latency and offline support.
      12
      MIT
    • F
      license
      Not graded
      quality
      B
      maintenance
      Structural code intelligence for AI agents. Scan once, query everything — dead exports, circular imports, dependency graphs, and more. CLI + MCP server.
      6 npm
      10
      -
    • F
      license
      Not graded
      quality
      D
      maintenance
      Give your AI coding agents superpowers — a local MCP server for fast, token-efficient code navigation, search & analysis.
      -