Skylos
Code checks that show their work.
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,
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
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
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.
!License: Apache 2.0
!PyPI - Python 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,
- LLM app risks such as unsafe tool use and missing output validation
--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 (there
are no Kotlin security rules), C++ is limited to unused file-local functions,
and Shell gets security checks only.
Skylos also checks CI/CD and deployment config. See
Language Support.
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, valid Git, URL, path and private-index 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 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; 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: | A remote registry image scanned by a separately installed Trivy; --fail-on turns findings into a gate |
Run skylos --help for this chooser, skylos for one
command, and skylos commands for the command-family map.
The report commands have different gate and network behavior:
image scanrequires Trivy on trustedPATHand uses Trivy's remote image
--fail-on, a completed scan exits 0 even
when it reports vulnerabilities.
suiteruns in the local process and does not upload unless--uploadis
0 regardless of their count. Operational and output failures
are nonzero; --upload can also fail for an upload error or Cloud quality
gate.
defendreports guardrail findings by default. It becomes a gate with
--fail-on, --min-score, or gate settings in an explicit policy.
cleanwithout--dry-runor--applyis interactive and can write after
0 if an individual edit prints a
failure, so review the completion output.
doneexits0on pass,1when a blocking check fails or does not
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
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. 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 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,
- 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, and asks before installs it cannot verify (git and
URL sources, unknown registries, failed lookups).
- Before a git command: blocks
--no-verify,HUSKY=0and other ways
- At stop: blocks "done" while issues the agent added are still open.
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.
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 the changes to read first; --format json for a review agent | Change map |
| MCP change map | change_map MCP tool | Gives a review agent the change map as JSON before it reads the diff. Requires a free Skylos API key (SKYLOS_API_KEY). skylos done map needs no key | Change map |
| 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 | 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 and runs skylos done when your tests can run; 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/ | 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 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
- Attestation: JSON/md/SARIF reports carry a reproducible SHA-256 digest
- CI-native:
skylos cicd init --defendgenerates 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.yamlpins gate thresholds and severity
--policy).
- Agent-native: the
verify_agentMCP tool lets coding agents verify the
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,
.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
- Local-first operation: core analysis executes locally and does not upload
- AI-assisted change review: checks for removed validation, auth, logging,
- Agent-loop verification:
skylos verifyand MCPverify_changeuse a
-o.
- Evidence-backed AI defects:
--ai-defectsand full scans put strict
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
- Project-specific rules: add local YAML rules and extend prompt, credential,
- One command surface: dead code, security, secrets, dependency, quality,
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-reviewand--verify-securitynever send anything to Skylos Cloud
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 remediateandagent remediate --standards
--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
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 feedbackmakes no request itself: it opens a form on skylos.dev
--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
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/ 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/ 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,
summary.json: compact status, counts, budget, and artifact paths.behavior-results.json: normalized runtime assertions, provenance, coverage,
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