@skybluejacket/paper2md
v0.1.1
Published
Agent-first local arXiv paper-to-Markdown CLI: one paper in, one JSON receipt out
Maintainers
Readme
paper2md
Agent-first local arXiv paper-to-Markdown CLI.
One modern arXiv ID or arXiv /abs///pdf/ URL in. One JSON receipt on stdout. One Markdown artifact on disk.
paper2md fetches arXiv directly and runs a local Rust engine. It is not a wrapper around Hugging Face, markxiv.org, or any hosted paper reader.
Install
npm
npm install -g @skybluejacket/paper2md
paper2md read 1706.03762Requirements:
- Node.js
>=20.19.0 pandoconPATHfor LaTeX-source fallbackpdftotextonPATHfor PDF fallback
The published package includes a native engine for the publish platform. Other platforms rebuild the Rust engine during install and need Rust/Cargo available.
macOS dependency shortcut:
brew install pandoc poppler rustCodex skill
If the CLI is already installed and you only want the Codex skill:
python ~/.codex/skills/.system/skill-installer/scripts/install-skill-from-github.py \
--repo AidenGeunGeun/paper2md \
--path skills/paper2mdRestart Codex after installing the skill.
Claude Code plugin
Install the CLI first (npm install -g @skybluejacket/paper2md, including the Requirements above), then add the plugin from GitHub:
/plugin marketplace add AidenGeunGeun/paper2md
/plugin install paper2md@paper2mdThis installs the bundled skill, invokable as /paper2md:paper2md. The plugin only adds the skill; conversion still runs through the locally installed paper2md CLI (no hosted backend).
Prefer a plain skill instead of the plugin? Copy the skill card into your personal skills directory:
mkdir -p ~/.claude/skills/paper2md
cp "$(npm root -g)/@skybluejacket/paper2md/skills/paper2md/SKILL.md" ~/.claude/skills/paper2md/Restart Claude Code after installing the plugin or skill.
From source
git clone https://github.com/AidenGeunGeun/paper2md.git
cd paper2md
npm install
scripts/install.shThe local installer builds the CLI, links paper2md into ~/.local/bin, installs the Codex skill, and links the OpenCode, Cursor, and Claude Code skills when those skill roots already exist.
Usage
paper2md read 1706.03762
paper2md read 1706.03762v7
paper2md read https://arxiv.org/abs/1706.03762
paper2md read https://arxiv.org/pdf/1706.03762.pdf
paper2md read '{"input":"1706.03762"}'
printf '{"input":"1706.03762"}' | paper2md read -Help/version:
paper2md --help
paper2md --version
paper2md read --helpJSON request shape:
{
"input": "1706.03762",
"outputDir": "/optional/exact/run/output-dir",
"refresh": false
}outputDir must be an absolute path. If omitted, paper2md creates a unique temp directory. If the target Markdown file already exists in a provided output directory, the run fails with OUTPUT_EXISTS instead of overwriting it. refresh is accepted as a no-op in v1.
Receipt contract
paper2md read stdout is exactly one JSON receipt on both success and failure. The paper body is never printed to stdout or stderr.
Success:
{
"success": true,
"tool": "paper2md",
"status": "ok",
"input": "1706.03762",
"id": "1706.03762",
"paperUrl": "https://arxiv.org/abs/1706.03762",
"outputDir": "/tmp/paper2md-1706.03762-Ab12Cd",
"artifacts": {
"markdown": "/tmp/paper2md-1706.03762-Ab12Cd/1706.03762.md"
},
"warnings": [],
"elapsedMs": 4210
}Failure receipts include error.code and exit nonzero.
Stable error codes: INVALID_INPUT, UNSUPPORTED_INPUT, ARXIV_NOT_FOUND, ARXIV_UNAVAILABLE, MISSING_DEPENDENCY, CONVERSION_FAILED, EMPTY_OUTPUT, OUTPUT_EXISTS, WRITE_FAILED, ENGINE_FAILED, INTERNAL_ERROR.
Supported inputs
- Modern arXiv IDs such as
0704.0001,1706.03762, and2301.07041, optionally versioned like1706.03762v7 https://arxiv.org/abs/<id>https://arxiv.org/pdf/<id>andhttps://arxiv.org/pdf/<id>.pdfhttps://www.arxiv.org/abs/<id>andhttps://www.arxiv.org/pdf/<id>.pdf
Rejected inputs include local file paths, old-style slash arXiv IDs, non-arXiv URLs, markxiv.org URLs, arbitrary PDFs, and IDs containing whitespace or non-ASCII characters.
Conversion behavior
The local Rust engine first tries arXiv's official HTML rendering and converts that to Markdown, which preserves resolved citation links and figure URLs better than raw LaTeX conversion. If HTML is unavailable, it falls back to markxiv-style source conversion: fetch the arXiv source archive, safely extract it, choose the main TeX file, and run pandoc -f latex -t gfm. If source conversion is unavailable, it fetches the arXiv PDF and runs pdftotext as the final fallback.
Quality target: useful paper reading, not perfect scholarly typesetting. Complex tables, custom macros, and visual figures can still be rough; this tool does not interpret images or charts.
Scope boundaries
v1 does not provide VLMs, figure/chart understanding, general PDF parsing, arbitrary URL fetching, DOI lookup, search, metadata-only commands, MCP, server management, image sidecars, or structured content JSON. It writes exactly one content artifact: artifacts.markdown.
Development
npm ci
npm run build
npm run typecheck
npm test
npm run release:checkTests mock the engine and do not require live arXiv, pandoc, or pdftotext. npm test also runs Rust unit tests for the HTML cleanup path.
Release
npm whoami
npm view @skybluejacket/paper2md version --json
npm run release:check
npm publish
git tag v0.1.0
git push origin main v0.1.0publishConfig.access is set to public, so npm publish publishes the scoped package publicly.
When bumping the version, update both package.json and .claude-plugin/plugin.json; npm test fails if they drift.
Attribution
paper2md was designed against the MIT-licensed tonydavis629/markxiv project as the local-conversion reference. This package reimplements the narrow one-shot CLI behavior needed here instead of calling the public markxiv.org service or porting markxiv's server/MCP/cache components.
See NOTICE for the retained markxiv MIT copyright and license notice.
