diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..d062ff2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,44 @@ +name: Feature request +description: Propose a new PaperReading capability, integration, schema field, or research workflow. +title: "[Feature]: " +labels: [enhancement] +body: + - type: markdown + attributes: + value: "Please avoid uploading copyrighted full-text papers, confidential data, credentials, or personal workbooks." + - type: textarea + id: research_problem + attributes: + label: Research workflow problem + description: What research task is difficult or repetitive today? + placeholder: "Example: comparing identification strategies across 30 papers requires manual coding." + validations: + required: true + - type: textarea + id: proposed_behavior + attributes: + label: Proposed behavior + description: Describe the input, expected output, and where this should live in the workflow. + validations: + required: true + - type: dropdown + id: area + attributes: + label: Area + options: + - Structured reading + - Evidence grounding + - Method audit + - Literature Matrix / synthesis + - Export / integration + - Codex skill + - Excel workflow + - Documentation / examples + - Other + validations: + required: true + - type: textarea + id: evidence + attributes: + label: Example or acceptance criteria + description: Provide a sanitized example, expected schema, or concrete success criteria if possible. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06e4259..e273432 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: run: python tools/validate_skill.py skills/papers-reading-skill - name: Compile Python sources - run: python -m compileall -q skills tools tests + run: python -m compileall -q paperreading skills tools tests - name: Run tests run: python -m unittest discover -s tests -v diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..13460ed --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,29 @@ +# Changelog + +All notable changes to PaperReading will be documented in this file. + +The project follows a lightweight Keep-a-Changelog style. Versioning will become strict once the reusable Python core reaches its first tagged release. + +## [Unreleased] + +### Added + +- Reusable `paperreading` Python core for paper records, empirical designs, findings, and evidence anchors. +- Evidence-label rendering and evidence-coverage metrics. +- Dependency-free Literature Matrix generation and Markdown rendering. +- Portable JSON Schema for structured paper records. +- Architecture documentation and a staged product roadmap. +- `CITATION.cff` metadata. +- MIT License. +- Feature-request issue template. + +### Changed + +- Repositioned the project from a Codex-only skill to an evidence-grounded research workflow while preserving the existing skill and Excel writer. +- Updated bilingual README documentation around the new architecture and product direction. +- Extended CI compilation to cover the reusable Python core. + +### Compatibility + +- The existing `skills/papers-reading-skill/` runtime contract is intentionally unchanged in this restructuring. +- Existing workbook behavior and the 13-field Excel export remain unchanged. diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..59004c3 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,18 @@ +cff-version: 1.2.0 +message: "If you use PaperReading in your research workflow, please cite this software." +title: "PaperReading: Evidence-grounded AI paper reading for empirical research" +type: software +authors: + - name: AOROM +repository-code: "https://github.com/AOROM/paperreading" +license: MIT +version: "0.2.0-dev" +date-released: "2026-08-11" +keywords: + - literature review + - paper reading + - empirical research + - evidence grounding + - finance + - economics + - management diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..48016c6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 AOROM + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 40db24f..3b5d94a 100644 --- a/README.md +++ b/README.md @@ -1,106 +1,151 @@ -# Paper Reading Skill +# PaperReading **English** | [简体中文](README.zh-CN.md) [![CI](https://github.com/AOROM/paperreading/actions/workflows/ci.yml/badge.svg)](https://github.com/AOROM/paperreading/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) -An installable Codex skill for reading finance, economics, management, and social-science papers. It converts each paper into 13 auditable fields, separates the paper's claims, empirical evidence, and the reviewer's assessment, proposes executable follow-up research designs, and can safely append the results to an existing Excel literature-review workbook. +> **Turn papers into research intelligence.** -## Core capabilities +PaperReading is an evidence-grounded AI research workflow for **finance, economics, management, accounting, and empirical social science**. Instead of stopping at a generic summary, it structures papers around research questions, theory, identification, variables, evidence, mechanisms, robustness, limitations, and executable follow-up designs. -- Extract the title, authors, journal, ranking, publication date, keywords, research questions, findings, research logic, empirical models, data and variables, and extension designs in a fixed order. -- Organize baseline results, mechanisms, heterogeneity, economic consequences, endogeneity treatment, and robustness checks into distinct layers. -- Avoid presenting correlation as causation or inventing missing variables, models, data sources, or journal rankings. -- Safely add the thirteenth field to a compatible 12-column workbook while preserving existing content, styles, formulas, filters, and table structure. -- Detect duplicates before writing, validate a temporary save, create a backup, and atomically replace the original workbook. +The repository keeps the existing installable Codex skill and safe Excel workflow, while evolving toward a reusable Python core for auditable paper records, evidence maps, cross-paper comparison, and literature synthesis. -## Project structure +## Why PaperReading? + +Most paper-reading tools optimize for *what a paper says*. PaperReading is designed around *why a result should be believed and how it can be extended*. ```text -paperreading/ -├── skills/papers-reading-skill/ # Installable skill -│ ├── SKILL.md -│ ├── agents/openai.yaml -│ ├── references/ -│ └── scripts/append_paper_reading.py -├── examples/ # Example input -├── tests/ # End-to-end and structural tests -├── tools/ # Repository-level validation tools -└── .github/workflows/ci.yml # Automated validation +Paper / PDF + │ + ├── Structured Reading ── 13-field review schema + ├── Evidence Map ──────── page / section / table / figure anchors + ├── Method Audit ──────── identification / endogeneity / robustness + ├── Literature Matrix ─── cross-paper comparison + └── Research Extensions ─ executable follow-up designs + │ + └── Excel / JSON / Markdown / future integrations ``` -Repository-level documentation, tests, and CI configuration are not loaded into the skill's runtime context. Install only `skills/papers-reading-skill/`. +## Current capabilities -## Installation +### 1. Evidence-grounded 13-field reading -1. Clone the repository and install the script dependencies: +The existing Codex skill extracts bibliographic metadata, research questions, findings, research logic, empirical models, data and variables, and follow-up research designs in a fixed auditable structure. - ```bash - git clone https://github.com/AOROM/paperreading.git - cd paperreading - python -m pip install -r requirements.txt - ``` +It explicitly separates baseline findings, mechanisms, heterogeneity, economic consequences, endogeneity treatment, and robustness checks, and avoids inventing missing variables, models, rankings, or causal claims. -2. Copy the skill directory into your Codex skills directory. Windows PowerShell example: +### 2. Auditable paper records - ```powershell - Copy-Item -Recurse -Force ` - .\skills\papers-reading-skill ` - "$env:USERPROFILE\.codex\skills\papers-reading-skill" - ``` +The new `paperreading` Python package provides a reusable data model for paper metadata, empirical design, findings, and evidence anchors. -3. Start a new Codex session. Invoke the skill explicitly with `$papers-reading-skill`, or use a natural-language request about paper reading, 13-field extraction, or literature-review workbook updates. +```python +from paperreading import EvidenceRef, Finding, PaperRecord -## Workbook configuration +paper = PaperRecord( + title="Example paper", + research_questions=["Does X affect Y?"], + findings=[ + Finding( + text="X is positively associated with Y.", + category="baseline", + evidence=[EvidenceRef(page=12, table="Table 3", section="4.2")], + ) + ], +) +``` -The public repository contains no personal workbook paths. The write script resolves its target in this order: +### 3. Literature Matrix -1. The command-line option `--workbook `; -2. The `PAPER_READING_WORKBOOK` environment variable; -3. If neither is provided, stop without writing. +Multiple `PaperRecord` objects can be converted into a compact comparison matrix without requiring pandas: -PowerShell: +```python +from paperreading import build_literature_matrix, matrix_to_markdown -```powershell -$env:PAPER_READING_WORKBOOK = "D:\research\paper-reading.xlsx" +rows = build_literature_matrix([paper_a, paper_b]) +print(matrix_to_markdown(rows)) ``` -Bash: +The matrix exposes title, journal, research question, identification strategy, key X/Y variables, mechanisms, main finding, and evidence coverage. -```bash -export PAPER_READING_WORKBOOK="/data/research/paper-reading.xlsx" -``` +### 4. Safe Excel literature-review workflow -## Usage +The existing deterministic writer can append validated 13-field results to an existing workbook while preserving values, formulas, formatting, filters, tables, and workbook structure. It detects duplicates, validates a temporary save, creates a backup, and atomically replaces the source file. -Generate a draft without writing to a workbook: +## Project structure ```text -Use $papers-reading-skill to read this paper and produce the 13 structured fields, but do not write to a workbook. +paperreading/ +├── paperreading/ # Reusable research-intelligence core +│ ├── models.py # Paper, method, finding, evidence models +│ ├── evidence.py # Evidence labels and coverage metrics +│ └── matrix.py # Cross-paper literature matrix +├── schemas/paper.schema.json # Portable paper-record contract +├── skills/papers-reading-skill/ # Installable Codex skill +├── examples/ # Structured examples +├── docs/ # Architecture and methodology +├── tests/ # Core + workbook tests +├── ROADMAP.md +├── CHANGELOG.md +└── CITATION.cff ``` -Append a validated result to the configured workbook: +## Quick start -```text -Use $papers-reading-skill to read this paper; after validating all fields, append it to the Chinese worksheet. +### Use the Codex skill + +```bash +git clone https://github.com/AOROM/paperreading.git +cd paperreading +python -m pip install -r requirements.txt ``` -Call the deterministic write script directly: +Copy `skills/papers-reading-skill/` into your Codex skills directory, start a new Codex session, then invoke `$papers-reading-skill` or ask naturally for a structured paper review. -```bash -python skills/papers-reading-skill/scripts/append_paper_reading.py \ - --workbook "/path/to/paper-reading.xlsx" \ - --sheet 中文 \ - --data-json examples/paper-reading.example.json +### Use the Python core + +The current core uses only the Python standard library: + +```python +from paperreading import PaperRecord, EmpiricalDesign + +paper = PaperRecord( + title="Digital finance and firm innovation", + authors=["Author A", "Author B"], + research_questions=["Does digital finance affect firm innovation?"], + empirical_design=EmpiricalDesign( + explanatory_variables=["Digital finance"], + outcome_variables=["Innovation"], + fixed_effects=["Firm", "Year"], + identification="Two-way fixed effects", + ), +) + +paper.validate() ``` -Use `--sheet 中文` for a Chinese paper or `--sheet 英文` for an English paper. The script returns a JSON status such as `paper_appended`, `duplicate_skipped`, `schema_updated`, or `error`. If validation fails, the original workbook remains unchanged. +See [`examples/paper-record.example.json`](examples/paper-record.example.json) for the portable JSON representation. + +## Design principles + +- **Evidence before fluency:** important claims should be traceable to the source. +- **Causal discipline:** correlation is not described as causality without an identification design that supports it. +- **Structured but portable:** Excel is an export target, not the canonical data model. +- **Research-oriented extensions:** follow-up ideas should specify an implementable identification strategy, sample, variable construction, mechanism test, outcome, or falsification test. +- **No silent invention:** unknown metadata, rankings, methods, or evidence remain unknown. -## Field and journal-ranking boundaries +## Roadmap -See [`reading-fields.md`](skills/papers-reading-skill/references/reading-fields.md) for the field definitions. Record only journal-ranking labels confirmed by a reliable source, preserve the source system's original wording, and do not infer or translate classifications across ranking systems. For evaluation, promotion, research reporting, or submission decisions, verify the applicable system, version, and effective date. +The next milestones are tracked in [`ROADMAP.md`](ROADMAP.md): -## Development and validation +- evidence extraction and evidence-map rendering; +- batch paper ingestion and richer literature matrices; +- research-gap synthesis across papers; +- Markdown / BibTeX / Zotero exporters; +- benchmark datasets and hallucination/evidence metrics; +- optional CLI, agent adapters, and web demo. + +## Development ```bash python -m pip install -r requirements-dev.txt @@ -108,10 +153,12 @@ python tools/validate_skill.py skills/papers-reading-skill python -m unittest discover -s tests -v ``` -GitHub Actions validates the skill metadata on every push and pull request and runs end-to-end tests for workbook updates, duplicate detection, environment-variable configuration, and failure-safe source preservation. +See [CONTRIBUTING.md](CONTRIBUTING.md) before submitting a change. Feature proposals are welcome through the GitHub issue templates. + +## Citation -See [CONTRIBUTING.md](CONTRIBUTING.md) before submitting a change. +If PaperReading supports your research workflow, see [`CITATION.cff`](CITATION.cff) for citation metadata. ## License -This repository currently has no open-source license. Public visibility does not automatically grant permission to copy, modify, or distribute its contents. +MIT License. See [LICENSE](LICENSE). diff --git a/README.zh-CN.md b/README.zh-CN.md index a24af69..b21f396 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,104 +1,149 @@ -# Paper Reading Skill +# PaperReading [English](README.md) | **简体中文** [![CI](https://github.com/AOROM/paperreading/actions/workflows/ci.yml/badge.svg)](https://github.com/AOROM/paperreading/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) -面向金融、经济、管理与社会科学论文的 Codex skill。它把论文整理为 13 个可复核字段,区分论文主张、经验证据与研究者判断,提出可执行的后续研究设计,并可安全写入既有 Excel 文献研读表。 +> **把论文变成可检验、可比较、可延伸的研究知识。** -## 核心能力 +PaperReading 是面向**金融、经济、管理、会计与实证社会科学**的 evidence-grounded AI 论文研读工作流。它不止回答“论文讲了什么”,而是围绕研究问题、理论逻辑、识别策略、变量、证据、作用机制、稳健性、研究局限与可执行延伸设计建立结构化记录。 -- 按固定顺序提取题名、作者、期刊、等级、时间、关键词、研究问题、结论、研究逻辑、实证模型、数据与变量以及延伸设计。 -- 对基准结果、作用机制、异质性、经济后果、内生性与稳健性检验进行分层表达。 -- 避免把相关关系误写为因果关系,不补造缺失的变量、模型、数据来源或期刊等级。 -- 在兼容的 12 列工作簿中安全补充第 13 列,并保留原有内容、样式、公式、筛选与表格结构。 -- 写入前查重;写入时先保存临时文件并验证,再备份和原子替换原工作簿。 +项目保留现有可安装的 Codex Skill 和安全 Excel 写入能力,同时开始抽离可复用的 Python 核心,用于可审计 Paper Record、Evidence Map、跨论文比较与后续文献综合。 -## 项目结构 +## 为什么是 PaperReading? + +多数论文阅读工具优化的是“总结内容”;PaperReading 更关注“为什么这个结论可信,以及下一步还能如何研究”。 ```text -paperreading/ -├── skills/papers-reading-skill/ # 可直接安装的 skill -│ ├── SKILL.md -│ ├── agents/openai.yaml -│ ├── references/ -│ └── scripts/append_paper_reading.py -├── examples/ # 示例输入 -├── tests/ # 端到端与结构测试 -├── tools/ # 仓库级校验工具 -└── .github/workflows/ci.yml # 自动校验 +论文 / PDF + │ + ├── Structured Reading ── 13 字段研读体系 + ├── Evidence Map ──────── 页码 / 章节 / 表格 / 图形证据定位 + ├── Method Audit ──────── 识别 / 内生性 / 稳健性 + ├── Literature Matrix ─── 多论文横向比较 + └── Research Extensions ─ 可执行延伸研究设计 + │ + └── Excel / JSON / Markdown / 后续集成 ``` -仓库层文档、测试与 CI 不会进入 skill 的运行上下文;真正需要安装的是 `skills/papers-reading-skill/`。 +## 当前能力 -## 安装 +### 1. Evidence-grounded 13 字段论文研读 -1. 克隆仓库并安装脚本依赖: +现有 Codex Skill 可以按固定结构整理题名、作者、期刊、等级、时间、关键词、研究问题、研究结论、研究逻辑、实证模型、数据与变量以及延伸研究设计。 - ```bash - git clone https://github.com/AOROM/paperreading.git - cd paperreading - python -m pip install -r requirements.txt - ``` +它会明确区分基准结果、作用机制、异质性、经济后果、内生性处理与稳健性检验,并避免补造缺失变量、模型、期刊等级或不受识别策略支持的因果表述。 -2. 将 skill 目录复制到 Codex skills 目录。Windows PowerShell 示例: +### 2. 可审计 Paper Record - ```powershell - Copy-Item -Recurse -Force ` - .\skills\papers-reading-skill ` - "$env:USERPROFILE\.codex\skills\papers-reading-skill" - ``` +新增 `paperreading` Python 包,为论文元数据、实证设计、研究结论与证据定位提供可复用的数据模型。 -3. 重新打开 Codex 会话,并通过 `$papers-reading-skill` 显式调用,或使用与论文研读、13 字段整理、文献表写入相关的自然语言请求触发。 +```python +from paperreading import EvidenceRef, Finding, PaperRecord -## 配置工作簿 +paper = PaperRecord( + title="示例论文", + research_questions=["X 是否影响 Y?"], + findings=[ + Finding( + text="X 与 Y 显著正相关。", + category="baseline", + evidence=[EvidenceRef(page=12, table="表3", section="4.2")], + ) + ], +) +``` -公开版本不包含任何个人工作簿路径。写入脚本按以下优先级解析目标文件: +### 3. Literature Matrix -1. 命令行 `--workbook `; -2. 环境变量 `PAPER_READING_WORKBOOK`; -3. 两者均不存在时停止写入。 +多个 `PaperRecord` 可以直接生成跨论文比较矩阵,不依赖 pandas: -PowerShell: +```python +from paperreading import build_literature_matrix, matrix_to_markdown -```powershell -$env:PAPER_READING_WORKBOOK = "D:\research\paper-reading.xlsx" +rows = build_literature_matrix([paper_a, paper_b]) +print(matrix_to_markdown(rows)) ``` -Bash: +矩阵会展示论文、期刊、研究问题、识别策略、核心 X/Y、作用机制、主要结论以及证据覆盖率。 -```bash -export PAPER_READING_WORKBOOK="/data/research/paper-reading.xlsx" -``` +### 4. 安全 Excel 文献研读工作流 -## 使用方式 +原有确定性写入脚本继续保留:在已有工作簿中追加 13 字段记录,同时保留原始值、公式、样式、筛选、Excel Table 与工作簿结构;写入前查重,临时保存后重新验证,创建备份,再原子替换源文件。 -仅生成草稿: +## 项目结构 ```text -使用 $papers-reading-skill 研读这篇论文,生成 13 个结构化字段,但不要写入工作簿。 +paperreading/ +├── paperreading/ # 可复用 Research Intelligence 核心 +│ ├── models.py # Paper / Method / Finding / Evidence 模型 +│ ├── evidence.py # Evidence 标签与覆盖率 +│ └── matrix.py # 跨论文 Literature Matrix +├── schemas/paper.schema.json # Paper Record 可移植契约 +├── skills/papers-reading-skill/ # 可安装 Codex Skill +├── examples/ # 结构化示例 +├── docs/ # 架构与方法文档 +├── tests/ # Core + Excel 测试 +├── ROADMAP.md +├── CHANGELOG.md +└── CITATION.cff ``` -写入已配置的工作簿: +## 快速开始 -```text -使用 $papers-reading-skill 研读这篇论文;核验字段完整后,写入中文工作表。 +### 使用 Codex Skill + +```bash +git clone https://github.com/AOROM/paperreading.git +cd paperreading +python -m pip install -r requirements.txt ``` -直接调用确定性写入脚本: +将 `skills/papers-reading-skill/` 复制到 Codex skills 目录,重新打开 Codex 会话,然后调用 `$papers-reading-skill`,或直接用自然语言要求进行结构化论文研读。 -```bash -python skills/papers-reading-skill/scripts/append_paper_reading.py \ - --workbook "/path/to/paper-reading.xlsx" \ - --sheet 中文 \ - --data-json examples/paper-reading.example.json +### 使用 Python Core + +当前核心只依赖 Python 标准库: + +```python +from paperreading import PaperRecord, EmpiricalDesign + +paper = PaperRecord( + title="Digital finance and firm innovation", + authors=["Author A", "Author B"], + research_questions=["Does digital finance affect firm innovation?"], + empirical_design=EmpiricalDesign( + explanatory_variables=["Digital finance"], + outcome_variables=["Innovation"], + fixed_effects=["Firm", "Year"], + identification="Two-way fixed effects", + ), +) + +paper.validate() ``` -中文论文使用 `--sheet 中文`,英文论文使用 `--sheet 英文`。脚本输出 JSON 状态,例如 `paper_appended`、`duplicate_skipped`、`schema_updated` 或 `error`。发生校验错误时,原工作簿保持不变。 +可移植 JSON 示例见 [`examples/paper-record.example.json`](examples/paper-record.example.json)。 + +## 设计原则 + +- **Evidence before fluency**:重要结论优先保证可回查,而不是只追求流畅表述。 +- **因果纪律**:没有足够识别设计时,不把相关关系写成因果关系。 +- **结构化但可移植**:Excel 是导出目标,不再作为唯一底层数据模型。 +- **研究导向延伸**:研究建议应尽量包含可实施的识别策略、样本、变量构造、机制检验、结果变量或证伪设计。 +- **不静默补造**:未知的元数据、等级、方法或证据保持未知。 -## 字段与期刊等级边界 +## Roadmap -字段定义见 [`reading-fields.md`](skills/papers-reading-skill/references/reading-fields.md)。期刊等级仅记录经可靠来源确认的原始标签;不同评价体系之间不得推断或换算。涉及当前评价、职称、成果申报或投稿决策时,必须核实适用体系、版本与生效日期。 +下一阶段见 [`ROADMAP.md`](ROADMAP.md): + +- 自动 Evidence 抽取与 Evidence Map; +- Batch Paper Reading 与更丰富的 Literature Matrix; +- 跨论文 Research Gap 综合; +- Markdown / BibTeX / Zotero 导出; +- Benchmark 与幻觉率、证据准确率指标; +- 可选 CLI、Agent Adapter 与 Web Demo。 ## 开发与验证 @@ -108,10 +153,12 @@ python tools/validate_skill.py skills/papers-reading-skill python -m unittest discover -s tests -v ``` -GitHub Actions 会在推送和拉取请求上验证 skill 元数据,并对 Excel 写入、重复检测、环境变量配置和失败不改源文件等行为执行端到端测试。 +提交前请阅读[中文贡献指南](CONTRIBUTING.zh-CN.md)。功能建议可通过 GitHub Issue Template 提交。 + +## 引用 -提交变更前,请阅读[中文贡献指南](CONTRIBUTING.zh-CN.md)。 +如果 PaperReading 对你的研究工作有帮助,可使用 [`CITATION.cff`](CITATION.cff) 中的引用信息。 ## 许可 -本仓库目前未附加开源许可证。公开可见不等于自动授予复制、修改或分发权利。 +MIT License,见 [LICENSE](LICENSE)。 diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..3170f17 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,75 @@ +# PaperReading Roadmap + +PaperReading is evolving from a single Codex paper-reading skill into an evidence-grounded research workflow for empirical social science. The roadmap intentionally keeps the existing skill and Excel workflow stable while moving reusable logic into a portable core. + +## v0.2 — Research-intelligence foundation + +Status: **in progress** + +- [x] Reposition the repository around evidence-grounded empirical research. +- [x] Introduce portable `PaperRecord`, `EmpiricalDesign`, `Finding`, and `EvidenceRef` models. +- [x] Add a JSON Schema for interoperable paper records. +- [x] Add evidence labels and evidence-coverage metrics. +- [x] Add a dependency-free Literature Matrix builder. +- [x] Keep the current Codex skill and safe Excel append workflow compatible. +- [x] Add MIT license, citation metadata, changelog, architecture documentation, and feature-request template. +- [ ] Add representative public-domain / redistributable example outputs from finance, economics, and management. +- [ ] Add a short visual demo for the README. + +## v0.3 — Evidence Map and method audit + +- [ ] Normalize page, section, table, and figure anchors from model output. +- [ ] Render claim-to-evidence maps for each major finding. +- [ ] Add explicit evidence status: direct, inferred, missing, conflicting. +- [ ] Add method-audit adapters for panel FE, DID, IV, RDD, PSM, mediation, and common robustness designs. +- [ ] Add warnings for causal language that is stronger than the reported identification strategy. +- [ ] Export evidence maps to Markdown and JSON. + +## v0.4 — Batch reading and synthesis + +- [ ] Batch ingest a directory of structured paper records. +- [ ] Produce configurable Literature Matrices. +- [ ] Detect consensus, conflicting evidence, recurring mechanisms, common datasets, and repeated identification choices. +- [ ] Generate research-gap candidates grounded in the compared papers. +- [ ] Require every proposed gap to reference the papers and evidence that motivate it. + +## v0.5 — Research workflow integrations + +- [ ] Markdown exporter. +- [ ] BibTeX metadata bridge. +- [ ] Zotero-compatible export/import workflow. +- [ ] Obsidian-oriented Markdown template. +- [ ] Agent adapters beyond the existing Codex skill where stable integration contracts exist. +- [ ] Optional CLI for validate / matrix / export workflows. + +## v0.6 — Benchmark and quality metrics + +- [ ] Publish a redistributable PaperReading benchmark set. +- [ ] Measure metadata accuracy, variable accuracy, method accuracy, evidence-anchor accuracy, field completeness, and hallucination rate. +- [ ] Add regression tests against gold structured records. +- [ ] Publish benchmark methodology and limitations. + +## v1.0 — Stable research workflow + +Target criteria: + +- stable paper-record schema with migration policy; +- auditable evidence model; +- batch comparison and synthesis; +- at least three durable export targets; +- benchmarked extraction quality; +- contributor documentation and release discipline; +- no dependence on a single agent client for the core data model. + +## Contribution priorities + +Good first contributions include: + +1. adding sanitized example `PaperRecord` files; +2. adding matrix columns without introducing mandatory dependencies; +3. improving schema validation error messages; +4. documenting discipline-specific empirical methods; +5. adding tests for evidence edge cases; +6. proposing exporters behind small, stable interfaces. + +Please open a feature request before large architectural changes so the data contract remains coherent. diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..2c20757 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,87 @@ +# Architecture + +## Product boundary + +PaperReading separates the **canonical research record** from the **agent that extracts it** and the **destination that stores it**. + +```text + INPUTS + PDF / DOI / structured text + │ + ▼ + AGENT ADAPTERS + Codex skill / future adapters + │ + ▼ + CORE RECORD + PaperRecord + EvidenceRef + │ + ┌───────────┼───────────┐ + ▼ ▼ ▼ + Evidence Method Literature + Map Audit Matrix + │ │ │ + └───────────┼───────────┘ + ▼ + EXPORTS + Excel / JSON / Markdown / future +``` + +The existing Codex skill is an adapter that produces the 13-field review and can invoke the deterministic Excel writer. The `paperreading` package is deliberately agent-neutral. + +## Canonical data model + +The canonical representation is `PaperRecord`, mirrored by `schemas/paper.schema.json`. + +Core entities: + +- `PaperRecord`: metadata, research questions, research logic, mechanisms, limitations, empirical design, findings, and extension ideas. +- `EmpiricalDesign`: X/Y variables, controls, fixed effects, model type, identification strategy, endogeneity treatment, and robustness checks. +- `Finding`: one baseline/mechanism/heterogeneity/economic-consequence result plus its evidence anchors. +- `EvidenceRef`: source location such as page, section, table, figure, and a short non-verbatim note. + +Excel's 13 fields remain a supported **view/export contract**, not the only internal representation. + +## Evidence model + +Evidence is attached at the finding level. A finding can have zero or more `EvidenceRef` objects. + +An evidence anchor should prefer structural references over copied prose: + +```json +{ + "page": 12, + "section": "4.2 Baseline results", + "table": "Table 3", + "figure": null, + "note": "Main coefficient reported in column (4)." +} +``` + +`evidence_coverage()` measures how many findings have at least one source anchor. It is a completeness indicator, not a truth or quality score. + +## Literature Matrix + +`build_literature_matrix()` intentionally returns plain dictionaries instead of a dataframe. This keeps the core dependency-free and lets callers choose pandas, Excel, HTML, or another presentation layer. + +The initial matrix focuses on: + +- title and journal; +- first research question; +- identification strategy; +- key explanatory and outcome variables; +- mechanisms; +- main finding; +- evidence coverage. + +Future releases can add configurable columns without coupling the canonical model to a specific table library. + +## Compatibility strategy + +During v0.x: + +1. Existing Codex Skill behavior should remain backward compatible unless a change is explicitly documented. +2. Existing workbook-writing safety guarantees must not regress. +3. New core fields should be additive when possible. +4. Breaking JSON-schema changes require a migration note in `CHANGELOG.md`. +5. Agent-specific prompts must not become dependencies of the core Python package. diff --git a/examples/paper-record.example.json b/examples/paper-record.example.json new file mode 100644 index 0000000..2f2d08e --- /dev/null +++ b/examples/paper-record.example.json @@ -0,0 +1,42 @@ +{ + "title": "Digital finance and firm innovation", + "authors": ["Author A", "Author B"], + "journal": "Example Journal", + "journal_rankings": [], + "publication_date": "2025", + "doi": null, + "keywords": ["digital finance", "firm innovation", "financing constraints"], + "research_questions": ["Does digital finance affect firm innovation?"], + "research_logic": "Digital financial development may reduce financing frictions and improve firms' capacity to invest in innovation.", + "empirical_design": { + "explanatory_variables": ["Digital finance index"], + "outcome_variables": ["Patent applications"], + "controls": ["Firm size", "Leverage"], + "fixed_effects": ["Firm", "Year"], + "model_type": "Panel regression", + "identification": "Two-way fixed effects", + "endogeneity": ["Alternative specification / instrument if supported by the source"], + "robustness": ["Alternative innovation measure"] + }, + "findings": [ + { + "text": "Digital finance is positively associated with firm innovation in the baseline specification.", + "category": "baseline", + "coefficient": null, + "significance": null, + "evidence": [ + { + "page": 12, + "section": "4.2 Baseline results", + "table": "Table 3", + "figure": null, + "note": "Illustrative sanitized example; not a claim about a real paper." + } + ] + } + ], + "mechanisms": ["Financing constraints"], + "data_sources": ["Illustrative firm-level panel data"], + "limitations": ["Illustrative example only"], + "extensions": ["Use an externally timed policy shock and a DID design to strengthen causal identification."] +} diff --git a/paperreading/__init__.py b/paperreading/__init__.py new file mode 100644 index 0000000..32867b0 --- /dev/null +++ b/paperreading/__init__.py @@ -0,0 +1,16 @@ +"""Portable research-intelligence primitives for PaperReading.""" + +from .evidence import evidence_coverage, evidence_label +from .matrix import build_literature_matrix, matrix_to_markdown +from .models import EmpiricalDesign, EvidenceRef, Finding, PaperRecord + +__all__ = [ + "EmpiricalDesign", + "EvidenceRef", + "Finding", + "PaperRecord", + "build_literature_matrix", + "evidence_coverage", + "evidence_label", + "matrix_to_markdown", +] diff --git a/paperreading/evidence.py b/paperreading/evidence.py new file mode 100644 index 0000000..534c991 --- /dev/null +++ b/paperreading/evidence.py @@ -0,0 +1,33 @@ +"""Helpers for rendering and measuring source evidence.""" + +from __future__ import annotations + +from .models import EvidenceRef, PaperRecord + + +def evidence_label(ref: EvidenceRef) -> str: + """Render a compact human-readable evidence anchor.""" + + ref.validate() + parts: list[str] = [] + if ref.page is not None: + parts.append(f"p. {ref.page}") + if ref.section: + parts.append(ref.section) + if ref.table: + parts.append(ref.table) + if ref.figure: + parts.append(ref.figure) + if ref.note: + parts.append(ref.note) + return " · ".join(parts) + + +def evidence_coverage(record: PaperRecord) -> float: + """Return the share of findings that contain at least one evidence anchor.""" + + record.validate() + if not record.findings: + return 0.0 + grounded = sum(1 for finding in record.findings if finding.evidence) + return grounded / len(record.findings) diff --git a/paperreading/matrix.py b/paperreading/matrix.py new file mode 100644 index 0000000..788d287 --- /dev/null +++ b/paperreading/matrix.py @@ -0,0 +1,68 @@ +"""Cross-paper comparison utilities.""" + +from __future__ import annotations + +from collections.abc import Iterable + +from .evidence import evidence_coverage +from .models import PaperRecord + + +MATRIX_COLUMNS = [ + "Title", + "Journal", + "Research question", + "Identification", + "X", + "Y", + "Mechanisms", + "Main finding", + "Evidence coverage", +] + + +def _join(values: list[str]) -> str: + return "; ".join(value for value in values if value) + + +def build_literature_matrix(records: Iterable[PaperRecord]) -> list[dict[str, str]]: + """Convert paper records into dependency-free comparison rows.""" + + rows: list[dict[str, str]] = [] + for record in records: + record.validate() + design = record.empirical_design + main_finding = record.findings[0].text if record.findings else "" + first_question = record.research_questions[0] if record.research_questions else "" + rows.append( + { + "Title": record.title, + "Journal": record.journal or "", + "Research question": first_question, + "Identification": design.identification or design.model_type or "", + "X": _join(design.explanatory_variables), + "Y": _join(design.outcome_variables), + "Mechanisms": _join(record.mechanisms), + "Main finding": main_finding, + "Evidence coverage": f"{evidence_coverage(record):.0%}", + } + ) + return rows + + +def matrix_to_markdown(rows: list[dict[str, str]]) -> str: + """Render Literature Matrix rows as a GitHub-compatible Markdown table.""" + + if not rows: + return "" + + def clean(value: str) -> str: + return str(value).replace("|", "\\|").replace("\n", " ") + + header = "| " + " | ".join(MATRIX_COLUMNS) + " |" + separator = "| " + " | ".join("---" for _ in MATRIX_COLUMNS) + " |" + body = [ + "| " + " | ".join(clean(row.get(column, "")) for column in MATRIX_COLUMNS) + " |" + for row in rows + ] + return "\n".join([header, separator, *body]) diff --git a/paperreading/models.py b/paperreading/models.py new file mode 100644 index 0000000..b6bcd04 --- /dev/null +++ b/paperreading/models.py @@ -0,0 +1,121 @@ +"""Canonical, agent-neutral data models used by PaperReading.""" + +from __future__ import annotations + +from dataclasses import asdict, dataclass, field +from typing import Any + + +@dataclass +class EvidenceRef: + """A structural source anchor for one research claim.""" + + page: int | None = None + section: str | None = None + table: str | None = None + figure: str | None = None + note: str | None = None + + def validate(self) -> None: + if self.page is not None and self.page < 1: + raise ValueError("evidence page must be a positive integer") + if not any((self.page, self.section, self.table, self.figure, self.note)): + raise ValueError("evidence reference must contain at least one anchor") + + +@dataclass +class Finding: + """A reported result and the source anchors that support it.""" + + text: str + category: str = "baseline" + coefficient: str | None = None + significance: str | None = None + evidence: list[EvidenceRef] = field(default_factory=list) + + def validate(self) -> None: + if not self.text.strip(): + raise ValueError("finding text cannot be empty") + for ref in self.evidence: + ref.validate() + + +@dataclass +class EmpiricalDesign: + """Compact representation of an empirical identification design.""" + + explanatory_variables: list[str] = field(default_factory=list) + outcome_variables: list[str] = field(default_factory=list) + controls: list[str] = field(default_factory=list) + fixed_effects: list[str] = field(default_factory=list) + model_type: str | None = None + identification: str | None = None + endogeneity: list[str] = field(default_factory=list) + robustness: list[str] = field(default_factory=list) + + +@dataclass +class PaperRecord: + """Canonical structured record for one academic paper.""" + + title: str + authors: list[str] = field(default_factory=list) + journal: str | None = None + journal_rankings: list[str] = field(default_factory=list) + publication_date: str | None = None + doi: str | None = None + keywords: list[str] = field(default_factory=list) + research_questions: list[str] = field(default_factory=list) + research_logic: str | None = None + empirical_design: EmpiricalDesign = field(default_factory=EmpiricalDesign) + findings: list[Finding] = field(default_factory=list) + mechanisms: list[str] = field(default_factory=list) + data_sources: list[str] = field(default_factory=list) + limitations: list[str] = field(default_factory=list) + extensions: list[str] = field(default_factory=list) + + def validate(self) -> None: + if not self.title.strip(): + raise ValueError("paper title cannot be empty") + if any(not question.strip() for question in self.research_questions): + raise ValueError("research questions cannot contain empty values") + for finding in self.findings: + finding.validate() + + def to_dict(self) -> dict[str, Any]: + self.validate() + return asdict(self) + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> "PaperRecord": + design_data = data.get("empirical_design") or {} + findings_data = data.get("findings") or [] + findings = [] + for item in findings_data: + evidence = [EvidenceRef(**ref) for ref in item.get("evidence", [])] + finding_data = {key: value for key, value in item.items() if key != "evidence"} + findings.append(Finding(evidence=evidence, **finding_data)) + + known = { + "title", + "authors", + "journal", + "journal_rankings", + "publication_date", + "doi", + "keywords", + "research_questions", + "research_logic", + "mechanisms", + "data_sources", + "limitations", + "extensions", + } + kwargs = {key: data[key] for key in known if key in data} + record = cls( + **kwargs, + empirical_design=EmpiricalDesign(**design_data), + findings=findings, + ) + record.validate() + return record diff --git a/schemas/paper.schema.json b/schemas/paper.schema.json new file mode 100644 index 0000000..e069476 --- /dev/null +++ b/schemas/paper.schema.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/AOROM/paperreading/schemas/paper.schema.json", + "title": "PaperReading PaperRecord", + "type": "object", + "required": ["title"], + "additionalProperties": false, + "properties": { + "title": {"type": "string", "minLength": 1}, + "authors": {"type": "array", "items": {"type": "string"}, "default": []}, + "journal": {"type": ["string", "null"]}, + "journal_rankings": {"type": "array", "items": {"type": "string"}, "default": []}, + "publication_date": {"type": ["string", "null"]}, + "doi": {"type": ["string", "null"]}, + "keywords": {"type": "array", "items": {"type": "string"}, "default": []}, + "research_questions": {"type": "array", "items": {"type": "string", "minLength": 1}, "default": []}, + "research_logic": {"type": ["string", "null"]}, + "empirical_design": {"$ref": "#/$defs/empiricalDesign"}, + "findings": {"type": "array", "items": {"$ref": "#/$defs/finding"}, "default": []}, + "mechanisms": {"type": "array", "items": {"type": "string"}, "default": []}, + "data_sources": {"type": "array", "items": {"type": "string"}, "default": []}, + "limitations": {"type": "array", "items": {"type": "string"}, "default": []}, + "extensions": {"type": "array", "items": {"type": "string"}, "default": []} + }, + "$defs": { + "evidenceRef": { + "type": "object", + "additionalProperties": false, + "properties": { + "page": {"type": ["integer", "null"], "minimum": 1}, + "section": {"type": ["string", "null"]}, + "table": {"type": ["string", "null"]}, + "figure": {"type": ["string", "null"]}, + "note": {"type": ["string", "null"]} + } + }, + "finding": { + "type": "object", + "required": ["text"], + "additionalProperties": false, + "properties": { + "text": {"type": "string", "minLength": 1}, + "category": {"type": "string", "default": "baseline"}, + "coefficient": {"type": ["string", "null"]}, + "significance": {"type": ["string", "null"]}, + "evidence": {"type": "array", "items": {"$ref": "#/$defs/evidenceRef"}, "default": []} + } + }, + "empiricalDesign": { + "type": "object", + "additionalProperties": false, + "properties": { + "explanatory_variables": {"type": "array", "items": {"type": "string"}, "default": []}, + "outcome_variables": {"type": "array", "items": {"type": "string"}, "default": []}, + "controls": {"type": "array", "items": {"type": "string"}, "default": []}, + "fixed_effects": {"type": "array", "items": {"type": "string"}, "default": []}, + "model_type": {"type": ["string", "null"]}, + "identification": {"type": ["string", "null"]}, + "endogeneity": {"type": "array", "items": {"type": "string"}, "default": []}, + "robustness": {"type": "array", "items": {"type": "string"}, "default": []} + } + } + } +} diff --git a/tests/test_research_core.py b/tests/test_research_core.py new file mode 100644 index 0000000..c913889 --- /dev/null +++ b/tests/test_research_core.py @@ -0,0 +1,99 @@ +import json +import unittest +from pathlib import Path + +from paperreading import ( + EmpiricalDesign, + EvidenceRef, + Finding, + PaperRecord, + build_literature_matrix, + evidence_coverage, + evidence_label, + matrix_to_markdown, +) + + +class PaperRecordTests(unittest.TestCase): + def test_round_trip_from_dict(self): + source = { + "title": "Example", + "research_questions": ["Does X affect Y?"], + "empirical_design": { + "explanatory_variables": ["X"], + "outcome_variables": ["Y"], + "identification": "DID", + }, + "findings": [ + { + "text": "X increases Y.", + "category": "baseline", + "evidence": [{"page": 10, "table": "Table 2"}], + } + ], + } + record = PaperRecord.from_dict(source) + self.assertEqual(record.title, "Example") + self.assertEqual(record.empirical_design.identification, "DID") + self.assertEqual(record.findings[0].evidence[0].page, 10) + self.assertEqual(record.to_dict()["findings"][0]["text"], "X increases Y.") + + def test_invalid_evidence_page_fails(self): + with self.assertRaises(ValueError): + EvidenceRef(page=0).validate() + + def test_empty_evidence_anchor_fails(self): + with self.assertRaises(ValueError): + EvidenceRef().validate() + + +class EvidenceTests(unittest.TestCase): + def test_label_and_coverage(self): + grounded = Finding( + text="Result A", + evidence=[EvidenceRef(page=12, section="4.2", table="Table 3")], + ) + ungrounded = Finding(text="Result B") + record = PaperRecord(title="Example", findings=[grounded, ungrounded]) + self.assertEqual(evidence_label(grounded.evidence[0]), "p. 12 · 4.2 · Table 3") + self.assertEqual(evidence_coverage(record), 0.5) + + +class LiteratureMatrixTests(unittest.TestCase): + def test_matrix_contains_method_variables_and_coverage(self): + record = PaperRecord( + title="Example", + journal="Journal", + research_questions=["Does X affect Y?"], + empirical_design=EmpiricalDesign( + explanatory_variables=["X"], + outcome_variables=["Y"], + identification="DID", + ), + mechanisms=["M"], + findings=[Finding(text="X increases Y", evidence=[EvidenceRef(page=9)])], + ) + rows = build_literature_matrix([record]) + self.assertEqual(rows[0]["Identification"], "DID") + self.assertEqual(rows[0]["X"], "X") + self.assertEqual(rows[0]["Y"], "Y") + self.assertEqual(rows[0]["Evidence coverage"], "100%") + markdown = matrix_to_markdown(rows) + self.assertIn("| Title | Journal |", markdown) + self.assertIn("Example", markdown) + + def test_empty_matrix_is_empty_string(self): + self.assertEqual(matrix_to_markdown([]), "") + + +class SchemaTests(unittest.TestCase): + def test_schema_and_example_are_valid_json(self): + root = Path(__file__).resolve().parents[1] + schema = json.loads((root / "schemas" / "paper.schema.json").read_text(encoding="utf-8")) + example = json.loads((root / "examples" / "paper-record.example.json").read_text(encoding="utf-8")) + self.assertEqual(schema["title"], "PaperReading PaperRecord") + self.assertEqual(example["title"], "Digital finance and firm innovation") + + +if __name__ == "__main__": + unittest.main()