Somnora/GSPOT

Hard to find, but keeps everything running smoothly.

7

stars

3

commits

Python

primary language

Aug 23, 2026

updated

README

G-Spot

Google Status, Project, & Optimization Tool

"Hard to find, but keeps everything running smoothly."

G-Spot is a lightweight, cross-platform system tray application for macOS, Windows, and Linux that continuously monitors Google Cloud SDK authentication, tracks active GCP project configurations, inspects billing, and prevents AI coding agents (Gemini, Claude Code, Cursor, Copilot, LangChain, etc.) from timing out due to expired OAuth or Application Default Credentials (ADC).


Features

Essential Tray Functions (Root Menu)

  • Dynamic GCP-Inspired Generic Cloud Icon System (Pillow ImageDraw):
    • Programmatically rendered in Python using Pillow without using official trademarked logos.
    • Dynamically colored based on credential status using Google's signature color palette:
      • Solid Green (#34A853): Both User (gcloud auth) and ADC (application-default) tokens are active.
      • Solid Yellow (#FBBC05): Partial authentication (only one set of tokens is active).
      • Solid Red (#EA4335): Both tokens are expired, missing, or disconnected.
      • Solid Blue (#4285F4): Initializing / actively refreshing.
      • Solid Gray (#80868B): Offline — no network reachable, so credential status is unknown. Distinguished from Red deliberately: a red icon on a plane is a false alarm, and false alarms train you to ignore the icon.
  • Dynamic Tooltips: Hover displays G-Spot: Active, G-Spot: Partial Auth, G-Spot: Expired, or G-Spot: Offline (no network) alongside the active project ID (e.g. G-Spot: Active (my-project-id)).
  • Identity & Token Expiry Header: Shows the authenticated Google account email and remaining token lifetime (e.g., Account: dev@company.com (~48m left)).
  • Proactive Desktop Notifications & Interactive Modal Popups:
    • Fires native OS desktop notification banners whenever authentication drops from Green to Yellow/Red — and on the first check after launch, since opening your laptop to a session that died overnight is the most common way this bites you.
    • Stays quiet when the cause is simply no network: G-Spot will not ask you to re-authenticate against a server it can't reach.
    • Automatically pops up an Interactive System Modal Alert Dialog with a 1-click [Re-Authenticate Now] action button when authentication is lost, immediately opening the terminal login flow.
    • Toggleable via Popup on Auth Loss: [ON/OFF] with an instant preview action Test Auth Loss Popup Now.
  • One-Click Re-Authentication: "Connect All (User + ADC)" launches your native terminal emulator (Terminal.app on macOS, Command Prompt / PowerShell on Windows, or standard Linux emulators) to run gcloud auth login && gcloud auth application-default login interactively.
  • Instant Project Switcher: View recent projects and switch your active gcloud project directly from the tray context menu without opening a shell.
  • Cloud Console Launcher: Quick-jump directly to the Cloud Console dashboard for the currently active project.

Developer & Agent Tools (Nested Submenu)

To keep the primary tray menu lightweight and clutter-free, pro-developer utilities are housed in the Developer & Agent Tools submenu:

  • Copy Agent Env Vars (Export): Copies standard shell export statements directly to the system clipboard:
    export GOOGLE_CLOUD_PROJECT="active-project-id"
    export CLOUDSDK_CORE_PROJECT="active-project-id"
    export GOOGLE_APPLICATION_CREDENTIALS="/path/to/application_default_credentials.json"
    export VERTEX_AI_PROJECT="active-project-id"
    
  • Run Agent Health Doctor: Runs a diagnostic scan verifying physical ADC file paths, token expiry, network reachability, and detecting any conflicting environment variables (GOOGLE_APPLICATION_CREDENTIALS, CLOUDSDK_AUTH_ACCESS_TOKEN). The full report is copied to your clipboard — a nine-field diagnostic doesn't fit in a notification banner.
  • Switch SDK Profile / Config: Submenu to list and activate named gcloud configuration profiles (default, staging, production).
  • Billing & Spend Snapshot: Real-time visibility into project billing account linkage and status, with automatic fallback when missing billing IAM permissions.
  • Auto-Renew Tokens: Toggleable background watcher that performs a real non-interactive refresh (via gcloud config config-helper --min-expiry) when fewer than 10 minutes remain. If the refresh does not extend the token, the underlying session has expired and G-Spot says so rather than reporting a success it didn't achieve.
  • Desktop Notifications: Toggleable via Desktop Notifications: [ON/OFF] to enable or disable system notification toasts and banners when credential status changes.
  • Popup on Auth Loss: Toggleable via Popup on Auth Loss: [ON/OFF] to enable or disable the interactive modal dialog window when authentication is lost, with an instant preview action Test Auth Loss Popup Now.
  • Session Policy: Direct links to the settings that actually govern how long your credentials live. Token lifetime is not a local setting - session length for Google Cloud (which covers the gcloud CLI and ADC, not just the web console) is a Google Workspace admin policy, configurable between 1 and 24 hours by someone holding the Security Settings privilege. G-Spot detects whether your active account belongs to a Workspace domain and either links you to the right admin page or explains why no such policy exists for a personal account.

Installation

Prerequisites

  1. Download GSPOT.exe directly from windows/GSPOT.exe or the root GSPOT.exe (also available on the latest GitHub Release).
  2. Double-click GSPOT.exe to launch.
  3. G-Spot will appear in your Windows notification area / taskbar tray (bottom-right near the clock, or inside the ^ overflow menu).
  4. Both left-click and right-click open the status menu and quick switcher.
  1. Download G-Spot-1.0.0.dmg directly from macos/G-Spot-1.0.0.dmg or the root G-Spot-1.0.0.dmg (also available on the latest GitHub Release).
  2. Open the .dmg and drag G-Spot.app into your Applications folder.
  3. Launch G-Spot from Launchpad or Spotlight.

Note: On first launch macOS may show a Gatekeeper warning since the app is not notarized. Right-click the app → OpenOpen to bypass.

From Source (All Platforms)

Requires Python 3.9+.

# 1. Clone the repository
git clone https://github.com/Somnora/GSPOT.git && cd GSPOT

# 2. Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate    # On Windows: .venv\Scripts\activate

# 3. Install dependencies
pip install -r requirements.txt

# 4. Launch G-Spot
python main.py

Build Standalone Binaries Locally

Windows (.exe):

pip install pyinstaller
.\windows\build_windows.bat
# Output: dist\GSPOT.exe and windows\GSPOT.exe

macOS (.dmg):

pip install pyinstaller
python macos/generate_icns.py   # Generate macOS .icns app icon
pyinstaller macos/G-Spot.spec --noconfirm --clean
bash macos/build_dmg.sh         # Output: dist/G-Spot-1.0.0.dmg

Command Line Options

python main.py --help
# Options:
#   -i, --interval SECONDS   Polling check interval in seconds (default: 300 / 5 minutes)
#   --debug                  Enable verbose debug logging
#   -v, --version            Display version information
#
# Headless mode (no tray, no display required):
#   --status                 Print current status and exit 0
#   --json                   With --status, print JSON instead of one line
#   --check                  Exit 0 if at least --min-minutes remain, else 1
#   --renew                  Force a non-interactive refresh; exit 0 on success
#   --min-minutes N          Minutes required (--check: 30, --renew: 55)

Headless / CI Usage

--status, --check and --renew run without a tray and without a display. They never import pystray, so they work over SSH, in a container, or in CI where importing a GUI toolkit would raise.

Preflight gate

The failure this tool exists to prevent is starting a long agent run on a token that dies halfway through. Gate the run instead of being notified about it:

python main.py --check --min-minutes 30 || python main.py --renew

Exit 0 means you have at least 30 minutes and can safely start. Exit 1 means the credential could not be brought up to that mark and only an interactive gcloud auth login will help.

Status

$ python main.py --status
GREEN | you@example.com | my-project | ~42m left | user=ok adc=ok

$ python main.py --status --json
{
  "state": "green",
  "account": "you@example.com",
  "project": "my-project",
  "token_expiry_minutes": 42,
  "adc_valid": true,
  "user_valid": true,
  "network_reachable": true
}

state is one of green, yellow, red, offline, searching. JSON goes to stdout and diagnostics to stderr, so --status --json 2>/dev/null is safe to pipe straight into jq. --status always exits 0 — it reports, it does not gate.

network_reachable is only actively probed when every auth check has already failed, so true means "not proven unreachable" rather than "just pinged".

Exit codes

Command01
--statusalways
--checkat least --min-minutes remaintoo little time, expired, offline, unknown expiry, or no gcloud
--renewrefreshed, or already above --min-minutesrefresh could not extend the credential

--check fails closed: anything it cannot positively verify is a failure, since a false pass costs you a dead agent run. Partial auth (one of user/ADC missing) still exits 0 if there is enough time, but prints a warning to stderr.

--renew exits 0 when the token was already comfortable and gcloud declined to refresh it — that is the normal case in the one-liner above, not an error.


Running G-Spot Silently on Startup

To have G-Spot run automatically in the background on system boot without showing a terminal window:

macOS (LaunchAgent)

  1. Create a LaunchAgent plist file at ~/Library/LaunchAgents/com.user.gspot.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.gspot</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/YOUR_USERNAME/Desktop/G_Spot/.venv/bin/python</string>
        <string>/Users/YOUR_USERNAME/Desktop/G_Spot/main.py</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/tmp/gspot.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/gspot.err</string>
</dict>
</plist>
  1. Load and start the service:
launchctl load ~/Library/LaunchAgents/com.user.gspot.plist

Windows (Startup Folder or Task Scheduler)

Method 1: Startup Folder Shortcut (pythonw.exe)

  1. Press Win + R, type shell:startup, and hit Enter.
  2. Right-click in the folder -> New -> Shortcut.
  3. For location, enter:
    "C:\path\to\G_Spot\.venv\Scripts\pythonw.exe" "C:\path\to\G_Spot\main.py"
    
    (Using pythonw.exe runs Python without opening a Command Prompt window).
  4. Click Next, name it G-Spot, and click Finish.

Method 2: Task Scheduler

  1. Open Task Scheduler -> Create Basic Task.
  2. Trigger: When I log on.
  3. Action: Start a program.
  4. Program: C:\path\to\G_Spot\.venv\Scripts\pythonw.exe
  5. Arguments: main.py
  6. Start in: C:\path\to\G_Spot

Linux (systemd user service or Autostart Desktop Entry)

Method 1: Desktop Autostart (~/.config/autostart)

Create ~/.config/autostart/gspot.desktop:

[Desktop Entry]
Type=Application
Name=G-Spot
Comment=Google Status, Project, & Optimization Tool
Exec=/path/to/G_Spot/.venv/bin/python /path/to/G_Spot/main.py
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true

Method 2: Systemd User Service

  1. Create ~/.config/systemd/user/gspot.service:
[Unit]
Description=G-Spot Background Tray Service
After=graphical-session.target

[Service]
Type=simple
WorkingDirectory=/path/to/G_Spot
ExecStart=/path/to/G_Spot/.venv/bin/python main.py
Restart=always
RestartSec=5

[Install]
WantedBy=default.target
  1. Enable and start:
systemctl --user daemon-reload
systemctl --user enable --now gspot.service

Project Architecture

G-Spot/
├── .github/
│   └── workflows/
│       └── release.yml         # CI: Build .app, package .dmg, publish GitHub Release on tag
├── assets/
│   ├── icons/                  # Monotone SVG icons (active, degraded, expired, actions)
│   ├── preview/                # Pre-rendered PNG previews of each icon state
│   └── icon.icns               # macOS app icon bundle (generated by scripts/generate_icns.py)
├── gspot/
│   ├── __init__.py             # Package metadata & tagline
│   ├── app.py                  # Pystray tray application loop & streamlined menu hierarchy
│   ├── clipboard.py            # Cross-platform clipboard copy helper (pbcopy / clip / xclip)
│   ├── config.py               # State enums (GREEN/YELLOW/RED), polling constants, status dataclass
│   ├── gcloud.py               # Subprocess wrappers for auth, ADC, projects, configs, diagnostics
│   ├── headless.py             # --status / --check / --renew CLI; imports no GUI dependencies
│   ├── icons.py                # High-DPI 8x supersampled Pillow dynamic tray icon generator
│   ├── notifications.py        # Desktop alert dispatcher + interactive modal popups
│   ├── settings.py             # Persisted user preferences (~/.config/gspot/config.json)
│   └── terminal.py             # Native interactive terminal launcher for re-authentication
├── scripts/
│   ├── generate_icns.py        # Renders app icon into macOS .iconset → .icns
│   └── build_dmg.sh            # Packages G-Spot.app into a distributable .dmg installer
├── tests/
│   ├── __init__.py
│   ├── test_auth_lifecycle.py  # 40 tests for state transitions, offline handling, auto-renew
│   ├── test_gcloud.py          # 25 tests for gcloud wrappers, billing, and the health doctor
│   ├── test_headless.py        # 22 tests for headless exit codes and display independence
│   └── test_settings.py        # 12 tests for preference persistence and corrupt-file fallback
├── main.py                     # CLI entrypoint; dispatches headless mode before loading the tray
├── G-Spot.spec                 # PyInstaller build specification
├── requirements.txt            # Dependencies (pystray, Pillow, plyer)
└── README.md

Configuration

Preferences you set from the tray menu (auto-renew, popup alerts, check interval) persist to:

PlatformPath
macOS / Linux~/.config/gspot/config.json (respects XDG_CONFIG_HOME)
Windows%APPDATA%\gspot\config.json

The file is written atomically and is safe to edit by hand; out-of-range or malformed values fall back to defaults rather than preventing startup. --interval overrides the saved value for a single run without rewriting it.


A note on token lifetime

G-Spot cannot extend how long your credentials last, and neither can any other local tool. Access tokens live about an hour and refresh transparently; what actually kills a long agent run is the session behind them expiring. That session length is set by a Google Workspace administrator (Admin console → Security → Access and data control → Google Cloud session control), ranges from 1 to 24 hours, and applies to the gcloud CLI and ADC just as much as to the web console. There is no gcloud flag or config property that changes it.

What G-Spot does instead: refresh while refreshing still works, tell you clearly when it stops working, and put the relevant admin page one click away under Developer & Agent Tools → Session Policy. Personal @gmail.com accounts have no Workspace org and therefore no such policy — the menu says so rather than linking you to a page you'd get denied on.


Running Tests

source .venv/bin/activate
python -m unittest discover -s tests -v

The suite mocks every gcloud invocation and network call, so it runs without a Google Cloud SDK installation and without touching your real credentials.


License

MIT License. Built to keep AI agents authenticated and uninterrupted.

Contributors

Somnora

3 commits

Somnora/GSPOT

Hard to find, but keeps everything running smoothly.

7

stars

3

commits

Python

primary language

Aug 23, 2026

updated

README

G-Spot

Google Status, Project, & Optimization Tool

"Hard to find, but keeps everything running smoothly."

G-Spot is a lightweight, cross-platform system tray application for macOS, Windows, and Linux that continuously monitors Google Cloud SDK authentication, tracks active GCP project configurations, inspects billing, and prevents AI coding agents (Gemini, Claude Code, Cursor, Copilot, LangChain, etc.) from timing out due to expired OAuth or Application Default Credentials (ADC).


Features

Essential Tray Functions (Root Menu)

  • Dynamic GCP-Inspired Generic Cloud Icon System (Pillow ImageDraw):
    • Programmatically rendered in Python using Pillow without using official trademarked logos.
    • Dynamically colored based on credential status using Google's signature color palette:
      • Solid Green (#34A853): Both User (gcloud auth) and ADC (application-default) tokens are active.
      • Solid Yellow (#FBBC05): Partial authentication (only one set of tokens is active).
      • Solid Red (#EA4335): Both tokens are expired, missing, or disconnected.
      • Solid Blue (#4285F4): Initializing / actively refreshing.
      • Solid Gray (#80868B): Offline — no network reachable, so credential status is unknown. Distinguished from Red deliberately: a red icon on a plane is a false alarm, and false alarms train you to ignore the icon.
  • Dynamic Tooltips: Hover displays G-Spot: Active, G-Spot: Partial Auth, G-Spot: Expired, or G-Spot: Offline (no network) alongside the active project ID (e.g. G-Spot: Active (my-project-id)).
  • Identity & Token Expiry Header: Shows the authenticated Google account email and remaining token lifetime (e.g., Account: dev@company.com (~48m left)).
  • Proactive Desktop Notifications & Interactive Modal Popups:
    • Fires native OS desktop notification banners whenever authentication drops from Green to Yellow/Red — and on the first check after launch, since opening your laptop to a session that died overnight is the most common way this bites you.
    • Stays quiet when the cause is simply no network: G-Spot will not ask you to re-authenticate against a server it can't reach.
    • Automatically pops up an Interactive System Modal Alert Dialog with a 1-click [Re-Authenticate Now] action button when authentication is lost, immediately opening the terminal login flow.
    • Toggleable via Popup on Auth Loss: [ON/OFF] with an instant preview action Test Auth Loss Popup Now.
  • One-Click Re-Authentication: "Connect All (User + ADC)" launches your native terminal emulator (Terminal.app on macOS, Command Prompt / PowerShell on Windows, or standard Linux emulators) to run gcloud auth login && gcloud auth application-default login interactively.
  • Instant Project Switcher: View recent projects and switch your active gcloud project directly from the tray context menu without opening a shell.
  • Cloud Console Launcher: Quick-jump directly to the Cloud Console dashboard for the currently active project.

Developer & Agent Tools (Nested Submenu)

To keep the primary tray menu lightweight and clutter-free, pro-developer utilities are housed in the Developer & Agent Tools submenu:

  • Copy Agent Env Vars (Export): Copies standard shell export statements directly to the system clipboard:
    export GOOGLE_CLOUD_PROJECT="active-project-id"
    export CLOUDSDK_CORE_PROJECT="active-project-id"
    export GOOGLE_APPLICATION_CREDENTIALS="/path/to/application_default_credentials.json"
    export VERTEX_AI_PROJECT="active-project-id"
    
  • Run Agent Health Doctor: Runs a diagnostic scan verifying physical ADC file paths, token expiry, network reachability, and detecting any conflicting environment variables (GOOGLE_APPLICATION_CREDENTIALS, CLOUDSDK_AUTH_ACCESS_TOKEN). The full report is copied to your clipboard — a nine-field diagnostic doesn't fit in a notification banner.
  • Switch SDK Profile / Config: Submenu to list and activate named gcloud configuration profiles (default, staging, production).
  • Billing & Spend Snapshot: Real-time visibility into project billing account linkage and status, with automatic fallback when missing billing IAM permissions.
  • Auto-Renew Tokens: Toggleable background watcher that performs a real non-interactive refresh (via gcloud config config-helper --min-expiry) when fewer than 10 minutes remain. If the refresh does not extend the token, the underlying session has expired and G-Spot says so rather than reporting a success it didn't achieve.
  • Desktop Notifications: Toggleable via Desktop Notifications: [ON/OFF] to enable or disable system notification toasts and banners when credential status changes.
  • Popup on Auth Loss: Toggleable via Popup on Auth Loss: [ON/OFF] to enable or disable the interactive modal dialog window when authentication is lost, with an instant preview action Test Auth Loss Popup Now.
  • Session Policy: Direct links to the settings that actually govern how long your credentials live. Token lifetime is not a local setting - session length for Google Cloud (which covers the gcloud CLI and ADC, not just the web console) is a Google Workspace admin policy, configurable between 1 and 24 hours by someone holding the Security Settings privilege. G-Spot detects whether your active account belongs to a Workspace domain and either links you to the right admin page or explains why no such policy exists for a personal account.

Installation

Prerequisites

  1. Download GSPOT.exe directly from windows/GSPOT.exe or the root GSPOT.exe (also available on the latest GitHub Release).
  2. Double-click GSPOT.exe to launch.
  3. G-Spot will appear in your Windows notification area / taskbar tray (bottom-right near the clock, or inside the ^ overflow menu).
  4. Both left-click and right-click open the status menu and quick switcher.
  1. Download G-Spot-1.0.0.dmg directly from macos/G-Spot-1.0.0.dmg or the root G-Spot-1.0.0.dmg (also available on the latest GitHub Release).
  2. Open the .dmg and drag G-Spot.app into your Applications folder.
  3. Launch G-Spot from Launchpad or Spotlight.

Note: On first launch macOS may show a Gatekeeper warning since the app is not notarized. Right-click the app → OpenOpen to bypass.

From Source (All Platforms)

Requires Python 3.9+.

# 1. Clone the repository
git clone https://github.com/Somnora/GSPOT.git && cd GSPOT

# 2. Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate    # On Windows: .venv\Scripts\activate

# 3. Install dependencies
pip install -r requirements.txt

# 4. Launch G-Spot
python main.py

Build Standalone Binaries Locally

Windows (.exe):

pip install pyinstaller
.\windows\build_windows.bat
# Output: dist\GSPOT.exe and windows\GSPOT.exe

macOS (.dmg):

pip install pyinstaller
python macos/generate_icns.py   # Generate macOS .icns app icon
pyinstaller macos/G-Spot.spec --noconfirm --clean
bash macos/build_dmg.sh         # Output: dist/G-Spot-1.0.0.dmg

Command Line Options

python main.py --help
# Options:
#   -i, --interval SECONDS   Polling check interval in seconds (default: 300 / 5 minutes)
#   --debug                  Enable verbose debug logging
#   -v, --version            Display version information
#
# Headless mode (no tray, no display required):
#   --status                 Print current status and exit 0
#   --json                   With --status, print JSON instead of one line
#   --check                  Exit 0 if at least --min-minutes remain, else 1
#   --renew                  Force a non-interactive refresh; exit 0 on success
#   --min-minutes N          Minutes required (--check: 30, --renew: 55)

Headless / CI Usage

--status, --check and --renew run without a tray and without a display. They never import pystray, so they work over SSH, in a container, or in CI where importing a GUI toolkit would raise.

Preflight gate

The failure this tool exists to prevent is starting a long agent run on a token that dies halfway through. Gate the run instead of being notified about it:

python main.py --check --min-minutes 30 || python main.py --renew

Exit 0 means you have at least 30 minutes and can safely start. Exit 1 means the credential could not be brought up to that mark and only an interactive gcloud auth login will help.

Status

$ python main.py --status
GREEN | you@example.com | my-project | ~42m left | user=ok adc=ok

$ python main.py --status --json
{
  "state": "green",
  "account": "you@example.com",
  "project": "my-project",
  "token_expiry_minutes": 42,
  "adc_valid": true,
  "user_valid": true,
  "network_reachable": true
}

state is one of green, yellow, red, offline, searching. JSON goes to stdout and diagnostics to stderr, so --status --json 2>/dev/null is safe to pipe straight into jq. --status always exits 0 — it reports, it does not gate.

network_reachable is only actively probed when every auth check has already failed, so true means "not proven unreachable" rather than "just pinged".

Exit codes

Command01
--statusalways
--checkat least --min-minutes remaintoo little time, expired, offline, unknown expiry, or no gcloud
--renewrefreshed, or already above --min-minutesrefresh could not extend the credential

--check fails closed: anything it cannot positively verify is a failure, since a false pass costs you a dead agent run. Partial auth (one of user/ADC missing) still exits 0 if there is enough time, but prints a warning to stderr.

--renew exits 0 when the token was already comfortable and gcloud declined to refresh it — that is the normal case in the one-liner above, not an error.


Running G-Spot Silently on Startup

To have G-Spot run automatically in the background on system boot without showing a terminal window:

macOS (LaunchAgent)

  1. Create a LaunchAgent plist file at ~/Library/LaunchAgents/com.user.gspot.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.gspot</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/YOUR_USERNAME/Desktop/G_Spot/.venv/bin/python</string>
        <string>/Users/YOUR_USERNAME/Desktop/G_Spot/main.py</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/tmp/gspot.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/gspot.err</string>
</dict>
</plist>
  1. Load and start the service:
launchctl load ~/Library/LaunchAgents/com.user.gspot.plist

Windows (Startup Folder or Task Scheduler)

Method 1: Startup Folder Shortcut (pythonw.exe)

  1. Press Win + R, type shell:startup, and hit Enter.
  2. Right-click in the folder -> New -> Shortcut.
  3. For location, enter:
    "C:\path\to\G_Spot\.venv\Scripts\pythonw.exe" "C:\path\to\G_Spot\main.py"
    
    (Using pythonw.exe runs Python without opening a Command Prompt window).
  4. Click Next, name it G-Spot, and click Finish.

Method 2: Task Scheduler

  1. Open Task Scheduler -> Create Basic Task.
  2. Trigger: When I log on.
  3. Action: Start a program.
  4. Program: C:\path\to\G_Spot\.venv\Scripts\pythonw.exe
  5. Arguments: main.py
  6. Start in: C:\path\to\G_Spot

Linux (systemd user service or Autostart Desktop Entry)

Method 1: Desktop Autostart (~/.config/autostart)

Create ~/.config/autostart/gspot.desktop:

[Desktop Entry]
Type=Application
Name=G-Spot
Comment=Google Status, Project, & Optimization Tool
Exec=/path/to/G_Spot/.venv/bin/python /path/to/G_Spot/main.py
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true

Method 2: Systemd User Service

  1. Create ~/.config/systemd/user/gspot.service:
[Unit]
Description=G-Spot Background Tray Service
After=graphical-session.target

[Service]
Type=simple
WorkingDirectory=/path/to/G_Spot
ExecStart=/path/to/G_Spot/.venv/bin/python main.py
Restart=always
RestartSec=5

[Install]
WantedBy=default.target
  1. Enable and start:
systemctl --user daemon-reload
systemctl --user enable --now gspot.service

Project Architecture

G-Spot/
├── .github/
│   └── workflows/
│       └── release.yml         # CI: Build .app, package .dmg, publish GitHub Release on tag
├── assets/
│   ├── icons/                  # Monotone SVG icons (active, degraded, expired, actions)
│   ├── preview/                # Pre-rendered PNG previews of each icon state
│   └── icon.icns               # macOS app icon bundle (generated by scripts/generate_icns.py)
├── gspot/
│   ├── __init__.py             # Package metadata & tagline
│   ├── app.py                  # Pystray tray application loop & streamlined menu hierarchy
│   ├── clipboard.py            # Cross-platform clipboard copy helper (pbcopy / clip / xclip)
│   ├── config.py               # State enums (GREEN/YELLOW/RED), polling constants, status dataclass
│   ├── gcloud.py               # Subprocess wrappers for auth, ADC, projects, configs, diagnostics
│   ├── headless.py             # --status / --check / --renew CLI; imports no GUI dependencies
│   ├── icons.py                # High-DPI 8x supersampled Pillow dynamic tray icon generator
│   ├── notifications.py        # Desktop alert dispatcher + interactive modal popups
│   ├── settings.py             # Persisted user preferences (~/.config/gspot/config.json)
│   └── terminal.py             # Native interactive terminal launcher for re-authentication
├── scripts/
│   ├── generate_icns.py        # Renders app icon into macOS .iconset → .icns
│   └── build_dmg.sh            # Packages G-Spot.app into a distributable .dmg installer
├── tests/
│   ├── __init__.py
│   ├── test_auth_lifecycle.py  # 40 tests for state transitions, offline handling, auto-renew
│   ├── test_gcloud.py          # 25 tests for gcloud wrappers, billing, and the health doctor
│   ├── test_headless.py        # 22 tests for headless exit codes and display independence
│   └── test_settings.py        # 12 tests for preference persistence and corrupt-file fallback
├── main.py                     # CLI entrypoint; dispatches headless mode before loading the tray
├── G-Spot.spec                 # PyInstaller build specification
├── requirements.txt            # Dependencies (pystray, Pillow, plyer)
└── README.md

Configuration

Preferences you set from the tray menu (auto-renew, popup alerts, check interval) persist to:

PlatformPath
macOS / Linux~/.config/gspot/config.json (respects XDG_CONFIG_HOME)
Windows%APPDATA%\gspot\config.json

The file is written atomically and is safe to edit by hand; out-of-range or malformed values fall back to defaults rather than preventing startup. --interval overrides the saved value for a single run without rewriting it.


A note on token lifetime

G-Spot cannot extend how long your credentials last, and neither can any other local tool. Access tokens live about an hour and refresh transparently; what actually kills a long agent run is the session behind them expiring. That session length is set by a Google Workspace administrator (Admin console → Security → Access and data control → Google Cloud session control), ranges from 1 to 24 hours, and applies to the gcloud CLI and ADC just as much as to the web console. There is no gcloud flag or config property that changes it.

What G-Spot does instead: refresh while refreshing still works, tell you clearly when it stops working, and put the relevant admin page one click away under Developer & Agent Tools → Session Policy. Personal @gmail.com accounts have no Workspace org and therefore no such policy — the menu says so rather than linking you to a page you'd get denied on.


Running Tests

source .venv/bin/activate
python -m unittest discover -s tests -v

The suite mocks every gcloud invocation and network call, so it runs without a Google Cloud SDK installation and without touching your real credentials.


License

MIT License. Built to keep AI agents authenticated and uninterrupted.

Contributors

Somnora

3 commits

Languages

Python

95.9%

PowerShell

1.6%

Batchfile

1.6%