Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
720a40d
docs(workstation): record lampstand-backed local search surface
mdheller Apr 23, 2026
840c08f
workstation-v0: record lampstand-backed search policy in manifest
mdheller Apr 23, 2026
28511ef
workstation-v0: add lampstand-backed search helper
mdheller Apr 23, 2026
9076085
workstation-v0: fix sourceos-search helper execution path
mdheller Apr 23, 2026
cc9d098
workstation-v0: wire lampstand search into sourceos helper and palette
mdheller Apr 23, 2026
ed71483
workstation-v0: invoke sourceos-search helper via bash
mdheller Apr 23, 2026
467ce0d
ci(workstation): add sourceos search smoke with stubbed lampstand
mdheller Apr 23, 2026
d7f4ea3
workstation-v0: add lampstand-aware doctor validation
mdheller Apr 23, 2026
da41a79
workstation-v0: add lampstand-aware status warnings
mdheller Apr 23, 2026
550aad6
workstation-v0: add lampstand install and user-service helper
mdheller Apr 23, 2026
a706614
workstation-v0: wire lampstand install helper into profile setup
mdheller Apr 23, 2026
1746d64
workstation-v0: declare pipx for lampstand provisioning
mdheller Apr 23, 2026
f9b8535
ci(workstation): add lampstand installer smoke workflow
mdheller Apr 23, 2026
b233ca5
docs(workstation): document lampstand provisioning lane
mdheller Apr 23, 2026
47403ad
packages(search): add Lampstand Nix package expression
mdheller Apr 23, 2026
2696fc3
packages(search): fix Lampstand package metadata lib binding
mdheller Apr 23, 2026
ee7a2df
flake: wire Lampstand package into workstation realization
mdheller Apr 23, 2026
df577f9
flake: restore host and contract path names after Lampstand wiring
mdheller Apr 23, 2026
01dfeb9
docs(workstation): document Lampstand Nix package path
mdheller Apr 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/workflows/workstation-lampstand.yml
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions .github/workflows/workstation-scripts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 26 additions & 1 deletion docs/workstation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,25 @@ 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

- 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`.
Expand All @@ -44,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
Expand All @@ -52,14 +69,20 @@ Or via the installed helper:

sourceos doctor
sourceos status --json
sourceos search 'report OR invoice' --snippet

## Nix-first support

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.

Expand All @@ -68,6 +91,8 @@ 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.
- Lampstand is installed in user space and exposed through a user service, not as a mandatory host-system package.

## Related docs

Expand Down
14 changes: 11 additions & 3 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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" ];
Expand All @@ -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;
});

Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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.";
};
};
}
26 changes: 26 additions & 0 deletions packages/search/lampstand.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{ lib, 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 = lib.licenses.mit;
mainProgram = "lampstand";
};
}
93 changes: 93 additions & 0 deletions profiles/linux-dev/workstation-v0/bin/install-lampstand.sh
Original file line number Diff line number Diff line change
@@ -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 "$@"
29 changes: 29 additions & 0 deletions profiles/linux-dev/workstation-v0/bin/sourceos
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Usage:
sourceos fix fish [apply|dry-run|revert] [--json] [--open|--write <path>]
sourceos doctor [--json|--open|--write <path>]
sourceos status [--json|--open|--write <path>]
sourceos search [--limit N] [--snippet] [--prompt] [--open|--write <path>] [query...]
sourceos profile apply
sourceos profile path

Expand Down Expand Up @@ -285,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=()
Expand All @@ -310,6 +329,8 @@ status_collect(){
OPTIONAL_MISSING+=("xclip")
fi

status_check_lampstand

if gnome_detect; then
if ! check_bin gsettings; then
WARNINGS+=("gsettings missing")
Expand Down Expand Up @@ -451,6 +472,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
Expand Down Expand Up @@ -560,6 +582,13 @@ main(){
esac
;;

search)
shift || true
local search_helper="$PROFILE_DIR/bin/sourceos-search.sh"
[[ -f "$search_helper" ]] || { err "search helper missing: $search_helper"; exit 2; }
exec bash "$search_helper" "$@"
;;

profile)
shift || true
local sub=${1:-}
Expand Down
Loading