Antigravity Sidecars Architecture
7 Active • Self-Healing
Antigravity Sidecars & Autonomous Scheduling Engine

Comprehensive reference for the sidecar subsystem on dell5040. Combines declarative sidecar manifests (~/.gemini/config/sidecars/), user-scoped systemd timers, dynamic Language Server ephemeral gRPC port discovery, process-memory CSRF token extraction, SQLite trajectory state monitoring, and automated failure alerting via the official Google Gmail API.

Host: dell5040 Daemon: agy remote-control serve Alerts: Gmail API (masonwan@gmail.com) Updated: 2026-09-26
Total Sidecars
7
6 Scheduled Jobs + 1 Web UI Panel
LS Port Discovery
Dynamic
ss -tlpn + gRPC Handshake Probe
CSRF Resolution
/proc/mem
Zero-config runtime UUID extraction
State Tracking
SQLite WAL
2s polling • 3,600s max timeout
Failure Alerting
Gmail API
OAuth2 via gsuite.mjs (500/day limit)

1. End-to-End Execution Pipeline

5-Layer Autonomous Architecture

Antigravity supports two distinct sidecar paradigms: Scheduled Background Automation (triggered autonomously via systemd --user timers through the agy-agentapi-run bridge) and Interactive Web UI Extensions (spawned with Node.js and mounted inside the IDE auxiliary pane via sidecar://).

flowchart TD
    subgraph L1["Layer 1: Triggers & Entrypoints"]
        T1["systemd --user Timers
(6 Scheduled Cron Units)"] T2["Antigravity IDE Host
(auxPane Web UI Extension)"] end subgraph L2["Layer 2: Dynamic Runtime Bridge (agy-agentapi-run)"] B1["1. Locate Daemon PID
pgrep -f 'agy.*remote-control'"] B2["2. Resolve Ephemeral LS Port
Validate /run/user/1000/agy_ls_address
or scan ss -tlpn + gRPC probe"] B3["3. Extract CSRF Token
Validate /run/user/1000/agy_csrf_token
or scan /proc/<pid>/mem"] end subgraph L3["Layer 3: RPC Dispatch & Daemon Execution"] D1["/home/mason/.gemini/antigravity-cli/bin/agentapi
new-conversation --title=<Name> <Prompt>"] D2["antigravity-cli-daemon.service
(agy remote-control serve)"] D3["demo-web-control/server.mjs
(Node.js Web UI Server :8765)"] end subgraph L4["Layer 4: Trajectory Monitoring & Completion"] M1[("conversation_summaries.db
(SQLite WAL State Store)")] M2{"Status == IDLE &
not_fully_idle == 0?"} M3["Exit 0 (Success)
Logged to systemd journal"] end subgraph L5["Layer 5: Automated Failure Alerting"] A1["Catch Any Failure Stage:
• Daemon Offline • Port/Token Fail
• Dispatch Error • Killed • Timeout"] A2["gsuite.mjs gmail send
(OAuth2 HTTPS REST API)"] A3["masonwan@gmail.com
(Diagnostic Alert Email)"] end T1 -->|"Triggers Oneshot .service"| B1 T2 -->|"Spawns with ANTIGRAVITY_SIDECAR_WEB_PORT"| D3 D3 <-->|"/_sidecar/* Bridge & agentapi"| D2 B1 --> B2 --> B3 --> D1 D1 -->|"gRPC over 127.0.0.1:<dynamic_port>"| D2 D2 -->|"Writes Trajectory State"| M1 D1 -->|"Returns conversationId"| M2 M1 -.->|"Polled every 2s"| M2 M2 -->|"Yes"| M3 B1 -.->|"Timeout / Error"| A1 B2 -.->|"No Valid Port"| A1 B3 -.->|"Token Missing"| A1 D1 -.->|"Exit Code != 0"| A1 M2 -.->|"killed == 1 or >3600s"| A1 A1 --> A2 --> A3

2. Dynamic Ephemeral Port & CSRF Token Resolution

Zero Hardcoded Ports

Why Does the Daemon Use Random Ports?

When antigravity-cli-daemon.service starts /home/mason/.local/bin/agy remote-control serve, the internal Language Server and HTTP control servers bind to port 0. The Linux kernel dynamically assigns available ephemeral ports in the 32768–60999 range to prevent port collisions across multiple CLI sessions.

  • 1

    Dual Socket Allocation

    The daemon opens two localhost listeners: an HTTP control socket (e.g. 127.0.0.1:36947) and the gRPC Language Server socket (e.g. 127.0.0.1:36345).

  • 2

    Distinguishing gRPC from HTTP

    Simple TCP connect checks fail because the HTTP socket accepts connections but aborts gRPC calls with error reading server preface: EOF. test_ls_address() runs an actual agentapi get-conversation-metadata probe-test handshake to verify a genuine gRPC response.

  • 3

    Self-Healing Cache Invalidation

    Cached addresses in /run/user/1000/agy_ls_address are probed before every run. If the daemon restarted and changed ports, the stale cache file is immediately purged and re-discovered via ss -tlpn.

Cache Hit vs. Stale Port Self-Healing Sequence

sequenceDiagram
    autonumber
    participant S as systemd Service
    participant R as agy-agentapi-run
    participant C as /run/user/1000 Cache
    participant K as Kernel (ss / /proc)
    participant D as agy Daemon (gRPC)

    S->>R: Start Sidecar Trigger
    R->>K: pgrep -f "agy.*remote-control"
    K-->>R: daemon_pid (e.g. 522323)
    R->>C: Read agy_ls_address
    alt Cache Valid (Fast Path)
        R->>D: Probe cached port (get-conversation-metadata)
        D-->>R: Valid gRPC Response ("trajectory not found")
    else Cache Stale / Missing (Self-Healing Path)
        R->>D: Probe stale port (e.g. 46707)
        D--xR: Connection Refused / Unavailable
        R->>C: Remove stale agy_ls_address
        R->>K: ss -tlpn (filter pid=522323)
        K-->>R: Candidate Ports [36947, 36345]
        R->>D: Probe 36947 -> EOF (Rejected)
        R->>D: Probe 36345 -> Valid gRPC!
        R->>C: Write 127.0.0.1:36345
    end
    R->>K: Extract CSRF UUID from /proc/522323/mem
    R->>D: Dispatch new-conversation + Poll SQLite
          

3. Configured Sidecars Registry (7 Total)

Click any row to inspect configuration & systemd unit details
Sidecar ID & Name Type & Mechanism Schedule (PDT) Target Skill / Execution Action Status
Find Big Screen MacBook Deals find-big-screen-macbook-deals
Scheduled Cron systemd timer + oneshot
0 6,18 * * * Daily at 06:00 & 18:00
python3 scripts/find_deals.py --json --limit 5 + /learn check
Enabled Timer Waiting
Files & Units:
Manifest: ~/.gemini/config/sidecars/find-big-screen-macbook-deals/sidecar.json
Service:  ~/.config/systemd/user/sidecar-find-big-screen-macbook-deals.service
Timer:    ~/.config/systemd/user/sidecar-find-big-screen-macbook-deals.timer
ExecStart Command:
/home/mason/.local/bin/agy-agentapi-run new-conversation \
  --title="Find Big Screen MacBook Deals" \
  "In /home/mason/repos/llm-skills/prod/find-big-screen-macbook-deals, execute python3 scripts/find_deals.py --json --limit 5, output the markdown table of results, and perform the /learn diagnostic check."
Link Media link-media
Scheduled Cron systemd timer + oneshot
0 6 * * * Daily at 06:00
/link-media (Classify ~/sync/oracle1, Taiwanese titles, subtitles)
Enabled Timer Waiting
Daily Digest daily-digest
Scheduled Cron systemd timer + oneshot
0 7 * * * Daily at 07:00
/daily-digest /send-mail (Multi-agent executive briefing via email)
Enabled Timer Waiting
Files & Units:
Manifest: ~/.gemini/config/sidecars/daily-digest/sidecar.json
Service:  ~/.config/systemd/user/sidecar-daily-digest.service
Timer:    ~/.config/systemd/user/sidecar-daily-digest.timer
ExecStart Command:
/home/mason/.local/bin/agy-agentapi-run new-conversation \
  --title="Daily Digest" \
  "In /home/mason/repos/llm-skills/prod, /daily-digest /send-mail"
Daily Server Update update-servers-daily
Scheduled Cron systemd timer + oneshot
0 7 * * * Daily at 07:00
/update-servers /send-mail (Package upgrades & reboot audit across fleet)
Enabled Timer Waiting
Files & Units:
Manifest: ~/.gemini/config/sidecars/update-servers-daily/sidecar.json
Service:  ~/.config/systemd/user/sidecar-update-servers-daily.service
Timer:    ~/.config/systemd/user/sidecar-update-servers-daily.timer
ExecStart Command:
/home/mason/.local/bin/agy-agentapi-run new-conversation \
  --title="Daily Server Update" \
  "In /home/mason/repos/llm-skills/prod, /update-servers /send-mail"
Hacker News Daily Digest hacker-news-daily
Scheduled Cron systemd timer + oneshot
0 9 * * * Daily at 09:00
node scripts/run.mjs --notify (Top 10 HN stories + dashboard + email)
Enabled Timer Waiting
Files & Units:
Manifest: ~/.gemini/config/sidecars/hacker-news-daily/sidecar.json
Service:  ~/.config/systemd/user/sidecar-hacker-news-daily.service
Timer:    ~/.config/systemd/user/sidecar-hacker-news-daily.timer
ExecStart Command:
/home/mason/.local/bin/agy-agentapi-run new-conversation \
  --title="Hacker News Daily Digest" \
  "In /home/mason/repos/llm-skills/prod/hacker-news-daily, node scripts/run.mjs --notify"
Weekly Server Attack Audit audit-server-attacks-weekly
Scheduled Cron systemd timer + oneshot
0 17 * * 5 Fridays at 17:00
/audit-server-attacks /serve-page /send-mail (7-day CrowdSec/SSH/nftables audit)
Enabled Timer Waiting
Files & Units:
Manifest: ~/.gemini/config/sidecars/audit-server-attacks-weekly/sidecar.json
Service:  ~/.config/systemd/user/sidecar-audit-server-attacks-weekly.service
Timer:    ~/.config/systemd/user/sidecar-audit-server-attacks-weekly.timer
ExecStart Command:
/home/mason/.local/bin/agy-agentapi-run new-conversation \
  --title="Weekly Server Attack Audit" \
  "In /home/mason/repos/llm-skills/prod, /audit-server-attacks /serve-page /send-mail"
Demo Web Control Panel demo-web-control
Web UI Extension auxPane HTTP Server
On-Demand IDE Auxiliary Pane
node server.mjs (Host telemetry, workspace URI inspector, Agent API console)
Enabled sidecar://demo-web-control/
Files & Entrypoint:
Manifest: ~/.gemini/config/sidecars/demo-web-control/sidecar.json
Backend:  ~/.gemini/config/sidecars/demo-web-control/server.mjs
URI:      sidecar://demo-web-control/
Runtime Environment Provided by Antigravity:
ANTIGRAVITY_SIDECAR_WEB_PORT=8765
ANTIGRAVITY_SIDECAR_UI_TOKEN=<session-token>
ANTIGRAVITY_EXECUTABLE_DATA_DIR=~/.gemini/antigravity-cli/sidecar_data/demo-web-control/data/

4. Failure Detection & Gmail API Notification Architecture

6 Failure Gates Covered

Failure Gates Monitored by agy-agentapi-run

Stage Trigger Condition Diagnostic Captured
1. Daemon Offline pgrep finds no agy remote-control within 15s Host & process search status
2. LS Port Fail No socket on daemon PID passes gRPC handshake probe Daemon PID & candidate ports
3. CSRF Missing UUID token not found or rejected by send-message probe Daemon PID & LS address
4. Dispatch Error agentapi new-conversation returns exit code $\ne 0$ Full command, exit code, stderr/stdout
5. Task Killed SQLite row reports killed == 1 during polling Conversation ID, status, step count
6. Timeout Conversation exceeds 3600s (1 hour) execution window Conversation ID & elapsed limit

Why Official Gmail API Over Local MTA (exim4)?

Local /usr/sbin/exim4 on dell5040 is configured with dc_eximconfig_configtype='local' (rejecting external domains with R: nonlocal for masonwan@gmail.com). Instead of storing plaintext SMTP App Passwords in /etc/exim4/passwd.client, alerts use your persistent OAuth2 credential via gsuite.mjs:

Gmail API Metric Quota / Specification
Daily Sending Limit 500 recipients / day (Personal @gmail.com)
Throughput Rate Limit 250 quota units / user / sec (messages.send = 100 units $\rightarrow$ 2.5/sec)
Token Caching Atomic POSIX 0600 cache in /tmp/gsuite_access_token.json (~315ms latency)
Endpoint POST https://gmail.googleapis.com/gmail/v1/users/me/messages/send

5. Filesystem & Component Reference Map

System & User Paths

Directory Hierarchy

/home/mason/
├── .local/bin/
│   ├── agy                                # Core Antigravity CLI & daemon binary
│   └── agy-agentapi-run                   # Dynamic port/CSRF bridge & Gmail alert engine
├── .config/systemd/user/
│   ├── antigravity-cli-daemon.service     # Long-running agy remote-control serve daemon
│   ├── sidecar-*.timer                    # 6 systemd calendar timers
│   └── sidecar-*.service                  # 6 systemd oneshot trigger services
├── .gemini/
│   ├── config/
│   │   ├── config.json                    # Master sidecar enable/disable registry
│   │   ├── sidecars/<id>/sidecar.json     # 7 declarative sidecar definitions
│   │   └── skills/gsuite/scripts/gsuite.mjs # Authenticated Gmail API OAuth2 client
│   └── antigravity-cli/
│       ├── bin/agentapi                   # CLI wrapper invoking `agy agentapi`
│       ├── conversation_summaries.db      # SQLite WAL trajectory state database
│       ├── brain/<conv-id>/               # Conversation transcripts & artifacts
│       └── sidecar_data/<id>/logs/        # Sidecar execution & Web UI logs
└── /run/user/1000/                        # tmpfs volatile runtime cache
    ├── agy_ls_address                     # Verified Language Server 127.0.0.1:<port>
    └── agy_csrf_token                     # Extracted daemon CSRF UUID token

Common Operations Cheat Sheet

# 1. List all sidecar timers & next trigger times
systemctl --user list-timers "*sidecar*" --no-pager

# 2. Check status of all sidecar services
systemctl --user list-units "*sidecar*" --all --no-pager

# 3. Trigger a specific sidecar immediately in background
systemctl --user start --no-block sidecar-daily-digest.service

# 4. Follow live execution logs of a sidecar run
journalctl --user -u sidecar-daily-digest.service -f

# 5. Inspect current dynamically cached LS port & CSRF token
cat /run/user/1000/agy_ls_address && echo ""
cat /run/user/1000/agy_csrf_token && echo ""

# 6. Verify Gmail API health & latency
node ~/.gemini/config/skills/gsuite/scripts/gsuite.mjs doctor