---
title: Architecture
description: How spindle listens for records and executes pipelines.
---


Spindle is a small CI runner service. Here's a high-level overview of how it operates:

- Listens for [`sh.tangled.spindle.member`](https://tangled.org/@tangled.org/core/blob/master/lexicons/spindle/member.json) and
  [`sh.tangled.repo`](https://tangled.org/@tangled.org/core/blob/master/lexicons/repo.json) records on the Jetstream.
- When a new repo record comes through (typically when you add a spindle to a
  repo from the settings), spindle then resolves the underlying knot and
  subscribes to repo events (see:
  [`sh.tangled.pipeline`](https://tangled.org/@tangled.org/core/blob/master/lexicons/pipeline.json)).
- The spindle engine then handles execution of the pipeline, with results and
  logs beamed on the spindle event stream over WebSocket

## The engines

Spindle has two execution backends, picked per-workflow with
the [`engine`](#engine) field:

- **nixery**: executes each step in a fresh Docker container
  (Podman works too, if Docker compatibility is enabled so
  that `/run/docker.sock` is created), with state persisted
  across steps within the `/tangled/workspace` directory. The
  base image for the container is constructed on the fly using
  [Nixery](https://nixery.dev), which is/rhandy for caching
  layers for frequently used packages.
- **microvm**: runs the whole workflow inside its own
  microVM, supporting different images, with extra
  configuration for NixOS images (e.g. services in workflow file)
  See the [engine
  README](https://tangled.org/tangled.org/core/blob/master/spindle/engines/microvm/README.md)
  for the architecture in depth.

The pipeline manifest is [specified here](/spindles/workflows/#pipelines).
