ov-core/skills/start/SKILL.md
Start a container as a background service. MUST be invoked before any work involving: ov start command, launching containers, quadlet vs direct mode startup, or encrypted volume auto-mounting.
npx skillsauth add overthinkos/overthink-plugins startInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Start a container image as a background service. In quadlet mode, ov config <image> MUST be run first to generate the systemd quadlet unit. In direct mode, start creates an ephemeral container directly.
Relationship to ov deploy add — ov start <image> is the ergonomic wrapper for ov deploy add <image> <image> (container target). New scripts should prefer ov deploy add <name> <ref> directly when they need explicit deploy names, --add-layer overlays, or the host target. ov start covers the common single-image case and is retained for backwards compatibility. See /ov-core:deploy for the unified command family and /ov-advanced:local-deploy for the host target.
| Action | Command | Description |
|--------|---------|-------------|
| Start (quadlet) | ov start <image> | Start via systemd quadlet unit |
| Start (direct) | ov start <image> | Create ephemeral container (when run_mode=direct) |
| With specific tag | ov start <image> --tag TAG | Use specific image tag |
| Build first | ov start <image> --build | Build image before starting |
| Named instance | ov start <image> -i INSTANCE | Start a named instance |
| Action | Flag | Description |
|--------|------|-------------|
| Bind volume | --bind name=path | Override volume backing for session |
| Volume config | -v name:type[:path] | Configure volume backing |
| Environment | -e KEY=VALUE | Set environment variable |
| Env file | --env-file PATH | Load environment from file |
| Port mapping | -p PORT | Additional port mapping |
Note: -e flags use Kong sep:"none" — commas in values are preserved (e.g., NO_PROXY=localhost,127.0.0.1).
ov start reads only OCI labels (via ExtractMetadata) + deploy.yml. It
does not touch image.yml. Remote refs (@github.com/...) are rejected
with a redirect to ov image pull.
If the image isn't in local storage, startup fails with the standard
ErrImageNotLocal recommendation pointing to ov image pull. See
/ov-build:pull.
In quadlet mode (default), ov config <image> MUST be run before ov start. If the quadlet file does not exist, start fails with:
not configured; run 'ov config <image>' first
The correct workflow is:
# Step 1: Configure (generates quadlet, provisions secrets, sets up volumes)
ov config sway-browser-vnc
# Step 2: Start
ov start sway-browser-vnc
# Configure first
ov config jupyter --bind workspace --password auto
# Start the service (systemctl --user start ov-jupyter.service)
ov start jupyter
Encrypted volumes declared in the image are auto-mounted at start time. In quadlet mode, ExecStartPost commands in the quadlet file register Tailscale serve/funnel rules (if tunnel is configured in deploy.yml). These are automatically cleaned up by ExecStopPost on service stop.
Quadlet auto-mount hook (added 2026-04-16). Quadlets generated for encrypted-volume images now carry an ExecStartPre=ov config mount <image> directive. Without it, a host reboot or any other event that drops the gocryptfs FUSE mount would let systemd start the container against an empty plain/ mountpoint — at which point the container would write plaintext data on top of the populated cipher tree (the actual root cause of the 2026-04-18 immich incident). If you have quadlets generated by an older ov, run ov migrate quadlets to regenerate them in place — see /ov-build:migrate "ov migrate quadlets". Direct-mode starts have a parallel safety net: verifyBindMounts fails loud when the cipher dir is populated and the plain mount is empty (see /ov-advanced:enc "Pre-start safety check").
# Start with workspace and env vars
ov start jupyter -e JUPYTER_TOKEN=mytoken
# Start with port mapping
ov start jupyter -p 8888:8888
# Build the image first, then start
ov start jupyter --build
/ov-build:pull -- Required before ov start can work on a fresh host. Rejects remote refs that pre-refactor ov start used to accept./ov-core:config -- MUST run first in quadlet mode (setup: quadlet + secrets + encrypted volumes)/ov-core:service -- Full service lifecycle (in-container supervisord/systemd services)/ov-core:stop -- Stop a running service/ov-core:status -- Check service status/ov-core:update -- Update image and restart/ov-core:logs -- View service logs/ov-core:shell -- Interactive shell into the same image/ov-core:deploy -- Tunnel configuration (ExecStartPost commands generated by quadlet)/ov-advanced:enc -- Encrypted volume mount lifecycle (inline mount in direct mode, ExecStartPre=ov config mount in quadlet mode, short-circuit fast path)/ov-build:secrets -- Credential store hierarchy for encrypted volume passphrase resolution/ov-build:image -- Image definitions (ports, volumes, env) in image.yml/ov-build:build -- Build the image you intend to start/ov-build:eval 10 standards)Changes that touch this verb's output must reach a healthy deployment on a target explicitly marked disposable: true (see /ov-dev:disposable). Use ov update <name> to destroy + rebuild unattended on any disposable target. Never experiment on a non-disposable deploy — set up a disposable one first with ov deploy add <name> <ref> --disposable or mark a VM in vms.yml.
After committing the source-level fix, ov update the disposable target ONCE MORE from clean and re-run the full verification. A fix that passes only on a hand-patched target is not a real fix — it's a regression waiting for the next unrelated rebuild. Paste BOTH the exploratory-pass output and the fresh-rebuild-pass output into the conversation.
Unit tests + a clean compile are necessary but not sufficient. See CLAUDE.md R1–R10.
tools
Use when authoring or modifying a charly PLUGIN — a candy with a `plugin:` block that contributes Providers (verbs/kinds/deploy-targets/steps/builders/commands), its own CUE schema, builtin (compiled-in) or external (out-of-tree git repo). Covers the unified Provider model, the per-plugin CUE-schema contract (single source → Go params for dev + schema-over-Describe RPC for runtime), the SDK, and the loader.
tools
The CUE data-validation / configuration CLI (cue), pinned to v0.16.1. Use when working with the cue candy, installing the cue binary into a box or onto a target:local dev host, or running the offline schema-vendoring pipeline that feeds charly's egress validation.
tools
CUE EGRESS validation — validating (and, where it adds value, generating) the config files charly WRITES to a system BEFORE the bytes hit disk. MUST be invoked before working on charly/egress.go, the vendored schemas under candy/plugin-egress/egress-schemas/vendor/, the ValidateEgress / registerVendoredEgressKind path, the offline `task cue:vendor` pipeline, or adding an egress schema for any written artifact (cloud-init, k8s manifests, traefik routes, runtime config, install ledger, systemd/quadlet units, ssh_config, libvirt XML).
tools
Kubernetes cluster-probe declarative check verb — the `kube:` check verb (nodes, pods, ingress, storage class, addon health, apply/delete, and arbitrary resource GETs) served out-of-process by the candy/plugin-kube plugin (vendored client-go; no external kubectl required).