Liking cljdoc? Tell your friends :D

hive-spi

Service Provider Interface (SPI) protocol contracts for hive workflows.

This library is pure protocol definitions — no implementations, no runtime state, no third-party deps. It exists so that consumers can depend on stable contracts rather than concrete implementations.

Ports

src/hive_spi/workflow/ports.cljc defines the workflow ports:

ProtocolPurpose
IPlanCompilerLower a Plan-EDN front-end into the wf-IR node-map tree.
IPlanGraphRead-only view of a Plan as a Kahn-orderable DAG.
ITaskBoardHeadless task/kanban surface used by methods.
IHeadlessDispatcherSpawn/dispatch on a headless backend.
IWorkflowStorePersistence facade for authored workflow ASTs.
IEffectHandlerSelf-describing verb seam for routing effects.
IIntrospectableProbe for strategies and verbs.

Injection points

Two shapes, for two different questions.

src/hive_spi/slot.cljc — a mutable holder. Use it when the injection point is the process: one active implementation (single-slot) or a keyed map of them (multi-slot), installed at boot and read from anywhere.

src/hive_spi/provider.cljc — an immutable registry of providers as data. Use it when two of them must coexist: a request and its test, a tenant and another tenant. A provider is an implementation plus a profile — plain data describing its measured behaviour — and the registry is a value threaded through a call rather than a global installed into.

(require '[hive-spi.provider :as provider])

(def RailProfile
  (provider/profile-schema [[:provider/currency :keyword]]))

(def rails
  (provider/registry [(provider/entry #:provider{:id :chain
                                                 :currency :xmr
                                                 :capabilities #{:poll}}
                                      (chain-rail config))
                      (provider/entry #:provider{:id :cards :currency :usd}
                                      (card-rail config))]
                     {:schema RailProfile
                      :satisfies-port? #(satisfies? IRail %)}))

;; the SUBJECT selects its provider; a caller cannot substitute one
(provider/via rails invoice :invoice/provider #(charge! % amount))

;; and a provider is never asked to do what its profile does not admit
(provider/via-capable rails invoice :invoice/provider :poll #(poll % invoice))

Three rules the API enforces rather than documents:

  1. Profiles are validated at registration — a malformed provider fails at boot, where an operator is watching, not at the first caller.
  2. Capability is read off the profile, never inferred from the id. Adding a provider is an entry in a registry, not a branch in a component.
  3. A subject selects its provider. for-subject / via take the id from the subject, so a caller naming a provider is stating a claim to be checked — never the authority that resolves it.

conformance / conforming? are the Liskov check for a test: every registered implementation is substitutable for the port, and every profile means what its schema says.

Layout

hive-spi/
├── deps.edn
├── .hive-project.edn
├── src/hive_spi/slot.cljc          — mutable injection points
├── src/hive_spi/provider.cljc      — providers as data, registry as a value
├── src/hive_spi/workflow/ports.cljc
└── test/hive_spi/workflow/ports_test.clj

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close