Skip to main content

See what your code does to the world before it runs.

Project description

libgaze

See what your code does to the world before it runs.

$ libgaze check agent_tool.py

agent_tool.py  can Fs, Net, Unsafe

  restricted_import:75  can Unsafe
    99 | return __import__(name, custom_globals, custom_locals, fromlist or (), level)
  exec:119  can Unsafe
    126 | exec(code, {"__builtins__": SandboxPython.safe_builtins()}, locals)
  _run:194  can Fs, Net, Unsafe
    calls run_code_unsafe (line 347)
    calls run_code_safety (line 281)
  run_code_unsafe:347  can Unsafe
    365 | os.system(f"pip install {library}")
    370 | exec(code, {}, exec_locals)

2/13 functions are pure.

libgaze is a static effect analyzer for Python. It scans your code and reports which of 10 effects each function performs. Effects propagate through the call graph: if function A calls function B, A inherits B's effects.

Install

pip install libgaze

Usage

# Check a file
libgaze check myfile.py

# JSON output (for CI pipelines and agents)
libgaze check myfile.py --json

# Scan a directory
libgaze scan src/tools/

# Fail if denied effects are found (CI gate)
libgaze scan src/ --deny Unsafe,Db

# Check against a policy file
libgaze policy myfile.py --policy .gazepolicy

Policy files

A .gazepolicy file declares which effects are allowed or denied:

{
    "deny": ["Unsafe", "Db"],
    "functions": {
        "transform": { "allow": [] }
    }
}

The ten effects

Effect What it means
Net Touches the network
Fs Reads or writes files
Db Queries or mutates a database
Console Reads or writes the terminal
Env Reads environment variables
Time Reads the clock or sleeps
Rand Generates random numbers
Async Spawns concurrent tasks
Unsafe Subprocess, exec, eval, FFI, deserialization
Fail Can fail (sys.exit, etc.)

How it works

Two-pass analysis:

  1. AST walk. Detect direct effects from known functions (open, subprocess.run, os.getenv, etc.) and module imports (requests, sqlite3, docker, etc.).

  2. Call graph propagation. Trace self.method(), ClassName.method(), and bare function() calls within the same file. If a callee has effects, the caller inherits them. Iterate until stable.

This catches the common patterns. It does not catch effects hidden behind getattr, dynamic imports, method calls on injected objects, or metaclass magic. Silence doesn't mean safe.

Benchmark

Two benchmarks: a labeled accuracy suite and an unlabeled scale scan.

Accuracy (labeled, 101 functions)

8 files, 101 functions with human-labeled # EXPECT: ground truth. Stdlib patterns, class method propagation, async, network, edge cases, pure code, and real-world agent tools from CrewAI.

precision  100.0%
recall     100.0%
F1         100.0%
uv run --extra dev python bench/run.py

100% on a benchmark you wrote yourself is expected. It proves the tool works on the patterns it was designed for and catches regressions. Add a .py file to bench/ with # EXPECT: comments to extend it.

Scale (unlabeled, 12,511 functions)

1,604 files across 4 real agent framework repos: CrewAI Tools, LangChain Community, LangChain Core, and AutoGPT.

1,604 files, 12,511 functions
8,251 pure (66%), 4,260 effectful (34%)
71 functions with Unsafe + other effects

Effect frequency across all effectful functions:

Effect Count % of effectful
Async 2,125 50%
Net 1,621 38%
Fs 342 8%
Time 250 6%
Db 238 6%
Console 220 5%
Env 168 4%
Unsafe 106 2%
Rand 20 <1%

Spot-checked against source code: every flagged effect verified as real. Known false negatives occur on method calls to injected objects (e.g., self._firecrawl.scrape_url() where _firecrawl is a FirecrawlApp instance set in __init__). These are correctly reported as pure because libgaze does single-file analysis and cannot resolve the type.

uv run --extra dev python bench/scan_repos.py

Limitations

libgaze uses static AST analysis. Python is dynamic. The things it catches:

  • Direct calls to stdlib functions (open, os.system, subprocess.run)
  • Imports of known modules (requests, docker, sqlite3)
  • Intra-module call propagation (self.method(), ClassName.method())
  • Builtins (print, input, exec, eval)

The things it misses:

  • Method calls on injected objects (container.exec_run())
  • Dynamic dispatch (getattr(obj, name)())
  • Metaclass magic, monkey-patching, *args/**kwargs forwarding
  • Cross-file analysis (effects from imported user modules)

It's a first line of defense, not a proof.

Part of Gaze

libgaze is the Python effect analyzer from the Gaze project. The same ten effects are used in:

  • Gaze language — compiler-enforced effects (Rust)
  • libgaze — static analysis for Python (this package)
  • libgaze-ts — static analysis for TypeScript

The vocabulary is language-independent. It was tested against 15,293 functions across Python and TypeScript without modification.

Project details


Download files

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

Source Distribution

libgaze-0.2.1.tar.gz (43.9 kB view details)

Uploaded Source

Built Distribution

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

libgaze-0.2.1-py3-none-any.whl (14.9 kB view details)

Uploaded Python 3

File details

Details for the file libgaze-0.2.1.tar.gz.

File metadata

  • Download URL: libgaze-0.2.1.tar.gz
  • Upload date:
  • Size: 43.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for libgaze-0.2.1.tar.gz
Algorithm Hash digest
SHA256 c911f5f2f95b875de7ea987c49accb1ad98f90f3b86b024f1771f4ea3c21579d
MD5 b005bd7d0b375a6a9219dcc8687a0c79
BLAKE2b-256 3597650651095eface75b48939f651e648e3ef39486a2e92005e8ce6e626125b

See more details on using hashes here.

File details

Details for the file libgaze-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: libgaze-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 14.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for libgaze-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7dcb917031374927c8c3d9aae6b69d8fdcda27cd90aa76552e0ae82cf3a49255
MD5 31100f00b308aa2b26ede8a3dee7e216
BLAKE2b-256 494ddc63e9063718948f66c11340d19bc8ddfe9aed3b4e5f1c8666882c92ff04

See more details on using hashes here.

Supported by

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