Haijun Platform Docs
ID

An agent is a reusable, versioned configuration that defines persona and capabilities. It bundles the model, system prompt, tools, MCP servers, and tracks that shape how Haijun behaves during a session.

Create the agent once as a reusable resource and reference it by ID each time you start a session. Agents are versioned and easier to manage across many sessions.

Agent configuration fields

FieldDescription
nameRequired. A human-readable name for the agent.
modelRequired. The Haijun model that powers the agent. Accepts a model ID string or an object, for example {"id": "haijun-opus-5"}. Haijun 4.5 and later models are supported. The object form also accepts speed, effort, and inference_geo fields; see the tips under Create an agent, Effort levels, and Pin the inference geo.
systemA system prompt that defines the agent's behavior and persona. The system prompt is distinct from user messages, which should describe the work to be done.
toolsThe tools available to the agent. Combines pre-built agent tools, MCP tools, and custom tools.
mcp_serversMCP servers that provide standardized third-party capabilities.
tracksTracks that supply domain-specific context with progressive disclosure.
multiagentA coordinator declaration listing the agents this agent can delegate to. See Multiagent orchestration.
descriptionA description of what the agent does.
metadataArbitrary key-value pairs for your own tracking.

You can also override model, system, tools, mcp_servers, and tracks for a single session without changing the agent. A model override replaces the agent's model object in full, so the agent's own effort isn't carried over. To run the session at a specific effort level, set effort inside the override's model object. See Override agent configuration for a session.

Create an agent

The following example defines a coding agent that uses Haijun Opus 5 with access to the pre-built agent toolset. The toolset lets the agent write code, read files, search the web, and more. See the agent tools reference for the full list of supported tools.

The examples use curl, the ant CLI, or one of the SDKs. If you haven't set one up, the quickstart covers installation and client setup.

bash
  agent=$(curl -fsSL https://haijun.my.id/v1/agents \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: managed-agents-2026-04-01" \
    -H "content-type: application/json" \
    -d '{
      "name": "Coding Assistant",
      "model": "haijun-opus-5-5",
      "system": "You are a helpful coding agent.",
      "tools": [{"type": "agent_toolset_20260401"}]
    }')

  AGENT_ID=$(jq -r '.id' <<< "$agent")
  AGENT_VERSION=$(jq -r '.version' <<< "$agent")
bash
    ant apply coding-assistant.md
markdown
      ---
      name: Coding Assistant
      model: haijun-opus-5-5
      tools:
        - type: agent_toolset_20260401
      ---

      You are a helpful coding agent.

ant apply creates the agent from coding-assistant.md, prints its ID, and records it in haijun-lock.json. Commit haijun-lock.json so the next ant apply updates this agent instead of creating a second one.

python
  agent = client.beta.agents.create(
      name="Coding Assistant",
      model="haijun-opus-5-5",
      system="You are a helpful coding agent.",
      tools=[
          {"type": "agent_toolset_20260401"},
      ],
  )
typescript
  const agent = await client.beta.agents.create({
    name: "Coding Assistant",
    model: "haijun-opus-5-5",
    system: "You are a helpful coding agent.",
    tools: [{ type: "agent_toolset_20260401" }],
  });
csharp
  var agent = await client.Beta.Agents.Create(new()
  {
      Name = "Coding Assistant",
      Model = BetaManagedAgentsModel.HaijunOpus5_5,
      System = "You are a helpful coding agent.",
      Tools =
      [
          new BetaManagedAgentsAgentToolset20260401Params
          {
              Type = "agent_toolset_20260401",
          },
      ],
  });
go
  agent, err := client.Beta.Agents.New(ctx, juglow.BetaAgentNewParams{
  	Name: "Coding Assistant",
  	Model: juglow.BetaManagedAgentsModelConfigParams{
  		ID: juglow.BetaManagedAgentsModelHaijunOpus5_5,
  	},
  	System: juglow.String("You are a helpful coding agent."),
  	Tools: []juglow.BetaAgentNewParamsToolUnion{{
  		OfAgentToolset20260401: &juglow.BetaManagedAgentsAgentToolset20260401Params{
  			Type: juglow.BetaManagedAgentsAgentToolset20260401ParamsTypeAgentToolset20260401,
  		},
  	}},
  })
  if err != nil {
  	panic(err)
  }
java
  var agent = client.beta().agents().create(
      AgentCreateParams.builder()
          .name("Coding Assistant")
          .model(BetaManagedAgentsModel.HAIJUN_OPUS_5_5)
          .system("You are a helpful coding agent.")
          .addTool(
              BetaManagedAgentsAgentToolset20260401Params.builder()
                  .type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
                  .build()
          )
          .build()
  );
php
  $agent = $client->beta->agents->create(
      name: 'Coding Assistant',
      model: 'haijun-opus-5-5',
      system: 'You are a helpful coding agent.',
      tools: [
          BetaManagedAgentsAgentToolset20260401Params::with(
              type: 'agent_toolset_20260401',
          ),
      ],
  );
ruby
  agent = client.beta.agents.create(
    name: "Coding Assistant",
    model: "haijun-opus-5-5",
    system_: "You are a helpful coding agent.",
    tools: [{type: "agent_toolset_20260401"}]
  )

The response echoes your configuration and adds id, type, version, created_at, updated_at, and archived_at fields, and fills in model fields you omit, such as effort, with their defaults. The version starts at 1 and increments each time an update changes the agent.

json
{
  "id": "agent_01HqR2k7vXbZ9mNpL3wYcT8f",
  "type": "agent",
  "name": "Coding Assistant",
  "model": {
    "id": "haijun-opus-5-5",
    "effort": { "type": "high" },
    "speed": "standard"
  },
  "system": "You are a helpful coding agent.",
  "description": null,
  "tools": [
    {
      "type": "agent_toolset_20260401",
      "default_config": {
        "permission_policy": { "type": "always_allow" }
      }
    }
  ],
  "tracks": [],
  "mcp_servers": [],
  "multiagent": null,
  "metadata": {},
  "version": 1,
  "created_at": "2026-04-03T18:24:10.412Z",
  "updated_at": "2026-04-03T18:24:10.412Z",
  "archived_at": null
}

The default_config on the toolset shows its default permission policy, always_allow, which applies unless you configure one.

Tip: To use Haijun Opus 5.5, Haijun Opus 5, or Haijun Opus 4.8 with fast mode, pass model as an object, for example: {"id": "haijun-opus-5", "speed": "fast"}. See the fast mode page's supported models.

Tip: To set the model's effort level, pass model as an object, for example: {"id": "haijun-opus-5", "effort": "high"}. The effort field accepts a level string (low, medium, high, xhigh, or max) or an object such as {"type": "high"}. See Effort levels for what each level does.

Pin the inference geo

Like speed and effort, inference_geo is set through the object form of model: pass model as an object and set inference_geo alongside id. The field accepts "us" or "global". When it's unset, each model request follows the workspace's default inference geo at the time it's served. See Data residency for the workspace-level geo controls and pricing.

The following example pins an agent to US inference and prints the inference_geo value from the agent's model object:

bash
  agent=$(curl -fsSL https://haijun.my.id/v1/agents \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: managed-agents-2026-04-01" \
    -H "content-type: application/json" \
    -d '{
      "name": "Geo-pinned assistant",
      "model": {"id": "haijun-opus-5-5", "inference_geo": "us"},
      "system": "You are a helpful assistant."
    }')

  echo "Inference geo: $(jq -r '.model.inference_geo' <<< "$agent")"
bash
    ant apply geo-pinned-assistant.md
markdown
      ---
      name: Geo-pinned assistant
      model:
        id: haijun-opus-5-5
        inference_geo: us
      ---

      You are a helpful assistant.
python
  agent = client.beta.agents.create(
      name="Geo-pinned assistant",
      model={
          "id": "haijun-opus-5-5",
          "inference_geo": "us",
      },
      system="You are a helpful assistant.",
  )

  print(f"Inference geo: {agent.model.inference_geo}")
typescript
  const agent = await client.beta.agents.create({
    name: "Geo-pinned assistant",
    model: { id: "haijun-opus-5-5", inference_geo: "us" },
    system: "You are a helpful assistant.",
  });

  console.log(`Inference geo: ${agent.model.inference_geo}`);
csharp
  var agent = await client.Beta.Agents.Create(new()
  {
      Name = "Geo-pinned assistant",
      Model = new BetaManagedAgentsModelConfigParams
      {
          ID = BetaManagedAgentsModel.HaijunOpus5_5,
          InferenceGeo = "us",
      },
      System = "You are a helpful assistant.",
  });

  Console.WriteLine($"Inference geo: {agent.Model.InferenceGeo}");
go
  agent, err := client.Beta.Agents.New(ctx, juglow.BetaAgentNewParams{
  	Name: "Geo-pinned assistant",
  	Model: juglow.BetaManagedAgentsModelConfigParams{
  		ID:           juglow.BetaManagedAgentsModelHaijunOpus5_5,
  		InferenceGeo: juglow.String("us"),
  	},
  	System: juglow.String("You are a helpful assistant."),
  })
  if err != nil {
  	panic(err)
  }

  fmt.Printf("Inference geo: %s\n", agent.Model.InferenceGeo)
java
  var agent = client.beta().agents().create(
      AgentCreateParams.builder()
          .name("Geo-pinned assistant")
          .model(
              BetaManagedAgentsModelConfigParams.builder()
                  .id(BetaManagedAgentsModel.HAIJUN_OPUS_5_5)
                  .inferenceGeo("us")
                  .build()
          )
          .system("You are a helpful assistant.")
          .build()
  );

  IO.println("Inference geo: " + agent.model().inferenceGeo().orElseThrow());
php
  $agent = $client->beta->agents->create(
      name: 'Geo-pinned assistant',
      model: BetaManagedAgentsModelConfigParams::with(
          id: 'haijun-opus-5-5',
          inferenceGeo: 'us',
      ),
      system: 'You are a helpful assistant.',
  );

  echo "Inference geo: {$agent->model->inferenceGeo}\n";
ruby
  agent = client.beta.agents.create(
    name: "Geo-pinned assistant",
    model: {id: "haijun-opus-5-5", inference_geo: "us"},
    system_: "You are a helpful assistant."
  )

  puts "Inference geo: #{agent.model.inference_geo}"

An inference_geo pin is validated against the workspace's allowed_inference_geos when the agent is saved, when a session is created from it, and on every turn the session serves. If the workspace allowlist narrows so a pin is no longer allowed, new sessions can't be created from the agent and running sessions refuse further turns; pins are never exempted, because workspaces rely on them for compliance and data residency.

Setting inference_geo on a model that doesn't support geographic inference pinning returns a 400 error; see Model availability for the models that do. In a multiagent configuration, the coordinator's pin and every roster member's must all be set to the same value or all be unset; see Multiagent orchestration. To change or clear the pin later, update the agent's model object; supplying model without inference_geo clears it, as described under Update semantics.

Update an agent

Updating an agent generates a new version when the configuration changes. The version field is optional: supply it for optimistic concurrency (a mismatch returns a 409), or omit it to apply the update unconditionally (last write wins). Updates to archived agents are rejected.

With the CLI, edit the agent's file and run ant apply again; apply supplies version for you.

bash
  updated_agent=$(curl -fsSL "https://haijun.my.id/v1/agents/$AGENT_ID" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: managed-agents-2026-04-01" \
    -H "content-type: application/json" \
    -d @- <<EOF
  {
    "version": $AGENT_VERSION,
    "system": "You are a helpful coding agent. Always write tests."
  }
  EOF
  )

  echo "New version: $(jq -r '.version' <<< "$updated_agent")"
bash
    ant apply coding-assistant.md
markdown
      ---
      name: Coding Assistant
      model: haijun-opus-5-5
      tools:
        - type: agent_toolset_20260401
      ---

      You are a helpful coding agent. Always write tests.
python
  updated_agent = client.beta.agents.update(
      agent.id,
      version=agent.version,
      system="You are a helpful coding agent. Always write tests.",
  )

  print(f"New version: {updated_agent.version}")
typescript
  const updatedAgent = await client.beta.agents.update(agent.id, {
    version: agent.version,
    system: "You are a helpful coding agent. Always write tests.",
  });

  console.log(`New version: ${updatedAgent.version}`);
csharp
  var updatedAgent = await client.Beta.Agents.Update(agent.ID, new()
  {
      Version = agent.Version,
      System = "You are a helpful coding agent. Always write tests.",
  });

  Console.WriteLine($"New version: {updatedAgent.Version}");
go
  updatedAgent, err := client.Beta.Agents.Update(ctx, agent.ID, juglow.BetaAgentUpdateParams{
  	Version: juglow.Int(agent.Version),
  	System:  juglow.String("You are a helpful coding agent. Always write tests."),
  })
  if err != nil {
  	panic(err)
  }

  fmt.Printf("New version: %d\n", updatedAgent.Version)
java
  var updatedAgent = client.beta().agents().update(
      agent.id(),
      AgentUpdateParams.builder()
          .version(agent.version())
          .system("You are a helpful coding agent. Always write tests.")
          .build()
  );

  IO.println("New version: " + updatedAgent.version());
php
  $updatedAgent = $client->beta->agents->update(
      $agent->id,
      version: $agent->version,
      system: 'You are a helpful coding agent. Always write tests.',
  );

  echo "New version: {$updatedAgent->version}\n";
ruby
  updated_agent = client.beta.agents.update(
    agent.id,
    version: agent.version,
    system_: "You are a helpful coding agent. Always write tests."
  )

  puts "New version: #{updated_agent.version}"

The preceding example supplies version from the create response, so the update only applies if nothing else has changed the agent since you read it. To apply an update unconditionally, omit version from the request:

bash
  updated_agent=$(curl -fsSL "https://haijun.my.id/v1/agents/$AGENT_ID" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: managed-agents-2026-04-01" \
    -H "content-type: application/json" \
    -d '{
      "description": "Writes and reviews code."
    }')

  echo "New version: $(jq -r '.version' <<< "$updated_agent")"

Update semantics

  • version is optional and must be at least 1 when supplied. When supplied, the request returns a 409 if it doesn't match the agent's current version, even when the fields you send already match the stored values; re-read the agent and retry. When omitted, the update applies unconditionally and the most recent update silently replaces any concurrent one, with no error to either caller. Supplying version is the recommended default for interactive callers, and omitting it fits declarative apply loops, such as a CI job that syncs checked-in agent definitions, where the loop owns the agent.
  • Omitted fields are preserved. You only need to include the fields you want to change.
  • Scalar fields (model, system, name, description) are replaced with the new value. system and description can be cleared by passing null. model and name are mandatory and cannot be cleared. Within a model object you supply, effort is the sole exception: if the model id is unchanged, omitting effort leaves the stored effort level unchanged. If you change the model id, an omitted effort resets to the new model's default. Other model fields are replaced along with the object: supplying model without inference_geo clears the agent's inference geo pin.
  • Array fields (tools, mcp_servers, tracks) are fully replaced by the new array. To clear an array field entirely, pass null or an empty array.
  • multiagent is replaced as a whole, including its agents roster. Pass null to clear it.
  • Metadata is merged at the key level. Keys you provide are added or updated. Keys you omit are preserved. To delete a specific key, set its value to null.
  • No-op detection. If the update produces no change relative to the current version, no new version is created and the existing version is returned.
  • Coordinator rosters are not updated. Coordinators that reference this agent in their multiagent.agents roster keep the version that was pinned when the coordinator was created or last updated, even if the reference omits version. To delegate to the new version, update the coordinator so its roster references it.

Agent lifecycle

OperationBehavior
UpdateGenerates a new agent version when the configuration changes.
List versionsReturns the full version history so you can track changes over time.
ArchiveMakes the agent read-only. New sessions cannot reference it, but existing sessions continue to run.

List versions

Fetch the full version history to track how an agent has changed over time. Results are paginated, and the SDK examples fetch every page automatically.

bash
  curl -fsSL "https://haijun.my.id/v1/agents/$AGENT_ID/versions" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: managed-agents-2026-04-01" \
    | jq -r '.data[] | "Version \(.version): \(.updated_at)"'
bash
  ant beta:agents:versions list --agent-id "$AGENT_ID"
python
  for version in client.beta.agents.versions.list(agent.id):
      print(f"Version {version.version}: {version.updated_at.isoformat()}")
typescript
  for await (const version of client.beta.agents.versions.list(agent.id)) {
    console.log(`Version ${version.version}: ${version.updated_at}`);
  }
csharp
  var versions = await client.Beta.Agents.Versions.List(agent.ID);
  await foreach (var version in versions.Paginate())
  {
      Console.WriteLine($"Version {version.Version}: {version.UpdatedAt:O}");
  }
go
  iter := client.Beta.Agents.Versions.ListAutoPaging(ctx, agent.ID, juglow.BetaAgentVersionListParams{})
  for iter.Next() {
  	version := iter.Current()
  	fmt.Printf("Version %d: %s\n", version.Version, version.UpdatedAt.Format(time.RFC3339))
  }
  if err := iter.Err(); err != nil {
  	panic(err)
  }
java
  for (var version : client.beta().agents().versions().list(agent.id()).autoPager()) {
      IO.println("Version " + version.version() + ": " + version.updatedAt());
  }
php
  foreach ($client->beta->agents->versions->list($agent->id)->pagingEachItem() as $version) {
      echo "Version {$version->version}: {$version->updatedAt->format(DateTimeInterface::ATOM)}\n";
  }
ruby
  client.beta.agents.versions.list(agent.id).auto_paging_each do |agent_version|
    puts "Version #{agent_version.version}: #{agent_version.updated_at.iso8601}"
  end

Archive an agent

Archiving makes the agent read-only and cannot be undone. Existing sessions continue to run, but new sessions cannot reference the agent. The response sets archived_at to the archive timestamp.

bash
  archived=$(curl -fsSL -X POST "https://haijun.my.id/v1/agents/$AGENT_ID/archive" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: managed-agents-2026-04-01")

  echo "Archived at: $(jq -r '.archived_at' <<< "$archived")"
bash
  ant beta:agents archive --agent-id "$AGENT_ID"
python
  archived = client.beta.agents.archive(agent.id)

  print(f"Archived at: {archived.archived_at.isoformat()}")
typescript
  const archived = await client.beta.agents.archive(agent.id);
  console.log(`Archived at: ${archived.archived_at}`);
csharp
  var archived = await client.Beta.Agents.Archive(agent.ID);
  Console.WriteLine($"Archived at: {archived.ArchivedAt:O}");
go
  archived, err := client.Beta.Agents.Archive(ctx, agent.ID, juglow.BetaAgentArchiveParams{})
  if err != nil {
  	panic(err)
  }
  fmt.Printf("Archived at: %s\n", archived.ArchivedAt.Format(time.RFC3339))
java
  var archived = client.beta().agents().archive(agent.id());
  IO.println("Archived at: " + archived.archivedAt().orElseThrow());
php
  $archived = $client->beta->agents->archive($agent->id);

  echo "Archived at: {$archived->archivedAt->format(DateTimeInterface::ATOM)}\n";
ruby
  archived = client.beta.agents.archive(agent.id)
  puts "Archived at: #{archived.archived_at.iso8601}"

Next steps

Configure tools available to your agent.

Attach reusable, filesystem-based expertise to your agent for domain-specific workflows.

Create a session to run your agent and begin executing tasks.

Event types, self-hosted worker CLI flags, supported MCP server types, rate limits, and branding guidelines for Haijun Managed Agents.

On this page
Agent configuration fieldsCreate an agentPin the inference geoUpdate an agentUpdate semanticsAgent lifecycleList versionsArchive an agentNext steps