You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The issue author (jmchilton) is working through tool shed cleanup and notes that while Claude (AI) is eager to eliminate the WSGI app, the author considers it "maybe too potentially disruptive" and is deferring it personally. The WSGI shim for hg (Mercurial) is considered acceptable for now. The issue is filed so someone else could pick it up after other cleanup work lands.
Current State
Request lifecycle:
fast_factory.py:factory() calls buildapp.app_pair() to create WSGI CommunityWebApplication
fast_app.py:initialize_fast_app() wraps WSGI app via WSGIMiddleware (a2wsgi), mounts at /
Any request not matched by FastAPI falls through to WSGI
WSGI app serves exactly two functional routes:
/repository/static/images/{id}/{image_file} -- tool help images from hg repos
/repos/*path_info -- mercurial HTTP clone via hgwebdir
Plus middleware (wrap_in_middleware) and a legacy redirect (_map_redirects).
Proposed Architecture
Image serving: Pure FastAPI endpoint (trivial file serving)
Hg clone: Mount hgwebdir directly as WSGI sub-app under /repos via a2wsgi.WSGIMiddleware
buildapp.py:app_pair() constructs the full WSGI CommunityWebApplication with Routes, controllers, middleware
fast_app.py:initialize_fast_app() wraps it via WSGIMiddleware(gx_webapp) and mounts at /
What the WSGI App Actually Serves
Analysis of buildapp.py shows the WSGI app has extensive route definitions, but with the TS2.0 FastAPI endpoints in place, only two functional routes still require WSGI:
Note: The issue lists 8 files but the controllers directory also contains admin.py, groups.py, and user.py which would also be removed (they are only used by the WSGI app).
Files Requiring Modification
File
Change
Complexity
lib/tool_shed/webapp/fast_factory.py
Remove app_pair() import, create app directly
Low
lib/tool_shed/webapp/fast_app.py
Remove WSGI mount, add hg sub-app mount
Medium
lib/tool_shed/util/common_util.py
Remove from routes import url_for fallback
Low
lib/tool_shed/util/shed_util_common.py
Remove url_for fallback
Low
lib/tool_shed/util/repository_util.py
Remove web.url_for usage (lines 138, 255)
Low
lib/tool_shed/util/readme_util.py
Remove web.url_for usage (line 78)
Low
lib/tool_shed/util/admin_util.py
Massive web.url_for usage (40+ instances) -- but entire file may be dead code if admin controllers are removed
The SHED_API_VERSION env var (v1 or v2) controls which API layer is active. The v2 frontend (TS2.0) is fully functional. The WSGI v1 API routes in buildapp.py overlap with v2 FastAPI routes.
Dependency Impact
Dependency
Current Usage in ToolShed
Can Remove?
Paste
buildapp.py only (httpexceptions, TransLogger)
Yes
Routes
buildapp.py + common_util.py url_for fallback
Yes (after url_for cleanup)
a2wsgi
fast_app.py WSGI mount
Keep (still needed for hg sub-app)
Mako
readme_util.py
Keep (independent of WSGI)
mercurial
controllers/hg.py
Keep (hgwebdir still needed)
Comparison: Galaxy Main App
The main Galaxy app (lib/galaxy/webapps/galaxy/fast_app.py) still uses the identical WSGI-fallback pattern:
wsgi_handler=WSGIMiddleware(gx_wsgi_webapp)
The ToolShed elimination would serve as a proof of concept for eventually doing the same in the main Galaxy app, though Galaxy's WSGI surface is vastly larger.
Key Risk: hgwebdir Integration
The most complex part of this change is the Mercurial hgwebdir integration. Currently it runs inside the full WSGI request lifecycle with session management, URL routing, and error handling. Moving it to a standalone WSGI sub-app requires:
PATH_INFO rewriting: hgwebdir expects /repos/owner/name in PATH_INFO, but Starlette strips the mount prefix
Session management: Download tracking (times_downloaded increment) currently uses the WSGI app's request-scoped SQLAlchemy session
Thread safety: Current code creates a new hgwebdir instance per request; caching may or may not be safe
Error handling: Deprecated repo checks need to produce proper HTTP errors outside the WSGI error middleware
url_for Dependency Analysis
The url_for function from Routes is used as a fallback in several places when no trans or hostname is available. These are:
common_util.py:43 -- url_for("/", qualified=True) as hostname fallback
shed_util_common.py:379 -- same pattern
repository_util.py:138,255 -- web.url_for("/", qualified=True) for base URL
readme_util.py:78 -- static path and host URL generation
admin_util.py -- 40+ instances for controller/action URL generation (but admin_util is only used by the admin controller, which is itself WSGI-only)
The Routes url_for requires the Routes mapper to be configured, which currently happens through the WSGI app. Removing WSGI means these fallback paths would break. The fix is to require hostname from config or trans context in all cases.
Demand Research: Issue #21896 -- Eliminate WSGI App for ToolShed
Quantified Demand
Reactions & Engagement
Thumbs up: 0
Total reactions: 0
Comments: 0
Created: 2026-02-19 (5 days old at time of triage)
Linked / Duplicate Issues
No linked or duplicate issues found. This is a fresh issue, not a long-standing community request.
Related Issues & Context
Issue
Title
State
Relevance
#12257
Roadmap to FastAPI
Closed
The parent effort; Galaxy main app completed WSGI-to-FastAPI migration for most endpoints. Tool Shed was not in scope.
#10889
Progressively adapt old API routes to FastAPI
Open
Broad FastAPI migration tracking.
#15639
Tool Shed 2.0
Closed
TS2.0 introduced the FastAPI-based frontend. The WSGI layer survived as a fallback.
#19693
Pin mercurial for Python 3.12
Closed
Mercurial dependency is directly related -- hg clone is the main reason WSGI persists.
Author Context
Filed by jmchilton, a core maintainer and the primary driver of tool shed modernization.
The issue is explicitly self-deferred: "I think this little shim for hg is fine so I'm putting this off personally."
Part of a broader cleanup effort; jmchilton mentions a forthcoming PR that removes "tons of legacy stuff."
The detailed 9-step plan was AI-generated (Claude), suggesting this was exploratory research rather than imminent work.
Community Discussion
No external discussion threads found on Galaxy Dev mailing list or Gitter/Matrix.
No mentions in Galaxy Training Network or admin documentation requests.
The ToolShed is a shared community resource but has a small active maintainer base (primarily jmchilton, mvdbeek, guerler).
Demand Assessment
User demand: LOW
This is an internal tech debt issue, not a user-facing feature request. No community members have requested it, reacted to it, or commented on it. The issue was filed as a "maybe someday" placeholder by its author. The WSGI layer is invisible to end users -- it handles hg clone and image serving, both of which work fine today.
The demand is entirely developer-side: reducing maintenance burden, simplifying the codebase, and removing legacy dependencies. While that has real value, there is no external pressure to prioritize this.
Test driver updates require understanding the test infrastructure
Several unresolved questions in the issue that need answers before implementation
Functional testing requires a running ToolShed with Mercurial
What keeps it from being large:
The plan is well-researched and specific
Most individual steps are small (FastAPI endpoint, redirect, delete files)
The most complex piece (hgwebdir sub-app) is ~50 lines of new code
The majority of the work is deletion
Estimated effort: 2-4 days for an experienced Galaxy developer, assuming the unresolved questions do not surface surprises. Add buffer time for hg protocol testing.
Risk Assessment: MODERATE
Disruption Risk
The issue author explicitly flags this: "I think it is maybe too potentially disruptive." This concern is valid.
Breaking change vectors:
hg clone: If the PATH_INFO rewriting is wrong, Mercurial clone/push operations break for all ToolShed users
Image serving: If the FastAPI endpoint has different path matching behavior, tool help images break
Session scoping: If the hg download tracking loses its session, download counts silently stop incrementing
url_for fallback: If any code path calls url_for without trans/hostname, it will crash at runtime rather than failing gracefully
Test infrastructure: Changes to driver.py could break the ToolShed test suite, which is already fragile
Mitigating factors:
The ToolShed has functional tests covering hg clone and image serving
The WSGI surface is very small (2 routes + 1 redirect)
Changes can be staged incrementally (steps 1-2 first, then 3-4, etc.)
The v1 API is still the default; v2 is opt-in via environment variable
Timing Risk
jmchilton has a pending PR removing "tons of legacy stuff" -- this change should wait for that to land
Doing this concurrently with other ToolShed cleanup risks merge conflicts
The issue was filed as a "park it for later" item, not an urgent need
Maintenance Risk (of NOT doing it)
Every release cycle, the dual WSGI+FastAPI stack adds cognitive overhead
Paste and Routes are aging dependencies with declining maintenance
New developers hitting ToolShed code face unnecessary complexity
The longer legacy code sits, the harder it is to reason about what is actually used
Recommendation: BACKLOG
Rationale: This is good, well-scoped work that aligns with the project's long-term direction. However, it should not be prioritized ahead of user-facing features or bug fixes given zero user demand. The right time to do this is:
After jmchilton's pending ToolShed cleanup PR lands
When someone is already working in the ToolShed codebase
Ideally early in a release cycle to allow time for regression discovery
The issue is well-documented enough that it can be picked up at any time. It would be a good task for a developer looking to deepen their understanding of the ToolShed architecture.
Do not decline: The work has clear value and a solid plan. It just does not have urgency.
Implementation Plan: Issue #21896 -- Eliminate WSGI App for ToolShed
Prerequisites
jmchilton's pending ToolShed cleanup PR must land first. That PR removes "tons of legacy stuff" and will change the baseline for this work.
Verify which controllers and utility code survive that cleanup before starting.
Recommended Approach: Incremental PRs
Rather than one large PR (which the issue author already flagged as "too potentially disruptive"), this should be split into 2-3 smaller PRs that can be reviewed and tested independently.
# New FastAPI endpoint for repository images# GET /repository/static/images/{repository_id}/{image_file:path}# Returns FileResponse with mimetypes.guess_type() for MIME detection# include_in_schema=False (internal route)
Key decisions:
Use mimetypes.guess_type() instead of datatypes_registry.get_mimetype_by_extension()
Return proper 404 for missing repos/files
Register in api2/__init__.py router list
Step 1b: Legacy redirect
Add to repository_images.py or a new redirects.py:
# GET /repository/status_for_installed_repository -> 301 /api/repositories/updates/# Preserve query parameters
Testing: Deploy and verify both old and new endpoints serve identical responses.
Has jmchilton's cleanup PR landed? Check what survived. The file list above may be stale.
admin_util.py: Is it entirely dead code once admin controllers are removed, or do any FastAPI endpoints use it?
hgwebdir thread safety: Can a single hgwebdir instance be reused across concurrent requests, or must we create one per request?
Session management for hg download tracking: Use scoped_session from the app's session factory, or create a standalone session?
v1 vs v2 API version: If SHED_API_VERSION=v1 is still the default, the WSGI v1 API routes are actively serving traffic. Those routes need to survive or be ported to FastAPI.
Question 5 is critical. If v1 is still the default, eliminating the WSGI app means all v1 API routes must either be ported to FastAPI or the default must change to v2. The issue does not address this explicitly.
Triage Summary: Issue #21896 -- Eliminate WSGI App for ToolShed
Top-Line Summary
The ToolShed currently runs a dual-stack architecture where a full WSGI application (Routes, Paste middleware, legacy controllers) is mounted as a catch-all fallback behind the FastAPI app, but only two functional routes still require it: Mercurial HTTP clone (/repos/) and repository image serving. This issue proposes replacing those with a targeted hgwebdir WSGI sub-app and a trivial FastAPI file-serving endpoint, then deleting ~4,100 lines of legacy code including the entire controllers/ and framework/ directories, plus the buildapp.py module. The recommended approach is three incremental PRs -- first adding FastAPI replacements (non-breaking), then swapping the WSGI mount for a minimal hg sub-app, then cleaning up dead code and dependencies. This work should wait for jmchilton's pending ToolShed cleanup PR to land and should be scheduled early in a release cycle to allow regression discovery.
Importance Assessment Summary
Dimension
Rating
Notes
User demand
Low
Zero reactions, zero comments; internal tech debt only
Strategic value
Medium-High
Removes legacy dependencies, simplifies architecture, proof-of-concept for Galaxy main app
Effort estimate
Medium
2-4 days for experienced developer; 9 steps with hg protocol testing
Risk
Moderate
hg clone breakage is the primary concern; author flagged as "potentially disruptive"
Recommendation
Backlog
Good work, no urgency; pick up after pending cleanup lands
Key Questions for Group Discussion
Timing: Should this wait for a specific release cycle, or can it ride with jmchilton's ongoing ToolShed cleanup?
v1 API dependency: The SHED_API_VERSION defaults to v1, meaning the WSGI-mounted v1 API routes are still the default code path. Eliminating WSGI requires either porting all v1 routes to FastAPI or changing the default to v2. Is v2 ready to be the default?
Scope of jmchilton's pending PR: How much of the code identified for deletion here will already be removed by that PR? The implementation plan may need significant revision after it lands.
hg clone testing: Do we have adequate CI coverage for Mercurial wire protocol operations? The hgwebdir PATH_INFO rewriting is the highest-risk change and needs thorough testing.
Galaxy main app precedent: If this succeeds for ToolShed, do we want to pursue the same WSGI elimination for the main Galaxy app? That would be a much larger effort but the ToolShed could prove the pattern.
Concerns
Scope creep: The 9-step plan is already medium-sized. If the url_for cleanup or v1 API porting turns out to be larger than expected, this could grow into a large effort.
Breaking changes: Mercurial clone is critical infrastructure for anyone hosting a ToolShed. A regression here affects all downstream Galaxy installations pulling tools.
Maintenance burden: Ironically, the current WSGI shim requires almost zero maintenance -- it works and nobody touches it. The risk of introducing bugs during removal may outweigh the maintenance savings in the short term.
Test fragility: The ToolShed test infrastructure is already complex (dual Galaxy+ToolShed server startup). Changes to driver.py could have cascading effects on test reliability.