Conflux
A deterministic state protocol for autonomous multi-agent systems. State is not a set of rows — it is the join of an evolving stream of signed, replayable actions. Agents write concurrently to the same shared state with no table locks, no two-phase commit, and no central coordinator; every node that has seen the same actions converges to the identical state by construction.
Installation
Install the zero-dependency core package from PyPI (imported in Python as conflux):
pip install conflux-state
Optional extras for Ed25519 asymmetric signing and framework integrations:
pip install "conflux-state[crypto]" # Ed25519 signing via cryptography
pip install "conflux-state[langgraph]" # LangGraph CheckpointSaver + Store
pip install "conflux-state[crewai]" # CrewAI Memory StorageBackend + Flow + Tools
pip install "conflux-state[autogen]" # AutoGen Memory + FunctionTools
pip install "conflux-state[integrations]" # All framework integrations
Core use case: shared agent state
The headline problem conflux solves is shared agent state: a few dozen
agents of one application reading and mutating the same counters, registers,
and sets — fleet progress, job counters, leader/slot election, capability
flags, hand-off pointers — with signed writes, durable replay, and crash
recovery, on a mesh of commodity TCP/WebSocket nodes. Two adjacent use cases
ride on the same fabric: workflow state (task queues and step status
through TaskStore and deterministic Workflow) and a replicated memory /
knowledge layer (an agent's shared facts as register/set/string slots).
All three are one storage geometry; the product pitches the agent-state head.
This is not a blockchain and not a distributed SQL system. It is a replicated state fabric built on mathematically convergent data structures (CRDTs / lattice theory) — a coordination layer for distributed AI workflows.
Product definition and scope
Conflux is a small-crew deterministic state fabric for a few dozen agents
of a single application: signed, replayable, eventually-consistent shared
agent state with durable journaling and crash recovery. The protocol is
specified in docs/PROTOCOL.md; every claim in it maps to
a test (conformance index at the end of the spec). The signing, identity, and
storage subsystems are reviewed in docs/SECURITY.md,
which also states the trust boundary and the open findings. Conflux is
released under the MIT License.
Scope — what it is:
- deterministic convergence: same action set ⇒ same
state_hash, in any order; - signed identity: HMAC (zero deps) or Ed25519, plus op/namespace/quota rules;
- durability: fsynced journal + cumulative snapshots that survive a hard crash;
- TCP and WebSocket transports, TLS on both, gossip between peer nodes.
Explicitly out of scope (backlog, not promised):
- linearizable reads, multi-region federation, general-scale KV, blockchain-style global ordering.
Problem
Classic distributed databases serialize writes: a crew of agents updating the same operation counters, queue pointers, capability flags, or hand-off state either blocks itself (latency) or deadlocks. Locks scale poorly once agents outnumber transactions — and agent crews are exactly that regime: many writers, one small shared state.
Approach
Conflux treats shared state not as static rows but as the join of an evolving stream of probabilistic actions. Every value living in the store is an element of a join-semilattice, so any two replicas can merge their states with a single commutative, associative, idempotent operation — the lattice join. Because a join is order-independent, every replica that has seen the same set of actions converges to the identical state, no matter the delivery order.
state = join(contribution(action_1), ..., contribution(action_n))
Core concepts
The lattice
Lattice is the abstract contract: every CRDT implements merge(other) (the join),
read(), and canonical() (a deterministic fingerprint used for hashing). The join
laws are verified directly in tests/test_crdts.py:
- idempotent:
a ⨆ a = a - commutative:
a ⨆ b = b ⨆ a - associative:
(a ⨆ b) ⨆ c = a ⨆ (b ⨆ c)
CRDT types
| Type | Field | Meaning |
|---|---|---|
GCounter |
count per key | grow-only counter, merge = elementwise max |
PNCounter |
(p, n) slots | counters with increments and decrements |
LWWRegister |
value, stamp | last-writer-wins register, stamp = (tick, agent) |
GSet |
set | grows only, merge = union |
ORSet |
tags, values | add/remove with tombstones, merge = union |
ORMap |
key -> CRDT | grows-only keys over any of the above |
Register values are ordinary JSON-ish values; equal stamps (or equal set tags, an invalid protocol usage) are resolved deterministically by canonical order so every replica still picks the same winner.
Actions and determinism
Agents do not mutate shared rows. They emit immutable Actions, each with a globally
unique action_id, an agent, a logical tick, an operation, and params:
Action(action_id="act-agent-1-42", agent="agent-1", tick=42,
op="counter_inc", key="orders", params={"by": 5})
Probabilistic actions carry a weight param. Whether an action "fires" is decided by
SHA-256(action_id, key) projected onto a fixed-point 32-bit scale — a pure function
every replica can compute, so probabilistic inference produces identical state
everywhere without any coordination.
Convergence protocol
- Each agent owns a
Replica— its local join of the actions it has seen. Its journal is append-only and de-duplicated byaction_id. reconcile(a, b): the two replicas exchange journals and absorb what they have not seen. Absorption is exactly the lattice join.converge_all(replicas): full-mesh anti-entropy sweep (for tests and small crews).converge_by_gossip(replicas, rounds): randomized pairwise anti-entropy (for large, partial meshes).Cluster/DistributedApp/InMemoryTransport: a thin network abstraction to demonstrate the protocol over message passing.
Any two replicas that have both absorbed the union of available actions are
provably identical: identical action sets + identical join = identical state. A
consensus fingerprint, state_hash(state), is a SHA-256 over the canonical
serialization.
Quick start
from conflux import Cluster, InMemoryTransport
cluster = Cluster({"agent-a", "agent-b", "agent-c"}, transport=InMemoryTransport())
cluster.node("agent-a").counter_inc("orders", 5)
cluster.node("agent-b").counter_inc("orders", 3)
cluster.node("agent-c").register_set_weighted("risk.appetite", "low", weight=0.6)
cluster.gossip_round()
assert cluster.read("agent-a", "orders") == 8
assert cluster.read("agent-b", "orders") == 8
Deterministic replay from a journal:
from conflux import state_hash, replay
from conflux.protocol import journal_from_json, journal_to_json
blob = journal_to_json(cluster.node("agent-a"))
actions = journal_from_json(blob)
# fold in any order, every time, always the same state:
assert state_hash(replay(actions).state) == state_hash(cluster.node("agent-b").state)
Protocol hardening: versioning, signatures, authority
Actions travel as envelopes that any node can verify before they touch state.
{
"action": { "action_id": "act-a-1", "agent": "a", "tick": 1, "op": "counter_inc",
"key": "orders", "params": {"by": 3}, "version": 1 },
"signed_by": "a",
"signature": "<signature over canonical action bytes>",
"alg": "hmac-sha256"
}
- Versioning. Every action carries
version; the validator rejects unknown versions, so protocol changes are explicit (current:1). - Signatures.
sign_action(action, secret)produces an HMAC-SHA256 over the canonical (key-sorted) JSON of the action (zero dependencies). For asymmetric identity, passalg="ed25519"with a raw private key —generate_ed25519_keypair()returns(private, public),verify_action(envelope, public, "ed25519")checks it. Ed25519 requires the optionalcryptographypackage; HMAC needs nothing. - Identity + authority.
AgentRegistrymaps agent ids to a secret (HMAC) or a public key (Ed25519), plus allowed op sets and per-agent write quotas.validate_envelopechecks signer identity, signature, authorization, and quota before a node ever merges, and refuses envelopes whose algorithm does not match the agent's registered key. - Schema.
validate_actionenforces op-specific payload rules (counterby, JSON-safe register/set values, non-empty tags,weightin[0, 1]).
A server equipped with a registry refuses unverified, unauthorized, or
quota-exhausted submits ({"type": "error", "reason": "..."}); a server without
one still schema-validates but runs in trust-less dev mode. Note that the
registry guards the agent submit path only — the peer gossip path is trusted
at the network layer, and every node's listen port must therefore be treated
as a peer-trusted boundary. docs/SECURITY.md walks
through what the signing, identity, and storage layers do and do not
guarantee, with each property mapped to the code and tests that enforce it.
from conflux import AgentRegistry, Client, Server
registry = AgentRegistry()
registry.register("driver", "s3cr3t", ops={"counter_inc", "lww_set"}, quota=1000)
server = Server("n1", ("127.0.0.1", 7001), registry=registry)
server.start()
client = Client("127.0.0.1", 7001, agent_id="driver", secret="s3cr3t")
client.counter_inc("orders", 5) # signed, authorized, quota-counted
Running the tests
python -m pytest
The suite covers join laws, threaded lock-free convergence, merge-order determinism, probabilistic determinism, journal round-tripping, the network-framework gossip path, the networked backend (client round-trip, two-node gossip convergence, restart persistence), signed-envelope authority, namespaces, the WebSocket transport (RFC6455 framing, WS node convergence, discovery, batching, backoff), the application layer (events, watchers, task state, deterministic workflows), and the operational surface (TLS framing over tcp + ws, signed/verified journals, membership + partition heal, and cumulative snapshot compaction).
Application layer: workflows, tasks, events, watchers
Everything sits on the same replicated fabric, so application state converges and replays exactly like raw CRDT state.
EventBus— subscribe to the action stream by op, exact key, or key prefix; handlers get(action, origin)where origin islocal(this node's own emit) orabsorb(received from a peer).Server.subscribe(...)wires it onto the live wire path.Watcher— value-level snapshots:watch(key, handler)fires when a key's effective value changes, with the previous value.TaskStore— replicated task execution state undertasks/<id>(created → running → step → done/failed), each transition a signed, deterministiclww_set.Workflow/WorkflowRunner— ordered steps (counter_inc,lww_set,orset_add,orset_remove,noop) against keys, with optionalweight-gated steps decided by the same deterministic hash every replica can reproduce. Identical inputs always emit identical action logs.
from conflux import Server, Workflow, WorkflowRunner, WorkflowStep, TaskStore
server = Server("n1", ("127.0.0.1", 7001))
server.start()
server.subscribe(lambda action, origin: print("event:", origin, action.op),
op="counter_inc")
server.watch("wf/shipments", lambda value, key, old: print("watched:", value))
workflow = Workflow("fulfill", [
WorkflowStep("reserve", "counter_inc", key="wf/capacity", params={"by": 1}),
WorkflowStep("ship", "orset_add", key="wf/shipments", params={"value": "carrier-17"}),
])
task = WorkflowRunner(server.replica, workflow).run("fulfill-1", "fulfill",
inputs={"sku": "A-1"})
Framework integrations: LangGraph, CrewAI, AutoGen
conflux.integrations ships drop-in adapters that let popular orchestration
frameworks use Conflux as a lock-free, convergent shared state backend.
Every adapter accepts any Conflux runtime object (Replica, Cluster node,
Server, or networked/signed Client), works out of the box with zero
third-party dependencies, and automatically inherits each framework's native
base classes when installed.
LangGraph (ConfluxCheckpointSaver + ConfluxStore)
Persist, fork, and resume StateGraph checkpoints across separate Conflux
nodes, and share cross-thread items, CRDT counters, and sets without DB locks:
from langgraph.graph import StateGraph
from conflux import Client
from conflux.integrations.langgraph import ConfluxCheckpointSaver, ConfluxStore
client = Client("127.0.0.1", 7001, agent_id="planner", secret="s3cr3t")
checkpointer = ConfluxCheckpointSaver(client)
store = ConfluxStore(client)
graph = builder.compile(checkpointer=checkpointer, store=store)
graph.invoke({"topic": "CRDTs"}, config={"configurable": {"thread_id": "run-42"}})
# Concurrent CRDT counters & sets across parallel LangGraph workers:
store.counter_inc(("metrics", "research"), "queries_executed", by=1)
Runnable example: examples/langgraph_shared_state.py
CrewAI (ConfluxCrewStorage, ConfluxFlowPersistence, create_crewai_tools)
Plug Conflux into CrewAI's unified Memory (StorageBackend protocol),
checkpoint @persist Flows across nodes, and give agents direct CRDT tools:
from crewai import Agent, Crew
from crewai.memory import Memory
from conflux import Client
from conflux.integrations.crewai import (
ConfluxCrewStorage,
ConfluxFlowPersistence,
create_crewai_tools,
)
client = Client("127.0.0.1", 7001, agent_id="researcher", secret="s3cr3t")
storage = ConfluxCrewStorage(client)
tools = create_crewai_tools(client, namespace="crew.")
researcher = Agent(role="Researcher", goal="...", backstory="...", tools=tools)
crew = Crew(agents=[researcher], tasks=[...], memory=Memory(storage=storage))
Runnable example: examples/crewai_shared_memory.py
AutoGen (ConfluxAutoGenMemory + create_autogen_tools)
Equip AutoGen v0.4+/v0.7+ AssistantAgent teams with a replicated
autogen_core.memory.Memory store that injects converged facts + live CRDT
keys into ChatCompletionContext, alongside native FunctionTools:
from autogen_agentchat.agents import AssistantAgent
from conflux import Client
from conflux.integrations.autogen import ConfluxAutoGenMemory, create_autogen_tools
client = Client("127.0.0.1", 7001, agent_id="coder", secret="s3cr3t")
shared_memory = ConfluxAutoGenMemory(client, state_watch_prefix="team.")
shared_tools = create_autogen_tools(client, namespace="team.")
agent = AssistantAgent(
name="coder",
model_client=model_client,
memory=[shared_memory],
tools=shared_tools,
)
Runnable example: examples/autogen_shared_state.py
Publishing to PyPI (Trusted Publishing / OIDC)
Conflux is packaged as conflux-state on PyPI (imported as conflux) and
ships ready-to-use GitHub Actions workflows in
docs/github-workflows/publish.yml and
docs/github-workflows/ci.yml using PyPI
Trusted Publishing (OIDC — no long-lived API tokens required):
- Move or copy the workflows into
.github/workflows/:mkdir -p .github/workflows && cp docs/github-workflows/*.yml .github/workflows/
- On pypi.org/manage/account/publishing/,
add a Pending Publisher:
- PyPI Project Name:
conflux-state - Owner:
lolllll212 - Repository name:
Conflux - Workflow name:
publish.yml - Environment name:
pypi
- PyPI Project Name:
- Tag and push a release (or publish a GitHub Release):
git tag v0.8.0 && git push origin v0.8.0
GitHub Actions runs the full test suite, verifies the wheel + sdist viatwine check --strict, and publishesconflux-stateto PyPI automatically.
Operations: metrics, admin stats, benchmarks
Every server exposes a live metrics() dict — absorbed/submitted actions,
journal length, links, outbound dials, discovered peers, known members, uptime,
current state_hash — and answers the wire query {"type": "admin", "what": "stats"}
with the same payload, so monitoring can poll nodes without a driver agent.
For Prometheus, the same data is rendered in text exposition format — no
dependencies — and served three ways: Server.prometheus(), the wire query
{"type": "admin", "what": "prometheus"} (returns the body over the framed
connection), and an embedded stdlib HTTP listener:
python -m conflux.server --id alpha --listen 127.0.0.1:7001 --metrics-http
# -> metrics http on http://127.0.0.1:<ephemeral>/metrics
server = Server("alpha", ("127.0.0.1", 7001)).start()
server.start_metrics_http("0.0.0.0", 9101) # scrape http://<node>:9101/metrics
Counters (conflux_actions_absorbed_total, ..._submitted_total) and gauges
(links, outbound, peers, discovered, members, journal_actions, uptime,
state-hash info label) are labeled with node_id:
python benchmarks/bench.py # replay, cluster, tcp + ws round-trips
python benchmarks/bench.py --quick # small sizes for CI
Example (previous run, this machine): ~168k actions/s journal replay, ~38k actions/s full-mesh cluster convergence, ~0.13 ms single-agent submit→ack round-trip over TCP and ~0.17 ms over WebSocket.
The real agent-state app, in one file: examples/agent_crew_demo.py — six
signed agents share state (crew.work_done, check-in set, leader slot) across
a 3-node mesh, then put the runtime through the failure model it was hardened
for: a hard crash, continued writes through the partition, restart from the
signed snapshot + journal tail, keyless reload refused, and an out-of-namespace
write refused with no state mutation. examples/durable_crew_demo.py shows the
same crash-recovery cycle on a single agent. Supporting demos:
examples/workflow_demo.py (tasks/events/watchers over a cluster) and
examples/deploy_multi_node.py (signed Ed25519 crews over TCP and WS meshes).
Backend: networked, persistent nodes
The reference implementation ships with a multi-node backend so agents in
different processes (or different machines) can converge. Two transports are
built in: the default framed TCP and --transport ws, a dependency-free
RFC6455 WebSocket transport (conflux.websocket). Set transport="ws" on the
Server/Client to use it.
Run a node
python -m conflux.server --id alpha --listen 127.0.0.1:7001 --data ./data/alpha
python -m conflux.server --id beta --listen 127.0.0.1:7002 --peers 127.0.0.1:7001 --data ./data/beta
Use --peers host:port,host:port to list neighbors. Gossip links are
bidirectional once established, and each node replays its persisted journal on
startup.
TLS framing (tls:// and wss://)
Pass a PEM certificate to encrypt every socket with the stdlib ssl module —
both the framed TCP transport and the RFC6455 WebSocket transport, for agent
clients and peer-to-peer gossip alike:
python -m conflux.server --id alpha --listen 127.0.0.1:7001 \
--cert ./cert.pem --key ./key.pem --data ./data/alpha
server = Server("alpha", ("127.0.0.1", 7001), tls=("cert.pem", "key.pem")).start()
client = Client("127.0.0.1", 7001, tls=("cert.pem", "key.pem", "cert.pem")) # ca = 3rd element
Omitting the CA in the client's tls= tuple disables peer verification (self-signed
clusters); tls=True uses the system CAs, and tls="ca.pem" verifies against that CA.
Membership and partitions
Peers announce their node id, address, peer list, and member view on
handshake; every server maintains a members view (see metrics()["members"]
and members_view()). When a neighbor dies, the receive loop drops the link
and the gossip loop re-dials it with exponential backoff. Links that go silent
without closing (a hung or partitioned peer) are liveness-checked and dropped
after --stale-after seconds (default 3× gossip_interval), then re-dialed —
so a healed partition re-converges automatically once the peer is reachable
again (see tests/test_phase4.py::test_partition_reconnect).
Signed, compacted journals
python -m conflux.server --id alpha --listen 127.0.0.1:7001 \
--cert ./cert.pem --key ./key.pem --journal-key "$(openssl rand -hex 16)" --data ./data/alpha
Every journal line carries "sig" — an HMAC-SHA256 over the canonical action
bytes — and every snapshot carries the same over its {seq, root} payload.
Replay verifies both; a tampered log or snapshot raises instead of silently
restoring a corrupt state. Snapshots are cumulative: each compaction folds
the current root into the previous generation via the lattice join and emits a
single merged summary, pruning older generations, so a crash mid-history never
loses committed state.
Write and read from an agent
from conflux import Client
client = Client("127.0.0.1", 7001, agent_id="agent-42")
client.counter_inc("bookings.seats", 2)
client.register_set("flight.eta", "14:05")
client.set_add("tickets", "TK-100", tag="tk-100")
print(client.read("bookings.seats")) # 2
print(client.hash()) # 64-hex SHA-256 of canonical state
# Batch multiple mutations in a single atomic round-trip:
with client.batch() as b:
b.counter_inc("bookings.seats", 1)
b.register_set("flight.status", "boarding")
client.close()
Durability
Each absorbed action is appended to data/<node>/journal.jsonl immediately.
When the journal passes the snapshot threshold, the current CRDT root is merged
(lattice join) into the previous generation's root and written atomically —
both as snapshot-<seq>.json (generation) and snapshot.json (latest alias) —
after which the log is truncated and older generations are pruned. A node never
replays a tail older than what its cumulative snapshot already captures, and a
crash mid-rotation degrades to the newest untampered generation. Optional
--journal-key HMAC-signs every line and snapshot, and replay refuses
tampered files. State values travel on the wire as JSON; register/set values
must be JSON-serializable.
Guarantees and limits
Conflux promises, and the test suite verifies:
- Eventually consistent convergence: every node that has absorbed the union of
available actions shows identical state (same
state_hash), regardless of delivery order. - No global lock, no blocking writes: agents write to their own replicas concurrently; merging is a join, so writers never contend.
- Deterministic merges: identical action sets always yield identical state, including tie-breaks (equal stamps/tags) resolved by canonical order.
- Replayability: any subset of the journal rebuilds exactly the same state.
- Durable ack: a submit is acknowledged only after the accepting node has absorbed the actions and fsynced them to its journal; an acked action survives that node's process crash (torn-tail recovery).
The exact limits — schema bounds, frame size, snapshot/gossip/stale defaults,
backoff schedule, quota rules, and measured throughput (≈24k actions/s local
replay, ≈2.8k actions/s across an 8-agent TCP cluster) — are pinned in
docs/PROTOCOL.md §8; re-run benchmarks/bench.py for
host-local figures.
Honest limits:
- Stale reads: a read observes the join of everything that node has gossiped so far. Convergence is eventual, not linearizable; workflows that need strictly ordered reads need an external sequencing channel.
- One type per key: merging a key's existing CRDT with a different CRDT type
raises
TypeError— a deterministic schema contract, not an ambiguity. - Unique IDs are load-bearing:
action_idand set tags are event identities; reuse silently merges (so agent ids must be process-unique and ticks monotonic). - Fixed-point weights: probabilistic decisions use a fixed 32-bit scale over
the same serialized
weight, so all replicas agree as long asweightis a JSON number.
Roadmap -> status
Phase 1 (protocol foundations), Phase 2 (cluster runtime), Phase 3 (application layer), and the Phase 4 operational surface (metrics/admin probe, Prometheus exporter, benchmarks, TLS, signed journals, membership/partition handling, cumulative compaction) are complete.
The remaining ideas in each phase are backlog, deliberately out of scope under the current product definition (§"Product definition and scope"): secure framing beyond TLS, multi-cluster federation, chunked cross-peer snapshot exchange, OpenTelemetry exporters, and workflow orchestration expansion. Each is a candidate to revisit only after the core fabric — determinism, durability, crash recovery — is proven by adopters.
Security
The cryptographic signing, identity verification, and storage subsystems are
documented in docs/SECURITY.md: threat model and trust
boundary, the properties the implementation enforces (constant-time
verification, algorithm binding, canonical serialization, signer binding,
replay idempotence, keyless-reload refusal), the findings that remain open,
and a deployment checklist. To report a vulnerability, open a GitHub issue or
contact the maintainer privately as described there.
License
Conflux is released under the MIT License, as declared in
pyproject.toml.
Metadata
Release files for conflux-state 0.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| conflux_state-0.8.0.tar.gz | 84.5 kB | With provenance | Details for conflux_state-0.8.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| conflux_state-0.8.0-py3-none-any.whl | Python 3 | none | any | Details for conflux_state-0.8.0-py3-none-any.whl |
Total release size: 143.5 kB
Release files / conflux_state-0.8.0.tar.gz
| Download URL | conflux_state-0.8.0.tar.gz |
|---|---|
| Size | 84.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8be235307db5a9114697368a22c3869a46cdf099f93ae0f7edff926651af2ba0
|
|
BLAKE2b-256 checksum How to use checksums |
e00de95518ae9e22fe06733893275caffd90f67d3282c34aff6d3505206445a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logRelease files / conflux_state-0.8.0-py3-none-any.whl
| Download URL | conflux_state-0.8.0-py3-none-any.whl |
|---|---|
| Size | 59.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
95ff54b26bd65c25e04040e9858cf1115f23cb8517680a129c6c583265965943
|
|
BLAKE2b-256 checksum How to use checksums |
98de0f985bcc9a08a4aeb6c54c09038dfb1203592873c116e8cfded9d82461b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logSecurity for conflux-state 0.8.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for conflux_state-0.8.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.