Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions .github/workflows/update-ref-docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,16 @@ jobs:

echo "Extracted from kagent ${KAGENT_COMMIT}:"
check SUBSTRATE_VERSION "$SUBSTRATE_VERSION" "$SEMVER"
check KMCP_VERSION "$KMCP_VERSION" "$SEMVER"
# kagent stopped bundling kmcp at 1.0.0-alpha14 (kagent#3223), so its
# go.mod no longer requires it. An absent require is a real answer,
# not a parse failure: KMCP_VERSION stays empty and versions/kmcp.md
# is left alone. A require that IS present must still parse.
if grep -q 'github\.com/kagent-dev/kmcp' "$GOMOD"; then
check KMCP_VERSION "$KMCP_VERSION" "$SEMVER"
else
KMCP_VERSION=""
echo " KMCP_VERSION = (not bundled; go.mod does not require kmcp)"
fi
check KAGENT_TOOLS_VERSION "$KAGENT_TOOLS_VERSION" "$SEMVER"
check MAX_KUBE "$MAX_KUBE" '^[0-9]+\.[0-9]+$'

Expand Down Expand Up @@ -566,7 +575,10 @@ jobs:
# than warned about. It is still worth saying out loud: it means the
# kagent support matrix and the kmcp guides name different versions on
# purpose, which looks like a bug to anyone who has not read this.
if [ "$KMCP_LATEST" != "$KMCP_VERSION" ]; then
if [ -z "$KMCP_VERSION" ]; then
echo "kmcp: kagent no longer bundles kmcp; kmcp's latest release is $KMCP_LATEST."
echo "KMCP_MISMATCH=" >> $GITHUB_ENV
elif [ "$KMCP_LATEST" != "$KMCP_VERSION" ]; then
echo "kmcp split: kagent pins $KMCP_VERSION, kmcp's latest release is $KMCP_LATEST. Writing both."
echo "KMCP_MISMATCH=\`versions/kmcp.md\` is \`$KMCP_VERSION\` (what kagent bundles) and \`versions/kmcp-latest.md\` is \`$KMCP_LATEST\` (kmcp's newest release). The two naming different versions is expected -- the kagent support matrix and the standalone kmcp guides are answering different questions." >> $GITHUB_ENV
else
Expand Down Expand Up @@ -682,7 +694,12 @@ jobs:
}

echo "Flat conrefs:"
write_conref "$VERSIONS_DIR/kmcp.md" "$KMCP_VERSION"
# Empty when kagent no longer bundles kmcp; see the extraction step.
if [ -n "$KMCP_VERSION" ]; then
write_conref "$VERSIONS_DIR/kmcp.md" "$KMCP_VERSION"
else
echo " kmcp.md: SKIPPED, kagent does not bundle kmcp. Left at $(cat "$VERSIONS_DIR/kmcp.md")"
fi
# Only when it resolved; see the cross-check step above.
if [ -n "${KMCP_LATEST:-}" ]; then
write_conref "$VERSIONS_DIR/kmcp-latest.md" "$KMCP_LATEST"
Expand Down Expand Up @@ -728,7 +745,7 @@ jobs:
echo "KMCP_SOURCE_LINE=- **kmcp**: [\`${KMCP_TAG}\`](https://github.com/${{ github.repository_owner }}/kmcp/releases/tag/${KMCP_TAG}) (\`${KMCP_COMMIT}\`)"
echo "LINE_SCOPE_NOTE="
echo "FLAT_CONREF_ROWS<<ROWS_EOF"
echo "| \`kmcp\` | \`${KMCP_VERSION}\` | \`go/go.mod\` require (what kagent bundles) |"
echo "| \`kmcp\` | \`${KMCP_VERSION:-not bundled}\` | \`go/go.mod\` require (what kagent bundles) |"
echo "| \`kmcp-latest\` | \`${KMCP_LATEST:-unresolved}\` | kmcp's latest release (what the kmcp guides show) |"
echo "| \`kagent-tools\` | \`${KAGENT_TOOLS_VERSION}\` | \`helm/kagent/Chart-template.yaml\` |"
echo "| \`runtime-image\` | \`${RUNTIME_IMAGE:-unresolved}\` | GHCR, at \`${KAGENT_TAG}\` |"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ The following diagram traces an Actor through one suspend-and-resume cycle, and

{{< reuse "kagent-docs/snippets/snapshot-cycle-diagram.md" >}}

A **WorkerPool** keeps **Workers** running and ready, and a Worker hosts the **Actor** alongside other Actors while its Session is active. Suspending this Actor writes its full state to an immutable **ActorSnapshot** and releases the capacity that it held on its Worker.
A **WorkerPool** keeps **Workers** running and ready, and a Worker hosts the **Actor** alongside other Actors while its Session is active. Suspending this Actor writes its durable data to an immutable **ActorSnapshot** and releases the capacity that it held on its Worker.

The diagram forks at this snapshot, because a snapshot serves two purposes.

- **Resume** restores the same Actor onto **any Worker in the pool with room**, which is not necessarily the Worker that it ran on before. Because the snapshot captures the Actor's full state, the conversation continues from where it left off. Every idle agent takes this path.
- **Resume** restores the same Actor onto **any Worker in the pool with room**, which is not necessarily the Worker that it ran on before. Agent Substrate starts new containers for the Actor and restores the durable data from the snapshot. The conversation continues from where it left off. Every idle agent takes this path.
- A **{{< gloss "Tag" >}}Tag{{< /gloss >}}** pins this snapshot so that Agent Substrate does not collect it. To fork a Session from a checkpoint, kagent seeds a **New Actor** from that tag. Resuming an existing Actor never goes through a tag.

A tag gives a snapshot a stable name, so callers do not track Agent Substrate's internal snapshot identity. The tag names one snapshot permanently, and only its visibility scope can change afterward. A tag is also a retention pin, so Agent Substrate does not delete a snapshot while a tag still names it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,7 @@ Listing behaves the same way. A list returns the caller's own Sessions by defaul

A share lets a Session's owner give another account access to that one conversation. Creating a share produces a token, and a caller presenting that token reaches the shared Session without becoming its creator.

A share carries one of two permissions.

- **`READ_ONLY`**: The holder can read the conversation. kagent refuses any call that is not a read before the request reaches the service.
- **`READ_WRITE`**: The holder can also send messages to the Session.
Every share is read-only. The holder can read the conversation, but cannot send a message, answer an approval, cancel a task, or retry a turn. kagent enforces the restriction in its services and transports. A shared conversation in the UI does not show controls for those actions.

A client that creates a share can set `CreateSessionShareRequest.ttl` to a positive lifetime, which starts when the share is created. Once that lifetime ends, the token does not grant access, and a token lookup returns not found. The owner still sees the expired share in `ListSessionShares` and can revoke it.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ An {{< gloss "ActorTemplate" >}}ActorTemplate{{< /gloss >}}'s snapshot configura
- **`Full`**: Captures process memory, the root filesystem changes layered on top of the container image, and any attached durable volumes. A `Full` snapshot holds everything that is needed to resume the Actor hot, with its in-memory state intact.
- **`Data`**: Captures only the contents of attached durable volumes. Process memory and the rest of the root filesystem are discarded, which makes the snapshot much cheaper to write and store.

kagent sets the scope automatically on every ActorTemplate that it generates, and it sets `Full` so that process memory survives both a pause and a suspend. Each Actor also gets a single durable volume named `data`. The one snapshot setting that you author is the storage location, which you set on the {{< gloss "Harness" >}}Harness{{< /gloss >}}.
kagent sets the `Data` scope on every ActorTemplate that it generates, for both agents and standalone Sandboxes. Each Actor gets one durable volume named `data`, mounted at `/data`. The only snapshot setting that you configure is the storage location, in the `substrate.snapshotPolicy` section of the {{< gloss "Harness" >}}Harness{{< /gloss >}}.

A suspend keeps the durable volume and discards process memory. A resume therefore starts new containers from the image and restores the saved durable directories. The agent runtimes store what a turn needs in the durable volume, including a pending approval or question, and continue the conversation after the restart.

One scope governs both operations. The ActorTemplate's `onCommit` setting selects what a suspend uploads to snapshot storage, and a pause captures this same scope on the node.

Expand All @@ -46,8 +48,8 @@ A **DurableDir volume** is the per-Actor application data surface. Its contents

Two kinds of snapshot serve different purposes, and both appear in a normal installation.

- The **golden snapshot** is shared by every Actor of one ActorTemplate. Agent Substrate captures it once by booting the workload temporarily when the template is created. Every new Actor of this template starts from this snapshot rather than from a cold start. kagent waits for the golden snapshot before an {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} becomes ready, and the controller reports `waiting for the ActorTemplate golden snapshot` while the capture runs.
- The **last snapshot** belongs to one Actor. Agent Substrate writes it on every suspend and restores this same Actor from it on the next resume. It keeps the files and memory that this one Session built up, so the Session continues from where it stopped.
- The **golden snapshot** is shared by every Actor of one ActorTemplate. Agent Substrate captures it once by booting the workload temporarily when the template is created. Every new Actor of this template starts from this snapshot. kagent waits for the golden snapshot before an {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} becomes ready, and the controller reports `waiting for the ActorTemplate golden snapshot` while the capture runs.
- The **last snapshot** belongs to one Actor. Agent Substrate writes it on every suspend and restores this same Actor from it on the next resume. It keeps the durable files that this one Session built up, so the Session continues from where it stopped.

Agent Substrate writes every snapshot to object storage, so Actor state is durable and portable across the cluster. The supported backends are Google Cloud Storage and Amazon Simple Storage Service (S3), and the S3 client also reaches S3-compatible stores that accept a custom endpoint and path-style addressing. For the settings that select and configure each client, see [Configure snapshot storage]({{< link path="operations/tune-agent-substrate#configure-snapshot-storage" >}}). A {{< gloss "Harness" >}}Harness{{< /gloss >}} names the location for its Actors' snapshots in its `substrate.snapshotPolicy` section.

Expand Down
28 changes: 26 additions & 2 deletions docs-site/content/kagent/1.x/agents/agent-harness.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This page covers the Harness schema, the four harnesses, and what each one suppo

## Configure a Harness

The following configuration shows a complete Harness resource. Only `workload`, `substrate`, and one harness block are required.
The following configuration shows a complete Harness resource. Only `substrate` and one harness block are required. The `byo` harness also requires `workload.image` and `workload.command`.

```yaml
kubectl apply -f - <<EOF
Expand Down Expand Up @@ -41,7 +41,7 @@ EOF
| Field | Required | Description |
| ----- | -------- | ----------- |
| One of `kagent`, `codex`, `claude`, `byo` | Yes | The harness that executes the agent. Naming none, or more than one, is rejected. To compare the four harnesses, see [Choose a harness](#choose-a-harness). |
| `workload.image` | Yes | The container image to run, pinned by `sha256` digest. A tag with no digest is rejected, because a revision must be reproducible. |
| `workload.image` | For `byo` | The container image to run, pinned by `sha256` digest. A tag with no digest is rejected, because a revision must be reproducible. Omit it on a `kagent`, `codex`, or `claude` Harness to run the built-in image of the installed release. For more information, see [Built-in runtime images](#built-in-runtime-images). |
| `workload.command` | For `byo` | Overrides the image entrypoint, up to 32 entries. Required for the `byo` harness, optional otherwise. Every harness honors an explicit value, the `kagent` harness included, regardless of the language its image is written in. |
| `workload.args` | No | Overrides the image arguments, up to 64 entries. An override that you omit stays unset rather than taking a default. |
| `env` | No | Environment variables for the agent process. Each entry sets a literal `value`, which is required and can be an empty string. The schema does not define a secret-backed source, so the API server rejects a `credentialRef` entry as an unknown field. Put credentials in a ModelConfig or a RemoteMCPServer instead. For more information, see [About model providers]({{< link path="setup/model-providers/about-model-providers#credentials-that-do-not-compile" >}}). Limits and reserved names both apply. For more information, see [Environment variables on an Actor](#environment-variables-on-an-actor). |
Expand All @@ -52,6 +52,30 @@ A Harness and an AgentTemplate do not reference each other. An {{< gloss "Agent"

The image, command, arguments, environment, and resolved AgentTemplate together form a {{< gloss "Revision" >}}revision{{< /gloss >}}, which kagent identifies by a digest of that content. Editing any of them produces a new revision at the next reconcile. A {{< gloss "Session" >}}Session{{< /gloss >}} runs the revision that it was created from until that Session ends, so only Sessions that start after the edit use the new revision.

### Built-in runtime images

Each kagent release ships a runtime image for the `kagent`, `codex`, and `claude` harnesses, pinned by digest. If a Harness of one of these types omits `workload.image`, it runs the image of the installed release. If the Harness explicitly sets `workload.image`, this image overrides the release image. After the Agent compiles, `status.workloadImage` reports the image that the Agent's desired revision runs. Existing Sessions keep both the revision and the image that they were created from.

To read the image that an Agent runs, check its status.

```bash
kubectl get agent my-agent -n kagent -o jsonpath='{.status.workloadImage}'
```

To replace the release defaults for the whole installation, set `config.harnessImages` in your Helm values, such as in the following example. Your values merge over the image catalog that the chart packages. `global.imageRegistry` rewrites both the packaged defaults and your overrides, so a mirrored registry needs no further configuration.

```yaml
config:
harnessImages:
kagent: registry.example.com/kagent/golang-adk@sha256:<digest>
codex: registry.example.com/kagent/codex-harness@sha256:<digest>
claude: registry.example.com/kagent/claude-harness@sha256:<digest>
```

The `kagent`, `codex`, and `claude` fields set the digest-pinned default image for each harness. Omit a key to keep the release default for that harness. An empty string disables the default, and a Harness of that type must then set `workload.image`.

The chart also sets `config.harnessImages.release` to the release that the packaged images belong to. When that value does not match the controller's release, the controller fails at startup.

## Choose a harness

A Harness resource names exactly one of the following four harnesses, and that choice decides what executes an agent and how much of kagent's feature set the agent can use.
Expand Down
39 changes: 22 additions & 17 deletions docs-site/content/kagent/1.x/agents/agent-memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,40 @@ Memories are scoped to the agent and to the user who created them, and carry the

Agent memory requires your own PostgreSQL database with the [pgvector](https://github.com/pgvector/pgvector) extension installed. The default database that `kagent install` deploys runs the stock `postgres` image, which omits pgvector, so that database cannot store memories.

1. Install the pgvector extension in your database, in the schema that kagent reads it from. The `config.database.vectorSchema` value names this schema and defaults to `extensions`. Grant `USAGE` on the schema to the role that kagent assumes after it connects, which the `config.database.role` value names. When you leave `config.database.role` empty, grant `USAGE` to the login user.
1. Prepare the database for kagent and create its two connection Secrets. Follow steps 1 - 3 of [Use an external PostgreSQL instance]({{< link path="operations/operational-considerations#use-an-external-postgresql-instance" >}}) to create the `kagent_owner` and `kagent_readwrite` roles and the `my-postgres-owner` and `my-postgres-readwrite` Secrets.

2. Install the pgvector extension in the schema that kagent reads it from. The `config.database.vectorSchema` value names this schema and defaults to `extensions`. Migrations and runtime queries both use the extension, so grant `USAGE` on the schema to both kagent roles.
```sql
CREATE SCHEMA IF NOT EXISTS extensions;
CREATE EXTENSION IF NOT EXISTS vector SCHEMA extensions;
GRANT USAGE ON SCHEMA extensions TO <kagent-user-or-role>;
GRANT USAGE ON SCHEMA extensions TO kagent_owner, kagent_readwrite;
```

The kagent migrations create the memory tables, and they never create the extension. Be sure to install it yourself before you enable memory.

2. Store the connection string for your database in a Kubernetes Secret in the same namespace as the kagent controller.
```bash
kubectl create secret generic my-postgres-url-secret -n kagent \
--from-literal=connectionString='postgres://<username>:<password>@<host>:5432/<database>?sslmode=require'
```

3. Save the following Helm values to point kagent at your database and run the migration that creates the memory tables.
```yaml
cat > kagent-memory-values.yaml <<EOF
database:
postgres:
# Secret holding the connection string.
connectionStringSecretRef:
name: my-postgres-url-secret
key: connectionString
# Secrets holding the two connection strings.
ownerConnectionStringSecretRef:
name: my-postgres-owner
key: ownerConnectionString
readWriteConnectionStringSecretRef:
name: my-postgres-readwrite
key: readWriteConnectionString
# Your database authenticates with passwords, not Pod Certificates.
clientCertificate:
enabled: false
config:
database:
# Use the login user directly. To assume a role instead, create the role in PostgreSQL and set its name here.
role: ""
# Schema that contains the pgvector extension, which you installed in the first step.
# Roles that the setup script created.
owner:
role: kagent_owner
readWrite:
role: kagent_readwrite
# Schema that contains the pgvector extension, which you installed in the preceding step.
vectorSchema: extensions
# Runs the vector migration, which creates the memory tables.
vectorEnabled: true
Expand Down Expand Up @@ -218,7 +223,7 @@ No CLI command manages memories, so these examples call the service with [grpcur
grpcurl -plaintext -d '{
"agent_name": "kagent__NS__my_first_agent_my_first_harness",
"user_id": "admin@kagent.dev"
}' localhost:8083 kagent.api.v1alpha1.MemoryService/List
}' localhost:8083 kagent.runtime.v1.MemoryService/List
```

Each entry returns the `id`, `content`, `access_count`, `created_at`, and `expires_at` fields. Results are ranked by how often retrieval has returned them, so the most-used memories appear first.
Expand All @@ -228,7 +233,7 @@ No CLI command manages memories, so these examples call the service with [grpcur
grpcurl -plaintext -d '{
"agent_name": "kagent__NS__my_first_agent_my_first_harness",
"user_id": "admin@kagent.dev"
}' localhost:8083 kagent.api.v1alpha1.MemoryService/Delete
}' localhost:8083 kagent.runtime.v1.MemoryService/Delete
```

The memory service also exposes `Search`, `AddSession`, and `AddSessionBatch`. Each method takes a 768-dimensional vector rather than text, because kagent does not embed on the caller's behalf. Call them from a program that already has an embedding model, rather than by hand.
Expand Down
Loading
Loading