snodo
AI-SDLC Protocol Engine — a governance layer for AI-assisted software development.
snodo lets you define a protocol — a YAML specification of operational modes, validators, and constraints — and then executes tasks through that protocol. Each task passes through validation gates before and after execution, with disagreement policies (unanimous, majority, quorum, any) determining whether work proceeds, escalates, or halts. The result is a structured, auditable workflow where AI-generated code is checked against your standards before it lands.
Preprint: Specifying AI-SDLC Processes: A Protocol Language for Human-Agent Boundaries — arXiv:2606.20615 (doi:10.48550/arXiv.2606.20615).
Project status
snodo is an actively-developed research implementation (beta). Current state of the codebase:
| Metric | Value |
|---|---|
| Code | ~33,800 lines across 5 packages (snodo-core, snodo-tools, snodo-foundation, snodo-engine, snodo-mcp) |
| Complexity | average cyclomatic complexity A (3.9) — no high-complexity hotspots |
| Lint / architecture | ruff clean; package layering enforced in CI by import-linter |
| Python | 3.12 and 3.13 (CI matrix) |
The enforcement invariants (token integrity, capability boundaries, non-overridable blockers, audit completeness) are verified by property-based tests over randomized inputs.
Install
From PyPI (recommended)
pip install snodo
From source
snodo is a uv workspace of modular packages:
git clone https://github.com/snodo-dev/snodo.git
cd snodo
uv sync --all-extras # installs all workspace packages editable, plus dev + studies extras
Requirements
- Python 3.12+
- A model for the validators, which always run through LiteLLM. Providers with
built-in configuration: Anthropic, OpenAI, Google, OpenRouter, DeepSeek and
Cloudflare Workers AI. Any other OpenAI-compatible endpoint works by declaring a
provider block with
base_urlandlitellm_provider: openai— that covers Ollama Cloud, a local Ollama orllama.cppserver, vLLM, LM Studio, and self-hosted gateways. A local endpoint that needs no key is not asked for one. - A coder, which need not be the same thing.
--coder opencode-clior--coder agydelegate code generation to a CLI authenticated against your own subscription, so no provider key is spent on writing the code.--mockneeds nothing at all.
Quickstart
1. Initialize a project
snodo init --template solo
This creates .snodo/protocol.yml with a single-mode protocol:
protocol_id: "solo"
name: "Solo Developer Protocol"
version: "1.0.0"
modes:
- mode_id: "producer"
name: "Producer Mode"
tools:
- "edit"
- "dispatch"
- "resolve"
- "test"
- "validate"
- "commit"
- "merge"
validators:
- "security"
- "architecture"
- "quality"
- "meta-spec"
transitions: {}
validators:
- validator_id: "security"
validator_type: "security"
evaluation_phase: "pre_execute"
criteria:
- "Check for security vulnerabilities"
- "Validate input sanitization"
- "Check authentication/authorization"
- validator_id: "architecture"
validator_type: "architecture"
evaluation_phase: "pre_execute"
criteria:
- "Check design patterns"
- "Validate separation of concerns"
- "Check for tight coupling"
- validator_id: "quality"
validator_type: "quality"
evaluation_phase: "post_execute"
tooling: {} # auto-detect from repo marker files
disagreement_policy: "unanimous"
initial_mode: "producer"
global_constraints: []
2. Configure your API key
Configuration lives in ~/.snodo/config.yml, managed via the snodo config commands:
snodo config add anthropic sk-ant-... # store a provider key
snodo config set model claude-sonnet-4 # set the default model
A provider key already exported in your environment (e.g. ANTHROPIC_API_KEY) is auto-detected if it isn't in the config.
For a provider outside the built-in catalog — Ollama Cloud, a local Ollama or
llama.cpp server, vLLM, or any other OpenAI-compatible endpoint — declare a
provider block instead:
providers:
ollama:
base_url: https://ollama.com/v1
api_key_env: OLLAMA_API_KEY
litellm_provider: openai # route ollama/<model> through the OpenAI protocol
litellm_provider: openai is what makes an arbitrary compatible endpoint work:
snodo rewrites ollama/<model> to openai/<model> and sends it to base_url.
Omit api_key_env for a local server that needs no key. See
Configuration for the full file format.
3. Run a task
snodo run "implement a hello world function"
4. Dry run with mock coder (no API key needed)
snodo run "implement a hello world function" --mock
Protocol Language
A protocol is defined in YAML and consists of:
| Concept | Description |
|---|---|
| Mode | An operational stage with a defined set of tools and validators. Modes enforce separation of capabilities (e.g., producer can edit, reviewer can merge). |
| Validator | An evaluation criterion applied to a task. Each has a validator_type (security, architecture, quality, conventions, protocol, planning, etc.), an evaluation_phase (pre_execute or post_execute), and criteria (LLM prompt strings or tooling config). |
| Disagreement Policy | How validator results are combined: unanimous (all must pass), majority (>50%), quorum (configurable threshold, default 2/3), or any (at least one). |
| Severity | Validator results are pass, warn, or blocker. Any blocker halts execution regardless of policy. |
| Constraint | A rule enforced over execution artifacts (e.g., files must be within scope, tests must exist for modified code). Constraints use a predicate framework for deterministic evaluation. |
| Transition | A declarative event-to-mode mapping that documents the protocol's intended mode handoffs. |
Three templates ship with snodo:
| Template | Modes | Description |
|---|---|---|
solo |
producer | Single developer with full access |
team |
producer, reviewer, planner | Three-mode team workflow |
2+n |
producer, reviewer | Paper reference config: producer + reviewer with N validators and global constraints |
Coder Backends
snodo executes protocol tasks under interchangeable code generation backends (coders). The coder generates code, while snodo enforces protocol governance, runs validation gates, and maintains an append-only audit log.
Supported and External Coders
Coder (--coder) |
Description | Type | Requirements | Authentication |
|---|---|---|---|---|
litellm (default) |
Direct LLM completions via LiteLLM (~100+ providers) | Engine-Managed | Python litellm (built-in) |
Provider API keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc. or snodo config add) |
opencode |
OpenCode server running in Docker container over HTTP | In-Place Container | Docker daemon running; image opencode:latest |
OpenCode config/env variables inside container |
opencode-cli |
Host opencode run CLI invocation |
In-Place Host CLI | opencode CLI on PATH |
opencode auth login or host provider env vars (OPENROUTER_API_KEY, etc.) |
agy |
Antigravity CLI (agy -p) host invocation |
In-Place Host CLI | agy CLI on PATH |
agy login / Google Cloud host credentials |
mock |
Deterministic stub for dry-runs and testing | Stub | None | None |
Model Role Separation: Judging vs Execution
-m/--modelsets the JUDGING model: The model passed via-m(e.g.-m claude-3-5-sonnetor-m deepseek/deepseek-v4) is resolved through LiteLLM for validators (pre-execute and post-execute gates) and the classifier (intent routing).- External CLI coders use their own model catalogs: Host CLI tools like
agyoropencode-climaintain their own internal model catalogs and CLI settings. Passing a judging model identifier to an external CLI coder is meaningless;SubprocessCoderAdapter._bare_model()automatically strips non-prefixed model names so the CLI falls back to its own default/last-selected model. - Explicit Coder Model Override: To specify a coder's model explicitly while keeping
-mfor validators, prefix the model string with the coder's namespace:snodo run "implement feature" --coder agy --model agy/gemini-2.5-pro snodo run "implement feature" --coder opencode-cli --model opencode-cli/claude-3-7-sonnet
Coder Selection Precedence
resolve_coder_name() selects the active coder by evaluating criteria in strict order:
- Explicit Mock Flag:
--mock/use_mock_coder=True(always returns'mock'). - Explicit CLI Flag:
--coder <name>(e.g.,snodo run "task" --coder agy). - Protocol Mode Field:
coder: <name>declared in a mode definition in.snodo/protocol.yml(modes[].coder). - Model Prefix Mapping: Inferred from model prefix:
opencode-cli/→opencode-cli,opencode/→opencode,agy/→agy,gpt/o1/o3→openai,claude→anthropic,gemini/google/→gemini. - Default Fallback:
'litellm'.
In-Place Coders vs litellm
External coders (opencode, opencode-cli, agy) inherit InPlaceCoderAdapter (skip_engine_commit = True, skip_workspace_write = True):
- In-Place File Writes: External coders edit files directly in the workspace working tree.
- Commit Ownership: The adapter stages and commits changes to git upon completion (
InPlaceCoderAdapter._commit_changes()), advancingHEADso post-execute validators reviewinggit diff HEAD~1..HEADsee the exact change produced. .snodo/Mutation Guard: Any attempt by an in-place coder to modify the.snodo/directory triggers aSnodoMutationErrorand halts execution as asnodo_mutation_blockedblocker (ADR 027).- No Per-Turn Usage or Token Records: Per ADR 034, the absence of turn-by-turn usage and token metrics for external coders is a stated decision (non-goal), not an attestation gap. Token and cost data reside in per-job operational telemetry (
state.jsonviasnodo meta), whereas snodo's hash-chained audit trail attests to governance decisions and verification evidence across all coders.
Adding a New Coder Adapter
New host CLI coder adapters inherit SubprocessCoderAdapter (snodo.coders.subprocess_adapter), which provides shared subprocess execution, prompt construction, git diff readback, and artifact construction.
Creating a new CLI adapter requires specifying four class attributes and implementing _build_argv:
from typing import List
from snodo.coders.subprocess_adapter import SubprocessCoderAdapter
class CustomCoderAdapter(SubprocessCoderAdapter):
binary: str = "custom-coder"
model_prefix: str = "custom/"
install_hint: str = "Install custom-coder: https://example.com/install"
def _build_argv(self, prompt: str, project_root: str, model: str) -> List[str]:
argv = [self.binary, "run", "--dir", project_root, prompt]
if model:
argv.extend(["--model", model])
return argv
Registering the adapter class in CODER_REGISTRY (snodo/coders/__init__.py) automatically exposes it to --coder, enables model prefix routing, and includes it in the adapter conformance test suite (tests/coders/test_adapter_conformance.py).
CLI Reference
snodo init
Initialize a snodo project.
--template, -t TEXT Protocol template: solo, team, or 2+n
--force, -f Overwrite existing .snodo/ directory
--mode, -m TEXT Starting mode (skips interactive picker)
snodo run
Execute a task through the protocol.
DESCRIPTION Task description (required unless --plan is used)
--protocol TEXT Path to protocol file [default: .snodo/protocol.yml]
--coder TEXT Coder backend: litellm, opencode, opencode-cli, agy, mock
--model, -m TEXT Model to use for judging (e.g., claude-sonnet-4-20250514, gpt-4)
--verbose Show detailed output
--mock Use mock coder instead of real LLM
--plan, -p TEXT Execute a plan by name
--wave, -w INTEGER Execute only a specific wave (requires --plan)
--interactive, -i Confirm each task before execution
--from-pr INTEGER Fetch PR comments as task context
--background, -b Run task in background
--sandbox TEXT Sandbox type: local or docker [default: local]
--resume TEXT Resume execution from session ID
--retry Retry execution of a halted task using saved failure context
--retain-worktree Retain task git worktree after execution finishes
--no-isolation Run task directly in the main repository working tree
snodo status
Show status of the active snodo session, mode, and task progress.
snodo validate
Validate the project protocol definition and well-formedness rules.
--protocol TEXT Path to protocol file [default: .snodo/protocol.yml]
snodo serve
Start MCP server from protocol definition.
--protocol TEXT Path to protocol file [default: .snodo/protocol.yml]
--mode TEXT Serve a single mode (default: all modes)
--transport TEXT Transport type: stdio or sse [default: stdio]
--port INTEGER Port for SSE transport [default: 8080]
--install Install MCP servers into Claude Desktop config (deprecated)
--uninstall Remove this project's MCP entries (deprecated)
--uninstall-all Remove ALL snodo MCP entries (deprecated)
--project-name TEXT Override project name for MCP entry naming
snodo plan
Manage plans. Subcommands: list, status, create, validate,
add-wave, add-task, run, delete.
snodo plan list List all plans with wave and task counts
snodo plan status NAME Show per-wave task progress
snodo plan create DESCRIPTION Create an empty plan to author into
--name, -n TEXT Plan name (auto-generated from the
description if omitted)
--protocol TEXT Path to protocol file
[default: .snodo/protocol.yml]
--model, -m TEXT Model to use (accepted; currently unused)
--mock Use mock coder instead of real LLM
(accepted; currently unused)
snodo plan validate NAME Verify plan structure and task spec files
--json Emit the result as JSON
(schema snodo.plan_validate.v1)
create scaffolds plan.yml and status.json with a single empty wave, so a
new plan already validates — validate rejects a plan with no waves at all.
It does not generate waves from the description: Tasks: 0 on a fresh plan is
expected. Author the plan with the commands below, by editing plan.yml
directly, or through the MCP planner's generate_spec.
snodo plan add-wave NAME ID Add a wave (integer id) to the plan
--depends-on TEXT Comma-separated wave ids this wave depends on
snodo plan add-task NAME TASK_ID Add a task to a wave from a spec file
--spec-file PATH Markdown spec for the task (required)
--parent TEXT Parent task ref, for subtask depth tracking
--replace Overwrite an existing task spec
snodo plan delete NAME Remove a plan directory
--force Delete even when tasks are completed or
in progress
Task ids are <wave>.<seq>_<name>, e.g. 1.1_models. Wave 1 exists from
create, so the first wave you add is 2. Both add-wave and add-task
re-verify the plan afterwards and report if the edit left it invalid.
Execute a plan with either form — they take the same arguments and run the same code:
snodo plan run NAME Execute the plan's tasks, wave by wave
snodo run --plan NAME Equivalent
--wave, -w INTEGER Execute only a specific wave
--interactive, -i Confirm each task before execution
A plan is verified before its first task runs and every time it is loaded. See docs/runbooks/hand-authored-plan.md for a worked example of authoring and running a plan by hand.
snodo session
Manage protocol sessions. Subcommands: list, show, delete, prune.
snodo session list
--mode TEXT Filter by mode
--project TEXT Filter by project path
--status TEXT Filter by status
snodo mode
Manage active protocol mode. Subcommands: show, change.
snodo mode change NEW_MODE
snodo config
Manage API keys and configuration. Subcommands: show, add, remove, test, set, get.
snodo config add PROVIDER KEY Store an API key (provider: openai, anthropic, google)
Custom OpenAI-Compatible Providers (e.g. Ollama Cloud)
You can bring your own OpenAI-compatible endpoint by declaring a custom provider block in ~/.snodo/config.yml. Specify litellm_provider: openai to route completions via LiteLLM's OpenAI handler:
providers:
ollama:
litellm_provider: openai
base_url: https://ollama.com/v1
api_key_env: OLLAMA_API_KEY
With this configuration:
snodo models --provider=ollama --flushdiscovers models directly fromhttps://ollama.com/v1/models.snodo run "implement feature" --model=ollama/llama-3.3-70b-instructexecutes tasks using your custom provider endpoint without requiring anopenaiprovider block.
snodo authorize
Review and authorize (or reject) pending decisions the orchestrator escalated to a human — disagreement adjudications and set_model proposals.
snodo authorize [TASK_ID]
--yes, -y Skip the confirmation prompt
--reject-all Bulk-reject all pending decisions
snodo job
Manage background jobs. Subcommands: list, status, logs, wait, cancel.
snodo job logs JOB_ID
--stream, -s TEXT Log stream: stdout or stderr [default: stdout]
--tail, -n INTEGER Show last N lines
snodo agent
Manage agent memory and threads. Subcommands: list, memory, reset, rotate.
snodo sandbox
Manage Docker sandbox. Subcommands: build, status.
snodo sandbox build
--tag, -t TEXT Image tag (default: snodo-worker:latest)
snodo install
Install MCP servers into Claude Desktop config.
--protocol TEXT Path to protocol file [default: .snodo/protocol.yml]
snodo uninstall
Remove MCP servers from Claude Desktop config.
--mode TEXT Remove a single mode entry
--all Remove ALL snodo-* entries from Claude config
--purge Also delete .snodo/ directory and sessions
--orphans Detect and remove orphan MCP entries
--yes, -y Skip confirmation prompts
snodo dashboard
Launch the TUI dashboard (snop).
snodo recon
Fan out read-only exploration agents to answer a question about the codebase.
snodo recon "how does token issuance work?" [PATHS...]
--agents, -n INTEGER Number of agents to fan out (default: from config)
snodo models
List available models for a provider, with cost and capability filters.
snodo models --provider anthropic --id-contains sonnet
snodo logs
Stream logs for a job or recon run.
snodo logs <j_xxx | rec_xxx> [--watch]
snodo meta
Show metadata and usage for a job or task.
snodo meta <j_xxx | task_xxx>
snodo cloud
Manage the snodo cloud connection and audit sync. Subcommands: connect, disconnect, status.
snodo cloud connect <api-key>
snodo task
Manage task branches. Subcommands: list, abandon, prune.
snodo worktree
Manage git worktrees used for task isolation. Subcommands: list, remove, prune.
snodo worktree list
snodo worktree remove WORKTREE_NAME
snodo worktree prune
Architecture
-
Mode-based capability separation. Each mode declares its available tools. Disjoint tool sets between modes (enforced by WF1 well-formedness checks) ensure structural separation of duties — a producer cannot merge, a reviewer cannot edit.
-
Validator gates with disagreement policies. Tasks pass through
pre_executevalidators before execution andpost_executevalidators after. Results (pass/warn/blocker) are combined via a configurable policy (unanimous, majority, quorum, any). Any blocker halts immediately. -
JWT validation tokens. When validators agree, a signed JWT token is issued. Mutating MCP tools require a valid token (WF1 enforcement at the server level), making validation non-overridable at the capability boundary.
-
Session resumability. Execution state is checkpointed to
~/.snodo/sessions/(or$SNODO_HOME/sessions/). Sessions can be resumed withsnodo run --resume <session_id>. Escalated disagreements are adjudicated viasnodo authorizeand the session continues. -
Coder adapter pattern. The code generation backend is abstracted behind a
CoderAdapterinterface. Built-in adapters includeLiteLLMAdapter(any LiteLLM-supported model), provider-specific adapters (Anthropic, OpenAI, Gemini), anOpenCodeAdapter(containerised OpenCode), andMockAdapter(deterministic stubs for testing). New backends can be plugged in without changing the engine. -
LangGraph execution engine. The protocol is compiled into a LangGraph
StateGraphwith nodes for governance, validation, execution, and completion. The graph is dynamically built from the protocol YAML, supporting arbitrary mode and validator configurations. -
Modular package layout. The codebase is split into independently-installable packages under a
uvworkspace:snodo-core(kernel — config, predicates, sandbox),snodo-tools(workspace/git/shell primitives and code-host providers),snodo-foundation(infrastructure, compiler, protocols),snodo-engine(execution engine, validators, coders), andsnodo-mcp(MCP servers, recon, jobs) — with the rootsnodopackage as the CLI and dashboard app. Dependency layering is enforced in CI byimport-linter.
Configuration
snodo stores its configuration in ~/.snodo/config.yml (override the location with $SNODO_HOME). Manage it with the snodo config commands rather than editing by hand:
snodo config add anthropic sk-ant-... # add a provider API key
snodo config set model deepseek/deepseek-v4 # default model for all roles
snodo config set engine.max_subtask_depth 3
snodo config show
A typical config.yml:
model: deepseek/deepseek-v4 # default model for all roles
llm:
coder: # per-role overrides
max_tokens: 64000
temperature: 0.1
validator:
model: openai/@cf/google/gemma-4 # role-specific model override
max_tokens: 25000
classifier:
model: openai/@cf/google/gemma-4 # omit -> falls back to top-level `model`
recon:
num_agents: 2
models:
- deepseek/deepseek-v4
engine:
max_subtask_depth: 3
max_session_age_days: 30
token_ttl_seconds: 1200
providers:
anthropic:
api_key: sk-ant-...
api_key_env: ANTHROPIC_API_KEY # env var the key is injected into at runtime
deepseek:
api_key: sk-...
api_key_env: DEEPSEEK_API_KEY
cloudflare:
api_key: cfut_...
api_key_env: OPENAI_API_KEY # Cloudflare Workers AI via the OpenAI-compatible endpoint
account_id: <account-id>
base_url: https://api.cloudflare.com/client/v4/accounts/<account-id>/ai/v1
cloud: # optional: snodo cloud sync
api_url: https://api.snodo.dev
sync_enabled: true
Each provider's api_key is injected into its api_key_env environment variable when a matching model runs, so provider SDKs pick it up automatically.
Environment variables
These are read directly from the environment (not stored in config.yml):
| Variable | Purpose |
|---|---|
SNODO_HOME |
Override the snodo home directory (default: ~/.snodo). Config, sessions, and agent memory live here. |
SNODO_TOKEN_SECRET |
Override the HMAC secret for JWT validation-token signing (default: randomly generated per process). |
GITHUB_TOKEN |
GitHub token for PR-related features (--from-pr). |
<PROVIDER>_API_KEY |
Any provider key set in the environment is auto-detected if it isn't already in config.yml. |
Research
snodo is described in a research paper covering the protocol language, well-formedness conditions, enforcement invariants, and empirical evaluation of disagreement policies.
Prifti, Y. (2026). Specifying AI-SDLC Processes: A Protocol Language for Human-Agent Boundaries. arXiv:2606.20615. https://doi.org/10.48550/arXiv.2606.20615
@misc{prifti2026snodo,
title = {Specifying AI-SDLC Processes: A Protocol Language for Human-Agent Boundaries},
author = {Prifti, Ylli},
year = {2026},
eprint = {2606.20615},
archivePrefix = {arXiv},
doi = {10.48550/arXiv.2606.20615},
url = {https://arxiv.org/abs/2606.20615}
}
Empirical studies are included in the studies/ directory and can be run with:
uv sync --extra studies
make studies
Contributing
See CONTRIBUTING.md for development setup and guidelines.
License
Copyright (C) 2026 The snodo Authors
Licensed under the Apache License, Version 2.0. See the LICENSE file for details.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 snodo-0.7.2.tar.gz.
File metadata
- Download URL: snodo-0.7.2.tar.gz
- Upload date:
- Size: 134.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e0a501529ac53ae12b67f1543ea02291f0d0bad36e8ac77761a1abd0454d4f3
|
|
| MD5 |
c0ff1c1a948a0293a55708ed32baaaa6
|
|
| BLAKE2b-256 |
c808370105a0aa67fd14532e3706751c539c9e84d07f442c4a1c2038459c6517
|
Provenance
The following attestation bundles were made for snodo-0.7.2.tar.gz:
Publisher:
release.yml on snodo-dev/snodo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
snodo-0.7.2.tar.gz -
Subject digest:
5e0a501529ac53ae12b67f1543ea02291f0d0bad36e8ac77761a1abd0454d4f3 - Sigstore transparency entry: 2688182698
- Sigstore integration time:
-
Permalink:
snodo-dev/snodo@c497bfa7b3fc31ee208b02e0a37d1e3a2da1c815 -
Branch / Tag:
refs/tags/v0.7.2 - Owner: https://github.com/snodo-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c497bfa7b3fc31ee208b02e0a37d1e3a2da1c815 -
Trigger Event:
push
-
Statement type:
File details
Details for the file snodo-0.7.2-py3-none-any.whl.
File metadata
- Download URL: snodo-0.7.2-py3-none-any.whl
- Upload date:
- Size: 142.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dcaa9a9b9e6e205f1e9f49ef0f453738c86d2494b540666e3f838f7d829a5d69
|
|
| MD5 |
c4e49f0c4da8b59f65a2e0fcce00c892
|
|
| BLAKE2b-256 |
e572b98175edfb1f8d3ef5ce01dcf5f4143e8b212a57a7c9dbfee78869244a8f
|
Provenance
The following attestation bundles were made for snodo-0.7.2-py3-none-any.whl:
Publisher:
release.yml on snodo-dev/snodo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
snodo-0.7.2-py3-none-any.whl -
Subject digest:
dcaa9a9b9e6e205f1e9f49ef0f453738c86d2494b540666e3f838f7d829a5d69 - Sigstore transparency entry: 2685618907
- Sigstore integration time:
-
Permalink:
snodo-dev/snodo@c497bfa7b3fc31ee208b02e0a37d1e3a2da1c815 -
Branch / Tag:
refs/tags/v0.7.2 - Owner: https://github.com/snodo-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c497bfa7b3fc31ee208b02e0a37d1e3a2da1c815 -
Trigger Event:
push
-
Statement type: