AI-powered academic paper generation SDK
Project description
EasyPaper
EasyPaper is a multi-agent academic paper generation system. It turns a small set of metadata (title, idea, method, data, experiments, references) into a structured LaTeX paper and optionally compiles it into a PDF through a typesetting agent.
Features
- Python SDK —
pip install easypaper, thenimport easypaperin your own project - Streaming generation — async generator yields real-time progress events at each phase
- Multi-agent pipeline: planning, writing, review, typesetting, and optional VLM review
- Optional FastAPI server mode with health and agent discovery endpoints
- LaTeX output with citation validation, figure/table injection, and review loop
Requirements
- Python 3.11+
- LaTeX toolchain (
pdflatex+bibtex) for PDF compilation - Poppler — required by
pdf2imagefor PDF-to-image conversion- macOS:
brew install poppler - Ubuntu/Debian:
apt install poppler-utils
- macOS:
- Model API keys configured in YAML (see Config)
SDK Usage
Install from PyPI:
pip install easypaper
One-shot generation
Inline metadata:
import asyncio
from easypaper import EasyPaper, PaperMetaData
async def main():
ep = EasyPaper(config_path="config.yaml")
metadata = PaperMetaData(
title="My Paper Title",
idea_hypothesis="...",
method="...",
data="...",
experiments="...",
)
result = await ep.generate(metadata)
print(result.status, result.total_word_count)
for sec in result.sections:
print(f" {sec.section_type}: {sec.word_count} words")
asyncio.run(main())
Load metadata from a JSON file (recommended):
Prepare a metadata.json (see examples/meta.json for the full schema). The clean SDK flow is to parse as PaperGenerationRequest, then split into content metadata and runtime options:
import asyncio
from easypaper import EasyPaper, PaperGenerationRequest
async def main():
ep = EasyPaper(config_path="config.yaml")
request = PaperGenerationRequest.model_validate_json_file("metadata.json")
metadata = request.to_metadata()
options = request.to_generate_options()
result = await ep.generate(metadata, **options)
print(result.status, result.total_word_count)
asyncio.run(main())
For a minimal metadata-only JSON (no runtime options), you can use:
metadata = PaperMetaData.model_validate_json_file("metadata.json")
result = await ep.generate(metadata)
Streaming generation
Use generate_stream() to receive real-time progress events via async generator. Metadata can be built inline or loaded from a JSON file (e.g. PaperMetaData.model_validate_json_file("metadata.json")).
import asyncio
from easypaper import EasyPaper, PaperMetaData, EventType
async def main():
ep = EasyPaper(config_path="config.yaml")
metadata = PaperMetaData.model_validate_json_file("metadata.json") # or build inline
async for event in ep.generate_stream(metadata):
if event.event_type == EventType.PHASE_START:
print(f"▶ [{event.phase}] {event.message}")
elif event.event_type == EventType.SECTION_COMPLETE:
print(f" ✎ {event.phase} done")
elif event.event_type == EventType.COMPLETE:
result = event.data["result"]
print(f"Done! {result['total_word_count']} words")
asyncio.run(main())
GenerationEvent fields:
| Field | Type | Description |
|---|---|---|
event_type |
EventType |
PHASE_START, PHASE_COMPLETE, SECTION_COMPLETE, PROGRESS, WARNING, ERROR, COMPLETE |
phase |
str |
Logical phase name (e.g. "planning", "introduction", "body") |
message |
str |
Human-readable description |
data |
dict | None |
Structured payload (section content, final result, etc.) |
timestamp |
datetime |
When the event was created |
A complete working example is available in user_case/.
Server Mode
To run EasyPaper as a FastAPI service (requires the server extra):
pip install "easypaper[server]"
- Copy the example config and fill in your API keys:
cp configs/example.yaml configs/dev.yaml
- Start the server:
uvicorn easypaper.main:app --reload --port 8000
- Generate via API:
curl -X POST http://localhost:8000/metadata/generate \
-H "Content-Type: application/json" \
-d @economist_example/metadata.json
Skills
EasyPaper includes a pluggable Skills system that injects writing constraints, venue-specific
formatting rules, and reviewer checkers into the generation pipeline. Built-in skills are bundled
as static assets inside the easypaper package:
| Category | Skills | Description |
|---|---|---|
| Writing | anti-ai-style, academic-polish, latex-conventions |
Style constraints applied to all sections — eliminates AI-flavored phrasing, enforces academic tone, ensures LaTeX best practices |
| Venues | neurips, icml, iclr, acl, aaai, colm, nature |
Conference/journal profiles with page limits, formatting rules, and venue-specific style requirements |
| Reviewing | logic-check, style-check |
Reviewer checker prompts — detects logical contradictions, terminology inconsistencies, and style violations |
Enabling skills
Built-in skills are loaded by default. You only need enabled/active_skills in config:
skills:
enabled: true
active_skills:
- "*" # "*" = load all skills; or list specific names
If you add skills.skills_dir, EasyPaper merges bundled skills with that directory:
same skill name → your file wins. If the path is missing, bundled skills still load and a warning is logged.
Venue profiles
To apply venue-specific constraints (e.g. page limits, formatting), set style_guide in your
PaperMetaData to match a venue profile name:
metadata = PaperMetaData(
title="...",
idea_hypothesis="...",
method="...",
data="...",
experiments="...",
style_guide="neurips", # activates the neurips venue profile
)
Custom skills
Each skill is a single YAML file with the following structure:
name: my-custom-skill
description: "What this skill does"
type: writing_constraint # writing_constraint | reviewer_checker | venue_profile
target_sections: ["*"] # ["*"] = all sections, or specific ones
priority: 10 # lower = higher priority
system_prompt_append: |
## My Custom Rules
- Rule 1: ...
- Rule 2: ...
anti_patterns:
- "word to avoid"
Drop the file into your skills_dir and it will be automatically loaded on the next run.
See the built-in skills in easypaper/assets/skills/ for complete examples.
Config
The application loads configuration from AGENT_CONFIG_PATH (defaults to ./configs/dev.yaml).
You can also set this variable in a .env file at the project root.
See configs/example.yaml for a fully commented configuration template. Each agent entry defines
its model and optional agent-specific settings.
Key fields per agent:
model_name— LLM model identifierapi_key— API key for the model providerbase_url— API endpoint URL
Additional top-level sections:
skills— skills system toggle and active skill list (see Skills)tools— ReAct tool configuration (citation validation, paper search, etc.)vlm_service— shared VLM provider for visual review (supports OpenAI-compatible and Claude)
Repository Layout
easypaper/— SDK core, agent implementations, event system, shared utilitiesconfigs/— YAML configs for agents and modelsskills/— backend YAML skills loaded by the Python serviceplugins/easypaper/— Claude/OpenCode plugin root (commands + SKILL.md prompts).claude-plugin/marketplace.json— marketplace catalog.opencode/opencode.json— OpenCode/OpenClaw runtime configurationAGENTS.md— repository-level instructions for coding agentsscripts/— CLI utilities and demosuser_case/— standalone usage example (independent environment)economist_example/— sample metadata input
Claude Code Plugin Market
This repository ships a Claude Code marketplace with one installable plugin located at plugins/easypaper.
Installation
Add the marketplace:
/plugin marketplace add https://github.com/your-username/easypaper
Install the plugin from this marketplace:
/plugin install easypaper@easypaper
Available Plugin
| Plugin | Source | Description |
|---|---|---|
| easypaper | ./plugins/easypaper |
Generate AI-powered academic papers from metadata interactively |
Usage
After installation:
/easypaper
Related commands:
/paper-from-metadata
/paper-section
Plugin Prerequisites
- Python 3.11+
easypaperpackage installed (pip install easypaper)- LaTeX toolchain (pdflatex + bibtex) for PDF compilation
- API key for LLM provider (configured via config file)
OpenCode / OpenClaw Usage
This repository includes native OpenCode/OpenClaw configuration in .opencode/opencode.json.
Run directly in this repository
opencode
The runtime loads:
- Plugin path:
./plugins/easypaper - Skills:
plugins/easypaper/skills/*/SKILL.md - Commands:
easypaper,paper-from-metadata,paper-section
For both Claude Code and OpenCode/OpenClaw workflows, start the EasyPaper API service before generation:
uv run uvicorn easypaper.main:app --reload --port 8000
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file easypaper-0.1.5.tar.gz.
File metadata
- Download URL: easypaper-0.1.5.tar.gz
- Upload date:
- Size: 303.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea20039274c6e7cd95d6a66d33962055528fe34a4ce7318a51f3ea02c4b377d5
|
|
| MD5 |
abdaa563da7d576cec52c73037d24f24
|
|
| BLAKE2b-256 |
d07146f5e24731414b3920391d385f8fb596a087871da2ee2317cb50a2064b76
|
File details
Details for the file easypaper-0.1.5-py3-none-any.whl.
File metadata
- Download URL: easypaper-0.1.5-py3-none-any.whl
- Upload date:
- Size: 341.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47fc3f6b3ca8acf77370c36025e90c0fdb4440405bc20402d3e702e722f0babf
|
|
| MD5 |
ed8050da734a68041e5974c48c92139f
|
|
| BLAKE2b-256 |
26d341ae93ad6aed1f4c98d3a53cd0ded09fbc53a2ad54564740e8eb1e354f04
|