Skip to content

Agent architecture

Astrolift's agent support is part of the main control plane. It is not a separate product or a set of optional Django applications. Agent definitions, skills, environment recipes, tasks, workflows, secrets, and dispatch records share the platform's organization, project, permission, and audit boundaries.

This page describes the code that runs today. The public CLI and API reference remain the source of truth for command syntax and wire contracts.

The objects that make up an agent

An agent is assembled from several independently managed objects:

Object Purpose
RegisteredApp + Workload(kind="agent") Registered agent identity, source repository, image, run policy, and deployment metadata
AgentEnvironmentSpec Reusable image/runtime recipe, tool preset, install policy, VNC choice, managed-model choice, environment variables, and secret references
Skill Versioned instructions and dependency metadata; global skills are readable by every organization and organization skills remain tenant-scoped
ToolDef Callable tool metadata for a skill: Python function, HTTP endpoint, or MCP server
Brief Immutable, content-hashed snapshot assembled for one definition or dispatch
AgentTask One dispatch and its lifecycle, runtime location, callback identity, result, failure, and telemetry pointers
AgentRun Fleet/run history associated with a workload; newer dispatches link it directly to their AgentTask
DispatcherInstance Registered execution endpoint and its cloud, region, backend, capabilities, and heartbeat

This split is intentional. Updating a skill or environment recipe does not rewrite historical tasks: a task uses a frozen Brief and stores the environment recipe and source reference selected for that run.

Repository definitions

The ordinary source of an agent definition is astrolift.toml. A repository may contain one agent at its root or many independently registered agents below different paths. An environment spec's config_manifest_path selects either a particular manifest or a directory whose astrolift.toml is authoritative.

Registration turns an agent workload into database objects and resolves its skill and tool references. Repository-owned files may supply prompts, scripts, and other assets without pasting them into a single TOML string; path resolution is constrained to the selected manifest tree. Imported skill repositories are represented by OrgSkillRepo and use a source connection for private GitHub access.

The declarative manifest is the desired configuration. Secret values are not declarative repository content. Manifests and environment specs contain secret references; the dispatcher resolves values at launch.

Brief assembly

A Brief is the hand-off between definition and execution. Assembly combines:

  • the registered workload and source manifest snapshot;
  • resolved environment variables and dispatch input;
  • selected skills and their versions;
  • tool definitions and install metadata;
  • secret references, never plaintext secret values; and
  • organization, project, workflow, and source context.

The canonical JSON payload is SHA-256 addressed and stored under an object-store key. A READY Brief can therefore be reused when its content is identical. A change creates a new Brief rather than mutating the package used by an existing task. Briefs can also expire or be revoked.

Dispatch lifecycle

The platform creates an AgentTask, prepares its Brief, and starts a durable Temporal dispatch workflow. Its states are:

DRAFT -> QUEUED -> PROVISIONING -> RUNNING
  |        |            |            |
  +--------+------------+------------+-> CANCELLED
           +------------+------------+-> FAILED
                        +------------+-> TIMED_OUT
                                     +-> COMPLETED

The managed Kubernetes path creates a per-dispatch Job in an organization namespace. It resolves the target tenant cluster, materializes launch secrets in a Kubernetes Secret, injects task and callback metadata, and polls the Job until a terminal state. The terminal path cleans up the per-task secret. A configured timeout becomes the Job's activeDeadlineSeconds as well as a control-plane timeout.

Cancellation is an execution operation, not merely a database update. For a provisioning or running Kubernetes task, Astrolift deletes the Job and its pod before marking the task cancelled. Operators can use astro agent cancel for runaway tasks; see the operator runbooks.

K8sJobSpawner is the managed production spawner. A local Docker spawner also exists for development. DispatcherInstance and the /api/dispatch/v1/ controller endpoints support registered external dispatch processes, but the managed Temporal activity currently selects the Kubernetes Job spawner for cluster-backed tasks. Do not infer that every backend value on DispatcherInstance is implemented by that managed activity.

Container contract and callbacks

The injector supplies the task's runtime contract, including task/organization identity, input, prompt and Brief context. A valid externally reachable PLATFORM_API_URL is required to construct:

  • AGENT_CALLBACK_URL;
  • AGENT_CALLBACK_TOKEN; and
  • the log, meter, and check-in endpoints used by the running container.

The callback token is short-lived and task-scoped; only its SHA-256 hash is stored. A terminal transition clears that hash. The agent callback endpoint persists the result and interactions and then advances the task. Tooling must not report a callback as successful if no callback URL was injected; that is a configuration failure, not a successful no-op.

The controller REST surface is mounted by the main Django application at /api/dispatch/v1/. It may be used by a separately deployed dispatcher, but it does not require a separate control-plane service in the standard deployment.

Logs, terminal, and VNC

Kubernetes pod stdout/stderr is the source used by astro agent logs. A terminal or noVNC session is a separate stream. An image that directs only its Xvnc supervisor to stdout can therefore show Xvnc messages in pod logs while an attached terminal displays application output. Agent images should send the actual runtime's stdout and stderr to the container streams as well as any interactive terminal.

When an environment recipe enables VNC, the task records a relay URL after it enters RUNNING. The ASGI application relays raw RFB traffic at /app/vnc/<task-guid> and can expose the latest uploaded JPEG snapshot. The old HTTP/WSGI VNC proxy no longer exists.

Environments, tools, and managed models

AgentEnvironmentSpec.image_tag takes precedence over its runtime catalogue name. When no explicit image is supplied, the runtime catalogue resolves a canonical Astrolift agent image; an empty runtime falls back to the workload's image.

The recipe also controls tool_preset, allow_install, VNC, and managed_model. These fields are launch inputs, not documentation-only metadata. Tool definitions can bind to specific agent runtimes, declare command and package requirements, and indicate whether they are already in the image. Install-at-run behavior still depends on the selected image and policy; allowing installation does not grant arbitrary platform permissions.

With managed_model=true, the cluster driver supplies cloud-native model identity and provider environment instead of requiring a long-lived model API key. AWS uses Bedrock and GCP uses Vertex. Model identifiers should remain operator-configurable because cloud providers can retire models independently of IAM policy changes.

Secrets

There are three related layers:

  1. an organization/app secret value in a configured secrets backend;
  2. a reference or bundle attached to an agent/environment; and
  3. the short-lived Kubernetes Secret materialized for a task.

Secret access is permission-checked and API-token scopes are an additional ceiling over a user's RBAC grants. Being an organization administrator does not make a read-only device token capable of secret.write or agent.dispatch. Use a token carrying the required narrow scope, and remember that revealing a value also depends on the backing provider's reveal capability.

Agent workflows

WorkflowDefinition is the reusable workflow template and WorkflowStage is its ordered execution plan. Agent pipelines normally leave model_label blank: that field is a legacy Django content-object target, not an LLM model or an agent selector.

For an agent stage:

  • agent selects the registered agent workload by local slug;
  • environment_spec_slug optionally overrides the agent's environment recipe;
  • skills adds local, catalogue, or organization-repository skill references;
  • prompt adds instructions for this stage; and
  • output_key names the stage result in the workflow's accumulated output map.

Ordered stages are the executable pipeline. The legacy states and transitions JSON fields still serve content-object state machines; they do not need to be invented for a declarative agent pipeline. A chained workflow passes each stage's result into the next stage and also stores it under the unique output_key. Human-gate stages pause the Temporal workflow until approval or rejection.

Workflow manifests use a [workflow] table followed by ordered [[stage]] tables. They can be bundled in Astrolift's catalogue or reconciled from a connected repository. See the generated CLI/config reference for the exact schema accepted by the installed release.

Tenant and trust boundaries

  • Definitions, environment recipes, tasks, dispatchers, secret bindings, and organization skills are organization-scoped.
  • Platform-global skills and workflow templates are readable by tenants but writable only by platform operators.
  • Dispatch lookup verifies workload kind, run family, organization, and permissions before preparing a task.
  • Repository sync is bound to the connected source identity and configured path.
  • Callback, deploy, API, and MCP tokens each have explicit scopes. A bearer token never inherits permissions outside its own scope ceiling.
  • Values stay in a secrets backend until launch and are not persisted in a Brief or repository manifest.

These boundaries must hold on every entry point: dashboard, CLI, GraphQL, REST, MCP, webhooks, schedulers, and workflow activities.