cleanvibe
Website · cleanvibe.emmaleonhart.com
A tiny, zero-dependency Python CLI that starts a Claude Code session in a git-tracked project and gets out of the way.
cleanvibe 2 starts every project as an open-ended working session built to
work from low information. You might explain exactly what you want, drop a
few files in and say nothing, or not be at the computer at all (a scheduled job
or another agent can start the session). The agent works out what the project is
for from the chat, the files in the folder and the directory name. It writes its
read of the goal into INTENT.md and gets on with it. Every session's transcript
is saved into the repository, and sessions start with Remote Control on, so you
can pick them up from the Claude app or web.
Install
pip install cleanvibe
Developer install (working on cleanvibe itself)
git clone https://github.com/EmmaLeonhart/cleanvibe
cd cleanvibe
pip install . # or use !dev-install.bat on Windows
Use pip install ., not pip install -e .. The repository directory is itself named cleanvibe, which means an editable install collides with Python's namespace-package CWD scanning when you run python from the repo's parent directory — Python finds the repo dir as a namespace package and beats the editable finder, so import cleanvibe returns a module with no __version__. The non-editable install copies the package into site-packages where it always wins. After any source edit, run pip install . again (or !dev-install.bat). The console-script entry point (cleanvibe on PATH) works correctly under both install modes — this quirk only affects programmatic import cleanvibe.
Usage
Start a project
cleanvibe # in a cleanvibe project: open a new session there
# anywhere else: create untitled-cleanvibe-project/ here and open it
cleanvibe new # create an untitled project and open it
cleanvibe new ai-history # create ai-history/ and open it
An unnamed project is untitled-cleanvibe-project; if that exists, it gets a
timestamp (untitled-cleanvibe-project-2026-09-26-2104), and only if that is
taken too, a number. A name you choose is also the session's name in the Claude
app and /resume (--name, and the Remote Control session name); untitled
projects are left for Claude to name.
A new project gets a git repo on main (local and private, with no remote
unless you ask for one) and a Claude Code session in a new window. The session
starts with a first message that tells the agent how cleanvibe works: this is the
first session, the information may be thin, and the user may be away. When the
name was generated, the message says so, so the agent doesn't read meaning into
it.
cleanvibe new NAME on an existing cleanvibe project opens it instead of
touching it. On a non-empty folder that isn't a project it refuses (use
cleanvibe legacy convert to adopt a folder in place).
What happens in the first session
- The agent reads
CLAUDE.mdand schedules a one-time intake 30 minutes out (CronCreate). - It looks at what's already in the folder, writes a first read of the purpose
into
INTENT.md, and says briefly what it sees. If you're there and talking, it follows your lead;AskUserQuestionis only for when you are clearly present. - At 30 minutes, the intake runs (
.claude/scripts/data_lake_intake.py):- commit 1 records the repository exactly as found ("the repository 30 minutes in, before moving into data_lake/");
- commit 2
git mvs everything that had never been committed (files you dropped in, new folders) intodata_lake/; - it reports what moved and how much you've said in the chat.
- The agent then studies
data_lake/(a spec or brief in there is followed unless the chat says otherwise), updatesINTENT.md, plans the work with the matching skill, and starts the autonomous work loop. If you said little or nothing, it starts right away; if you've been actively steering, it waits another hour (90 minutes in).
So you can create a project, drop a brief into it, and walk away. With no
brief, no chat and no name there is nothing to go on: the agent says so in
INTENT.md and waits instead of inventing a purpose. A guess about why a
project exists is not a task. (Case studies of real sessions are in
docs/case-studies/.)
What a project contains
| Path | What it is |
|---|---|
CLAUDE.md |
How the project works: low-information operation, the data-lake rule, the intake |
INTENT.md |
The agent's running read of what you're trying to do, with evidence and confidence |
data_lake/ |
The material the project works from, committed as part of its history |
sessions/ |
Every session's transcript, raw .jsonl plus readable .md |
scratch/ |
One-off scripts and downloads, gitignored so they don't pile up as crud |
.claude/skills/ |
Practices the agent picks up when the work takes a shape (below) |
.claude/settings.json, .claude/hooks/ |
The transcript hook |
.cleanvibe.json |
Marks the folder as a cleanvibe project |
There is no queue.md, todo.md or devlog.md at the start. The
queue-driven-workflow skill adds them if the work turns into building
something.
Transcripts are kept in git
A hook (not the agent) copies the session transcript into sessions/ after every
response and commits it at most once an hour and always when the session ends,
so the repository is an audit trail of the whole conversation. The readable
.md is what the agent reads to catch up in a later session.
Sessions are real top-level sessions
A session started by an agent used to inherit that agent's identity
(CLAUDE_CODE_CHILD_SESSION and friends) and ran as its child, without its own
transcript. cleanvibe strips that before launching, so a session is its own
session no matter who started it. On Windows it opens in a new console that
outlives the caller; on macOS/Linux without a terminal it opens a new terminal
window. New project folders are marked trusted in Claude Code's config
(~/.claude.json, backed up first), so an unattended session doesn't stop at
"Do you trust this folder?".
Skills
cleanvibe vendors these into every project's .claude/skills/:
| Skill | Used for |
|---|---|
queue-driven-workflow |
building software: queue.md → devlog.md, tests, CI |
research-practice |
research on any topic: sources, notes with citations, a living summary |
autonomous-loop |
long unattended stretches: one cron every half hour that commits, pushes and keeps working the queue; only you switch it off |
writing-style |
prose without the "honestly" tic |
cron-is-local |
"cron" means a local CronCreate job |
emergency-stop |
"stop stop stop" halts everything |
cleanvibe-update-check |
weekly refresh of these skills from https://cleanvibe.emmaleonhart.com/updates.md |
The single source of truth is cleanvibe/skills.py. To back-fill them into an
older repo, run migrate_repos_to_skills.py.
Replicate a paper
cleanvibe replicate takes a clawRxiv reference, an arXiv/alphaxiv
reference, a plain URL to non-arXiv research, or a folder name:
From a clawRxiv paper (skill-first):
cleanvibe replicate https://www.clawrxiv.io/abs/2605.02609
cleanvibe replicate clawrxiv:2605.02609
clawRxiv publishes papers authored autonomously by
AI agents and exposes a JSON API (/api/abs/<id>) that differentiates the
paper content, abstract, and skill file (an agent-runnable replication
recipe). That separation is the purest recipe-first case, so clawRxiv gets its
own dedicated mode. The scaffold fetches all three up front: the paper content
is written locally to replication_target/source/paper.md (gitignored —
the paper is copyrighted and is never committed), and when clawRxiv ships a
separate skill file it lands at replication_skill.md at the root (otherwise
the recipe is embedded in the content and the queue tells the agent to extract
it). A download_paper.py re-fetches the content from the clawRxiv API if
replication_target/ is ever empty (e.g. a fresh clone). The generated
queue.md/SKILL.md are
skill-first: go live early, run the recipe, verify it against the paper,
check all references, then fill only the gaps. clawRxiv ids look arXiv-shaped,
so a bare id stays arXiv — use a clawrxiv.io URL or clawrxiv:<id> to select
clawRxiv mode.
From an arXiv / alphaxiv paper:
cleanvibe replicate https://arxiv.org/abs/1706.03762
cleanvibe replicate https://www.alphaxiv.org/overview/2201.02177
cleanvibe replicate https://doi.org/10.48550/arXiv.1706.03762
cleanvibe replicate 1706.03762v5
Any arXiv/alphaxiv id or URL is accepted — /abs/, /pdf/, /html/,
/src/, alphaxiv's primary /overview/, /audio/, /forum/, the arXiv
DOI form (doi.org/10.48550/arXiv.<id>), arXiv:<id> citation style,
trailing slugs and query strings all resolve. A pinned vN version is
preserved (recorded in paper.json and used for the download), not silently
dropped. This will:
- Fetch the paper's metadata from the arXiv API (with 429-aware
retry/backoff — arXiv rate-limits, so requests honour
Retry-Afterand back off rather than crashing) - Create
replicating-<paper-slug>/(silently-2/-3if it already exists) - Scaffold a standalone replication project: cleanvibe conventions
(
CLAUDE.md,queue.md,data_lake/) plus the replication structure —SKILL.md(the agent-executable replication plan),download_paper.py(fetches the arXiv LaTeX/e-print source and extracts it toreplication_target/source/, with the PDF as a fallback), the paper's homereplication_target/(gitignored — never indata_lake/; the authors' code is cloned here as a git submodule),paper.json, and.github/workflows/that build a GitHub Pages findings site, a transportable PDF report, and a downloadable ZIP replication package - Initialize a git repo with an initial commit
- Launch Claude Code inside the project
The generated scaffold is built around the efficient, recipe-first path:
- Source, not HTML.
download_paper.pydownloads the arXiv e-print source (arxiv.org/src/<id>) and extracts the.textoreplication_target/source/. The.texis far more token-efficient than the rendered HTML, which embeds figures as huge base64 data-URIs you'd otherwise have to strip. The paper is never committed: the wholereplication_target/tree is gitignored (papers are copyrighted), so the download is local context only — runpython download_paper.pyto (re)populate it whenever it's empty. Thecleanvibe replicatecommand runs this download itself before launching Claude, so the agent opens onto an already-extracted paper — but nothing underreplication_target/ever enters a commit. - Consent before running code. Because a replication runs code you didn't
write (the recipe / cloned scripts / a downloaded zip), the generated
queue.md's first step makes the agent stop and get your explicit consent before executing any external/cloned code. Reading the paper, source, and recipe is fine; running third-party code is the gated action. - Find the recipe FIRST. Authors very often ship a reproduction recipe
right in the paper source (usually near the end): a
SKILL.md/AGENTS.md, areproduce.*/replicate.*/run.shscript, a Makefile target, a Dockerfile, or a downloadable replication zip. The generatedqueue.md/SKILL.mdtell the agent to find it (copying a recipe toreplication_skill.md, extracting a zip intoreplication/) and run it first, before any deep paper analysis — then verify its output against the paper, check all the paper's references, and only reimplement the gaps the recipe didn't cover. - Go live early. The agent is told to create a PRIVATE GitHub repo and push near the start, so every commit pushes and CI builds as the work goes — not left local-only. Every mode defaults to private; on a private repo the Pages workflow uploads the report as a workflow artifact instead of deploying it, until you make the repo public.
- Themed report with a status badge. The GitHub Pages findings site is
rendered with the shared cleanvibe report theme (
report-theme.css— the same warm "paper" + dark-mode themecleanvibe legacy researchuses) and topped with a big color-coded replication status badge — 🟢 replicated / 🔴 failed / 🟠 insufficient hardware / 🔵 in progress — driven by astatusfield inpaper.json(defaults to in-progress). A transportable PDF is built too.
From a plain URL (research that isn't on arXiv):
cleanvibe replicate https://some-lab.org/papers/cool-thing.pdf
cleanvibe replicate https://openreview.net/forum?id=XXXX
When the argument is a plain http(s) URL that isn't an arXiv/clawRxiv
reference, cleanvibe downloads it as the replication source — the page or
PDF lands locally in replication_target/source/ (paper.pdf or
paper.html, detected automatically) — gitignored, never committed — and
provenance is recorded in source.json. A download_paper.py re-downloads
from that recorded URL if replication_target/ is ever empty. Same 429-aware
retry/backoff as arXiv mode. Use it for research hosted on lab sites,
OpenReview, journal pages, or anywhere that isn't arXiv/clawRxiv.
From a folder you fill yourself (manual drop-in mode):
cleanvibe replicate my-paper-replication
When the argument is not an arXiv/alphaxiv reference (and not a URL) it is
treated as a folder name and a manual drop-in project is scaffolded — no
metadata
fetch, no download_paper.py, no paper.json, no network. You drop the
paper PDF(s) into replication_target/ and any datasets/notes into
data_lake/ yourself; the scaffolded CLAUDE.md / queue.md / SKILL.md
/ README.md say so up front, and the first queue step makes the agent
stop and ask you for the paper if replication_target/ is empty rather
than invent one. Injection is non-destructive: you can create the folder,
drop your PDF in, then run cleanvibe replicate ./that-folder — nothing
you put there is overwritten.
Many papers at once:
cleanvibe replicate --batch papers.json --into replications/
cleanvibe replicate --batch papers.txt
One replication project per paper, each routed exactly as a single
replicate would be. The file is JSON (a list, or {"papers": [...]} like
docs/replication-examples/papers.json; each entry a ref string or an object
with ref, arxiv_id or url and an optional path) or plain text with one
ref per line and # comments. Projects land in --into (default: here).
Batch mode never launches Claude; open a project later with cleanvibe
inside its folder. It waits three seconds between network papers (arXiv's
rate limit), carries on past a paper that fails, lists the failures at the
end and exits 1 if there were any.
Every replication produces three compounding artifacts: the runnable
replication, a published findings report, and the reusable SKILL.md
methodology. See docs/replication_framing.md for the full vision.
Doctor — audit a project for drift
cleanvibe doctor # audit the current directory
cleanvibe doctor path/to/project
A read-only check of a cleanvibe project for the drift that builds up over
time. It changes nothing, and exits 1 if it finds anything (so it can run in CI):
| Check | Flags |
|---|---|
files |
a missing CLAUDE.md, README.md, queue.md, or devlog.md |
skills |
a vendored skill that is missing or differs from this cleanvibe's copy |
queue-done |
ticked boxes, check marks, DONE, or strikethrough left in queue.md |
version |
queue.md's "Current version" not matching pyproject.toml |
devlog-tags |
a v* git tag with no devlog.md entry |
section-refs |
a reference to a CLAUDE.md section heading that doesn't exist |
ci |
a tests/ directory with no GitHub Actions workflow |
pages-gate |
a pre-v1.18.0 Pages workflow that fails on a private repo |
Scan — look at third-party code before running it
cleanvibe scan # scan the current directory
cleanvibe scan replication_target/ replication_skill.md
A read-only pattern scan for code you did not write: a replication's
recipe, the authors' cloned repo, a downloaded zip. It groups what matched
(piping a download into a shell, eval/exec and decoding, destructive
commands, credential files and tokens, changes that outlive the run, unusual
package sources, binaries) with file and line, and lists every host the code
mentions. The replicate consent gate has the agent run it and show you the
summary when it asks to run anything. It is a pattern match, not a security
review: no match does not mean the code is safe. It skips .git/, .github/
(CI runs on GitHub, not your machine), .claude/, and the docs cleanvibe
writes at the project root. Exits 1 if anything matched.
Options
cleanvibe --dry-run # Preview what bare `cleanvibe` would do here
cleanvibe new NAME --dry-run # Preview a new project
cleanvibe new NAME --no-claude # Create it without launching Claude
cleanvibe replicate URL --dry-run # Preview a replication scaffold
cleanvibe doctor # Audit the current project for drift (read-only)
cleanvibe scan # Pattern-scan third-party code before running it (read-only)
cleanvibe legacy research NAME --dry-run # Preview a 1.x mode (prints a deprecation warning)
cleanvibe --version # Show version
Legacy modes (deprecated)
The cleanvibe 1.x modes still work as cleanvibe legacy <cmd>. Each run prints a
DEPRECATED warning; they are no longer developed. Their old top-level names
(cleanvibe research, …) now just point here. The cleanvibe 2 default covers most
of what they did: it starts from whatever you give it and picks up development or
research practices as skills. All of them create private repos, and their
sessions start with a first message explaining the mode.
legacy new — the 1.x bootstrap project
cleanvibe legacy new my-project
This will:
- Create the directory
my-project/ - Write
CLAUDE.md(a short pointer to the skills + project-specific notes) - Write
README.md(starter documentation) - Write
queue.md(active work queue, pre-seeded with a first-session bootstrap sequence that walks Claude through triaging dropped-in files, inferring the project, interviewing the user, creatingtodo.md, populating the real queue, and pushing to a private GitHub repo) - Write
devlog.md(where "done" lives) and.gitignore(sensible Python defaults) - Create
data_lake/(drop files in before the first session) and, on Windows,!runClaude.bat - Vendor
.claude/skills/(the workflow skills; see Skills above) - Initialize a git repo on
mainwith an initial commit - Launch Claude Code inside the project, with the 1.x
newstarting prompt
Research a question — your own investigation
cleanvibe legacy research reservoiragent
cleanvibe legacy research reservoiragent --question "What is the memory capacity of a reservoir-computing agent?"
cleanvibe legacy new reservoiragent --research # equivalent alias
research is for an original-research project — your own investigation,
not a replication of someone else's paper. It is new
plus the two things that make research legible: an up-front literature
review and a published, themed report. It scaffolds everything new
does (CLAUDE.md, README.md, queue.md, devlog.md, .gitignore,
data_lake/, the three-cron playbook) and adds:
literature/— the literature review, built before any code. The bootstrap queue's distinctive step uses agentic RAG (web search,WebFetch, thedeep-researchskill if present) to survey prior work, collect sources with citations, and synthesizeliterature/REVIEW.md(what's known, the gaps, what this project adds). This grounds the project in the field instead of reinventing it — and is what separatesresearchfromnew.docs/— a published GitHub Pages report site, pre-styled with a warm "paper" light theme + dark-mode variant (the look of latent-space.emmaleonhart.com), plus a transportable PDF built fromFINDINGS.md..github/workflows/pages.ymldeploys it. The agent edits the content; the theme stays.
The bootstrap sequence is literature-review-first: start the crons →
triage data_lake/ → define the research question with you → literature
review (agentic RAG) → write the long-horizon todo.md → push to a
private GitHub repo (going public for Pages is your call) → replace the bootstrap queue with the real
experiment/build queue → work it, keeping FINDINGS.md + the docs/ report
current. Pass --question if you already know the question; otherwise the
bootstrap pins it down with you.
Original research — when you don't have a topic yet
cleanvibe legacy original driftprobe
cleanvibe legacy original driftprobe --area "reservoir computing"
cleanvibe legacy new driftprobe --original # equivalent alias
original is research for an uncertain topic: you don't yet have a fixed
research question. It keeps everything research has — literature/,
data_lake/, the three-cron playbook, the themed docs/ report — and prepends
one distinctive bootstrap step:
topics/— the topic-finding loop, run before the literature review. The bootstrap explores the focus area (agentic search / RAG), drafts a slate of candidate research questions, scores them (novelty, tractability, interest, available data/compute, what a result is worth), confirms the shortlist with you, and converges on ONE — recording the candidates + scoring + the chosen question + rationale intopics/TOPICS.md. Then it proceeds exactly likeresearch.
The seed is --area (a field to explore), not --question — the question is
what the loop discovers. The bootstrap sequence is topic-finding-first: start
the crons → triage data_lake/ → topic-finding loop (pick the question) →
literature review (agentic RAG) → write todo.md → push to a private repo → replace
the bootstrap queue → work it. Use original when you want to investigate some
area but haven't settled on the precise question; use research
when you already know what you're asking.
Chat — a git-tracked conversation
cleanvibe legacy chat # -> chat-YYYY-MM-DD/
cleanvibe legacy chat tea-notes --topic "oolong vs pu-erh"
chat is for a conversation about one topic rather than a software project:
research-heavy, light on code, kept in a private git repo so you can resume,
search and share it. The session opens by asking you what you are trying to do
(AskUserQuestion) before it plans or researches anything. Conclusions and
sources go into notes/, and the README keeps a running "where things stand".
Session logs are git-tracked. The scaffold's .claude/settings.json runs a
small stdlib script (.claude/hooks/save_session_log.py) after every response
and at session end. It copies the transcript into sessions/ as raw .jsonl
plus a readable .md, and commits only sessions/. At session end it also
pushes if the repo has a remote. Transcripts contain everything in the session,
including tool output, which is one reason the repo stays private.
It starts with Remote Control on (claude "<prompt>" --remote-control,
unnamed), so you can pick the conversation up from the Claude app or web.
!runClaude.bat does the same. NAME is optional; without one you get
chat-YYYY-MM-DD in the current directory, auto-suffixed -2/-3 if it exists. Chat mode has no three-cron
playbook and no Pages report.
Clone an existing repo — codebase onboarding
cleanvibe legacy clone https://github.com/user/repo
clone is for onboarding an existing codebase, not bootstrapping a blank
one. It is deliberately different from new:
git clonethe repository- Create and check out a dedicated
cleanvibe-onboardingbranch — the default branch is left untouched - Prepend-or-write an onboarding
CLAUDE.mdandqueue.md: if the repo already has them, the fresh block goes on top (newest first) and the original content is preserved below — re-running just layers another block - Inject
.gitignoreonly if missing. Nodata_lake/(it is a real codebase, nothing was dropped in) and no README overwrite - Commit the onboarding scaffold on the branch
- Launch Claude Code inside the project
The onboarding queue.md is small and focused: read & document the repo,
make existing docs accurate, rewrite CLAUDE.md to the repo's real
development practices, add tests/CI if sparse, then synthesize any existing
planning artifacts and hand off to the repo's own todo.md.
Why?
Most sessions don't start with a well-defined goal, and a rigid scaffold that
assumes one ends up being fought rather than used. cleanvibe 2 assumes as little
as possible up front and makes the agent do the work of figuring out the goal,
from the chat when you're there and from what's in the folder when you're not.
It keeps two things fixed: everything is committed (including the transcript),
and the agent writes down what it thinks you want (INTENT.md), so you can
check and correct it.
Cross-platform
Works on Windows, Linux, and macOS. Zero dependencies beyond Python 3.9+. On Windows a session opens in its own console window; on macOS/Linux it takes over your terminal, or opens a new terminal window when there isn't one (for example when an agent runs cleanvibe).
Website
Full walkthrough at the project site (built from pages/ and deployed by GitHub
Actions): https://cleanvibe.emmaleonhart.com/
Stability
cleanvibe 2.0.0 is a new major version: the default cleanvibe / cleanvibe new
behavior changed, and the 1.x modes moved under cleanvibe legacy. Within 2.x:
- Commands:
cleanvibe,new,replicate,doctorandlegacyare stable.replicatebehaves as in 1.x, plus the additive--batch. Thelegacymodes keep working but are frozen. - A new project always has:
CLAUDE.md,README.md,INTENT.md,.cleanvibe.json,.gitignore(withscratch/),sessions/,data_lake/,.claude/settings.json,.claude/hooks/save_session_log.py,.claude/scripts/data_lake_intake.pyand the vendored skills, in a git repo onmainwith no remote. - Non-destructive:
newnever overwrites an existing project (it opens it) and refuses a non-empty folder that isn't one.replicateand the legacy modes keep their 1.x guarantees (clone/convertnever overwrite; the replication paper is never committed). - Template wording may evolve; the file set and command contracts above are what 2.x holds stable.
- Zero runtime dependencies remains a hard guarantee.
License
MIT
Metadata
Release files for cleanvibe 2.0.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cleanvibe-2.0.4.tar.gz | 162.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cleanvibe-2.0.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 286.5 kB
Release files / cleanvibe-2.0.4.tar.gz
| Download URL | cleanvibe-2.0.4.tar.gz |
|---|---|
| Size | 162.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7ba69710468251238ea848ea0c5209313d1ee88a31b4cc5d3d8f7aff52bf111a
|
|
BLAKE2b-256 checksum How to use checksums |
33ad6cce57fb367786e9a334da2e698dae4df462d930af9cdfcd456281fb77f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 4, 2026.
Transparency logRelease files / cleanvibe-2.0.4-py3-none-any.whl
| Download URL | cleanvibe-2.0.4-py3-none-any.whl |
|---|---|
| Size | 124.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
79f6d606ae9197c7f5aa9be5d8300bfdc15488c6b12c94db6ca1407ab8be7391
|
|
BLAKE2b-256 checksum How to use checksums |
7f4da55171f5eb2ef79cc5543149ca865276572f24b69a9193a51aba4d7cc1f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 4, 2026.
Transparency log