prompts/skills/clojure-donut-system/SKILL.md
Reference for donut.party/system - component lifecycle and dependency injection library for Clojure. Use when working with component definitions, system management, refs between components, or lifecycle signals (start/stop/suspend/resume). Triggers on donut.system imports, ::ds/start, ::ds/stop, ::ds/config, ds/ref, or component-based architecture. Prefer using donut.system over mount, integrant, and stuart sierra's component.
npx skillsauth add ramblurr/nix-devenv clojure-donut-systemInstall 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.
Component lifecycle and dependency injection library for Clojure applications. Helps organize applications as systems of components with managed dependencies and lifecycle.
deps.edn:
party.donut/system {:mvn/version "1.0.257"}
Require:
(require '[donut.system :as ds])
See https://clojars.org/party.donut/system for the latest version.
Define components with ::ds/start and ::ds/stop handlers:
(def system
{::ds/defs
{:app
{:server #::ds{:start (fn [{:keys [::ds/config]}]
(start-server (:port config)))
:stop (fn [{:keys [::ds/instance]}]
(stop-server instance))
:config {:port 8080}}}}})
;; Start the system
(def running-system (ds/signal system ::ds/start))
;; Stop the system
(ds/signal running-system ::ds/stop)
{::ds/defs ; component definitions go here
::ds/instances ; runtime instances (created by signals)
::ds/signals ; custom signal definitions (optional)
::ds/plugins ; plugins to extend functionality (optional)}
Components are maps with signal handlers:
#::ds{:start (fn [arg] ...) ; creates instance
:stop (fn [arg] ...) ; cleans up instance
:config {...}} ; configuration data
Components are organized into groups (2-level structure):
{::ds/defs
{:group-name ; first level: component group
{:component-name ; second level: component
#::ds{:start ...}}}}
Signal handlers receive a map with:
::ds/instance - component instance (if exists)::ds/config - component config with refs resolved::ds/system - entire system map::ds/component-id - e.g. [:group :component]Use ds/ref to reference other components:
(def system
{::ds/defs
{:services
{:db #::ds{:start (fn [_] (create-db-pool))}}
:app
{:handler #::ds{:start (fn [{:keys [::ds/config]}]
(make-handler (:db config)))
:config {:db (ds/ref [:services :db])}}}}})
Refs determine startup order - dependencies start first.
Use ds/local-ref to reference components in the same group:
(def HTTPServer
#::ds{:start (fn [{:keys [::ds/config]}]
(start-server (:handler config) (:port config)))
:config {:handler (ds/local-ref [:handler])
:port (ds/local-ref [:port])}})
(def system
{::ds/defs
{:http-1 {:server HTTPServer
:handler (fn [req] {:status 200 :body "Server 1"})
:port 8080}
:http-2 {:server HTTPServer
:handler (fn [req] {:status 200 :body "Server 2"})
:port 9090}}})
Maps without ::ds/start are treated as data and can be referenced:
{::ds/defs
{:env {:db-url "jdbc:postgresql://localhost/mydb"
:port 8080}
:services
{:db #::ds{:start (fn [{:keys [::ds/config]}]
(connect (:url config)))
:config {:url (ds/ref [:env :db-url])}}}}}
Define systems by environment:
(defmethod ds/named-system :dev
[_]
{::ds/defs {:env {:port 8080}
:app {...}}})
(defmethod ds/named-system :test
[_]
{::ds/defs {:env {:port 9999}
:app {...}}})
;; Start with overrides
(ds/start :dev {[:env :port] 3000})
Use donut.system.repl for development:
(require '[donut.system.repl :as dsr])
;; Define default REPL system
(defmethod ds/named-system :donut.system/repl
[_]
(ds/system :dev))
;; REPL commands
(dsr/start) ; start system
(dsr/stop) ; stop system
(dsr/restart) ; stop, reload namespaces, start
::ds/start - create/start component instances (reverse-topsort order)::ds/stop - stop/cleanup component instances (topsort order)::ds/suspend - pause without full teardown::ds/resume - resume suspended componentsConvenience functions: ds/start, ds/stop, ds/suspend, ds/resume
Component Organization: Components must be direct children of groups. This won't work:
{::ds/defs
{:group {:subgroup {:component ...}}}} ; TOO NESTED!
Refs Must Be Reachable: Refs must be in the data structure, not hidden in functions:
;; BAD - ref inside function, not reachable
#::ds{:start (fn [_] (ds/ref [:services :db]))}
;; GOOD - ref in config
#::ds{:start (fn [{:keys [::ds/config]}] (:db config))
:config {:db (ds/ref [:services :db])}}
Deep Refs: Can reference into component instances:
(ds/ref [:group :component :level-1 :level-2])
Idempotent Start Handlers: If you signal the same system multiple times, make start handlers idempotent:
(fn [{::ds/keys [instance config]}]
(or instance (create-component config)))
(use-fixtures :each (ds/system-fixture ::test))
(deftest my-test
(is (= expected-value
@(ds/instance ds/*system* [:group :component]))))
Override components in tests:
(ds/start ::test
{[:services :external-api] mock-api
[:services :email] mock-email-sender})
::ds/signals::ds/pre-start, ::ds/post-start, etc.(ds/start system {} #{[:group :component]})testing
Use this OCP when executing or preparing to execute commands that change a live or important system, service reloads/restarts, package changes, deployments, migrations, firewall/network/access changes, credential rotation, NixOS switch/test/boot/deploy, or incident mitigation. It guides safe operations with a persisted ledger for scope, preflight, baseline, rollback, validation, and evidence.
development
Create new agent skills with proper structure, progressive disclosure, and bundled resources. Use when user wants to create, write, or build a new skill.
documentation
Naming conventions for workflow documents in prompts/. Use when creating plans, PRDs, research reports, idea capture or other workflow documents. Triggers on (1) creating new planning documents, (2) naming PRDs or research reports, (3) questions about document organization in prompts/.
testing
Grilling session that challenges your plan against the existing domain model, sharpens terminology, and updates documentation (CONTEXT.md, ADRs) inline as decisions crystallise. Use when user wants to stress-test a plan against their project's language and documented decisions.