Papyrus Lint Export for AI document
The JSON document produced by the desktop app's Export for AI feature or the CLI's --format ai option. It contains the GUI's currently filtered lint findings, or the CLI's unfiltered findings, and metadata for each recognized rule represented in those findings.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://papyrus-lint.idrinth.de/schema/papyrus-lint-ai-export.v3.schema.json",
"title": "Papyrus Lint Export for AI document",
"description": "The JSON document produced by the desktop app's Export for AI feature or the CLI's --format ai option. It contains the GUI's currently filtered lint findings, or the CLI's unfiltered findings, and metadata for each recognized rule represented in those findings.",
"type": "object",
"additionalProperties": false,
"required": [
"$schema",
"header",
"configuration",
"findings",
"rule_details"
],
"properties": {
"$schema": {
"description": "The canonical JSON Schema for validating and interpreting this AI export document.",
"const": "https://papyrus-lint.idrinth.de/schema/papyrus-lint-ai-export.v3.schema.json"
},
"header": {
"$ref": "#/$defs/header"
},
"configuration": {
"description": "The fully resolved lint configuration used to produce the findings, including defaults for settings omitted from the project's YAML file.",
"$ref": "#/$defs/configuration"
},
"filters": {
"description": "The desktop GUI result filters active when the export was generated. This is optional because these filters do not exist in non-GUI integrations.",
"$ref": "#/$defs/filters"
},
"findings": {
"$ref": "#/$defs/findingsReport"
},
"rule_details": {
"description": "Tag metadata for each recognized rule represented in findings. Triggered rule ids for which Papyrus Lint has no metadata are omitted.",
"type": "array",
"uniqueItems": true,
"items": {
"$ref": "#/$defs/ruleDetail"
}
}
},
"$defs": {
"severity": {
"description": "A diagnostic severity bucket.",
"type": "string",
"enum": [
"error",
"warning",
"info"
]
},
"importance": {
"description": "A rule's relative importance.",
"type": "string",
"enum": [
"low",
"medium",
"high"
]
},
"ruleId": {
"description": "A stable, hyphenated lint rule identifier.",
"type": "string",
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
},
"filters": {
"type": "object",
"additionalProperties": false,
"required": [
"filename_pattern",
"severities",
"importances",
"rules",
"auto_fixable_only"
],
"properties": {
"filename_pattern": {
"description": "The filename search pattern, including any glob-like *, %, or ? characters; an empty string matches every file.",
"type": "string"
},
"severities": {
"description": "The diagnostic severity buckets selected in the GUI. The GUI never lets every bucket in a filter group (severities, importances, or rules) be deselected at once, so this is never empty; a bucket left out here was deliberately excluded, not \"no restriction\".",
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"$ref": "#/$defs/severity"
}
},
"importances": {
"description": "The rule importance levels selected in the GUI. Never empty; see severities above for why.",
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"$ref": "#/$defs/importance"
}
},
"rules": {
"description": "The rule ids selected across the GUI's kind-grouped rule filters. Never empty; see severities above for why. A finding whose rule carries no known tag metadata (e.g. a compiler-reported diagnostic) is exempt from this filter and importances, so it can still appear in findings even though its own rule id isn't listed here.",
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"$ref": "#/$defs/ruleId"
}
},
"auto_fixable_only": {
"description": "Whether the GUI was restricted to findings from auto-fixable rules.",
"type": "boolean"
}
}
},
"configuration": {
"type": "object",
"additionalProperties": false,
"required": [
"semicolon",
"indentation",
"indentation_width",
"identifier_casing",
"cyclomatic_complexity_warning",
"cyclomatic_complexity_error",
"type_casing",
"named_arguments",
"min_wait_interval",
"magic_numbers",
"fail_on_warning",
"fail_on_info",
"bool_like_int",
"assume_auto_properties_filled",
"enabled_rules"
],
"properties": {
"semicolon": {
"type": "boolean"
},
"indentation": {
"type": "string",
"enum": [
"tab",
"space"
]
},
"indentation_width": {
"type": "integer",
"minimum": 0,
"description": "A value of 0 is only valid for tabs. For spaces the value will be equal or greater 1"
},
"identifier_casing": {
"type": "string",
"enum": [
"camelCase",
"PascalCase",
"snake_case",
"CONSTANT_CASE"
]
},
"cyclomatic_complexity_warning": {
"description": "The cyclomatic complexity a function/event can reach before the cyclomatic-complexity finding's severity is [warning].",
"type": "integer",
"minimum": 0
},
"cyclomatic_complexity_error": {
"description": "The cyclomatic complexity a function/event can reach before the cyclomatic-complexity finding's severity is [error]. This value as configured can be lower than cyclomatic_complexity_warning, but Papyrus Lint then treats it as equal to cyclomatic_complexity_warning when actually deciding a finding's severity, since a lower error threshold would otherwise contradict the warning one it's supposed to escalate.",
"type": "integer",
"minimum": 0
},
"type_casing": {
"type": "string",
"enum": [
"PascalCase",
"camelCase",
"lowercase",
"UPPERCASE"
]
},
"named_arguments": {
"type": "string",
"enum": [
"always",
"instead_of_defaults",
"never"
]
},
"min_wait_interval": {
"type": "number",
"minimum": 0
},
"magic_numbers": {
"type": "string",
"enum": [
"loose",
"strict"
]
},
"fail_on_warning": {
"type": "boolean"
},
"fail_on_info": {
"type": "boolean"
},
"bool_like_int": {
"type": "boolean"
},
"assume_auto_properties_filled": {
"type": "boolean"
},
"enabled_rules": {
"description": "The hyphenated ids of every currently enabled lint rule, alphabetically sorted. A rule not listed here is disabled. Disabled rules will not be listed in the findings.",
"type": "array",
"uniqueItems": true,
"items": {
"$ref": "#/$defs/ruleId"
}
}
},
"if": {
"properties": {
"indentation": {
"const": "space"
}
}
},
"then": {
"properties": {
"indentation_width": {
"minimum": 1
}
}
}
},
"header": {
"type": "object",
"additionalProperties": false,
"required": [
"tool",
"version",
"website",
"target_game",
"generated_at"
],
"properties": {
"tool": {
"description": "The application that produced this document.",
"const": "Papyrus Lint"
},
"version": {
"description": "The running desktop app's version, or `unknown` when it could not be read.",
"type": "string",
"minLength": 1
},
"website": {
"description": "The Papyrus Lint website, where additional rule and configuration documentation is available.",
"type": "string",
"format": "uri"
},
"target_game": {
"description": "The Papyrus dialect/engine these findings and rule details were produced for. Papyrus Lint has no per-project game/edition setting, so this is fixed.",
"enum": [
"Skyrim SE/AE"
]
},
"generated_at": {
"description": "The UTC date and time at which this export was generated, in RFC 3339 format.",
"type": "string",
"format": "date-time",
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$"
}
}
},
"findingsReport": {
"description": "The filtered findings. Every exported file has at least one diagnostic (see `fileReport`).",
"type": "object",
"additionalProperties": false,
"required": [
"files",
"total_diagnostics",
"severity_counts",
"rule_counts"
],
"properties": {
"files": {
"type": "array",
"items": {
"$ref": "#/$defs/fileReport"
}
},
"total_diagnostics": {
"description": "The total number of exported diagnostics across all files.",
"type": "integer",
"minimum": 0
},
"severity_counts": {
"description": "The sum of all file severity counts.",
"$ref": "#/$defs/severityCounts"
},
"rule_counts": {
"$ref": "#/$defs/ruleCounts"
}
}
},
"fileReport": {
"type": "object",
"additionalProperties": false,
"required": [
"path",
"severity_counts",
"rule_counts",
"diagnostics",
"source"
],
"properties": {
"path": {
"description": "The script path relative to the currently loaded project when possible.",
"type": "string",
"minLength": 1
},
"diagnostics": {
"description": "The diagnostics for this script that passed every active results filter.",
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/diagnostic"
}
},
"rule_counts": {
"$ref": "#/$defs/ruleCounts"
},
"severity_counts": {
"$ref": "#/$defs/severityCounts"
},
"source": {
"description": "How this script's source is represented: null when none was attached at all; otherwise an object whose \"type\" names which of the other three forms it takes.",
"oneOf": [
{
"type": "null"
},
{
"$ref": "#/$defs/sourceContent"
},
{
"$ref": "#/$defs/sourceHash"
},
{
"$ref": "#/$defs/sourceError"
}
]
}
}
},
"ruleCounts": {
"description": "Counts of exported diagnostics grouped by rule id. Rules with no diagnostics are omitted.",
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^[a-z0-9]+(?:-[a-z0-9]+)*$": {
"type": "integer",
"minimum": 1
}
}
},
"severityCounts": {
"description": "Counts of exported diagnostics grouped by severity.",
"type": "object",
"additionalProperties": false,
"required": [
"errors",
"warnings",
"info"
],
"properties": {
"errors": {
"type": "integer",
"minimum": 0
},
"warnings": {
"type": "integer",
"minimum": 0
},
"info": {
"type": "integer",
"minimum": 0
}
}
},
"sourceContent": {
"description": "This script's current on-disk contents, letting the assistant see the code each diagnostic refers to without the project open.",
"type": "object",
"additionalProperties": false,
"required": [
"type",
"content"
],
"properties": {
"type": {
"const": "content"
},
"content": {
"type": "string"
}
}
},
"sourceHash": {
"description": "This script's content hash instead of its full text, attached via the desktop app's \"Redact source\" export option or the CLI's --hash-source flag so a report can be shared without exposing proprietary script text; a viewer can still tell files apart, or notice a file changed between exports, from the hash alone.",
"type": "object",
"additionalProperties": false,
"required": [
"type",
"algorithm",
"hash"
],
"properties": {
"type": {
"const": "hash"
},
"algorithm": {
"enum": [
"md5"
]
},
"hash": {
"description": "The lowercase hex digest of this script's current on-disk contents.",
"type": "string",
"pattern": "^[0-9a-f]+$"
}
}
},
"sourceError": {
"description": "Why this script's source couldn't be attached, e.g. it was moved or deleted since linting.",
"type": "object",
"additionalProperties": false,
"required": [
"type",
"message"
],
"properties": {
"type": {
"const": "error"
},
"message": {
"type": "string"
}
}
},
"diagnostic": {
"type": "object",
"additionalProperties": false,
"required": [
"line",
"column",
"rule",
"level",
"message",
"doc_url"
],
"dependentRequired": {
"external": [
"source"
],
"source": [
"external"
]
},
"properties": {
"line": {
"description": "The 1-indexed source line where the diagnostic starts.",
"type": "integer",
"minimum": 1
},
"column": {
"description": "The 1-indexed source column where the diagnostic starts.",
"type": "integer",
"minimum": 1
},
"rule": {
"description": "The stable, hyphenated lint rule id.",
"$ref": "#/$defs/ruleId"
},
"level": {
"description": "The diagnostic severity. Untagged external diagnostics are classified as errors.",
"$ref": "#/$defs/severity"
},
"message": {
"description": "The human-readable diagnostic message.",
"type": "string",
"minLength": 1
},
"external": {
"description": "Present and `true` only for a diagnostic raised by a tool outside Papyrus Lint's own lint rules rather than one of Papyrus Lint's own rules; see `source` for which tool. Omitted for an ordinary lint finding.",
"const": true
},
"source": {
"description": "Which external tool raised this diagnostic. Present only alongside `external`. Currently always `compiler`, for a diagnostic parsed out of PapyrusCompiler.exe's own reported errors (rule `compiler-error`).",
"const": "compiler"
},
"repair": {
"description": "What this diagnostic's line would look like after applying its rule's automatic fix, present only when Papyrus Lint could compute one. Omitted for a rule with no automatic fix, for a finding that fix wouldn't actually change (e.g. type-casing's own \"no automatic fix\" case), or when the fix would shift the file's line count elsewhere (e.g. property-sorting relocating a property's declaration).",
"type": "string",
"minLength": 1
},
"doc_url": {
"description": "This rule's own documentation link on the project website, so the assistant can look up its full explanation, or null for a rule with no known tag metadata (e.g. a compiler-reported diagnostic).",
"type": [
"string",
"null"
],
"format": "uri"
}
}
},
"ruleDetail": {
"type": "object",
"additionalProperties": false,
"required": [
"rule",
"description",
"kinds",
"importance",
"auto_fixable",
"doc_url"
],
"properties": {
"rule": {
"description": "The stable, hyphenated identifier of the lint rule.",
"$ref": "#/$defs/ruleId"
},
"description": {
"description": "The rule's detailed description, copied from its row in the project README's Implemented Lints tables.",
"type": "string",
"minLength": 1
},
"kinds": {
"description": "The classes of issue this rule detects.",
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "string",
"enum": [
"style",
"performance",
"correctness",
"maintainability"
]
}
},
"importance": {
"description": "The rule's relative importance.",
"$ref": "#/$defs/importance"
},
"auto_fixable": {
"description": "Whether Papyrus Lint can automatically fix this rule's findings.",
"type": "boolean"
},
"doc_url": {
"description": "This rule's own documentation link on the project website (its row on the Implemented Lints table), so an assistant or a human reader can jump straight to it.",
"type": "string",
"format": "uri"
}
}
}
}
}