Configurator – Application Hub Profile Generator
configurator is a framework and CLI tool to define, compose, and export application profiles (Code Server, GPU Code Server, Remote Desktop, …) into a single YAML configuration consumable by an Application Hub (e.g. JupyterHub + KubeSpawner).
The design focuses on:
- explicit configuration (no magic)
- strong typing (Pydantic)
- extensible base classes
- deterministic profile selection
- deployment-time overrides via CLI
Core Concepts
Profile
A Profile represents a runnable application configuration:
- container image
- CPU / memory limits
- node selector
- volumes
- environment variables
- config maps
- init containers
- optional default URL
Profiles are serialized into a YAML file via the Config model.
BaseAppProfile
BaseAppProfile is the foundation for all applications.
It implements:
- profile construction (
build()) - resource wiring
- config map handling
- init containers
- volume merging
- node selector handling
- default URL propagation
Concrete profiles never override build().
App Families
Profiles are grouped by base app classes:
BaseCoderProfile→ code / notebook / CWL appsBaseRemoteDesktopProfile→ web-based desktop appsBaseJupyterLabProfile→ JupyterLab apps
Each family defines sane defaults for:
- image
- resources
- volumes
- environment
Profile Registry
Profiles are registered explicitly in a central registry.
- Each profile has a unique slug
- Deployments select profiles by slug
- No auto-discovery or hidden imports
This makes profile selection deterministic and debuggable.
Repository Structure
configurator/
cli/
commands.py # Click command definitions
options.py # Shared CLI options
describe/
profile.py # Human-readable profile output
io/
yaml_writer.py # YAML serialization
overrides/
apply.py # Override application
parser.py # Override parsing
plugins/
loader.py # Builtin/external profile loading
apps/
base.py # BaseAppProfile
registry.py # ProfileRegistry
coder/
base_coder.py # BaseCoderProfile
coder_profiles.py # CoderProfile, GpuCoderProfile
__init__.py # re-exports + registration
remote_desktop/
base_remote_desktop.py # BaseRemoteDesktopProfile
remote_desktop_profiles.py
__init__.py # re-exports + registration
jupyterlab/
base_jupyterlab.py # BaseJupyterLabProfile
jupyterlab_profiles.py # JupyterLab profiles
models.py # Pydantic models
main.py # click-based CLI entrypoint
Defining Profiles
Example: Base coder profile
class BaseCoderProfile(BaseAppProfile):
image = "ghcr.io/eoepca/pde-code-server:latest-dev"
cpu_guarantee = 1
cpu_limit = 2
mem_guarantee = "4G"
mem_limit = "6G"
Example: Concrete coder profile
class CoderProfile(BaseCoderProfile):
display_name = "Code Server"
description = "Code Server for development"
slug = "coder_app"
Example: GPU coder profile
class GpuCoderProfile(BaseCoderProfile):
display_name = "GPU Code Server"
description = "Code Server with GPU acceleration"
slug = "gpu_coder_app"
cpu_limit = 8
mem_limit = "32G"
def get_extra_resource_limits(self):
return {"nvidia.com/gpu": 1}
Example: Remote desktop base profile
class BaseRemoteDesktopProfile(BaseAppProfile):
image = "ghcr.io/eoepca/iga-remote-desktop:1.2.0"
default_url = "/desktop"
Registering Profiles
Profiles are registered explicitly in their package init.py:
from configurator.apps import profile_registry
from .coder_profiles import CoderProfile, GpuCoderProfile, DaskGatewayCoderProfile
profile_registry.register(CoderProfile)
profile_registry.register(GpuCoderProfile)
profile_registry.register(DaskGatewayCoderProfile)
Only concrete profiles are registered.
Base classes are never registered.
CLI: dump-config
The CLI is implemented using Click.
dump-config --help
Options
Option Description --profiles Comma-separated list of profile slugs --groups Comma-separated list of groups --node-selector Per-profile node selector override --override Per-profile attribute override --output Output YAML file
Environment variables can be used as defaults.
Selecting Profiles
dump-config \
--profiles coder_app,gpu_coder_app,remote_desktop
Profiles are selected by slug, in order.
Groups
dump-config \
--profiles coder_app \
--groups developers,ml-users
Groups are deployment-level policy and apply to all selected profiles.
Node Selector Overrides (per slug)
Syntax
--node-selector <slug>:<key>=<value>
Example
dump-config \
--profiles coder_app,gpu_coder_app \
--node-selector gpu_coder_app:nodepool=gpu
Result (excerpt)
profiles:
- id: profile_gpu_coder_app
node_selector:
nodepool: gpu
Resource & Image Overrides (per slug)
Syntax
--override <slug>:<field>=<value>
Supported fields include:
cpu_limitcpu_guaranteemem_limitmem_guaranteeimage- any other profile attribute
Example: CPU & memory
dump-config \
--profiles coder_app \
--override coder_app:cpu_limit=4 \
--override coder_app:mem_limit=8G
Example: image override
dump-config \
--profiles coder_app \
--override coder_app:image=ghcr.io/eoepca/pde-code-server:2024.11
Combined Example
dump-config \
--profiles coder_app,gpu_coder_app,remote_desktop \
--groups developers,ml-users \
--node-selector gpu_coder_app:nodepool=gpu \
--override coder_app:cpu_limit=4 \
--override gpu_coder_app:mem_limit=32G \
--output config.yaml
Output
The CLI generates a single YAML file:
profiles:
- id: profile_coder_app
groups:
- developers
- ml-users
definition:
display_name: Code Server
slug: coder_app
kubespawner_override:
cpu_limit: 4
mem_limit: 6G
image: ghcr.io/eoepca/pde-code-server:latest-dev
Serialization uses:
config.model_dump(exclude_none=True)
No Python-specific YAML tags are emitted.
Design Rules (Important)
- Profiles define defaults, not deployment policy
- Deployment overrides happen only via the CLI
- Selection is by slug, not by class name
- Concrete profiles never override build()
- Base classes define shared behavior
- CLI remains the single control plane
Why This Architecture Scales
This design supports, without refactoring:
- new app families
- cluster-specific overrides
- GPU / non-GPU deployments
- multiple environments
- CI-generated configs
- Helm / GitOps workflows
License
Usage examples
dump-config \
--profiles coder_app,gpu_coder_app,remote_desktop,qgis_remote_desktop,jupyterlab_small \
--override coder_app:image=ghcr.io/eoepca/pde-code-server:2024.11 \
--groups group-a,group-b,group-c
dump-config \
--profiles coder_app,gpu_coder_app,remote_desktop,qgis_remote_desktop,jupyterlab_small \
--override coder_app:image=ghcr.io/eoepca/pde-code-server:2024.11 \
--groups group-a,group-b,group-c \
--override gpu_coder_app:groups=ml-users,gpu-users
dump-config \
--profiles-dir ./data/work/extra-profiles \
--profiles coder_app,training_how_to_app,mlflow_coder_app \
--groups group-a,group-b \
--output config.yaml
Metadata
Release files for app-hub-configurator 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| app_hub_configurator-0.1.1.tar.gz | 23.6 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| app_hub_configurator-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 62.4 kB
Release files / app_hub_configurator-0.1.1.tar.gz
| Download URL | app_hub_configurator-0.1.1.tar.gz |
|---|---|
| Size | 23.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c80753e8674406f13d4558f45f6e58eb7cd683618819dd66f69fe60f2afb09c0
|
|
BLAKE2b-256 checksum How to use checksums |
755035aa8637b9c1b0bb5c4715593b000011e42adae81e24dffb0014a2edfbb7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 22, 2026.
Transparency logRelease files / app_hub_configurator-0.1.1-py3-none-any.whl
| Download URL | app_hub_configurator-0.1.1-py3-none-any.whl |
|---|---|
| Size | 38.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2df6d89b7c03e90a6ee841a46f4adf32f0928f990ea01cfbbd22665c52e814ac
|
|
BLAKE2b-256 checksum How to use checksums |
801891e2d27682e52dcc497a2a84ba5ea77c88d7366e5a46a91e05c36e72dffa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 22, 2026.
Transparency logSecurity for app-hub-configurator 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for app_hub_configurator-0.1.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.