Skip to content

Instantly share code, notes, and snippets.

@mattezell
Last active June 1, 2026 16:30
Show Gist options
  • Select an option

  • Save mattezell/febc265a34f9f60058fa48d0f000364d to your computer and use it in GitHub Desktop.

Select an option

Save mattezell/febc265a34f9f60058fa48d0f000364d to your computer and use it in GitHub Desktop.
Install Antigravity 2.0 / Antigravity IDE on Linux from the official tarballs (user-local install, Ubuntu 24.04+ AppArmor handled)

Antigravity / Antigravity IDE — Linux tarball installer

Antigravity 2.0 and the Antigravity IDE currently ship for Linux as raw .tar.gz archives — no .deb, no .AppImage, no Flatpak, no installer. This gist is a small set of shell scripts that turn one of those extracted tarballs into a proper user-local install: a desktop launcher in your app menu, a CLI symlink on your $PATH, an icon, and (on Ubuntu 24.04+) a working Chromium sandbox via an AppArmor profile.

Status: community workaround. Replace with whatever Google ships officially when they get around to it.


What you get

  • App installed to ~/Applications/<app>/ (user-owned — no sudo needed for the app itself or for future updates).
  • Launcher in ~/.local/share/applications/ so it shows up in the app menu, taskbar, etc.
  • Icon in ~/.local/share/icons/hicolor/512x512/apps/.
  • Symlink in ~/.local/bin/ so antigravity / antigravity-ide work from the terminal (this dir is on $PATH by default on Ubuntu).
  • For the IDE, the desktop integrations VS Code's .deb would normally set up:
    • "Open With → Antigravity IDE" on folders and text files in the file manager (via the .desktop MimeType= field).
    • "Open in Antigravity IDE" as a top-level right-click entry in Nautilus (GNOME Files). This needs python3-nautilus; the installer offers to apt-install it for you.
    • antigravity-ide:// URL scheme registered as the default handler, so deep links open the IDE.

The AppArmor wrinkle

Ubuntu 24.04+ ships with kernel.apparmor_restrict_unprivileged_userns=1, which blocks Chromium's user-namespace sandbox for any unsigned binary without a matching AppArmor profile. The install scripts handle this by dropping a tiny per-binary profile in /etc/apparmor.d/ that allows userns for exactly the installed binary path. This step needs sudoonce. Updates afterwards do not need sudo, since the binary path doesn't change.

If sudo fails or you decline, the script falls back to writing --no-sandbox into the launcher's Exec= line. The app still runs, just without renderer sandboxing. Your call.

Install

Extract the tarball wherever, then point the matching install script at the extraction directory. The script moves the extracted directory into ~/Applications, so the source path won't exist afterward.

# Antigravity (the 2.0 "Hub" app)
tar xzf Antigravity.tar.gz
./install-antigravity.sh ./Antigravity-x64

# Antigravity IDE
tar xzf "Antigravity IDE.tar.gz"
./install-antigravity-ide.sh "./Antigravity IDE"

After install, launch from your app menu or:

antigravity        # the Hub
antigravity-ide    # the IDE

If the CLI doesn't resolve, make sure ~/.local/bin is on your $PATH (it is by default on Ubuntu after a fresh login).

Update

When a new tarball drops, just re-run the install script with the new extraction. It replaces ~/Applications/<app>/ in place, leaves your settings and the AppArmor profile untouched, and refreshes the icon / desktop entry.

tar xzf Antigravity.tar.gz        # latest
./install-antigravity.sh ./Antigravity-x64

No sudo needed for updates.

Uninstall

./uninstall-antigravity.sh
./uninstall-antigravity-ide.sh

Each removes its app dir, launcher, icon, CLI symlink, and AppArmor profile (the profile removal prompts for sudo). Your settings under ~/.antigravity-ide are left in place — delete by hand if you want.

Removing an older system-wide install

If you previously installed to /opt/antigravity (e.g. by following the older "just move it to /opt" advice), use uninstall-system-wide-legacy.sh to clean that up before running the user-local installer.

Notes / known limitations

  • The Antigravity Hub's auto-updater (electron-updater with a generic provider) can detect new versions but on Linux it cannot replace an extracted-tarball install in place. Treat any update notice as a cue to re-download the tarball and re-run the install script.
  • On distros without AppArmor (Fedora, Arch, etc.) the AppArmor block is skipped entirely and Chromium's sandbox works out of the box.
  • The IDE is a VS Code fork; settings live under ~/.antigravity-ide/.
  • The Nautilus "Open in Antigravity IDE" extension targets the Nautilus Python binding versions 4.1 / 4.0 / 3.0 (auto-detected). It only applies to GNOME / Nautilus — Nemo / Caja / Dolphin / Thunar would each need their own equivalent.
#!/usr/bin/env bash
# install-antigravity-ide.sh
#
# Installs the Antigravity IDE Linux tarball into ~/Applications as a
# user-owned install, with a desktop launcher, icon, CLI symlink, and the
# desktop integrations VS Code's .deb would normally provide:
# - "Open With > Antigravity IDE" in the file manager for folders and
# text files (via .desktop MimeType)
# - "Open in Antigravity IDE" right-click entry in Nautilus (via a small
# python3-nautilus extension; GNOME / Nautilus only)
# - antigravity-ide:// URL scheme handler
#
# Usage:
# ./install-antigravity-ide.sh "/path/to/extracted/Antigravity IDE"
#
# Notes:
# - User-owned; no sudo for the app itself or for future updates.
# - On Ubuntu 24.04+ Chromium's user-namespace sandbox is blocked by AppArmor
# by default. The script tries to install a one-time AppArmor profile
# (this step needs sudo). If sudo isn't available or the profile fails to
# load, it falls back to launching the IDE with --no-sandbox.
set -euo pipefail
SRC="${1:-}"
if [ -z "$SRC" ] || [ ! -x "$SRC/antigravity-ide" ]; then
echo "Usage: $0 \"/path/to/extracted/Antigravity IDE\""
echo " (Expected to find an executable 'antigravity-ide' inside that dir.)"
exit 1
fi
SRC="$(cd "$SRC" && pwd)"
APP_NAME="antigravity-ide"
APP_DISPLAY="Antigravity IDE"
BINARY="antigravity-ide"
DEST="$HOME/Applications/$APP_NAME"
ICON_DEST="$HOME/.local/share/icons/hicolor/512x512/apps/$APP_NAME.png"
DESKTOP="$HOME/.local/share/applications/$APP_NAME.desktop"
BIN_LINK="$HOME/.local/bin/$APP_NAME"
ICON_SRC="$SRC/resources/app/resources/linux/code.png"
if [ ! -f "$ICON_SRC" ]; then
echo "Warning: expected icon at $ICON_SRC not found; launcher will have no icon."
ICON_SRC=""
fi
# --- 1. Move app into ~/Applications --------------------------------------
mkdir -p "$(dirname "$DEST")" "$(dirname "$BIN_LINK")" \
"$(dirname "$DESKTOP")" "$(dirname "$ICON_DEST")"
rm -rf "$DEST"
mv "$SRC" "$DEST"
# --- 2. Install icon (resized down to 512x512 if ImageMagick available;
# otherwise just install the original 1024x1024 PNG) -----------------
if [ -n "$ICON_SRC" ]; then
ORIG_ICON="$DEST/resources/app/resources/linux/code.png"
if command -v magick >/dev/null 2>&1; then
magick "$ORIG_ICON" -resize 512x512 "$ICON_DEST"
elif command -v convert >/dev/null 2>&1; then
convert "$ORIG_ICON" -resize 512x512 "$ICON_DEST"
else
install -Dm644 "$ORIG_ICON" \
"$HOME/.local/share/icons/hicolor/1024x1024/apps/$APP_NAME.png"
install -Dm644 "$ORIG_ICON" "$ICON_DEST"
fi
gtk-update-icon-cache "$HOME/.local/share/icons/hicolor" 2>/dev/null || true
fi
# --- 3. Sandbox: try AppArmor profile, else fall back to --no-sandbox -----
EXEC_LINE="\"$DEST/$BINARY\" %F"
USERNS_RESTRICTED="$(cat /proc/sys/kernel/apparmor_restrict_unprivileged_userns 2>/dev/null || echo 0)"
if [ "$USERNS_RESTRICTED" = "1" ]; then
PROFILE_NAME="userns-${APP_NAME}-${USER}"
PROFILE_PATH="/etc/apparmor.d/${PROFILE_NAME}"
PROFILE_BODY="abi <abi/4.0>,
include <tunables/global>
profile ${PROFILE_NAME} \"$DEST/$BINARY\" flags=(unconfined) {
userns,
include if exists <local/${PROFILE_NAME}>
}
"
echo "Ubuntu AppArmor restricts unprivileged user namespaces."
echo "Installing a one-time AppArmor profile so Chromium's sandbox works"
echo "(requires sudo; updates afterwards will not need sudo)."
if echo "$PROFILE_BODY" | sudo tee "$PROFILE_PATH" >/dev/null \
&& sudo apparmor_parser -r "$PROFILE_PATH"; then
echo "AppArmor profile installed: $PROFILE_PATH"
else
echo "AppArmor profile install failed; using --no-sandbox in launcher."
EXEC_LINE="\"$DEST/$BINARY\" --no-sandbox %F"
fi
fi
# --- 4. Desktop launcher (registers as editor + URL handler) --------------
cat > "$DESKTOP" <<EOF
[Desktop Entry]
Name=$APP_DISPLAY
Comment=Code editor
GenericName=Text Editor
Exec=$EXEC_LINE
Icon=$APP_NAME
Terminal=false
Type=Application
Categories=Development;IDE;TextEditor;
StartupWMClass=$APP_NAME
MimeType=text/plain;inode/directory;application/x-antigravity-ide-workspace;x-scheme-handler/antigravity-ide;
Actions=new-empty-window;
[Desktop Action new-empty-window]
Name=New Empty Window
Exec=$EXEC_LINE --new-window
Icon=$APP_NAME
EOF
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
# --- 5. CLI symlink -------------------------------------------------------
ln -sf "$DEST/$BINARY" "$BIN_LINK"
# --- 6. Register as the handler for antigravity-ide:// links --------------
xdg-mime default "$APP_NAME.desktop" x-scheme-handler/antigravity-ide 2>/dev/null || true
# --- 7. Nautilus "Open in Antigravity IDE" right-click entry --------------
# GNOME / Nautilus only. Requires python3-nautilus (offered via apt below).
# Skipped silently if nautilus is not the active file manager.
NAUTILUS_EXT_DIR="$HOME/.local/share/nautilus-python/extensions"
NAUTILUS_EXT_FILE="$NAUTILUS_EXT_DIR/antigravity-ide.py"
install_nautilus_extension() {
if ! command -v nautilus >/dev/null 2>&1; then
return 0 # not a Nautilus desktop, silently skip
fi
if ! dpkg -s python3-nautilus >/dev/null 2>&1; then
echo
echo "Nautilus 'Open in $APP_DISPLAY' menu entry needs the python3-nautilus"
echo "package. Install it now? (sudo apt install python3-nautilus)"
if [ -t 0 ]; then
read -r -p " [Y/n] " ans
else
ans="Y"
fi
case "${ans:-Y}" in
[Nn]*) echo "Skipping Nautilus extension."; return 0 ;;
esac
sudo apt-get install -y python3-nautilus || {
echo "Failed to install python3-nautilus; skipping Nautilus extension."
return 0
}
fi
mkdir -p "$NAUTILUS_EXT_DIR"
cat > "$NAUTILUS_EXT_FILE" <<'PYEOF'
"""Nautilus right-click entry: Open in Antigravity IDE."""
import os
import subprocess
from urllib.parse import unquote, urlparse
import gi
for _v in ("4.1", "4.0", "3.0"):
try:
gi.require_version("Nautilus", _v)
break
except ValueError:
continue
from gi.repository import GObject, Nautilus
APP_DISPLAY = "Antigravity IDE"
BINARY = os.path.expanduser("~/Applications/antigravity-ide/antigravity-ide")
def _local_path(file_info):
parts = urlparse(file_info.get_uri())
if parts.scheme != "file":
return None
return unquote(parts.path)
def _launch(paths):
subprocess.Popen([BINARY, *paths], start_new_session=True)
class OpenInAntigravityIDE(GObject.GObject, Nautilus.MenuProvider):
def _item(self, name, label, paths):
item = Nautilus.MenuItem(name=name, label=label, tip=f"Open in {APP_DISPLAY}")
item.connect("activate", lambda _i, _p=paths: _launch(_p))
return item
def get_file_items(self, files):
paths = [p for p in (_local_path(f) for f in files) if p]
if not paths:
return []
return [self._item("AntigravityIDE::open_files",
f"Open in {APP_DISPLAY}", paths)]
def get_background_items(self, folder):
path = _local_path(folder)
if not path:
return []
return [self._item("AntigravityIDE::open_folder",
f"Open Folder in {APP_DISPLAY}", [path])]
PYEOF
nautilus -q 2>/dev/null || true
echo "Nautilus extension installed at $NAUTILUS_EXT_FILE"
echo "(Nautilus has been restarted; open windows will reappear.)"
}
install_nautilus_extension
echo
echo "Installed $APP_DISPLAY -> $DEST"
echo "Launch from your application menu, or run: $APP_NAME"
echo "(If '$APP_NAME' is not found, add ~/.local/bin to your PATH or log out/in.)"
#!/usr/bin/env bash
# install-antigravity.sh
#
# Installs the Antigravity (2.0 "Hub") Linux tarball into ~/Applications
# as a user-owned install, with a desktop launcher, icon, and CLI symlink.
#
# Usage:
# ./install-antigravity.sh /path/to/extracted/Antigravity-x64
#
# Notes:
# - User-owned; no sudo for the app itself or for future updates.
# - On Ubuntu 24.04+ Chromium's user-namespace sandbox is blocked by AppArmor
# by default. The script tries to install a one-time AppArmor profile
# (this step needs sudo). If sudo isn't available or the profile fails to
# load, it falls back to launching the app with --no-sandbox.
set -euo pipefail
SRC="${1:-}"
if [ -z "$SRC" ] || [ ! -x "$SRC/antigravity" ]; then
echo "Usage: $0 /path/to/extracted/Antigravity-x64"
echo " (Expected to find an executable 'antigravity' inside that dir.)"
exit 1
fi
SRC="$(cd "$SRC" && pwd)"
APP_NAME="antigravity"
APP_DISPLAY="Antigravity"
BINARY="antigravity"
DEST="$HOME/Applications/$APP_NAME"
ICON_DEST="$HOME/.local/share/icons/hicolor/512x512/apps/$APP_NAME.png"
DESKTOP="$HOME/.local/share/applications/$APP_NAME.desktop"
BIN_LINK="$HOME/.local/bin/$APP_NAME"
# --- 1. Extract icon.png from app.asar (pure stdlib python, no extra deps) ----
ICON_TMP="$(mktemp --suffix=.png)"
python3 - "$SRC/resources/app.asar" "$ICON_TMP" <<'PY'
import json, struct, sys
asar, out = sys.argv[1], sys.argv[2]
with open(asar, "rb") as f:
f.read(4)
struct.unpack("<I", f.read(4))
struct.unpack("<I", f.read(4))
hdr_len = struct.unpack("<I", f.read(4))[0]
hdr = f.read(hdr_len)
data_start = f.tell()
j = json.loads(hdr.split(b"\x00", 1)[0].decode("utf-8", "ignore"))
info = j["files"]["icon.png"]
with open(asar, "rb") as f:
f.seek(data_start + int(info["offset"]))
open(out, "wb").write(f.read(int(info["size"])))
PY
# --- 2. Move app into ~/Applications --------------------------------------
mkdir -p "$(dirname "$DEST")" "$(dirname "$BIN_LINK")" \
"$(dirname "$DESKTOP")" "$(dirname "$ICON_DEST")"
rm -rf "$DEST"
mv "$SRC" "$DEST"
# --- 3. Install icon -------------------------------------------------------
install -Dm644 "$ICON_TMP" "$ICON_DEST"
rm -f "$ICON_TMP"
gtk-update-icon-cache "$HOME/.local/share/icons/hicolor" 2>/dev/null || true
# --- 4. Sandbox: try AppArmor profile, else fall back to --no-sandbox -----
EXEC_LINE="\"$DEST/$BINARY\" %U"
USERNS_RESTRICTED="$(cat /proc/sys/kernel/apparmor_restrict_unprivileged_userns 2>/dev/null || echo 0)"
if [ "$USERNS_RESTRICTED" = "1" ]; then
PROFILE_NAME="userns-${APP_NAME}-${USER}"
PROFILE_PATH="/etc/apparmor.d/${PROFILE_NAME}"
PROFILE_BODY="abi <abi/4.0>,
include <tunables/global>
profile ${PROFILE_NAME} \"$DEST/$BINARY\" flags=(unconfined) {
userns,
include if exists <local/${PROFILE_NAME}>
}
"
echo "Ubuntu AppArmor restricts unprivileged user namespaces."
echo "Installing a one-time AppArmor profile so Chromium's sandbox works"
echo "(requires sudo; updates afterwards will not need sudo)."
if echo "$PROFILE_BODY" | sudo tee "$PROFILE_PATH" >/dev/null \
&& sudo apparmor_parser -r "$PROFILE_PATH"; then
echo "AppArmor profile installed: $PROFILE_PATH"
else
echo "AppArmor profile install failed; using --no-sandbox in launcher."
EXEC_LINE="\"$DEST/$BINARY\" --no-sandbox %U"
fi
fi
# --- 5. Desktop launcher ---------------------------------------------------
cat > "$DESKTOP" <<EOF
[Desktop Entry]
Name=$APP_DISPLAY
Comment=Antigravity agent control surface
Exec=$EXEC_LINE
Icon=$APP_NAME
Terminal=false
Type=Application
Categories=Development;IDE;
StartupWMClass=$APP_NAME
EOF
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
# --- 6. CLI symlink (~/.local/bin is on PATH by default on Ubuntu) --------
ln -sf "$DEST/$BINARY" "$BIN_LINK"
echo
echo "Installed $APP_DISPLAY -> $DEST"
echo "Launch from your application menu, or run: $APP_NAME"
echo "(If '$APP_NAME' is not found, add ~/.local/bin to your PATH or log out/in.)"
#!/usr/bin/env bash
# uninstall-antigravity-ide.sh
# Removes a user install of Antigravity IDE created by install-antigravity-ide.sh.
set -euo pipefail
APP_NAME="antigravity-ide"
DEST="$HOME/Applications/$APP_NAME"
ICON_DEST="$HOME/.local/share/icons/hicolor/512x512/apps/$APP_NAME.png"
ICON_DEST_BIG="$HOME/.local/share/icons/hicolor/1024x1024/apps/$APP_NAME.png"
DESKTOP="$HOME/.local/share/applications/$APP_NAME.desktop"
BIN_LINK="$HOME/.local/bin/$APP_NAME"
PROFILE_PATH="/etc/apparmor.d/userns-${APP_NAME}-${USER}"
NAUTILUS_EXT_FILE="$HOME/.local/share/nautilus-python/extensions/antigravity-ide.py"
rm -f "$BIN_LINK" "$DESKTOP" "$ICON_DEST" "$ICON_DEST_BIG" "$NAUTILUS_EXT_FILE"
rm -rf "$DEST"
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
gtk-update-icon-cache "$HOME/.local/share/icons/hicolor" 2>/dev/null || true
nautilus -q 2>/dev/null || true
if [ -f "$PROFILE_PATH" ]; then
echo "Removing AppArmor profile (sudo)..."
sudo apparmor_parser -R "$PROFILE_PATH" 2>/dev/null || true
sudo rm -f "$PROFILE_PATH"
fi
echo "Removed Antigravity IDE."
echo "(Your settings under ~/.antigravity-ide are kept; delete manually if desired.)"
#!/usr/bin/env bash
# uninstall-antigravity.sh
# Removes a user install of Antigravity (Hub) created by install-antigravity.sh.
set -euo pipefail
APP_NAME="antigravity"
DEST="$HOME/Applications/$APP_NAME"
ICON_DEST="$HOME/.local/share/icons/hicolor/512x512/apps/$APP_NAME.png"
DESKTOP="$HOME/.local/share/applications/$APP_NAME.desktop"
BIN_LINK="$HOME/.local/bin/$APP_NAME"
PROFILE_PATH="/etc/apparmor.d/userns-${APP_NAME}-${USER}"
rm -f "$BIN_LINK" "$DESKTOP" "$ICON_DEST"
rm -rf "$DEST"
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
gtk-update-icon-cache "$HOME/.local/share/icons/hicolor" 2>/dev/null || true
# Drop the AppArmor profile if we installed one (sudo prompt only if needed).
if [ -f "$PROFILE_PATH" ]; then
echo "Removing AppArmor profile (sudo)..."
sudo apparmor_parser -R "$PROFILE_PATH" 2>/dev/null || true
sudo rm -f "$PROFILE_PATH"
fi
echo "Removed Antigravity."
#!/usr/bin/env bash
# uninstall-system-wide-legacy.sh
# Cleans up an earlier system-wide install of Antigravity / Antigravity IDE
# under /opt + /usr/share + /usr/local/bin. Safe to run if nothing's there.
set -euo pipefail
for app in antigravity antigravity-ide; do
echo "Removing system-wide $app ..."
sudo rm -f "/usr/local/bin/$app"
sudo rm -f "/usr/share/applications/$app.desktop"
sudo rm -f "/usr/share/icons/hicolor/512x512/apps/$app.png"
sudo rm -f "/usr/share/icons/hicolor/1024x1024/apps/$app.png"
sudo rm -rf "/opt/$app"
done
sudo update-desktop-database /usr/share/applications 2>/dev/null || true
sudo gtk-update-icon-cache /usr/share/icons/hicolor 2>/dev/null || true
echo "Done. (User-local installs under ~/Applications are not touched.)"
@nonZero
Copy link
Copy Markdown

nonZero commented May 26, 2026

Do you see the "Open in IDE" button if you use this install?

@mattezell
Copy link
Copy Markdown
Author

Do you see the "Open in IDE" button if you use this install?

It does now :)

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment