Configuration
Skylos uses pyproject.toml for configuration. Run skylos init to generate a configuration file with sensible defaults, or add the [tool.skylos] section to an existing file.
Configuration File
[tool.skylos]
# Quality thresholds
complexity = 10
nesting = 3
max_args = 5
max_lines = 50
duplicate_strings = 3
# Rules to ignore (by rule ID)
ignore = []
# AI model for --fix and --audit
model = "gpt-4.1"
[tool.skylos.whitelist]
# Glob patterns to ignore as unused
names = [
"handle_*",
"visit_*",
"*Plugin",
]
[tool.skylos.whitelist.documented]
# Patterns with reasons (recommended for teams)
"dark_logic" = "Called via globals() string manipulation"
"BasePlugin" = "Discovered via __subclasses__()"
[tool.skylos.whitelist.temporary]
# Temporary whitelist - warns when expired
"legacy_handler" = { reason = "Migration - JIRA-123", expires = "2026-03-01" }
[tool.skylos.overrides."src/plugins/*"]
# Per-path whitelist rules
whitelist = ["*Plugin", "*Handler"]
[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.languages.typescript]
# Language-specific overrides
complexity = 15
nesting = 4
[tool.skylos.languages.java]
complexity = 12
[tool.skylos.gate]
# Quality gate settings
fail_on_critical = true
max_security = 0
max_quality = 10
strict = false
[tool.skylos.contribution]
# Off by default. Stores structural accept/dismiss/learn signals locally only.
collect_local_signals = false
contribute_public_corpus = false
structural_signatures_only = true
include_source = false
Configuration Options
Quality Thresholds
| Option | Type | Default | Description |
|---|---|---|---|
complexity | int | 10 | Maximum cyclomatic complexity before flagging a function |
nesting | int | 3 | Maximum nesting depth before flagging |
max_args | int | 5 | Maximum function arguments before flagging |
max_lines | int | 50 | Maximum function length in lines |
Analysis Options
| Option | Type | Default | Description |
|---|---|---|---|
ignore | list | [] | List of rule IDs to suppress (e.g., ["SKY-L002", "SKY-Q301"]) |
model | string | "gpt-4.1" | LLM model for AI-powered features |
Contribution Signals
The [tool.skylos.contribution] section controls AI-code defect signal capture.
It is explicit, opt-in, and off by default.
| Option | Type | Default | Description |
|---|---|---|---|
collect_local_signals | bool | false | Record local structural accept/dismiss/learn events |
contribute_public_corpus | bool | false | Reserved for public corpus contribution; keep disabled unless you explicitly opt in |
structural_signatures_only | bool | true | Store rule/category/severity/file extension/line bucket/hashes instead of source text |
include_source | bool | false | Always sanitized to false; raw source is not captured |
When local signal capture is enabled, Skylos stores bounded local events at:
.skylos/contribution/events.json
Events are generated from agent-service accept, dismiss, and learn actions. They include structural hashes and message hashes, not raw code. The file is local project state and should normally be gitignored.
[tool.skylos.contribution]
collect_local_signals = true
contribute_public_corpus = false
structural_signatures_only = true
include_source = false
Gate Configuration
The [tool.skylos.gate] section controls the quality gate behavior when using --gate:
| Option | Type | Default | Description |
|---|---|---|---|
fail_on_critical | bool | true | Block deployment if CRITICAL security issues or secrets are found |
max_security | int | 0 | Maximum allowed security findings before gate fails |
max_quality | int | 10 | Maximum allowed quality findings before gate fails |
strict | bool | false | When true, prevents bypassing a failed gate interactively |
Whitelist Configuration
Suppress false positives permanently without cluttering your code with inline comments.
CLI Commands
# Add a glob pattern
skylos whitelist 'handle_*'
# Add with reason (recommended for teams)
skylos whitelist dark_logic --reason "Called via globals() in dispatcher"
# View current whitelist
skylos whitelist --show
Whitelist Sections
[tool.skylos.whitelist]
Simple glob patterns for names to ignore:
[tool.skylos.whitelist]
names = [
"handle_*", # Event handlers called via getattr
"visit_*", # AST visitor methods
"*Plugin", # Plugin classes discovered via __subclasses__
"*_callback", # Callback functions
]
[tool.skylos.whitelist.documented]
Patterns with reasons - shows up in skylos whitelist --show and helps teams understand why something is whitelisted:
[tool.skylos.whitelist.documented]
"dark_logic" = "Called via globals() string manipulation in trigger_blindspots()"
"BasePlugin" = "Discovered via __subclasses__() at runtime"
"legacy_api" = "Called by external service - do not remove"
[tool.skylos.whitelist.temporary]
Patterns with expiration dates - Skylos warns when these expire to prevent whitelist rot:
[tool.skylos.whitelist.temporary]
"legacy_handler" = { reason = "Migration in progress - JIRA-123", expires = "2026-03-01" }
"old_api_v1" = { reason = "Deprecated, removing in Q2", expires = "2026-06-30" }
[tool.skylos.overrides."path/*"]
Per-file or per-folder whitelist rules:
[tool.skylos.overrides."src/plugins/*"]
whitelist = ["*Plugin", "*Handler"]
[tool.skylos.overrides."src/events/*"]
whitelist = ["on_*", "*_listener"]
Dead-Code Entrypoints
Use [[tool.skylos.dead_code.entrypoints]] when code is live because a
project-specific framework, plugin loader, or decorator calls it implicitly.
Entrypoint rules are more precise than broad whitelists because they can match
definition type, name, path, decorator, base class, and parent class metadata.
[tool.skylos.dead_code]
entrypoints = []
[[tool.skylos.dead_code.entrypoints]]
type = "class"
name = "Main"
path = "**/main.py"
base_classes = ["Application"]
reason = "framework application entrypoint"
[[tool.skylos.dead_code.entrypoints]]
type = "method"
name = ["create", "pre_hook", "post_hook"]
parent = { name = "Main", base_classes = ["Application"] }
reason = "framework lifecycle method"
[[tool.skylos.dead_code.entrypoints]]
type = "function"
decorators = ["runtime_hook"]
path = "src/**"
reason = "registered by runtime_hook"
Supported match fields are type, name, full_name, module, path,
decorator, decorators, base_class, base_classes, and parent. The
parent rule can match the parent class by name, full_name, module,
path, base_class, or base_classes. Rules must include a symbol selector
such as name, decorators, base_classes, or parent; path, module,
and type only narrow the match.
Inline Ignores
For one-off exceptions, use inline comments instead of config:
# Single line ignore
def dynamic_handler(): # skylos: ignore
pass
# Alternative syntaxes (all equivalent)
def another(): # noqa: skylos
pass
def yet_another(): # pragma: no skylos
pass
# Block ignore (multiple functions)
# skylos: ignore-start
def block_one():
pass
def block_two():
pass
# skylos: ignore-end
Whitelist Summary
| Want to... | Do this |
|---|---|
| Whitelist a pattern | skylos whitelist 'handle_*' or add to names = [] |
| Document why | skylos whitelist x --reason "why" or add to [tool.skylos.whitelist.documented] |
| Temporary whitelist | Add to [tool.skylos.whitelist.temporary] with expires date |
| Per-folder rules | Add [tool.skylos.overrides."path/*"] section |
| View all whitelists | skylos whitelist --show |
| Inline ignore | # skylos: ignore comment |
| Block ignore | # skylos: ignore-start ... # skylos: ignore-end |
Language-Specific Overrides
You can override global settings for specific languages under [tool.skylos.languages.<lang>]:
[tool.skylos.languages.typescript]
complexity = 15
nesting = 4
[tool.skylos.languages.java]
complexity = 12
Currently supported language overrides: typescript and java.
Configuration Resolution
Skylos searches for pyproject.toml by walking up from the target path to the filesystem root. The first file containing [tool.skylos] is used. If no configuration is found, Skylos applies the built-in defaults.
This approach was chosen over per-directory configuration to keep analysis consistent across monorepos while still allowing project-level customization.
Default Excluded Folders
Skylos automatically excludes common non-source directories:
__pycache__
.git
.pytest_cache
.mypy_cache
.tox
htmlcov
.coverage
build
dist
*.egg-info
venv
.venv
To see the current exclusion list:
skylos . --list-default-excludes
To disable default exclusions:
skylos . --no-default-excludes
To force-include a normally excluded folder:
skylos . --include-folder venv