Brandon Lucas 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
2026-02-16 01:06:55 -05:00

Ultimate Notetaking, Sync & Backup System

A NixOS-based system for managing the three types of data across devices:

Tier Type Examples Sync Model
1 Configuration flake.nix, dotfiles Git (public, shareable)
2 Syncable Data Notes, documents Git (nb) + Syncthing
3 Large Data Photos, videos, repos Central backup, on-demand

Quick Start

# One-command setup (public repo, no SSH key needed)
nix run 'git+https://git.qrty.ink/blu/pal.git'

# Or clone first, then run
git clone https://git.qrty.ink/blu/pal.git
cd pal
nix run .

Full Setup Guide

First Computer (Initial Setup)

# 1. Clone the repo
git clone https://git.qrty.ink/blu/pal.git
cd pal

# 2. Run setup (one command - includes all dependencies)
nix run .
# Or: nix develop && ./setup

# 3. Choose option [1] "New setup (first device)"
#    This generates an age encryption key - SAVE IT!

# 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/pal.git

Additional Computers (Joining)

# One command (no SSH key needed for public repo)
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/pal.git && cd pal
nix run . -- <config-git-url> <your-age-key>

Mobile Device (Phone/Tablet)

# On any computer that's already set up:
nix run . -- mobile

# Or: ./setup mobile

This shows a QR code for Syncthing pairing. You can also manually paste device IDs.

Just Try the Tools (No Setup)

nix develop
# Provides: nb, syncthing, restic, rclone, age, sops, etc.

Apply as NixOS Module

Add to your flake.nix inputs, then import the module:

{
  inputs.pal.url = "git+https://git.qrty.ink/blu/pal.git";

  # In your configuration:
  imports = [ inputs.pal.nixosModules.default ];
}

Philosophy

  1. Config is code: Your system configuration should be version-controlled and shareable
  2. Notes deserve versioning: Use git-backed tools (nb) for notes, not just file sync
  3. Sync ≠ Backup: Syncthing syncs; restic backs up. Use both.
  4. Self-host when practical: Forgejo, Immich, Jellyfin over proprietary clouds
  5. Open source only: Every tool in this stack is FOSS

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    YOUR MACHINES                             │
│  ┌─────────┐    ┌─────────┐    ┌─────────┐                  │
│  │ Desktop │    │ Laptop  │    │ Phone   │                  │
│  └────┬────┘    └────┬────┘    └────┬────┘                  │
│       │              │              │                        │
│       └──────────────┼──────────────┘                        │
│                      │                                       │
│              ┌───────▼───────┐                               │
│              │   TIER 2      │                               │
│              │  nb (notes)   │◄── git push/pull             │
│              │  Syncthing    │◄── P2P sync (optional)       │
│              └───────────────┘                               │
└─────────────────────────────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│                    YOUR SERVER                               │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │   Forgejo   │  │   Immich    │  │  Jellyfin   │         │
│  │  (git/nb)   │  │  (photos)   │  │  (media)    │         │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘         │
│         └────────────────┼────────────────┘                 │
│                          │                                   │
│                   ┌──────▼──────┐                           │
│                   │   restic    │                           │
│                   │  (backup)   │                           │
│                   └──────┬──────┘                           │
│                          │                                   │
│                   ┌──────▼──────┐                           │
│                   │ B2 / NAS    │                           │
│                   │ (offsite)   │                           │
│                   └─────────────┘                           │
└─────────────────────────────────────────────────────────────┘

What's Included

NixOS Modules

  • modules/nb.nix - nb notebook CLI installation and configuration
  • modules/syncthing.nix - Declarative Syncthing setup
  • modules/neovim.nix - Neovim with nb integration
  • modules/backup.nix - restic backup timers
  • modules/server/ - Forgejo, Immich, Jellyfin configurations

Development Shell

nix develop

Provides: nb, syncthing, restic, rclone, jq, and helper scripts.

Helper Scripts

  • usync - Unified sync command (syncs nb + triggers Syncthing scan)
  • ubackup - Run restic backup manually
  • ustatus - Show sync/backup status across all tiers

Usage

Tier 1: Configuration

Your system config lives in this repo. Fork it, customize it, push to your own GitHub.

# Rebuild your system
sudo nixos-rebuild switch --flake .#your-hostname

# Update flake inputs
nix flake update

Tier 2: Notes with nb

# Create a note
nb add "My note title"

# Edit with neovim
nb edit 1

# Sync to remote
nb sync

# Search notes
nb search "keyword"

# List notebooks
nb notebooks

Set up git remote for nb:

nb remote set git@your-forgejo:you/notes.git

Tier 2: Documents with Syncthing

Documents in ~/Documents/ sync automatically via Syncthing.

# Check Syncthing status
syncthing cli show system

# Force rescan
syncthing cli scan --folder documents

Tier 3: Large Data

Photos upload to Immich (mobile app or web). Media is served via Jellyfin. Manual files can be uploaded with rclone:

# Upload to your server
rclone copy ~/Videos/project server:archive/videos/

# List remote files
rclone ls server:archive/

Customization

Adding Your Own Notebooks

Edit modules/nb.nix:

{
  programs.nb = {
    notebooks = {
      personal = {
        remote = "git@forgejo:you/personal-notes.git";
      };
      work = {
        remote = "git@forgejo:you/work-notes.git";
      };
    };
  };
}

Syncthing Folders

Edit modules/syncthing.nix:

{
  services.syncthing.settings.folders = {
    "documents" = {
      path = "~/Documents";
      devices = [ "laptop" "desktop" ];
    };
    "music" = {
      path = "~/Music";
      devices = [ "laptop" "desktop" "server" ];
    };
  };
}

Backup Paths

Edit modules/backup.nix:

{
  services.restic.backups.default = {
    paths = [
      "/home/you/Documents"
      "/home/you/notes"
      "/var/lib/important"
    ];
  };
}

FAQ

Why nb instead of Obsidian/Notion/etc?

  • Git-native: Full version history, proper merges
  • Plain text: Markdown files, no vendor lock-in
  • CLI-first: Works over SSH, in tmux, everywhere
  • Scriptable: Integrates with shell workflows
  • Encrypted option: Built-in GPG encryption

Why not just Syncthing for everything?

Syncthing is great for binary files but poor for text conflicts. When you edit notes on multiple devices, you want git-style merges, not .sync-conflict files scattered everywhere.

Is Syncthing buggy?

No. See our research. Common issues are:

  • Treating it as a backup (it's not)
  • Android battery killing the app (use Syncthing-Fork)
  • Expecting cloud-style behavior from P2P sync

Why self-host?

  • Control: Your data on your hardware
  • Privacy: No third-party access
  • Cost: One-time hardware vs. monthly subscriptions
  • Learning: Valuable sysadmin experience

But cloud is fine too. This system works with GitHub, Backblaze B2, etc.

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
│   ├── backup.nix
│   └── server/
│       ├── forgejo.nix
│       ├── immich.nix
│       └── jellyfin.nix
├── hosts/
│   ├── desktop/
│   │   └── configuration.nix
│   ├── laptop/
│   │   └── configuration.nix
│   └── server/
│       └── configuration.nix
├── home/
│   └── default.nix           # home-manager config
└── scripts/
    ├── usync
    ├── ubackup
    └── 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 first.

License

MIT


Built with Nix, because reproducibility matters.

Description
No description provided
Readme 496 KiB
Languages
Nix 58.7%
Shell 41.3%