stax
Normative reference

Agent Manifest

Root manifest and compiled config blob

Overview

The agent manifest is the root definition of an agent artifact. It declares identity, optional layer sources, runtime hints, package dependencies, secret requirements, optional workspace source dependencies, optional subagent and instruction-tree sources, and the adapter used to materialize or import the artifact for a target consumer environment.

Agents are authored in TypeScript using defineAgent() and compiled to JSON for the OCI config blob.

Source file

A project MUST contain exactly one root agent definition file, typically agent.ts.

All relative paths in the agent definition are resolved relative to the directory containing agent.ts.

Resolved paths MUST remain within the project root unless the builder is explicitly run with an escape hatch such as --allow-outside-root.

Path resolution rules:

  • Builders MUST resolve symlinks before checking containment. If the resolved target is outside the project root, the builder MUST reject the path.
  • Paths containing .. segments MUST be normalized before containment checking. A path that escapes the project root after normalization MUST be rejected.
  • --allow-outside-root MUST NOT be the default. Builders SHOULD warn prominently when this flag is used.
  • Builders SHOULD default to --symlink-mode reject. Builders MAY support --symlink-mode flatten for selected directory-backed layers as defined in 03 — Layers.

defineAgent()

import { defineAgent } from "stax";
import claudeCode from "@stax/claude-code";

export default defineAgent({
  name: "backend-engineer",
  version: "3.1.0",
  description: "Senior backend engineer with Go and distributed systems expertise.",
  author: "myorg",
  license: "MIT",
  tags: ["code-review", "architecture", "golang"],
  url: "https://github.com/myorg/backend-engineer",

  adapter: claudeCode({
    model: "claude-opus-4-1",
    modelParams: { temperature: 0.3 },
  }),
  adapterFallback: [
    {
      type: "generic",
      runtime: "generic",
      adapterVersion: "1.0.0",
      model: "any-model-id",
      config: {},
      features: {},
    },
  ],

  persona: "./personas/maya-chen.ts",
  prompt: "./SYSTEM_PROMPT.md",
  mcp: "./mcp-servers.ts",
  skills: "./skills/",
  rules: "./rules/",
  knowledge: "./knowledge/",
  memory: "./memory/",
  surfaces: "./surfaces/",
  instructionTree: "./instruction-tree/",
  subagents: "./subagents.ts",

  hints: {
    isolation: "microvm",
    capabilities: {
      shell: true,
      network: {
        mode: "restricted",
        allowlist: ["api.anthropic.com", "api.github.com"],
      },
      filesystem: {
        workspace: "/workspace",
        writable: ["/workspace"],
        denyRead: ["**/.env", "**/*credentials*"],
      },
    },
  },

  secrets: [
    { key: "ANTHROPIC_API_KEY", required: true, kind: "api-key" },
    { key: "GITHUB_TOKEN", required: true, kind: "token" },
    { key: "SLACK_WEBHOOK", required: false, kind: "url" },
  ],

  workspaceSources: [
    {
      id: "backend-repo",
      ref: "ghcr.io/myorg/sources/backend@sha256:abcdef123456...",
      mountPath: "/workspace/backend",
      writable: true,
      required: true,
    },
  ],

  packages: [
    "ghcr.io/myorg/packages/github-workflow:2.0.0",
    "ghcr.io/myorg/packages/org-standards@sha256:0123456789abcdef...",
    "./packages/local-team-overrides",
  ],
});

Type definitions

interface AgentDefinition {
  specVersion?: "1.0.0";

  // Identity
  name: string;
  version: string;
  description: string;
  author?: string;
  license?: string;
  url?: string;
  tags?: string[];

  // Adapter
  adapter: AdapterConfig;
  adapterFallback?: AdapterConfig[];

  // Source paths resolved at build time
  persona?: string;
  prompt?: string;
  mcp?: string;
  skills?: string;
  rules?: string;
  knowledge?: string;
  memory?: string;
  surfaces?: string;
  instructionTree?: string;
  subagents?: string;

  // Runtime hints
  hints?: RuntimeHints;

  // Secret declarations
  secrets?: SecretDeclaration[];

  // Shared workspace/source dependencies
  workspaceSources?: WorkspaceSourceReference[];

  // Package references
  packages?: PackageReference[];
}

interface RuntimeHints {
  isolation?: "process" | "container" | "gvisor" | "microvm";
  capabilities?: {
    shell?: boolean;
    processes?: boolean;
    docker?: boolean;
    network?: NetworkHint;
    filesystem?: FilesystemHint;
  };
}

interface NetworkHint {
  mode: "none" | "restricted" | "full";
  allowlist?: string[];
}

interface FilesystemHint {
  workspace?: string;
  writable?: string[];
  denyRead?: string[];
}

interface SecretDeclaration {
  key: string;
  required: boolean;
  description?: string;
  kind?: "api-key" | "token" | "password" | "certificate" | "connection-string" | "url" | "opaque";
  exposeAs?: { env?: string; file?: string };
}

type PackageReference = string;

interface WorkspaceSourceReference {
  id: string;
  ref: string; // OCI ref to a source artifact
  mountPath: string; // Where the consumer should materialize it
  writable?: boolean; // Default: false
  required?: boolean; // Default: true
  subpath?: string; // Optional subdirectory inside the source artifact
}

interface AdapterConfig {
  type: string; // Adapter identifier, e.g. "claude-code"
  runtime: string; // Runtime family, e.g. "claude-code"
  adapterVersion: string; // Adapter schema version
  runtimeVersionRange?: string; // Tested runtime-version range for exact claims
  model?: string;
  modelParams?: Record<string, unknown>;
  importMode?: "filesystem" | "api" | "bundle" | "object-map";
  fidelity?: "byte-exact" | "schema-exact" | "best-effort" | "unsupported";
  config: Record<string, unknown>;
  features: AdapterFeatureMap;
  targets?: MaterializationTarget[];
}

interface AdapterFeatureMap {
  prompt?: "native" | "embedded" | "unsupported";
  persona?: "native" | "embedded" | "unsupported";
  rules?: "native" | "embedded" | "unsupported";
  skills?: "native" | "unsupported";
  mcp?: "native" | "translated" | "unsupported";
  surfaces?: "native" | "translated" | "unsupported";
  secrets?: "native" | "consumer-only";
  toolPermissions?: "native" | "translated" | "unsupported";
  modelConfig?: "native" | "translated" | "unsupported";
  exactMode?: boolean;
}

interface MaterializationTarget {
  kind: "file" | "directory" | "setting" | "api" | "bundle" | "object";
  path: string;
  description?: string;
  scope?: "user" | "project" | "workspace" | "local" | "remote" | "account" | "organization";
  exact?: boolean;
  mediaType?: string;
}

Field validation

Identity

  • name MUST match ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
  • version MUST be valid semver
  • tags, if present, MUST contain unique case-sensitive strings

Paths

  • persona, prompt, mcp, and subagents MUST resolve to files
  • skills, rules, knowledge, memory, surfaces, and instructionTree MUST resolve to directories
  • Missing optional paths MUST be treated as validation errors if declared explicitly
  • Symlinks MUST be rejected by default. Builders MAY allow symlink flattening only when explicitly invoked with --symlink-mode flatten and only for the layers permitted by 03 — Layers.

Workspace sources

Each entry in workspaceSources MUST:

  • have a unique id
  • reference an OCI source artifact by digest or exact tag
  • specify an absolute mountPath
  • use a mountPath that does not collide with another workspace source entry

Consumers SHOULD cache workspace source artifacts by digest and SHOULD reuse the same cached source across many agents. See 22 — Workspace Sources.

Packages

Each entry in packages MUST be either:

  1. A relative local path beginning with ./ or ../
  2. An OCI reference with an explicit tag: <registry>/<repo>:<tag>
  3. An OCI digest reference: <registry>/<repo>@sha256:<digest>

Semver ranges, globs, and floating selectors such as ^1, ~2, or latest SHOULD NOT be used in committed manifests. Builders MAY allow them interactively, and lockfile-capable implementations SHOULD resolve them into stax.lock and warn.

Adapter fallback

adapterFallback provides alternate adapter configs in descending preference order.

Consumers MUST:

  1. Try the primary adapter. An adapter is compatible if the consumer supports its type, runtime, and adapterVersion major version.
  2. If the primary adapter is not compatible, try each adapterFallback entry in array order, stopping at the first compatible entry.
  3. Fail with exit code 5 (materialization compatibility error) if no adapter is compatible. The error message MUST list the attempted adapter types and versions.

Consumers MUST NOT select a fallback adapter if the primary adapter is compatible, even if the fallback would produce a "better" result.

Compiled config blob

The OCI config blob for an agent MUST use media type application/vnd.stax.config.v1+json and MUST contain canonical JSON with stable key ordering.

If surfaces or instructionTree are present, the config blob SHOULD record that fact so consumers can distinguish artifacts that support exact runtime file materialization from those that only provide a single prompt.

Canonical config example

{
  "specVersion": "1.0.0",
  "kind": "agent",
  "name": "backend-engineer",
  "version": "3.1.0",
  "description": "Senior backend engineer with Go and distributed systems expertise.",
  "author": "myorg",
  "license": "MIT",
  "url": "https://github.com/myorg/backend-engineer",
  "tags": ["code-review", "architecture", "golang"],
  "adapter": {
    "type": "claude-code",
    "runtime": "claude-code",
    "adapterVersion": "1.0.0",
    "model": "claude-opus-4-1",
    "modelParams": { "temperature": 0.3 },
    "config": {
      "permissions": {
        "allowedTools": ["Read", "Edit", "Bash", "Grep", "Write"]
      }
    },
    "features": {
      "prompt": "embedded",
      "persona": "embedded",
      "rules": "native",
      "skills": "native",
      "mcp": "translated",
      "secrets": "consumer-only",
      "toolPermissions": "native",
      "modelConfig": "native"
    }
  },
  "hints": {
    "isolation": "microvm",
    "capabilities": {
      "shell": true,
      "network": {
        "mode": "restricted",
        "allowlist": ["api.anthropic.com", "api.github.com"]
      }
    }
  },
  "workspaceSources": [
    {
      "id": "backend-repo",
      "ref": "ghcr.io/myorg/sources/backend@sha256:abcdef123456...",
      "mountPath": "/workspace/backend",
      "writable": true,
      "required": true
    }
  ],
  "packages": ["ghcr.io/myorg/packages/github-workflow:2.0.0"]
}

In vs out of scope

In the manifest

FieldWhy
Identity fieldsDefines what the artifact is
Adapter and fallbackDeclares intended runtimes
Layer paths, surfaces, instruction trees, and subagentsDefines the agent brain, exact runtime-facing documents, and bundled delegate agents
Runtime hintsCommunicates non-binding requirements and recommendations
Secret declarationsDeclares needed secret keys
Workspace source referencesDeclares shared repo/workspace dependencies
Package referencesDefines composition

Out of the manifest

ConcernWhy it's out
Secret values and providersEnvironment-specific
Resource limitsOperational
ReplicasOrchestration
Retry policyRuntime-specific
Session timeoutOperational
Scheduling and topologyOrchestration

Directory structure

my-agent/
├── agent.ts
├── SYSTEM_PROMPT.md
├── persona.ts
├── mcp-servers.ts
├── personas/
│   ├── _base.ts
│   ├── maya-chen.ts
│   └── alex-rivera.ts
├── skills/
├── rules/
├── knowledge/
├── memory/
├── surfaces/
│   ├── instructions.md
│   ├── persona.md
│   └── tools.md
├── .staxignore
└── stax.lock

On this page