Skip to main content

genvm-linter

Fast validation and schema extraction for GenLayer intelligent contracts.

Installation

pip install genvm-linter

Usage

# Run both lint and validate (default)
genvm-lint check contract.py

# Fast AST safety checks only (~50ms)
genvm-lint lint contract.py

# Full SDK semantic validation (~200ms cached)
genvm-lint validate contract.py

# Extract ABI schema
genvm-lint schema contract.py
genvm-lint schema contract.py --output abi.json

# Pyright type checking with SDK auto-configured
genvm-lint typecheck contract.py
genvm-lint typecheck contract.py --strict      # Strict mode
genvm-lint typecheck contract.py --all         # Show all errors (disable SDK suppressions)

# IDE setup — download SDK and output extraPaths for Pylance
genvm-lint setup                               # Latest version
genvm-lint setup --contract contract.py        # Auto-detect version from header
genvm-lint setup --version v0.2.12             # Specific version
genvm-lint setup --json                        # JSON output for IDE integration

# Pre-download GenVM artifacts
genvm-lint download                    # Latest
genvm-lint download --version v0.2.12  # Specific version
genvm-lint download --list             # Show cached

# JSON output (all commands)
genvm-lint check contract.py --json

How It Works

Layer 1: AST Lint Checks (Fast)

  • Forbidden imports (random, os, time, etc.)
  • Non-deterministic patterns (float(), time.time())
  • Structure validation (dependency header)
  • Semantic consensus rule (GL-S03)

Semantic Rules (GL-S)

These rules run as part of Layer 1 and catch common mistakes in GenLayer consensus patterns.

GL-S03 — eq_principle_strict_eq nondeterminism mismatch (ERROR)

Flags eq_principle_strict_eq (all API generations: gl.eq_principle.strict_eq, eq_principle_strict_eq, eq_principle.strict_eq) wrapping a lambda or function that returns raw nondeterministic output directly. LLM outputs and raw web content vary across validators, so strict-equality consensus will always fail.

Detection is conservative — only flagged when the wrapped function/lambda returns the nondeterministic value without any transformation. Processed output (boolean comparisons, json.loads, sorted results, etc.) is not flagged.

Nondeterministic calls detected in two forms:

  • Namespace-qualified (v0.1.0 and v0.1.3+ APIs): gl.exec_prompt, gl.get_webpage, gl.nondet.exec_prompt, gl.nondet.web.render, and their genlayer.* equivalents
  • Bare names (direct SDK import convention): exec_prompt, get_webpage — matched when called without a namespace prefix, representing from genlayer.std.nondet_fns import exec_prompt style imports

Flagged patterns:

# Bad — namespace-qualified, LLM output is non-deterministic (v0.1.0 API)
gl.eq_principle.strict_eq(lambda: gl.exec_prompt("What is 2+2?"))

# Bad — namespace-qualified, raw web content varies (v0.1.0 API)
gl.eq_principle.strict_eq(lambda: gl.get_webpage("https://example.com"))

# Bad — namespace-qualified, v0.1.3+ API
gl.eq_principle.strict_eq(lambda: gl.nondet.exec_prompt("What is 2+2?"))
gl.eq_principle.strict_eq(lambda: gl.nondet.web.render("https://example.com"))

# Bad — bare name (direct import: from genlayer.std.nondet_fns import exec_prompt)
gl.eq_principle.strict_eq(lambda: exec_prompt("What is 2+2?"))

# Bad — named function returning raw nondet
def fetch():
    return gl.exec_prompt("What is 2+2?")

gl.eq_principle.strict_eq(fetch)

# Bad — simple passthrough variable
def fetch():
    result = gl.exec_prompt("What is 2+2?")
    return result

gl.eq_principle.strict_eq(fetch)

Not flagged (processed output or third-party calls):

# OK — bool is deterministic
gl.eq_principle.strict_eq(lambda: "Paris" in gl.get_webpage("https://example.com"))

# OK — comparison produces deterministic bool
def classify():
    data = gl.exec_prompt("Answer YES or NO")
    return data == "YES"

gl.eq_principle.strict_eq(classify)

# OK — third-party: my_service.exec_prompt is not a GL SDK call
gl.eq_principle.strict_eq(lambda: my_service.exec_prompt("What is 2+2?"))

Alias handling: GL-S03 matches by name convention, not by import tracking. Bare names exec_prompt and get_webpage are flagged when called without a namespace prefix (representing direct SDK imports such as from genlayer.std.nondet_fns import exec_prompt). Calls through a non-SDK object — e.g. my_service.exec_prompt() — are not flagged because my_service.exec_prompt is not in the matched name list.

Fix — switch to a comparative principle:

gl.eq_principle.prompt_comparative(
    lambda: gl.exec_prompt("What is 2+2?", response_format=int),
    principle="Return YES if both answers are numerically equal",
)

Layer 2: SDK Validation (Accurate)

  • Downloads GenVM release artifacts (cached at ~/.cache/genvm-linter/)
  • Loads exact SDK version specified in contract header
  • Validates types, decorators, storage fields
  • Extracts ABI schema

Exit Codes

  • 0 - All checks passed
  • 1 - Lint or validation errors
  • 2 - Contract file not found
  • 3 - SDK download failed

IDE Integration

VS Code Extension

This linter is used by the GenLayer VS Code Extension for real-time contract validation.

Manual Pylance Setup

Use genvm-lint setup to configure Pylance with the correct SDK paths. This gives you hover docs, go-to-definition, and type checking without the extension.

genvm-lint setup --contract contract.py

Add the output paths to your VS Code settings.json:

{
  "python.analysis.extraPaths": ["<output paths>"],
  "python.analysis.reportMissingModuleSource": "none"
}

Type Checking

genvm-lint typecheck runs Pyright with the SDK auto-configured. By default it suppresses SDK-internal noise (dynamic attributes, NewType compat). Use --all to see everything, --strict for strict mode.

Development

git clone https://github.com/genlayerlabs/genvm-linter.git
cd genvm-linter
pip install -e ".[dev]"
pytest

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

genvm_linter-0.11.0.tar.gz (78.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

genvm_linter-0.11.0-py3-none-any.whl (40.9 kB view details)

Uploaded Python 3

File details

Details for the file genvm_linter-0.11.0.tar.gz.

File metadata

  • Download URL: genvm_linter-0.11.0.tar.gz
  • Upload date:
  • Size: 78.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for genvm_linter-0.11.0.tar.gz
Algorithm Hash digest
SHA256 c287ae64ba58dfe2a62b538c17a31c5b89d4dcf50718a8a4d35137dc0ebc4ad3
MD5 e52fa5a145069838853606ff217c3ac3
BLAKE2b-256 ab50e72b51176c229b528c8dba26caa3343f54fbe552cac6fea173c4ef8eefb5

See more details on using hashes here.

File details

Details for the file genvm_linter-0.11.0-py3-none-any.whl.

File metadata

  • Download URL: genvm_linter-0.11.0-py3-none-any.whl
  • Upload date:
  • Size: 40.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for genvm_linter-0.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 58af368831d670e5a0b717400252fdfae88ff71fd65f9fb5fdd3ced326b6d90e
MD5 0168ec75a64ab7f4182e3cfa42f140c9
BLAKE2b-256 53a7c9bc251e4b07954a31ac1365063e2c6b0d24ca28e7fcdec20cec328341bd

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.11.0 This release

2 files

0.10.0

2 files

0.9.0

2 files

0.8.0

2 files

0.7.1

2 files

0.7.0

2 files

0.6.3

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.5

2 files

0.5.4

2 files

0.5.3

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.0

2 files

0.0.1

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page