# Change a prompt or a setting without a deploy

> Keep an agent's prompt and settings as data blocks, so an expert changes them and makes a new agent version, with no code change.

This guide moves an agent's prompt and settings into data blocks, so the people who know the work change them and make a new agent version, with no code change and no deploy.

A **data block** is a prompt, or a set of settings, kept in the runtime instead of in your code. Each change is a new version of the block, and an agent version pins the block versions it uses. So the people who know the work can change a prompt or a limit and make a new agent version from it: no code change, and no deploy.

There are two kinds:

- **A prompt block** is an agent's instructions: a Liquid template, with the parameters it takes, rendered as the agent's [instructions](https://docs.kindgi.com/v0.1.8/guides/agents/give-an-agent-input.md) are.
- **A settings block** is a JSON object of values, with an optional JSON Schema they must satisfy. The agent's instructions and its tools read them.

## Before you start

- **An agent to change,** in a pack on a runtime such as `kindgi dev`, with Kindgi 0.1's CLI. This guide uses the reply drafter from [Give an agent its input](https://docs.kindgi.com/v0.1.8/guides/agents/give-an-agent-input.md).
- **The project's id:** `kindgi projects get-default` prints the Default project, with its `id`.
- **For the app's half:** Node 22.12 or later, Python 3.11 or later, or Java 17 or later, with Kindgi 0.1's client, and `KINDGI_API_URL` and `KINDGI_API_TOKEN` set.

## Publish the blocks

The examples on this page move the reply drafter's instructions from [Give an agent its input](https://docs.kindgi.com/v0.1.8/guides/agents/give-an-agent-input.md) into a prompt block, `acme.reply-prompt`, and add a settings block, `acme.reply-style`: how long a reply may be, and up to what amount a refund needs no approval.

A prompt block with parameters is published from a JSON file. Ask your coding agent to write the prompt block:

```text
I want my agent's instructions in a prompt block, with the tone as a parameter.
```

For reference, the block it writes looks like this. This guide saves it as `reply-prompt.json`:

```json excerpt
{
  "id": "acme.reply-prompt",
  "version": "1.0.0",
  "kind": "prompt",
  "description": "The reply drafter's instructions",
  "content": {
    "template": "You draft short replies to Acme customers, in a {{ tone }} tone, in at most {{ settings[\"acme.reply-style\"].maxSentences }} sentences.\nWhen a customer asks for money back, check the amount with the refund check tool, and say whether a person needs to approve the refund.\nSign every reply as {{ signature }}.",
    "parameters": [
      { "name": "tone", "type": "string", "description": "friendly, formal, …" },
      { "name": "signature", "type": "string", "default": "The Acme team" }
    ]
  }
}
```

Publish it, and the settings block:

- **TypeScript**

  ```sh
  pnpm exec kindgi blocks publish --project=<project-id> @reply-prompt.json
  pnpm exec kindgi blocks publish acme.reply-style --block-version=1.0.0 --project=<project-id> --settings='{"maxSentences":3,"refundLimit":50}' --schema=@reply-style.schema.json
  ```

- **Python**

  ```sh
  uv run kindgi blocks publish --project=<project-id> @reply-prompt.json
  uv run kindgi blocks publish acme.reply-style --block-version=1.0.0 --project=<project-id> --settings='{"maxSentences":3,"refundLimit":50}' --schema=@reply-style.schema.json
  ```

- **Java**

  ```sh
  ./kindgiw blocks publish --project=<project-id> @reply-prompt.json
  ./kindgiw blocks publish acme.reply-style --block-version=1.0.0 --project=<project-id> --settings='{"maxSentences":3,"refundLimit":50}' --schema=@reply-style.schema.json
  ```

- **Scala**

  ```sh
  ./kindgiw blocks publish --project=<project-id> @reply-prompt.json
  ./kindgiw blocks publish acme.reply-style --block-version=1.0.0 --project=<project-id> --settings='{"maxSentences":3,"refundLimit":50}' --schema=@reply-style.schema.json
  ```

* `--project=<project-id>` is the project the block lives in, where `<project-id>` is its id.
* `@reply-prompt.json` reads the whole block from the file.
* `acme.reply-style` and `--block-version` are the settings block's id and version.
* `--settings` is its values, as JSON.
* `--schema=@reply-style.schema.json` reads the JSON Schema its values must satisfy from a file.

Each prints the block's id and version. The second prints:

```json
{
  "blockId": "acme.reply-style",
  "version": "1.0.0"
}
```

- **The template reads a settings block** as `{{ settings["acme.reply-style"].maxSentences }}`: the block's id in quotes, then the key.

- **A settings block's schema** checks its values, and later versions' too. A version published without one keeps the latest version's. A version that gives one replaces it, and `--schema='{}'` drops the check on purpose. Values that don't fit are refused:

  ```text
  Block "acme.reply-style" can't take this version
    ✗ /content/values/refundLimit: must be >= 0 (the schema of version 1.0.0)
  ```

`kindgi blocks list`, `show` and `versions` read them. `unregister` and `reinstate` retire a version and bring it back.

## Use them in an agent

The agent names its prompt block and its settings blocks by range, as it names its tools. Ask your coding agent: "Have my agent use its prompt block and settings block." For reference, the agent looks like this:

- **TypeScript**

  `agents/reply-drafter/index.ts`

  ```ts
  import { defineAgent } from '@kindgi/sdk/define';
  import type { AgentId, Semver } from '@kindgi/sdk/types';

  const defined = defineAgent({
    id: 'acme-ops.reply-drafter' as AgentId,
    version: '1.0.0' as Semver,
    name: 'Reply drafter',
    instructions: { prompt: 'acme.reply-prompt', version: '^1.0.0' },
    settings: [{ id: 'acme.reply-style', version: '^1.0.0' }],
    capabilities: [{ needs: [{ feature: 'tool-use' as const }] }],
    tools: [{ id: 'acme-ops.refund-check', version: '^0.1.0' }],
    retrieval: [],
    guardrails: [],
  });

  if (defined.kind === 'err') throw new Error(defined.error.message);
  export default defined.value;
  ```

- **Python**

  `agents/reply_drafter.py`

  ```python
  from kindgi import Agent

  from ..tools.refund_check import refund_check

  reply_drafter = Agent(
      id="acme-ops.reply-drafter",
      version="1.0.0",
      name="Reply drafter",
      instructions={"prompt": "acme.reply-prompt", "version": "^1.0.0"},
      settings=[{"id": "acme.reply-style", "version": "^1.0.0"}],
      capabilities=[{"needs": [{"feature": "tool-use"}]}],
      tools=[refund_check],
  )
  ```

- **Java**

  `src/main/java/acmeops/agents/ReplyDrafter.java`

  ```java
  package acmeops.agents;

  import acmeops.tools.RefundCheck;
  import com.kindgi.pack.Agent;
  import java.util.List;
  import java.util.Map;

  public final class ReplyDrafter {
    public static final Agent AGENT = Agent.define("acme-ops.reply-drafter")
        .version("1.0.0")
        .name("Reply drafter")
        .instructions(Map.of("prompt", "acme.reply-prompt", "version", "^1.0.0"))
        .set("settings", List.of(Map.of("id", "acme.reply-style", "version", "^1.0.0")))
        .capability(Map.of("needs", List.of(Map.of("feature", "tool-use"))))
        .tool(RefundCheck.TOOL)
        .build();

    private ReplyDrafter() {}
  }
  ```

- **Scala**

  `src/main/scala/acmeops/agents/ReplyDrafter.scala`

  ```scala
  package acmeops.agents

  import acmeops.tools.RefundCheck
  import com.kindgi.pack.scaladsl._

  object ReplyDrafter {
    val agent: Agent = Agent("acme-ops.reply-drafter")
      .version("1.0.0")
      .name("Reply drafter")
      .instructions(Map("prompt" -> "acme.reply-prompt", "version" -> "^1.0.0"))
      .set("settings", Seq(Map("id" -> "acme.reply-style", "version" -> "^1.0.0")))
      .capability(Map("needs" -> Seq(Map("feature" -> "tool-use"))))
      .tool(RefundCheck.tool)
      .build()
  }
  ```

The prompt block brings its parameters, so the agent declares none. A tool reads the settings blocks of the agent version that calls it, as `ctx.settings`. Ask your coding agent: "I want a tool that says whether a refund needs a person's approval, with the limit from my settings block." For reference, the tool looks like this:

- **TypeScript**

  `tools/refund-check/index.ts`

  ```ts
  import { defineTool } from '@kindgi/sdk/define';
  import type { ToolId } from '@kindgi/sdk/types';
  import { z } from 'zod';

  const defined = defineTool({
    id: 'acme-ops.refund-check' as ToolId,
    description: 'Says whether a refund of this amount needs a person to approve it.',
    version: '0.1.0',
    input: z.object({ amount: z.number().positive() }),
    output: z.object({ needsApproval: z.boolean(), limit: z.number() }),
    effects: [],
    mutating: false,
    handler: async (input, ctx) => {
      // The agent version's settings block: an expert changes the limit, not this code.
      const limit = Number(ctx.settings?.['acme.reply-style']?.refundLimit ?? 0);
      return { needsApproval: input.amount > limit, limit };
    },
  });

  if (defined.kind === 'err') throw new Error(defined.error.message);
  export default defined.value;
  ```

- **Python**

  `tools/refund_check.py`

  ```python
  from pydantic import BaseModel, Field

  from kindgi import ToolContext, tool


  class RefundAmount(BaseModel):
      amount: float = Field(gt=0)


  class RefundCheck(BaseModel):
      needs_approval: bool = Field(alias="needsApproval")
      limit: float


  @tool(id="acme-ops.refund-check", mutating=False)
  def refund_check(refund: RefundAmount, ctx: ToolContext) -> RefundCheck:
      """Says whether a refund of this amount needs a person to approve it."""
      # The agent version's settings block: an expert changes the limit, not this code.
      limit = float(ctx.settings.get("acme.reply-style", {}).get("refundLimit", 0))
      return RefundCheck(needsApproval=refund.amount > limit, limit=limit)
  ```

- **Java**

  `src/main/java/acmeops/tools/RefundCheck.java`

  ```java
  package acmeops.tools;

  import com.kindgi.pack.Tool;
  import jakarta.validation.constraints.Positive;
  import java.util.Map;

  public final class RefundCheck {
    public record Input(@Positive double amount) {}

    public record Output(boolean needsApproval, double limit) {}

    public static final Tool<Input, Output> TOOL = Tool.define("acme-ops.refund-check")
        .description("Says whether a refund of this amount needs a person to approve it.")
        .version("0.1.0")
        .input(Input.class)
        .output(Output.class)
        .mutating(false)
        .handler((input, ctx) -> {
          // The agent version's settings block: an expert changes the limit, not this code.
          Map<String, Object> style = ctx.settings().getOrDefault("acme.reply-style", Map.of());
          double limit = style.get("refundLimit") instanceof Number n ? n.doubleValue() : 0;
          return new Output(input.amount() > limit, limit);
        });

    private RefundCheck() {}
  }
  ```

  `ctx.settings()` maps each settings block the calling agent version pins, by id, to its values.

- **Scala**

  `src/main/scala/acmeops/tools/RefundCheck.scala`

  ```scala
  package acmeops.tools

  import com.kindgi.pack.scaladsl._
  import jakarta.validation.constraints.Positive

  object RefundCheck {
    final case class Input(@Positive amount: Double)
    final case class Output(needsApproval: Boolean, limit: Double)

    val tool: Tool[Input, Output] = Tool[Input, Output]("acme-ops.refund-check")
      .description("Says whether a refund of this amount needs a person to approve it.")
      .version("0.1.0")
      .readOnly
      .handler { (input, ctx) =>
        // The agent version's settings block: an expert changes the limit, not this code.
        val limit = Option(ctx.settings.get("acme.reply-style")).flatMap(s => Option(s.get("refundLimit"))) match {
          case Some(n: Number) => n.doubleValue
          case _ => 0.0
        }
        Output(needsApproval = input.amount > limit, limit = limit)
      }
  }
  ```

  `ctx.settings` maps each settings block the calling agent version pins, by id, to its values (a Java map).

A run passes the prompt's parameters as it does an agent's own:

- **TypeScript**

  ```sh
  pnpm exec kindgi runs start --agent=acme-ops.reply-drafter --input='{"userMessage":"I was charged twice for my $80 order. Can I get my money back?","parameters":{"tone":"friendly"}}'
  ```

- **Python**

  ```sh
  uv run kindgi runs start --agent=acme-ops.reply-drafter --input='{"userMessage":"I was charged twice for my $80 order. Can I get my money back?","parameters":{"tone":"friendly"}}'
  ```

- **Java**

  ```sh
  ./kindgiw runs start --agent=acme-ops.reply-drafter --input='{"userMessage":"I was charged twice for my $80 order. Can I get my money back?","parameters":{"tone":"friendly"}}'
  ```

- **Scala**

  ```sh
  ./kindgiw runs start --agent=acme-ops.reply-drafter --input='{"userMessage":"I was charged twice for my $80 order. Can I get my money back?","parameters":{"tone":"friendly"}}'
  ```

`--input`'s `parameters` are the prompt's parameters: here, `tone`. The run's `appended` messages show the tool reading the settings block's limit:

```json excerpt
"appended": [
  { "role": "user", "content": "I was charged twice for my $80 order. Can I get my money back?", … },
  { "role": "agent", "content": { "text": "", "toolCalls": [{ "name": "acme-ops.refund-check", "arguments": { "amount": 80 }, … }] }, … },
  { "role": "tool", "content": { "limit": 50, "needsApproval": true }, … },
  { "role": "agent", "content": "We're so sorry you were charged twice—that's definitely a mistake on our end! The good news is we can process your $80 refund, but it will need approval from one of our team members, so you should see it within a couple of business days. Thanks for your patience!\n\nThe Acme team", … }
]
```

The run's journal, which `kindgi runs journal <run-id>` prints, has the versions it used, in its `setup` step. It has the instructions as rendered, in `render-prompt`:

```text
{ "blockVersions": { "prompts": { "acme.reply-prompt": "1.0.0" }, "settings": { "acme.reply-style": "1.0.0" } } }
{ "rendered": "You draft short replies to Acme customers, in a friendly tone, in at most 3 sentences.\nWhen a customer asks for money back, check the amount with the refund check tool, and say whether a person needs to approve the refund.\nSign every reply as The Acme team." }
```

**Under `kindgi dev`,** each run uses the newest block versions in the agent's ranges, so a block version you publish is used at the next run.

**A published agent version pins them.** When it's published, by `kindgi deploy` or the API, each range resolves once, like its tools', as [Agent and tool versions](https://docs.kindgi.com/v0.1.8/guides/agents/agent-and-tool-versions.md) describes:

```json excerpt
{
  "version": "1.0.0",
  "pins": {
    "tools": { "acme-ops.refund-check": "0.1.0" },
    "prompts": { "acme.reply-prompt": "1.0.0" },
    "settings": { "acme.reply-style": "1.0.0" }
  },
  "pinsDigest": "sha256:3a7b0e31e9b6fb9149ea98dc3d0be451512e9d765f1321a834a5a4fad2fffe09",
  …
}
```

A block version that's missing or of the wrong kind refuses the publish, naming each. So do model settings with values a model can't take: `Agent "acme-ops.reply-drafter" uses tool or data-block versions it can't pin (1 issue)`.

**Model settings** are a settings block the agent names as `modelSettings`, such as `{ "temperature": 0.2, "maxOutputTokens": 400 }`. A temperature goes from 0 to 2. Its model calls use them, and the version pins the block with its other settings.

- **A reply that reaches `maxOutputTokens` stops there,** mid-sentence if need be, and the run still completes.
- **Some models take no temperature,** such as the Claude 5.5 and GPT-6 models. Their calls go without it, and the turn carries a `sampling-unsupported` warning, as [Temperature and thinking](https://docs.kindgi.com/v0.1.8/guides/models.md#temperature-and-thinking) describes.
- **A model that thinks** spends part of `maxOutputTokens` on thinking.

## Change a block

A change is a new version of the block, so the people who know the work change the values, not the code. With the CLI:

- **TypeScript**

  ```sh
  pnpm exec kindgi blocks publish acme.reply-style --block-version=1.1.0 --project=<project-id> --settings='{"maxSentences":3,"refundLimit":100}'
  ```

- **Python**

  ```sh
  uv run kindgi blocks publish acme.reply-style --block-version=1.1.0 --project=<project-id> --settings='{"maxSentences":3,"refundLimit":100}'
  ```

- **Java**

  ```sh
  ./kindgiw blocks publish acme.reply-style --block-version=1.1.0 --project=<project-id> --settings='{"maxSentences":3,"refundLimit":100}'
  ```

- **Scala**

  ```sh
  ./kindgiw blocks publish acme.reply-style --block-version=1.1.0 --project=<project-id> --settings='{"maxSentences":3,"refundLimit":100}'
  ```

`--block-version=1.1.0` is the new version, and `--settings` its values: a higher refund limit. It prints the block's id and version.

From your code, such as an admin page of your own, ask your coding agent: "I want to publish a new version of my settings block from my app." For reference, the code looks like this:

- **TypeScript**

  `publish-block.ts`

  ```ts
  import { createClient } from '@kindgi/sdk/client';

  const kindgi = createClient(); // KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi dev
  const project = await kindgi.projects.getDefault();

  // The settings block's next version: a higher refund limit, and no code change.
  await kindgi.blocks.publish(
    {
      id: 'acme.reply-style',
      version: '1.1.0',
      kind: 'settings',
      content: { values: { maxSentences: 3, refundLimit: 100 } },
    },
    { projectId: project.id },
  );

  const versions = await kindgi.blocks.versions.list('acme.reply-style');
  console.log(versions.data.map((block) => block.version));
  ```

- **Python**

  `publish_block.py`

  ```python
  from kindgi.client import Kindgi

  kindgi = Kindgi()  # KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi dev
  project = kindgi.projects.get_default()

  # The settings block's next version: a higher refund limit, and no code change.
  kindgi.blocks.publish(
      project_id=project.id,
      id="acme.reply-style",
      version="1.1.0",
      kind="settings",
      content={"values": {"maxSentences": 3, "refundLimit": 100}},
  )

  versions = kindgi.blocks.versions.list("acme.reply-style")
  print([block.version for block in versions.data])
  ```

- **Java**

  `src/main/java/com/acme/app/PublishBlock.java`

  ```java
  package com.acme.app;

  import com.kindgi.client.Kindgi;
  import com.kindgi.client.models.Block;
  import com.kindgi.client.models.BlockKind;
  import com.kindgi.client.models.Project;
  import com.kindgi.client.models.PublishBlockBody;
  import com.kindgi.client.models.SettingsBlockContent;
  import java.util.Map;
  import java.util.UUID;

  public final class PublishBlock {
    public static void main(String[] args) {
      Kindgi kindgi = Kindgi.create(); // KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi dev
      Project project = kindgi.projects().getDefault();

      // The settings block's next version: a higher refund limit, and no code change.
      kindgi.blocks().publish(PublishBlockBody.builder()
          .projectId(UUID.fromString(project.id()))
          .id("acme.reply-style")
          .version("1.1.0")
          .kind(BlockKind.SETTINGS)
          .content(SettingsBlockContent.builder().values(Map.of("maxSentences", 3, "refundLimit", 100)).build())
          .build());

      System.out.println(kindgi.blocks().versions().list("acme.reply-style").data().stream()
          .map(Block::version).toList());
    }
  }
  ```

  It prints the versions below without quotes: `[1.1.0, 1.0.0]`.

- **Scala**

  `src/main/scala/acme/app/PublishBlock.scala`

  ```scala
  package acme.app

  import com.kindgi.client.Kindgi
  import com.kindgi.client.models.{BlockKind, PublishBlockBody, SettingsBlockContent}
  import java.util.UUID
  import scala.jdk.CollectionConverters._

  object PublishBlock {
    def main(args: Array[String]): Unit = {
      val kindgi = Kindgi.create() // KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi dev
      val project = kindgi.projects().getDefault()

      // The settings block's next version: a higher refund limit, and no code change.
      kindgi.blocks().publish(PublishBlockBody.builder()
        .projectId(UUID.fromString(project.id))
        .id("acme.reply-style")
        .version("1.1.0")
        .kind(BlockKind.SETTINGS)
        .content(SettingsBlockContent.builder()
          .values(Map[String, AnyRef]("maxSentences" -> Int.box(3), "refundLimit" -> Int.box(100)).asJava)
          .build())
        .build())

      println(kindgi.blocks().versions().list("acme.reply-style").data.asScala.map(_.version).mkString("[", ", ", "]"))
    }
  }
  ```

  It prints the versions below without quotes: `[1.1.0, 1.0.0]`.

It prints the block's versions, newest first:

```text
[ '1.1.0', '1.0.0' ]
```

Under `kindgi dev`, that's all: the next run reads 1.1.0, and its tool gets `{ "limit": 100, "needsApproval": false }`.

## Make an agent version that runs it

A new block version doesn't change a published agent version: it keeps running the versions it pins. To use the new one, **derive** an agent version: the same agent, with some of its block pins swapped. It needs no code change and no deploy.

- **TypeScript**

  ```sh
  pnpm exec kindgi agents derive acme-ops.reply-drafter --from=1.0.0 --setting=acme.reply-style=1.1.0 --label="Refund limit 100"
  ```

- **Python**

  ```sh
  uv run kindgi agents derive acme-ops.reply-drafter --from=1.0.0 --setting=acme.reply-style=1.1.0 --label="Refund limit 100"
  ```

- **Java**

  ```sh
  ./kindgiw agents derive acme-ops.reply-drafter --from=1.0.0 --setting=acme.reply-style=1.1.0 --label="Refund limit 100"
  ```

- **Scala**

  ```sh
  ./kindgiw agents derive acme-ops.reply-drafter --from=1.0.0 --setting=acme.reply-style=1.1.0 --label="Refund limit 100"
  ```

* `--from=1.0.0` is the version to start from.
* `--setting=acme.reply-style=1.1.0` swaps in that settings block version.
* `--label` says what changed.

It prints the new agent version:

```json excerpt
{
  "id": "acme-ops.reply-drafter",
  "version": "1.0.1",
  …
  "pins": {
    "tools": { "acme-ops.refund-check": "0.1.0" },
    "prompts": { "acme.reply-prompt": "1.0.0" },
    "settings": { "acme.reply-style": "1.1.0" }
  },
  "derivedFrom": {
    "version": "1.0.0",
    "reason": "edited",
    "label": "Refund limit 100",
    "by": "user:35aa4131-bc65-43c9-80ba-8931a53fafdc"
  }
}
```

From your code, ask your coding agent: "I want a new version of my agent that uses the new refund limit." For reference, the code looks like this:

- **TypeScript**

  `derive.ts`

  ```ts
  import { createClient } from '@kindgi/sdk/client';
  import type { AgentId } from '@kindgi/sdk/types';

  const kindgi = createClient(); // KINDGI_API_URL, KINDGI_API_TOKEN

  // Version 1.0.0 with version 1.1.0 of its settings block: no code change, no deploy.
  const derived = await kindgi.agents.versions.derive('acme-ops.reply-drafter' as AgentId, {
    from: '1.0.0',
    pins: { settings: { 'acme.reply-style': '1.1.0' } },
    label: 'Refund limit 100',
  });
  console.log(derived.version, derived.pins?.settings, derived.derivedFrom);
  ```

- **Python**

  `derive.py`

  ```python
  from kindgi.client import Kindgi

  kindgi = Kindgi()  # KINDGI_API_URL, KINDGI_API_TOKEN

  # Version 1.0.0 with version 1.1.0 of its settings block: no code change, no deploy.
  derived = kindgi.agents.derive_version(
      "acme-ops.reply-drafter",
      from_="1.0.0",
      pins={"settings": {"acme.reply-style": "1.1.0"}},
      label="Refund limit 100",
  )
  print(derived.version, derived.pins.settings if derived.pins else None, derived.derived_from)
  ```

* **The new version is the next free patch** after the highest one, and `derivedFrom` says where it came from. Runs choose it like any other version. The same swap again returns that version, with `200`, not a new one.
* **Swap prompts with `--prompt=<block-id>=<version>`,** or `pins.prompts` in the clients, and settings with `--setting`. Repeat either for several.
* **Only blocks the version already uses** can be swapped, and only on a version that has pins.
* **Under `kindgi dev`, there's nothing to derive:** each run already uses the newest block versions, and a derive is refused: `Error [registry-read-only]: Under kindgi dev, the pack is the source of agents: change the agent in the pack's files and kindgi dev reloads it.`
* **Then a developer publishing the next number from code** gets told which one is free: `Agent "acme-ops.reply-drafter" version "1.0.1" is already registered, and versions never change; publish it as 1.0.2, the next free version`.

Before anyone uses the new version, [compare it on a test set](https://docs.kindgi.com/v0.1.8/guides/evals/compare-an-agent-version.md). Because 1.0.1 pins another settings block version than 1.0.0, the comparison runs read-only tools such as `acme-ops.refund-check` live, rather than reusing the recorded results. So the new refund limit shows in the answers. Those cases count as `diverged`, which a gate with `replay` and `maxDiverged: 0` refuses.

## In the console

A project's **Data blocks** section lists its blocks. A block's page shows its template or values, its versions with **Retire**, and the agents using it.

1. **Edit as a new version** starts from the version you're viewing and proposes the next number, with an optional note for this version. Published versions never change: this publishes a new one.
2. After it's published, **Derive a version** next to an agent using the block makes the agent version that runs it: "Derive a new version of Reply drafter with acme.reply-prompt 1.0.1?"

An agent's page says where its instructions and settings come from, and where a derived version came from: "Derived from 1.0.0 with new data-block versions ("Refund limit 100")".

Under `kindgi dev`, a block's page says each pack agent "Runs the newest version in ^1.0.0 on each run (kindgi dev)", and offers no derive.

## Next

- [Compare a version on a test set](https://docs.kindgi.com/v0.1.8/guides/evals/compare-an-agent-version.md)
- [Release an agent version](https://docs.kindgi.com/v0.1.8/guides/evals/release-an-agent-version.md)
- [Propose a change, and test it](https://docs.kindgi.com/v0.1.8/guides/evals/propose-a-change.md)
