Skip to main content

Security-focused DeFi payload validation SDK (zero private keys in-library; explicit dependencies).

Project description

PyPI Python Version Coverage 100% License

English | 🇨🇳 简体中文 | Migration | 📦 Installation | ⚡ Quickstart | 🌐 Integrations | 🏗️ Architecture | 💬 Support | 🛠️ Contributing | 🛡️ Security | ⚔️ Conduct | 📜 License

Current version: v2.0.3 (see [project].version in pyproject.toml).

Reading order: start with the value proposition, then installation, then quickstart, then architecture, then security and support. The Chinese section below follows the same sequence and keeps the same section-level evidence boundaries.

Lirix 2.0 · The EVM-grade execution airlock for AI agents

PyPI version Build Status

Lirix is a fail-closed validation and simulation control plane that stands between untrusted agent payloads and anything that can move value. It is not a signer; it is the execution airlock that forces intent, schema, ABI, RPC evidence, and local EVM simulation through L1–L5 before any broadcast handoff is emitted.

🧭 At a glance

  • Start here — the value proposition explains the problem Lirix solves.
  • Then install — the recommended setup path keeps environments clean and reproducible.
  • Then run quickstart — a five-minute walkthrough shows the approved handoff.
  • Then inspect the architecture — the control-plane model explains how the layers fit together.
  • Then read security and support — the boundary rules and contributor norms are explicit.

That sequence is deliberate: it matches how first-time visitors decide whether to trust, try, and then adopt a project.

🎯 Why Lirix?

The Web3 agent stack fails in predictable ways: prompt injection becomes malicious calldata, toxic DeFi shapes pass review but fail on-chain, proxies hide real code paths, and RPC views diverge under load. Lirix collapses that attack surface into a single deterministic DAG: validate intent, decode and pierce contracts, reconcile RPC evidence, simulate with state overrides, and only then return an evidence-rich envelope that your orchestrator can retry, rewrite, or reject without guessing.

✨ What you get

  • Fail-closed by design — blocked requests stay blocked unless every gate passes.
  • Evidence-first output — every approval carries structured feedback and replay-friendly artifacts.
  • Agent-friendly integration — a single control plane for LLM tools, signers, and orchestrators.
  • Production-oriented guardrails — architecture, tests, and docs are tied together by SSOT links.

📚 Contract boundaries & evidence sources

This README is an orientation layer only. It is intentionally incomplete and must not be treated as the contract SSOT. For any hard claim, prefer the evidence sources listed below.

Use the dedicated docs for authoritative detail:

  • API and behavior contract: docs/api_reference.md plus the public tests under tests/
  • Architecture and audit topology: docs/architecture_control_plane.md and docs/audit_path_map.md
  • Workflow / gate truth: docs/ci_gate_matrix.md and the GitHub workflows under .github/workflows/
  • Repository exclusions: docs/repo_exclusions.md
  • Security boundary: SECURITY.md

Core README claims should be auditable against code, tests, and evidence fields. The anchors below are the shortest path for that review:

  • Production / Stable status: pyproject.toml, docs/release_notes.md
  • Fail-closed behavior: implementation in lirix/ and coverage in tests/
  • Coverage and regression posture: tests/, docs/ci_gate_matrix.md
  • Audit / replay fields: docs/audit_path_map.md, docs/api_reference.md

If this README conflicts with code, tests, or SSOT docs, the latter win.

PyPI maturity: package metadata lists Development Status :: 5 - Production/Stable for the 2.x line on PyPI; semver and docs/migration_legacy_to_v2.md remain the authority for breaking-change cadence.

Public API vs migration shims: Supported 2.x import surfaces and payload contracts are treated as stable for integrators. DeprecationWarning paths and legacy config alias coercion exist only for documented migration and the next-major removal window described in docs/migration_legacy_to_v2.md and docs/release_notes.md — they do not contradict the Production/Stable classifier; they simply bound compatibility shims before a semver major.

🧩 How to read this repository

If you only have a minute, read the sections in this order: value proposition, installation, quickstart, architecture, security, support.

If you are integrating or upgrading, keep docs/migration_legacy_to_v2.md, docs/api_reference.md, and docs/audit_path_map.md open side by side with this README.

📦 Installation & Setup

This README tracks v2.0.3 with PyPI/source metadata in pyproject.toml.

If you are new, use the recommended path below. If you are upgrading, skim the migration note first.

Recommended path

python3 -m venv .venv
source .venv/bin/activate  # Windows: `.venv\\Scripts\\activate`
pip install lirix
lirix init

If you are upgrading from an older line

Read docs/migration_legacy_to_v2.md before changing imports, config aliases, or release assumptions. The migration guide is the source of truth for compatibility windows and breaking-change timing.

What to expect after install

Lirix is designed to fail closed. If the boundary cannot be verified with enough confidence, the result is rejection rather than speculation.

⚡ Quickstart: Five-Minute Blitz

The fastest path is intentionally linear: validate, inspect the handoff, then triage failures. If you only copy one section, copy this one.

1) Fail-closed validation and simulation

from typing import Any, Mapping

from lirix import Lirix

guardian = Lirix(rpc_urls=["https://eth-mainnet.g.alchemy.com/v2/…"])
draft: Mapping[str, Any] = {
    "to": "0x0000000000000000000000000000000000000001",
    "data": "0x",
    "value": 0,
}
result = guardian.validate_and_simulate("swap", draft)
print(result["decision"], result["status"], result["agent_feedback"]["reason_code"])
print(result["payload"].get("simulation_ok"))

2) Extract the broadcast handoff

Use Lirix.extract_broadcast_fields(result) only after both decision and status are "approved". The signer should receive the extracted broadcast fields, not the full result envelope.

from lirix import Lirix

if result.get("decision") == "approved" and result.get("status") == "approved":
    broadcast_fields = Lirix.extract_broadcast_fields(result)
    # Sign and broadcast using broadcast_fields only.
else:
    rc = (result.get("agent_feedback") or {}).get("reason_code")
    print(
        f"Validation failed: decision={result.get('decision')!r} "
        f"status={result.get('status')!r} reason_code={rc!r}"
    )

3) Failure triage

When a request is blocked, inspect agent_feedback.remediation, then agent_feedback.reason_code, then resolve the protocol with resolve_failure_protocol(...) or Lirix.resolve_failure_protocol(...). Stable audit fields include canonical_error_code, failure_type_canonical, canonical_reason_codes, and the replay-facing aliases inside forensic_bundle.

For the lower-level contract and the exact recovery order, use the SSOT docs and tests listed in docs/audit_path_map.md rather than extending this README narrative.

4) E2E regression mirror

pytest -q tests/test_integration/test_real_e2e_paths.py

🌐 Ecosystem Integrations (LangChain & AutoGen)

Use these patterns when Lirix sits between model output and a downstream signer or executor.

Rule: validate_and_simulate takes intent: str and payload: Mapping[str, Any]. Always schema-lock model output before it crosses the Lirix boundary.

LangChain

from __future__ import annotations

import json
from typing import Any, Mapping, cast

from langchain_core.tools import tool
from pydantic import BaseModel, ConfigDict, Field

from lirix import Lirix, LirixSecurityException


class LirixValidationRequest(BaseModel):
    model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)

    raw_llm_output: str = Field(..., min_length=1)
    intent: str = Field(..., min_length=1)


class LirixSecurityValidator:
    def __init__(self, guardian: Lirix) -> None:
        self._guardian = guardian

    def validate(self, raw_llm_output: str, intent: str) -> str:
        draft = cast(Mapping[str, Any], json.loads(raw_llm_output))
        # 先做结构化反序列化,再交给 Lirix 执行 fail-closed 校验与模拟
        result = self._guardian.validate_and_simulate(intent, draft)
        if result.get("decision") != "approved" or result.get("status") != "approved":
            rc = (result.get("agent_feedback") or {}).get("reason_code")
            return json.dumps(
                {"result": result, "tx_payload": None, "reason_code": rc},
                sort_keys=True,
                default=str,
            )
        try:
            tx_payload = Lirix.extract_broadcast_fields(result)
        except LirixSecurityException as exc:
            return json.dumps(
                {"result": result, "tx_payload": None, "resolution_for_agent": exc.resolution_for_agent},
                sort_keys=True,
                default=str,
            )
        return json.dumps({"result": result, "tx_payload": tx_payload}, sort_keys=True, default=str)


guardian = Lirix(rpc_urls=["https://eth-mainnet.g.alchemy.com/v2/…"])
validator = LirixSecurityValidator(guardian=guardian)


@tool("lirix_validate_and_simulate")
def lirix_validate_and_simulate(raw_llm_output: str, intent: str) -> str:
    """在任何广播路径前进行 fail-closed 校验。"""
    return validator.validate(raw_llm_output=raw_llm_output, intent=intent)

AutoGen

from __future__ import annotations

import json
from dataclasses import dataclass
from typing import Any, Mapping, cast

from lirix import Lirix, LirixSecurityException


@dataclass(frozen=True)
class AutoGenLirixBridge:
    guardian: Lirix

    def __call__(self, raw_llm_output: str, intent: str) -> Mapping[str, Any]:
        draft = cast(Mapping[str, Any], json.loads(raw_llm_output))
        result = self.guardian.validate_and_simulate(intent, draft)
        if result.get("decision") != "approved" or result.get("status") != "approved":
            rc = (result.get("agent_feedback") or {}).get("reason_code")
            return {"status": "blocked", "result": result, "reason_code": rc}
        try:
            tx_payload = Lirix.extract_broadcast_fields(result)
        except LirixSecurityException as exc:
            return {"status": "blocked", "resolution_for_agent": exc.resolution_for_agent}
        return {"status": "approved", "result": result, "tx_payload": tx_payload}


autogen_lirix = AutoGenLirixBridge(guardian=Lirix(rpc_urls=["https://eth-mainnet.g.alchemy.com/v2/…"]))

🏗️ Architecture & Security Trace

This section explains the control plane after the quickstart has shown the outcome. Read it once for the model, then return to the tests and docs for detail.

Public Lirix (lirix/_facade.py) composes HookManager, ClientPipelineProtocol, and LirixPipelineOrchestrator into a one-way pipeline with session and trace FSM semantics. Hooks extend policy at the perimeter; they do not bypass the core.

For implementation details, prefer the architecture and audit docs plus the tests that pin behavior. This section is intentionally a compressed overview.

flowchart LR
  A[LLM / Tool output] --> B[Payload Mapping]
  B --> C{L1 Intent}
  C -- pass --> D{L2 Schema}
  D -- pass --> E{L3 DeFi / ABI}
  E -- pass --> F{L4 RPC Quorum}
  F -- pass --> G{L5 Sandbox + Policy}
  G -- pass --> H[Approved envelope]
  H --> I[Your signer + broadcast]

  C -- fail-closed --> X[Block + structured agent_feedback]
  D -- fail-closed --> X
  E -- fail-closed --> X
  F -- fail-closed --> X
  G -- fail-closed --> X
  1. L1 — Intent firewall with injection-resistant allowlists.
  2. L2 — Schema boundary with strict payload typing.
  3. L3 — DeFi / ABI decoding plus proxy piercing.
  4. L4 — Multi-node RPC reconciliation with evidence.
  5. L5 — Local EVM simulation plus shadow policy audit.

HookManager gives you RBAC, sandbox routing, OTel export, and pre/post-flight policy hooks without forking the kernel. The rule is simple: the kernel stays deterministic; the perimeter stays customizable.

Developer paths

  • validate_only / async_validate_only — L1–L3 + evidence.
  • simulate_only / async_simulate_only — L4–L5, with optional prior validation gate.
  • validate_and_simulate / async_validate_and_simulate — full DAG.
  • atomic_multicall — multicall packing with L1–L3 alignment.
  • Layer types — prefer from lirix import HookManager, ProxyPiercer, RPCManager, SandboxSimulator; use lirix.layers / lirix.core when you need the full catalog (e.g. ShadowAuditor, MulticallEncoder).

Progressive migration flags

LirixConfig exposes hook_contract_mode, policy_lifecycle_mode, and rpc_evidence_mode. Move hook_contract_mode from shadow to enforce only after the hook evidence is clean and the v2 rails are verified.

Project layout

lirix/
├── lirix/        # core defense layers + facade
├── tests/        # verification + adversarial coverage
├── docs/         # audit + architecture SSOT
└── SECURITY.md   # disclosure policy

Full tree: docs/STRUCTURE.md. Control plane table: docs/architecture_control_plane.md.

🛡️ Security Model

This repository’s trust boundary is intentionally narrow.

Triple-Zero: Zero-Key · Zero-Telemetry · Zero-Trust — see SECURITY.md. If a request cannot be verified with high confidence, Lirix rejects it rather than guessing.

✅ Stability, guarantees, and evidence sources

This README is a high-level entry point, not the SSOT for every operational claim. When a claim matters, trace it to code, tests, and the relevant evidence doc.

  • API and behavior guarantees: confirm against docs/api_reference.md and the public tests under tests/.
  • Architecture and audit trace: confirm against docs/audit_path_map.md, docs/architecture_control_plane.md, and docs/lirix_import_topology.md.
  • Workflow / gate truth: confirm against docs/ci_gate_matrix.md and .github/workflows/*.yml.
  • Versioned packaging truth: confirm against pyproject.toml.
  • Repository exclusions: confirm against docs/repo_exclusions.md, .gitignore, and .harnessignore.

When this README and the evidence sources differ, the evidence sources win.

💬 Support & FAQ

Use the support paths below after you have read the contract and the quickstart. Clear docs, narrow boundaries, and reproducible behavior are the preferred way to keep support useful.

  • General: Discussions / Issues
  • Security: do not open public issues; follow SECURITY.md.
  • Contributor norms: follow CONTRIBUTING.md and CODE_OF_CONDUCT.md before opening a PR or joining the conversation.

Q: Why no private key?
A: Lirix validates and simulates; you sign. Separation of duties is the model.

Q: externally-managed-environment?
A: Use a venv; never pip install --break-system-packages.

Q: Where should I read first?
A: Start with the value proposition, then installation, then quickstart, then architecture, then security. The Chinese section below follows the same order.


🇨🇳 Lirix 2.0 · 面向 AI Agent 的 EVM 级执行气闸

一句话定义: Lirix 是夹在「不可信模型输出」与「私钥 / 广播」之间的 fail-closed 校验 + 模拟控制平面。它不是钱包,也不是 Signer;它是 EVM-grade execution airlock,要求意图、Payload、RPC 证据与本地 EVM 模拟逐层通过 L1–L5 单向 DAG,然后才吐出可交接的广播字段。

🎯 为什么需要 Lirix?

Web3 Agent 的常见死法非常一致:Prompt 注入 变成恶意 calldata,有毒 DeFi 形状 在审查时看似合理、上线后却 Revert 或失血,Proxy / Router 把真实执行路径藏起来,RPC 视图还会在高压下分叉。Lirix 把这些风险压成一条确定性 DAG:先校验意图与结构,再做 ABI 解码与 Proxy 穿透,必要时进行多节点 RPC 对账,并配合 State Overrides 做沙盒模拟,最后输出带 security_tracereplay_bundle 的证据信封——由你的编排器决定重试、改写,还是直接硬拒绝。

📦 安装与初始化

当前版本:v2.0.3(与 pyproject.toml[project].version 一致)。

如果你是新读者,直接按下面的推荐方式开始;如果你在升级,请先看迁移说明。

阅读顺序: 先看价值定义,再看安装,再看快速上手,再看架构,再看安全与支持。下方中文内容与英文部分在章节顺序上保持一致,并尽量保持语义与契约意图对齐。

推荐方式

python3 -m venv .venv
source .venv/bin/activate  # Windows:`.venv\\Scripts\\activate`
pip install lirix
lirix init

⚡ 快速上手:五分钟闪电战

最短路径是线性的:先校验,再看交接字段,最后做失败分流。

1) fail-closed 校验与模拟

from typing import Any, Mapping

from lirix import Lirix

guardian = Lirix(rpc_urls=["https://eth-mainnet.g.alchemy.com/v2/…"])
draft: Mapping[str, Any] = {
    "to": "0x0000000000000000000000000000000000000001",
    "data": "0x",
    "value": 0,
}
result = guardian.validate_and_simulate("swap", draft)
print(result["decision"], result["status"], result["agent_feedback"]["reason_code"])
print(result["payload"].get("simulation_ok"))

2) 提取广播交接字段

只有当 decisionstatus 都是 "approved" 时,才允许调用 Lirix.extract_broadcast_fields(result)。签名器只接收提取后的广播字段,绝不接收完整 result envelope。

from lirix import Lirix

if result.get("decision") == "approved" and result.get("status") == "approved":
    broadcast_fields = Lirix.extract_broadcast_fields(result)
    # 仅将 broadcast_fields 交给签名器并广播。
else:
    rc = (result.get("agent_feedback") or {}).get("reason_code")
    print(
        f"校验未通过:decision={result.get('decision')!r} "
        f"status={result.get('status')!r} reason_code={rc!r}"
    )

3) 失败排查

被阻断时,按顺序查看 agent_feedback.remediationagent_feedback.reason_code,再用 resolve_failure_protocol(...)Lirix.resolve_failure_protocol(...) 定位。稳定审计字段包括 canonical_error_codefailure_type_canonicalcanonical_reason_codes,以及 forensic_bundle 中面向回放的别名字段。

4) E2E 回归镜像

pytest -q tests/test_integration/test_real_e2e_paths.py

🌐 生态集成(LangChain 与 AutoGen)

当 Lirix 夹在模型输出与下游签名器 / 执行器之间时,请使用以下模式。

规则: validate_and_simulate 只接受 intent: strpayload: Mapping[str, Any]。模型输出必须先做 JSON / schema-lock,再跨过 Lirix 边界。

LangChain

from __future__ import annotations

import json
from typing import Any, Mapping, cast

from langchain_core.tools import tool
from pydantic import BaseModel, ConfigDict, Field

from lirix import Lirix, LirixSecurityException


class LirixValidationRequest(BaseModel):
    model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)

    raw_llm_output: str = Field(..., min_length=1)
    intent: str = Field(..., min_length=1)


class LirixSecurityValidator:
    def __init__(self, guardian: Lirix) -> None:
        self._guardian = guardian

    def validate(self, raw_llm_output: str, intent: str) -> str:
        draft = cast(Mapping[str, Any], json.loads(raw_llm_output))
        # 先做结构化反序列化,再交给 Lirix 执行 fail-closed 校验与模拟
        result = self._guardian.validate_and_simulate(intent, draft)
        if result.get("decision") != "approved" or result.get("status") != "approved":
            rc = (result.get("agent_feedback") or {}).get("reason_code")
            return json.dumps(
                {"result": result, "tx_payload": None, "reason_code": rc},
                sort_keys=True,
                default=str,
            )
        try:
            tx_payload = Lirix.extract_broadcast_fields(result)
        except LirixSecurityException as exc:
            return json.dumps(
                {"result": result, "tx_payload": None, "resolution_for_agent": exc.resolution_for_agent},
                sort_keys=True,
                default=str,
            )
        return json.dumps({"result": result, "tx_payload": tx_payload}, sort_keys=True, default=str)


guardian = Lirix(rpc_urls=["https://eth-mainnet.g.alchemy.com/v2/…"])
validator = LirixSecurityValidator(guardian=guardian)


@tool("lirix_validate_and_simulate")
def lirix_validate_and_simulate(raw_llm_output: str, intent: str) -> str:
    """在任何广播路径前进行 fail-closed 校验。"""
    return validator.validate(raw_llm_output=raw_llm_output, intent=intent)

AutoGen

from __future__ import annotations

import json
from dataclasses import dataclass
from typing import Any, Mapping, cast

from lirix import Lirix, LirixSecurityException


@dataclass(frozen=True)
class AutoGenLirixBridge:
    guardian: Lirix

    def __call__(self, raw_llm_output: str, intent: str) -> Mapping[str, Any]:
        draft = cast(Mapping[str, Any], json.loads(raw_llm_output))
        result = self.guardian.validate_and_simulate(intent, draft)
        if result.get("decision") != "approved" or result.get("status") != "approved":
            rc = (result.get("agent_feedback") or {}).get("reason_code")
            return {"status": "blocked", "result": result, "reason_code": rc}
        try:
            tx_payload = Lirix.extract_broadcast_fields(result)
        except LirixSecurityException as exc:
            return {"status": "blocked", "resolution_for_agent": exc.resolution_for_agent}
        return {"status": "approved", "result": result, "tx_payload": tx_payload}


autogen_lirix = AutoGenLirixBridge(guardian=Lirix(rpc_urls=["https://eth-mainnet.g.alchemy.com/v2/…"]))

🏗️ 架构与安全追踪

这部分解释控制平面;读完快速上手后再看最顺。

对外 Lirixlirix/_facade.py)把 HookManagerClientPipelineProtocolLirixPipelineOrchestrator 组合成一条单向流水线;会话与追踪由 FSM 约束。Hook 是隔离契约面,只能扩展策略,不能绕过核心层

flowchart LR
  A[LLM / 工具输出] --> B[Payload 映射]
  B --> C{L1 意图}
  C -- pass --> D{L2 Schema}
  D -- pass --> E{L3 DeFi / ABI}
  E -- pass --> F{L4 RPC Quorum}
  F -- pass --> G{L5 沙盒 + Policy}
  G -- pass --> H[Approved 信封]
  H --> I[你的签名与广播]

  C -- fail-closed --> X[阻断 + 结构化 agent_feedback]
  D -- fail-closed --> X
  E -- fail-closed --> X
  F -- fail-closed --> X
  G -- fail-closed --> X
  1. L1 — 意图防火墙,拦截注入型 Payload。
  2. L2 — Schema 边界,严格类型化 Payload。
  3. L3 — DeFi / ABI 解码与 Proxy 穿透。
  4. L4 — 多节点 RPC 对账与证据收集。
  5. L5 — 本地 EVM 模拟与影子策略审计。

HookManager 提供 RBAC、沙盒路由、OTel 导出与前后置策略钩子,而不会把核心内核拆散。原则很简单:内核保持确定性,外围保持可定制。

开发路径

  • validate_only / async_validate_only — L1–L3 + evidence。
  • simulate_only / async_simulate_only — L4–L5,可按配置在前面挂验证门。
  • validate_and_simulate / async_validate_and_simulate — 全 DAG 路径。
  • atomic_multicall — 与 L1–L3 对齐的 multicall 打包。
  • Layer 类型 — 优先 from lirix import HookManager, ProxyPiercer, RPCManager, SandboxSimulator;需要完整目录(如 ShadowAuditorMulticallEncoder)时再用 lirix.layers / lirix.core

渐进式迁移开关

LirixConfig 暴露 hook_contract_modepolicy_lifecycle_moderpc_evidence_mode。只有当 hook 证据干净、v2 轨道验证通过后,才把 hook_contract_modeshadow 切到 enforce

项目结构

lirix/
├── lirix/        # 核心防线层 + 门面
├── tests/        # 验证与对抗覆盖
├── docs/         # 审计与架构单一真相源
└── SECURITY.md   # 披露政策

完整目录见 docs/STRUCTURE.md。控制面表见 docs/architecture_control_plane.md

🛡️ 安全模型

这份仓库的信任边界非常窄。

Triple-Zero:零密钥 · 零遥测 · 零信任 — 详见 SECURITY.md。如果请求无法被高置信验证,Lirix 会拒绝它,而不是猜测。

💬 支持与 FAQ

  • 普通讨论: Discussions / Issues
  • 安全问题: 不要开公开 Issue;请遵循 SECURITY.md

Q:为什么没有私钥?
A:Lirix 负责校验与模拟, 负责签名。职责分离是设计本身。

Q:遇到 externally-managed-environment 怎么办?
A:先建 venv,永远不要直接 pip install --break-system-packages


PyPI Python Version Coverage 100% License

© 2026 lokii-D — see LICENSE.

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

lirix-2.0.3.tar.gz (119.1 kB view details)

Uploaded Source

Built Distribution

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

lirix-2.0.3-py3-none-any.whl (132.2 kB view details)

Uploaded Python 3

File details

Details for the file lirix-2.0.3.tar.gz.

File metadata

  • Download URL: lirix-2.0.3.tar.gz
  • Upload date:
  • Size: 119.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for lirix-2.0.3.tar.gz
Algorithm Hash digest
SHA256 9a5c8ea7967b04977a9dac529dfa77462ae223cd1933d9229b61b91665e8fc72
MD5 ed7fecb79b0e6e4819072f3026ba7c42
BLAKE2b-256 a4844b4ef4ac1da34a00c365b24ffddc70df623b62ac3b650e787c8f9c6db3e5

See more details on using hashes here.

Provenance

The following attestation bundles were made for lirix-2.0.3.tar.gz:

Publisher: release.yml on lokii-D/lirix

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lirix-2.0.3-py3-none-any.whl.

File metadata

  • Download URL: lirix-2.0.3-py3-none-any.whl
  • Upload date:
  • Size: 132.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for lirix-2.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 7c88864bb55d3f7c67978c4143302997500d3514781330ac8c31ed98e5df09a9
MD5 513d5584801287e0fe03106a83b33f47
BLAKE2b-256 c5d502d82d7b66b037b5dd316115d5737ab2d4907beb57119b138de18ebff55b

See more details on using hashes here.

Provenance

The following attestation bundles were made for lirix-2.0.3-py3-none-any.whl:

Publisher: release.yml on lokii-D/lirix

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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