AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A fast linter for Ignition 8.3 projects: Perspective views, Jython scripts, expressions and the references between them. CLI, pre-commit, language server and VS Code.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A fast linter for Ignition 8.3 projects, written in Rust.
iglint reads an Ignition project the way the gateway stores it on disk and checks:
view.json (findings point inside the JSON string);It has more than 100 rules, auto-fixes, a language server for editors, and a compatibility mode for projects that use ign-lint. See the rule reference and the documentation at https://iglint.mustrysolutions.com/.
system.* functions, expression
functions and Perspective components come from a real 8.3 gateway. A false
positive is a bug.Benchmarks against ign-lint and how to reproduce them are in bench/README.md.
Prebuilt binaries are attached to every
GitHub release:
iglint-linux-x64.tar.gz, iglint-linux-arm64.tar.gz (static, any
distribution), iglint-macos.tar.gz (Intel and Apple silicon) and
iglint-windows-x64.zip, with their checksums in SHA256SUMS. Unpack the
archive and put iglint (or iglint.exe) on your PATH:
curl -sSfL https://github.com/Mustry-Solutions/iglint/releases/download/v0.1.0/iglint-linux-x64.tar.gz | tar -xz
sudo install iglint-linux-x64/iglint /usr/local/bin/
With Cargo (Rust 1.90 or newer):
cargo install --locked --git https://github.com/Mustry-Solutions/iglint --tag v0.1.0 iglint
# or, from a clone:
cargo install --locked --path crates/iglint
The VS Code extension is on the
Visual Studio Marketplace,
with the binary for every platform inside. It is also attached to the
releases as iglint-vscode.vsix:
code --install-extension mustry-solutions.iglint
The PyPI wheel contains the binary and no Python code:
pip install iglint # or: uv tool install iglint / pipx install iglint
Check the installation with iglint --version. More details are on the
installation page of
the documentation.
Run iglint in the directory that holds your projects/ folder (a gateway
data directory or a project repository):
iglint # same as `iglint check .`
iglint check projects/MyProject
iglint check --fix # apply safe fixes
iglint check --diff # show the fixes instead of writing them
iglint check --statistics # count findings per rule
iglint rules # list the rules
iglint rule SCR101 # explain a rule
A directory is searched for Ignition projects and gateway resource
collections; Python files are linted as Ignition scripts only inside
them. A .py file named on the command line is linted on its own, as a
standalone script. When a directory holds nothing to lint (a folder of
loose .py files without a project.json), the run says so on standard
error and exits with 0.
Output looks like this:
projects/fixture-hmi/com.inductiveautomation.perspective/views/Main/Overview/view.json:85:43: BIND004 [warning] `now` polls every 1000 ms, faster than the minimum of 10000 ms
|
85 | "expression": "dateFormat(now(1000), \"HH:mm:ss\")"
| ^^^
|
= note: at root/Clock.props.text@binding
Exit status: 0 when no finding reaches the --error-on level (default
warning), 1 when one does, 2 for usage, configuration and internal
errors. --exit-zero always exits with 0 on findings.
iglint looks for iglint.toml, .iglint.toml or a pyproject.toml with a
[tool.iglint] table, starting at the linted path and going up. Without one,
the default rule set runs. Every key is optional:
# iglint.toml
# extend = "../shared/iglint.toml" # build on another configuration file
# select = ["ALL"] # replace the default set
extend-select = ["NAME001", "REF011"] # opt-in rules, on top of the defaults
ignore = ["A11Y"] # codes, prefixes, names or categories
# unfixable = ["NAME001"] # report, but never apply these fixes
exclude = ["projects/Sandbox/**"] # never lint these paths
# extend-exclude = ["projects/Old/**"] # add to the excludes of `extend`
strict = false # also report dynamic references
baseline = "ci/iglint-baseline.json" # default: .iglint-baseline.json, if present
# projects = ["../shared/projects/Base"] # more of the workspace
# gateways = ["../gateway/data/config/resources"]
# respect-gitignore = true # skip files Git ignores
# cache-dir = ".iglint_cache" # default: .iglint_cache in the root
# output-format = "text"
[rules.BIND004] # or [rules.polling-interval]
minimum-interval = 5000
[rules.SCR103]
severity = "error"
exclude = ["projects/*/ignition/script-python/legacy/**"]
[rules.NAME001]
convention = "PascalCase"
target-node-types = ["component"]
[[overrides]]
files = ["projects/Legacy/**"]
ignore = ["NAME"]
severity = { SCR = "info" }
[fix]
# assume-scripts-do-not-read-workspace-files = true # see below
# vetted-system-functions = ["system.mes.getThing"] # see below
# vetted-expression-functions = ["myModuleFunction"]
select replaces the default set, extend-select adds to it, ignore
(or its alias extend-ignore) removes rules. Selectors are rule codes
(SCR101), names (undefined-name), code prefixes (SCR1), categories
(SCR) or ALL.extend names another configuration file (a TOML file with these keys,
or a pyproject.toml with [tool.iglint]), relative to this one, that
this file builds on; it may extend another in turn (a cycle is an
error). The base is read first: a key this file sets wins, the
select/ignore lists of each file apply in order (base first),
[rules.*] tables are merged per rule and [[overrides]] are added.exclude replaces the excludes of an extended file, extend-exclude
adds to them.unfixable (selectors, default none): findings of these rules are
still reported, but their fixes are never applied (--fix, the
editor).projects and gateways (paths relative to the configuration file,
default none): more project directories and gateway configuration
trees for the workspace. They are analysed with the rest (parent
projects, references, the safety of fixes) but only linted when you
name them on the command line.respect-gitignore (default true): skip files that .gitignore,
.ignore and Git's excludes ignore. Ignored files still count for the
workspace analysis; they are only not reported.cache-dir (default .iglint_cache in the root): where the result
cache lives; --cache-dir overrides it and --no-cache turns the
cache off.[rules.<code or name>] sets severity, enabled, a per-rule exclude
and the rule's options (see each rule's page).[[overrides]] apply other settings to the files matching files.[fix] assume-scripts-do-not-read-workspace-files (default false):
every fix edits a file of the workspace, and a script that reads that
file (open(path).read(), its size or modification time) sees the
edit; a script that writes, appends to, renames or deletes one changes
what the fix edits or moves it where a later read sees it. So while
any code in the workspace may access a workspace file (any file
operation whose path is not a literal outside the workspace, whatever
its mode, or code that is not vetted), every fix is unsafe and says
where that code is. Setting
this to states that no script reads the files of the workspace;
checking that is your responsibility. It lifts only this condition,
not the other reasons a fix may be unsafe.iglint check --show-settings prints the settings that apply to a path, and
iglint check --show-files the files that would be linted.
iglint has an equivalent for every ign-lint rule and reads ign-lint's configuration.
Convert once: iglint migrate turns rule_config.json into
iglint.toml. If an ign-lint whitelist (.ignition-lint-whitelist.txt or
.whitelist.txt) exists, the whitelisted files' current findings go into a
baseline instead, so those files are linted from now on and only new
findings fail. iglint migrate --dry-run shows the result first.
ign-lint lints only view.json files, so the rules it runs on top of
iglint's defaults (SCR900, which runs pylint, above all) are selected
for views only, in an [[overrides]] entry with
files = ["**/view.json"]; library modules, gateway events and WebDev
scripts get iglint's native rules. Move a rule out of that entry (into
extend-select) to run it everywhere. iglint check with a
rule_config.json uses the same scope.
Keep the old command line: iglint ign-lint [ARGS] accepts ign-lint
0.6.4's arguments (--config, --files, --whitelist,
--ignore-warnings, --results-output, ...) and prints ign-lint's output
format. Called through a link named ign-lint, the binary behaves the same,
so existing scripts keep working:
ln -s "$(command -v iglint)" /usr/local/bin/ign-lint
ign-lint --config rule_config.json --files "**/view.json"
iglint check also reads a rule_config.json when no iglint.toml
exists, with a deprecation warning.
[!WARNING]
iglint ign-lintfinds more than ign-lint, so a CI gate that passes with ign-lint can fail after the switch. For example,BIND005reports references to viewcustomproperties andparamsthat do not exist, which ign-lint'sComponentReferenceValidationRuledoes not check, andPylintScriptRulealso runs iglint's own script rules.iglint ign-linthas no baseline (its--whitelistskips whole files). To adopt iglint without breaking the build, runiglint migrateand theniglint baselinefirst, and gate oniglint check: today's findings are recorded in.iglint-baseline.jsonand only new ones fail. The extraBIND005errors are real (a reference that resolves nowhere evaluates tonullwith a bad quality); the baseline lets you fix them over time.
The differences in findings are listed in docs/compat/ign-lint-differences.md.
In scripts, with a comment:
value = legacy_global # iglint: ignore[SCR101]
x = 1 # iglint: ignore[unused-variable, SCR1]
# iglint: ignore-file[SCR102]
ignore applies to findings that start on the comment's line; at the end
of a statement that spans several lines, to the whole statement.
ignore-file applies to the whole script. Unused suppressions are reported
(SCR123).
view.json and other JSON resources have no comments: use exclude, a
per-rule exclude, [[overrides]] or the baseline.
A baseline records the current findings so that only new ones fail, which lets you adopt iglint on a large project at once:
iglint baseline # writes .iglint-baseline.json
iglint check # known findings are hidden; new ones fail
iglint check --prune-baseline # drop entries whose findings were fixed
Entries are matched by rule, file and a fingerprint that survives moving code
around. Paths in the baseline are relative and use /, so one file works on
every platform. Commit it.
--output-format (or output-format in the configuration) takes text
(default), concise, grouped, json, json-lines, sarif, github,
azure, gitlab, junit and pylint. --output-file FILE writes the
report to a file.
GitHub Actions, with annotations on the pull request and code scanning:
- name: Install iglint
run: |
curl -sSfL https://github.com/Mustry-Solutions/iglint/releases/download/v0.1.0/iglint-linux-x64.tar.gz \
| tar -xz -C "$RUNNER_TEMP"
echo "$RUNNER_TEMP/iglint-linux-x64" >> "$GITHUB_PATH"
- run: iglint check --output-format github
- run: iglint check --output-format sarif --output-file iglint.sarif --exit-zero
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: iglint.sarif
(Uploading SARIF needs permissions: security-events: write.)
Azure DevOps (##vso[task.logissue] lines show up in the build summary):
- script: |
curl -sSfL https://github.com/Mustry-Solutions/iglint/releases/download/v0.1.0/iglint-linux-x64.tar.gz \
| tar -xz -C "$(Agent.TempDirectory)"
"$(Agent.TempDirectory)/iglint-linux-x64/iglint" check --output-format azure
displayName: iglint
GitLab Code Quality:
iglint:
image: python:3.12 # any Linux image with curl
script:
- curl -sSfL -o /tmp/iglint.tar.gz https://github.com/Mustry-Solutions/iglint/releases/download/v0.1.0/iglint-linux-x64.tar.gz
- tar -xzf /tmp/iglint.tar.gz -C /usr/local/bin --strip-components=1 iglint-linux-x64/iglint
- iglint check --output-format gitlab --output-file gl-code-quality-report.json
artifacts:
when: always
reports:
codequality: gl-code-quality-report.json
JUnit XML (--output-format junit) works with most other CI systems. The
examples download the static Linux x86_64 binary of v0.1.0;
pip install iglint==0.1.0 does the same in an image with Python.
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Mustry-Solutions/iglint
rev: v0.1.0
hooks:
- id: iglint # or iglint-fix to apply safe fixes
To replace ign-lint's own pre-commit hook, keep its id and change only
the repository: the ign-lint hook runs iglint ign-lint with the same
files pattern (view\.json$), file types, default args
(--config=.ignition-lint-precommit.json) and file passing, so your
configuration, args overrides, output and exit status stay as they were:
repos:
- repo: https://github.com/Mustry-Solutions/iglint # was bw-design-group/ignition-lint
rev: v0.1.0
hooks:
- id: ign-lint
args: ["--config=rule_config.json", "--ignore-warnings"] # optional, as before
These hooks build iglint from source on first use, which needs a Rust toolchain. A local hook can use the PyPI wheel instead:
repos:
- repo: local
hooks:
- id: iglint
name: iglint
entry: iglint check
language: python
additional_dependencies: ["iglint==0.1.0"]
types_or: [json, python]
require_serial: true
Only the changed files are reported and fixed, but iglint analyses the
whole workspace around them (every project and gateway collection below
the workspace root: the configuration file's directory, the directory that
holds projects/, or the Git work tree), so cross-resource rules and the
safety of fixes are the same as for a run over the whole repository. A
warm single-file run takes a few tens of milliseconds on a workspace of
3,000 files.
A linked Git work tree (git worktree add, also one inside the repository
such as .worktrees/feature or .claude/worktrees/feature) is a checkout
of its own: the hook that runs in it analyses the work tree's projects and
collections, as if it were a separate clone, and runs in the main checkout
do not read the work tree's files. Submodules and nested repositories
stay part of the repository around them. iglint reads the .git entries
on disk, not GIT_DIR or GIT_WORK_TREE, so the hook and a run from a
shell find the same workspace root.
iglint server is a language server (LSP over standard input and output):
findings while you type, quick fixes, "fix all" and rule documentation on
hover. Every fix it applies is computed when you pick it by a fresh
iglint check --fix of the folder on the disk as it would be after
saving the file you fix, so it is the fix the command line would make.
While any other open file has unsaved changes, no fix is computed: save
the other files first (editors that show disabled code actions, such as
VS Code, say so). Nor is one computed for a file that starts with a byte
order mark or is not valid UTF-8. The findings shown while you type leave
out pylint (SCR900): the server does not run pylint for them, and
iglint check reports them. The fresh check behind a fix runs pylint
when the configuration selects SCR900, as iglint check --fix does. The VS Code extension in
editors/vscode runs it; other editors can start
iglint server directly.
docs/rules/README.md lists every rule by category,
with its default severity, whether it runs by default and whether it can fix
findings. iglint rule <CODE> shows the same page in the terminal.
See CONTRIBUTING.md. Changes are listed in CHANGELOG.md.
Licensed under either of Apache License, Version 2.0 or MIT license at your option. Third-party material is listed in NOTICE.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in iglint by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
iglint is not affiliated with or endorsed by Inductive Automation.
true[fix] vetted-system-functions and vetted-expression-functions
(default empty): a system.* function or an expression function that
Ignition 8.3 does not have (one of a third-party module) may run code,
read a frame or read files, so it keeps the fixes that depend on what
code can do from being safe, and the fix says where it is. List the
ones you have checked cannot: a system.* path also covers what is
read from it (system.mes.getThing covers system.mes.getThing.x),
expression functions match in any letter case. Checking them is your
responsibility. SCR201's allow and BIND002's extra-functions
only silence those rules' findings./.--select, --extend-select,
--ignore, --strict, --config FILE, --isolated. --select
replaces the selection everywhere, [[overrides]] included, so an
override's select/extend-select cannot re-add a rule the command line
left out; --extend-select only adds and --ignore only removes. The
same holds in ign-lint compatibility mode and for migrated configurations.