Add Ghost: runtime with optional Omarchy HUD (#390)

* Add ghost: an owner-local AI persona with an Omarchy-native HUD

Ghost (https://github.com/ferdousbhai/ghost, Apache-2.0) is a local AI
persona for Omarchy: a daemon on 127.0.0.1, a Quickshell HUD summoned
with Super+Ctrl+G, a `ghost` CLI, an opt-in Chromium relay, and a
computer-use helper. The package builds from the v0.1.0 GitHub release's
sanitized source archive plus its prebuilt Bun runtime archive; the
`.omarchy/package.json` upstream block follows later releases the same
way. check() runs the project's own test suite against the payload.

Built locally with `makepkg --cleanbuild` from these exact inputs on
Omarchy 4.0.0.alpha: ghost-0.1.0-1-x86_64.pkg.tar.zst.

* ghost 0.1.1: arch=('any'), one runtime archive for every architecture

The payload is Bun-target JavaScript with no native modules; verified
on aarch64 under emulation (ferdousbhai/ghost#52). The runtime archive
is now named linux-any and listed with the source tarball under
sources.any.

* ghost: 0.1.2

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017TQbyws7icrhj7H7V7yi6v

* ghost: 0.2.0

* ghost: 0.2.1

* ghost: 0.2.2

* ghost: 0.2.3

* ghost: 0.3.0

* ghost: 0.4.0 with independently installable runtime

* ghost: 0.4.1

* ghost: 0.4.2

* ghost: 0.4.3

* ghost: 0.5.0

* ghost: 0.5.1

* ghost: 0.5.2

* ghost: 0.6.0

* ghost: 0.6.0-2, declare ripgrep for package checks

check() in the 0.6.0 source runs packaging tests that need rg, and the
clean build container does not have it, so every build since 0.5.0 stopped
with "ripgrep is required by package checks but is not installed".
Same version, so pkgrel goes to 2 (ghost e97eb09 carries the same
checkdepend for the next release's render).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ferdousandClaude Opus 5.5 authored and GitHub committed 2026-10-09 14:39:53 +00:00
1 parent 1aecf94f22
commit 8b8ede46ed
4 files changed
+228

No files matched your search

+15
View File
@@ -0,0 +1,15 @@
{
"source": "local",
"release_ring": "fast",
"upstream": {
"github": "ferdousbhai/ghost",
"digests": true,
"latest_only": true,
"sources": {
"any": [
"https://github.com/ferdousbhai/ghost/releases/download/{tag}/ghost-{pkgver}.tar.gz",
"https://github.com/ferdousbhai/ghost/releases/download/{tag}/ghost-runtime-{pkgver}-linux-any.tar.zst"
]
}
}
}
+144
View File
@@ -0,0 +1,144 @@
# Maintainer: Ferdous Bhai <https://github.com/ferdousbhai>
pkgbase=ghost
pkgname=(ghost-runtime ghost)
pkgver=0.6.0
pkgrel=2
pkgdesc="Owner-local AI persona with a character, tools, and an Omarchy-native desktop shell"
arch=('any')
url="https://github.com/ferdousbhai/ghost"
license=('Apache-2.0')
_runtime_depends=(
'at-spi2-core>=2.58'
'bun>=1.3.14'
'grim>=1.5'
'hyprland>=0.56'
'libnotify>=0.8'
'qrencode'
'systemd'
'wl-clipboard'
'wtype>=0.4'
)
_ui_depends=('qt6-5compat>=6.8' 'quickshell>=0.3' 'xdg-utils>=1.2')
depends=("${_runtime_depends[@]}" "${_ui_depends[@]}")
makedepends=(
'bun>=1.4.0'
'desktop-file-utils'
)
checkdepends=(
'jq'
'nodejs'
'python-yaml'
'ripgrep'
)
_runtime_optdepends=(
'chromium: the browser the relay drives, and the browser-relay smoke test'
'npm: npx-launched MCP servers'
)
options=('!debug' '!strip')
# Omarchy's sync-upstream follows the GitHub release named in
# .omarchy/package.json and rewrites pkgver and both checksum arrays.
_release="https://github.com/ferdousbhai/ghost/releases/download/v${pkgver}"
# One runtime archive for every architecture: Bun-target JavaScript, no
# native modules (verified on aarch64, ghost#52).
_runtime="ghost-runtime-${pkgver}-linux-any.tar.zst"
source=(
"ghost-${pkgver}.tar.gz::${_release}/ghost-${pkgver}.tar.gz"
"${_runtime}::${_release}/${_runtime}"
)
noextract=("${_runtime}")
sha256sums=(
'681320615fa6192fe57f8fe6ab1e36ae04a7680d7b371721762bfdedf48ac985'
'1c9c66ca0299dbf9d15a37e541f61352658bcb9700a067eec1081a3bfc1549f5'
)
_release_identity() {
local manifest="$1"
local line key value
declare -A fields=()
[[ -f "$manifest" && ! -L "$manifest" ]] || return 1
while IFS= read -r line || [[ -n "$line" ]]; do
[[ "$line" == *=* ]] || return 1
key="${line%%=*}"
value="${line#*=}"
case "$key" in
format|version|source_commit|source_date_epoch) ;;
*) return 1 ;;
esac
[[ ! -v "fields[$key]" ]] || return 1
fields["$key"]="$value"
done < "$manifest"
[[ "${#fields[@]}" -eq 4 ]] || return 1
[[ "${fields[format]}" == ghost-release-source/v1 ]] || return 1
[[ "${fields[version]}" == "$pkgver" ]] || return 1
[[ "${fields[source_commit]}" =~ ^[0-9a-f]{40}$ ]] || return 1
[[ "${fields[source_date_epoch]}" =~ ^[0-9]+$ ]] || return 1
printf '%s\t%s\n' \
"${fields[source_commit]}" "${fields[source_date_epoch]}"
}
prepare() {
local source_root="$srcdir/ghost-${pkgver}"
local runtime_parent="$srcdir/runtime"
local runtime_root="$runtime_parent/ghost-runtime-${pkgver}-linux-any"
local identity source_commit source_date_epoch
identity="$(_release_identity \
"$source_root/RELEASE-SOURCE.MANIFEST")" || return 1
IFS=$'\t' read -r source_commit source_date_epoch <<< "$identity" || return 1
bash "$source_root/packaging/release/verify-release-source.sh" \
"$source_root" "$pkgver" "$source_commit" "$source_date_epoch" || return 1
export SOURCE_DATE_EPOCH="$source_date_epoch"
install -d -m755 "$runtime_parent"
find "$runtime_parent" -mindepth 1 -delete
bsdtar -xf "$srcdir/$_runtime" -C "$runtime_parent" || return 1
bash "$srcdir/ghost-${pkgver}/packaging/release/verify-runtime-source.sh" \
"$runtime_root" "$source_root" "$pkgver" any "$source_commit" \
"$source_date_epoch" || return 1
}
build() {
# The Bun bundles were built from the frozen lock and verified in
# prepare(); there is no network build step.
:
}
check() {
local source_root="$srcdir/ghost-${pkgver}"
local runtime_root="$srcdir/runtime/ghost-runtime-${pkgver}-linux-any"
local identity source_commit source_date_epoch
identity="$(_release_identity \
"$source_root/RELEASE-SOURCE.MANIFEST")" || return 1
IFS=$'\t' read -r source_commit source_date_epoch <<< "$identity" || return 1
bash "$source_root/packaging/arch/test-check-dependencies.sh" || return 1
bash "$source_root/packaging/release/verify-runtime-source.sh" \
"$runtime_root" "$source_root" "$pkgver" any "$source_commit" \
"$source_date_epoch" || return 1
desktop-file-validate \
"$source_root/packages/shell/contrib/ghost.desktop" || return 1
}
package_ghost-runtime() {
pkgdesc="Ghost daemon, API, CLI, and desktop/browser automation without the HUD"
depends=("${_runtime_depends[@]}")
optdepends=("${_runtime_optdepends[@]}")
conflicts=(ghost-runtime-dev)
install=ghost-runtime.install
local source_root="$srcdir/ghost-${pkgver}"
local runtime_root="$srcdir/runtime/ghost-runtime-${pkgver}-linux-any"
bash "$source_root/packaging/release/install-payload.sh" \
"$source_root" "$runtime_root" "$pkgdir" "$pkgname" runtime
}
package_ghost() {
pkgdesc="Ghost HUD and desktop integration for Omarchy"
depends=("ghost-runtime=$pkgver-$pkgrel" "${_ui_depends[@]}")
conflicts=(ghost-dev)
install=ghost.install
local source_root="$srcdir/ghost-${pkgver}"
local runtime_root="$srcdir/runtime/ghost-runtime-${pkgver}-linux-any"
bash "$source_root/packaging/release/install-payload.sh" \
"$source_root" "$runtime_root" "$pkgdir" "$pkgname" ui
}
+37
View File
@@ -0,0 +1,37 @@
post_install() {
cat <<'TEXT'
Ghost runtime is installed without the Ghost HUD. Enable the daemon in the
current graphical session with:
systemctl --user enable --now ghostd.service
ghost status
The runtime keeps the CLI, authenticated API, desktop helper, and the relay
that the Ghost browser extension pairs with. The extension itself is a
separate install: https://github.com/ferdousbhai/ghost-chromium-extension
(pairing: `ghost browser allow <code>`). An app can supply its own UI.
See /usr/share/doc/ghost/ARCH.md for UI installation and removal.
Ghost homes, credentials, and state belong to you; package removal preserves them.
TEXT
}
post_upgrade() {
cat <<'TEXT'
Ghost runtime was upgraded. Restart it in the graphical user's session:
systemctl --user reenable --now ghostd.service
Ghost homes, credentials, and state were preserved.
TEXT
}
pre_remove() {
cat <<'TEXT'
Before removing the runtime, stop it from the graphical user's session:
systemctl --user disable --now ghostd.service
Removal preserves ghost homes, credentials, and state.
TEXT
}
+32
View File
@@ -0,0 +1,32 @@
post_install() {
cat <<'TEXT'
Ghost's Omarchy UI is installed. Enable it in the graphical user's session:
mkdir -p ~/.config/omarchy/plugins
ln -sfn /usr/share/ghost/plugin ~/.config/omarchy/plugins/ferdousbhai.ghost
omarchy-shell shell rescanPlugins && omarchy plugin enable ferdousbhai.ghost
Summon it with `omarchy-shell shell toggle ferdousbhai.ghost`.
Shell snippets are under /usr/share/doc/ghost/shell-contrib/.
The runtime is managed separately; see /usr/share/doc/ghost/ARCH.md.
TEXT
}
post_upgrade() {
cat <<'TEXT'
Ghost's Omarchy UI was upgraded. Reload its QML by restarting the shell:
omarchy-restart-shell
TEXT
}
pre_remove() {
cat <<'TEXT'
Before removing the UI, disable and unlink its plugin in the graphical session:
omarchy plugin remove ferdousbhai.ghost --yes
omarchy-restart-shell
Removing only the UI leaves Ghost runtime and all owner data available.
TEXT
}