ANTIGRAVITY LABJP
Articles/Antigravity Basics
Antigravity Basics/2026-05-25Intermediate

Why Antigravity Agents Hang on ssh, sudo, and git rebase -i — Diagnosing and Permanently Fixing the Missing TTY Problem

When you ask an Antigravity agent to deploy, the terminal panel stops on 'password:' and never moves. The agent isn't broken — the shell behind it has no PTY, so interactive prompts have no one to answer them. Here's how to diagnose and remove every interactive command from your agent workflow.

antigravity429agent17terminal4ttysshsudotroubleshooting105

You hand the Antigravity agent a simple deploy task, and forty seconds later the terminal output is frozen on a single line: password:. Two minutes pass. The agent isn't crashed; it's politely blocked on read(0, ...), waiting for a stdin that doesn't exist. I've watched this exact failure mode happen twenty-plus times over the past six months, mostly while running the four Dolice Labs sites in parallel inside one Antigravity workspace.

The root cause is almost always the same: the agent's terminal sessions do not allocate a pseudo-terminal (PTY), so any command that uses isatty(0) to decide whether to prompt the user ends up waiting forever for someone who isn't there. I'm Masaki Hirokawa — an indie developer who's been shipping wallpaper apps since 2014 with around 50 million downloads across the catalog — and silent agents waste more of my engineering time than any other single failure mode in modern AI tooling. This article walks through why the failure happens and the permanent guards I've baked into every project's AGENTS.md.

Why sudo and ssh actually freeze inside the agent shell

A normal terminal allocates a PTY at startup. If you run tty and see /dev/ttys000, you have one. Commands like sudo, ssh, and git rebase -i call isatty(0) to ask: "is my stdin connected to a terminal?" If yes, they show password prompts, launch editors, or render full-screen UIs. If no, they fall back to one of three failure modes.

The Antigravity agent's terminal looks like a real shell, but under the hood it's a JSON-RPC stream wired into the agent's tool layer. There's no PTY, or the PTY exists but the agent doesn't hook stdin, so isatty(0) returns false. From the command's perspective, you're asking it to read from a pipe with no writer attached.

  • sudo: Without a TTY, it either dies immediately with sudo: a terminal is required to read the password, or — depending on the PAM config — quietly blocks until something kills it.
  • ssh: Password authentication paths fail with Permission denied (publickey,password). Worse, ssh user@host some-command often emits the warning Pseudo-terminal will not be allocated because stdin is not a terminal. and then sits there if the remote shell expects input.
  • git rebase -i: Launches the editor named in core.editor (usually vi or nano), but with no PTY it can't paint anything to the screen, and the agent simply reports "no output for a long time."

In every case the command is behaving correctly; it just has no one to talk to.

Diagnose: is this really a TTY problem?

My rule of thumb after six months of debugging these freezes: any agent terminal that goes silent for more than thirty seconds gets a TTY check before anything else. Ask the agent to run two short commands and the answer is unambiguous.

# Is this shell actually attached to a PTY?
tty
# Expected (good): /dev/ttys003 or similar
# Expected (bad):  "not a tty"
 
# What is the most recent interactive command holding the slot?
ps -ef | grep -E "(sudo|ssh|vi|nano|git rebase)" | grep -v grep
# STAT = "S+" or "Ss+" means foreground, waiting for stdin
# STAT = "T" means stopped (SIGTSTP)
# STAT = "Z" means zombie — different problem

If tty reports not a tty, every other interactive command you launch from this shell will hit the same wall. Don't blame the agent — fix the command-side assumption that someone is sitting in front of the keyboard.

Fix 1: stop asking for sudo passwords in the first place

The sudo freezes I see in the wild are nine times out of ten caused by missing NOPASSWD rules. Designing your agent workflow around "type the password every time" is structurally broken. Treat the local dev box like a CI runner — give the agent a service-account-style sudoers entry that whitelists only the commands it actually needs.

# /etc/sudoers.d/antigravity-agent  (created as root)
# Whitelist just the commands the agent will run on your behalf
cat << 'EOF' | sudo tee /etc/sudoers.d/antigravity-agent
# Antigravity agent — narrowed to operational helpers only
%admin ALL=(ALL) NOPASSWD: /usr/bin/lsof, /usr/bin/kill, /usr/sbin/nginx -s reload
EOF
sudo chmod 0440 /etc/sudoers.d/antigravity-agent
 
# Syntax-check the file before logging out
sudo visudo -c -f /etc/sudoers.d/antigravity-agent
# Expected output: /etc/sudoers.d/antigravity-agent: parsed OK

The important word is "whitelist." Never reach for NOPASSWD: ALL. If the agent's autonomy ever decides rm -rf / is a reasonable cleanup step, you want sudo to still ask for a password and time out. I keep per-site sudoers fragments under _documents/sudoers/ so I can audit exactly what each project's agent is allowed to escalate.

Fix 2: make SSH non-interactive with BatchMode and key-only auth

Defending against ssh freezes means removing the possibility of an interactive prompt entirely. The flag for this is BatchMode=yes, which tells SSH "if you would have prompted the user, fail instead."

# ~/.ssh/config — add a deploy-target entry the agent can use by alias
cat << 'EOF' >> ~/.ssh/config
 
Host antigravity-deploy
    HostName deploy.example.internal
    User deploy
    IdentityFile ~/.ssh/keys/deploy_ed25519
    IdentitiesOnly yes
    BatchMode yes
    StrictHostKeyChecking accept-new
    ServerAliveInterval 30
    ServerAliveCountMax 3
EOF
chmod 600 ~/.ssh/config

BatchMode yes means a rejected key terminates the SSH process deterministically — no password: prompt that goes nowhere. StrictHostKeyChecking accept-new automates the first-time fingerprint exchange while still refusing connections to hosts that have changed keys, so you don't sacrifice safety to get rid of the prompt.

ServerAliveInterval 30 is there because Antigravity agents often hold long-lived SSH tunnels to watch deploys. Without keepalives, a NAT session somewhere between you and the deploy host eventually expires, and the tunnel becomes a zombie that the agent will wait on indefinitely.

Fix 3: replace interactive git operations with scripted ones

git rebase -i is the single most common command I've seen Antigravity agents hang on. The trick is to skip the editor entirely by feeding GIT_SEQUENCE_EDITOR a non-interactive script that rewrites the todo list for you.

# Squash the last 5 commits into one — fully scripted, no editor needed
GIT_SEQUENCE_EDITOR='sed -i -e "2,\$s/^pick/squash/"' \
GIT_EDITOR=true \
git rebase -i HEAD~5
# Expected output: Successfully rebased and updated refs/heads/<branch>.

GIT_EDITOR=true makes the squashed-message editor step run the true binary, which exits cleanly without modifying the file — so Git keeps the concatenated commit messages exactly as Git itself proposed them. I use this combo as a pre-merge cleanup step across all four Dolice Labs repos.

The other classic freeze, git commit launching the editor, has an embarrassingly simple fix: require -m "..." on every commit the agent makes. Write that rule into AGENTS.md once and the agent will respect it.

Fix 4: codify a "no interactive commands" rule in AGENTS.md

The fixes above only stick if the agent knows about them on every new project. The AGENTS.md at the repo root is where I make these rules explicit. After adding this section across all four Dolice Labs repos, the rate of silent-agent incidents dropped by roughly 80% in my own logs.

# Terminal rules (shared with the agent)
 
## Forbidden: commands that can produce an interactive prompt
- `sudo` with a password prompt (only NOPASSWD-whitelisted commands are allowed)
- `ssh user@host` (always use the alias from ~/.ssh/config)
- `git rebase -i` (must pass GIT_SEQUENCE_EDITOR)
- `git commit` (always pass `-m`; never let the editor open)
- `npm init` / `pnpm init` (always pass `-y`)
- `apt install` / `apt remove` (always pass `-y`)
 
## Required: env vars that suppress interactive UIs
Source these in the project's `.envrc`:
 
    export DEBIAN_FRONTEND=noninteractive
    export CI=true
    export GIT_TERMINAL_PROMPT=0
    export NPM_CONFIG_YES=true
 
## If a command is silent for more than 30 seconds
Send SIGTERM, then report the output of `tty` and `ps -ef`.
Never escalate to `kill -9` without human confirmation.

The CI=true line does a surprising amount of heavy lifting. Many modern CLIs (Vercel, Cloudflare Wrangler, Stripe CLI, plenty more) check that variable and silently switch off interactive features. The Antigravity agent shell isn't technically CI, but it shares the same constraint: nothing on the other end is going to type anything.

Fix 5: when interactivity is unavoidable, script it with expect

Some legacy tools insist on walking you through a wizard the first time you run them. The escape hatch is expect, which lets you fully script the prompt-and-answer dance and hand the agent a single deterministic script to invoke.

# Example: a legacy tool that asks Y/n three times on first launch
cat << 'EOF' > /tmp/setup.expect
#!/usr/bin/env expect -f
set timeout 60
spawn legacy-tool --init
expect "Continue? \[Y/n\]"
send "y\r"
expect "Overwrite config? \[Y/n\]"
send "y\r"
expect "Enable telemetry? \[Y/n\]"
send "n\r"
expect eof
EOF
chmod +x /tmp/setup.expect
/tmp/setup.expect
# Expected output: the tool's normal completion message

expect ships in the standard package set for Linux and macOS, and the Antigravity agent terminal can invoke it without any special setup. The prompt strings are fragile — if the upstream tool changes wording, the script breaks — but as a last resort for un-CI-able tooling it's invaluable.

Quick recovery playbook for when the agent is already stuck

The final piece is the recovery flow itself. When I notice the agent has gone quiet, I paste this short playbook into the chat and let the agent execute it. Most "silent agent" incidents resolve in under a minute.

# 1. Find the foreground process that's holding the shell hostage
ps -ef | grep -E "(sudo|ssh|vi|nano|git)" | grep -v grep
 
# 2. Ask it to exit gracefully first
PID=<from the previous output>
kill -15 $PID
 
# 3. Escalate if needed: SIGINT, then SIGKILL as a last resort
sleep 5 && kill -2 $PID 2>/dev/null
sleep 5 && kill -9 $PID 2>/dev/null
 
# 4. Re-check the PTY state before issuing the next command
tty

Pair that recovery flow with a one-line entry in AGENTS.md describing what tripped the freeze, and you stop paying the same tax twice. Running four sites alone, those small documentation deltas are the difference between maintainable automation and a workflow that quietly bleeds an hour a week to silent waits.

If even one of these guards saves you a midnight debugging session, I'll consider this article well spent. Thanks for reading.

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Antigravity2026-05-23
Why Antigravity's AI Agent Misreads .env Values — Quoting, Whitespace, and Export Pitfalls
When Antigravity's agent writes or reads .env files, subtle differences in quoting, trailing whitespace, export prefixes, and # characters cause silent value corruption. Here are four real cases I hit in production, with concrete diagnostics and fixes.
Antigravity2026-04-24
When Antigravity's Built-in Terminal Won't Start or Commands Fail: A Layered Diagnostic Guide
When the Antigravity terminal panel won't open, stays unresponsive, or can't find your commands, the fix depends on which layer actually broke. This guide splits the symptoms into three patterns and walks through each recovery path.
Antigravity2026-05-31
Why Your Antigravity Agent Stops Mid-Task with 429 RESOURCE_EXHAUSTED, and How to Fix It
When you hand a long task to an Antigravity agent, it sometimes halts halfway with a red 429 RESOURCE_EXHAUSTED. That is a rate-limit or quota signal, not a bug. Here is how I diagnose the three flavors of 429 in production, and how to keep your agent from stalling on the same wall twice.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →