Make Task manifests fully immutable once created, removing `UpdateTask`
in favor of `CreateTask` and driving lifecycle transitions (suspend,
resume, delete) through dedicated RPCs and event stream processing.
- Proto: Replace `UpdateTask` with `CreateTask` in AX service.
- Proto: Remove mutable `suspend` field from `TaskSpec` and reserve field 2.
- API / Server: Implement `CreateTask` with duplicate name rejection
(`codes.AlreadyExists`). Update `SuspendTask`, `ResumeTask`, and `DeleteTask`
to transition status phase and publish lifecycle events.
- Store: Remove redundant `SetTaskSuspended` and `MarkTaskDeleting` methods;
standardize on `CreateTask`, `UpdateTaskStatus`, `DeleteTask`, and
`PublishEvent`.
- Controller: Decouple spec reconciliation from task suspension; introduce
`ReconcileSuspend` to handle checkpointing and pausing actors on Substrate.
- CLI: Update `ax apply` to submit tasks via `CreateTask`.
- Docs: Update design docs and specifications to reflect task immutability.
AX is undergoing a significant redesign, moving away from a single CLI with
an embedded Python harness toward a general-purpose orchestration layer for
agentic tasks. The repository is reorganized around three binaries: ax-server
exposes a gRPC API for submitting Task manifests, ax-controller runs as a
horizontally scaled reconciler that consumes work from Redis Streams, and
ax-task-runner executes tasks inside sandboxed workers. Task state now lives
in Redis rather than Kubernetes CRDs so the system can handle millions of
short-lived tasks without straining etcd. The legacy Python harness, ATE
client, SQL event log, and skill examples are removed, and new design,
concepts, manifest, networking, runner, and sandbox docs plus Kubernetes
deploy manifests describe the new architecture.
We want AX to be compatible with the Interactions API protocol as much as possible. This PR aligns the proto with Steps and with the Interactions semantics. We will follow up with more changes to make it more compatible with Interactions while preserving a `conversation_id` based history model.
`ConversationService` is removed for now until we know what kind of data operations we want to provide for event log management.
Introduce a local skills source parallel to the Gemini Enterprise Skill
Registry integration. A local source points at a directory already on disk
(a parent dir holding <skill-id>/SKILL.md subfolders, the same layout as
examples/skills and a registry's target_dir); nothing is fetched and the
directory is used as-is.
- New mode-agnostic result shape (internal/skills: Available/Group/Skill) so
both sources feed the same consumers without either depending on the other.
- internal/skills/local.Discover enumerates enabled local paths, treating
immediate subfolders with a SKILL.md as skills (subfolder name = id). It is
fail-safe like registry materialization: a missing/unreadable/empty path is
logged and skipped, never blocking harness creation.
- config.SkillsConfig gains Local []LocalSkillsConfig (enabled + path) with
validation; geminienterprise.Materialize now returns skills.Available.
- cliutil combines registry and local groups into one system-instruction
pointer for the Antigravity Interactions harness. The Antigravity SDK
harness (SKILLS_DIR-based) is left as a TODO.
Only the interactions harness is wired; tests cover discovery, fail-safe
degradation, config validation, and the examples/skills fixture.
google-antigravity 0.1.7's _connect_websocket retries both "localhost"
and "127.0.0.1" when dialing localharness (local_connection.py:993), so
the sidecar no longer needs to patch /etc/hosts for substrate/gVisor
environments where localhost may not resolve.
Ref #325
antigravity: guard conversation_id for safe save_dir use (#312)
harness_server uses the caller-supplied conversation_id directly as a
per-conversation storage directory name (save_dir = state_dir /
conversation_id) before the Antigravity harness ever sees it, so a value
like "../escape" could traverse outside state_dir. Reject an empty id or
one containing a path separator or a "." / ".." component at the boundary
in _run_turn, returning an INVALID_ARGUMENT end frame.
This is intentionally only a path-safety guard, not the id-format
contract. The Antigravity harness owns that: it validates the forwarded
cascade_id (length and character set) per cl/948016352. Keeping the
format rule in one place avoids the two layers drifting.
chore: remove stale docs, gitignore, and Makefile entries (#329)
- CONTRIBUTING.md: drop 'make run-remote' (no such Makefile target)
- .gitignore: remove orphaned entries (local/remote_agent, sandbox-router,
tasklog, axepp, google-cloud-sdk, test-sandbox-config.yaml)
- Makefile: add missing deps, clean-logs to .PHONY
antigravity: remove vertex env-var override (superseded by AGY 0.1.7) (#331)
* antigravity: remove vertex env-var override (superseded by AGY 0.1.7)
google-antigravity 0.1.7 reads GOOGLE_GENAI_USE_VERTEXAI /
GOOGLE_GENAI_USE_ENTERPRISE + GOOGLE_CLOUD_{PROJECT,LOCATION} natively,
so the sidecar no longer needs _vertex_kwargs_from_env to thread them
into LocalAgentConfig.
- Delete _vertex_kwargs_from_env + VertexKwargs.
- _build_default_config: bare LocalAgentConfig(system_instructions=...).
- _has_credentials: read project/location from env (SDK hydrates them
onto VertexEndpoint, not LocalAgentConfig).
- Update tests accordingly.
Requires the 0.1.7 bump. Credential resolution is startup-only and
does not touch the save_dir/state_dir resume path.
Ref #325
* antigravity: drop stale _has_credentials docstring note about vertex env override
Interactions: persist interactions harness with durable dir and resume from it (#327)
interactions: make WorkDir authoritative for run_command (#335)
The interactions harness executed run_command relative to the process's
ambient working directory, which is not reliably the agent's workspace: with
no Cwd argument the command ran wherever the process cwd happened to be, and a
model-supplied Cwd (including "/") was honored blindly. As a result tool calls
often ran from "/" instead of the configured workspace (#332).
Make the workspace directory authoritative in the executor rather than relying
on ambient process state:
- Add AntigravityInteractionsConfig.WorkDir (defaults from AX_HARNESS_WORKDIR).
- run_command now resolves its directory via resolveRunDir: no Cwd -> WorkDir;
relative Cwd -> joined under WorkDir; absolute Cwd -> honored as-is. Empty
WorkDir preserves the previous process-cwd behavior.
- Add WorkspaceSystemInstruction to orient the agent about its working
directory so it emits workspace-relative paths, and wire it in cmd/ax.
Fixes#332
Remove the binary (#334)
* Remove the binary
* chore: add e2e directory to .gitignore
* refactor: migrate binary file check to a dedicated workflow file
* fix: restrict binary file check to added, copied, or modified files
0.1.7 reads GenAI credential env vars natively. Bump first; the
sidecar override is removed in a follow-up (#325). Behavior unchanged
here since explicit override kwargs still take precedence.
Ref #325
runAntigravityHarness (the `ax harness antigravity` path used by the
substrate ActorTemplate) forked the Python sidecar with only --host/--port.
The sidecar then fell back to its own default state dir, so on a substrate
actor per-conversation save_dir landed on a path AX does not control, which
breaks SDK-native resume across actor Run/Restore and snapshotting.
Derive the trajectory dir via antigravity.DefaultStateDir() and pass it as
--state-dir, mirroring the local path in antigravity.New and the interactions
harness in runAntigravityInteractionsHarness (both own the path internally
rather than taking it from ax.yaml/ActorTemplate).
Fixes#321