Summary
When the built-in Antigravity SDK harness runs via ax harness antigravity (the path used by the substrate ActorTemplate), the Python sidecar is launched with only --host/--port and no --state-dir. AX therefore does not explicitly own the per-conversation trajectory (save_dir) path in this path — it relies on the sidecar's own built-in default. The local path and the Interactions harness both pass the state dir explicitly; the SDK substrate path is the odd one out.
Background: how save_dir is derived
The sidecar derives per-conversation save_dir from its state_dir base:
python/antigravity/harness_server.py:210 — overrides["save_dir"] = str(self._state_dir / conversation_id)
state_dir comes from the --state-dir CLI arg (harness_server.py:484), defaulting to ~/.ax/antigravity/conversations (harness_server.py:485).
- SDK-native resume then scans
{save_dir}/*.db (_existing_sdk_conv_id, harness_server.py:155-159).
So whoever launches the sidecar should pass --state-dir to explicitly control trajectory storage.
The gap
Local path (correct): cmd/ax/internal/cliutil/cliutil.go:94-98 derives antigravity.DefaultStateDir() and passes it into antigravity.New, which forwards it to the sidecar as --state-dir (internal/harness/antigravity/antigravity.go:82-84).
Substrate path (missing): cmd/ax/harness.go runAntigravityHarness builds the sidecar args with only --host and --port:
cfg := pythonsidecar.Config{
Module: "python.antigravity.harness_server",
Args: []string{
"--host", harnessHost,
"--port", strconv.Itoa(harnessPort),
},
...
}
Reference implementation: the sibling runAntigravityInteractionsHarness (cmd/ax/harness.go) derives antigravityinteractions.DefaultStateDir() and passes it into the harness config, with the comment "AX owns the resume-cursor path ... derived internally". The SDK harness should do the equivalent.
Why it matters (correctness / robustness, not a currently-broken path)
Note: today the container runs as root (no USER in cmd/ax/Dockerfile), so the Go DefaultStateDir() (os.UserHomeDir()/.ax/...) and the Python sidecar default (pathlib.Path.home()/.ax/...) both resolve to the same /root/.ax/antigravity/conversations. So on the default image the missing flag does not currently point trajectories at a different location.
The problem is that this correctness depends on the Go and Python sides coincidentally computing the same default:
- If the sidecar's built-in default changes, or the image adds a non-root
USER (different HOME), or AX_HARNESS_WORKDIR/env differs between the launcher and the sidecar, the two sides silently diverge and SDK-native resume (which relies on {save_dir}/*.db) can break across actor Run/Restore and snapshotting.
- AX should own the path explicitly rather than rely on this implicit agreement — matching the local path and the Interactions harness.
Proposed fix
In runAntigravityHarness (cmd/ax/harness.go), derive the state dir via antigravity.DefaultStateDir() and pass it to the sidecar as --state-dir, mirroring the local path and runAntigravityInteractionsHarness. Fixed in #322.
Surfaced during the v0.2.0 verification pass (tracking: #299).
Summary
When the built-in Antigravity SDK harness runs via
ax harness antigravity(the path used by the substrate ActorTemplate), the Python sidecar is launched with only--host/--portand no--state-dir. AX therefore does not explicitly own the per-conversation trajectory (save_dir) path in this path — it relies on the sidecar's own built-in default. The local path and the Interactions harness both pass the state dir explicitly; the SDK substrate path is the odd one out.Background: how
save_diris derivedThe sidecar derives per-conversation
save_dirfrom itsstate_dirbase:python/antigravity/harness_server.py:210—overrides["save_dir"] = str(self._state_dir / conversation_id)state_dircomes from the--state-dirCLI arg (harness_server.py:484), defaulting to~/.ax/antigravity/conversations(harness_server.py:485).{save_dir}/*.db(_existing_sdk_conv_id,harness_server.py:155-159).So whoever launches the sidecar should pass
--state-dirto explicitly control trajectory storage.The gap
Local path (correct):
cmd/ax/internal/cliutil/cliutil.go:94-98derivesantigravity.DefaultStateDir()and passes it intoantigravity.New, which forwards it to the sidecar as--state-dir(internal/harness/antigravity/antigravity.go:82-84).Substrate path (missing):
cmd/ax/harness.gorunAntigravityHarnessbuilds the sidecar args with only--hostand--port:Reference implementation: the sibling
runAntigravityInteractionsHarness(cmd/ax/harness.go) derivesantigravityinteractions.DefaultStateDir()and passes it into the harness config, with the comment "AX owns the resume-cursor path ... derived internally". The SDK harness should do the equivalent.Why it matters (correctness / robustness, not a currently-broken path)
Note: today the container runs as root (no
USERincmd/ax/Dockerfile), so the GoDefaultStateDir()(os.UserHomeDir()/.ax/...) and the Python sidecar default (pathlib.Path.home()/.ax/...) both resolve to the same/root/.ax/antigravity/conversations. So on the default image the missing flag does not currently point trajectories at a different location.The problem is that this correctness depends on the Go and Python sides coincidentally computing the same default:
USER(differentHOME), orAX_HARNESS_WORKDIR/env differs between the launcher and the sidecar, the two sides silently diverge and SDK-native resume (which relies on{save_dir}/*.db) can break across actor Run/Restore and snapshotting.Proposed fix
In
runAntigravityHarness(cmd/ax/harness.go), derive the state dir viaantigravity.DefaultStateDir()and pass it to the sidecar as--state-dir, mirroring the local path andrunAntigravityInteractionsHarness. Fixed in #322.Surfaced during the v0.2.0 verification pass (tracking: #299).