A vibe coded tangled fork which supports pijul.
1{
2 config,
3 pkgs,
4 lib,
5 ...
6}: let
7 cfg = config.services.tangled.spindle;
8in
9 with lib; {
10 options = {
11 services.tangled.spindle = {
12 enable = mkOption {
13 type = types.bool;
14 default = false;
15 description = "Enable a tangled spindle";
16 };
17 package = mkOption {
18 type = types.package;
19 description = "Package to use for the spindle";
20 };
21
22 server = {
23 listenAddr = mkOption {
24 type = types.str;
25 default = "0.0.0.0:6555";
26 description = "Address to listen on";
27 };
28
29 stateDir = mkOption {
30 type = types.path;
31 default = "/var/lib/spindle";
32 description = "Tangled spindle data directory";
33 };
34
35 hostname = mkOption {
36 type = types.str;
37 example = "my.spindle.com";
38 description = "Hostname for the server (required)";
39 };
40
41 plcUrl = mkOption {
42 type = types.str;
43 default = "https://plc.directory";
44 description = "atproto PLC directory";
45 };
46
47 relayUrl = mkOption {
48 type = types.str;
49 default = "https://relay1.us-east.bsky.network";
50 description = "atproto relay";
51 };
52
53 tapPort = mkOption {
54 type = types.port;
55 default = 6480;
56 description = "Internal port to run the spindle tap";
57 };
58
59 tapDbUrl = mkOption {
60 type = types.str;
61 default = "sqlite:///var/lib/spindle/tap.db";
62 description = "tap db url";
63 };
64
65 dev = mkOption {
66 type = types.bool;
67 default = false;
68 description = "Enable development mode (disables signature verification)";
69 };
70
71 owner = mkOption {
72 type = types.str;
73 example = "did:plc:qfpnj4og54vl56wngdriaxug";
74 description = "DID of owner (required)";
75 };
76
77 maxJobCount = mkOption {
78 type = types.int;
79 default = 2;
80 example = 5;
81 description = "Maximum number of concurrent jobs to run";
82 };
83
84 queueSize = mkOption {
85 type = types.int;
86 default = 100;
87 example = 100;
88 description = "Maximum number of jobs queue up";
89 };
90
91 secrets = {
92 provider = mkOption {
93 type = types.str;
94 default = "sqlite";
95 description = "Backend to use for secret management, valid options are 'sqlite', and 'openbao'.";
96 };
97
98 openbao = {
99 proxyAddr = mkOption {
100 type = types.str;
101 default = "http://127.0.0.1:8200";
102 description = "Address of the OpenBAO proxy server";
103 };
104 mount = mkOption {
105 type = types.str;
106 default = "spindle";
107 description = "Mount path in OpenBAO to read secrets from";
108 };
109 };
110 };
111 };
112
113 pipelines = {
114 nixery = mkOption {
115 type = types.str;
116 default = "nixery.tangled.sh"; # note: this is *not* on tangled.org yet
117 description = "Nixery instance to use";
118 };
119
120 workflowTimeout = mkOption {
121 type = types.str;
122 default = "5m";
123 description = "Timeout for each step of a pipeline";
124 };
125 };
126 };
127 };
128
129 config = mkIf cfg.enable {
130 virtualisation.docker.enable = true;
131
132 systemd.services.spindle = {
133 description = "spindle service";
134 after = ["network.target" "docker.service"];
135 wantedBy = ["multi-user.target"];
136 path = [
137 pkgs.git
138 ];
139 serviceConfig = {
140 LogsDirectory = "spindle";
141 StateDirectory = "spindle";
142 Environment = [
143 "SPINDLE_SERVER_LISTEN_ADDR=${cfg.server.listenAddr}"
144 "SPINDLE_SERVER_DATA_DIR=${cfg.server.stateDir}"
145 "SPINDLE_SERVER_HOSTNAME=${cfg.server.hostname}"
146 "SPINDLE_SERVER_PLC_URL=${cfg.server.plcUrl}"
147 "SPINDLE_SERVER_RELAY_URL=${cfg.server.relayUrl}"
148 "SPINDLE_SERVER_DEV=${lib.boolToString cfg.server.dev}"
149 "SPINDLE_SERVER_OWNER=${cfg.server.owner}"
150 "SPINDLE_SERVER_MAX_JOB_COUNT=${toString cfg.server.maxJobCount}"
151 "SPINDLE_SERVER_QUEUE_SIZE=${toString cfg.server.queueSize}"
152 "SPINDLE_SERVER_SECRETS_PROVIDER=${cfg.server.secrets.provider}"
153 "SPINDLE_SERVER_SECRETS_OPENBAO_PROXY_ADDR=${cfg.server.secrets.openbao.proxyAddr}"
154 "SPINDLE_SERVER_SECRETS_OPENBAO_MOUNT=${cfg.server.secrets.openbao.mount}"
155 "SPINDLE_SERVER_TAP_PORT=${toString cfg.server.tapPort}"
156 "SPINDLE_SERVER_TAP_DB_URL=${cfg.server.tapDbUrl}"
157 "SPINDLE_NIXERY_PIPELINES_NIXERY=${cfg.pipelines.nixery}"
158 "SPINDLE_NIXERY_PIPELINES_WORKFLOW_TIMEOUT=${cfg.pipelines.workflowTimeout}"
159 ];
160 ExecStart = "${cfg.package}/bin/spindle";
161 Restart = "always";
162 };
163 };
164 };
165 }