Compare commits

..

8 Commits

Author SHA1 Message Date
ec5e77f796 Prompt for backup location during re-onboard instead of skipping
When step 4 finds an existing backup repo, show the current location
and ask to reconfigure with the existing path as default, rather than
silently skipping the step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 13:51:24 -05:00
3be9586238 Fix design issues and add comprehensive test suite
Guard doSetup() against re-initialization, route welcome to onboard
wizard, fix import confirmation logic, remove invalid syncthing
generate flags, and show full export path. Add shell-based integration
test suite (123 tests) at ~/src/test/pal/ covering all commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 13:50:04 -05:00
4a5fa4415c Fix interactive input by using Console.readLine instead of Process.exec
Process.exec uses popen(cmd, "r") which creates a read-only pipe where
the subprocess stdin is disconnected from the terminal. Console.readLine
reads directly from the parent process stdin via fgets, fixing all
interactive prompts (askConfirm, askInput, choice menus).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 23:48:33 -05:00
d30d2efa4e Rename grapho to pal, add onboard command, fix interactive input
- Rename grapho → pal across entire codebase (CLI, NixOS module,
  flake, docs, config paths)
- Add `pal onboard` interactive setup wizard with 4 steps:
  device, config repo, sync, backups
- Shows current setup summary when re-running onboard on an
  existing installation with warnings about what will change
- Fix askConfirm/askInput to read from /dev/tty so interactive
  prompts work correctly
- Remove || operator usage in askConfirm (not reliable in Lux)
- Add pal package to nix develop shell
- Document ~/.config/pal/ directory structure in README

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 22:38:37 -05:00
05c04b209c Clean up repo: gitignore binaries, remove stale docs
- Add compiled binaries (grapho, *_test) to .gitignore
- Remove grapho binary from tracking (build from source)
- Delete obsolete LUX-LIMITATIONS.md
- Minor README wording fix

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 23:05:36 -05:00
13fe22a804 Improve server mount help with detailed instructions
- Add SSHFS section with common options explained
- Add NFS mount example
- Reference NixOS wiki for declarative mounts
- Show unmount hint

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 22:58:19 -05:00
dedfbfce64 Add QR code support for Device IDs
- Add printQR() helper function using qrencode
- Display QR code in sync setup for easy mobile pairing
- Add qrencode to doctor dependency check

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 22:28:10 -05:00
d3d720b3bc Modernize CLI UX with gh/cargo-style polish
- Add --version/-V and per-subcommand --help
- Replace logo spam with compact status dashboard
- Add aligned step output (label    done format)
- Add confirmation prompts for destructive operations
- Interactive first-run wizard when uninitialized
- Consistent color language and status line formatting
- Clean help with USAGE/COMMANDS/OPTIONS structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 22:15:35 -05:00
11 changed files with 1861 additions and 1400 deletions

4
.gitignore vendored
View File

@@ -3,6 +3,10 @@ result
result-*
.direnv/
# Compiled binaries
pal
*_test
# Secrets (NEVER commit unencrypted secrets)
secrets/*.yaml
!secrets/secrets.yaml.example

View File

@@ -1,6 +1,6 @@
# Ultimate Notetaking, Sync & Backup System
A NixOS-based system for managing the three types of data in a computer:
A NixOS-based system for managing the three types of data across devices:
| Tier | Type | Examples | Sync Model |
|------|------|----------|------------|
@@ -12,11 +12,11 @@ A NixOS-based system for managing the three types of data in a computer:
```bash
# One-command setup (public repo, no SSH key needed)
nix run 'git+https://git.qrty.ink/blu/grapho.git'
nix run 'git+https://git.qrty.ink/blu/pal.git'
# Or clone first, then run
git clone https://git.qrty.ink/blu/grapho.git
cd grapho
git clone https://git.qrty.ink/blu/pal.git
cd pal
nix run .
```
@@ -26,8 +26,8 @@ nix run .
```bash
# 1. Clone the repo
git clone https://git.qrty.ink/blu/grapho.git
cd grapho
git clone https://git.qrty.ink/blu/pal.git
cd pal
# 2. Run setup (one command - includes all dependencies)
nix run .
@@ -39,18 +39,18 @@ nix run .
# 4. (Optional) Set up SSH for push access
# Add your SSH key to Gitea: https://git.qrty.ink/user/settings/keys
# Then switch to SSH remote:
git remote set-url origin ssh://git@git.qrty.ink:2222/blu/grapho.git
git remote set-url origin ssh://git@git.qrty.ink:2222/blu/pal.git
```
### Additional Computers (Joining)
```bash
# One command (no SSH key needed for public repo)
nix run 'git+https://git.qrty.ink/blu/grapho.git'
nix run 'git+https://git.qrty.ink/blu/pal.git'
# Choose option [2], enter your config git URL and age key
# Or clone first:
git clone https://git.qrty.ink/blu/grapho.git && cd grapho
git clone https://git.qrty.ink/blu/pal.git && cd pal
nix run . -- <config-git-url> <your-age-key>
```
@@ -78,10 +78,10 @@ Add to your flake.nix inputs, then import the module:
```nix
{
inputs.grapho.url = "git+https://git.qrty.ink/blu/grapho.git";
inputs.pal.url = "git+https://git.qrty.ink/blu/pal.git";
# In your configuration:
imports = [ inputs.grapho.nixosModules.default ];
imports = [ inputs.pal.nixosModules.default ];
}
```
@@ -306,19 +306,22 @@ No. See [our research](./docs/research/sync-tools-comparison.md). Common issues
But cloud is fine too. This system works with GitHub, Backblaze B2, etc.
## Directory Structure
## Repository Structure
```
.
├── flake.nix # Entry point
├── flake.lock
├── README.md
├── cli/
│ └── pal.lux # CLI source (Lux language)
├── docs/
│ ├── research/
│ │ └── sync-tools-comparison.md
│ ├── ARCHITECTURE.md
│ └── LLM-CONTEXT.md # For AI assistants
├── modules/
│ ├── pal.nix # Core pal NixOS module
│ ├── nb.nix
│ ├── syncthing.nix
│ ├── neovim.nix
@@ -342,6 +345,47 @@ But cloud is fine too. This system works with GitHub, Backblaze B2, etc.
└── ustatus
```
## Data Directory (`~/.config/pal/`)
When you run `pal onboard` or `pal setup`, this directory is created to hold all your data and configuration. Everything is human-readable unless noted.
```
~/.config/pal/
├── pal.toml # Main config (TOML) — device name, ports, schedule
├── age-key.txt # Age encryption private key
├── state.db # Event history (SQLite)
├── config-repo/ # Your system config (git-managed)
│ └── .git/
├── sync/ # Syncthing-managed data (syncs across devices)
│ ├── notes/ # Your notes
│ ├── documents/ # Your documents
│ └── dotfiles/ # Your dotfiles
├── syncthing/ # Syncthing runtime (auto-generated)
│ ├── config/ # config.xml, TLS certs, keys
│ └── db/ # Syncthing index database
├── restic/ # Backup settings
│ ├── password # Repository password (auto-generated, plaintext)
│ ├── repository # Repository URL/path (plaintext)
│ └── cache/ # Local cache for faster operations
├── backups/ # Restic repository (if backing up locally)
│ ├── config # ⚠ Encrypted — restic internal, not human-readable
│ ├── data/ # Encrypted, deduplicated backup chunks
│ ├── index/ # Backup index
│ ├── keys/ # Repository encryption keys
│ ├── locks/ # Lock files
│ └── snapshots/ # Snapshot metadata
└── server/ # Mount point for remote server storage
```
**What's human-readable?** `pal.toml`, `restic/password`, `restic/repository`, and everything in `sync/` and `config-repo/`. The `syncthing/config/` directory is auto-generated XML. The `backups/` directory is a restic repository where everything is encrypted by design — use `pal backup list` to inspect snapshots.
## Contributing
PRs welcome! Please read [ARCHITECTURE.md](./docs/ARCHITECTURE.md) first.

File diff suppressed because it is too large Load Diff

1722
cli/pal.lux Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,218 +0,0 @@
# Lux Language Limitations (grapho CLI)
This document tracks limitations encountered while developing the grapho CLI in Lux, to help improve the language.
## Fixed Issues
### 1. Double Execution Bug (FIXED)
**Severity:** Critical
**Status:** Fixed in Lux c_backend.rs
When using `let result = run main() with {}` to invoke the main function, the entire program was executing twice.
**Root Cause:** In `c_backend.rs:3878-3907`, the generated C code was:
1. Executing all `run` expressions (including `run main() with {}`)
2. Then ALSO calling `main_lux()` separately because `has_main` was true
**Fix:** Added tracking of whether main was already called via a `run` expression, and skip the separate `main_lux()` call if so.
---
## String Handling Issues
### 2. No Escape Sequences in String Literals
**Severity:** High
**Status:** Confirmed
Lux does not support backslash escape sequences like `\"`, `\n`, `\t` in string literals.
```lux
// This FAILS - backslash causes parse error
Console.print("Hello \"World\"") // ERROR: Unexpected character: '\'
// This FAILS
Console.print("Line1\nLine2") // ERROR: Unexpected character: '\'
```
**Impact:** Cannot include quotes in strings, cannot create multi-line strings, cannot output JSON with proper formatting.
**Workaround:**
- Use shell commands via `Process.exec` to generate quoted output
- Use `String.fromChar('"')` for quotes (but this had issues too)
- For JSON output, use key=value format instead
### 3. Dollar Sign in Strings Causes Parse Error
**Severity:** Medium
**Status:** Confirmed
The `$` character in strings triggers the string interpolation lexer, even inside shell command strings.
```lux
// This FAILS
execQuiet("jq -n --arg x '$foo' ...") // ERROR: Unexpected character: '$'
```
**Impact:** Cannot use shell variable syntax or jq arguments in command strings.
**Workaround:** Avoid `$` in strings, or construct commands differently.
### 4. String.fromChar Returns Int, Not String
**Severity:** Medium
**Status:** Bug
`String.fromChar('"')` appears to return an Int instead of a String, causing C compilation errors.
```lux
let q = String.fromChar('"') // Compiles but C code is wrong
Console.print(q + "hello") // C error: int + string
```
**Impact:** Cannot use character literals to build strings.
**Workaround:** Use `execQuiet("printf '%s' '\"'")` to get a quote character.
---
## Type System Issues
### 5. Record Type Definitions Don't Work as Expected
**Severity:** Medium
**Status:** Needs Investigation
Defining a record type and then creating values of that type doesn't work:
```lux
type ComponentStatus = {
name: String,
status: HealthStatus,
message: String,
fix: String
}
fn checkNb(): ComponentStatus with {Process} = {
// ...
{ name: "nb", status: Healthy, message: "ok", fix: "" }
// ERROR: Cannot unify { name: String, ... } with ComponentStatus
}
```
**Impact:** Cannot use structured types for cleaner code organization.
**Workaround:** Avoid record types, use multiple return values via tuples or restructure code.
### 6. Int.parse Doesn't Exist or Has Wrong Signature
**Severity:** Low
**Status:** Confirmed
There's no obvious way to parse a string to an integer.
```lux
let count = Int.parse(someString) // ERROR: Unknown effect operation
```
**Impact:** Cannot convert string output from shell commands to numbers.
**Workaround:** Keep numbers as strings, use shell for numeric comparisons.
---
## C Backend Issues
### 7. String Equality Comparison Generates Incorrect C Code
**Severity:** High
**Status:** Bug
Using `==` to compare strings generates C code that compares pointers instead of string contents.
```lux
let result = execQuiet("echo yes")
if result == "yes" then ... // C code: (result == "yes") - pointer comparison!
```
**Impact:** String comparisons fail in compiled binaries.
**Workaround:** Use `String.contains` for comparison:
```lux
fn isYes(s: String): Bool = String.contains(s, "yes")
if result |> isYes then ...
```
### 8. String.startsWith Not Available in C Backend
**Severity:** Medium
**Status:** Bug
`String.startsWith` works in interpreter but generates undefined function calls in C.
```lux
String.startsWith(s, "prefix") // C error: lux_string__startsWith undefined
```
**Workaround:** Use `String.contains` instead.
### 9. `let _ = expr` Pattern Not Supported
**Severity:** Low
**Status:** Bug
The underscore wildcard pattern for discarding results doesn't work.
```lux
let _ = Process.exec("...") // ERROR: Expected identifier
```
**Workaround:** Use a named binding:
```lux
let ignore = Process.exec("...")
```
### 10. List Literals and Recursion Cause Segfaults
**Severity:** High
**Status:** Bug
Combining list literals with recursive functions can cause segmentation faults in compiled binaries while working fine in interpreter.
```lux
// This crashes when compiled:
let dirs = ["a", "b", "c"]
fn processDirs(dirs: List<String>): Unit =
match List.head(dirs) {
Some(d) => { ...; match List.tail(dirs) { Some(rest) => processDirs(rest), ... } }
None => ()
}
```
**Workaround:** Avoid list literals with recursive processing. Inline the operations:
```lux
fn processA(): Unit = ...
fn processB(): Unit = ...
fn processC(): Unit = ...
// Call each individually
```
---
## Suggestions for Lux
1. **Add escape sequence support** - At minimum `\"`, `\\`, `\n`, `\t`
2. **Fix String.fromChar** to return String, not Int
3. **Add raw string literals** - Something like `r"..."` or `'''...'''` for shell commands
4. **Fix the double execution bug** in the runtime (DONE)
5. **Support record type literals** matching their declared type
6. **Add Int.parse and Float.parse** for string-to-number conversion
7. **Consider a heredoc syntax** for multi-line strings with special characters
8. **Fix string equality** - Use strcmp in C backend for string ==
9. **Support `let _ = `** - Allow underscore as discard binding
10. **Fix String.startsWith** in C backend
11. **Fix list literals with recursion** causing segfaults
---
## Current Workarounds in grapho CLI
1. **Double output:** FIXED in Lux c_backend.rs
2. **JSON output:** Using key=value format instead of proper JSON
3. **Quotes in output:** Avoided entirely or generated via shell
4. **Structured types:** Using individual variables instead of records
5. **Numeric parsing:** Keeping counts as strings throughout
6. **String comparison:** Using `String.contains` with helper functions instead of `==`
7. **Discarding results:** Using `let ignore = ...` instead of `let _ = ...`
8. **Lists with recursion:** Replaced with individual function calls

View File

@@ -1,6 +1,6 @@
# Markdown Editors for grapho
# Markdown Editors for pal
This document covers recommended markdown editors for use with grapho across desktop and mobile platforms.
This document covers recommended markdown editors for use with pal across desktop and mobile platforms.
## Recommended: md (PWA)
@@ -19,7 +19,7 @@ A lightweight, browser-based markdown editor that works on both desktop and mobi
- Syntax highlighting for code blocks
- Keyboard shortcuts (Ctrl+S to download, Ctrl+B/I for formatting)
### Why It's Good for grapho
### Why It's Good for pal
- Works on any device with a browser
- Can be installed as a PWA on mobile home screen
- No account required
@@ -156,7 +156,7 @@ The best open-source markdown editor for Android.
- Supports markdown, todo.txt, and more
- Offline-first
**Best for:** grapho users on Android.
**Best for:** pal users on Android.
### iA Writer (iOS/Android)
**Paid** | [Website](https://ia.net/writer)
@@ -187,12 +187,12 @@ Mobile companion to Obsidian desktop.
---
## Recommendation for grapho Users
## Recommendation for pal Users
### Simple Setup (Recommended)
1. **Desktop:** MarkText or VS Code
2. **Mobile:** md PWA (https://md-ashy.vercel.app) or Markor (Android)
3. **Sync:** Syncthing (already part of grapho)
3. **Sync:** Syncthing (already part of pal)
### Power User Setup
1. **Desktop:** Obsidian with Syncthing sync
@@ -206,7 +206,7 @@ Mobile companion to Obsidian desktop.
---
## Integration with grapho
## Integration with pal
All recommended editors work with plain markdown files, which means:
@@ -225,7 +225,7 @@ marktext ~/.nb/home/meeting-notes.md
# Or on mobile, open the same file via Syncthing folder
# Sync happens automatically
grapho sync
pal sync
```
## Sources

8
flake.lock generated
View File

@@ -47,13 +47,13 @@
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1771221263,
"narHash": "sha256-Av4s4pelV+ueIMSY61aHuT8KjKZ6ekXtJsnjVc89gtQ=",
"path": "/home/blu/src/lux",
"lastModified": 1771638380,
"narHash": "sha256-RLGfahDSlYi8ec50DtmfOZn9q8JpF2xBTcUb8K2ZQ3Q=",
"path": "/home/blu/src/lux/lang",
"type": "path"
},
"original": {
"path": "/home/blu/src/lux",
"path": "/home/blu/src/lux/lang",
"type": "path"
}
},

View File

@@ -15,7 +15,7 @@
};
lux = {
url = "path:/home/blu/src/lux";
url = "path:/home/blu/src/lux/lang";
inputs.nixpkgs.follows = "nixpkgs";
};
@@ -42,7 +42,7 @@
# Shared modules for all hosts
sharedModules = [
./modules/grapho.nix
./modules/pal.nix
./modules/nb.nix
./modules/syncthing.nix
./modules/backup.nix
@@ -66,36 +66,36 @@
};
in {
# Grapho CLI package
# Pal CLI package
packages = forAllSystems (system:
let
pkgs = nixpkgsFor.${system};
luxPkg = lux.packages.${system}.default;
in {
grapho = pkgs.stdenv.mkDerivation {
pname = "grapho";
pal = pkgs.stdenv.mkDerivation {
pname = "pal";
version = "0.1.0";
src = ./cli;
nativeBuildInputs = [ luxPkg pkgs.gcc ];
buildPhase = ''
${luxPkg}/bin/lux compile grapho.lux -o grapho
${luxPkg}/bin/lux compile pal.lux -o pal
'';
installPhase = ''
mkdir -p $out/bin
cp grapho $out/bin/
cp pal $out/bin/
'';
meta = {
description = "Personal data infrastructure CLI";
homepage = "https://github.com/user/grapho";
homepage = "https://github.com/user/pal";
license = pkgs.lib.licenses.mit;
};
};
default = self.packages.${system}.grapho;
default = self.packages.${system}.pal;
}
);
@@ -144,7 +144,7 @@
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"
echo " git clone ssh://git@your-server:2222/you/pal.git"
exit 1
fi
fi
@@ -173,6 +173,7 @@
packages = [
lux.packages.${system}.default
self.packages.${system}.pal
] ++ (with pkgs; [
# Tier 2: Notes & Sync
nb # Notebook CLI
@@ -203,12 +204,11 @@
]);
shellHook = ''
printf '\033[1m%s\033[0m\n' "Ultimate Notetaking, Sync & Backup System"
printf '\033[1m%s\033[0m\n' "pal - Your personal data, everywhere"
echo ""
echo "Get started: ./setup"
echo "Pair mobile: ./setup mobile"
echo "Sync: ./scripts/usync"
echo "Status: ./scripts/ustatus"
echo "Get started: pal onboard"
echo "Status: pal status"
echo "Help: pal help"
'';
};
}
@@ -216,7 +216,7 @@
# Export modules for use in other flakes
nixosModules = {
grapho = import ./modules/grapho.nix;
pal = import ./modules/pal.nix;
nb = import ./modules/nb.nix;
syncthing = import ./modules/syncthing.nix;
backup = import ./modules/backup.nix;

BIN
grapho

Binary file not shown.

View File

@@ -1,39 +1,39 @@
# Grapho Module
# Pal Module
#
# Unified personal data infrastructure module for NixOS.
# Sets up Syncthing (isolated) + Restic backup + directory structure.
#
# Usage:
# services.grapho.enable = true;
# services.grapho.user = "youruser";
# services.pal.enable = true;
# services.pal.user = "youruser";
#
# This creates:
# - ~/.config/grapho/ directory structure
# - ~/.config/pal/ directory structure
# - Isolated Syncthing on port 8385 (separate from system Syncthing)
# - Restic backup timer for grapho data
# - Restic backup timer for pal data
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.grapho;
cfg = config.services.pal;
home = config.users.users.${cfg.user}.home;
graphoDir = "${home}/.config/grapho";
palDir = "${home}/.config/pal";
in {
options.services.grapho = {
enable = mkEnableOption "grapho personal data infrastructure";
options.services.pal = {
enable = mkEnableOption "pal personal data infrastructure";
user = mkOption {
type = types.str;
description = "User to run grapho services as.";
description = "User to run pal services as.";
example = "alice";
};
group = mkOption {
type = types.str;
default = "users";
description = "Group to run grapho services as.";
description = "Group to run pal services as.";
};
# Syncthing options
@@ -41,7 +41,7 @@ in {
enable = mkOption {
type = types.bool;
default = true;
description = "Enable grapho's isolated Syncthing instance.";
description = "Enable pal's isolated Syncthing instance.";
};
guiPort = mkOption {
@@ -65,7 +65,7 @@ in {
openFirewall = mkOption {
type = types.bool;
default = true;
description = "Open firewall for grapho's Syncthing ports.";
description = "Open firewall for pal's Syncthing ports.";
};
devices = mkOption {
@@ -120,14 +120,14 @@ in {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable restic backup of grapho data.";
description = "Enable restic backup of pal data.";
};
repository = mkOption {
type = types.str;
default = "";
description = "Restic repository location (e.g., 'sftp:server:/backups/grapho').";
example = "sftp:backup-server:/backups/grapho";
description = "Restic repository location (e.g., 'sftp:server:/backups/pal').";
example = "sftp:backup-server:/backups/pal";
};
passwordFile = mkOption {
@@ -195,27 +195,27 @@ in {
isNormalUser = true;
};
# Create grapho directory structure
# Create pal directory structure
systemd.tmpfiles.rules = [
"d ${graphoDir} 0755 ${cfg.user} ${cfg.group} -"
"d ${graphoDir}/config-repo 0755 ${cfg.user} ${cfg.group} -"
"d ${graphoDir}/syncthing/config 0755 ${cfg.user} ${cfg.group} -"
"d ${graphoDir}/syncthing/db 0755 ${cfg.user} ${cfg.group} -"
"d ${graphoDir}/sync 0755 ${cfg.user} ${cfg.group} -"
"d ${graphoDir}/sync/notes 0755 ${cfg.user} ${cfg.group} -"
"d ${graphoDir}/sync/documents 0755 ${cfg.user} ${cfg.group} -"
"d ${graphoDir}/sync/dotfiles 0755 ${cfg.user} ${cfg.group} -"
"d ${graphoDir}/restic/cache 0755 ${cfg.user} ${cfg.group} -"
"d ${graphoDir}/server 0755 ${cfg.user} ${cfg.group} -"
"d ${palDir} 0755 ${cfg.user} ${cfg.group} -"
"d ${palDir}/config-repo 0755 ${cfg.user} ${cfg.group} -"
"d ${palDir}/syncthing/config 0755 ${cfg.user} ${cfg.group} -"
"d ${palDir}/syncthing/db 0755 ${cfg.user} ${cfg.group} -"
"d ${palDir}/sync 0755 ${cfg.user} ${cfg.group} -"
"d ${palDir}/sync/notes 0755 ${cfg.user} ${cfg.group} -"
"d ${palDir}/sync/documents 0755 ${cfg.user} ${cfg.group} -"
"d ${palDir}/sync/dotfiles 0755 ${cfg.user} ${cfg.group} -"
"d ${palDir}/restic/cache 0755 ${cfg.user} ${cfg.group} -"
"d ${palDir}/server 0755 ${cfg.user} ${cfg.group} -"
];
# Isolated Syncthing for grapho
# Isolated Syncthing for pal
services.syncthing = mkIf cfg.syncthing.enable {
enable = true;
user = cfg.user;
group = cfg.group;
dataDir = "${graphoDir}/sync";
configDir = "${graphoDir}/syncthing/config";
dataDir = "${palDir}/sync";
configDir = "${palDir}/syncthing/config";
guiAddress = "127.0.0.1:${toString cfg.syncthing.guiPort}";
overrideDevices = true;
@@ -228,24 +228,24 @@ in {
}) cfg.syncthing.devices;
folders = {
# Default grapho folders
"grapho-notes" = {
path = "${graphoDir}/sync/notes";
id = "grapho-notes";
# Default pal folders
"pal-notes" = {
path = "${palDir}/sync/notes";
id = "pal-notes";
devices = attrNames cfg.syncthing.devices;
type = "sendreceive";
fsWatcherEnabled = true;
};
"grapho-documents" = {
path = "${graphoDir}/sync/documents";
id = "grapho-documents";
"pal-documents" = {
path = "${palDir}/sync/documents";
id = "pal-documents";
devices = attrNames cfg.syncthing.devices;
type = "sendreceive";
fsWatcherEnabled = true;
};
"grapho-dotfiles" = {
path = "${graphoDir}/sync/dotfiles";
id = "grapho-dotfiles";
"pal-dotfiles" = {
path = "${palDir}/sync/dotfiles";
id = "pal-dotfiles";
devices = attrNames cfg.syncthing.devices;
type = "sendreceive";
fsWatcherEnabled = true;
@@ -271,15 +271,15 @@ in {
};
};
# Firewall for grapho Syncthing
# Firewall for pal Syncthing
networking.firewall = mkIf (cfg.syncthing.enable && cfg.syncthing.openFirewall) {
allowedTCPPorts = [ cfg.syncthing.syncPort ];
allowedUDPPorts = [ cfg.syncthing.syncPort cfg.syncthing.discoveryPort ];
};
# Restic backup service
systemd.services.grapho-backup = mkIf (cfg.backup.enable && cfg.backup.repository != "") {
description = "Grapho data backup";
systemd.services.pal-backup = mkIf (cfg.backup.enable && cfg.backup.repository != "") {
description = "Pal data backup";
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
@@ -288,18 +288,18 @@ in {
User = cfg.user;
Group = cfg.group;
ExecStart = let
paths = [ "${graphoDir}/sync" ] ++ cfg.backup.extraPaths;
paths = [ "${palDir}/sync" ] ++ cfg.backup.extraPaths;
pathArgs = concatMapStringsSep " " (p: "'${p}'") paths;
in ''
${pkgs.restic}/bin/restic backup \
--cache-dir ${graphoDir}/restic/cache \
--cache-dir ${palDir}/restic/cache \
${optionalString (cfg.backup.passwordFile != null) "--password-file ${cfg.backup.passwordFile}"} \
-r ${cfg.backup.repository} \
${pathArgs}
'';
ExecStartPost = ''
${pkgs.restic}/bin/restic forget \
--cache-dir ${graphoDir}/restic/cache \
--cache-dir ${palDir}/restic/cache \
${optionalString (cfg.backup.passwordFile != null) "--password-file ${cfg.backup.passwordFile}"} \
-r ${cfg.backup.repository} \
${concatStringsSep " " cfg.backup.pruneOpts}
@@ -307,8 +307,8 @@ in {
};
};
systemd.timers.grapho-backup = mkIf (cfg.backup.enable && cfg.backup.repository != "") {
description = "Grapho backup timer";
systemd.timers.pal-backup = mkIf (cfg.backup.enable && cfg.backup.repository != "") {
description = "Pal backup timer";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = cfg.backup.schedule;
@@ -318,7 +318,7 @@ in {
};
# Server mount (NFS)
fileSystems."${graphoDir}/server" = mkIf (cfg.server.enable && cfg.server.type == "nfs" && cfg.server.host != "") {
fileSystems."${palDir}/server" = mkIf (cfg.server.enable && cfg.server.type == "nfs" && cfg.server.host != "") {
device = "${cfg.server.host}:${cfg.server.remotePath}";
fsType = "nfs";
options = [
@@ -330,7 +330,7 @@ in {
];
};
# Install grapho CLI and dependencies
# Install pal CLI and dependencies
environment.systemPackages = with pkgs; [
syncthing
restic

2
setup
View File

@@ -133,7 +133,7 @@ EOF
age_key=$(grep 'AGE-SECRET-KEY' "$AGE_KEY_FILE")
# Build join command for other devices
local join_cmd="nix run '<grapho-flake>' -- '${config_url}' '${age_key}'"
local join_cmd="nix run '<pal-flake>' -- '${config_url}' '${age_key}'"
# Summary
echo ""