Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .agents/skills/skylos/references/dead-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ evidence. Do not use trace mode as the default answer for untrusted PR review.

## Suppression Options

- `# skylos: ignore`: suppress a finding on one line.
- `# skylos: ignore`: suppress a finding on one line;
`# skylos: ignore[SKY-D211] reason` suppresses only that rule.
- A bare `# noqa` hides dead-code, quality and LOW/MEDIUM findings, but
not HIGH/CRITICAL security findings (`SKY-D*`, `SKY-S*`); those stay
reported with `bare_noqa_ignored: true`. `# noqa: <ruff code>` never
hides Skylos security/quality findings (F401/F841 only mark the
matching unused import/variable).
- `# skylos: ignore-start` / `# skylos: ignore-end`: suppress a block.
- `ignore = ["SKY-XXX"]` in `[tool.skylos]`: suppress a rule project-wide.
- `skylos whitelist <pattern>`: manage whitelisted symbols.
Expand Down
16 changes: 14 additions & 2 deletions .claude/skills/skylos/references/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,11 @@ The top level may also include `grade`, `provenance`, and
`analysis_summary`. Empty arrays can be omitted, so use `.get(key, [])`.
With `--gate` (or `--strict` without `--force`), `gate` holds `passed`,
`reasons` (strings), `scope`, `status`, `forced`, the `verdict` (`passed`,
`failed`, `incomplete`), its `exit_code`, and `reason_details` (`message`,
`details`, `hint` per reason).
`failed`, `incomplete`), its `exit_code`, `reason_details` (`message`,
`details`, `hint` per reason), and `coverage_status` / `coverage_warnings`.
`analysis_summary.analysis_coverage` says what was not analysed (`status`
`complete` / `partial` / `incomplete`, `exit_blocking`, `unchecked_files`,
`unverified_dead_code_candidates`).

## Filtering

Expand Down Expand Up @@ -110,6 +113,15 @@ Full scans skip generated/vendored files (Django migrations, `static/**/lib`,
could not decide (exit 2)` when required analysis did not finish (the reason
names the check, the counts, and the fix; `--force` does not override it).
Concise, LLM, GitHub, and GitLab output print it on stderr.
- Coverage gaps (a file that does not parse, `.go`/`.dart` files without
their engine, dead-code candidates grep verification did not reach) are
warnings: the scan and gate are decided on the analysed code and end with
`Coverage: INCOMPLETE — some code was not analysed`. They exit 2 only with
`--strict`, `require_complete = true` under `[tool.skylos.gate.coverage]`,
when most source files were not analysed, or for a changed file in a
`--diff` scan.
- A missing path or mistyped command (`skylos donee`) exits 2 with a "did
you mean" line.
- `--format concise`: exits non-zero when findings exist.

## Useful Subcommands
Expand Down
31 changes: 27 additions & 4 deletions .claude/skills/skylos/references/dead-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ python scripts/dead_code_compare_scanners.py
```

Use `--confidence` to tune dead-code reporting. Higher confidence reduces
candidate volume. Lower confidence surfaces riskier candidates.
candidate volume. Lower confidence surfaces riskier candidates. Confidence is
capped by the weakest evidence (`skylos/deadcode/confidence.py`, table in
`docs/cli-output.md`): imports/private symbols 100, public Python names 90,
exported-but-unimported 85, public methods/class attributes and unimported
files 80, files imported only by unused files 65, default exports 60,
unused parameters 50 (hidden by default; `--confidence 50`), Rust
(experimental) 40, so parameters and Rust are hidden at the default threshold.

## False-Positive Reduction Ladder

Expand All @@ -39,8 +45,19 @@ Skylos has framework-aware behavior for patterns such as:
- SQLAlchemy models and metadata.
- Next.js and React entrypoints, including metadata routes (`robots`,
`sitemap`, `opengraph-image`, ...) gated on a detected Next.js project.
- Tool config files (`next.config.*`, `postcss.config.*`, ...) and their
default export.
- Tool config files (`next.config.*`, `postcss.config.*`, any
`<tool>.config.*` next to a `package.json`, `turbo/generators/config.*`) and
their exports.
- Expo Router routes, React Email templates, Jest `__mocks__`, esbuild entry
points (including build scripts under excluded folders).
- Blade template references, FQN class strings in PHP, Laravel seeders.
- Flask app factories, call-registered callbacks and their signatures;
SQLAlchemy/SQLModel declarative fields.
- Django/Wagtail (`skylos/analysis/documented_conventions.py`): `*Field(...)`
and relation attributes, `Meta`, Wagtail Page/viewset/task attributes and
hook signatures, CBV/system-check/admin hook signatures, models in `models`
modules, `register*` class decorators, format files. Template lookups stay
proof-based (`django_template_liveness.py`); do not add name-only matching.
- Laravel convention classes, each with the evidence Laravel's discovery
needs (`Command` base, typed listener event, existing model for factories
and policies), plus Livewire and Blade components, migrations,
Expand All @@ -61,7 +78,13 @@ evidence. Do not use trace mode as the default answer for untrusted PR review.

## Suppression Options

- `# skylos: ignore`: suppress a finding on one line.
- `# skylos: ignore`: suppress a finding on one line;
`# skylos: ignore[SKY-D211] reason` suppresses only that rule.
- A bare `# noqa` hides dead-code, quality and LOW/MEDIUM findings, but
not HIGH/CRITICAL security findings (`SKY-D*`, `SKY-S*`); those stay
reported with `bare_noqa_ignored: true`. `# noqa: <ruff code>` never
hides Skylos security/quality findings (F401/F841 only mark the
matching unused import/variable).
- `# skylos: ignore-start` / `# skylos: ignore-end`: suppress a block.
- `ignore = ["SKY-XXX"]` in `[tool.skylos]`: suppress a rule project-wide.
- `skylos whitelist <pattern>`: manage whitelisted symbols.
Expand Down
31 changes: 0 additions & 31 deletions .github/ISSUE_TEMPLATE/bug_report.md

This file was deleted.

51 changes: 51 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Bug report
description: Something isn't working as expected. Anyone can read GitHub issues, so leave out company code and repository names.
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for reporting. `skylos feedback --github` opens this form with your versions filled in.
If the problem involves private code, use the private form instead: https://skylos.dev/feedback?src=github
- type: textarea
id: what-happened
attributes:
label: What happened?
description: What did you do, and what happened instead? Include the full error output if there is one.
placeholder: Skylos reported ... / crashed with ...
validations:
required: true
- type: input
id: command
attributes:
label: Command you ran
description: Replace file paths, tokens and repository names.
placeholder: skylos . -a --format json
- type: input
id: version
attributes:
label: Skylos version
description: Output of `skylos --version`.
placeholder: "4.49.0"
validations:
required: true
- type: input
id: os
attributes:
label: Operating system
placeholder: macOS 14, Ubuntu 22.04, Windows 11
- type: input
id: python
attributes:
label: Python version
placeholder: "3.12"
- type: textarea
id: expected
attributes:
label: What did you expect?
- type: textarea
id: repro
attributes:
label: Steps to reproduce
description: The smallest set of commands (and a tiny example project, if needed) that shows the problem.
render: shell
11 changes: 11 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
blank_issues_enabled: true
contact_links:
- name: Private report (no GitHub account needed, or it involves company code)
url: https://skylos.dev/feedback?src=github
about: Goes privately to the founder. Nothing is posted publicly. From a terminal, run `skylos feedback`.
- name: Security vulnerability (private)
url: https://github.com/duriantaco/skylos/security/advisories/new
about: Report vulnerabilities through GitHub private vulnerability reporting, never in a public issue.
- name: Questions
url: https://github.com/duriantaco/skylos/discussions
about: Ask and answer questions in GitHub Discussions.
21 changes: 0 additions & 21 deletions .github/ISSUE_TEMPLATE/false_positive.md

This file was deleted.

39 changes: 39 additions & 0 deletions .github/ISSUE_TEMPLATE/false_positive.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Wrong finding (false positive)
description: Skylos flagged something that is actually used or isn't a problem.
title: "FP: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Share the smallest snippet that triggers the finding. Anyone can read GitHub issues, so leave out company code;
for private code, use https://skylos.dev/feedback?src=github instead.
- type: input
id: rule-id
attributes:
label: Rule or finding
description: The rule ID (for example SKY-D211) or category (dead code, security, quality), and the flagged name.
placeholder: SKY-D211 unused function `handle_event`
validations:
required: true
- type: input
id: version
attributes:
label: Skylos version
description: Output of `skylos --version`.
placeholder: "4.49.0"
validations:
required: true
- type: textarea
id: snippet
attributes:
label: Minimal reproduction
description: A small code snippet that triggers the wrong finding. Use any language; the field is highlighted as Python.
render: python
- type: textarea
id: why
attributes:
label: Why is it wrong?
description: How the flagged item is actually used (framework callback, dynamic dispatch, re-export, ...).
validations:
required: true
19 changes: 0 additions & 19 deletions .github/ISSUE_TEMPLATE/feature_request.md

This file was deleted.

16 changes: 16 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Feature request
description: Suggest an idea for Skylos.
labels: ["enhancement"]
body:
- type: textarea
id: problem
attributes:
label: What problem does this solve?
description: A clear description of the problem. For example, "I'm always frustrated when ..."
validations:
required: true
- type: textarea
id: proposal
attributes:
label: Proposed solution
description: What you'd like to happen, alternatives you considered, and examples from other tools.
100 changes: 100 additions & 0 deletions .github/workflows/dist-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: dist-check

# Builds the release artefacts exactly as publish.yml does (both call
# tools/release/build_dist.py) on pull requests that could break them, so a
# packaging change fails here instead of at the next release. It never
# publishes: no secrets, read-only token, and the only upload is a short-lived
# workflow artifact the install jobs below read.
on:
pull_request:
paths:
- ".github/workflows/publish.yml"
- ".github/workflows/dist-check.yml"
- "tools/release/**"
- "pyproject.toml"
- "MANIFEST.in"
- "skylos/engines/go/**"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: dist-check-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
build:
name: build sdist and wheels
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"

- name: Install build tools
run: |
python -m pip install --upgrade pip
python -m pip install "build>=1.2.2" "packaging>=24.2" "twine>=6.1.0"

- name: Set up Go
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: "1.22.x"
cache: false

# Same command as publish.yml: sdist, pure wheel, six platform wheels,
# then a check that each wheel holds the engine built for its platform.
- name: Build sdist and wheels
run: python tools/release/build_dist.py build --out dist

- name: Smoke test the bundled Go engine
run: python tools/release/build_dist.py smoke --dist dist

- name: Check dist contents
run: |
ls -lah dist
python -m twine check dist/*

- name: Keep the built dist for the install jobs
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: dist-check
path: dist
retention-days: 3
if-no-files-found: error

install:
name: install on ${{ matrix.os }}
needs: build
runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
# Apple silicon and Windows x86_64; build covers Linux x86_64.
os: [macos-latest, windows-latest]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"

- name: Download the built dist
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: dist-check
path: dist

- name: Smoke test the bundled Go engine
run: python tools/release/build_dist.py smoke --dist dist
Loading
Loading