Add thirteen ArtCraft desktop applications to the OCI catalog

This commit is contained in:
Jonatan Castro
2026-11-03 14:50:20 +01:00
parent 9940f05adf
commit aa19af66eb
37 changed files with 15283 additions and 8 deletions
+14 -1
View File
@@ -8967,5 +8967,18 @@
"⚠ Disk data will NOT be erased.": "⚠ Festplattendaten werden NICHT gelöscht.",
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ Die Festplatte wird ausgehängt und aus /etc/fstab entfernt.",
"⚠ The /etc/fstab entry will be removed.": "⚠ Der /etc/fstab-Eintrag wird entfernt.",
"⚠ The disk will be unmounted.": "⚠ Die Festplatte wird ausgehängt."
"⚠ The disk will be unmounted.": "⚠ Die Festplatte wird ausgehängt.",
"Computer-aided design and drafting in your browser": "Computergestütztes Konstruieren und technisches Zeichnen im Browser",
"Presentations and slide decks in your browser": "Präsentationen und Folien im Browser",
"Page layout and publishing in your browser": "Seitenlayout und Publizieren im Browser",
"Motion graphics and compositing in your browser": "Motion-Design und Compositing im Browser",
"Interface design and prototyping in your browser": "Oberflächendesign und Prototyping im Browser",
"Video editing in your browser": "Videoschnitt im Browser",
"Spreadsheets in your browser": "Tabellenkalkulation im Browser",
"Photo library and RAW development in your browser": "Fotoverwaltung und RAW-Entwicklung im Browser",
"Read and edit PDF documents in your browser": "PDF-Dokumente im Browser lesen und bearbeiten",
"Photo editing in your browser": "Fotobearbeitung im Browser",
"Audio recording and mixing in your browser": "Audioaufnahme und -mischung im Browser",
"Vector illustration in your browser": "Vektorillustrationen im Browser",
"Word processing in your browser": "Textverarbeitung im Browser"
}
+14 -1
View File
@@ -8937,5 +8937,18 @@
"⚠ Disk data will NOT be erased.": "⚠ Los datos del disco NO se borrarán.",
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ El disco se desmontará y se eliminará de /etc/fstab.",
"⚠ The /etc/fstab entry will be removed.": "⚠ Se eliminará la entrada /etc/fstab.",
"⚠ The disk will be unmounted.": "⚠ El disco se desmontará."
"⚠ The disk will be unmounted.": "⚠ El disco se desmontará.",
"Computer-aided design and drafting in your browser": "Diseño CAD y dibujo técnico en el navegador",
"Presentations and slide decks in your browser": "Presentaciones y diapositivas en el navegador",
"Page layout and publishing in your browser": "Maquetación y publicación en el navegador",
"Motion graphics and compositing in your browser": "Animación gráfica y composición en el navegador",
"Interface design and prototyping in your browser": "Diseño de interfaces y prototipos en el navegador",
"Video editing in your browser": "Edición de vídeo en el navegador",
"Spreadsheets in your browser": "Hojas de cálculo en el navegador",
"Photo library and RAW development in your browser": "Biblioteca de fotos y revelado RAW en el navegador",
"Read and edit PDF documents in your browser": "Lectura y edición de documentos PDF en el navegador",
"Photo editing in your browser": "Edición de fotos en el navegador",
"Audio recording and mixing in your browser": "Grabación y mezcla de audio en el navegador",
"Vector illustration in your browser": "Ilustración vectorial en el navegador",
"Word processing in your browser": "Procesador de textos en el navegador"
}
+14 -1
View File
@@ -8966,5 +8966,18 @@
"⚠ Disk data will NOT be erased.": "⚠ Les données du disque ne seront PAS effacées.",
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ Le disque sera démonté et supprimé de /etc/fstab.",
"⚠ The /etc/fstab entry will be removed.": "⚠ L'entrée /etc/fstab sera supprimée.",
"⚠ The disk will be unmounted.": "⚠ Le disque sera démonté."
"⚠ The disk will be unmounted.": "⚠ Le disque sera démonté.",
"Computer-aided design and drafting in your browser": "Conception assistée par ordinateur et dessin technique dans le navigateur",
"Presentations and slide decks in your browser": "Présentations et diaporamas dans le navigateur",
"Page layout and publishing in your browser": "Mise en page et publication dans le navigateur",
"Motion graphics and compositing in your browser": "Animation graphique et compositing dans le navigateur",
"Interface design and prototyping in your browser": "Conception d’interfaces et prototypage dans le navigateur",
"Video editing in your browser": "Montage vidéo dans le navigateur",
"Spreadsheets in your browser": "Tableur dans le navigateur",
"Photo library and RAW development in your browser": "Photothèque et développement RAW dans le navigateur",
"Read and edit PDF documents in your browser": "Lire et modifier des documents PDF dans le navigateur",
"Photo editing in your browser": "Retouche photo dans le navigateur",
"Audio recording and mixing in your browser": "Enregistrement et mixage audio dans le navigateur",
"Vector illustration in your browser": "Illustration vectorielle dans le navigateur",
"Word processing in your browser": "Traitement de texte dans le navigateur"
}
+14 -1
View File
@@ -8967,5 +8967,18 @@
"⚠ Disk data will NOT be erased.": "⚠ I dati del disco NON verranno cancellati.",
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ Il disco verrà smontato e rimosso da /etc/fstab.",
"⚠ The /etc/fstab entry will be removed.": "⚠ La voce /etc/fstab verrà rimossa.",
"⚠ The disk will be unmounted.": "⚠ Il disco verrà smontato."
"⚠ The disk will be unmounted.": "⚠ Il disco verrà smontato.",
"Computer-aided design and drafting in your browser": "Progettazione CAD e disegno tecnico nel browser",
"Presentations and slide decks in your browser": "Presentazioni e diapositive nel browser",
"Page layout and publishing in your browser": "Impaginazione e pubblicazione nel browser",
"Motion graphics and compositing in your browser": "Grafica animata e compositing nel browser",
"Interface design and prototyping in your browser": "Progettazione di interfacce e prototipi nel browser",
"Video editing in your browser": "Montaggio video nel browser",
"Spreadsheets in your browser": "Fogli di calcolo nel browser",
"Photo library and RAW development in your browser": "Libreria fotografica e sviluppo RAW nel browser",
"Read and edit PDF documents in your browser": "Lettura e modifica di documenti PDF nel browser",
"Photo editing in your browser": "Fotoritocco nel browser",
"Audio recording and mixing in your browser": "Registrazione e missaggio audio nel browser",
"Vector illustration in your browser": "Illustrazione vettoriale nel browser",
"Word processing in your browser": "Elaborazione di testi nel browser"
}
+14 -1
View File
@@ -8967,5 +8967,18 @@
"⚠ Disk data will NOT be erased.": "⚠ Os dados do disco NÃO serão apagados.",
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ O disco será desmontado e removido de /etc/fstab.",
"⚠ The /etc/fstab entry will be removed.": "⚠ A entrada /etc/fstab será removida.",
"⚠ The disk will be unmounted.": "⚠ O disco será desmontado."
"⚠ The disk will be unmounted.": "⚠ O disco será desmontado.",
"Computer-aided design and drafting in your browser": "Projeto CAD e desenho técnico no navegador",
"Presentations and slide decks in your browser": "Apresentações e slides no navegador",
"Page layout and publishing in your browser": "Diagramação e publicação no navegador",
"Motion graphics and compositing in your browser": "Animação gráfica e composição no navegador",
"Interface design and prototyping in your browser": "Design de interfaces e protótipos no navegador",
"Video editing in your browser": "Edição de vídeo no navegador",
"Spreadsheets in your browser": "Planilhas no navegador",
"Photo library and RAW development in your browser": "Biblioteca de fotos e revelação RAW no navegador",
"Read and edit PDF documents in your browser": "Leitura e edição de documentos PDF no navegador",
"Photo editing in your browser": "Edição de fotos no navegador",
"Audio recording and mixing in your browser": "Gravação e mixagem de áudio no navegador",
"Vector illustration in your browser": "Ilustração vetorial no navegador",
"Word processing in your browser": "Processamento de texto no navegador"
}
+14 -1
View File
@@ -8967,5 +8967,18 @@
"⚠ Disk data will NOT be erased.": "⚠ Dáta na disku sa NEVYMAŽÚ.",
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ Disk sa odpojí a odstráni z /etc/fstab.",
"⚠ The /etc/fstab entry will be removed.": "⚠ Záznam v /etc/fstab bude odstránený.",
"⚠ The disk will be unmounted.": "⚠ Disk bude odpojený."
"⚠ The disk will be unmounted.": "⚠ Disk bude odpojený.",
"Computer-aided design and drafting in your browser": "Počítačom podporované navrhovanie a technické kreslenie v prehliadači",
"Presentations and slide decks in your browser": "Prezentácie a snímky v prehliadači",
"Page layout and publishing in your browser": "Zalomenie strán a publikovanie v prehliadači",
"Motion graphics and compositing in your browser": "Animovaná grafika a kompoziting v prehliadači",
"Interface design and prototyping in your browser": "Návrh rozhraní a prototypov v prehliadači",
"Video editing in your browser": "Strih videa v prehliadači",
"Spreadsheets in your browser": "Tabuľkový procesor v prehliadači",
"Photo library and RAW development in your browser": "Fotoknižnica a vyvolávanie RAW v prehliadači",
"Read and edit PDF documents in your browser": "Čítanie a úprava dokumentov PDF v prehliadači",
"Photo editing in your browser": "Úprava fotografií v prehliadači",
"Audio recording and mixing in your browser": "Nahrávanie a mixovanie zvuku v prehliadači",
"Vector illustration in your browser": "Vektorová ilustrácia v prehliadači",
"Word processing in your browser": "Spracovanie textu v prehliadači"
}
+14 -1
View File
@@ -8967,5 +8967,18 @@
"⚠ Disk data will NOT be erased.": "⚠ Diskdata kommer INTE att raderas.",
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ Disken kommer att avmonteras och tas bort från /etc/fstab.",
"⚠ The /etc/fstab entry will be removed.": "⚠ /etc/fstab-posten kommer att tas bort.",
"⚠ The disk will be unmounted.": "⚠ Disken kommer att avmonteras."
"⚠ The disk will be unmounted.": "⚠ Disken kommer att avmonteras.",
"Computer-aided design and drafting in your browser": "CAD och teknisk ritning i webbläsaren",
"Presentations and slide decks in your browser": "Presentationer och bildspel i webbläsaren",
"Page layout and publishing in your browser": "Sidlayout och publicering i webbläsaren",
"Motion graphics and compositing in your browser": "Rörlig grafik och komposition i webbläsaren",
"Interface design and prototyping in your browser": "Gränssnittsdesign och prototyper i webbläsaren",
"Video editing in your browser": "Videoredigering i webbläsaren",
"Spreadsheets in your browser": "Kalkylblad i webbläsaren",
"Photo library and RAW development in your browser": "Fotobibliotek och RAW-framkallning i webbläsaren",
"Read and edit PDF documents in your browser": "Läs och redigera PDF-dokument i webbläsaren",
"Photo editing in your browser": "Fotoredigering i webbläsaren",
"Audio recording and mixing in your browser": "Ljudinspelning och mixning i webbläsaren",
"Vector illustration in your browser": "Vektorillustration i webbläsaren",
"Word processing in your browser": "Ordbehandling i webbläsaren"
}
+1 -1
View File
@@ -2,7 +2,7 @@
<!-- Generated from oci/catalog/verification.json by .github/scripts/oci_validation.py. Do not edit by hand. -->
52 of 533 applications in the OCI catalog have been tested for real: 49 in the ProxMenux lab and 3 by the community. The OCI installer shows them as verified, with a ✓ in the lists.
52 of 546 applications in the OCI catalog have been tested for real: 49 in the ProxMenux lab and 3 by the community. The OCI installer shows them as verified, with a ✓ in the lists.
Each test describes the scenario that was run and names the image it ran on. It does not cover every possible configuration of the application, and a newer image has not been tested until someone reports it.
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-cadcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "CADCraft",
"es_ES": "CADCraft"
},
"tagline": {
"en_US": "Computer-aided design and drafting in your browser",
"es_ES": "Diseño CAD y dibujo técnico en el navegador"
},
"description": {
"en_US": "CADCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "CADCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/cadcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/cadcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/cadcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/cadcraft",
"readme_pushed_at": "",
"compose_sha256": "ab46cb8e87addb261680a50fc8bdde1f9d689a0d14f6ca570eaf11e43868655a",
"generated_at": "2026-11-03T12:57:27+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/cadcraft.yaml"
},
"container_contract": {
"service_name": "cadcraft",
"container_name": "cadcraft",
"image": {
"reference": "docker.io/junkerderprovinz/cadcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/cadcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n cadcraft:\n image: junkerderprovinz/cadcraft:latest\n container_name: cadcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "cadcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "cadcraft",
"service_count": 1,
"services": [
{
"name": "cadcraft",
"image": "junkerderprovinz/cadcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/cadcraft:latest",
"container_name": "cadcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "cadcraft-volume-0",
"service": "cadcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "cadcraft-volume-1",
"service": "cadcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"cadcraft"
],
"stop_order": [
"cadcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-deckcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "DeckCraft",
"es_ES": "DeckCraft"
},
"tagline": {
"en_US": "Presentations and slide decks in your browser",
"es_ES": "Presentaciones y diapositivas en el navegador"
},
"description": {
"en_US": "DeckCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "DeckCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/deckcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/deckcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/deckcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/deckcraft",
"readme_pushed_at": "",
"compose_sha256": "38d24b673dd5fb50e00d1094e681112671cf04a8e99952021f476c8b2754ef05",
"generated_at": "2026-11-03T12:57:28+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/deckcraft.yaml"
},
"container_contract": {
"service_name": "deckcraft",
"container_name": "deckcraft",
"image": {
"reference": "docker.io/junkerderprovinz/deckcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/deckcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n deckcraft:\n image: junkerderprovinz/deckcraft:latest\n container_name: deckcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "deckcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "deckcraft",
"service_count": 1,
"services": [
{
"name": "deckcraft",
"image": "junkerderprovinz/deckcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/deckcraft:latest",
"container_name": "deckcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "deckcraft-volume-0",
"service": "deckcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "deckcraft-volume-1",
"service": "deckcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"deckcraft"
],
"stop_order": [
"deckcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-designcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "DesignCraft",
"es_ES": "DesignCraft"
},
"tagline": {
"en_US": "Page layout and publishing in your browser",
"es_ES": "Maquetación y publicación en el navegador"
},
"description": {
"en_US": "DesignCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "DesignCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/designcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/designcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/designcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/designcraft",
"readme_pushed_at": "",
"compose_sha256": "68fdc2548c3ecedc792ff41e1ce7002d8f0219e78781b89265ce77761685a0fd",
"generated_at": "2026-11-03T12:57:28+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/designcraft.yaml"
},
"container_contract": {
"service_name": "designcraft",
"container_name": "designcraft",
"image": {
"reference": "docker.io/junkerderprovinz/designcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/designcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n designcraft:\n image: junkerderprovinz/designcraft:latest\n container_name: designcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "designcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "designcraft",
"service_count": 1,
"services": [
{
"name": "designcraft",
"image": "junkerderprovinz/designcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/designcraft:latest",
"container_name": "designcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "designcraft-volume-0",
"service": "designcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "designcraft-volume-1",
"service": "designcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"designcraft"
],
"stop_order": [
"designcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-effectcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "EffectCraft",
"es_ES": "EffectCraft"
},
"tagline": {
"en_US": "Motion graphics and compositing in your browser",
"es_ES": "Animación gráfica y composición en el navegador"
},
"description": {
"en_US": "EffectCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "EffectCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/effectcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/effectcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/effectcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/effectcraft",
"readme_pushed_at": "",
"compose_sha256": "8dde56d083a5120e342967f15141e95d742d19ea0c6b782c5552d40438b46ef7",
"generated_at": "2026-11-03T12:57:28+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/effectcraft.yaml"
},
"container_contract": {
"service_name": "effectcraft",
"container_name": "effectcraft",
"image": {
"reference": "docker.io/junkerderprovinz/effectcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/effectcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n effectcraft:\n image: junkerderprovinz/effectcraft:latest\n container_name: effectcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "effectcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "effectcraft",
"service_count": 1,
"services": [
{
"name": "effectcraft",
"image": "junkerderprovinz/effectcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/effectcraft:latest",
"container_name": "effectcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "effectcraft-volume-0",
"service": "effectcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "effectcraft-volume-1",
"service": "effectcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"effectcraft"
],
"stop_order": [
"effectcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-figcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "FigCraft",
"es_ES": "FigCraft"
},
"tagline": {
"en_US": "Interface design and prototyping in your browser",
"es_ES": "Diseño de interfaces y prototipos en el navegador"
},
"description": {
"en_US": "FigCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "FigCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/figcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/figcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/figcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/figcraft",
"readme_pushed_at": "",
"compose_sha256": "b47cfa4e01943f509964b0027b9385d00fe6d233d31e24cdc117a4a4dd153262",
"generated_at": "2026-11-03T12:57:28+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/figcraft.yaml"
},
"container_contract": {
"service_name": "figcraft",
"container_name": "figcraft",
"image": {
"reference": "docker.io/junkerderprovinz/figcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/figcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n figcraft:\n image: junkerderprovinz/figcraft:latest\n container_name: figcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "figcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "figcraft",
"service_count": 1,
"services": [
{
"name": "figcraft",
"image": "junkerderprovinz/figcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/figcraft:latest",
"container_name": "figcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "figcraft-volume-0",
"service": "figcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "figcraft-volume-1",
"service": "figcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"figcraft"
],
"stop_order": [
"figcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-filmcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "FilmCraft",
"es_ES": "FilmCraft"
},
"tagline": {
"en_US": "Video editing in your browser",
"es_ES": "Edición de vídeo en el navegador"
},
"description": {
"en_US": "FilmCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "FilmCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/filmcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/filmcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/filmcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/filmcraft",
"readme_pushed_at": "",
"compose_sha256": "fa1e82ca686a530579d91c9d75184adb800453607baee37ad15ac3cfbf39d746",
"generated_at": "2026-11-03T12:57:28+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/filmcraft.yaml"
},
"container_contract": {
"service_name": "filmcraft",
"container_name": "filmcraft",
"image": {
"reference": "docker.io/junkerderprovinz/filmcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/filmcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n filmcraft:\n image: junkerderprovinz/filmcraft:latest\n container_name: filmcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "filmcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "filmcraft",
"service_count": 1,
"services": [
{
"name": "filmcraft",
"image": "junkerderprovinz/filmcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/filmcraft:latest",
"container_name": "filmcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "filmcraft-volume-0",
"service": "filmcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "filmcraft-volume-1",
"service": "filmcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"filmcraft"
],
"stop_order": [
"filmcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-gridcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "GridCraft",
"es_ES": "GridCraft"
},
"tagline": {
"en_US": "Spreadsheets in your browser",
"es_ES": "Hojas de cálculo en el navegador"
},
"description": {
"en_US": "GridCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "GridCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/gridcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/gridcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/gridcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/gridcraft",
"readme_pushed_at": "",
"compose_sha256": "dcd244dd54033b4a00e1220ff8885ba26a5508414ab5069f7ab9456476fbb420",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/gridcraft.yaml"
},
"container_contract": {
"service_name": "gridcraft",
"container_name": "gridcraft",
"image": {
"reference": "docker.io/junkerderprovinz/gridcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/gridcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n gridcraft:\n image: junkerderprovinz/gridcraft:latest\n container_name: gridcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "gridcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "gridcraft",
"service_count": 1,
"services": [
{
"name": "gridcraft",
"image": "junkerderprovinz/gridcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/gridcraft:latest",
"container_name": "gridcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "gridcraft-volume-0",
"service": "gridcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "gridcraft-volume-1",
"service": "gridcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"gridcraft"
],
"stop_order": [
"gridcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-lightcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "LightCraft",
"es_ES": "LightCraft"
},
"tagline": {
"en_US": "Photo library and RAW development in your browser",
"es_ES": "Biblioteca de fotos y revelado RAW en el navegador"
},
"description": {
"en_US": "LightCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "LightCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/lightcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/lightcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/lightcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/lightcraft",
"readme_pushed_at": "",
"compose_sha256": "26d20ee6d028b198f569b66116ff5b55d7ab08f2cc26a13400d0e444ce10ba0f",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/lightcraft.yaml"
},
"container_contract": {
"service_name": "lightcraft",
"container_name": "lightcraft",
"image": {
"reference": "docker.io/junkerderprovinz/lightcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/lightcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n lightcraft:\n image: junkerderprovinz/lightcraft:latest\n container_name: lightcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "lightcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "lightcraft",
"service_count": 1,
"services": [
{
"name": "lightcraft",
"image": "junkerderprovinz/lightcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/lightcraft:latest",
"container_name": "lightcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "lightcraft-volume-0",
"service": "lightcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "lightcraft-volume-1",
"service": "lightcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"lightcraft"
],
"stop_order": [
"lightcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-pdfcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "PdfCraft",
"es_ES": "PdfCraft"
},
"tagline": {
"en_US": "Read and edit PDF documents in your browser",
"es_ES": "Lectura y edición de documentos PDF en el navegador"
},
"description": {
"en_US": "PdfCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "PdfCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/pdfcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/pdfcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/pdfcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/pdfcraft",
"readme_pushed_at": "",
"compose_sha256": "4416cf187df8cccbc11fc14af6e4d5155cd386871f9514ae1ca10968a8b4a372",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/pdfcraft.yaml"
},
"container_contract": {
"service_name": "pdfcraft",
"container_name": "pdfcraft",
"image": {
"reference": "docker.io/junkerderprovinz/pdfcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/pdfcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n pdfcraft:\n image: junkerderprovinz/pdfcraft:latest\n container_name: pdfcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "pdfcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "pdfcraft",
"service_count": 1,
"services": [
{
"name": "pdfcraft",
"image": "junkerderprovinz/pdfcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/pdfcraft:latest",
"container_name": "pdfcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "pdfcraft-volume-0",
"service": "pdfcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "pdfcraft-volume-1",
"service": "pdfcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"pdfcraft"
],
"stop_order": [
"pdfcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-photocraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "PhotoCraft",
"es_ES": "PhotoCraft"
},
"tagline": {
"en_US": "Photo editing in your browser",
"es_ES": "Edición de fotos en el navegador"
},
"description": {
"en_US": "PhotoCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "PhotoCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/photocraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/photocraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/photocraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/photocraft",
"readme_pushed_at": "",
"compose_sha256": "459ac4e3adbd7544f3d0acb2f34230e8a396566ff910288898f689d54a78e722",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/photocraft.yaml"
},
"container_contract": {
"service_name": "photocraft",
"container_name": "photocraft",
"image": {
"reference": "docker.io/junkerderprovinz/photocraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/photocraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n photocraft:\n image: junkerderprovinz/photocraft:latest\n container_name: photocraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "photocraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "photocraft",
"service_count": 1,
"services": [
{
"name": "photocraft",
"image": "junkerderprovinz/photocraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/photocraft:latest",
"container_name": "photocraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "photocraft-volume-0",
"service": "photocraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "photocraft-volume-1",
"service": "photocraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"photocraft"
],
"stop_order": [
"photocraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-soundcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "SoundCraft",
"es_ES": "SoundCraft"
},
"tagline": {
"en_US": "Audio recording and mixing in your browser",
"es_ES": "Grabación y mezcla de audio en el navegador"
},
"description": {
"en_US": "SoundCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "SoundCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/soundcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/soundcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/soundcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/soundcraft",
"readme_pushed_at": "",
"compose_sha256": "8fef65b5330dd21035acbd8bc587c597610e6db5fdf8a70a07b54dcab25b3695",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/soundcraft.yaml"
},
"container_contract": {
"service_name": "soundcraft",
"container_name": "soundcraft",
"image": {
"reference": "docker.io/junkerderprovinz/soundcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/soundcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n soundcraft:\n image: junkerderprovinz/soundcraft:latest\n container_name: soundcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "soundcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "soundcraft",
"service_count": 1,
"services": [
{
"name": "soundcraft",
"image": "junkerderprovinz/soundcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/soundcraft:latest",
"container_name": "soundcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "soundcraft-volume-0",
"service": "soundcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "soundcraft-volume-1",
"service": "soundcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"soundcraft"
],
"stop_order": [
"soundcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-vectorcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "VectorCraft",
"es_ES": "VectorCraft"
},
"tagline": {
"en_US": "Vector illustration in your browser",
"es_ES": "Ilustración vectorial en el navegador"
},
"description": {
"en_US": "VectorCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "VectorCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/vectorcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/vectorcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/vectorcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/vectorcraft",
"readme_pushed_at": "",
"compose_sha256": "a62cf232ee367ccb49096aec28637b0e9b78fce44b52574a57fe05e918468a14",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/vectorcraft.yaml"
},
"container_contract": {
"service_name": "vectorcraft",
"container_name": "vectorcraft",
"image": {
"reference": "docker.io/junkerderprovinz/vectorcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/vectorcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n vectorcraft:\n image: junkerderprovinz/vectorcraft:latest\n container_name: vectorcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "vectorcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "vectorcraft",
"service_count": 1,
"services": [
{
"name": "vectorcraft",
"image": "junkerderprovinz/vectorcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/vectorcraft:latest",
"container_name": "vectorcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "vectorcraft-volume-0",
"service": "vectorcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "vectorcraft-volume-1",
"service": "vectorcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"vectorcraft"
],
"stop_order": [
"vectorcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-wordcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "WordCraft",
"es_ES": "WordCraft"
},
"tagline": {
"en_US": "Word processing in your browser",
"es_ES": "Procesador de textos en el navegador"
},
"description": {
"en_US": "WordCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "WordCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/wordcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/wordcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/wordcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/wordcraft",
"readme_pushed_at": "",
"compose_sha256": "cc6ac9c1448000c780e93d69e0ced1f39f3256fb2478fda4453442f62e2aa23f",
"generated_at": "2026-11-03T12:57:30+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/wordcraft.yaml"
},
"container_contract": {
"service_name": "wordcraft",
"container_name": "wordcraft",
"image": {
"reference": "docker.io/junkerderprovinz/wordcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/wordcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n wordcraft:\n image: junkerderprovinz/wordcraft:latest\n container_name: wordcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "wordcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "wordcraft",
"service_count": 1,
"services": [
{
"name": "wordcraft",
"image": "junkerderprovinz/wordcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/wordcraft:latest",
"container_name": "wordcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "wordcraft-volume-0",
"service": "wordcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "wordcraft-volume-1",
"service": "wordcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"wordcraft"
],
"stop_order": [
"wordcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-cadcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "CADCraft",
"es_ES": "CADCraft"
},
"tagline": {
"en_US": "Computer-aided design and drafting in your browser",
"es_ES": "Diseño CAD y dibujo técnico en el navegador"
},
"description": {
"en_US": "CADCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "CADCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/cadcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/cadcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/cadcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/cadcraft",
"readme_pushed_at": "",
"compose_sha256": "ab46cb8e87addb261680a50fc8bdde1f9d689a0d14f6ca570eaf11e43868655a",
"generated_at": "2026-11-03T12:57:27+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/cadcraft.yaml"
},
"container_contract": {
"service_name": "cadcraft",
"container_name": "cadcraft",
"image": {
"reference": "docker.io/junkerderprovinz/cadcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/cadcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n cadcraft:\n image: junkerderprovinz/cadcraft:latest\n container_name: cadcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "cadcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "cadcraft",
"service_count": 1,
"services": [
{
"name": "cadcraft",
"image": "junkerderprovinz/cadcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/cadcraft:latest",
"container_name": "cadcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "cadcraft-volume-0",
"service": "cadcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "cadcraft-volume-1",
"service": "cadcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"cadcraft"
],
"stop_order": [
"cadcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-deckcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "DeckCraft",
"es_ES": "DeckCraft"
},
"tagline": {
"en_US": "Presentations and slide decks in your browser",
"es_ES": "Presentaciones y diapositivas en el navegador"
},
"description": {
"en_US": "DeckCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "DeckCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/deckcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/deckcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/deckcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/deckcraft",
"readme_pushed_at": "",
"compose_sha256": "38d24b673dd5fb50e00d1094e681112671cf04a8e99952021f476c8b2754ef05",
"generated_at": "2026-11-03T12:57:28+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/deckcraft.yaml"
},
"container_contract": {
"service_name": "deckcraft",
"container_name": "deckcraft",
"image": {
"reference": "docker.io/junkerderprovinz/deckcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/deckcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n deckcraft:\n image: junkerderprovinz/deckcraft:latest\n container_name: deckcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "deckcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "deckcraft",
"service_count": 1,
"services": [
{
"name": "deckcraft",
"image": "junkerderprovinz/deckcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/deckcraft:latest",
"container_name": "deckcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "deckcraft-volume-0",
"service": "deckcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "deckcraft-volume-1",
"service": "deckcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"deckcraft"
],
"stop_order": [
"deckcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-designcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "DesignCraft",
"es_ES": "DesignCraft"
},
"tagline": {
"en_US": "Page layout and publishing in your browser",
"es_ES": "Maquetación y publicación en el navegador"
},
"description": {
"en_US": "DesignCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "DesignCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/designcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/designcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/designcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/designcraft",
"readme_pushed_at": "",
"compose_sha256": "68fdc2548c3ecedc792ff41e1ce7002d8f0219e78781b89265ce77761685a0fd",
"generated_at": "2026-11-03T12:57:28+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/designcraft.yaml"
},
"container_contract": {
"service_name": "designcraft",
"container_name": "designcraft",
"image": {
"reference": "docker.io/junkerderprovinz/designcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/designcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n designcraft:\n image: junkerderprovinz/designcraft:latest\n container_name: designcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "designcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "designcraft",
"service_count": 1,
"services": [
{
"name": "designcraft",
"image": "junkerderprovinz/designcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/designcraft:latest",
"container_name": "designcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "designcraft-volume-0",
"service": "designcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "designcraft-volume-1",
"service": "designcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"designcraft"
],
"stop_order": [
"designcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-effectcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "EffectCraft",
"es_ES": "EffectCraft"
},
"tagline": {
"en_US": "Motion graphics and compositing in your browser",
"es_ES": "Animación gráfica y composición en el navegador"
},
"description": {
"en_US": "EffectCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "EffectCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/effectcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/effectcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/effectcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/effectcraft",
"readme_pushed_at": "",
"compose_sha256": "8dde56d083a5120e342967f15141e95d742d19ea0c6b782c5552d40438b46ef7",
"generated_at": "2026-11-03T12:57:28+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/effectcraft.yaml"
},
"container_contract": {
"service_name": "effectcraft",
"container_name": "effectcraft",
"image": {
"reference": "docker.io/junkerderprovinz/effectcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/effectcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n effectcraft:\n image: junkerderprovinz/effectcraft:latest\n container_name: effectcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "effectcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "effectcraft",
"service_count": 1,
"services": [
{
"name": "effectcraft",
"image": "junkerderprovinz/effectcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/effectcraft:latest",
"container_name": "effectcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "effectcraft-volume-0",
"service": "effectcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "effectcraft-volume-1",
"service": "effectcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"effectcraft"
],
"stop_order": [
"effectcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-figcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "FigCraft",
"es_ES": "FigCraft"
},
"tagline": {
"en_US": "Interface design and prototyping in your browser",
"es_ES": "Diseño de interfaces y prototipos en el navegador"
},
"description": {
"en_US": "FigCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "FigCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/figcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/figcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/figcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/figcraft",
"readme_pushed_at": "",
"compose_sha256": "b47cfa4e01943f509964b0027b9385d00fe6d233d31e24cdc117a4a4dd153262",
"generated_at": "2026-11-03T12:57:28+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/figcraft.yaml"
},
"container_contract": {
"service_name": "figcraft",
"container_name": "figcraft",
"image": {
"reference": "docker.io/junkerderprovinz/figcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/figcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n figcraft:\n image: junkerderprovinz/figcraft:latest\n container_name: figcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "figcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "figcraft",
"service_count": 1,
"services": [
{
"name": "figcraft",
"image": "junkerderprovinz/figcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/figcraft:latest",
"container_name": "figcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "figcraft-volume-0",
"service": "figcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "figcraft-volume-1",
"service": "figcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"figcraft"
],
"stop_order": [
"figcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-filmcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "FilmCraft",
"es_ES": "FilmCraft"
},
"tagline": {
"en_US": "Video editing in your browser",
"es_ES": "Edición de vídeo en el navegador"
},
"description": {
"en_US": "FilmCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "FilmCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/filmcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/filmcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/filmcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/filmcraft",
"readme_pushed_at": "",
"compose_sha256": "fa1e82ca686a530579d91c9d75184adb800453607baee37ad15ac3cfbf39d746",
"generated_at": "2026-11-03T12:57:28+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/filmcraft.yaml"
},
"container_contract": {
"service_name": "filmcraft",
"container_name": "filmcraft",
"image": {
"reference": "docker.io/junkerderprovinz/filmcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/filmcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n filmcraft:\n image: junkerderprovinz/filmcraft:latest\n container_name: filmcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "filmcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "filmcraft",
"service_count": 1,
"services": [
{
"name": "filmcraft",
"image": "junkerderprovinz/filmcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/filmcraft:latest",
"container_name": "filmcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "filmcraft-volume-0",
"service": "filmcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "filmcraft-volume-1",
"service": "filmcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"filmcraft"
],
"stop_order": [
"filmcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-gridcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "GridCraft",
"es_ES": "GridCraft"
},
"tagline": {
"en_US": "Spreadsheets in your browser",
"es_ES": "Hojas de cálculo en el navegador"
},
"description": {
"en_US": "GridCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "GridCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/gridcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/gridcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/gridcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/gridcraft",
"readme_pushed_at": "",
"compose_sha256": "dcd244dd54033b4a00e1220ff8885ba26a5508414ab5069f7ab9456476fbb420",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/gridcraft.yaml"
},
"container_contract": {
"service_name": "gridcraft",
"container_name": "gridcraft",
"image": {
"reference": "docker.io/junkerderprovinz/gridcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/gridcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n gridcraft:\n image: junkerderprovinz/gridcraft:latest\n container_name: gridcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "gridcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "gridcraft",
"service_count": 1,
"services": [
{
"name": "gridcraft",
"image": "junkerderprovinz/gridcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/gridcraft:latest",
"container_name": "gridcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "gridcraft-volume-0",
"service": "gridcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "gridcraft-volume-1",
"service": "gridcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"gridcraft"
],
"stop_order": [
"gridcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-lightcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "LightCraft",
"es_ES": "LightCraft"
},
"tagline": {
"en_US": "Photo library and RAW development in your browser",
"es_ES": "Biblioteca de fotos y revelado RAW en el navegador"
},
"description": {
"en_US": "LightCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "LightCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/lightcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/lightcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/lightcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/lightcraft",
"readme_pushed_at": "",
"compose_sha256": "26d20ee6d028b198f569b66116ff5b55d7ab08f2cc26a13400d0e444ce10ba0f",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/lightcraft.yaml"
},
"container_contract": {
"service_name": "lightcraft",
"container_name": "lightcraft",
"image": {
"reference": "docker.io/junkerderprovinz/lightcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/lightcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n lightcraft:\n image: junkerderprovinz/lightcraft:latest\n container_name: lightcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "lightcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "lightcraft",
"service_count": 1,
"services": [
{
"name": "lightcraft",
"image": "junkerderprovinz/lightcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/lightcraft:latest",
"container_name": "lightcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "lightcraft-volume-0",
"service": "lightcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "lightcraft-volume-1",
"service": "lightcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"lightcraft"
],
"stop_order": [
"lightcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-pdfcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "PdfCraft",
"es_ES": "PdfCraft"
},
"tagline": {
"en_US": "Read and edit PDF documents in your browser",
"es_ES": "Lectura y edición de documentos PDF en el navegador"
},
"description": {
"en_US": "PdfCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "PdfCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/pdfcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/pdfcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/pdfcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/pdfcraft",
"readme_pushed_at": "",
"compose_sha256": "4416cf187df8cccbc11fc14af6e4d5155cd386871f9514ae1ca10968a8b4a372",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/pdfcraft.yaml"
},
"container_contract": {
"service_name": "pdfcraft",
"container_name": "pdfcraft",
"image": {
"reference": "docker.io/junkerderprovinz/pdfcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/pdfcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n pdfcraft:\n image: junkerderprovinz/pdfcraft:latest\n container_name: pdfcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "pdfcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "pdfcraft",
"service_count": 1,
"services": [
{
"name": "pdfcraft",
"image": "junkerderprovinz/pdfcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/pdfcraft:latest",
"container_name": "pdfcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "pdfcraft-volume-0",
"service": "pdfcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "pdfcraft-volume-1",
"service": "pdfcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"pdfcraft"
],
"stop_order": [
"pdfcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-photocraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "PhotoCraft",
"es_ES": "PhotoCraft"
},
"tagline": {
"en_US": "Photo editing in your browser",
"es_ES": "Edición de fotos en el navegador"
},
"description": {
"en_US": "PhotoCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "PhotoCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/photocraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/photocraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/photocraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/photocraft",
"readme_pushed_at": "",
"compose_sha256": "459ac4e3adbd7544f3d0acb2f34230e8a396566ff910288898f689d54a78e722",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/photocraft.yaml"
},
"container_contract": {
"service_name": "photocraft",
"container_name": "photocraft",
"image": {
"reference": "docker.io/junkerderprovinz/photocraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/photocraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n photocraft:\n image: junkerderprovinz/photocraft:latest\n container_name: photocraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "photocraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "photocraft",
"service_count": 1,
"services": [
{
"name": "photocraft",
"image": "junkerderprovinz/photocraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/photocraft:latest",
"container_name": "photocraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "photocraft-volume-0",
"service": "photocraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "photocraft-volume-1",
"service": "photocraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"photocraft"
],
"stop_order": [
"photocraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-soundcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "SoundCraft",
"es_ES": "SoundCraft"
},
"tagline": {
"en_US": "Audio recording and mixing in your browser",
"es_ES": "Grabación y mezcla de audio en el navegador"
},
"description": {
"en_US": "SoundCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "SoundCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/soundcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/soundcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/soundcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/soundcraft",
"readme_pushed_at": "",
"compose_sha256": "8fef65b5330dd21035acbd8bc587c597610e6db5fdf8a70a07b54dcab25b3695",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/soundcraft.yaml"
},
"container_contract": {
"service_name": "soundcraft",
"container_name": "soundcraft",
"image": {
"reference": "docker.io/junkerderprovinz/soundcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/soundcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n soundcraft:\n image: junkerderprovinz/soundcraft:latest\n container_name: soundcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "soundcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "soundcraft",
"service_count": 1,
"services": [
{
"name": "soundcraft",
"image": "junkerderprovinz/soundcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/soundcraft:latest",
"container_name": "soundcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "soundcraft-volume-0",
"service": "soundcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "soundcraft-volume-1",
"service": "soundcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"soundcraft"
],
"stop_order": [
"soundcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-vectorcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "VectorCraft",
"es_ES": "VectorCraft"
},
"tagline": {
"en_US": "Vector illustration in your browser",
"es_ES": "Ilustración vectorial en el navegador"
},
"description": {
"en_US": "VectorCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "VectorCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/vectorcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/vectorcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/vectorcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/vectorcraft",
"readme_pushed_at": "",
"compose_sha256": "a62cf232ee367ccb49096aec28637b0e9b78fce44b52574a57fe05e918468a14",
"generated_at": "2026-11-03T12:57:29+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/vectorcraft.yaml"
},
"container_contract": {
"service_name": "vectorcraft",
"container_name": "vectorcraft",
"image": {
"reference": "docker.io/junkerderprovinz/vectorcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/vectorcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n vectorcraft:\n image: junkerderprovinz/vectorcraft:latest\n container_name: vectorcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "vectorcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "vectorcraft",
"service_count": 1,
"services": [
{
"name": "vectorcraft",
"image": "junkerderprovinz/vectorcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/vectorcraft:latest",
"container_name": "vectorcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "vectorcraft-volume-0",
"service": "vectorcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "vectorcraft-volume-1",
"service": "vectorcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"vectorcraft"
],
"stop_order": [
"vectorcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+564
View File
@@ -0,0 +1,564 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-wordcraft",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "WordCraft",
"es_ES": "WordCraft"
},
"tagline": {
"en_US": "Word processing in your browser",
"es_ES": "Procesador de textos en el navegador"
},
"description": {
"en_US": "WordCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"es_ES": "WordCraft del proyecto ArtCraft, con su aplicación nativa de Linux transmitida al navegador mediante la imagen comunitaria de junkerderprovinz. Los documentos se guardan en el servidor, no en el almacenamiento del navegador."
},
"category": "creative",
"category_label": "Creative & Design",
"author": "junkerderprovinz",
"developer": "ArtCraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/wordcraft.png",
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://getartcraft.com/apps/wordcraft",
"documentation": "https://github.com/junkerderprovinz/artcraft-apps",
"repository": "https://github.com/storytold/wordcraft",
"tips": [
"This is the native Linux application streamed by Selkies, not the WebAssembly build. Processing and documents stay in the LXC and its mounted directories.",
"The image is maintained by junkerderprovinz; ArtCraft publishes the application packages. It is not an official ArtCraft container image.",
"Use a trusted HTTPS reverse proxy for browser access. Port 3001 uses the upstream self-signed certificate; port 3000 is for an HTTP reverse-proxy backend.",
"The upstream default has no login. Optional CUSTOM_USER and PASSWORD variables enable HTTP basic authentication; do not expose an unauthenticated desktop to untrusted networks.",
"/config holds settings and desktop state and is included in Proxmox backups. /storage holds documents and supports a managed volume or an explicitly selected host directory; host directories require separate backups.",
"The default uses software rendering. GPU acceleration and other CPU architectures are not claimed tested by a CPU-only amd64 installation.",
"Without an assigned GPU, an application may ask to switch to CPU rendering. Choose the CPU option; hardware acceleration is not required for the default configuration."
],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "junkerderprovinz",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"revision": "32bee0dea9bdaf5310c693210bea0d732a129ae8",
"image_repository_url": "https://hub.docker.com/r/junkerderprovinz/wordcraft",
"readme_pushed_at": "",
"compose_sha256": "cc6ac9c1448000c780e93d69e0ced1f39f3256fb2478fda4453442f62e2aa23f",
"generated_at": "2026-11-03T12:57:30+00:00",
"default_branch": "main",
"readme_raw_url": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/compose/wordcraft.yaml"
},
"container_contract": {
"service_name": "wordcraft",
"container_name": "wordcraft",
"image": {
"reference": "docker.io/junkerderprovinz/wordcraft:latest",
"registry": "docker.io",
"repository": "junkerderprovinz/wordcraft",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Europe/Vienna",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "UMASK",
"example": "022",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "CUSTOM_USER",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "upstream-documentation"
}
],
"volumes": [
{
"id": "config",
"container_path": "/config",
"compose_source_example": "./appdata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "storage",
"container_path": "/storage",
"compose_source_example": "./storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "services:\n wordcraft:\n image: junkerderprovinz/wordcraft:latest\n container_name: wordcraft\n restart: unless-stopped\n shm_size: 1gb\n ports:\n - 3001:3001\n - 3000:3000\n volumes:\n - ./appdata:/config\n - ./storage:/storage\n environment:\n TZ: Europe/Vienna\n PUID: '1000'\n PGID: '1000'\n UMASK: '022'\n"
},
"compose_stack": {
"project_name": "wordcraft",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "wordcraft",
"service_count": 1,
"services": [
{
"name": "wordcraft",
"image": "junkerderprovinz/wordcraft:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "junkerderprovinz/wordcraft:latest",
"container_name": "wordcraft",
"restart": "unless-stopped",
"shm_size": "1gb",
"ports": [
"3001:3001",
"3000:3000"
],
"volumes": [
"./appdata:/config",
"./storage:/storage"
],
"environment": {
"TZ": "Europe/Vienna",
"PUID": "1000",
"PGID": "1000",
"UMASK": "022"
}
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "wordcraft-volume-0",
"service": "wordcraft",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "wordcraft-volume-1",
"service": "wordcraft",
"container_path": "/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"wordcraft"
],
"stop_order": [
"wordcraft"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "https://github.com/junkerderprovinz/artcraft-apps"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"volume_preparations": [
{
"container_path": "/config",
"remove_lost_found": true,
"owner_strategy": "mapped-root",
"only_when_mount_type": "managed-volume"
},
{
"container_path": "/storage",
"remove_lost_found": true,
"owner_strategy": "mapped-application-user"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 3000,
"path": "/",
"timeout_seconds": 240,
"request_timeout_seconds": 5,
"stability_seconds": 8,
"accept_any_status": true,
"verify_tls": true
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux keeps the LXC unprivileged by default and exposes the broad Compose privilege request only as an explicit compatibility option.",
"reason": "A Compose privilege request is source metadata, not proof that the image technically requires a privileged LXC.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"stop_signal",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Community native-desktop image contract reviewed against its published Compose and Dockerfile. Linux amd64 and arm64 manifests exist; runtime, storage and lifecycle tests remain pending per architecture."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+416
View File
@@ -18733,6 +18733,422 @@
"requires_security_confirmation": false,
"hidden": true,
"template_id": "image-ztnet"
},
{
"id": "cadcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "CADCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "CADCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/cadcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/cadcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/cadcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/cadcraft.json",
"template_id": "image-cadcraft",
"template": "apps/cadcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "deckcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "DeckCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "DeckCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/deckcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/deckcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/deckcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/deckcraft.json",
"template_id": "image-deckcraft",
"template": "apps/deckcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "designcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "DesignCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "DesignCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/designcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/designcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/designcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/designcraft.json",
"template_id": "image-designcraft",
"template": "apps/designcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "effectcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "EffectCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "EffectCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/effectcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/effectcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/effectcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/effectcraft.json",
"template_id": "image-effectcraft",
"template": "apps/effectcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "figcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "FigCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "FigCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/figcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/figcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/figcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/figcraft.json",
"template_id": "image-figcraft",
"template": "apps/figcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "filmcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "FilmCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "FilmCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/filmcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/filmcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/filmcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/filmcraft.json",
"template_id": "image-filmcraft",
"template": "apps/filmcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "gridcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "GridCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "GridCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/gridcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/gridcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/gridcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/gridcraft.json",
"template_id": "image-gridcraft",
"template": "apps/gridcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "lightcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "LightCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "LightCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/lightcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/lightcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/lightcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/lightcraft.json",
"template_id": "image-lightcraft",
"template": "apps/lightcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "pdfcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "PdfCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "PdfCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/pdfcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/pdfcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/pdfcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/pdfcraft.json",
"template_id": "image-pdfcraft",
"template": "apps/pdfcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "photocraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "PhotoCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "PhotoCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/photocraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/photocraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/photocraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/photocraft.json",
"template_id": "image-photocraft",
"template": "apps/photocraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "soundcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "SoundCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "SoundCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/soundcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/soundcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/soundcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/soundcraft.json",
"template_id": "image-soundcraft",
"template": "apps/soundcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "vectorcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "VectorCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "VectorCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/vectorcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/vectorcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/vectorcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/vectorcraft.json",
"template_id": "image-vectorcraft",
"template": "apps/vectorcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
},
{
"id": "wordcraft",
"provider": "junkerderprovinz",
"template_family": "curated-profile",
"title": "WordCraft",
"repository": "https://github.com/junkerderprovinz/artcraft-apps",
"description": "WordCraft from the ArtCraft project, streamed from a native Linux application using the community-maintained junkerderprovinz image. Files are stored on the server, not in browser storage.",
"website": "https://getartcraft.com/apps/wordcraft",
"icon": "https://raw.githubusercontent.com/junkerderprovinz/artcraft-apps/32bee0dea9bdaf5310c693210bea0d732a129ae8/.github/assets/icons/wordcraft.png",
"architectures": [
"amd64",
"arm64"
],
"updated_at": null,
"main_image": "docker.io/junkerderprovinz/wordcraft:latest",
"category": "creative",
"category_label": "Creative & Design",
"replaces_discovered_ids": [],
"curated_path": "catalog/curated/wordcraft.json",
"template_id": "image-wordcraft",
"template": "apps/wordcraft.json",
"template_status": "generated-unvalidated",
"automatic_install_candidate": true,
"untranslated_blockers": [],
"requires_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"requires_security_confirmation": false,
"hidden": false
}
],
"discovery": {
+39
View File
@@ -115,6 +115,45 @@
],
"unpackerr": [
"/data"
],
"cadcraft": [
"/storage"
],
"deckcraft": [
"/storage"
],
"designcraft": [
"/storage"
],
"effectcraft": [
"/storage"
],
"figcraft": [
"/storage"
],
"filmcraft": [
"/storage"
],
"gridcraft": [
"/storage"
],
"lightcraft": [
"/storage"
],
"pdfcraft": [
"/storage"
],
"photocraft": [
"/storage"
],
"soundcraft": [
"/storage"
],
"vectorcraft": [
"/storage"
],
"wordcraft": [
"/storage"
]
},
"sizes": {
+65
View File
@@ -0,0 +1,65 @@
"""Shared files, image identity and desktop runtime survive catalog composition."""
import json
from pathlib import Path
import sys
import unittest
from unittest.mock import patch
ROOT=Path(__file__).resolve().parents[1]
sys.path[:0]=[str(ROOT/'src'),str(ROOT/'remote'),str(ROOT/'tests')]
from proxmenux_oci.catalog import Catalog
from proxmenux_oci.custom import template_from_oci_compose
from proxmenux_oci.installer import build_deployment,DEFAULT_MODE,ADVANCED_MODE
from test_advanced_flow_order import RecordingUI,storages,addresses
APPS=('cadcraft','deckcraft','designcraft','effectcraft','figcraft','filmcraft','gridcraft','lightcraft','pdfcraft','photocraft','soundcraft','vectorcraft','wordcraft')
class ArtCraftRecipeTests(unittest.TestCase):
def test_native_images_remain_distinct_from_flatpak_and_wasm_builds(self):
catalog=Catalog(ROOT)
for app in APPS:
with self.subTest(app=app):
t=catalog.compose(app);catalog.validate(t)
self.assertEqual(t['container_contract']['image']['reference'],'docker.io/junkerderprovinz/'+app+':latest')
self.assertEqual(t['catalog_ui']['author'],'junkerderprovinz')
self.assertEqual(t['catalog_ui']['repository'],'https://github.com/storytold/'+app)
self.assertEqual(t['catalog_ui']['architectures'],['amd64','arm64'])
self.assertEqual(t['proxmox']['image_metadata_policy']['entrypoint'],'import-from-oci-image')
self.assertTrue(t['catalog_ui']['icon'].endswith('/'+app+'.png'))
self.assertFalse(t['compatibility']['validated'])
def test_import_preserves_document_storage_backup_and_runtime_mounts(self):
catalog=Catalog(ROOT)
for app in APPS:
with self.subTest(app=app):
t=template_from_oci_compose(json.dumps(catalog.compose(app)));catalog.validate(t)
volumes={m['container_path']:m for m in t['container_contract']['volumes']}
self.assertEqual(set(volumes),{'/config','/storage'})
self.assertEqual(volumes['/config']['installation_choice'],['managed-volume'])
self.assertEqual(volumes['/storage']['installation_choice'],['managed-volume','host-bind'])
self.assertTrue(all(m['managed_volume']['backup'] and not m['read_only'] for m in volumes.values()))
runtime={m['container_path']:m for m in t['proxmox']['installer_profile']['tmpfs_mounts']}
self.assertEqual(runtime['/dev/shm']['default_size_mb'],1024)
self.assertIn('/run/nginx',runtime)
self.assertEqual(t['proxmox']['installer_profile']['startup_healthcheck']['port'],3000)
self.assertEqual(t['catalog_ui']['launch']['port'],3001)
def test_both_wizards_offer_shared_documents_without_exposing_private_config(self):
from contextlib import ExitStack
with ExitStack() as stack:
for target,value in [('proxmenux_oci.installer.host.storages',storages),('proxmenux_oci.installer.access.ask_addresses',addresses)]:stack.enter_context(patch(target,side_effect=value))
stack.enter_context(patch('proxmenux_oci.i18n.language',return_value='en'))
stack.enter_context(patch('proxmenux_oci.installer.host.bridges',return_value=[{'iface':'vmbr0','cidr':'192.0.2.10/24'}]))
stack.enter_context(patch('proxmenux_oci.installer.host.timezone',return_value='Europe/Madrid'))
stack.enter_context(patch('proxmenux_oci.installer.host.gpus',return_value={'intel':[],'amd':[],'nvidia':False}))
stack.enter_context(patch('proxmenux_oci.installer.access.ask_ipv4',return_value=('dhcp',None)))
for app in APPS:
for mode in (DEFAULT_MODE,ADVANCED_MODE):
with self.subTest(app=app,mode=mode):
plan=build_deployment(Catalog(ROOT).compose(app),RecordingUI({'Where to store /storage':'host-bind'}),mode)
mounts={m['container_path']:m for m in plan['mounts']}
self.assertEqual(mounts['/config']['type'],'managed-volume')
self.assertTrue(mounts['/config']['backup'])
self.assertEqual(mounts['/storage']['type'],'host-bind')
self.assertFalse(mounts['/storage']['backup'])
self.assertTrue(plan['security']['unprivileged'])
if __name__=='__main__':unittest.main()