1{ config, lib, pkgs, ... }:
2let
3 inherit (lib) types;
4
5 cfg = config.services.tabby;
6 format = pkgs.formats.toml { };
7 tabbyPackage = cfg.package.override {
8 inherit (cfg) acceleration;
9 };
10in
11{
12 options = {
13 services.tabby = {
14 enable = lib.mkEnableOption "Self-hosted AI coding assistant using large language models";
15
16 package = lib.mkPackageOption pkgs "tabby" { };
17
18 port = lib.mkOption {
19 type = types.port;
20 default = 11029;
21 description = ''
22 Specifies the bind port on which the tabby server HTTP interface listens.
23 '';
24 };
25
26 model = lib.mkOption {
27 type = types.str;
28 default = "TabbyML/StarCoder-1B";
29 description = ''
30 Specify the model that tabby will use to generate completions.
31
32 This model will be downloaded automatically if it is not already present.
33
34 If you want to utilize an existing model that you've already
35 downloaded you'll need to move it into tabby's state directory which
36 lives in `/var/lib/tabby`. Because the tabby.service is configured to
37 use a DyanmicUser the service will need to have been started at least
38 once before you can move the locally existing model into
39 `/var/lib/tabby`. You can set the model to 'none' and tabby will
40 startup and fail to download a model, but will have created the
41 `/var/lib/tabby` directory. You can then copy over the model manually
42 into `/var/lib/tabby`, update the model option to the name you just
43 downloaded and copied over then `nixos-rebuild switch` to start using
44 it.
45
46 $ tabby download --model TabbyML/DeepseekCoder-6.7B
47 $ find ~/.tabby/ | tail -n1
48 /home/ghthor/.tabby/models/TabbyML/DeepseekCoder-6.7B/ggml/q8_0.v2.gguf
49 $ sudo rsync -r ~/.tabby/models/ /var/lib/tabby/models/
50 $ sudo chown -R tabby:tabby /var/lib/tabby/models/
51
52 See for Model Options:
53 > https://github.com/TabbyML/registry-tabby
54 '';
55 };
56
57 acceleration = lib.mkOption {
58 type = types.nullOr (types.enum [ "cpu" "rocm" "cuda" "metal" ]);
59 default = null;
60 example = "rocm";
61 description = ''
62 Specifies the device to use for hardware acceleration.
63
64 - `cpu`: no acceleration just use the CPU
65 - `rocm`: supported by modern AMD GPUs
66 - `cuda`: supported by modern NVIDIA GPUs
67 - `metal`: supported on darwin aarch64 machines
68
69 Tabby will try and determine what type of acceleration that is
70 already enabled in your configuration when `acceleration = null`.
71
72 - nixpkgs.config.cudaSupport
73 - nixpkgs.config.rocmSupport
74 - if stdenv.isDarwin && stdenv.isAarch64
75
76 IFF multiple acceleration methods are found to be enabled or if you
77 haven't set either `cudaSupport or rocmSupport` you will have to
78 specify the device type manually here otherwise it will default to
79 the first from the list above or to cpu.
80 '';
81 };
82
83 settings = lib.mkOption {
84 inherit (format) type;
85 default = { };
86 description = ''
87 Tabby scheduler configuration
88
89 See for more details:
90 > https://tabby.tabbyml.com/docs/configuration/#repository-context-for-code-completion
91 '';
92 example = lib.literalExpression ''
93 settings = {
94 repositories = [
95 { name = "tabby"; git_url = "https://github.com/TabbyML/tabby.git"; }
96 { name = "CTranslate2"; git_url = "git@github.com:OpenNMT/CTranslate2.git"; }
97
98 # local directory is also supported, but limited by systemd DynamicUser=1
99 # adding local repositories will need to be done manually
100 { name = "repository_a"; git_url = "file:///var/lib/tabby/repository_a"; }
101 ];
102 };
103 '';
104 };
105
106 usageCollection = lib.mkOption {
107 type = types.bool;
108 default = false;
109 description = ''
110 Enable sending anonymous usage data.
111
112 See for more details:
113 > https://tabby.tabbyml.com/docs/configuration#usage-collection
114 '';
115 };
116
117 indexInterval = lib.mkOption {
118 type = types.str;
119 default = "5hours";
120 example = "5hours";
121 description = ''
122 Run tabby scheduler to generate the index database at this interval.
123 Updates by default every 5 hours. This value applies to
124 `OnUnitInactiveSec`
125
126 The format is described in
127 {manpage}`systemd.time(7)`.
128
129 To disable running `tabby scheduler --now` updates, set to `"never"`
130 '';
131 };
132 };
133 };
134
135 # TODO(ghthor): firewall config
136
137 config = lib.mkIf cfg.enable {
138 environment = {
139 etc."tabby/config.toml".source = format.generate "config.toml" cfg.settings;
140 systemPackages = [ tabbyPackage ];
141 };
142
143
144 systemd = let
145 serviceUser = {
146 WorkingDirectory = "/var/lib/tabby";
147 StateDirectory = [ "tabby" ];
148 ConfigurationDirectory = [ "tabby" ];
149 DynamicUser = true;
150 User = "tabby";
151 Group = "tabby";
152 };
153
154 serviceEnv = lib.mkMerge [
155 {
156 TABBY_ROOT = "%S/tabby";
157 }
158 (lib.mkIf (!cfg.usageCollection) {
159 TABBY_DISABLE_USAGE_COLLECTION = "1";
160 })
161 ];
162 in {
163 services.tabby = {
164 wantedBy = [ "multi-user.target" ];
165 description = "Self-hosted AI coding assistant using large language models";
166 after = [ "network.target" ];
167 environment = serviceEnv;
168 serviceConfig = lib.mkMerge [
169 serviceUser
170 {
171 ExecStart =
172 "${lib.getExe tabbyPackage} serve --model ${cfg.model} --port ${toString cfg.port} --device ${tabbyPackage.featureDevice}";
173 }
174 ];
175 };
176
177 services.tabby-scheduler = lib.mkIf (cfg.indexInterval != "never") {
178 wantedBy = [ "multi-user.target" ];
179 description = "Tabby repository indexing service";
180 after = [ "network.target" ];
181 environment = serviceEnv;
182 preStart = "cp -f /etc/tabby/config.toml \${TABBY_ROOT}/config.toml";
183 serviceConfig = lib.mkMerge [
184 serviceUser
185 {
186 # Type = "oneshot";
187 ExecStart = "${lib.getExe tabbyPackage} scheduler --now";
188 }
189 ];
190 };
191 timers.tabby-scheduler = lib.mkIf (cfg.indexInterval != "never") {
192 description = "Update timer for tabby-scheduler";
193 partOf = [ "tabby-scheduler.service" ];
194 wantedBy = [ "timers.target" ];
195 timerConfig.OnUnitInactiveSec = cfg.indexInterval;
196 };
197 };
198 };
199
200 meta.maintainers = with lib.maintainers; [ ghthor ];
201}