Skip to content

Let other packages plug in, and write the guide to building on jupyddl - #164

Merged
guilyx merged 3 commits into
mainfrom
feat/zen-gates-g3lolk
Nov 3, 2026
Merged

guilyx merged 3 commits into
mainfrom
feat/zen-gates-g3lolk

Conversation

@guilyx

@guilyx guilyx commented Nov 2, 2026

Copy link
Copy Markdown
Member

What and why

jupyddl is meant to be built on. Before this PR, the only way to add an algorithm was to fork the repo or edit the registry dicts by hand. That second route only reaches the process that does it, so the CLI never saw the result. This PR adds two things.

1. Plugins through entry points (jupyddl/plugins.py)

A package declares one of these in its own pyproject.toml:

[project.entry-points."jupyddl.planners"]
astar-tb = "my_package.search:TieBreakingAStar"

After pip install, jupyddl solve … -s astar-tb works. So do jupyddl.solve, the benchmark harness and jupyddl generate.

  • Lazy. The CLI scans installed packages before building its parser. The library only scans when asked for a name it doesn't know. Importing jupyddl never scans anything.
  • Defensive:
    • A built-in name always wins.
    • A plugin that fails to import or isn't callable is skipped with a PluginWarning.
    • Names containing : are refused (that syntax is reserved for learned:<path>).
    • JUPYDDL_NO_PLUGINS=1 turns discovery off.
  • New command: jupyddl plugins lists what was found and what was skipped, and why.
  • CLI fix: the CLI now reads requires_heuristic from the registry when it runs. INFORMED_PLANNERS is fixed at import, so it couldn't know about plugin planners.

2. .docs/EXTENDING.md, the guide

It covers:

  • a heuristic
  • a planner built from a priority function
  • a planner written from scratch, with the full budget and observer contract spelled out
  • a generator
  • how to test the guarantees you claim: compare cost against dijkstra, check h(s0) ≤ h*, and check that a truncated run is not reported as unsolvable
  • how to watch a search run
  • how to ship your additions as a plugin

tests/test_extending.py runs every Python block in the guide, so the guide fails CI instead of going stale.

Small engine change: best_first accepts a tuple priority for tie-breaking, lambda g, h: (g + h, h). Observers get its first element as f, so traces stay numeric. There is no overhead without an observer.

Also: the README, the .docs/ index, the PUBLISHING checklist (the extending-guide row is now ✅), AGENTS.md and the CHANGELOG are updated. web/dist is rebuilt.

How it was checked

  • Full suite: 427 passed, 1 skipped (7 new tests). flake8 and black are clean.
  • New tests cover:
    • a plugin found on first lookup
    • a built-in can't be replaced
    • broken, non-callable and :-named plugins are skipped and the good one still lands
    • discovery runs once and can be switched off
    • the CLI lists, generates with and solves with a plugin end to end
  • The suite now sets JUPYDDL_NO_PLUGINS=1 in conftest.py, so a developer's installed plugins can't change its results.

Checklist

  • flake8 jupyddl tests tools and pytest pass locally
  • python tools/build_web.py re-run; web/dist committed
  • No planner moves in or out of OPTIMAL_PLANNERS
  • CHANGELOG.md updated under Unreleased

The branch history has a merge commit: it fast-forwards over the already-merged #163 tip, because a force-push was not available. Its tree is identical to the feature commit, and the PR diff against main contains only this change. Squash-merge as usual.


Generated by Claude Code

Write down where and why we mean to publish jupyddl as citable research
software (.docs/PUBLISHING.md): 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 and
its Cite section now says which version the 2021 preprint describes.

Add the community files an outside contributor expects: a security policy,
a pull-request template, a "Propose an algorithm" issue template, and an
"Adding an algorithm" section in CONTRIBUTING.md.

Run tests and build on pull requests. They were `on: [push]`, which never
fires for a fork, so a contributor's PR showed no checks at all.

Fix AGENTS.md drift: the Python floor is 3.10 and Mergify is retired.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014RbGtRHF8XhkiPQCDVHtV2
A package can now add planners, heuristics and generators by declaring
`jupyddl.planners`, `jupyddl.heuristics` or `jupyddl.generators` entry
points. Once installed, they work from the CLI, the benchmark harness and
`jupyddl.solve` by name, without anyone importing the package.

Discovery is lazy and defensive (jupyddl/plugins.py): the CLI runs it
before building its parser, the library only on a registry miss, so
importing jupyddl never scans installed packages. A built-in name always
wins, a plugin that fails to import is skipped with a warning, and
JUPYDDL_NO_PLUGINS=1 turns it off. `jupyddl plugins` lists what was found.
The CLI now reads `requires_heuristic` from the registry at call time,
since INFORMED_PLANNERS is fixed at import and cannot know about plugins.

.docs/EXTENDING.md walks through a heuristic, a planner from a priority
function, a planner from scratch with the budget/observer contract, a
generator, testing the guarantees you claim, and shipping as a plugin.
tests/test_extending.py runs every Python block in it, so it cannot drift.

best_first now accepts a tuple priority for tie-breaking; observers get
its first element as `f`, so traces stay numeric.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014RbGtRHF8XhkiPQCDVHtV2
# Conflicts:
#	.docs/PUBLISHING.md
#	AGENTS.md
#	CHANGELOG.md
@guilyx
guilyx marked this pull request as ready for review November 3, 2026 07:46
@guilyx
guilyx merged commit f033712 into main Nov 3, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants