Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: CI
on:
push:
branches: [master]
pull_request:
permissions:
contents: read
jobs:
validate-app:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: sudo apt-get update && sudo apt-get install -y imagemagick
- run: npm ci
- run: npm run check
- run: npm test
- run: bash -n build.sh install.sh uninstall.sh scripts/generate-icons.sh
- run: npm audit --audit-level=high
- run: ./build.sh
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Changelog

## v1.1.0 — 2026-07-11

- Updated from Electron 31 to exact Electron 43.1.0 and electron-builder 26.15.3.
- Added sandboxing, default-deny permissions, safe navigation/auth windows, external-link validation, hostname audit mode, locked builds, tests, CI, multi-size icons, atomic install, checksums, and profile purge.
- Added prominent privacy documentation and honest Chromium limitations.

## v1.0.0

- Initial Perplexity Computer wrapper. Superseded because its Electron runtime is unsupported.
3 changes: 3 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Run npm ci, npm run check, npm test, bash -n on all shell scripts, npm audit --audit-level=high, and ./build.sh. Review authentication, uploads/downloads, navigation policy, privacy claims, and KDE identity before release.
7 changes: 7 additions & 0 deletions PRIVACY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Privacy and Network Behavior

The wrapper adds no AAHA analytics. It disables Chromium component updates, background networking, domain-reliability reporting, Breakpad, Translate, Optimization Hints, Media Router, and Secure DNS; known Google update/telemetry hosts are blocked.

Perplexity must still contact perplexity.ai, CDNs, model/search infrastructure, authentication providers, connectors, and linked sources. Google or Apple traffic may occur when the user deliberately selects those sign-in methods. Blocklists reduce known optional traffic but are not proof of zero third-party traffic.

The local profile at ~/.config/Perplexity contains cookies, sessions, cache, local storage, and preferences. Normal uninstall preserves it; --purge removes it and signs the wrapper out without deleting the Perplexity account.
119 changes: 8 additions & 111 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,118 +1,15 @@
# Perplexity (AAHA)
# Perplexity for Linux — AAHA

A native **Perplexity desktop app for Linux**, built with Electron by
**Adam And His Agents (AAHA)**. It wraps the official Perplexity web app
(`https://www.perplexity.ai`) in a clean, standalone window that behaves
like a real desktop application — including a **stable taskbar icon that
KDE Plasma on Wayland will NOT swap for the generic browser icon**.
Unofficial Perplexity Electron desktop app for Fedora KDE, with a stable Wayland taskbar icon.

> **Unofficial / not affiliated with Perplexity AI, Inc.** This is a
> third-party wrapper. It is not endorsed by or affiliated with Perplexity.
> "Perplexity" and the Perplexity logo are trademarks of Perplexity AI,
> Inc. See `NOTICE` for details. Your use of Perplexity remains subject
> to Perplexity's own Terms of Service.
## Privacy notice

---
This app uses Electron, which is Chromium-based. It disables unnecessary Chromium background services and adds no AAHA telemetry, but Perplexity, its CDNs, identity providers, connectors, and selected external sources still receive required traffic. Safeguards cannot make Chromium completely Google-free or independently auditable. See PRIVACY.md.

## Why this exists
## Install from source

KDE on Wayland picks an app's panel icon from the window's `app_id`
(WM class) and matches it to a `.desktop` file. Chromium-based PWAs all
share Chromium's identity, so KDE falls back to the generic browser icon.
Run chmod +x on the shell scripts, then ./build.sh and ./install.sh. The app installs under ~/MyApps/perplexity-aaha/app. Normal uninstall preserves ~/.config/Perplexity; ./uninstall.sh --purge removes that local profile.

A real Electron app sets its **own** `app_id` (`app.setName()` + `--class`)
and ships a `.desktop` file whose `StartupWMClass` matches exactly. KDE
finds a unique match, so your icon sticks.
AAHA_NETWORK_AUDIT=1 prints first-seen hostnames. External citations open in the system browser. File upload, drag-and-drop, and downloads remain available.

---

## Requirements (Fedora / KDE example)

Node.js + npm, plus FUSE for running AppImages:

```bash
sudo dnf install nodejs npm fuse fuse-libs
```

(On Debian/Ubuntu: `sudo apt install nodejs npm libfuse2`.)

---

## Build & install

From the project folder:

```bash
chmod +x *.sh # one time, make scripts executable
./build.sh # installs deps, builds dist/ (first run downloads Electron, ~150MB)
./install.sh # registers icon + .desktop with your desktop environment
```

Then open your app launcher, search "Perplexity", launch it, and pin it
to your taskbar/panel. The icon stays.

Build outputs:
- `dist/linux-unpacked/` — the native unpacked app (what `install.sh` wires up)
- `dist/*.AppImage` — a portable single-file version

To remove it later: `./uninstall.sh`

---

## Configuration (`app.config.js`)

| Field | Value |
|-------------------------|--------------------------------------------------|
| `url` | `https://www.perplexity.ai` |
| `name` | `Perplexity` |
| `wmClass` | `Perplexity` |
| `appId` | `com.adamandhisagents.perplexity` |
| `allowedHosts` | `["perplexity.ai", "pplx.ai"]` |
| `disableHardening` | `false` (privacy hardening ON) |

> `build.sh` syncs `app.config.js` and `icons/icon.png` into `src/`
> before building so they get packed into the app bundle (`app.asar`).

---

## Privacy hardening (on by default)

This app launches with Chromium background/phone-home subsystems disabled:
`disable-background-networking`, `disable-domain-reliability`,
`disable-component-update`, `disable-features=NetworkTimeServiceQuerying,
Translate,OptimizationHints,MediaRouter`, and `disable-breakpad`. The app
should only talk to Perplexity. To opt out, set `disableHardening: true` in
`app.config.js`.

Verify with:

```bash
sudo tcpdump -n -i any 'port 53 or port 443' | grep -Ei 'google|gstatic|gvt|1e100'
```

Note: if the wrapped site itself loads Google Fonts/reCAPTCHA/Analytics,
that is the site's own traffic and would occur in any browser too.

---

## Notes / gotchas

- **Disk:** each app bundles its own Electron runtime (~150–250 MB).
- **Single instance:** clicking the icon focuses the existing window.
- **No menu bar:** the app launches chrome-less. Remove
`Menu.setApplicationMenu(null)` in `src/main.js` if you want one.
- **Session data** lives in `~/.config/Perplexity/`, NOT in the project
folder. Your login is never committed to git or shipped in the AppImage.
- **Updates:** the bundled Electron does not auto-update. To refresh:
`npm install electron@latest --save-dev` then rebuild.

---

## License

Copyright 2026 **Adam And His Agents (AAHA)**.

The wrapper/launcher code in this repository is licensed under the
**Apache License, Version 2.0** — see `LICENSE`. This license applies only
to the code authored here; it does not cover Perplexity, Perplexity's
software/service, or Perplexity's trademarks and logos. See `NOTICE`.
This project is unofficial and is not affiliated with Perplexity.
50 changes: 13 additions & 37 deletions app.config.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,16 @@
// ============================================================
// APP CONFIG — This is the ONLY file you edit per app.
// Change these values, swap the icon in icons/, rebuild.
// ============================================================
"use strict";
module.exports = {
// The web app you want to wrap:
schemaVersion: 2, configured: true,
repoName: "perplexity-aaha", productName: "Perplexity",
appId: "com.adamandhisagents.perplexity", executable: "perplexity-aaha",
iconName: "perplexity-aaha", profileName: "Perplexity",
legacyProfileNames: [], compatibilityDesktopIds: ["perplexity"],
url: "https://www.perplexity.ai",

// Display name (shows in title bar, launcher, panel tooltip):
name: "Perplexity",

// Wayland/X11 window identity. MUST match productName in package.json
// and StartupWMClass in the .desktop file so KDE keeps your icon.
wmClass: "Perplexity",

// Reverse-DNS app id — unique per app.
appId: "com.adamandhisagents.perplexity",

// Initial window size:
width: 1280,
height: 800,

// Open external links (e.g. links that leave the app's domain)
// in your real browser instead of inside the app window:
openExternalInBrowser: true,

// Restrict in-app navigation to these host suffixes. Anything else
// opens in the external browser. Perplexity uses both perplexity.ai
// and pplx.ai (short-links), so both are kept in-app.
allowedHosts: ["perplexity.ai", "pplx.ai"],

// Optional custom user-agent. Leave null for Electron's default.
userAgent: null,

// PRIVACY HARDENING (default: ON). Disables Chromium's background
// networking, domain-reliability beacons, component updates, network-time
// queries, translate, optimization hints, and crash metrics, so the app
// only talks to Perplexity. Set to true only if something breaks.
disableHardening: false
trustedNavigationHosts: ["perplexity.ai", "pplx.ai"],
trustedAuthHosts: ["accounts.google.com", "appleid.apple.com"],
permissions: { "clipboard-sanitized-write": ["perplexity.ai"] },
blockedHosts: ["clients2.google.com", "clients4.google.com", "update.googleapis.com", "safebrowsing.googleapis.com", "optimizationguide-pa.googleapis.com", "redirector.gvt1.com", "google-analytics.com", "www.google-analytics.com", "stats.g.doubleclick.net"],
externalProtocols: ["http:", "https:", "mailto:"], openExternalLinks: true,
width: 1360, height: 860, category: "Network;",
comment: "Perplexity AI answer engine", keywords: "ai;search;research;perplexity;"
};
File renamed without changes
69 changes: 15 additions & 54 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,58 +1,19 @@
#!/usr/bin/env bash
# Build the Electron app into an unpacked native dir + AppImage.
# app.config.js is the SINGLE SOURCE OF TRUTH — this script syncs its
# values into package.json and into src/ before building.
#
# Run from the project root: ./build.sh
set -euo pipefail
cd "$(dirname "$0")"

echo ">> Reading identity from app.config.js..."
NAME="$(node -p "require('./app.config.js').name")"
WMCLASS="$(node -p "require('./app.config.js').wmClass")"
APPID="$(node -p "require('./app.config.js').appId")"
# slug: lowercase, spaces -> dashes (e.g. "Proton Calendar" -> "proton-calendar")
SLUG="$(echo "$NAME" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')"

echo " name=$NAME slug=$SLUG appId=$APPID"

echo ">> Syncing identity into package.json..."
node - "$NAME" "$SLUG" "$APPID" "$WMCLASS" <<'NODE'
const fs = require("fs");
const [name, slug, appId, wmClass] = process.argv.slice(2);
const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
pkg.name = slug;
pkg.productName = name;
pkg.description = name + " desktop wrapper (Electron) by Adam And His Agents";
pkg.build.appId = appId;
pkg.build.productName = name;
pkg.build.linux.executableName = slug;
// AppImage filename: lowercase slug + -aaha- + version + arch, no spaces.
pkg.build.linux.artifactName = slug + "-aaha-${version}-${arch}.AppImage";
pkg.build.linux.desktop.Name = name;
pkg.build.linux.desktop.Comment = name + " desktop wrapper";
pkg.build.linux.desktop.StartupWMClass = wmClass;
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 2) + "\n");
NODE

echo ">> Bundling config + icon into src/ (so they pack into app.asar)..."
cp -f app.config.js src/app.config.js
if [ -f icons/icon.png ]; then
cp -f icons/icon.png src/icon.png
else
echo " WARNING: icons/icon.png not found. The app will build but use a"
echo " generic icon. Add a 512x512 PNG at icons/icon.png and rebuild."
fi

echo ">> Installing dependencies (first run downloads Electron, ~150MB)..."
npm install

echo ">> Building Linux targets (dir + AppImage)..."
npm ci
npm run check
npm test
npm run icons
npm run dist

echo
echo ">> Done. Outputs are in ./dist/"
echo " - Unpacked app: ./dist/linux-unpacked/"
echo " - AppImage: ./dist/*.AppImage"
echo
echo "Next: run ./install.sh to register the app with your desktop."
appimage="$(find dist -maxdepth 1 -type f -name '*.AppImage' -print -quit)"
if [[ -z "$appimage" ]]; then
echo "ERROR: electron-builder did not produce an AppImage." >&2
exit 1
fi
(
cd dist
sha256sum "$(basename "$appimage")" > SHA256SUMS
sha256sum -c SHA256SUMS
)
echo "Build complete: $appimage"
Binary file added build/icons/128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/24x24.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/256x256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/48x48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/64x64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/96x96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading