core/skills/start/SKILL.md
Start a container as a background service. MUST be invoked before any work involving: charly 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, charly config <image> MUST be run first to generate the systemd quadlet unit. In direct mode, start creates an ephemeral container directly.
Relationship to charly bundle add — charly start <image> is the ergonomic wrapper for charly bundle add <image> <image> (container target). New scripts should prefer charly bundle add <name> <ref> directly when they need explicit deploy names, --add-candy overlays, or the host target. charly start covers the common single-image case and is retained for backwards compatibility. See /charly-core:deploy for the unified command family and /charly-local:local-deploy for the host target.
| Action | Command | Description |
|--------|---------|-------------|
| Start (quadlet) | charly start <image> | Start via systemd quadlet unit |
| Start (direct) | charly start <image> | Create ephemeral container (when run_mode=direct) |
| With specific tag | charly start <image> --tag TAG | Use specific image tag |
| Build first | charly start <image> --build | Build image before starting |
| Named instance | charly 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).
charly start reads only OCI labels (via ExtractMetadata) + charly.yml. It
does not touch charly.yml. Remote refs (@github.com/...) are rejected
with a redirect to charly box pull.
If the image isn't in local storage, startup fails with the standard
ErrImageNotLocal recommendation pointing to charly box pull. See
/charly-build:pull.
In quadlet mode (default), charly config <image> MUST be run before charly start. If the quadlet file does not exist, start fails with:
not configured; run 'charly config <image>' first
The correct workflow is:
# Step 1: Configure (generates quadlet, provisions secrets, sets up volumes)
charly config sway-browser-vnc
# Step 2: Start
charly start sway-browser-vnc
# Configure first
charly config jupyter --bind workspace --password auto
# Start the service (systemctl --user start charly-jupyter.service)
charly 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 charly.yml). These are automatically cleaned up by ExecStopPost on service stop.
Quadlet auto-mount hook. Quadlets generated for encrypted-volume images carry an ExecStartPre=charly 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. If you have quadlets generated by an older charly, run charly migrate to regenerate them in place — see /charly-build:migrate "charly migrate". Direct-mode starts have a parallel safety net: verifyBindMounts fails loud when the cipher dir is populated and the plain mount is empty (see /charly-automation:enc "Pre-start safety check").
# Start with workspace and env vars
charly start jupyter -e JUPYTER_TOKEN=mytoken
# Start with port mapping
charly start jupyter -p 8888:8888
# Build the image first, then start
charly start jupyter --build
/charly-build:pull -- Required before charly start can work on a fresh host. charly start rejects remote refs (@github.com/...) — pull first./charly-core:charly-config -- MUST run first in quadlet mode (setup: quadlet + secrets + encrypted volumes)/charly-core:service -- Full service lifecycle (in-container supervisord/systemd services)/charly-core:stop -- Stop a running service/charly-core:charly-status -- Check service status/charly-core:charly-update -- Update image and restart/charly-core:logs -- View service logs/charly-core:shell -- Interactive shell into the same image/charly-core:deploy -- Tunnel configuration (ExecStartPost commands generated by quadlet)/charly-automation:enc -- Encrypted volume mount lifecycle (inline mount in direct mode, ExecStartPre=charly config mount in quadlet mode, short-circuit fast path)/charly-build:secrets -- Credential store hierarchy for encrypted volume passphrase resolution/charly-image:image -- Box definitions (ports, volumes, env) in charly.yml/charly-build:build -- Build the image you intend to start/charly-check:check 10 standards)Changes that touch this verb's output must reach a healthy deployment on a target explicitly marked disposable: true (see /charly-internals:disposable). Use charly update <name> to destroy + rebuild unattended on any disposable target. Never experiment on a non-disposable deploy — set up a disposable one first with charly bundle add <name> <ref> --disposable or mark a VM in vm.yml.
After committing the source-level fix, charly 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).