lllin000_PaperForge/CONTRIBUTING.md
Research Assistant 2096039e03 docs(DX-04): create CONTRIBUTING.md with dev setup and conventions
- Development setup instructions (pip install -e .[test])
- Pre-commit hooks setup and hook descriptions
- Test workflow with common pytest invocations
- Architecture overview (two-layer design, leaf module rule)
- Code conventions (10 rules: logging, imports, commit format, etc.)
- Pull request process and getting help section
2026-04-27 17:59:18 +08:00

7.2 KiB

Contributing to PaperForge Lite

Thank you for your interest in contributing to PaperForge Lite! This document provides setup instructions, workflow guidelines, and code conventions to help you get started.


Development Setup

# Clone the repository
git clone https://github.com/LLLin000/PaperForge.git
cd PaperForge

# Editable install with test dependencies
pip install -e ".[test]"

# Verify installation
python -m paperforge --version

Requirements

  • Python 3.10+
  • Zotero + Better BibTeX plugin (for end-to-end testing)
  • Obsidian (for Base view generation)
  • PaddleOCR API Key (for OCR pipeline — configure in .env)

Pre-commit Hooks

Before committing, install the pre-commit hooks to ensure code quality:

pip install pre-commit
pre-commit install

Hooks are configured in .pre-commit-config.yaml and include:

  • Ruff lint (ruff check --fix) — catches common errors and style issues
  • Ruff format (ruff format) — enforces consistent code formatting
  • check-yaml — validates YAML file syntax
  • check-toml — validates TOML file syntax
  • end-of-file-fixer — ensures files end with a single newline
  • trailing-whitespace-fixer — removes trailing whitespace
  • Consistency audit (scripts/consistency_audit.py) — detects duplicate utility functions across modules

Note: Pre-commit hooks run automatically on git commit. Do not bypass them. If a hook fails, fix the issue and re-commit. The Ruff configuration in pyproject.toml suppresses E501 (line-too-long) and pre-existing simplifications via per-file-ignores — these are not blockers.


Test Workflow

# Run all tests, stop on first failure
pytest tests/ -x

# Verbose output
pytest tests/ -v

# Filter by keyword (e.g., OCR-related tests)
pytest tests/ -k "ocr"

# Run with coverage report
pytest tests/ --cov

# Collect tests only (no execution) — useful for import validation
pytest tests/ --collect-only

Test Requirements

  • All tests must pass before merging. The current baseline is 203+ tests, 0 failures, 0 errors (2 pre-existing skips for PDF-dependent tests).
  • Lint must pass: ruff check . && ruff format --check .
  • Do not introduce new test failures or lint violations.
  • Tests must not make live API calls (PaddleOCR, etc.). Use sandbox fixtures in tests/sandbox/.

Test Structure

Tests are in tests/ with a shared conftest.py providing fixtures. The tests/sandbox/ directory contains generated deterministic fixtures for OCR, Zotero exports, and vault layouts. Fixture generation scripts are in tests/sandbox/generate_*.py — run these only when fixtures need updating.


Architecture Overview

PaperForge Lite uses a two-layer design:

Worker Layer (automated, deterministic, CLI-triggered)
    paperforge/worker/
    ├── _utils.py        — Leaf module: shared utilities (read_json, write_json, etc.)
    ├── sync.py          — Zotero sync (selection-sync, index-refresh)
    ├── ocr.py           — OCR pipeline (upload, poll, postprocess)
    ├── repair.py        — State and path repair
    ├── status.py        — Doctor and status commands
    ├── deep_reading.py  — Deep-reading queue management
    ├── base_views.py    — Obsidian Base view generation
    ├── update.py        — Auto-update system
    ├── _progress.py     — Progress bar utilities
    └── _retry.py        — Retry with backoff utilities

Agent Layer (interactive, reasoning-driven, user-triggered)
    paperforge/skills/literature-qa/
    ├── scripts/ld_deep.py      — /pf-deep implementation
    ├── prompt_deep_subagent.md  — Agent prompt for deep reading
    └── chart-reading/           — 14 chart-type review guides

Key Architecture Rules

  1. _utils.py is a leaf module — imports only from stdlib and paperforge/config.py. Must never import from paperforge.worker.* or paperforge.commands.*. This prevents circular dependencies.
  2. Worker modules do not import each other directly — use _sync.run_selection_sync(vault) (module-reference pattern) in ocr.py to break the sync↔ocr cycle.
  3. Config flows one way: paperforge/config.py_utils.py → worker modules. No reverse imports.
  4. Re-exports preserve backward compatibility: Moved functions retain # Re-exported from _utils.py comments in original modules.

Key Files

File Purpose
paperforge/config.py Path resolution and config loading
paperforge/cli.py CLI entry point and command routing
paperforge/__main__.py python -m paperforge entry point
paperforge.json User-facing configuration (paths, update settings, feature flags)
setup_wizard.py Interactive first-time setup
scripts/consistency_audit.py Duplicate utility function detection

Code Conventions

  1. No new print() calls in worker modules — use logger = logging.getLogger(__name__) with logger.info(), logger.debug(), etc. print() is reserved for user-facing stdout output in CLI commands (paperforge/commands/).

  2. Import shared utilities from _utils.py — do not copy-paste read_json, write_json, load_journal_db, etc. into new modules. If you need a utility, add it to _utils.py first.

  3. _utils.py is a leaf module — must never import from paperforge.worker.* or paperforge.commands.*. Violations cause circular import errors.

  4. Requirement IDs in commit messages — link commits to requirements using the format: feat(UX-01): add auto_analyze_after_ocr. Requirement IDs are tracked in REQUIREMENTS.md and .planning/.

  5. Pre-commit hooks run on git commit — do not bypass them with --no-verify. Fix hook failures rather than skipping them.

  6. Forward slashes in paths — use Path.as_posix() for all path-to-string conversions. This ensures consistent wikilinks regardless of OS.

  7. Structured logging — use logging.getLogger(__name__) at module level. Log levels: DEBUG for detailed diagnostics, INFO for normal operations, WARNING for recoverable issues, ERROR for failures.

  8. No live API calls in tests — all tests must use deterministic sandbox fixtures. Mock external services where necessary.

  9. Type hints — use from __future__ import annotations at the top of new modules for PEP 604-style type hints.

  10. Backward compatibility — API breaks are unacceptable within a major version. Use function-level imports and re-exports when refactoring.


Pull Request Process

  1. Ensure all tests pass and lint is clean.
  2. Update CHANGELOG.md under [Unreleased] with the changes.
  3. Update documentation (AGENTS.md, command docs) if user-facing behavior changes.
  4. Create a pull request with a clear description of changes and motivation.
  5. Reference requirement IDs where applicable.

Getting Help


Thank you for contributing to PaperForge Lite — Building a better literature workflow, underground!