Deploy your code or any project to your Olares
Flags and syntax come from
olares-cli chart <verb> --help
. Read the shared
Olares platform model before porting: chart decisions depend on its storage, uid-1000, namespace, middleware and version semantics.
Authoring (
,
,
) is local-only. Building for a specific Olares needs the target node architecture before the first image build, and deployment needs the active profile.
Porting targets Olares 1.12.6+; load versioning before writing manifest/chart version and dependency fields.
When to use
- Turn a repo / docker-compose / generic Helm chart into an Olares app, or validate an OlaresManifest; package its image; wire storage / middleware / entrances / env / GPU
- Deploy / run the app on your own Olares ( + ); after identifies a chart-owned root cause, edit, lint, and redeploy the chart
- Serve a generation/chat model with an official base app, integrate , or route an embedding app to the appropriate Market install
This skill owns changes to your chart.
finds runtime root causes,
manages published apps,
configures and calls a model once its application is running, and
prepares a public listing.
The shape of the work — two axes
Porting an app is
not a fixed
from-compose → lint → deploy
pipeline — it is driving two
orthogonal but coupled axes each to its own
ready state, looping back as constraints surface (an image's baked-in uid/paths constrain the chart's mounts/permissions; a deploy constraint can send you back to rebuild the image). Start wherever your app already stands, not at a fixed step 1. Once both axes are ready,
deploy to the current Olares — an automatic upload + install + diagnose loop.
- Packaging — the image: the app built into a pullable, arch-correct artifact. Olares only pulls, never builds.
- Deployment — the chart: a -passing OlaresManifest + templates. is only one way in.
First move (not a pipeline): locate where the app already sits on the packaging and deployment state tables → drive the concerns to ready, looping as constraints surface → deploy to your Olares.
Axis 1 — Packaging (the image)
Olares
pulls images from a registry and never builds from source, so every workload must reference a publicly pullable, node-arch-correct image. Image work is
agent-driven: resolve the
target Olares node's architecture with
olares-cli cluster node list
, then ask which registry the developer uses (Docker Hub / ghcr), check docker is usable and logged in, and
build + push yourself — only
stays manual, and only when not already authenticated (
references/olares-chart-image.md). Build for the target node's arch (single-arch), never the development host's implicit/default arch; multi-arch is only for publishing.
The target architecture is a build input, so resolving it cannot be deferred. says what the chart
claims; nothing opens the image to check what it
is. A wrong guess therefore survives build, push and
, and first appears as
in the cluster — and on Apple Silicon an unresolved target silently becomes arm64. Query the node or have the developer state the arch; with
neither, ask instead of guessing. Only a chart nobody is deploying yet needs no target.
| Packaging state | Do this | Ready when |
|---|
| No Dockerfile (just source) | author a Dockerfile, then build+push | — |
| Dockerfile, but no pullable image | build+push (Docker Hub or ghcr) | — |
| A pullable image exists | check its arch; rebuild if it doesn't match the target Olares node (olares-cli cluster node list
) | every workload has a pullable, arch-correct image |
Axis 2 — Deployment (the chart)
The target is a
-passing Olares chart.
(kompose) is
just one entry method — a bare repo, a generic Helm chart, or an already-Olares chart each begin elsewhere (see the state table below). Local authoring (
/
/
) needs
no login.
| Deployment state | Do this | Ready when |
|---|
| Source only (no compose) | author a docker-compose from the code (compose.md) | — |
| A docker-compose | then refine (from-compose.md) | — |
| A generic Helm chart (no OlaresManifest) | hand-author + refine (skip ) | — |
| Uploaded to the Olares, but no local copy left | + unpack the , then refine that (olares-market, under → chart management) | — |
| Already an Olares chart | go straight to validation | a chart that passes |
Deploy to your Olares (the done step)
Both axes ready →
deploy to the current Olares automatically.
proves the chart is structurally valid; it does
not prove the app pulls its images, wires its middleware, and reaches
— the deploy loop does.
After passes, proceed without asking: check login → verify
intersects
→ package →
→
market install -s upload --watch
→ on failure fetch logs → diagnose → fix chart + re-lint → retry. An architecture upload rejection is terminal until the manifest/image changes; never bump and retry the unchanged package. Only stop to ask when the profile fails olares-shared's
auth-readiness gate (
/
) —
/
both proceed. Full procedure:
references/olares-chart-deploy.md.
For deploying to your own Olares,
metadata can stay a stub as long as
passes; functional refinement (storage / middleware / entrances) is still required.
Concern router
produces a skeleton that may lint without being a correct Olares app. Use this index to load only the references triggered by the current port. All 18 original concerns remain represented.
Every port
| Trigger | Read |
|---|
| Build or select every workload image | image |
| Decide process uid, then mounted-volume ownership — two independent questions, see below | run identity |
| Map persistence, entrances, metadata and workload replicas | manifest |
| Map configuration and platform values | environment, then defaults or system values only when needed |
| Handle passwords, API keys or generated keys | secrets |
| Set manifest/chart versions and dependencies | versioning |
| Validate after a chart change | lint |
| Prove the chart on the target Olares | deploy |
The manifest reference covers four concerns separately: storage, entrances/ports, workloads/replicas and metadata. Together with image, run identity, env, secrets, versioning, validation and deployment, these are the 11 concerns every port checks.
Run identity: answer two questions
Q1 (what uid the process ends up as) and Q2 (who owns the directories it writes) are independent: every Q1 answer can be paired with either Q2 answer. Answer both, then open the run identity reference for the how.
| Question | Answer | Do |
|---|
| Q1 What is the image's effective uid? | 1000 | ; on non-primary workloads also set securityContext.runAsUser: 1000
yourself |
| 0, and the entrypoint drops via / | Leave off, set , verify the final process |
| 0 and stays root, or any other non-1000 uid | Try securityContext.runAsUser: 1000
; if the app breaks, rebuild the image |
| Q2 Does it write a userspace mount? | no | Done |
| yes | Add a non-recursive initContainer ( image, container-level ) — on the / path read the startup log first, that entrypoint often does it already |
Two red lines: never
at runtime, and never set an explicit root
— the
permissions initContainer is the only exception.
Conditional
| Trigger | Read |
|---|
| Compose bundles a database/queue, or an app dependency is needed | middleware and dependencies |
| CUDA image, model provisioning or shared model cache | GPU and models |
| Generation/chat, custom , or embedding serving | model routing, model operations, custom integration |
| The model application is already running and serves the wrong thing | — the card inside it, not the chart |
| GPU/accelerator scheduling modes or resource envelope | accelerator |
| The app must run Docker or Compose | DinD |
| One heavy backend serves multiple users | shared backend |
| The running app needs a memorable route or custom FQDN | custom URL |
After
passes, drive the deploy/debug loop within the authorised chart task without asking at every install, upgrade, restart, uninstall or clean reinstall. Stop for login, missing registry credentials, an ambiguous target or work outside that task scope. The full assembly sequence is in
workflow.
CLI verbs
The only
subcommands (source of truth:
). Everything else above is docker or sibling skills.
| Verb | What it does | Reference |
|---|
| (alias ) | kompose-convert compose file(s) into an Olares chart skeleton | from-compose.md |
| validate a chart dir / with the Market ingest pipeline | lint.md |
| package a chart dir into a for upload (mirrors , no helm binary needed) | workflow.md (D4) |
Special porting patterns
Most of this skill assumes a web app with an HTTP entrance. When the upstream doesn't fit, match a known pattern first; if still unsure, see how the official ports solved it.
- Headless CLI / service (no web UI) — no GUI to point an entrance at: add a web-terminal sidecar as a visible entrance + expose the API/MCP port as an internal entrance. → archetype-headless.md
- GUI desktop app (browser-streamed) — a native Linux desktop app with no web UI: wrap it in a web-desktop base image (Selkies default, or KasmVNC for old hardware/static UIs), point one visible window entrance at HTTP , and device-gate optional iGPU/VAAPI acceleration on . → archetype-gui.md
- If no documented pattern fits, inspect a current active port in beclab/apps before guessing:
bash
gh search code --repo beclab/apps <keyword> # find charts using a pattern (e.g. type: application, accelerator, appCommon)
# then browse https://github.com/beclab/apps/tree/main/<app> — its OlaresManifest.yaml + templates/
Skip references that would mislead:
- Apps with a (or ) control file in the OAC root — suspended / no longer distributed; not a current, reliable pattern.
- Shared / cluster-scoped charts that express sharing with
spec.subCharts[].shared: true
+ options.appScope.clusterScoped: true
+ (the / shape). Copy the shared-app pattern from an app, not from these. See shared.md.
Gotchas (what won't catch)
validates structure, not Olares correctness. Beyond the concerns table above, these blind spots bite and are entirely on you:
- must match the chart folder and , and be . Keep equal to ( sets it). Rename all four together. does NOT require — a chart lints without it, but rejects a missing , so set it explicitly or a lint-clean chart still fails to upload. It does not decide the entrance host: the platform derives that from the app name, so read the real value from the column of rather than computing it.
- Cluster upload requires to intersect at least one current node architecture. Query
olares-cli cluster node list
; ensure the referenced images support the same target architecture. If upload reports architecture_incompatible
, fix and repackage before retrying. If it reports , keep the package/version unchanged and wait for node discovery to recover.
- Declared
.Values.userspace.appData
// mounts MUST have the matching field, or the app-data cross-check fails.
- volumes + rolling updates are incompatible — replace host mounts with the userspace volumes above.
- The entrance proxy caps every request at seconds (default 15s) — long LLM streams / big uploads / slow reports get cut at the entrance (504 / closed connection) even when the pod is healthy. Set to disable, or a large bounded value; a negative value is not "unlimited" (it falls back to 15s). See the Manifest refinement areas.