Convert born-digital, scanned, or mixed PDFs into auditable Markdown while preserving reading order, equations, source-page anchors, and information-bearing images as adjacent non-original text descriptions. Use this skill whenever a user asks to transcribe, OCR, understand, or convert a PDF into Markdown, especially for scanned PDFs, image-heavy pages, formulas, multi-column layouts, page or section ranges, or token-efficient reuse. LT2MD (Long Transcribe to Markdown) is a workflow contract, not a replacement for a PDF parser or OCR/VLM backend.
npx skills add https://github.com/libnyx/LT2MD --skill lt2md
LT2MD turns observable PDF content into Markdown that an agent or a person can audit later. It is designed for born-digital, scanned, and mixed PDFs. The goal is not merely to obtain text: preserve reading order, formulas, figure meaning, scope boundaries, and a path back to the source page.
The PDF remains the only authority for content. OCR, extracted text, model guesses, and formatting preferences are candidates or transformations, never evidence that can overrule the rendered page.
scripts/manage_job.py.scripts/validate_markdown.py, scripts/audit_markdown.py, and scripts/manage_job.py verify as separate final gates. Do not place OCR, model calls, or PDF interpretation inside the static tools.SOURCE HTML comment on its own line before every complete paragraph, display equation, figure block, table or example block. Do not insert an anchor inside a word, sentence, inline formula, display-math block, table row, caption or image description. A cross-page block uses one physical-page range before the merged block.转录注 with the exact page and ambiguity. Never silently normalize an uncertain value into a familiar one.manage_job.py set-book-page-offset <job> --offset <N>; otherwise retain unmapped rather than guessing. Once recorded, that mapping is source evidence: the batch scaffold's source_print_pages and every SOURCE BOOK_PAGE must follow it, and manager review/checkpoint/finalization rejects contradictions.manage_job.py batch-plan <job> --json after initialization, then visually lower any recommendation that contains formulas, tables, multi-column order, dense figures, poor legibility, or a cross-page semantic block. The raster-only plan is a conservative starting point, not visual proof. Prefer complete paragraphs, sections, or examples as cut points; keep a sentence crossing a page boundary with one transcriber.manage_job.py source-inventory-template, fill only source objects and evidence, then freeze it with manage_job.py seal-source-inventory. Only after that seal may the transcriber use manage_job.py batch-template --author-id <transcriber> to create a fresh, non-overwriting batch-scoped candidate. This order is a hard gate: candidate block IDs, review decisions and candidate text must not be retrofitted into the source inventory. Never copy an unreviewed full-document V1 draft into the batch candidate and mistake a whole-document audit failure for a batch transcription attempt. Separate body text, equations, figures, captions, examples, headers, footers, and scan noise. Preserve literal Markdown backslashes while writing formulas: an escape-interpreting string layer must not turn a formula command into TAB, FF, or another C0 control byte. Merge only print line breaks and cross-page continuation; do not insert a page boundary inside a word, sentence, or LaTeX expression. An existing Markdown draft is an untrusted candidate, not evidence: visually re-check every retained block. If an inventory item has no source-grounded candidate block, leave the batch blocked; do not omit it merely because the candidate lacks an anchor. If a block is left unchanged, preserve page-specific review evidence; if the page cannot be read, stop there rather than calling the unchanged draft complete.manage_job.py reviewer-handoff. The manager, not reviewer-supplied JSON, owns the reviewer actor ID, local security-principal record, candidate digest, and sealed-inventory binding. The default policy is an auditable process handoff: it does not prove subjective independence merely because labels differ. An optional init --review-identity-policy os-security-principal-v1 also requires the reviewer process to use a different local OS security principal from the candidate and source-inventory authoring processes; it still cannot prove distinct people or model contexts. The handoff reviewer re-reads the rendered source and completes mappings against the already sealed source-only inventory. The reviewer may add candidate mappings, dispositions and risk closures, but may not rewrite sealed source facts. The coordinator changes content only after confirming the source. An omitted footnote, caption, heading, or cross-page continuation remains blocking even when static Markdown checks pass.checkpoint-review JSON manifest through manage_job.py checkpoint before starting later pages. Use manage_job.py review-template only after the sealed-inventory-backed candidate passes the static contract and its exact-byte reviewer handoff is recorded; it produces a blocked identity/hash scaffold and does not replace source review. The manager rejects a missing handoff, a stale candidate digest, a forged reviewer label/principal, an indented-code pseudo-anchor, a review block spanning multiple SOURCE blocks, or a structural modification hidden by whitespace normalization. A failed static check, audit, source-inventory mapping, or independent review is a stop condition: repair the same batch or leave it explicitly incomplete; never treat a failure report as permission to continue. If a source object visibly continues to the next physical page before any independent review, do not accept the short batch or anchor a fragment. Use manage_job.py extend-unclosed-source-inventory only to preserve its sealed source facts and exact unclosed candidate while expanding the same-start range to at most six pages; then re-inventory every page, create a fresh candidate, and complete the normal independent review. This extension is blocked evidence, never acceptance, and cannot change a checkpointed range. When a reviewer supplies source-grounded omissions, misreads, ordering defects, or wrong-page anchors, return only that batch and the exact evidence to the transcriber, then obtain a new independent reread—never relabel the old review as accepted. If that review proves the source-only inventory facts themselves are incomplete or wrong, do not mutate the old seal: use manage_job.py source-inventory-revision-template with that independent blocked review, reread and seal the new source-only inventory, then create a fresh replacement candidate for the same range. The manager freezes a SHA-named copy of the blocked candidate and review; the new candidate receipt must bind the new active seal, and verification checks both the forward and backward revision chain. It rejects self-review, stale candidate replay, altered lineage, and unchanged source facts; a blocked review can never become acceptance. For jobs created before frozen-candidate evidence existed, use the strict manage_job.py backfill-revision-evidence <job> --pages <range> migration only when the preserved bytes, hashes, receipt, old seal and blocked review agree exactly. Every 16 accepted physical pages or 4 accepted batches, whichever comes first, actually reread task brief, render manifest, progress, frozen evidence and risk queue, then record the receipt with manage_job.py reread. This longer cadence supplements, rather than replaces, the per-batch evidence checkpoint; a cache-only or partial job must not pass manage_job.py verify.FORMAT_OK or strict FORMAT_CHANGE records. The reviewer must not read the source PDF or change content.--before <snapshot>. All content projections and source-anchor values must remain unchanged.10. Deliver. Only the coordinator atomically replaces the final Markdown after all gates pass. First make a blocked full-range final-review-template, obtain an independent source-page acceptance, then use manage_job.py finalize; verify with manage_job.py verify --require-finalization. If interruption leaves a prepared promotion, do not start another finalization: run manage_job.py recover-finalization <job> and re-verify. Report the final Markdown path, converted range, cache/job identity, validation result and any 转录注. Do not deliver internal candidate drafts unless the user asks for them.
Follow the four roles in workflow.md:
转录注.LT2MD itself is a text workflow and does not require a GPU. Its local page renderer uses CPython 3.10+, pypdfium2 and Pillow; these are PDF/image dependencies, not OCR engines. It does not require Tesseract, PaddleOCR, Poppler or another dedicated OCR executable. The actual scan transcription and image-description quality still depends on a host agent with usable visual reading capability. CPU-only execution is allowed, but it may be slower and a host without a usable visual backend cannot promise accurate scan transcription or image descriptions. Do not describe LT2MD as an unconditional guarantee that every computer can complete every PDF.
The final file must be UTF-8 Markdown with the YAML fields, block-level page anchors, LaTeX delimiters, figure-caption/description adjacency, example structure, uncertainty notes, and strict range termination required by markdown-contract.md. It should be self-contained and not depend on external image files unless the user explicitly requests image assets. Cache PNGs remain in the local workspace by default.
The static validator, risk audit and job verifier are separate format/state gates. None proves that the text, equations, or image descriptions are factually correct; that requires the source-grounded visual reviews above.
Before sealing each source inventory, use cached predecessor/successor pages as independent semantic-boundary evidence. They are context only, never automatic output pages: a successor continuation requires bounded expansion while still unsealed; a predecessor continuation blocks the job rather than rewriting any accepted checkpoint. See references/workflow.md and references/job-state.md.
Take libnyx/lt2md from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.