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.
ss -tlpn + gRPC Handshake Probegsuite.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 PortsWhy 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 actualagentapi get-conversation-metadata probe-testhandshake to verify a genuine gRPC response. -
3
Self-Healing Cache Invalidation
Cached addresses in
/run/user/1000/agy_ls_addressare probed before every run. If the daemon restarted and changed ports, the stale cache file is immediately purged and re-discovered viass -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:
ExecStart Command:
|
||||
|
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
|
|
Files & Units:
ExecStart Command:
|
||||
|
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:
ExecStart Command:
|
||||
|
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:
ExecStart Command:
|
||||
|
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:
ExecStart Command:
|
||||
|
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:
ExecStart Command:
|
||||
|
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:
Runtime Environment Provided by Antigravity:
|
||||
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 PathsDirectory 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