Fast dependency graph analysis and visualization for Python, JavaScript/TypeScript, Rust, and Terraform projects
Project description
Serpentine
See every reference between every named entity in your codebase — functions, classes, modules, variables — resolved down to the definition.
Serpentine builds a code reference graph for Python, JavaScript/TypeScript, Rust, and Terraform projects. A code reference is when one named entity mentions another by name — a function call, a type annotation, an assignment, an inheritance declaration. Serpentine resolves each reference through the language's scoping rules down to the exact definition it points to, then visualizes the result as an interactive graph that updates in real time as you edit.
Features
- Multi-language: Python, JavaScript, TypeScript, Rust, and Terraform
- Full reference resolution: Traces calls, type annotations, assignments, and inheritance — not just import edges
- Interactive graph: Expandable nodes, search, pan/zoom, collapsible modules
- Real-time updates: File watcher pushes changes via WebSocket
- Agent-ready CLI: Structured JSON output with selectors for use in AI agent workflows
What counts as a code reference?
Serpentine tracks every place one named entity statically mentions another by name, resolved through the language's scoping rules to the specific definition it refers to.
| Reference type | Example | Edge |
|---|---|---|
| Function call | result = parse(data) |
result --calls--> parse |
| Constructor | loader = CSVLoader(path) |
loader --has-a--> CSVLoader |
| Name reference | default = MISSING |
default --references--> MISSING |
| Inheritance | class Stats(Base) |
Stats --is-a--> Base |
| Expression | total = a + b |
total --references--> a, total --references--> b |
All four edge types (calls, has-a, references, is-a) resolve through imports — so a reference to an imported name traces all the way back to its definition in the source module.
Installation
PyPI (recommended)
pip install serpentine-parser
Or with uv:
uv tool install serpentine-parser
From source
Prerequisites: Python 3.12+, Rust toolchain, Node.js 18+
git clone https://github.com/serpentine-parser/serpentine.git
cd serpentine
# 1. Build the frontend
cd frontend && npm install && npm run build && cd ..
# 2. Build the Rust extension and install the CLI
make install
This installs the serpentine CLI globally via uv tool, which you will need to install separately.
Quick Start
Navigate to any Python, JavaScript/TypeScript, Rust, or Terraform project and run:
serpentine serve
Serpentine will analyze the project, start a local server at http://127.0.0.1:8765, and open the visualization in your browser. File changes are detected automatically and the graph updates in real time.
CLI Reference
serpentine serve
Start the visualization server with live file watching.
serpentine serve [PATH] [OPTIONS]
Arguments:
PATH Directory to analyze (default: current directory)
Options:
-p, --port INT Port to run the server on (default: 8765)
-h, --host TEXT Host to bind to (default: 127.0.0.1)
--no-browser Don't open browser automatically
--no-watch Disable file watching (static analysis only)
serpentine analyze
Analyze a project and output the code reference graph. Default format is text (one edge per line as caller --type--> callee); use --format json for structured output.
serpentine analyze [PATH] [OPTIONS]
Options:
-o, --output PATH Write output to file instead of stdout
--format TEXT Output format: text (default) or json
--pretty Pretty-print JSON output
--select TEXT Selector expression to filter nodes (see below)
--exclude TEXT Exclusion pattern (same syntax as --select)
--no-cfg Strip control-flow graph data from nodes
--edges-only Output only the edges array (compact, json only)
--source Include source code blocks in text output
--include-assignments Include variable/assignment nodes in text output
--include-standard Include stdlib nodes (default: off)
--include-third-party Include third-party nodes (default: off)
--state TEXT Filter by change state: modified,added,deleted
--edge-type TEXT Comma-separated edge types to include: calls,is-a,has-a,references,imports
serpentine catalog
Flat list of all nodes. Default format is text (file-grouped hierarchy); use --format json to see node IDs for selector expressions.
serpentine catalog [PATH] [OPTIONS]
Options:
--filter TEXT Glob pattern matched against node id and name
(repeatable; multiple patterns = union)
--format TEXT Output format: text (default) or json
--include-assignments Include variable/assignment nodes (default: excluded)
-o, --output PATH Write output to file instead of stdout
--pretty Pretty-print JSON output
--include-standard Include stdlib nodes
--include-third-party Include third-party nodes
serpentine stats
Quick summary of project scale: node/edge counts by type and origin.
serpentine stats [PATH] [OPTIONS]
Options:
--pretty Pretty-print JSON
--include-standard Include stdlib nodes
--include-third-party Include third-party nodes
serpentine init
Set up Serpentine in an existing project.
serpentine init [PATH] [OPTIONS]
Arguments:
PATH Project directory (default: current directory)
Options:
--harness TEXT Target a specific harness: claude, cursor, copilot,
codex, opencode (repeatable; auto-detects if omitted)
Creates .serpentine.yml with default configuration and adds .serpentine to .gitignore. Then installs harness-specific configuration for whichever AI coding tools are detected in the project:
| Harness | What gets installed |
|---|---|
claude |
.claude/skills/code-analysis/SKILL.md + appends to CLAUDE.md |
cursor |
.cursor/rules/serpentine.mdc |
copilot |
appends to .github/copilot-instructions.md |
codex |
appends to AGENTS.md |
opencode |
appends to AGENTS.md |
Already-existing files are skipped rather than overwritten. Use --harness to target a specific harness instead of auto-detecting.
Querying the Graph
serpentine analyze and serpentine catalog accept --select and --exclude to slice the graph down to just the nodes you care about. This is useful for large codebases where the full graph is too noisy, or for piping results into other tools.
Step 1 — Find your node IDs
Every node has a dotted ID that reflects its location in the codebase. Use catalog with --format json to discover them:
serpentine catalog . --format json --pretty
This outputs a flat list of every module, class, and function with its ID:
{
"nodes": [
{ "id": "src.auth.models.User", "name": "User", "type": "class", ... },
{ "id": "src.auth.views.login", "name": "login", "type": "function", ... },
{ "id": "src.payments.stripe.charge", "name": "charge", "type": "function", ... }
]
}
Narrow it down with --filter (glob matched against both ID and name):
# Find everything related to auth
serpentine catalog . --filter "*auth*" --format json --pretty
# Find by name across modules
serpentine catalog . --filter "*User*" --format json --pretty
Step 2 — Select nodes and their dependencies
Once you have IDs, use --select with serpentine analyze. The selector controls which nodes (and their relationships) appear in the output.
Plain pattern — just the matching nodes:
serpentine analyze --select "src.auth.*" --no-cfg --pretty
+pattern — the matching nodes plus everything they depend on (upstream):
# What does the login view need to work?
serpentine analyze --select "+src.auth.views.login" --no-cfg --pretty
pattern+ — the matching nodes plus everything that depends on them (downstream):
# What breaks if I change the User model?
serpentine analyze --select "src.auth.models.User+" --no-cfg --pretty
+pattern+ — both directions (full blast radius):
serpentine analyze --select "+src.payments.*+" --no-cfg --pretty
@pattern — the full connected component (everything reachable in any direction):
serpentine analyze --select "@src.auth.*" --no-cfg --pretty
Bounded hops — limit how many levels to traverse:
# 2 levels of dependencies upstream, 1 level downstream
serpentine analyze --select "2+src.auth.views.login+1" --no-cfg --pretty
Multiple selectors — comma-separated, combined as a union:
serpentine analyze --select "+src.auth.*,+src.payments.*" --no-cfg --pretty
Step 3 — Exclude noise
--exclude removes nodes from the result (including their descendants):
# Show auth and its deps, but skip test files
serpentine analyze --select "+src.auth.*" --exclude "*test*" --no-cfg --pretty
Glob pattern rules
* in a selector matches any characters including dots, so it crosses module boundaries:
| You want | Use |
|---|---|
| All nodes whose ID contains "auth" | *auth* |
| All children of a specific module | src.auth.* |
| A class anywhere in the project | *.User |
| All test files | *test* |
Tip:
**is equivalent to*— both match across dots.
Compact output for large graphs
Use --edges-only to get just the edge list (much smaller than the full node tree):
serpentine analyze --select "+src.auth.*+" --edges-only --pretty
Each edge has a from and to field with node IDs, and a type field:
| Type | Meaning |
|---|---|
calls |
One entity calls another as a function |
has-a |
A variable holds an instance of a class (constructor call) |
references |
One entity names another without calling it (assignment, annotation, expression) |
is-a |
Inheritance — one class extends another |
Configuration
Serpentine looks for .serpentine.yml or serpentine.yml in the project root. All settings are optional.
analysis:
# File extensions to analyze (default: all supported)
extensions: [".py", ".js", ".jsx", ".ts", ".tsx", ".rs", ".tf"]
# Directories to skip
exclude_dirs:
- node_modules
- .venv
- dist
- build
# Glob patterns for files to skip
exclude_patterns:
- "**/*.test.ts"
- "**/generated/**"
Using Serpentine with AI Agents
Serpentine's CLI is designed to be consumed by AI coding agents (Claude, Cursor, Copilot, etc.). The structured output, selector syntax, and --edges-only flag exist specifically to give agents precise, low-noise subgraphs without requiring file reads.
The problem it solves
When an agent starts a non-trivial task, it faces a cold-start problem: it doesn't know which files are relevant, how components relate, or what the blast radius of a change might be. The usual approach — grep, glob, read files one at a time — is expensive in tokens and often incomplete.
Serpentine collapses that exploration into 2-3 CLI calls. The agent gets a structural picture of the relevant code before it starts reading files or writing a plan. In practice this means:
- Plans are scoped to the right files and boundaries from the start
- Less back-and-forth between reading files to trace call chains
- Fewer surprises mid-implementation when a dependency was missed
Recommended workflow for agents
# 1. Get the lay of the land — module names, rough scale
serpentine stats .
# 2. Find relevant node IDs by name
serpentine catalog . --filter "*auth*" --format json --pretty
# 3. Get the subgraph for the relevant area
serpentine analyze . --select "+src.auth.*+" --no-cfg --edges-only --pretty
Read the edges to understand what connects to what, then read only the files that are actually relevant.
Scenarios where this pays off
Before refactoring a module
Use --select "module+" to map everything that depends on the module before writing a plan. This ensures the plan accounts for every callsite and doesn't discover new dependents halfway through.
Before adding a feature that spans modules
Use --select "+moduleA.*,+moduleB.*" to get the combined subgraph of two areas and understand exactly where they intersect. The boundaries of the work become clear before any code is written.
Orienting to an unfamiliar codebase
serpentine stats gives you the top-level module list and scale. serpentine catalog . gives a flat index of every class and function. Together these give structural orientation without reading a single file.
Before deleting code
Use --select "*.TargetFunction+" to get all downstream dependents. An empty result confirms the code is truly unused.
Tracing a call chain
Use --select "+*.entrypoint+3" to get 3 hops downstream from an entry point and understand the execution path before adding instrumentation or fixing a bug.
Harness integration
Run serpentine init in any project to wire Serpentine into your AI coding tools. For Claude Code, this installs the code-analysis skill to .claude/skills/code-analysis/ and appends navigation instructions to CLAUDE.md — Claude then uses stats, catalog, and analyze instead of reading files or grepping. For Cursor, Copilot, Codex, and OpenCode, it installs the equivalent rules or instructions file for each tool.
Development
Project Structure
serpentine/
├── rust/ # Rust analyzer (tree-sitter + PyO3)
│ └── src/
│ ├── lib.rs # PyO3 module entry point
│ ├── python/ # Python parser
│ ├── javascript/ # JS/TS parser
│ ├── rust_lang/ # Rust parser
│ ├── terraform/ # Terraform/HCL parser
│ ├── subscribers/ # Event processors (imports, calls, defs)
│ └── graph/ # Graph builder and resolvers
├── src/serpentine/ # Python package
│ ├── cli.py # CLI commands
│ ├── state.py # Graph state management
│ ├── watcher.py # File watcher
│ ├── selector.py # Graph selector engine
│ ├── config.py # Config loading
│ └── server/ # Starlette web server + WebSocket
├── frontend/ # React frontend (Vite + TypeScript)
│ └── src/
├── Makefile # Build targets
└── pyproject.toml
Building for Development
Tilt is recommended for development — it rebuilds the Rust extension and frontend in parallel when files change:
tilt up
Or manually:
# Build Rust extension (rerun after changes to rust/src/)
uv run maturin develop
# Build frontend (rerun after changes to frontend/src/)
cd frontend && npm run build
# Run server
uv run serpentine serve --no-browser
Adding a Language
- Create a parser module in
rust/src/<language>/ - Walk the AST and emit three event types via the message bus:
ImportStatement— records what names are imported from which modulesUseName— fires for every identifier in expression position (not definition position)CallExpression— fires for every function or constructor invocation
- Register the parser in
rust/src/lib.rs
These three events are the minimum required for the graph builder to resolve all code references in your language. See rust/src/python/ for a complete reference implementation and CONTRIBUTING.md for full details.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file serpentine_parser-0.3.2.tar.gz.
File metadata
- Download URL: serpentine_parser-0.3.2.tar.gz
- Upload date:
- Size: 1.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1185d5c1630077e94ff76ee341d02ee95093ab50bb300e3d184c3a66cc78369
|
|
| MD5 |
b687eca2ff9b30defbfb3095bdee2d0a
|
|
| BLAKE2b-256 |
435786260d79d608bf31849fd08e517ae22dcf3350e53cc1a058abe22541cc98
|
Provenance
The following attestation bundles were made for serpentine_parser-0.3.2.tar.gz:
Publisher:
release.yml on serpentine-parser/serpentine
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
serpentine_parser-0.3.2.tar.gz -
Subject digest:
b1185d5c1630077e94ff76ee341d02ee95093ab50bb300e3d184c3a66cc78369 - Sigstore transparency entry: 1885851085
- Sigstore integration time:
-
Permalink:
serpentine-parser/serpentine@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Branch / Tag:
refs/tags/v0.3.2 - Owner: https://github.com/serpentine-parser
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Trigger Event:
push
-
Statement type:
File details
Details for the file serpentine_parser-0.3.2-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: serpentine_parser-0.3.2-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67603b3d2fba15fffe53d0fe31dd3de7097178b97baeee26acca6f3770a5564e
|
|
| MD5 |
c4daab38a24a767c5807f0110c972709
|
|
| BLAKE2b-256 |
274e11151576797084689e22b4d60f0587e27759a147eac0620ed05fe5194f63
|
Provenance
The following attestation bundles were made for serpentine_parser-0.3.2-cp310-abi3-win_amd64.whl:
Publisher:
release.yml on serpentine-parser/serpentine
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
serpentine_parser-0.3.2-cp310-abi3-win_amd64.whl -
Subject digest:
67603b3d2fba15fffe53d0fe31dd3de7097178b97baeee26acca6f3770a5564e - Sigstore transparency entry: 1885851199
- Sigstore integration time:
-
Permalink:
serpentine-parser/serpentine@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Branch / Tag:
refs/tags/v0.3.2 - Owner: https://github.com/serpentine-parser
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Trigger Event:
push
-
Statement type:
File details
Details for the file serpentine_parser-0.3.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: serpentine_parser-0.3.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 3.0 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
126ebacd1e53d8773f55f3f872f975c4f069e9ad0874eb862b8c0e12d450e3c3
|
|
| MD5 |
a11cbeff6600f1de500b60985fdd5e4d
|
|
| BLAKE2b-256 |
e3bb06a103848e6563729aeeba75582bf997223c8f4cf20f2ba50aaba3f3c0dc
|
Provenance
The following attestation bundles were made for serpentine_parser-0.3.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on serpentine-parser/serpentine
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
serpentine_parser-0.3.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
126ebacd1e53d8773f55f3f872f975c4f069e9ad0874eb862b8c0e12d450e3c3 - Sigstore transparency entry: 1885851399
- Sigstore integration time:
-
Permalink:
serpentine-parser/serpentine@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Branch / Tag:
refs/tags/v0.3.2 - Owner: https://github.com/serpentine-parser
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Trigger Event:
push
-
Statement type:
File details
Details for the file serpentine_parser-0.3.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: serpentine_parser-0.3.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 3.0 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c68fd86e6d2dcb18acc3afe78ec41815adcd87dc4396821e61299d04c8e312c
|
|
| MD5 |
113a0de779d62997e6a9325b3c39c3fc
|
|
| BLAKE2b-256 |
035102d778db6d58ef5b473d9417dbe642593e32051800f9416bbf7c6cb4b66e
|
Provenance
The following attestation bundles were made for serpentine_parser-0.3.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release.yml on serpentine-parser/serpentine
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
serpentine_parser-0.3.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
7c68fd86e6d2dcb18acc3afe78ec41815adcd87dc4396821e61299d04c8e312c - Sigstore transparency entry: 1885851465
- Sigstore integration time:
-
Permalink:
serpentine-parser/serpentine@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Branch / Tag:
refs/tags/v0.3.2 - Owner: https://github.com/serpentine-parser
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Trigger Event:
push
-
Statement type:
File details
Details for the file serpentine_parser-0.3.2-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: serpentine_parser-0.3.2-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.9 MB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
476efc93f10e75cc5cba9694a4a9e8a1b30e843419edf93eedd8a8b4317e8724
|
|
| MD5 |
f3ad61c4de8a3ebc6a1d13a8c9cb7089
|
|
| BLAKE2b-256 |
b025e3a4c7da38781d2b5f7389e28af87e1372781b5fc74d956e394a264eea98
|
Provenance
The following attestation bundles were made for serpentine_parser-0.3.2-cp310-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on serpentine-parser/serpentine
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
serpentine_parser-0.3.2-cp310-abi3-macosx_11_0_arm64.whl -
Subject digest:
476efc93f10e75cc5cba9694a4a9e8a1b30e843419edf93eedd8a8b4317e8724 - Sigstore transparency entry: 1885851529
- Sigstore integration time:
-
Permalink:
serpentine-parser/serpentine@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Branch / Tag:
refs/tags/v0.3.2 - Owner: https://github.com/serpentine-parser
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Trigger Event:
push
-
Statement type:
File details
Details for the file serpentine_parser-0.3.2-cp310-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: serpentine_parser-0.3.2-cp310-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 3.0 MB
- Tags: CPython 3.10+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28f1130990cd58e5cf60bf6889f6e84aba8624c8f84088d184f2ae2cbdcae9dc
|
|
| MD5 |
4e4ec0b11dca3b61a6609ec4b777019b
|
|
| BLAKE2b-256 |
84e2cbdedfe22b3534c0a238e58e956539990934d72944bce72f348a9d5d3c91
|
Provenance
The following attestation bundles were made for serpentine_parser-0.3.2-cp310-abi3-macosx_10_12_x86_64.whl:
Publisher:
release.yml on serpentine-parser/serpentine
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
serpentine_parser-0.3.2-cp310-abi3-macosx_10_12_x86_64.whl -
Subject digest:
28f1130990cd58e5cf60bf6889f6e84aba8624c8f84088d184f2ae2cbdcae9dc - Sigstore transparency entry: 1885851334
- Sigstore integration time:
-
Permalink:
serpentine-parser/serpentine@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Branch / Tag:
refs/tags/v0.3.2 - Owner: https://github.com/serpentine-parser
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@87019468c2999a7d5327cdaffab23f406dfa1f9f -
Trigger Event:
push
-
Statement type: