Observed since 20 Oct, 18:43 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Free, open-source linter for Acumatica customization projects. The full pipeline is AcuOps.
Free, open-source linter for Acumatica customization projects. Catches publish-time failure modes — silent
NullReferenceExceptions, dropped DAC extensions, orphan SiteMap rows, GI catalog exclusions, schema mutations withoutIF NOT EXISTSguards — before they restart your production app pool.Want this run automatically on every PR, plus sandbox dry-run before prod, snapshot/rollback with integrity verification, Codex AI review, Slack telemetry, and deploy-window enforcement? → AcuOps
pip install acumatica-lint
Python 3.10+. One dependency (pyyaml for the ISV co-publish allowlist parser). Works on macOS, Linux, and Windows.
Point it at a project.xml:
acumatica-lint Customization/MyPackage/project.xml
With strict mode (additional warnings for best-practice violations):
acumatica-lint --strict Customization/MyPackage/project.xml
ISV authors — enforce a class-name prefix on all <Graph> declarations:
acumatica-lint --isv-prefix AO Customization/MyISV/project.xml
Debug-only DLL-source plugin scan (skips XML/Graph/semantic checks):
acumatica-lint --dll-source-only Customization/MyPackage/project.xml
0 — passed (with or without warnings)1 — failed (one or more hard-fail errors)2 — usage error (bad CLI args)acumatica-lint encodes ~60 failure-mode rules from real Acumatica production incidents Studio B has resolved. A non-exhaustive list:
<Sql> ALTER TABLE — auto-column creation has been broken on cloud Acumatica since early 2026. [PXDBx] fields without a corresponding <Sql> ALTER will silently fail at publish.<GITable Name> — silently aborts GI processing without an error in the publish log.<RolesInGraph Rolename="*" Accessrights="4" ApplicationName="/" /> AND a matching entry in the package's CustomizationPlugin allowlist. Miss either and the GI silently catalog-excludes, returning HTTP 404 from /OData/{tenant}/$metadata.ParentID="00000000-...") — invisible in SM205010 (Access Rights by Role), ungrantable, OData 404.GITable.Name must be fully-qualified DAC name; <GIWhere Condition> must use Acumatica's vocabulary ("E ", "NE", "GE", etc., NOT "EQ"); <GIWhere> attribute name is Operation= NOT Operator=; MUIScreen.SubcategoryID must point at tenant-real subcategory, not auto-created system-default.<Sql> re-execution warnings — <Sql> scripts are tracked by Name; bumping to _v2 is silently skipped. For logic that must survive every publish, use CustomizationPlugin.PXDatabase.Execute().<EntityEndpoint> mapping — PUT returns HTTP 200 + echoes value + silent-drops at commit. Three places must match: SQL column, DAC attribute, inline <EntityEndpoint> block.WebConfigurationManager, HttpContext); SQL against GI* tables in UpdateDatabase(); SQL against INUnit; INSERT/UPDATE/SELECT column refs on Acumatica system tables outside the allowlist..cs under src/<DllName>/ when project.xml references <File AppRelativePath="Bin\<DllName>.dll" />.--isv-prefix, validates that every <Graph ClassName=> follows your ISV convention.<EntityEndpoint> block requirements — must be a top-level child of <Customization> in project.xml; standalone EntityEndpoint_*.xml at zip root is NOT processed.Every hard-fail check ships an escape-hatch comment marker for audited exceptions:
<!-- REVIEWED: gi-sql-safe — suppress validate_gi_sql -->
<!-- REVIEWED: inunit-sql-safe — suppress validate_inunit_sql -->
<!-- REVIEWED: schema-safe — suppress validate_plugin_sql_column_refs -->
This linter is the deterministic check engine. It runs once, against one project, returns errors and warnings, exits.
It does not:
merge=true partial-publish corruption)CustomizationPlugin.UpdateDatabase() with AI to flag non-obvious correctness issues a static rule can't catch:rotating_light: Slack notifications when a publish failspublishBegin page count past Acumatica's ThreadAbortException limitAll of that is AcuOps — the managed pipeline. $800/mo per Acumatica instance.
AcuOps is selecting 7–10 founding partners locked at $500/mo for the life of subscription in exchange for a published case study + reference availability. We're picking partners across VAR, ISV, in-house mid-market, and enterprise deployment patterns. → Apply
Pull requests welcome. New rules should:
project.xml snippet that triggers the rule) and a negative exampleCoding style is enforced by ruff. Run pip install -e ".[dev]" then ruff check src/.
Apache 2.0 — see LICENSE.
The Apache 2.0 patent grant protects all contributors from patent litigation over contributed code. This matters when the codebase encodes hard-won failure-mode knowledge from real production incidents.
Studio B (studiob.ai) runs Acumatica deployments at scale across its portfolio. acumatica-lint is the static-check engine extracted from the AcuOps pipeline — the same code paths Studio B uses against its own production deployments.
The full pipeline → acuops.com
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.3.0 | 1 Jun 2026 | 4 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Observed since 20 Oct, 18:43 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:6a391814e3717da22395579a0654d1c8bc3d53d6551376d7260457ae1c17710f