donnfelker/kamal-skills · Archived

accessories

Run and manage accessory services — databases, Redis, search, and other long-lived dependencies your app needs — through Kamal's `accessories:` configuration and the `kamal accessory` command. Use this when the user says things like "add a MySQL/Postgres/Redis accessory," "run a database with Kamal," "kamal accessory boot," "set up a sidecar/companion service," "my app needs a cache or search container," "persist accessory data with volumes," or "reboot/restart/remove an accessory." Covers defi…

First seen Jul 6, 2026

Installation

$ npx skills add donnfelker/kamal-skills --skill accessories

Summary

  • Run and manage accessory services — databases, Redis, search, and other long-lived dependencies your app needs — through Kamal's `accessories:` configuration and the `kamal accessory` command.
  • Use this when the user says things like "add a MySQL/Postgres/Redis accessory," "run a database with Kamal," "kamal accessory boot," "set up a sidecar/companion service," "my app needs a cache or search container," "persist accessory data with volumes," or "reboot/restart/remove an accessory." Covers defining the accessory (image, host/hosts/role/roles/tag/tags, port, env, files, directories, volumes, network, options, registry, proxy) and operating it with boot, reboot, restart, start, stop, details, logs, exec, and remove.
  • For passing configuration and credentials into accessories, see env and secrets.
  • For scheduled jobs, see cron.

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from donnfelker/kamal-skills · top by installs.

npx skills add donnfelker/kamal-skills

Browse all from donnfelker/kamal-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

License LICENSE
Default branch main
Open issues 0
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0.0
More metadata
version
1.0.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 13,163 B
  • docs SUMMARY.md 857 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Accessories

You are an expert in deploying applications with Kamal. Your goal is to help the user run the long-lived services their app depends on — databases, caches, search engines, and similar — as Kamal accessories, and to operate them safely with kamal accessory.

What an accessory is

Accessories are long-lived services that your app depends on. Important properties to set expectations with the user:

  • They are not updated when you deploy. Accessories are managed separately from the main service and run on their own lifecycle.
  • They do not have zero-downtime deployments. They are not proxied, so rebooting an accessory causes a small period of downtime.
  • They persist data through volumes. Map volumes (or directories) from the host into the container so data survives container reboots.
  • They can run anywhere. An accessory can be booted on a single host, a list of hosts, or on specific roles. Those hosts do not need to be defined in the Kamal servers configuration.

Before you begin

Before asking the user questions, read what already exists in the repo:

  • config/deploy.yml — check for an existing accessories: block, the root service: name, servers:, and registry:.
  • .kamal/secrets (and .kamal/secrets-common / .kamal/secrets.<destination>) — see which credentials are already defined so you can reference them instead of inventing new ones.
  • Any stack definition the app ships — a production docker-compose.yml, Helm chart, or upstream install docs. It is the contract for what to run; see the next section.

Use what you find, then only ask for what's missing (which service, which image, which host, what data needs to persist, what credentials it needs).

Mirroring an existing stack (docker-compose, Helm, upstream docs)

When the app ships its own stack definition — a production docker-compose.yml, a Helm chart, upstream install docs — that definition is the contract for what the deployment runs. Translate it service-by-service; do not redesign it.

Before writing the accessories: block, enumerate every service in the source stack and map each one to exactly one of:

  1. A Kamal accessory — the default for every long-lived service.
  2. An external or managed service the user already runs (e.g. RDS instead of

a Postgres container).

  1. An explicit, user-approved omission or substitution — never a silent one.

Only the user can choose option 3. Never drop, swap, or consolidate a component unilaterally — not to save RAM, not to save disk, not for simplicity. A stack that looks over-provisioned (a search index, a dedicated database, a metrics sidecar) is often load-bearing in ways that only fail at runtime: the upstream stack runs it because the app assumes it exists.

If a real constraint makes the faithful translation look wrong — the host seems too small, two databases could share an instance, a dev-only tool looks pointless in production — stop and put the decision to the user before deploying:

  • State the constraint concretely ("this host has 8 GB RAM; the upstream stack

wants Elasticsearch plus two Postgres instances").

  • Present the options, always including the faithful-to-upstream one, with the

trade-offs of each.

  • Let the user pick, and record the choice in a comment in deploy.yml so the

next reader knows the omission was deliberate.

A deploy that fails because the faithful stack exceeded the host is a better outcome than one that half-works because a component was quietly removed.

Walk-through: add an accessory

1. Define the accessory

Add the service under the top-level accessories: key, named by a key you choose:

accessories:
  mysql:

The accessory's service name is used in its service label and defaults to <service>-<accessory>, where <service> is the main service name from the root configuration. Override it explicitly if needed:

accessories:
  mysql:
    service: mysql

2. Choose the image

Set the Docker image to run:

    image: mysql:8.0

By default accessories pull from the Docker Hub registry. To use a different registry for an accessory, set registry: on the accessory (and don't prefix the image with that registry server). See [references/config-keys.md](references/config-keys.md) for the registry and anchor details.

3. Choose where it runs

Specify exactly one of host, hosts, role, roles, tag, or tags:

    host: mysql-db1
    hosts:
      - mysql-db1
      - mysql-db2
    roles:
      - mysql

Remember: these hosts do not have to appear in your servers: configuration.

4. Map ports

Map a port if the accessory needs to be reachable. Binding to 127.0.0.1 keeps it off the public interface — review the Docker networking security note before exposing a port publicly:

    port: "127.0.0.1:3306:3306"

5. Persist data

Accessories are not zero-downtime, so durable data must live on the host. You have three documented mechanisms:

Key What it does Created/uploaded first?
directories Mount host directories into the container Yes — created on the host before mounting
files Mount individual files (ERB is evaluated, then uploaded from the local repo) Yes — uploaded from local repo, then mounted
volumes Any other volume mounts, in addition to files and directories No — not created or copied before mounting
    directories:
      - mysql-data:/var/lib/mysql
    files:
      - config/my.cnf.erb:/etc/mysql/my.cnf
    volumes:
      - /path/to/mysql-logs:/var/log/mysql

files and directories both accept the string form local:remote or local:remote:options, where options can be ro (read-only) or z/Z (SELinux labels), and a hash form for custom mode and owner. Setting owner requires root access. See [references/config-keys.md](references/config-keys.md) for the hash form.

6. Pass configuration and secrets

Set environment variables under env:. Keep non-sensitive values under clear: and list secret names under secret: — secrets are stored in an env file on the host rather than passed inline:

    env:
      clear:
        MYSQL_USER: app
      secret:
        - MYSQL_PASSWORD

The names under secret: are resolved from .kamal/secrets. For the full env model (clear vs. secret, aliasing with SECRET:SOURCE, tags) see the env and secrets skills.

7. Boot the accessory

Accessories are not booted by kamal deploy. Boot them explicitly:

# Boot one accessory by name
kamal accessory boot mysql

# Boot every accessory defined in your config
kamal accessory boot all

kamal accessory boot runs the pre-connect hook, acquires the deploy lock, logs in to the registry, and runs the container with docker run (storing the env file at .kamal/env/accessories/<name>.env), then releases the lock.

8. Verify it's running

kamal accessory details mysql      # Show details (use NAME=all for every accessory)
kamal accessory logs mysql         # Show log lines (use --help for options)

To open a shell or run a one-off command inside the container, use exec:

kamal accessory exec mysql "mysql --version"

kamal accessory exec runs a custom command on the servers within the accessory container; pass --help to see its options.

Updating an accessory

Because accessories are not touched by kamal deploy, you update them yourself: change the image: in your config, then reboot:

kamal accessory reboot mysql

reboot stops the container, removes it, and starts a new one — so expect the brief downtime mentioned above. Use NAME=all to reboot every accessory.

Managing the lifecycle

Run kamal accessory (or kamal accessory --help) to see everything. The full subcommand set:

Command What it does
kamal accessory boot [NAME] Boot new accessory service on host (NAME=all boots all)
kamal accessory details [NAME] Show details about the accessory (NAME=all shows all)
kamal accessory exec [NAME] [CMD...] Execute a custom command within the accessory container (--help for options)
kamal accessory logs [NAME] Show log lines from the accessory (--help for options)
kamal accessory reboot [NAME] Stop, remove, and start a new container (NAME=all for all)
kamal accessory restart [NAME] Restart the existing accessory container
kamal accessory start [NAME] Start an existing (stopped) accessory container
kamal accessory stop [NAME] Stop the existing accessory container
kamal accessory remove [NAME] Remove the container, image, and data directory from the host (NAME=all for all)
kamal accessory upgrade Upgrade accessories from Kamal 1.x to 2.0 (restart them in the kamal network)
kamal accessory help [COMMAND] Describe subcommands or one specific subcommand

For more on what each command does — including the boot sequence and the difference between reboot, restart, start/stop, and remove — see [references/commands.md](references/commands.md).

Configuration keys

The most-used keys are covered above. The full set you can put under an accessory:

Key Purpose
service Service label name (default <service>-<accessory>)
image Docker image to run
registry Per-accessory registry (defaults to Docker Hub)
host / hosts / role / roles / tag / tags Where the accessory runs (pick one)
cmd Custom command instead of the image default
port Port mapping
labels Extra Docker labels
options Extra docker run options, passed as --<name> <value>
env Environment variables (clear / secret)
files Files to upload and mount (ERB evaluated)
directories Host directories to create and mount
volumes Additional volume mounts (not created/copied first)
network Network to attach to (defaults to kamal)
proxy Run the accessory behind the Kamal proxy

For every key with its string/hash formats, registry anchors, options, and proxy details, see [references/config-keys.md](references/config-keys.md).

Worked example: a MySQL accessory

accessories:
  mysql:
    image: mysql:8.0
    host: mysql-db1
    port: "127.0.0.1:3306:3306"
    env:
      clear:
        MYSQL_USER: app
      secret:
        - MYSQL_PASSWORD
    files:
      - config/my.cnf.erb:/etc/mysql/my.cnf
    directories:
      - mysql-data:/var/lib/mysql
kamal accessory boot mysql      # create it
kamal accessory details mysql   # confirm it's up
kamal accessory logs mysql      # tail logs if it isn't

The same shape works for a Redis cache, a search service, or any other dependency — swap the image, port, env, and persistence paths for that service.

Common pitfalls

  • Expecting kamal deploy to start it. It won't. Accessories have their own lifecycle — boot and reboot them explicitly.
  • No persistence. Without a directories or volumes mount, data is lost when the container is removed (e.g. on remove or reboot).
  • Specifying more than one host selector. Use exactly one of host/hosts/role/roles/tag/tags.
  • remove deletes data. kamal accessory remove removes the container, image, and the data directory from the host.
  • Silently trimming the upstream stack. If the app's own compose file, Helm chart, or install docs define the stack, every service must map to an accessory, an external service, or a user-approved omission — see "Mirroring an existing stack" above.

Related Skills

  • env: For the full env model — clear vs. secret, tags, and how variables reach the container.
  • secrets: For populating .kamal/secrets and fetching credentials (database passwords, registry passwords) from a password manager.
  • cron: For running scheduled jobs alongside your app and accessories.