Skip to content

Antigravity SDK harness on substrate relies on an implicit sidecar default for save_dir instead of passing --state-dir #321

Description

@joycel-github

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:210overrides["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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions