diff --git a/.docs/PUBLISHING.md b/.docs/PUBLISHING.md new file mode 100644 index 0000000..028f4fc --- /dev/null +++ b/.docs/PUBLISHING.md @@ -0,0 +1,114 @@ +# Publishing jupyddl + +**We intend to publish jupyddl as citable, peer-reviewed research software.** +This page says why, where, what is already in place, and what is left. + +## Why + +jupyddl's goal is to be a framework other people build on: a place to +implement a planning algorithm in readable Python, check it against the ones +already here, and *explain* it. You can watch a search run, chart it, replay it +in the browser and publish the result. That goal only works if people can find +the project, trust it, and give it credit. A software paper does all three. It +also gives everyone who extends jupyddl something stable to cite. + +## The plan + +| # | Venue | What it gives us | Status | +|---|---|---|---| +| 1 | [Zenodo](https://zenodo.org) | A DOI for **every release**, so a paper can cite the exact code it ran | Needs a one-time maintainer setup ([below](#zenodo-one-time-setup)) | +| 2 | [JOSS](https://joss.theoj.org) — *Journal of Open Source Software* | Peer review of the software itself, held in public on GitHub. Free to publish and free to read; the paper gets a journal DOI | Planned. [Readiness checklist below](#joss-readiness) | +| 3 | ICAPS workshops | Peer review of the *research* results. **PRL** (Planning and Reinforcement Learning) for the learned-heuristic work, **PlanEdu** or the system-demo track for the workbench | After the evaluation protocol in [roadmap §3](roadmap.md#3-a-proper-evaluation-protocol). The current results are single-seed and the notes say so | +| 4 | arXiv | A preprint of the learned-heuristic write-up, citable immediately | Optional, alongside 3 | + +We are not targeting journals that charge to publish (SoftwareX, JORS). JOSS +covers the same ground for free. + +## Citing jupyddl today + +Use **"Cite this repository"** on the GitHub page. It reads +[`CITATION.cff`](../CITATION.cff). The current preferred citation is a 2021 +preprint that describes the *original* project, a thin wrapper around the +Julia `PDDL.jl` parser. When the JOSS paper is accepted, it replaces that +preprint in `CITATION.cff` and in the README's [Cite](../README.md#cite) +section. Each release's Zenodo DOI goes in `CITATION.cff` as an identifier. + +## Zenodo one-time setup + +This needs a maintainer and takes about ten minutes: + +1. Sign in at with the GitHub account that administers + `openplan-labs`. +2. Open **Settings → GitHub** and switch on `openplan-labs/PythonPDDL`. Because + the repository belongs to an organisation, the Zenodo GitHub app may first + need to be granted access to `openplan-labs` under that organisation's + *Third-party access* settings. +3. Cut a release as usual ([RELEASING.md](RELEASING.md)). The `release` + workflow publishes a GitHub Release, and Zenodo archives every published + release and mints a DOI for it. Zenodo takes its metadata from + `CITATION.cff`, so there is nothing else to fill in. +4. Add the *concept* DOI to `CITATION.cff` under `identifiers`, and as a badge + to the README. The concept DOI always resolves to the latest version. + +## JOSS readiness + +JOSS reviews the software against a public checklist. Here is where we stand. +JOSS revised its scope and submission requirements in 2026, so **re-read the +current [submission guide](https://joss.readthedocs.io/en/latest/submitting.html) +and [policies](https://joss.readthedocs.io/en/latest/policies.html) before +submitting**. This list is a working copy, not a substitute. + +| Requirement | Status | +|---|---| +| OSI-approved licence | ✅ Apache-2.0 | +| Public repository, open issue tracker, history in the open | ✅ | +| Substantial scholarly effort | ✅ Parser and grounder covering 20 of 21 PDDL requirement flags, 14 planners, LM-cut and `h^m`, PDDL 3 compiled to the classical core, learned heuristics, search tracing | +| Installation instructions | ✅ README → Install; `pip install jupyddl` | +| Example usage | ✅ README, `demos/`, the browser workbench | +| Automated tests | ✅ CI on Python 3.10–3.14, with and without the optional extras, plus a packaging check on the built wheel | +| Community guidelines | ✅ [`CONTRIBUTING.md`](../.github/CONTRIBUTING.md), [`CODE_OF_CONDUCT.md`](../.github/CODE_OF_CONDUCT.md), [`SECURITY.md`](../.github/SECURITY.md) | +| API documentation | 🟡 Docstrings throughout, but no rendered API reference yet | +| A guide to extending the framework | 🟡 A paragraph in the README's Architecture section; a full guide is in progress | +| Archived release with a DOI | ⏳ Waiting on the Zenodo setup above | +| `paper.md` and `paper.bib` | ⏳ Not written yet. See the outline below | +| Author list, with ORCIDs | ⏳ See [Authorship](#authorship) | +| AI-usage disclosure | ⏳ Required in the paper. See [below](#ai-usage-disclosure) | + +### Paper outline + +JOSS papers are short, roughly 250–1000 words. The outline: + +- **Summary.** A pure-Python PDDL planning framework meant to be read, + extended and taught with: no native dependencies, every search observable, + and the same registries behind the CLI, the benchmark harness and the + browser workbench. +- **Statement of need.** Researchers and students who want to *implement and + explain* a planning algorithm, not only run one. The production planners are + fast, but you have to learn their C++ before you can change anything. The + Python libraries are easy to read but stop at STRIPS, or at parsing. +- **State of the field.** Position jupyddl honestly against Fast Downward, + pyperplan, the Unified Planning Framework, Tarski and the `pddl` parsing + library: what each is for, and where jupyddl overlaps and differs. +- **Design.** Conditions in negation normal form, PDDL 3 compiled away before + grounding, cooperative budgets, zero-overhead observers, and why the core has + no runtime dependencies. +- **Research use.** The learned-heuristic line, including its negative results + and the two published claims that were later corrected. +- **AI usage disclosure** and **Acknowledgements**. + +### AI usage disclosure + +JOSS allows generative AI in software and papers, provided the use is +disclosed and humans keep oversight. Much of the current code was written with +an AI coding assistant. Those commits carry a `Co-Authored-By: Claude` trailer, +so the history records which work was assisted. The paper must state this +plainly. It should say which parts were assisted, and how the results were +checked: the test suite, the observed-equals-unobserved invariant, and +measurements re-taken at render time rather than typed in. + +### Authorship + +The maintainers settle the author list before submission, following JOSS's +authorship guidance. If you have made a substantial contribution, such as a +planner, a heuristic, a compilation or sustained review, and want to be +considered, say so in your pull request or open an issue. diff --git a/.docs/README.md b/.docs/README.md index f175546..39de28f 100644 --- a/.docs/README.md +++ b/.docs/README.md @@ -7,10 +7,10 @@ measurement cache under [`assets/`](assets). These notes are research documents, not user documentation — the user-facing description of `jupyddl learn` is in the README and the module docstrings. -The two files GitHub reads for its own community features, -`CONTRIBUTING.md` and `CODE_OF_CONDUCT.md`, are in `.github/` instead: GitHub -only looks for them in the repository root, `.github/` or `docs/`, and would -not find them here. +The files GitHub reads for its own community features — `CONTRIBUTING.md`, +`CODE_OF_CONDUCT.md`, `SECURITY.md` and the issue and pull-request templates — +are in `.github/` instead: GitHub only looks for them in the repository root, +`.github/` or `docs/`, and would not find them here. | Note | What it covers | |---|---| @@ -18,6 +18,7 @@ not find them here. | [rl-for-search.md](rl-for-search.md) | The reinforcement stage: the MDP that "minimise expansions" corresponds to, why the obvious policy gradient is hard here, and what we do instead | | [roadmap.md](roadmap.md) | What to build next, ordered by expected value, with the experiment that would settle each | | [RELEASING.md](RELEASING.md) | How a release is cut, and the one-time PyPI trusted-publisher setup only a maintainer can do | +| [PUBLISHING.md](PUBLISHING.md) | Our intent to publish jupyddl as citable research software: Zenodo, JOSS, ICAPS workshops, the readiness checklist and authorship | ## The one-paragraph version diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1755e92..1818066 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -57,6 +57,32 @@ New planners and heuristics should cite the paper they implement — name and year — in the docstring. It tells a later reader which variant they are getting. +## Adding an algorithm + +This is what the project is for. jupyddl aims to be the place where a planning +algorithm is implemented readably, compared fairly and *explained*. A new +planner, heuristic, compilation or generator is the most welcome contribution +there is. + +1. Open an issue with the **Propose an algorithm** template first, so the + variant and its guarantees are agreed before you write code. +2. Register it in the matching registry: `jupyddl.search.PLANNERS`, + `jupyddl.heuristics.HEURISTICS` or `jupyddl.generator.GENERATORS`. The CLI, + the benchmark harness and the browser workbench all read from these, so + registering it is all the wiring you need. +3. Test the guarantee, not only that it runs. If you claim optimality, compare + the plan cost against `dijkstra` on small instances. If you claim + admissibility, check `h(s0)` against the optimal cost. +4. Keep the core stdlib-only. Anything that needs a third-party package goes + behind an optional extra, the way `viz` and `learn` do. + +## Credit + +We intend to publish jupyddl as peer-reviewed research software (see +[`.docs/PUBLISHING.md`](../.docs/PUBLISHING.md)). If you make a substantial +contribution and want to be considered for authorship on the paper, say so in +your pull request. + ## Licence This project is licensed under **Apache 2.0** (see [`LICENSE`](../LICENSE)). By diff --git a/.github/ISSUE_TEMPLATE/algorithm.md b/.github/ISSUE_TEMPLATE/algorithm.md new file mode 100644 index 0000000..bb5ed01 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/algorithm.md @@ -0,0 +1,27 @@ +--- +name: Propose an algorithm +about: A planner, heuristic, compilation or generator you would like to see in jupyddl, or want to add yourself +title: '[algorithm] ' +labels: 'feature' +assignees: '' + +--- + +**Which algorithm?** +Name, paper and year, for example *LM-cut — Helmert & Domshlak, ICAPS 2009*. +Link the paper if it is open access. + +**What kind is it?** +Planner (`jupyddl.search.PLANNERS`), heuristic (`jupyddl.heuristics.HEURISTICS`), +PDDL compilation (`jupyddl/compile.py`), instance generator +(`jupyddl.generator.GENERATORS`), or something else. + +**What does it guarantee?** +Optimal, complete, admissible, anytime? Under which assumptions, for example +"admissible only without conditional effects"? + +**Why is it worth having here?** +What does it show or teach that the existing ones do not? + +**Do you want to implement it?** +Yes / no / with help. Read [CONTRIBUTING.md](../CONTRIBUTING.md) first. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..2c63ca7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +## What and why + + + +## How it was checked + + + +## Checklist + +- [ ] `flake8 jupyddl tests tools` and `pytest` pass locally +- [ ] Anything under `jupyddl/` changed → `python tools/build_web.py` was re-run and `web/dist` is committed +- [ ] A new planner or heuristic cites its paper (name and year) in the docstring +- [ ] If this moves a planner in or out of `OPTIMAL_PLANNERS`, or narrows a guarantee, the description says so +- [ ] `CHANGELOG.md` has an entry under **Unreleased** for anything a user would notice diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..e854fb2 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,38 @@ +# Security policy + +## Supported versions + +Fixes go into the latest release on PyPI. Older releases are not patched, so +upgrade before you report. + +## Reporting a vulnerability + +Please **do not open a public issue** for a security problem. + +Report it privately through GitHub instead: on the repository's **Security** +tab, choose **Report a vulnerability**. If that option is missing, open an +issue that only asks for a private contact. Leave out all details of the +problem. + +Include the input that triggers it (domain and problem files, a trace or +model file) and the exact command you ran. We aim to acknowledge a report +within a week. + +## What counts + +jupyddl reads planning files and its own JSON artefacts, so these are in +scope: + +- Code execution, or reading and writing files outside the paths you gave, + from a crafted PDDL file, search trace (`SearchTrace.load`) or learned + heuristic bundle (`learned:`). These formats are plain JSON and text, + and none of them should ever execute anything. +- Script injection in the browser workbench from a crafted domain, problem or + trace. + +These are **not** vulnerabilities: + +- Planning is PSPACE-complete in general. A small PDDL file can ground into an + enormous task or take a very long time to search. Use a budget + (`--time-limit`, `--max-expansions`) when you plan on input you do not + trust. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 62b7e1b..fc5331e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,7 +6,15 @@ name: build # distributions instead and proves the wheel stands on its own — no source # tree, no demos folder, no editable install. -on: [push] +on: + # Pull requests, including ones from forks: `push` alone never fires for a + # contributor's fork, so their PR would sit with no checks at all. Pushes to + # main still run so the badge reflects main. A branch pushed without a PR + # gets no CI; open a draft PR to get it. + pull_request: + push: + branches: [main] + workflow_dispatch: # Nothing here writes to the repository. Said explicitly so it stays true # even if the repository default is loosened again. diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 42a0d7e..0811216 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,6 +1,14 @@ name: tests -on: [push] +on: + # Pull requests, including ones from forks: `push` alone never fires for a + # contributor's fork, so their PR would sit with no checks at all. Pushes to + # main still run so the badge reflects main. A branch pushed without a PR + # gets no CI; open a draft PR to get it. + pull_request: + push: + branches: [main] + workflow_dispatch: # Nothing here writes to the repository. Said explicitly so it stays true # even if the repository default is loosened again. diff --git a/AGENTS.md b/AGENTS.md index d94f625..52053d6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ Julia/`PDDL.jl`/PyCall integration has been removed — there is no Julia, no native build step, and the core has zero runtime dependencies. ### Environment -- Python ≥ 3.9; a `.venv` (created with `uv`, Python 3.12) with an editable +- Python ≥ 3.10; a `.venv` (created with `uv`, Python 3.12) with an editable install: `uv pip install -e ".[dev]"` (add `viz` for the matplotlib charts, animations and benchmark dashboards). `.venv`, `web/vendor/` and `pddl-examples/` contents are git-ignored. @@ -27,7 +27,7 @@ native build step, and the core has zero runtime dependencies. ### What CI actually checks - **`tests`** — lint (`flake8 jupyddl tests tools`) and the suite on Python - 3.9–3.14. Most of the matrix installs `.[dev]` *without* matplotlib, which is + 3.10–3.14. Most of the matrix installs `.[dev]` *without* matplotlib, which is what nearly everyone installs and keeps the core honest about not importing it; one entry installs `.[dev,viz]` so `jupyddl/viz/` is executed rather than skipped. `tests/test_viz.py` and `tests/test_cli_viz.py` `importorskip` @@ -51,8 +51,12 @@ native build step, and the core has zero runtime dependencies. **Bump the version in two places** — `pyproject.toml` and `jupyddl/__init__.py` — and rebuild `web/dist`, which carries it too. - **`pages`** — bundles, refuses to deploy a stale `web/dist`, then deploys. - Its job is called `bundle`, not `build`, because `.mergify.yml` keys a merge - rule on a check named `build` and that has to mean the packaging workflow. + Its job is called `bundle`, not `build`: a check named `build` has to mean + the packaging workflow, and two checks with one name is a reliable way to gate + a merge on the wrong one. (Mergify used to key a rule on it; it is retired.) +- **Triggers.** `tests` and `build` run on pull requests, so a contributor's + fork gets CI, and on pushes to `main`. A branch pushed without a PR gets no + CI; open a draft PR. ### Layout beyond the core - `jupyddl/requirements.py` — **the source of truth** for what every PDDL diff --git a/CHANGELOG.md b/CHANGELOG.md index c58ca64..6ba0bb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,23 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- **The intent to publish, written down.** `.docs/PUBLISHING.md` says why and + where we mean to publish jupyddl as citable research software — a Zenodo DOI + per release, a JOSS paper, ICAPS workshops for the research results — with a + readiness checklist, the paper outline, the AI-usage disclosure JOSS requires + and how contributors can be considered for authorship. The README states the + project's aim (a framework to build on and to explain algorithms with) and + its Cite section says which version the 2021 preprint describes. +- **Community files for outside contributors**: a security policy, a + pull-request template, a *Propose an algorithm* issue template, and an + "Adding an algorithm" section in `CONTRIBUTING.md`. + ### Changed +- **CI now runs on pull requests, including from forks.** `tests` and `build` + were `on: [push]`, which never fires for a fork, so an outside contributor's + PR showed no checks at all. They now run on every pull request and on pushes + to `main`. - **Documentation lives in one place: `.docs/`.** It was spread over three directories — `docs/` for the contributor files and the README charts, `promo/` for the videos and screenshots, `.docs/` for the research notes — diff --git a/CITATION.cff b/CITATION.cff index 27a0688..1eaefa2 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -20,6 +20,9 @@ keywords: - automated planning - heuristic search - artificial intelligence +# This preprint describes the original, Julia-backed version. A software paper +# on the current framework is planned for JOSS, with a Zenodo DOI per release; +# when it is accepted it replaces this entry (see .docs/PUBLISHING.md). preferred-citation: type: article title: "Jupyddl, an extensible python library for PDDL planning and parsing" diff --git a/README.md b/README.md index 4d61dcf..214919f 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,13 @@ language runtime. It has since been **rewritten from scratch as a pure-Python framework** — no Julia, no native dependencies, just the standard library — so it is trivial to install, embed, teach with, and build on. +That is the point of it: a framework you can **build on** to implement a planning +algorithm in readable Python, measure it against the ones already here, and +**explain** it to someone else — every search can be traced, charted and +replayed. We intend to publish jupyddl as peer-reviewed research software so that +work built on it has something stable to cite; [the plan](.docs/PUBLISHING.md) +says where and what is left. +
@@ -597,6 +604,16 @@ planners — nothing in it is typed in by hand. ## Cite +If jupyddl helps your work, please cite it. GitHub's **"Cite this repository"** +button gives you APA and BibTeX from [`CITATION.cff`](CITATION.cff). + +The citation below is a 2021 preprint describing the project's original, +Julia-backed version. A software paper on the current framework is planned for +the [Journal of Open Source Software](https://joss.theoj.org), with a Zenodo +DOI for every release; once it is accepted it replaces this entry. See +[`.docs/PUBLISHING.md`](.docs/PUBLISHING.md) for the plan, the readiness +checklist, and how contributors can be considered for authorship. + ``` @misc{https://doi.org/10.13140/rg.2.2.22418.89282, doi = {10.13140/RG.2.2.22418.89282},