This specification defines the exact shape of JSON, YAML, and CSV output produced by pyscn. All field names, types, and semantics documented here are stable for as long as the report's top-level schema_version stays the same.
field names, field types, field semantics, enum values
May change
field ordering within an object, ordering of array elements, inclusion of new fields
Breaking
removal or rename of fields, change of field type, removal of enum values
Consumers MUST ignore unknown fields. Breaking changes to the pyscn analyze report increment its top-level schema_version and are listed as BREAKING in the CHANGELOG. They are not restricted to major version bumps — the snake_case key rename described below shipped in the 1.30.0 minor release — so pin against schema_version rather than the semantic version.
Every object key in pyscn analyze JSON/YAML is snake_case since 1.30.0. Releases up to 1.29.1 emitted Go-style PascalCase inside complexity, cbo, lcom, and system (including complexity.request and dead_code.request), and lowerCamelCase inside the config objects of cbo, lcom, and community_analysis. The rename is mechanical: convert the old key to snake_case and lowercase acronyms.
The top-level keys, summary, the dead_code findings, clone, community_analysis (other than config), module_quality, and suggestions were already snake_case and did not change. Reports written by releases before schema_version was introduced have no schema_version key; use the top-level version to tell 1.29.x (PascalCase) from 1.30.0 and later (snake_case).
Each entry joins module identity and size from dependency analysis with analyzer-owned complexity and dead-code rollups. The rollups are calculated before presentation filters, do not run another source-analysis pass, and do not contribute a new health-score category.
Field
Type
Description
module_name
string | absent
Importable Python module name when dependency analysis resolved it.
file_path
string
Source path as reported by the analyzer. Relative input paths remain relative.
lines_of_code
integer
Physical module line count from dependency analysis, or 0 when unavailable.
function_count
integer
Total module function count from dependency analysis, or 0 when unavailable.
analyzed_function_count
integer
Function complexity records before min_complexity and report_unchanged filters. The <module> pseudo-record is excluded.
average_complexity
number
Mean cyclomatic complexity across all function records.
average_cognitive_complexity
number
Mean cognitive complexity across all function records.
max_complexity
integer
Maximum cyclomatic complexity before presentation filters.
high_risk_function_count
integer
Complexity records classified as high risk before presentation filters.
exception_handler_count
integer
Sum of exception handlers across all function records.
dead_code_finding_count
integer
Detector findings before min_severity filtering.
dead_code_block_count
integer
Distinct unreachable CFG blocks represented by detector findings before min_severity filtering.
Entries are ordered by high-risk function count, maximum complexity, average complexity, dead-code findings, then file path. This places the most actionable modules first while retaining deterministic ties.
Each entry groups the reported complexity.Functions population by its direct directory relative to the analysis root. Counts and averages therefore reconcile with the function list after min_complexity and report_unchanged filters. The aggregation performs no source reads or analyzer passes.
Field
Type
Description
directory_path
string
Directory relative to the analyzed root. The root entry is ..
function_count
integer
Reported complexity.Functions entries whose files are directly in this directory, including a <module> pseudo-entry when it survives presentation filters.
average_complexity
number
Mean cyclomatic complexity of those functions.
max_complexity
integer
Maximum cyclomatic complexity of those functions.
high_risk_function_count
integer
Reported functions classified as high risk.
average_nesting_depth
number
Mean maximum nesting depth of the reported functions.
max_nesting_depth
integer
Maximum nesting depth in the directory.
When multiple input paths are supplied, their common directory is the analyzed root. File inputs participate through their parent directories. The root entry is .. Entries are ordered by high-risk count, maximum complexity, average complexity, then directory path.
When complexity analysis completes with no reported functions, by_directory is present as an empty array in JSON and YAML.
{"functions":[/* FunctionComplexity array */],"class_scopes":[/* FunctionComplexity array; omitted when empty */],"by_directory":[/* DirectoryComplexityMetrics array; empty when no functions are reported */],"summary":{/* ComplexitySummary */},"raw_metrics":[/* RawMetrics array, present when computed */],"raw_metrics_summary":{/* RawMetricsSummary, present when computed */},"warnings":["..."],"errors":["..."],"failures":[/* AnalysisFailure array, absent when empty */],"generated_at":"2026-04-14T10:18:23Z","version":"0.14.0","config":null}
The standalone complexity formatter uses by_directory at the report root beside results, optional class_scopes, summary, and metadata. results retains the established module/function collection; class_scopes contains executable class suites. Directory entries remain function-only and their semantics are identical to unified output.
functions[] and class_scopes[] element (FunctionComplexity)¶
Field
Type
Description
name
string
Qualified scope name. <module> for module-level code.
scope_kind
string
Required execution owner: module, function, or class.
Deprecated. Always equal to total_functions; kept for schema compatibility and will be removed.
average_complexity
number
Arithmetic mean of complexity across module and function scopes.
average_cognitive_complexity
number
Arithmetic mean of cognitive_complexity across module and function scopes.
average_nesting_depth
number
Arithmetic mean of nesting_depth across module and function scopes.
max_complexity
integer
Highest complexity among module and function scopes.
min_complexity
integer
Lowest complexity among module and function scopes.
max_class_complexity
integer
Highest class-suite cyclomatic complexity.
max_class_cognitive_complexity
integer
Highest class-suite cognitive complexity.
max_class_nesting_depth
integer
Highest class-suite nesting depth.
high_risk_class_scopes
integer
Class suites classified as high risk.
files_analyzed
integer
Files that were parsed and contributed to the metrics above.
total_files
integer
Files the request covered, parsed or not.
skipped_files
integer
Files dropped because they could not be read or parsed. Their contents are absent from every metric above.
low_risk_functions
integer
Module and function scopes with risk_level = low.
medium_risk_functions
integer
Module and function scopes with risk_level = medium.
high_risk_functions
integer
Module and function scopes with risk_level = high.
complexity_distribution
object
Function-only histogram keyed by complexity bucket (string) to count (integer), or null.
Class-scope counts and maxima are additive hotspot metrics. Adding a class scope does not change the legacy function collections, counts, averages, extrema, risk distribution, complexity distribution, module or directory rollups, or health score.
Summary, module-quality, optional community, and directory-complexity metrics. Two columns. Literal UTF-8 strings, no type annotations.
Column
Type
Description
Metric
string
Metric name.
Value
string
Metric value as string.
Rows (in this fixed order):
Metric,Value
Health Score,<integer>
Grade,<A|B|C|D|F|N/A>
Total Files,<integer>
Analyzed Files,<integer>
Skipped Files,<integer>
Total Functions,<integer>
Class Scopes,<integer>
Average Complexity,<float with 2 decimals>
High Complexity Count,<integer>
Dead Code Count,<integer>
Critical Dead Code,<integer>
Unique Fragments,<integer>
Clone Groups,<integer>
Code Duplication,<float with 2 decimals>
Total Classes Analyzed,<integer>
High Coupling (CBO) Classes,<integer>
Average CBO,<float with 2 decimals>
Module Quality Count,<integer>
Diagnostic,<file_path> [<code>]: <message>
Analysis Failure,<analysis> <file_path> [<code>]: <message>
Module 1 Name,<string>
Module 1 File Path,<string>
Module 1 Lines of Code,<integer>
Module 1 Function Count,<integer>
Module 1 Analyzed Function Count,<integer>
Module 1 Average Complexity,<float with 2 decimals>
Module 1 Average Cognitive Complexity,<float with 2 decimals>
Module 1 Max Complexity,<integer>
Module 1 High Risk Function Count,<integer>
Module 1 Exception Handler Count,<integer>
Module 1 Dead Code Findings,<integer>
Module 1 Dead Code Blocks,<integer>
Directory Complexity Count,<integer>
Directory 1 Path,<string>
Directory 1 Function Count,<integer>
Directory 1 Average Complexity,<float with 2 decimals>
Directory 1 Max Complexity,<integer>
Directory 1 High Risk Function Count,<integer>
Directory 1 Average Nesting Depth,<float with 2 decimals>
Directory 1 Max Nesting Depth,<integer>
The Diagnostic and Analysis Failure rows repeat once per corresponding entry and are omitted when empty. They appear before the numbered module rows. The numbered module and directory row groups repeat once per corresponding entry in the same order. Directory rows are appended after all summary, diagnostic, failure, module, and optional community rows, and are omitted when complexity analysis is disabled. CSV remains a summary format; use --json or --yaml for per-scope and per-finding detail.
The standalone complexity formatter emits one row per reported module, function, or class scope. Existing columns remain in place and Scope Kind is appended:
Mirrors domain.CommunityAnalysisResult. Emitted as a top-level field in unified pyscn analyze JSON/YAML when community detection runs. When pyscn analyze --json --select communities is used, the report file contains only this object (standalone JSON).
Cohesion within the community: share of internal edges whose endpoints share a package, or dominant-package module ratio when no qualifying internal edges exist.
dominant_layer
string | absent
Configured layer with the most modules in this community.
layer_count
integer | absent
Distinct configured layers represented in this community.
layers
array | absent
Configured layer names present in this community (sorted).
layer_alignment
number | absent
Cohesion within the community: share of internal edges whose endpoints share a layer, or dominant-layer module ratio when no qualifying internal edges exist.
A compact, deterministic view of the communities optimized for AI coding/review agents: which modules to inspect together, and which modules bridge otherwise-separate clusters. Derived entirely from the community analysis (no LLM-generated content).
Community detection is deterministic for a fixed codebase snapshot and configuration: repeated runs yield identical communities, bridge_modules, and modularity. Module and community ordering in JSON is stable (sorted ids and module names). Numeric fields are rounded to four decimal places for diff-friendly output. Results may change across pyscn versions or when min_community_size, resolution, or include_lazy_edges change. See Module Community Detection for details.
pyscn analyze takes one of --json, --yaml, --csv, --text, or --html (default). There is no --format flag, and there are no standalone complexity / deadcode / clone / deps subcommands. Run a single analyzer via --select.
--select communities with --json writes standalone community JSON (not the unified AnalyzeResponse wrapper). YAML standalone output is not supported yet; use unified pyscn analyze --yaml or --json --select communities.
Output files land in .pyscn/reports/; see Output Formats for path and filename details.