myMend repairs OCR'd books. mend.pipeline is the authority: it keeps complete document revisions in PostgreSQL and runs explicit Actions that change them. rinse and clean are the deterministic tools around it: rinse builds an edition from raw OCR, and the pipeline's cleaning Action runs clean's rules. Nothing in the package calls a model. INTAKE's eight verbs on the Store are in docs/intake.md, PROOF's generic runner in docs/proof.md, and SQL-backed work-level reading in docs/native-proof.md.
Left-rule blocks mark artificial prose; quotations retain their own attribution.
Repair history can also develop executable rules through finite, resumable batches. The symbolic cleanup guide connects preparation, learning, qualification, independent feedback and public CLEAN application. Search checkpoints preserve completed trials and costs; learned artifacts remain explicit, with their qualification and source-evidence grades.
Installation
Python 3.13 or later is required.
From a checkout, in a virtual environment:
$ uv pip install .
# or
$ python -m pip install .
Commands
The package installs three console scripts.
mend-pipelineis the pipeline and the one to learn first;docs/pipeline.mdis its manual.rinseandcleanare the deterministic tools around it (a cleaning Action runsclean's rules), and they stay usable on their own. None of them calls a model.
| Command | Purpose | State |
|---|---|---|
mend-pipeline |
Keep document revisions, run Actions, export and apply edits (docs/pipeline.md). |
working |
rinse |
Turn raw OCR output into an edition, structure first, then sembr. | working |
clean |
Run the pattern library over Markdown, in place; a second run is a no-op. | working |
$ clean works/ # repair in place
$ clean --check works/ # write nothing; exit 1 if anything would change
$ clean --diff works/hegel/chapter-003.md
$ clean --check --report edits.jsonl works/ # every edit and detector hit, with context
$ clean --no-corpus --summary convergence.jsonl draft/ # isolated context; explicit fixed-point receipt
$ clean --check -j 12 --rule spacing works/ # one concern (or `concern.rule`), 12 works at a time
$ clean --check --corpus ~/my/lit raw/book.md # weigh rare tokens against all of lit's English text
$ clean --family legal --skip legal.page_footer docs/ # a document family; leave one rule out
$ clean --list-rules --family legal # what the family runs, rule by rule
Rinse
rinseturns the raw OCR of a book into a lit edition, structure first. It reads a work's source (replay/sources/<hash>.md, read only) and, when the raw shelf holds a byte-identical copy, Marker's.metadata.jsonbeside it. It writesindex.mdandchapter-NNN.mdand nothing else: the pictures underassets/and at the root of an edition are never moved or deleted, and only stalechapter-*.mdfiles are removed. The build is deterministic and idempotent: a second run changes nothing. It makes no model call.
--intaketakes a candidate ledger in the schema of lit's retiredintake.yaml, which lit deleted on 2026-10-19 (MEMY-2113). TherinseAction on the Store replaces that admission (docs/intake.md, section 4); until then the command runs only against an explicit ledger file.
$ rinse hegel-g__1807__phenomenology-of-spirit --intake intake.yaml # rebuild a lit work in place
$ rinse --check --diff WORK... --intake intake.yaml # write nothing; print the diff; exit 1 if any edition would change
$ rinse WORK... --intake intake.yaml --out /tmp/sample # write /tmp/sample/<slug>/ and leave lit alone
$ rinse --source book.md --intake intake.yaml --out ~/ai/scratch/new # admit a new source by the ledger
Exit codes follow
clean: 0 when nothing is wrong, 1 when--checkor--difffinds an edition that would change, 2 when a work could not be rinsed.
--intake FILEis required. It names lit's generatedlit.intake.v1ledger, which is the only admission policy. A new source must match both the recorded path and full lowercase SHA-256, have statusverifiedorpromoted, and have a supported tier (core,primary,secondary,tertiary,auxiliary,nonacademic, orengineering). The ledger supplies the slug, title, author and year, and a source's own YAML header never overrides them. Output goes to--out/<slug>/. Relative ledger paths resolve beside the ledger. Candidate, held and withdrawn rows may retain null hashes for missing evidence with an explicitverdicts.reason; verified and promoted rows require full hashes.source.metadatamay name a Marker metadata file; otherwise the source's.metadata.jsonsibling is used, only while the recorded source bytes match. Missing or malformed ledgers, duplicate slugs/source paths/source hashes, held or withdrawn candidates, unknown tiers and changed bytes fail with exit 2 before an edition is written.--jsonincludes the refusal in anerrorfield. The ledger reader does not scan the shelf or fall back to ai.An edition is
index.md(the curated front matter kept key for key, a title, a byline and atoctree),chapter-000.md(# [Front matter], each front item an H2, the printed contents kept as a nested list of titles), and onechapter-NNN.mdper top-level section of the work, cut at H2 boundaries only above about 250 KB. Square brackets mark a heading rinse added ([Front matter],[Text]for a work with no headings,[Title, continued]); no other heading is ever invented. The back-of-book index is dropped, and it ends where the index does: at the heading of the notes behind it, or of the errata, abbreviations, bibliography or books referred to that follow it, which stay with their pictures. An index set in long paragraphs of entries is still an index: a paragraph in which a tenth of the words are page numbers or ranges (223,290-291;xxix-xxxi;) is no running text, and a headword with no number of its own (Greece) does not end an index whose entries follow it. A line that opens with a note number is a note, never a running head, however often its words recur. Inherited nonempty image alt survives an empty or missing target with a visible limitation; available images retain access text separately from printed captions (see image access).% page Ncomments mark the first block of each PDF page the source lets rinse place, strictly increasing, never guessed.
Step (mend/rinse/) |
What it does |
|---|---|
html, markup |
Marker's HTML to MyST; {sup}'12' roles mended; a superscript a, I or A read as the letter (by shape only, never a Bekker mark); padded table cells trimmed; links to gone anchors unlinked; the linked notes of a Project Gutenberg HTML edition become {sup} roles and note paragraphs, which the binder takes |
pages (layer) |
A text layer's Page N paragraphs become page labels; its # Pages 001-020 headings and [No embedded text on this page.] placeholders go |
figures |
Local images become native figures with alt, separate printed captions, and linked long descriptions. Missing images retain useful alt with a visible limitation. Images in prose blocks are lifted after their containing block; code and math remain literal. See image access. |
pages, marker |
Anchors, _page_N_ image names and the headings of Marker's table of contents become % page N; only the first of several PDFs is labelled |
furniture |
Running heads (recurring, set like a title, cutting sentences), printed page numbers, scan filler, extraction comments (<!-- source-pdf-sha256 -->) and repeated comment stubs (Note -->) |
matter |
Gutenberg's wrapper, the back-of-book index (not the notes, errata or abbreviations behind it, and not an Index among the entries of a printed contents), and the cut between front matter and work |
joins, lists |
A paragraph cut by a page break is whole again, and so is a note cut at the foot of a page whose end the scan marks with a rule (the rest of the note opens the next page, in lower case); 1) a 2) b 3) c and bullet runs become lists |
plain |
A text with no headings of its own: the printed contents and division labels (SECTION II.) give the headings; nothing is guessed from capitals |
headings |
Which blocks are headings, and how deep (below) |
layout, sembr |
Chapter files (an essay and the notes that close it are one file, the notes an H2); one sentence to a line (myform), applied to a paragraph only if its non-whitespace characters are exactly what they were |
Heading inference
Marker's ATX levels are noisy (a book's chapters may come out at
#,##and###by turns), so rinse reads each heading's numbering (Chapter IV,II.,b.,3.2.1,§ 12,(AA.),Teil 2) as a set of candidate readings and searches, over the whole sequence, for the nesting that breaks the fewest habits of books: a number that continues its series is a sibling, one that restarts it (A.afterIV.) opens a deeper level,PartoutranksChapter, a dotted number sits under its parent, and an unnumberedProoforRemarkis a leaf. Marker's own level breaks ties. A last pass puts the headings that follow aVolume,PartorBookinside it, up to the next one of its size or the notes and bibliography behind the work, whatever level Marker gave them; theParts of a series that runs through the whole work (no place comes twice) are raised when Marker set them below their chapters, and aPartand aBookdo not hold one another, since works put either first. A heading is never added except from evidence: a short line that Marker's table of contents lists, a line that is nothing butPrefaceorCHAPTER 3, or (in a source with no headings) a title the printed contents lists. Paragraph-length "headings", running heads, contents and index entries are turned back into text. Depth runs to six.Whatever rinse decides that a rerun must repeat is written under one
rinse:key ofindex.md:body_start(the heading that opens the work),demoteandpromote(titles that are, or are not, headings),levels(a title's forced depth) andkeep_sup(letters whose superscripts are notation in this work). A curator edits that key; rinse reads it and never overwrites it.
The pattern library
The CLEAN families guide groups the current repairs, explains existing note support and distinguishes lexical guards from embeddings or POS tagging.
cleanruns contextual OCR rules. Its actual output then uses the shared canonical reading policy: ordinary searchable accents, quotes, fraction characters, ellipses, dashes, ligatures and spaces. The policy is independent of language guessing and family selection;--ruleand--skipselect contextual repairs while canonical output still applies. Human-readable bibliographic fields and editorial access text follow the same policy.A rule names one pattern in a concern's
RegexStoreand says what becomes of each match: a template string, a niche function(match, context) -> strfor decisions a template cannot make, or nothing, which makes it a detector that reports hits for reviewers. Rules run in order, one whole-text pass each, and never touch a fence: front matter, code, math, inline code (idx tags), roles, comments (page labels), HTML tags, link destinations, footnote labels and URLs (mend/fences.py). A niche function sees the whole work, not just its file, so a word split in one chapter can be rejoined as another chapter spells it. A rule that is right in some languages only names them (languages=('en',)), and the rulebook skips it for a work in another: a work's language is guessed from its function words (mend/language.py), and a short text that cannot be told counts asother.Two more gates keep a rule to the text it was written for. A rule marked
prose=Trueruns only in English running prose, judged by the share of function words, so a table, a bibliography or a page of notation is left whole. A rule markedcorpus=Trueweighs a token against the whole library:Context.corpuscounts every token of every English chapter inworks/(mend/corpus.py, cached under$XDG_CACHE_HOME/mend), because damage is rare and the word it hides is common (rnightonce,mightten thousand times). Without a corpus such a rule makes no edit. The lexicon (mend/lexicon.py,mend/data/english.txt) answers the other question, whether a string is a word at all.For its reviewed default rulebook, the CLI keeps its newly loaded corpus counts in a read-only snapshot shared across the run. Custom rulebooks and caller-supplied corpora keep their existing live mapping behavior.
A repair can make another one visible, so
cleanrepeats the rulebook over a work until a round leaves final canonical text unchanged (five rounds at most), and rebuilds the evidence between rounds. A final round without a text change establishes convergence, including when it is the fifth round. Text still changing at the cap means convergence was not established: the command reports cap exhaustion and exits 2. In ordinary writing mode it still writes the capped result; callers must inspect the exit code before accepting it. One limit remains: cleaning lit itself changes the counts the corpus gives, so a first run over lit can leave a few dozen splits that a second run finds, and a third finds none.
--summary FILEwrites one JSON-lines convergence record per selected file, even when nothing changes:file,kind: "summary",changed,rounds,convergedandfinal_round_edits. Convergence and the final edit count describe the whole work because sibling files supply evidence. This is separate from the unchanged--reportedit/hit format. Summary and edit reports must be distinct files outside cleaning inputs.cleanwrites by default;--checkand--diffleave inputs intact.--checkexits 1 on changes; legacy--diffalone exits 0 even when it prints changes, so an empty-diff check must require both success and empty stdout. Cap exhaustion exits 2 in either mode.
--no-corpusexplicitly skips corpus token context and catalog title context, including automatic ancestor discovery. Rules requiring that context make no corresponding edits; diagnostics name skipped context. Work sibling evidence still runs. Record this selection with a preparation recipe rather than treating skipped context as a passed check. The option is mutually exclusive with--corpus ROOT; ordinary discovery defaults remain unchanged.
Concern (mend/stores/) |
Rules |
|---|---|
glyphs |
glyph: ligatures and invisible characters, from the table mend/data/glyphs.yaml; control_split; detectors replacement, mojibake, control |
markup |
entity (HTML escapes, from mend/data/entities.yaml), duplicate_bullet, stray_grave |
prep |
title (reviewed opt-in catalog-title styling), two_dots and mixed_dots (a damaged ellipsis set as the work prints it), detector greek |
source |
exact (finite source-proved OCR readings with structural guards); detector attached_link (ambiguous attached local link or function notation) |
front |
contact_line: the e-mail and corresponding-author lines of an article's first page |
spacing |
double_space, space_comma |
hyphen |
broken_word (rejoins philo- sophy as the work spells it), line_break, paragraph_break, dot_break; detector unresolved |
numbers |
note_marker; detectors fused_word, stray_marker (a paragraph number whose pilcrow the scan lost, among pilcrow-numbered paragraphs) |
words |
ligature_space, misread (table mend/data/misreads.yaml), the corpus rules ocr_swap, split_token, split_initial, joined_function, letter_spaced, ligature; detectors letter_run (letter-spaced type left unjoined) and spaced_capital (T HE, N OTE S) |
dashes |
double_hyphen |
punctuation |
space_stop, space_colon, double_comma, double_period, glued_stop, stray_dot; detectors middle_dot, comma_stop |
quotes |
adjacent, apostrophe_space (bounded English possessives and contractions), low_pair (German low quotes) |
breaks |
detectors split_paragraph (a sentence across a paragraph break) and lone_number |
legal |
the legal family only: redaction_bar, disclaimer, page_footer, bates_line (published stage), filed_stamp, received_stamp; detectors digit_line, confidential_stamp, privileged_stamp, exhibit_label, foia_stamp |
clean --rule prep --corpus /path/to/lit repairs mixed existing ellipses and reports Greek. Inferring an omission from two dots requires reviewed opt-in (--rule prep.two_dots --force); a dominant ellipsis style alone does not prove that the dots denote an omission. Reviewed title styling requires clean --rule prep.title --force --corpus /path/to/lit; catalog membership alone does not establish a quoted title's style. The catalog supplies full titles and pre-colon short forms; capital-started quoted matches become italics, except common one-word titles, nested quotations and existing emphasis. Missing or malformed catalogs make no title edit. Damaged ellipses use the unique dominant intact form in the work's unprotected text; ties, missing evidence and a lone adjacent sentence stop stay for the reader. Greek words are reported without editing; near-miss catalog titles still need a reader.
source.exact uses the finite readings and scope policy in mend/data/source_repairs.yaml. Missing structural evidence refuses a repair; code and markup cannot supply corroboration. This is not general running-head removal or junk-suffix stripping. source.attached_link reports forms such as DT[theorem](problem) without escaping them: a deliberately attached local Markdown link can have the same syntax. Use its report for source judgment; it is not a strict-build gate.
Frequency-based spelling repair preserves all-uppercase technical acronyms, named literals, apostrophes/primes and known lexicon words. Diagram separators remain intact. The reviewed compound policy in mend/data/lexicon.yaml keeps well-known when the work supplies no explicit closed spelling; rebuilding the dictionary retains that exclusion.
Document families
One library repairs more than one kind of document. A family is a profile of the rules (
mend/data/families.yaml), not a fork: for each family, the rules it runs, the rules it only reports (a repair listed underdetectruns as a detector), and the rules it switches off.--family NAMEpicks one; the default isacademic, an explicit profile that leaves catalog-title styling and frequency-based OCR substitutions off until reviewed opt-in (--rule prep.title --forceor--rule words.ocr_swap --force). Frequency alone cannot establish the intended word: valid rare words, page continuations and numbered references can resemble more common words. Exact misread and source-proved repairs remain enabled. The default and explicit family still agree (tests/test_families.pyholds that against the existing cases and frozen long texts).legalis for court papers, transcripts, mail and records: the 21 rules that the APPS-497 pilot found safe on 398 such documents, no rule that reads lit, and thelegalconcern, which adds a rule only this family has (Rule.families). A family places every rule of its library exactly once, so a rule added later fails the tests until someone decides where it goes.The academic profile also runs
words.split_lexicalfor guarded split-word repair. It protects explicit spelling/specimen/identifier contexts, code, math and meaningfuldifferancedistinctions; ordinary quoted prose remains eligible. Use--skip words.split_lexicalto omit it. Unique repeated same-work lost-letter recovery remains available explicitly through--rule glyphs.work_diacritic --forceor--rule glyphs.work_ascii --force; the legal profile keeps all three off. Canonical accent folding still applies to resulting prose.
--skip IDleaves out a rule or a concern, and may be repeated.--rulestays include-only, and in a profiled family it may name only rules the family runs;--force-rulelets it name a rule the family has switched off, and run it as the library registers it.--list-rulesprints what the family does with each rule and exits.--stage publishedis for text that has already been split into pages: a rule limited to a stage (Rule.stages) runs only there, and the default stage issource. The family, skip list and stage reach every worker of-j N.The
legalconcern ports ten of the twelve acceptedepstein_legalfixes. It repairs a redaction bar set as block characters ([REDACTED]), aPage X of Yline and, at thepublishedstage only, a bareEFTABates line; it reports a bare run of six digits or more and the stampsCONFIDENTIAL,PRIVILEGED,EXHIBITandRELEASED PURSUANT TO FOIA; and it holds two repairs, forFILED:andRECEIVED:date lines, off until a corpus shows them. The disclaimer that a mail system appends to a page is a bounded repair (legal.disclaimer): it removes the notice, fromplease noteat the head of a line to its last sentence or, when the page broke inside it, to the Bates stamp that follows, and never the stamp, a signature or any text after it. A repair that removes a line leaves the line break behind, as the original fixes did, exceptpage_footerandlegal.disclaimer: when one of them takes a whole line it takes the line break too, so that a paragraph cut by a page break is whole again, and when text or a stamp shares the line it leaves the line as it was. The legal profile leaveslegal.disclaimeroff, with four of the pilot's repairs (glyphs.glyph,punctuation.double_period,punctuation.space_colonandpunctuation.space_stop), because a review of 40 sampled edits per rule found more than one wrong edit in each (D-22);--force-rulestill runs one, as the library registers it, and the academic family is unchanged. It runs one hyphen join,hyphen.line_break, which the pilot read at 6 of 26 wrong and which a fresh review of its edits decides (D-26);hyphen.paragraph_break,hyphen.broken_wordandhyphen.dot_breakstay off. The cases aretests/examples/clean.legal.yaml.
$ clean --family legal --check --report edits.jsonl docs/
$ clean --family legal --stage published pages/ # also removes bare EFTA lines
$ clean --family legal --rule hyphen.broken_word --force-rule note.md # a rule the family switched off
Adding a rule
The library grows by turning accepted proofreading experience into tested symbolic capability. The operator's vision explains the purpose; the learning specification defines finite learning cycles, narrowly scoped cases, uncertainty-based review and the evaluation needed to measure useful growth. The source-scoped learned-case contract defines explicit source/member applicability, stable case attribution and Store-backed identity propagation. Standalone cleaning with unknown identity leaves those cases inactive. Contributors should be able to extend another agent's work without reconstructing its session. The tests hold every rule to the same contract.
- Put the pattern in the concern's store (
mend/stores/<concern>.py), named, using theregexmodule's syntax throughRegexStore(subroutines with(?P>name), atomic alternations with the'<|>'mark); never stdlibre. A new concern is a new module withNAME,STOREandRULES, listed inmend/stores/__init__.py.- Add a
Ruleto the module'sRULES: a template, a niche function, or no replacement for a detector; addlanguages=when the repair is right in some languages only,prose=Truewhen it is right in running English prose only,corpus=Truewhen it weighs a token against all of lit,encloses=Truewhen its match may take whole fences with it, andfamilies=('name',)when the rule belongs to one document family only (a concern of its own, listed under that family inmend/data/families.yaml;stages=('published',)limits it to a stage). Literal swaps belong in a YAML table undermend/data/.- Add pattern cases to
tests/examples/regexes.yaml(what matches, what must not).- Add rule cases to
tests/examples/clean.yaml(clean.legal.yamlfor a rule only thelegalfamily has): at least one input the rule changes (or reports) and one it must leave exactly alone. A case may carrylang: ento fix the language a short text cannot show, andlit: {token: uses}to give a corpus rule the counts it weighs (every other token of the text counts as common). Every case also runs twice; the second pass must change nothing.- Run
task test -- tests/test_clean_snapshots.py. It compares frozen long texts, work evidence, edits, and detector hits. Read every changed passage before accepting an intentional update withtask test:ssu -- tests/test_clean_snapshots.py, then inspectgit diff -- tests/__snapshots__/test_clean_snapshots.ambr. Unexpected changes become negative cases. Seetests/fixtures/clean/README.mdfor provenance and the update contract.- Run
clean --check --report edits.jsonl --rule <your rule>over lit'sworks/and over the raw sources inreplay/sources/(lit holds what was already repaired, the sources hold the damage), read a sample of the rule's edits yourself. Read 40 sampled edits per rule, with a seed you record. A repair lands when at most one of the 40 reads wrong and you have looked at that one. A misfire becomes a leave-alone case, and so does any clean edit a reviewer later reverses.Outside the library the same rule holds: a module that needs a pattern keeps it in a
RegexStorecalledSTOREbeside its code, with aNAME, and lists the module inmend/stores/support.py(rinse's modules inmend/rinse/stores.py), so thattests/test_support_regex.pyasks for cases intests/examples/support_regexes.yaml. Write a space or a word as the module's old engine read it when a pattern moves from stdlibre(RE_SPACEandRE_WORDinmend/stores/common.py), and hold the move to the old pattern intests/test_legacy_regex.py. The one pattern that stays raw issmoke's bytes pattern for PDF streams: aRegexStorecomposesstronly.
Downstream pins
Corpus pins this package by git revision and moves its pin deliberately.
apps/epstein-indexpins an older revision (1cc7b170) that still carries the retiredmend.proofharness, the model-review tooling andrinse's canon mode; its migration tomend.pipelineis APPS-566 (brief:~/ai/campaigns/canon-mymend-2026-10-18/handoffs/EPST.md). Do not move that pin to a revision from 0.2.0 on until the migration lands: its proof-drive lane and its read-through imports would fail.
Development
GitLab is the canonical development forge. Any GitHub repository is a read-only source mirror; report issues and propose changes at https://gitlab.com/doering-ai/libs/mend.
Versioning
This project follows semantic versioning. A
1.0.0release requires the maintainer's stability promise inRELEASE.md.
Metadata
Release files for my-mend 0.13.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 |
|---|---|---|---|---|
| my_mend-0.13.0.tar.gz | 743.5 kB | Without provenance | Details for my_mend-0.13.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| my_mend-0.13.0-py3-none-any.whl | Python 3 | none | any | Details for my_mend-0.13.0-py3-none-any.whl |
Total release size: 1.5 MB
Release files / my_mend-0.13.0.tar.gz
| Download URL | my_mend-0.13.0.tar.gz |
|---|---|
| Size | 743.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
417c7876ae013d9c4eb9033fe58b904e3346e982ce6b5c6e20353a0c618d63ac
|
|
BLAKE2b-256 checksum How to use checksums |
4188bad3547253f4fdac39bc54432cddd24bfdaa3f2873dc94276c636942c7a8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / my_mend-0.13.0-py3-none-any.whl
| Download URL | my_mend-0.13.0-py3-none-any.whl |
|---|---|
| Size | 799.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
90f292fbc92ce81014476085e0f0ec58e5226098695f949a702d90fb63b44e86
|
|
BLAKE2b-256 checksum How to use checksums |
3b69a45c810bfadae75c367a2ecad20e00d6d107026524db049a5b3efccbaa5f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for my-mend 0.13.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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.