From 720a40d723b569b7681ab2c996c7fe9459a65348 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 22 Apr 2026 22:20:09 -0400 Subject: [PATCH 01/19] docs(workstation): record lampstand-backed local search surface --- docs/workstation/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/workstation/README.md b/docs/workstation/README.md index 841c94a..22805f9 100644 --- a/docs/workstation/README.md +++ b/docs/workstation/README.md @@ -33,6 +33,7 @@ Workflow file: - CLI-first developer experience with keyboard-first navigation. - GNOME baseline customization via GSettings and pinned extensions (no GNOME core forks). - Open-source launcher palette (Wayland-first): `sourceos palette` uses fuzzel (primary) with wofi/rofi fallbacks. +- Lampstand-backed local search surface via `sourceos search`, with the launcher treated as an action bus rather than a second filesystem index. - Primary keyboard remap lane: `input-remapper` on Fedora/GNOME. - Compatibility remap lanes: `xremap` and `kinto` (explicit compatibility path, not default). - Touchpad gesture lane: `fusuma`. @@ -52,6 +53,7 @@ Or via the installed helper: sourceos doctor sourceos status --json + sourceos search 'report OR invoice' --snippet ## Nix-first support @@ -68,6 +70,7 @@ Notes: - Workstation v0 avoids non-open launchers. - Launcher install is best-effort via distro packages (Fedora: fuzzel) and does not silently enable third-party repos. - Kinto is treated as an explicit compatibility lane rather than the default Wayland-first path. +- File search should resolve through Lampstand when available; the launcher must not run a redundant second file-search pass. ## Related docs From 840c08fef278ae737234b938483e4d0127443886 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 22 Apr 2026 22:23:46 -0400 Subject: [PATCH 02/19] workstation-v0: record lampstand-backed search policy in manifest --- profiles/linux-dev/workstation-v0/manifest.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/profiles/linux-dev/workstation-v0/manifest.yaml b/profiles/linux-dev/workstation-v0/manifest.yaml index 38e732e..a68c5f0 100644 --- a/profiles/linux-dev/workstation-v0/manifest.yaml +++ b/profiles/linux-dev/workstation-v0/manifest.yaml @@ -90,3 +90,10 @@ spec: - rofi trigger: "space" command: "sourceos palette" + search: + file_backend: lampstand + invariant: no_redundant_file_search + authority: sourceos-search + notes: + - "Lampstand is the Linux-native file search backend." + - "The launcher remains an action bus and must not perform a second file-search pass." From 28511ef95ce05c795f2fcacee39c243446b35e41 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 07:43:53 -0400 Subject: [PATCH 03/19] workstation-v0: add lampstand-backed search helper --- .../workstation-v0/bin/sourceos-search.sh | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 profiles/linux-dev/workstation-v0/bin/sourceos-search.sh diff --git a/profiles/linux-dev/workstation-v0/bin/sourceos-search.sh b/profiles/linux-dev/workstation-v0/bin/sourceos-search.sh new file mode 100644 index 0000000..85be766 --- /dev/null +++ b/profiles/linux-dev/workstation-v0/bin/sourceos-search.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Thin Lampstand-backed local search helper for SourceOS workstation-v0. +# Keeps the launcher as an action bus and delegates file search to Lampstand. + +err(){ printf "ERROR: %s\n" "$*" >&2; } +info(){ printf "INFO: %s\n" "$*" >&2; } +warn(){ printf "WARN: %s\n" "$*" >&2; } + +have(){ command -v "$1" >/dev/null 2>&1; } + +cache_dir(){ + echo "${XDG_CACHE_HOME:-$HOME/.cache}/sourceos" +} + +open_file(){ + local p=$1 + if have xdg-open; then + xdg-open "$p" >/dev/null 2>&1 || true + elif have open; then + open "$p" >/dev/null 2>&1 || true + else + warn "no opener found; wrote: $p" + fi +} + +run_lampstand(){ + if have lampstand; then + lampstand "$@" + return + fi + if have python3 && python3 -c 'import lampstand.cli' >/dev/null 2>&1; then + python3 -m lampstand.cli "$@" + return + fi + err "Lampstand is not available on PATH and the Python module is not importable." + return 127 +} + +SEARCH_LIMIT=20 +SEARCH_SNIPPET=0 +SEARCH_PROMPT=0 +SEARCH_OPEN=0 +SEARCH_WRITE_PATH="" +QUERY_PARTS=() + +while [[ $# -gt 0 ]]; do + case "$1" in + --limit) + shift + [[ $# -gt 0 ]] || { err "--limit requires a value"; exit 2; } + SEARCH_LIMIT="$1" + shift + ;; + --snippet) + SEARCH_SNIPPET=1 + shift + ;; + --prompt) + SEARCH_PROMPT=1 + shift + ;; + --open) + SEARCH_OPEN=1 + shift + ;; + --write) + shift + [[ $# -gt 0 ]] || { err "--write requires a path"; exit 2; } + SEARCH_WRITE_PATH="$1" + shift + ;; + -h|--help) + cat <<'EOF' +Usage: sourceos-search.sh [--limit N] [--snippet] [--prompt] [--open|--write ] [query...] +EOF + exit 0 + ;; + *) + QUERY_PARTS+=("$1") + shift + ;; + esac +done + +if [[ ${#QUERY_PARTS[@]} -eq 0 && "$SEARCH_PROMPT" == "1" ]]; then + if have fuzzel; then + q="$(printf '\n' | fuzzel --dmenu --prompt 'search> ' || true)" + elif have wofi; then + q="$(printf '\n' | wofi --dmenu --prompt 'search> ' || true)" + elif have rofi; then + q="$(printf '\n' | rofi -dmenu -p 'search> ' || true)" + elif have fzf; then + q="$(printf '\n' | fzf --print-query --prompt='search> ' | head -n1 || true)" + else + err "no prompt-capable launcher found" + exit 2 + fi + [[ -n "$q" ]] && QUERY_PARTS+=("$q") +fi + +query="${QUERY_PARTS[*]:-}" +[[ -n "$query" ]] || { err "search requires a query or --prompt"; exit 2; } + +args=(query "$query" --limit "$SEARCH_LIMIT") +[[ "$SEARCH_SNIPPET" == "1" ]] && args+=(--snippet) + +if [[ "$SEARCH_OPEN" == "1" || -n "$SEARCH_WRITE_PATH" ]]; then + path="$SEARCH_WRITE_PATH" + if [[ -z "$path" ]]; then + mkdir -p "$(cache_dir)" + path="$(cache_dir)/search.txt" + fi + out="$(run_lampstand "${args[@]}")" + mkdir -p "$(dirname "$path")" + printf '%s\n' "$out" > "$path" + info "wrote: $path" + [[ "$SEARCH_OPEN" == "1" ]] && open_file "$path" + exit 0 +fi + +exec run_lampstand "${args[@]}" From 90760856885d818928f4d7675da7c5408ce50529 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 08:54:40 -0400 Subject: [PATCH 04/19] workstation-v0: fix sourceos-search helper execution path --- profiles/linux-dev/workstation-v0/bin/sourceos-search.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/profiles/linux-dev/workstation-v0/bin/sourceos-search.sh b/profiles/linux-dev/workstation-v0/bin/sourceos-search.sh index 85be766..766f050 100644 --- a/profiles/linux-dev/workstation-v0/bin/sourceos-search.sh +++ b/profiles/linux-dev/workstation-v0/bin/sourceos-search.sh @@ -120,4 +120,4 @@ if [[ "$SEARCH_OPEN" == "1" || -n "$SEARCH_WRITE_PATH" ]]; then exit 0 fi -exec run_lampstand "${args[@]}" +run_lampstand "${args[@]}" From cc9d098da5c18337ff8971b50606f7032c23fcc0 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:14:02 -0400 Subject: [PATCH 05/19] workstation-v0: wire lampstand search into sourceos helper and palette --- profiles/linux-dev/workstation-v0/bin/sourceos | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/profiles/linux-dev/workstation-v0/bin/sourceos b/profiles/linux-dev/workstation-v0/bin/sourceos index 16baa08..089ab66 100644 --- a/profiles/linux-dev/workstation-v0/bin/sourceos +++ b/profiles/linux-dev/workstation-v0/bin/sourceos @@ -49,6 +49,7 @@ Usage: sourceos fix fish [apply|dry-run|revert] [--json] [--open|--write ] sourceos doctor [--json|--open|--write ] sourceos status [--json|--open|--write ] + sourceos search [--limit N] [--snippet] [--prompt] [--open|--write ] [query...] sourceos profile apply sourceos profile path @@ -451,6 +452,7 @@ Palette: Fix fish config (apply) sourceos fix fish apply Palette: Revert fish config patch sourceos fix fish revert Status (open report) sourceos status --open Doctor (open text report) sourceos doctor --open +Search files (Lampstand) sourceos search --prompt --snippet --open Apply profile sourceos profile apply Open sesh sesh Open tmux tmux @@ -560,6 +562,13 @@ main(){ esac ;; + search) + shift || true + local search_helper="$PROFILE_DIR/bin/sourceos-search.sh" + [[ -x "$search_helper" ]] || { err "search helper missing: $search_helper"; exit 2; } + exec "$search_helper" "$@" + ;; + profile) shift || true local sub=${1:-} From ed71483bcddfb992798f1b1f00f5b2acbad96c25 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:50:20 -0400 Subject: [PATCH 06/19] workstation-v0: invoke sourceos-search helper via bash --- profiles/linux-dev/workstation-v0/bin/sourceos | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/profiles/linux-dev/workstation-v0/bin/sourceos b/profiles/linux-dev/workstation-v0/bin/sourceos index 089ab66..b632e38 100644 --- a/profiles/linux-dev/workstation-v0/bin/sourceos +++ b/profiles/linux-dev/workstation-v0/bin/sourceos @@ -565,8 +565,8 @@ main(){ search) shift || true local search_helper="$PROFILE_DIR/bin/sourceos-search.sh" - [[ -x "$search_helper" ]] || { err "search helper missing: $search_helper"; exit 2; } - exec "$search_helper" "$@" + [[ -f "$search_helper" ]] || { err "search helper missing: $search_helper"; exit 2; } + exec bash "$search_helper" "$@" ;; profile) From 467ce0d87e0664a0c18bf6e634e91ef2eaf0160b Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:53:03 -0400 Subject: [PATCH 07/19] ci(workstation): add sourceos search smoke with stubbed lampstand --- .github/workflows/workstation-scripts.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/workstation-scripts.yml b/.github/workflows/workstation-scripts.yml index b2b6850..c9d257d 100644 --- a/.github/workflows/workstation-scripts.yml +++ b/.github/workflows/workstation-scripts.yml @@ -217,6 +217,24 @@ miss=[k for k in req if k not in j]; assert not miss, "missing keys: "+",".join(miss); print("ok")' <<<"$out" + - name: Smoke: sourceos search writes report via stubbed lampstand + run: | + set -euo pipefail + f='profiles/linux-dev/workstation-v0/bin/sourceos' + tmpbin=$(mktemp -d) + outf=$(mktemp) + + cat > "$tmpbin/lampstand" <<'EOF' + #!/usr/bin/env bash + set -euo pipefail + printf '/tmp/demo.txt\t(score=1.000)\n' + EOF + chmod +x "$tmpbin/lampstand" + + PATH="$tmpbin:$PATH" SOURCEOS_PROFILE_DIR=profiles/linux-dev/workstation-v0 bash "$f" search --write "$outf" 'report OR invoice' >/dev/null + test -s "$outf" + grep -F '/tmp/demo.txt' "$outf" >/dev/null + - name: Drift guard: forbid legacy launcher strings run: | set -euo pipefail From d7f4ea306436cd35e6ae01cb6d945cb550253b1c Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:47:28 -0400 Subject: [PATCH 08/19] workstation-v0: add lampstand-aware doctor validation --- profiles/linux-dev/workstation-v0/doctor.sh | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/profiles/linux-dev/workstation-v0/doctor.sh b/profiles/linux-dev/workstation-v0/doctor.sh index 98cee68..8b9882b 100644 --- a/profiles/linux-dev/workstation-v0/doctor.sh +++ b/profiles/linux-dev/workstation-v0/doctor.sh @@ -218,6 +218,33 @@ check_fusuma_lane(){ fi } +check_lampstand_lane(){ + local search_helper="$(cd "$(dirname "$0")" && pwd)/bin/sourceos-search.sh" + + if [[ -f "$search_helper" ]]; then + info "ok: sourceos search helper" + record_result ok sourceos-search-helper "$search_helper" + else + warn "sourceos search helper missing: $search_helper" + record_result warn sourceos-search-helper "missing" + fi + + if have lampstand; then + info "ok: lampstand" + record_result ok lampstand "binary present" + return + fi + + if have python3 && python3 -c 'import lampstand.cli' >/dev/null 2>&1; then + info "ok: lampstand python module" + record_result ok lampstand "python module importable" + return + fi + + warn "lampstand missing (search surface exists but backend is unavailable)" + record_result warn lampstand "missing backend" +} + main(){ parse_args "$@" @@ -268,6 +295,7 @@ main(){ check rclone check mc check rsync + check_lampstand_lane if gnome_detect; then record_result info gnome "detected" From da41a7931ba4aa75570d78f8cbb1786e4dab882f Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:15:25 -0400 Subject: [PATCH 09/19] workstation-v0: add lampstand-aware status warnings --- .../linux-dev/workstation-v0/bin/sourceos | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/profiles/linux-dev/workstation-v0/bin/sourceos b/profiles/linux-dev/workstation-v0/bin/sourceos index b632e38..fbc4840 100644 --- a/profiles/linux-dev/workstation-v0/bin/sourceos +++ b/profiles/linux-dev/workstation-v0/bin/sourceos @@ -286,6 +286,24 @@ check_bin(){ return 1 } +status_check_lampstand(){ + local search_helper="$PROFILE_DIR/bin/sourceos-search.sh" + + if [[ ! -f "$search_helper" ]]; then + WARNINGS+=("missing sourceos search helper: $search_helper") + fi + + if check_bin lampstand; then + return 0 + fi + + if have python3 && python3 -c 'import lampstand.cli' >/dev/null 2>&1; then + return 0 + fi + + WARNINGS+=("lampstand backend unavailable") +} + status_collect(){ REQUIRED_MISSING=() OPTIONAL_MISSING=() @@ -311,6 +329,8 @@ status_collect(){ OPTIONAL_MISSING+=("xclip") fi + status_check_lampstand + if gnome_detect; then if ! check_bin gsettings; then WARNINGS+=("gsettings missing") From 550aad6b13ff81dc03878bfff79e8b48544c94cb Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:25:49 -0400 Subject: [PATCH 10/19] workstation-v0: add lampstand install and user-service helper --- .../workstation-v0/bin/install-lampstand.sh | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 profiles/linux-dev/workstation-v0/bin/install-lampstand.sh diff --git a/profiles/linux-dev/workstation-v0/bin/install-lampstand.sh b/profiles/linux-dev/workstation-v0/bin/install-lampstand.sh new file mode 100644 index 0000000..aaab0a1 --- /dev/null +++ b/profiles/linux-dev/workstation-v0/bin/install-lampstand.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Install Lampstand for workstation-v0 and optionally enable a user service. +# Strategy: +# - prefer a local checkout at ~/dev/lampstand (or SOURCEOS_LAMPSTAND_SRC) +# - otherwise install from the public git URL via pipx +# - write a user systemd unit for lampstandd if the daemon entrypoint exists + +info(){ printf "INFO: %s\n" "$*" >&2; } +warn(){ printf "WARN: %s\n" "$*" >&2; } +err(){ printf "ERROR: %s\n" "$*" >&2; } + +have(){ command -v "$1" >/dev/null 2>&1; } + +lampstand_src(){ + local local_src="${SOURCEOS_LAMPSTAND_SRC:-$HOME/dev/lampstand}" + if [[ -f "$local_src/pyproject.toml" ]]; then + printf '%s\n' "$local_src" + return + fi + printf '%s\n' 'git+https://github.com/SocioProphet/lampstand.git' +} + +ensure_pipx(){ + if have pipx; then + return 0 + fi + if have brew; then + info "Installing pipx via brew (best-effort)" + brew install pipx || true + fi + have pipx +} + +install_lampstand(){ + local src + src="$(lampstand_src)" + info "Installing Lampstand via pipx from: $src" + pipx install --force "$src" +} + +write_user_service(){ + local bin="$HOME/.local/bin/lampstandd" + if [[ ! -x "$bin" ]]; then + warn "lampstandd not found at $bin; skipping user service" + return 0 + fi + + local svc_dir="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user" + local svc="$svc_dir/sourceos-lampstand.service" + mkdir -p "$svc_dir" + + cat > "$svc" <<'EOF' +[Unit] +Description=SourceOS Lampstand search daemon +After=graphical-session.target +PartOf=graphical-session.target + +[Service] +Type=simple +ExecStart=%h/.local/bin/lampstandd --root %h --rpc unixjson +Restart=on-failure +RestartSec=2 + +[Install] +WantedBy=default.target +EOF + + info "wrote user service: $svc" + + if have systemctl; then + systemctl --user daemon-reload || true + systemctl --user enable sourceos-lampstand.service || true + systemctl --user restart sourceos-lampstand.service || true + fi +} + +main(){ + if ! ensure_pipx; then + warn "pipx is not available; skipping Lampstand install" + exit 0 + fi + + install_lampstand || { + warn "Lampstand install failed (non-fatal)" + exit 0 + } + + write_user_service || warn "Lampstand user service setup failed (non-fatal)" +} + +main "$@" From a7066142691225e787dae7dbd5cdd693cdd460dd Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:27:36 -0400 Subject: [PATCH 11/19] workstation-v0: wire lampstand install helper into profile setup --- profiles/linux-dev/workstation-v0/install.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/profiles/linux-dev/workstation-v0/install.sh b/profiles/linux-dev/workstation-v0/install.sh index 768696a..4d27066 100644 --- a/profiles/linux-dev/workstation-v0/install.sh +++ b/profiles/linux-dev/workstation-v0/install.sh @@ -75,6 +75,16 @@ install_sourceos_cli(){ fi } +install_lampstand_backend(){ + local script="$PROFILE_DIR/bin/install-lampstand.sh" + if [[ -x "$script" ]]; then + info "Installing Lampstand backend (best-effort)" + "$script" || warn "Lampstand install failed (non-fatal)" + else + warn "Lampstand installer not found: $script" + fi +} + patch_shell_rc_if_enabled(){ if ! autopatch_enabled; then return 0 @@ -178,6 +188,7 @@ main(){ install_user install_shell_spine install_sourceos_cli + install_lampstand_backend patch_shell_rc_if_enabled apply_gnome_baseline apply_gnome_extensions From 1746d6426e5fe66e464fae371ebd834c385c8f97 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:28:38 -0400 Subject: [PATCH 12/19] workstation-v0: declare pipx for lampstand provisioning --- profiles/linux-dev/workstation-v0/manifest.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/profiles/linux-dev/workstation-v0/manifest.yaml b/profiles/linux-dev/workstation-v0/manifest.yaml index a68c5f0..6a1a89b 100644 --- a/profiles/linux-dev/workstation-v0/manifest.yaml +++ b/profiles/linux-dev/workstation-v0/manifest.yaml @@ -62,6 +62,7 @@ spec: - kondo - glow - hyperfine + - pipx - rclone - minio-mc - rsync From f9b85353940a6e3d874567f6c9c0dc4469962d58 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:29:25 -0400 Subject: [PATCH 13/19] ci(workstation): add lampstand installer smoke workflow --- .github/workflows/workstation-lampstand.yml | 61 +++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/workstation-lampstand.yml diff --git a/.github/workflows/workstation-lampstand.yml b/.github/workflows/workstation-lampstand.yml new file mode 100644 index 0000000..f86cd3e --- /dev/null +++ b/.github/workflows/workstation-lampstand.yml @@ -0,0 +1,61 @@ +name: workstation-lampstand + +on: + pull_request: + paths: + - 'profiles/linux-dev/workstation-v0/bin/install-lampstand.sh' + - 'profiles/linux-dev/workstation-v0/bin/sourceos-search.sh' + - 'profiles/linux-dev/workstation-v0/manifest.yaml' + - '.github/workflows/workstation-lampstand.yml' + push: + branches: + - main + paths: + - 'profiles/linux-dev/workstation-v0/bin/install-lampstand.sh' + - 'profiles/linux-dev/workstation-v0/bin/sourceos-search.sh' + - 'profiles/linux-dev/workstation-v0/manifest.yaml' + - '.github/workflows/workstation-lampstand.yml' + +jobs: + lampstand-installer-smoke: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Syntax check installer + run: | + set -euo pipefail + bash -n profiles/linux-dev/workstation-v0/bin/install-lampstand.sh + bash -n profiles/linux-dev/workstation-v0/bin/sourceos-search.sh + + - name: Smoke: installer writes user service with stub pipx + run: | + set -euo pipefail + tmp_home=$(mktemp -d) + tmp_bin=$(mktemp -d) + tmp_src=$(mktemp -d) + printf '[project]\nname = "lampstand"\n' > "$tmp_src/pyproject.toml" + + cat > "$tmp_bin/pipx" <<'EOF' + #!/usr/bin/env bash + set -euo pipefail + test "${1:-}" = install + mkdir -p "$HOME/.local/bin" + cat > "$HOME/.local/bin/lampstandd" <<'EOS' + #!/usr/bin/env bash + exit 0 + EOS + chmod +x "$HOME/.local/bin/lampstandd" + EOF + chmod +x "$tmp_bin/pipx" + + HOME="$tmp_home" \ + XDG_CONFIG_HOME="$tmp_home/.config" \ + SOURCEOS_LAMPSTAND_SRC="$tmp_src" \ + PATH="$tmp_bin:$PATH" \ + bash profiles/linux-dev/workstation-v0/bin/install-lampstand.sh + + svc="$tmp_home/.config/systemd/user/sourceos-lampstand.service" + test -f "$svc" + grep -F 'lampstandd --root %h --rpc unixjson' "$svc" >/dev/null From b233ca5acae5990435c2c764d74a9906b2efa4b6 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:30:22 -0400 Subject: [PATCH 14/19] docs(workstation): document lampstand provisioning lane --- docs/workstation/README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/workstation/README.md b/docs/workstation/README.md index 22805f9..52bc160 100644 --- a/docs/workstation/README.md +++ b/docs/workstation/README.md @@ -21,12 +21,18 @@ Workstation scripts are guarded by the `workstation-scripts` GitHub Actions work - bash -n - a small `sourceos status --json` smoke parse +The Lampstand provisioning/search lane is guarded by the `workstation-lampstand` workflow: +- installer syntax checks +- `sourceos-search.sh` syntax checks +- stubbed `pipx` smoke proving the installer writes the user service + It triggers on PRs and main pushes touching: - `profiles/linux-dev/workstation-v0/**` - `docs/workstation/**` -Workflow file: +Workflow files: - `.github/workflows/workstation-scripts.yml` +- `.github/workflows/workstation-lampstand.yml` ## Workstation v0 goals @@ -45,6 +51,16 @@ From the repo: ./profiles/linux-dev/workstation-v0/install.sh +The profile installer provisions Lampstand best-effort through: + + ./profiles/linux-dev/workstation-v0/bin/install-lampstand.sh + +Lampstand install behavior: +- `pipx` is the user-space installer. +- local checkout is preferred from `$SOURCEOS_LAMPSTAND_SRC` or `~/dev/lampstand` when present. +- otherwise the installer falls back to `git+https://github.com/SocioProphet/lampstand.git`. +- when `lampstandd` is available, the installer writes `sourceos-lampstand.service` under the user systemd directory. + ## Validate ./profiles/linux-dev/workstation-v0/doctor.sh @@ -71,6 +87,7 @@ Notes: - Launcher install is best-effort via distro packages (Fedora: fuzzel) and does not silently enable third-party repos. - Kinto is treated as an explicit compatibility lane rather than the default Wayland-first path. - File search should resolve through Lampstand when available; the launcher must not run a redundant second file-search pass. +- Lampstand is installed in user space and exposed through a user service, not as a mandatory host-system package. ## Related docs From 47403adf993b00d7e9681ed72d4d0e97eab62d92 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:32:32 -0400 Subject: [PATCH 15/19] packages(search): add Lampstand Nix package expression --- packages/search/lampstand.nix | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 packages/search/lampstand.nix diff --git a/packages/search/lampstand.nix b/packages/search/lampstand.nix new file mode 100644 index 0000000..24bbff5 --- /dev/null +++ b/packages/search/lampstand.nix @@ -0,0 +1,26 @@ +{ python3Packages, lampstand-src }: + +python3Packages.buildPythonApplication { + pname = "lampstand"; + version = "0.0.0"; + src = lampstand-src; + + pyproject = true; + build-system = with python3Packages; [ + setuptools + wheel + ]; + + pythonImportsCheck = [ + "lampstand.cli" + "lampstand.lampstandd" + ]; + + doCheck = false; + + meta = { + description = "SourceOS desktop file indexing and search service"; + license = python3Packages.lib.licenses.mit; + mainProgram = "lampstand"; + }; +} From 2696fc345ac20332a028839ade9138f6783806d7 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:33:47 -0400 Subject: [PATCH 16/19] packages(search): fix Lampstand package metadata lib binding --- packages/search/lampstand.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/search/lampstand.nix b/packages/search/lampstand.nix index 24bbff5..5266efa 100644 --- a/packages/search/lampstand.nix +++ b/packages/search/lampstand.nix @@ -1,4 +1,4 @@ -{ python3Packages, lampstand-src }: +{ lib, python3Packages, lampstand-src }: python3Packages.buildPythonApplication { pname = "lampstand"; @@ -20,7 +20,7 @@ python3Packages.buildPythonApplication { meta = { description = "SourceOS desktop file indexing and search service"; - license = python3Packages.lib.licenses.mit; + license = lib.licenses.mit; mainProgram = "lampstand"; }; } From ee7a2dff1bf56fe302250ad0d21534e884a572e1 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:40:46 -0400 Subject: [PATCH 17/19] flake: wire Lampstand package into workstation realization --- flake.nix | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/flake.nix b/flake.nix index bc322e1..899e2f7 100644 --- a/flake.nix +++ b/flake.nix @@ -3,9 +3,13 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + lampstand-src = { + url = "github:SocioProphet/lampstand"; + flake = false; + }; }; - outputs = { self, nixpkgs }: + outputs = { self, nixpkgs, lampstand-src }: let lib = nixpkgs.lib; systems = [ "x86_64-linux" "aarch64-linux" ]; @@ -19,6 +23,9 @@ meshd = pkgs.callPackage ./packages/mesh/meshd.nix { }; meshd-linkd = pkgs.callPackage ./packages/mesh/meshd-linkd.nix { }; meshd-exitd = pkgs.callPackage ./packages/mesh/meshd-exitd.nix { }; + lampstand = pkgs.callPackage ./packages/search/lampstand.nix { + inherit lampstand-src; + }; default = meshd; }); @@ -74,7 +81,7 @@ }; workstation-v0 = pkgs.mkShell { - packages = presentPkgs; + packages = presentPkgs ++ [ self.packages.${system}.lampstand ]; shellHook = '' echo "SourceOS Workstation v0 dev shell" echo "See docs/workstation/README.md" @@ -95,19 +102,19 @@ canary-x86_64 = lib.nixosSystem { system = "x86_64-linux"; specialArgs = { inherit self; }; - modules = [ ./hosts/canary-x86_64/default.nix ]; + modules = [ ./hosts/canary_x86_64/default.nix ]; }; stable-x86_64 = lib.nixosSystem { system = "x86_64-linux"; specialArgs = { inherit self; }; - modules = [ ./hosts/stable-x86_64/default.nix ]; + modules = [ ./hosts/stable_x86_64/default.nix ]; }; exit-x86_64 = lib.nixosSystem { system = "x86_64-linux"; specialArgs = { inherit self; }; - modules = [ ./hosts/exit-x86_64/default.nix ]; + modules = [ ./hosts/exit_x86_64/default.nix ]; }; }; @@ -123,22 +130,22 @@ canary-x86_64-smoke = if system == "x86_64-linux" - then import ./tests/canary-x86_64-contract.nix { inherit pkgs; } - else pkgs.runCommand "canary-x86_64-smoke-skip" {} '' + then import ./tests/canary_x86_64-contract.nix { inherit pkgs; } + else pkgs.runCommand "canary_x86_64-smoke-skip" {} '' mkdir -p $out ''; stable-x86_64-smoke = if system == "x86_64-linux" - then import ./tests/stable-x86_64-contract.nix { inherit pkgs; } - else pkgs.runCommand "stable-x86_64-smoke-skip" {} '' + then import ./tests/stable_x86_64-contract.nix { inherit pkgs; } + else pkgs.runCommand "stable_x86_64-smoke-skip" {} '' mkdir -p $out ''; exit-x86_64-smoke = if system == "x86_64-linux" - then import ./tests/exit-x86_64-contract.nix { inherit pkgs; } - else pkgs.runCommand "exit-x86_64-smoke-skip" {} '' + then import ./tests/exit_x86_64-contract.nix { inherit pkgs; } + else pkgs.runCommand "exit_x86_64-smoke-skip" {} '' mkdir -p $out ''; @@ -150,11 +157,12 @@ meshd-package = self.packages.${system}.meshd; meshd-linkd-package = self.packages.${system}.meshd-linkd; meshd-exitd-package = self.packages.${system}.meshd-exitd; + lampstand-package = self.packages.${system}.lampstand; }); sourceos = { channels = [ "dev" "candidate" "stable" ]; - notes = "This flake is the Linux realization root. Control-plane semantics live in SocioProphet/agentplane and shared channel/capability schemas live in SocioProphet/socioprophet-agent-standards."; + notes = "This flake is the Linux realization root. Shared SourceOS/SociOS contracts live in SourceOS-Linux/sourceos-spec."; }; }; } From df577f9c851a0b27f50966440f1454ca688c44b5 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:41:24 -0400 Subject: [PATCH 18/19] flake: restore host and contract path names after Lampstand wiring --- flake.nix | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.nix b/flake.nix index 899e2f7..950a8bb 100644 --- a/flake.nix +++ b/flake.nix @@ -102,19 +102,19 @@ canary-x86_64 = lib.nixosSystem { system = "x86_64-linux"; specialArgs = { inherit self; }; - modules = [ ./hosts/canary_x86_64/default.nix ]; + modules = [ ./hosts/canary-x86_64/default.nix ]; }; stable-x86_64 = lib.nixosSystem { system = "x86_64-linux"; specialArgs = { inherit self; }; - modules = [ ./hosts/stable_x86_64/default.nix ]; + modules = [ ./hosts/stable-x86_64/default.nix ]; }; exit-x86_64 = lib.nixosSystem { system = "x86_64-linux"; specialArgs = { inherit self; }; - modules = [ ./hosts/exit_x86_64/default.nix ]; + modules = [ ./hosts/exit-x86_64/default.nix ]; }; }; @@ -130,22 +130,22 @@ canary-x86_64-smoke = if system == "x86_64-linux" - then import ./tests/canary_x86_64-contract.nix { inherit pkgs; } - else pkgs.runCommand "canary_x86_64-smoke-skip" {} '' + then import ./tests/canary-x86_64-contract.nix { inherit pkgs; } + else pkgs.runCommand "canary-x86_64-smoke-skip" {} '' mkdir -p $out ''; stable-x86_64-smoke = if system == "x86_64-linux" - then import ./tests/stable_x86_64-contract.nix { inherit pkgs; } - else pkgs.runCommand "stable_x86_64-smoke-skip" {} '' + then import ./tests/stable-x86_64-contract.nix { inherit pkgs; } + else pkgs.runCommand "stable-x86_64-smoke-skip" {} '' mkdir -p $out ''; exit-x86_64-smoke = if system == "x86_64-linux" - then import ./tests/exit_x86_64-contract.nix { inherit pkgs; } - else pkgs.runCommand "exit_x86_64-smoke-skip" {} '' + then import ./tests/exit-x86_64-contract.nix { inherit pkgs; } + else pkgs.runCommand "exit-x86_64-smoke-skip" {} '' mkdir -p $out ''; From 01dfeb9998b95b903ac492b167085d742ac971dd Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:42:33 -0400 Subject: [PATCH 19/19] docs(workstation): document Lampstand Nix package path --- docs/workstation/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/workstation/README.md b/docs/workstation/README.md index 52bc160..f758d30 100644 --- a/docs/workstation/README.md +++ b/docs/workstation/README.md @@ -77,7 +77,12 @@ This repository is Nix-native. A dev shell is provided: nix develop .#workstation-v0 +Lampstand is also exposed as a Nix package: + + nix build .#lampstand + Notes: +- The workstation devShell includes the repo-local Lampstand package in addition to best-effort nixpkgs CLI tools. - The workstation devShell is best-effort; missing nixpkgs attrs will be reported on entry. - The profile installers still support non-Nix systems using dnf/rpm-ostree and brew where applicable.