Files
grapho/flake.nix
Brandon Lucas 117e6af528 Implement self-contained grapho architecture with four data types
Major rewrite of grapho CLI to support:
- Type 1 (Config): grapho init <repo-url> clones NixOS config
- Type 2 (Sync): Isolated Syncthing on port 8385 (separate from system)
- Type 3 (Backup): Restic integration with systemd timer
- Type 4 (Server): Mount point for central server data

New features:
- Welcome flow on first run (detects ~/.config/grapho/grapho.toml)
- grapho setup wizard creates directory structure
- grapho sync/backup/server subcommands
- grapho status shows all four data types
- grapho doctor checks system health

Added modules/grapho.nix NixOS module:
- Configures isolated Syncthing (ports 8385, 22001, 21028)
- Sets up grapho-backup systemd service and timer
- Creates directory structure via tmpfiles
- Optional NFS server mount

Updated flake.nix:
- Export grapho NixOS module
- Add grapho CLI package (nix build .#grapho)

Documented additional Lux language limitations:
- String == comparison broken in C backend
- let _ = pattern not supported
- List literals with recursion cause segfaults

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 06:12:58 -05:00

235 lines
6.7 KiB
Nix

{
description = "Ultimate Notetaking, Sync & Backup System - NixOS configuration for managing personal data";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
sops-nix = {
url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
lux = {
url = "path:/home/blu/src/lux";
inputs.nixpkgs.follows = "nixpkgs";
};
# Optional: Neovim distribution
# nixvim = {
# url = "github:nix-community/nixvim";
# inputs.nixpkgs.follows = "nixpkgs";
# };
};
outputs = { self, nixpkgs, home-manager, sops-nix, lux, ... }@inputs:
let
# Supported systems
supportedSystems = [ "x86_64-linux" "aarch64-linux" ];
# Helper to generate outputs for all systems
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
# Nixpkgs instantiated for each system
nixpkgsFor = forAllSystems (system: import nixpkgs {
inherit system;
config.allowUnfree = false; # FOSS only
});
# Shared modules for all hosts
sharedModules = [
./modules/grapho.nix
./modules/nb.nix
./modules/syncthing.nix
./modules/backup.nix
sops-nix.nixosModules.sops
];
# Create a NixOS configuration for a host
mkHost = { hostname, system ? "x86_64-linux", extraModules ? [] }:
nixpkgs.lib.nixosSystem {
inherit system;
specialArgs = { inherit inputs; };
modules = sharedModules ++ [
./hosts/${hostname}/configuration.nix
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
# home-manager.users.YOUR_USERNAME = import ./home;
}
] ++ extraModules;
};
in {
# Grapho CLI package
packages = forAllSystems (system:
let
pkgs = nixpkgsFor.${system};
luxPkg = lux.packages.${system}.default;
in {
grapho = pkgs.stdenv.mkDerivation {
pname = "grapho";
version = "0.1.0";
src = ./cli;
nativeBuildInputs = [ luxPkg pkgs.gcc ];
buildPhase = ''
${luxPkg}/bin/lux compile grapho.lux -o grapho
'';
installPhase = ''
mkdir -p $out/bin
cp grapho $out/bin/
'';
meta = {
description = "Personal data infrastructure CLI";
homepage = "https://github.com/user/grapho";
license = pkgs.lib.licenses.mit;
};
};
default = self.packages.${system}.grapho;
}
);
# NixOS configurations
# Uncomment and customize for your hosts:
#
# nixosConfigurations = {
# desktop = mkHost { hostname = "desktop"; };
# laptop = mkHost { hostname = "laptop"; };
# server = mkHost {
# hostname = "server";
# extraModules = [
# ./modules/server/forgejo.nix
# ./modules/server/immich.nix
# ./modules/server/jellyfin.nix
# ];
# };
# };
# One-command setup: nix run .
apps = forAllSystems (system:
let
pkgs = nixpkgsFor.${system};
setupScript = pkgs.writeShellApplication {
name = "usync-setup";
runtimeInputs = with pkgs; [
git
jq
age
sops
syncthing
qrencode
zbar
ffmpeg
];
text = ''
# Find the setup script
SCRIPT_DIR="''${UNSBS_DIR:-}"
if [[ -z "$SCRIPT_DIR" ]]; then
# Try current directory first
if [[ -f "./setup" ]]; then
SCRIPT_DIR="."
# Try the flake source
elif [[ -f "${self}/setup" ]]; then
SCRIPT_DIR="${self}"
else
echo "Error: Cannot find setup script"
echo "Run from the repo directory, or clone it first:"
echo " git clone ssh://git@your-server:2222/you/grapho.git"
exit 1
fi
fi
exec "$SCRIPT_DIR/setup" "$@"
'';
};
in {
default = {
type = "app";
program = "${setupScript}/bin/usync-setup";
};
setup = {
type = "app";
program = "${setupScript}/bin/usync-setup";
};
}
);
# Development shell with all tools
devShells = forAllSystems (system:
let
pkgs = nixpkgsFor.${system};
in {
default = pkgs.mkShell {
name = "unsbs-dev";
packages = [
lux.packages.${system}.default
] ++ (with pkgs; [
# Tier 2: Notes & Sync
nb # Notebook CLI
syncthing # File sync
unison # Alternative sync
# Tier 3: Backup & Cloud
restic # Backup
rclone # Cloud storage
# Setup & Pairing
qrencode # QR codes for mobile pairing
zbar # QR scanning (zbarimg)
ffmpeg # Camera preview + capture
age # Encryption for secrets
sops # Secret management
# Development
git
neovim
jq
ripgrep
fd
# Nix tools
nil # Nix LSP
nixpkgs-fmt # Nix formatter
]);
shellHook = ''
printf '\033[1m%s\033[0m\n' "Ultimate Notetaking, Sync & Backup System"
echo ""
echo "Get started: ./setup"
echo "Pair mobile: ./setup mobile"
echo "Sync: ./scripts/usync"
echo "Status: ./scripts/ustatus"
'';
};
}
);
# Export modules for use in other flakes
nixosModules = {
grapho = import ./modules/grapho.nix;
nb = import ./modules/nb.nix;
syncthing = import ./modules/syncthing.nix;
backup = import ./modules/backup.nix;
default = { imports = sharedModules; };
};
# Templates for creating new hosts
templates = {
default = {
path = ./templates/host;
description = "Template for a new host configuration";
};
};
};
}