on 2026.09.23.1653 help sign in
diagonal/flake.nix
93 lines 3.9 kB history raw
1{
2 description = "Diagonal: Dia-style tab groups for Brave, named by Apple's on-device model";
4 inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
6 outputs = { self, nixpkgs, ... }:
7 let
8 systems = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
9 forAll = f: nixpkgs.lib.genAttrs systems (s: f nixpkgs.legacyPackages.${s});
10 extensionId = nixpkgs.lib.strings.trim (builtins.readFile ./extension-id);
11 in
12 {
13 packages = forAll (pkgs: rec {
14 # The unpacked extension (dist/). Load it from brave://extensions → Load unpacked.
15 extension = pkgs.buildNpmPackage {
16 pname = "diagonal-extension";
17 version = "0.1.0";
18 src = ./.;
19 npmDeps = pkgs.importNpmLock { npmRoot = ./.; };
20 npmConfigHook = pkgs.importNpmLock.npmConfigHook;
21 npmBuildScript = "build";
22 installPhase = "cp -r dist $out";
23 };
25 # The native host: host/ copied whole, the shebang pinned to Nix's python3.
26 diagonal-host = pkgs.stdenvNoCC.mkDerivation {
27 pname = "diagonal-host";
28 version = "0.1.0";
29 src = ./host;
30 dontBuild = true;
31 installPhase = ''
32 mkdir -p $out/libexec/diagonal-host $out/bin
33 cp diagonal-host.py prompts.py validate.py emoji.txt $out/libexec/diagonal-host/
34 substituteInPlace $out/libexec/diagonal-host/diagonal-host.py \
35 --replace-fail "#!/usr/bin/env python3" "#!${pkgs.python3}/bin/python3"
36 chmod +x $out/libexec/diagonal-host/diagonal-host.py
37 ln -s $out/libexec/diagonal-host/diagonal-host.py $out/bin/diagonal-host
38 '';
39 doInstallCheck = true;
40 installCheckPhase = "$out/bin/diagonal-host --version";
41 };
43 default = diagonal-host;
44 });
46 devShells = forAll (pkgs: {
47 default = pkgs.mkShell {
48 packages = with pkgs; [ nodejs pnpm typescript esbuild python3 openssl ];
49 };
50 });
52 homeManagerModules.default = { config, pkgs, lib, ... }:
53 let
54 cfg = config.programs.diagonal;
55 host = self.packages.${pkgs.stdenv.hostPlatform.system}.diagonal-host;
56 manifest = {
57 name = "io.diagonal.host";
58 description = "Diagonal: names tab groups with Apple's on-device model";
59 path = "${host}/bin/diagonal-host";
60 type = "stdio";
61 allowed_origins = [ "chrome-extension://${cfg.extensionId}/" ];
62 };
63 in
64 {
65 options.programs.diagonal = {
66 enable = lib.mkEnableOption "the Diagonal native messaging host for Brave";
67 extensionId = lib.mkOption {
68 type = lib.types.str;
69 default = extensionId;
70 description = "Pinned extension ID (from scripts/gen-key.sh). The host itself checks the ID baked into host/diagonal-host.py, so change both together by re-running gen-key.sh.";
71 };
72 channels = lib.mkOption {
73 type = lib.types.listOf (lib.types.enum [ "Brave-Browser" "Brave-Browser-Beta" "Brave-Browser-Nightly" ]);
74 default = [ "Brave-Browser" ];
75 description = "Brave channels to install the host manifest for.";
76 };
77 };
79 config = lib.mkIf cfg.enable {
80 home.packages = [ host ];
81 home.file = lib.listToAttrs (map
82 (ch: lib.nameValuePair
83 "Library/Application Support/BraveSoftware/${ch}/NativeMessagingHosts/io.diagonal.host.json"
84 { text = builtins.toJSON manifest; })
85 cfg.channels);
86 # `|| true`: a Mac without Apple Intelligence still activates.
87 home.activation.diagonalSchemas = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
88 ${host}/bin/diagonal-host --install-schemas || true
89 '';
90 };
91 };
92 };