From 9263ab8b854d0ec637f8f37d5e4cd9d4484d97f6 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 12 Oct 2026 17:53:45 +0000 Subject: [PATCH 1/3] [Automated] Draft docs (kagent): Bump Substrate to 0.5.0-alpha1 and share PostgreSQL via kagent install Signed-off-by: GitHub Action --- .../1.x/about/architecture/agent-substrate.md | 8 +- .../substrate-runtime/suspend-and-resume.md | 6 +- .../kagent/1.x/about/what-is-kagent.md | 2 +- .../content/kagent/1.x/agents/agent-memory.md | 29 +-- .../content/kagent/1.x/examples/a2a-byo.md | 2 +- .../kagent/1.x/examples/agent-substrate.md | 84 ++------- .../kagent/1.x/examples/agents-via-mcp.md | 89 ++------- .../1.x/get-started/your-first-mcp-tool.md | 2 +- .../kagent/1.x/observability/launch-ui.md | 6 +- .../operations/operational-considerations.md | 61 +++--- .../kagent/1.x/operations/uninstall.md | 44 +++-- .../kagent/1.x/operations/upgrade-from-0x.md | 17 +- .../content/kagent/1.x/setup/installation.md | 175 ++---------------- 13 files changed, 132 insertions(+), 393 deletions(-) diff --git a/docs-site/content/kagent/1.x/about/architecture/agent-substrate.md b/docs-site/content/kagent/1.x/about/architecture/agent-substrate.md index 20c7ec62..9766bd26 100644 --- a/docs-site/content/kagent/1.x/about/architecture/agent-substrate.md +++ b/docs-site/content/kagent/1.x/about/architecture/agent-substrate.md @@ -41,22 +41,24 @@ kagent compiles each ActorTemplate to the sandbox class of the WorkerPool that h Substrate's density model rests on one fact about agent workloads: an Actor spends most of its time idle, waiting on a person or a large language model (LLM) to respond, not actively computing. Substrate exploits that by suspending idle Actors and reclaiming their Worker, then resuming them on demand when traffic arrives. Suspending and resuming allows a WorkerPool to run far more Actors than it has Workers for at any given moment. -The following diagram traces an Actor through one suspend-and-resume cycle, and shows the second path that opens up once the resulting snapshot is tagged. +The following diagram traces an Actor through one suspend-and-resume cycle, and shows how a tag can pin the resulting snapshot.

{{< reuse "kagent-docs/snippets/snapshot-cycle-diagram.md" >}} A **WorkerPool** keeps **Workers** running and ready, and one Worker hosts the **Actor** while its conversation is active. Suspending that Actor writes its full state to an immutable **ActorSnapshot** and frees the Worker that it was running on. -The diagram forks at that snapshot, because a snapshot serves two purposes. +The diagram reaches a tagged snapshot, because a snapshot serves two purposes. - **Resume** restores the same Actor onto **any free Worker in the pool**, 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. -- A **{{< gloss "Tag" >}}Tag{{< /gloss >}}** pins that snapshot, and a **New Actor** can be seeded from the tag at the moment that it is created. Resuming an existing Actor never goes through a tag. +- A **{{< gloss "Tag" >}}Tag{{< /gloss >}}** pins that snapshot so that Agent Substrate does not collect the snapshot. Resuming an existing Actor never goes through a tag. A tag gives a snapshot a stable, human-meaningful name, so callers do not need to track Substrate's internal snapshot identity. A tag names one snapshot permanently, and only its visibility scope can change afterward. A tag also acts as a retention pin, so Substrate does not delete a snapshot while a tag still names it. For example, an agent partway through a long incident investigation reaches a state worth keeping. Creating a [checkpoint]({{< link path="about/substrate-runtime/suspend-and-resume#checkpoints" >}}) tags the snapshot that the agent most recently suspended to, which holds that one snapshot in place while the agent carries on and writes newer ones. Without the tag, Substrate collects that snapshot once a newer one supersedes it. +Checkpoint forks are temporarily unavailable in the current kagent release. Because the snapshots that kagent takes on suspend include process memory, `ForkSession` rejects checkpoint forks with `FAILED_PRECONDITION` instead of restoring processes that still hold the source Session's identifiers. + diff --git a/docs-site/content/kagent/1.x/about/substrate-runtime/suspend-and-resume.md b/docs-site/content/kagent/1.x/about/substrate-runtime/suspend-and-resume.md index 79f66fda..e541486c 100644 --- a/docs-site/content/kagent/1.x/about/substrate-runtime/suspend-and-resume.md +++ b/docs-site/content/kagent/1.x/about/substrate-runtime/suspend-and-resume.md @@ -34,14 +34,14 @@ 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. -Scopes describe only what a snapshot captures, and they are configured per trigger. The `onPause` setting selects what a pause captures on the node, and `onCommit` selects what a suspend uploads to snapshot storage. What `onCommit` captures must be a subset of what `onPause` captures. +Scopes describe only what a snapshot captures. In the current Agent Substrate release, one snapshot scope applies to both pause snapshots on the node and suspend snapshots in snapshot storage. A **DurableDir volume** is the per-Actor application data surface. Its contents are preserved by the `Data` scope, so they survive a suspend and resume cycle independently of process memory. How many volumes an ActorTemplate can declare depends on its sandbox class. A `microvm` template can declare several, because they are subdirectories of a single shared filesystem. A `gvisor` template is limited to one, until {{< gloss "gVisor" >}}gVisor{{< /gloss >}} accepts more than a single durable mount. When an Actor resumes from a `Data`-scope snapshot, the ActorTemplate's `onResume.fromData` setting decides where the rest of the guest state comes from. The default is `ColdBoot`, which starts the containers fresh from the container image with the durable volume contents restored over them. > [!NOTE] -> These scopes describe what Agent Substrate supports, not choices that you make. kagent compiles every ActorTemplate with the same snapshot configuration: `Full` on pause, `Data` on commit, `ColdBoot` on resume, and a single DurableDir volume named `data`. The only snapshot setting that you author is the storage location, on the Harness. +> These scopes describe what Agent Substrate supports, not choices that you make. kagent currently compiles every ActorTemplate with `Full` snapshots, so suspended Actors keep their process memory. The only snapshot setting that you author is the storage location on the Harness. ## Golden and per-Actor snapshots @@ -88,4 +88,4 @@ Creating a checkpoint attaches an Agent Substrate {{< gloss "Tag" >}}Tag{{< /glo A Session must be at a turn boundary to be checkpointed, because the turn boundary is captured. The request names the terminal task to pin. It fails when a newer turn has already started, and again while that turn's snapshot is still being written. -A checkpoint also records how far the conversation had advanced, and it lets you start a second Session from the state it pinned. That second Session, a {{< gloss "Fork" >}}fork{{< /gloss >}}, continues the conversation from the point that the checkpoint pinned, and new turns append only to the fork. A fork receives fresh conversation and task identifiers rather than inheriting the source's. To create a checkpoint and fork a Session from it, work through the [Agent Substrate example]({{< link path="examples/agent-substrate" >}}). +A checkpoint also records how far the conversation had advanced. Forking a checkpoint is temporarily unavailable because kagent's current checkpoints include process memory. `ForkSession` rejects these checkpoints with `FAILED_PRECONDITION` so that a restored Actor does not resume processes that still hold the source Session's identifiers. Forking returns when Agent Substrate lifecycle v2 lets kagent take `Data` snapshots on suspend again. To create and inspect a checkpoint, work through the [Agent Substrate example]({{< link path="examples/agent-substrate" >}}). diff --git a/docs-site/content/kagent/1.x/about/what-is-kagent.md b/docs-site/content/kagent/1.x/about/what-is-kagent.md index 1a0133a6..5fb8428d 100644 --- a/docs-site/content/kagent/1.x/about/what-is-kagent.md +++ b/docs-site/content/kagent/1.x/about/what-is-kagent.md @@ -32,7 +32,7 @@ kagent 1.0 separates an agent's capabilities from its runtime, then runs the two {{< feature-card title="Agent lifecycle via CRDs" desc="Define, version, and roll out Harnesses and AgentTemplates with kubectl and GitOps, the same workflow as every other workload." >}} {{< feature-card title="Sandboxed by default" desc="Every Session runs on a Substrate Actor, isolated from the host kernel by a gVisor sandbox. Run untrusted, model-directed code safely." >}} {{< feature-card title="Suspend and resume" desc="Idle Sessions suspend and free their compute, then resume on demand. Run far more agents than you have capacity for at any one moment." >}} -{{< feature-card title="Checkpoint and fork" desc="Pin a snapshot of a conversation at a turn boundary, then branch a second Session from it that keeps the revision it started with." >}} +{{< feature-card title="Checkpoints" desc="Pin a snapshot of a conversation at a turn boundary so that Agent Substrate keeps the state for inspection and retention." >}} {{< feature-card title="Pluggable agent runtimes" desc="A Harness selects the engine behind an agent: kagent's own Go and Python engines, the Codex or Claude coding agents, or any image of your own that speaks kagent's A2A contract." >}} {{< feature-card title="Tools over MCP" desc="Bind an agent to any Model Context Protocol (MCP) server with a RemoteMCPServer resource. An installation registers two servers already, including 124 tools for Kubernetes, Helm, Istio, and Argo Rollouts." >}} {{< feature-card title="Agent tools" desc="Bind another AgentTemplate as a tool, so an agent can hand work to a specialist. A Shared binding nests that agent inside its parent's Actor, one level deep." >}} diff --git a/docs-site/content/kagent/1.x/agents/agent-memory.md b/docs-site/content/kagent/1.x/agents/agent-memory.md index 3f60481e..29677570 100644 --- a/docs-site/content/kagent/1.x/agents/agent-memory.md +++ b/docs-site/content/kagent/1.x/agents/agent-memory.md @@ -26,36 +26,27 @@ Memories are scoped to the agent and to the user who created them, and carry the ## Before you begin > [!IMPORTANT] -> Memory requires an **external** PostgreSQL database with the [pgvector](https://github.com/pgvector/pgvector) extension installed. kagent's bundled database uses the stock `postgres` image, which does not ship pgvector, so it cannot store memories. Point kagent at your own database first. +> Memory requires an **external** PostgreSQL database with the [pgvector](https://github.com/pgvector/pgvector) extension installed. The development database that `kagent install` creates uses the stock `postgres` image, which does not ship pgvector, so the database cannot store memories. Point kagent at your own database first. -1. Store the connection string for your database in a Kubernetes Secret, in the same namespace as the kagent controller. The key that you choose becomes the file name that kagent reads, so `db-url` produces the path `/var/secrets/db-url`. +1. 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=db-url='postgres://:@:5432/?sslmode=require' + --from-literal=connectionString='postgres://:@:5432/?sslmode=require' ``` -2. Save the following values, which point kagent at your database, mount the Secret into the controller, and run the migration that creates the pgvector extension. +2. Save the following values, which point kagent at your database and run the migration that creates the pgvector extension. ```yaml cat > kagent-memory-values.yaml <}} {{< card link=`{{< link path="agents/bring-your-own-agent" >}}` title="Bring your own agent" subtitle="Read the full A2A contract and the limits of the byo runtime." >}} {{< card link=`{{< link path="examples/a2a-agents" >}}` title="Call an agent over A2A" subtitle="Talk to this Agent with grpcurl instead of the CLI." >}} - {{< card link=`{{< link path="examples/agent-substrate" >}}` title="Agent Substrate" subtitle="Watch the Actor behind your image suspend, checkpoint, and fork." >}} + {{< card link=`{{< link path="examples/agent-substrate" >}}` title="Agent Substrate" subtitle="Watch the Actor behind your image suspend and checkpoint." >}} {{< /cards >}} diff --git a/docs-site/content/kagent/1.x/examples/agent-substrate.md b/docs-site/content/kagent/1.x/examples/agent-substrate.md index 59e56c6e..2a3ce519 100644 --- a/docs-site/content/kagent/1.x/examples/agent-substrate.md +++ b/docs-site/content/kagent/1.x/examples/agent-substrate.md @@ -1,21 +1,30 @@ --- title: Agent Substrate -description: Watch an agent's Actor suspend between turns, pin its state with a checkpoint, and fork that checkpoint into a second agent that continues the conversation. +description: Watch an agent's Actor suspend between turns and pin its state with a checkpoint. weight: 10 author: kagent.dev --- -[Agent Substrate]({{< link path="about/architecture/agent-substrate" >}}) runs every agent as an Actor: a sandboxed unit of compute that holds a {{< gloss "Worker" >}}Worker{{< /gloss >}} only while a turn is in progress, and whose state you can pin and branch. This example follows one agent through all three behaviors. +[Agent Substrate]({{< link path="about/architecture/agent-substrate" >}}) runs every agent as an Actor: a sandboxed unit of compute that holds a {{< gloss "Worker" >}}Worker{{< /gloss >}} only while a turn is in progress. This example follows one agent through suspend, resume, and checkpoint creation. The Actor that these steps follow is also the isolation boundary. Every Actor runs in its own {{< gloss "gVisor" >}}gVisor{{< /gloss >}} sandbox rather than sharing one with its neighbors. This isolation allows a model to safely run tools and execute commands. For what the sandbox blocks, see [Sandboxing]({{< link path="about/substrate-runtime/sandboxing" >}}). ## Before you begin -Checkpoints and {{< gloss "Fork" >}}forks{{< /gloss >}} have no kagent CLI commands yet, so this example calls `CheckpointService` with grpcurl. +Checkpoints have no kagent CLI commands yet, so this example calls `CheckpointService` with grpcurl. {{< reuse "kagent-docs/snippets/grpcurl-prerequisites.md" >}} -5. Create a {{< gloss "Session" >}}Session{{< /gloss >}} and send it a message, then save the Session's ID and the ID of the task that the message produced. A checkpoint pins a completed turn, so the conversation needs at least one. +5. Install `kubectl-ate`, the Agent Substrate command line tool. + ```bash + curl -fsSL -o kubectl-ate \ + "https://github.com/kagent-dev/substrate/releases/download/v{{< reuse "kagent-docs/versions/agent-substrate.md" >}}/kubectl-ate-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" + chmod +x kubectl-ate + sudo mv kubectl-ate /usr/local/bin/ + kubectl ate --help + ``` + +6. Create a {{< gloss "Session" >}}Session{{< /gloss >}} and send it a message. Then save the Session's ID and the ID of the task that the message produced. A checkpoint pins a completed turn, so the conversation needs at least one. ```bash export SESSION_ID=$(kagent agent session create --agent my-first-agent -o json | jq -r '.session.id') export TASK_ID=$(kagent agent invoke --session $SESSION_ID --task "What is 2+2?" -o json | jq -r '.task.id') @@ -112,7 +121,7 @@ Each suspend writes a {{< gloss "Snapshot" >}}snapshot{{< /gloss >}}, and Agent > [!NOTE] > A checkpoint captures a turn boundary, so the named task must be terminal and its snapshot must be written. A newer turn that has already started fails the call with `conversation advanced beyond the expected task`, and a snapshot that is still being written fails it with `snapshot for the expected task is not ready`. The second is safe to retry with the same values; the first needs a newer task ID. -2. Save the checkpoint's `id` to fork from it in the next section. +2. Save the checkpoint's `id` so that you can delete it during cleanup. ```bash export CHECKPOINT_ID= ``` @@ -126,65 +135,11 @@ Each suspend writes a {{< gloss "Snapshot" >}}snapshot{{< /gloss >}}, and Agent Underneath, the checkpoint attaches a {{< gloss "Tag" >}}Tag{{< /gloss >}} named `checkpoint-` to the snapshot, and Agent Substrate does not collect a snapshot while a tag names it. You can see the tag by running `kubectl ate get tags --atespace kagent`. -## Fork the conversation into a second agent - -Forking creates a second Session from the pinned snapshot, running the revision that the checkpoint was taken on. The fork continues the conversation from the checkpoint: it inherits the {{< gloss "Transcript" >}}transcript{{< /gloss >}} up to that point, along with the Actor's durable state. - -> [!NOTE] -> The two branches share everything up to the checkpoint and nothing after it. New turns append only to the Session that received them, so the original's history and the checkpoint itself stay unchanged no matter what the fork goes on to do. Each branch runs its own Actor. - -1. Fork the checkpoint. - ```bash - grpcurl -plaintext \ - -d '{"checkpointId":"'"$CHECKPOINT_ID"'","requestId":"'"$(uuidgen)"'"}' \ - localhost:8083 kagent.api.v1alpha1.CheckpointService/ForkSession - ``` - - The response carries a new Session with its own ID. Example output: - ```json - { - "session": { - "id": "0198c3e5-1d62-7f38-a904-8b3c7e2f5d16", - "agent": { - "namespace": "kagent", - "name": "my-first-agent" - }, - "state": "RUNTIME_STATE_READY", - "contextId": "0198c3e5-1d62-7f38-a904-8b3c7e2f5d16", - "name": "my-first-agent turn 4" - } - } - ``` - - A fork receives fresh conversation and task IDs rather than inheriting the source's, so `contextId` is the fork's own `id`. The transcript it replays stops at the checkpoint's boundary. The fork takes the checkpoint's `name` as its own. - -2. Save the fork's ID, then ask it about a turn that happened before the checkpoint. - ```bash - export FORK_ID= - kagent agent invoke --session $FORK_ID --task "What did I ask you first?" - ``` +## Forking is temporarily unavailable - The fork answers from the conversation it inherited. That is the difference between a fork and a new Session on the same Agent. Send the original a different question and the two diverge from here. +Forking creates a second Session from a checkpoint only when the pinned snapshot contains durable data without process memory. In the current kagent release, suspended Actors use `Full` snapshots so that their process memory survives suspend and resume. A `ForkSession` request for these checkpoints is rejected with `FAILED_PRECONDITION`, because a restored Actor would resume processes that still hold the source Session's identifiers. -3. List your Sessions to verify that both appear as separate conversations. - ```bash - kagent agent session list - ``` - - The two rows share an Agent, and differ in their IDs and creation times. Each one has its own Actor, named `session-`. Example output: - ```console - +--------------------------------------+----------------+-------+----------------------+ - | ID | AGENT | STATE | CREATED | - +--------------------------------------+----------------+-------+----------------------+ - | 0198c3d7-4f2a-7b61-9c3e-5d8f7a2b4e10 | my-first-agent | READY | 2026-08-31T15:02:10Z | - | 0198c3e5-1d62-7f38-a904-8b3c7e2f5d16 | my-first-agent | READY | 2026-08-31T15:14:02Z | - +--------------------------------------+----------------+-------+----------------------+ - ``` - -A fork runs the compiled {{< gloss "Revision" >}}revision{{< /gloss >}} that its checkpoint was taken on, not whatever revision the Agent resolves to now. Editing the Agent after checkpointing does not change what a fork of that checkpoint runs. That stability is the point of a checkpoint: it holds a known-good configuration you can return to, rather than tracking the template as it moves on. - -> [!NOTE] -> A checkpoint can only be forked when its snapshot captured durable data alone. kagent compiles every ActorTemplate to take a `Data`-scope snapshot on commit, so a checkpoint taken on a suspended Session is forkable. A checkpoint whose snapshot also captured process state is rejected with `Checkpoint includes process state and cannot be forked`, because process memory belongs to the one Actor that produced it. +Checkpoint creation is still useful without forking. A checkpoint pins the snapshot for retention, gives the turn boundary a stable record, and keeps the checkpoint visible in the API while the original Session continues. ## Clean up @@ -195,11 +150,6 @@ A fork runs the compiled {{< gloss "Revision" >}}revision{{< /gloss >}} that its localhost:8083 kagent.api.v1alpha1.CheckpointService/DeleteCheckpoint ``` -2. Delete the fork. A fork is a Session in its own right, so deleting the checkpoint that it started from does not remove it. - ```bash - kagent agent session delete $FORK_ID - ``` - ## Next steps {{< cards >}} diff --git a/docs-site/content/kagent/1.x/examples/agents-via-mcp.md b/docs-site/content/kagent/1.x/examples/agents-via-mcp.md index 8c220d25..7a5fdb22 100644 --- a/docs-site/content/kagent/1.x/examples/agents-via-mcp.md +++ b/docs-site/content/kagent/1.x/examples/agents-via-mcp.md @@ -115,9 +115,9 @@ When an agent pauses to ask something, kagent returns the question as an MCP eli This is the same pause that any other client sees, reached through MCP instead of A2A. For the pause types, the approval model, and what the agent receives, see [Human in the loop]({{< link path="agents/human-in-the-loop" >}}). -### Checkpoint and fork +### Checkpoint a Session -You can checkpoint a Session before letting an agent try something risky, then fork that checkpoint to start a second conversation from the pinned state. The client calls the three {{< gloss "Checkpoint" >}}checkpoint{{< /gloss >}} tools, which give it the same operations that the [Agent Substrate example]({{< link path="examples/agent-substrate" >}}) performs from the command line. +You can checkpoint a Session before letting an agent try something risky. The client calls the {{< gloss "Checkpoint" >}}checkpoint{{< /gloss >}} tools, which give the client the same checkpoint operations that the [Agent Substrate example]({{< link path="examples/agent-substrate" >}}) performs from the command line. 1. Ask the client to checkpoint the Session. ```console @@ -126,27 +126,15 @@ You can checkpoint a Session before letting an agent try something risky, then f The client reports the checkpoint's own ID, the turn that it pinned, and a state of `CHECKPOINT_STATE_READY`. Because the client holds that result in context, you can refer to the checkpoint without repeating its ID. -2. Ask the client to fork that checkpoint. - ```console - > Fork that checkpoint. - ``` - - The client reports a second Session with its own ID, already `READY`, on the same Agent as the original. - -3. Ask the fork a question. - ```console - > Ask that fork what 10+5 is. - ``` - - The fork answers `15`. Ask it about an earlier turn and it answers from the conversation it inherited, because a fork continues from the checkpoint rather than starting fresh. +2. Keep the checkpoint ID if you need to inspect or delete the checkpoint later. -The two Sessions share everything up to the checkpoint and nothing after it, because new turns append only to the branch that received them. A fork also runs the {{< gloss "Revision" >}}revision{{< /gloss >}} its checkpoint was taken on, so editing the Agent afterwards does not change what the fork runs. +Forking a checkpoint is temporarily unavailable. The current release stores process memory in suspended Actor snapshots, so `fork_session` returns `FAILED_PRECONDITION` instead of creating a second Session from a checkpoint. You can now safely [clean up these resources](#clean-up). ## Use agents from curl -With `curl` you build each request yourself, so every field is visible: the tool name, its arguments, and the `_meta` that decides whether a call blocks or returns a task to poll. You list the agents in your cluster, hold a conversation with one, answer the agent when it pauses, and checkpoint an instance to fork a second agent from it. Every request is a `tools/call` to `/mcp` unless it names a `tasks/` method, and none of them needs an `initialize` handshake first. +With `curl` you build each request yourself, so every field is visible: the tool name, its arguments, and the `_meta` field that decides whether a call blocks or returns a task to poll. You list the agents in your cluster, hold a conversation with one, answer the agent when it pauses, and checkpoint an instance. Every request is a `tools/call` to `/mcp` unless it names a `tasks/` method, and no request needs an `initialize` handshake first. > [!NOTE] > Do not put `io.modelcontextprotocol/protocolVersion` in a request's `_meta`. The server then requires a matching `Mcp-Protocol-Version` header and rejects the call without one. Neither field is necessary for any of these requests. @@ -416,9 +404,9 @@ When an agent pauses to ask something, the task's status becomes `input_required For the pause types, the approval model, and what the agent receives, see [Human in the loop]({{< link path="agents/human-in-the-loop" >}}). -### Checkpoint and fork +### Checkpoint a Session -The three checkpoint tools pin a Session's state and start a second conversation from it. None of them needs the tasks extension, so none carries `_meta`. +The checkpoint tools pin a Session's state. These tools do not need the tasks extension, so they do not carry `_meta`. 1. Create a checkpoint. `expected_head_task_id` names the terminal task to pin, so the call fails rather than pinning the wrong turn when the conversation has advanced past it. Use the `$TASK_ID` that an earlier invocation returned. The `request_id` is an idempotency key, so repeating the call with the same value returns the checkpoint that the first call created rather than pinning a second one. ```bash @@ -459,7 +447,7 @@ The three checkpoint tools pin a Session's state and start a second conversation export CHECKPOINT_ID= ``` -3. List the instance's checkpoints to confirm what you can fork from. +3. List the Session's checkpoints. ```bash curl -s -X POST http://localhost:8083/mcp \ -H 'Content-Type: application/json' \ @@ -501,78 +489,31 @@ The three checkpoint tools pin a Session's state and start a second conversation } ``` -4. Fork the checkpoint into a second Session. This call takes `checkpoint_id` rather than a Session ID, because the checkpoint already identifies the Session it was taken on. - ```bash - curl -s -X POST http://localhost:8083/mcp \ - -H 'Content-Type: application/json' \ - -H 'Accept: application/json, text/event-stream' \ - -d '{ - "jsonrpc": "2.0", - "id": 8, - "method": "tools/call", - "params": { - "name": "fork_session", - "arguments": { - "checkpoint_id": "'"$CHECKPOINT_ID"'", - "request_id": "my-first-fork" - } - } - }' - ``` - - The result is a new Session with its own ID, already `READY`, on the same Agent as the original. Example output: - ```json - { - "session": { - "id": "01a06d19-7eec-797b-87b8-7397a96b1544", - "harness": "my-first-harness", - "agent_template": "my-first-agent", - "state": "RUNTIME_STATE_READY" - } - } - ``` - -5. Invoke the fork with `invoke_session` and its new ID. A fork receives a new conversation ID, so `context_id` is the fork's own Session ID. Example output: - ```json - { - "session_id": "01a06d19-7eec-797b-87b8-7397a96b1544", - "task_id": "01a06d19-80e7-7554-8288-377eda9e861b", - "context_id": "ce5a10b8-7789-4ba7-8395-e60a339de763", - "state": "TASK_STATE_COMPLETED", - "text": "15" - } - ``` - -A fork runs the {{< gloss "Revision" >}}revision{{< /gloss >}} its checkpoint was taken on, so editing the AgentTemplate afterwards does not change what the fork runs. For what a checkpoint captures, why a checkpoint taken on a suspended instance is the forkable kind, and what a fork does and does not inherit, see [Suspend and resume]({{< link path="about/substrate-runtime/suspend-and-resume" >}}) and the [Agent Substrate example]({{< link path="examples/agent-substrate" >}}). +Forking a checkpoint is temporarily unavailable. The current release stores process memory in suspended Actor snapshots, so `fork_session` returns `FAILED_PRECONDITION` instead of creating a second Session from a checkpoint. For what a checkpoint captures and why forking is rejected, see [Suspend and resume]({{< link path="about/substrate-runtime/suspend-and-resume" >}}) and the [Agent Substrate example]({{< link path="examples/agent-substrate" >}}). You can now safely [clean up these resources](#clean-up). ## Clean up -1. Delete the fork that you created. No MCP tool deletes a Session, so use the kagent command line interface. - ```bash - kagent agent session delete - ``` - -2. Port-forward the controller's gRPC port, and leave the command running. `CheckpointService` listens there rather than on the HTTP port that serves MCP. +1. Port-forward the controller's gRPC port, and leave the command running. `CheckpointService` listens there rather than on the HTTP port that serves MCP. ```bash kubectl port-forward -n kagent svc/kagent-controller 8083:8083 ``` -3. Delete the checkpoint that you created. +2. Delete the checkpoint that you created. ```bash grpcurl -plaintext \ -d '{"checkpointId":""}' \ localhost:8083 kagent.api.v1alpha1.CheckpointService/DeleteCheckpoint ``` -4. Remove the server entry from your client. In Claude Code, run `claude mcp remove kagent`. In Cursor, delete the `kagent` entry from your MCP settings. +3. Remove the server entry from your client. In Claude Code, run `claude mcp remove kagent`. In Cursor, delete the `kagent` entry from your MCP settings. -5. Stop both port-forwards with `Ctrl+C`. +4. Stop both port-forwards with `Ctrl+C`. ## MCP tool reference -The server exposes five Session tools. Two cover discovery and conversation. Three expose the {{< gloss "Checkpoint" >}}checkpoint{{< /gloss >}} operations, so a client can pin and branch an agent's state as well as talk to it. No tool takes a namespace. A Session is addressed by its own UUID. No tool deletes an object either. Deleting a Session takes the `kagent agent session delete` command, and deleting a checkpoint takes a direct call to the gRPC API, because the CLI has no checkpoint command. The server also exposes a set of [standalone sandbox]({{< link path="about/substrate-runtime/standalone-sandboxes" >}}) tools, which this example does not cover. +The server exposes five Session tools. Two cover discovery and conversation. Three expose the {{< gloss "Checkpoint" >}}checkpoint{{< /gloss >}} operations, so a client can pin an agent's state as well as talk to it. No tool takes a namespace. A Session is addressed by its own UUID. No tool deletes an object either. Deleting a Session takes the `kagent agent session delete` command, and deleting a checkpoint takes a direct call to the gRPC API, because the CLI has no checkpoint command. The server also exposes a set of [standalone sandbox]({{< link path="about/substrate-runtime/standalone-sandboxes" >}}) tools, which this example does not cover. | Tool | Required arguments | What it does | | ---- | ------------------ | ------------ | @@ -580,7 +521,7 @@ The server exposes five Session tools. Two cover discovery and conversation. Thr | `invoke_session` | `session_id`, `message` | Sends a message and returns the agent's reply. Takes `message_id` for idempotency. | | `create_session_checkpoint` | `session_id`, `expected_head_task_id` | Pins the conversation at a turn boundary. The call fails if the conversation has advanced past that task. Takes `request_id` for idempotency. | | `list_session_checkpoints` | `session_id` | Lists that Session's checkpoints. Takes `page_size` and `page_token`. | -| `fork_session` | `checkpoint_id` | Creates a new Session from a checkpoint. Takes `request_id` for idempotency. | +| `fork_session` | `checkpoint_id` | Temporarily rejects checkpoints with `FAILED_PRECONDITION` while suspended snapshots include process memory. Takes `request_id` for idempotency. | ## Next steps diff --git a/docs-site/content/kagent/1.x/get-started/your-first-mcp-tool.md b/docs-site/content/kagent/1.x/get-started/your-first-mcp-tool.md index 519d1c03..c2be36ee 100644 --- a/docs-site/content/kagent/1.x/get-started/your-first-mcp-tool.md +++ b/docs-site/content/kagent/1.x/get-started/your-first-mcp-tool.md @@ -185,5 +185,5 @@ kubectl delete remotemcpserver my-mcp-server -n kagent {{< cards >}} {{< card link=`{{< link path="skills-and-mcp/about-tools" >}}` title="About tools" subtitle="Read the full tool binding schema, including binding one AgentTemplate as another agent's subagent." >}} {{< card link=`{{< link path="skills-and-mcp/skills" >}}` title="Skills" subtitle="Give your agent capabilities that no MCP server provides." >}} - {{< card link=`{{< link path="examples/agent-substrate" >}}` title="Agent Substrate" subtitle="Watch your agent's Actor suspend between turns, then checkpoint and fork the conversation." >}} + {{< card link=`{{< link path="examples/agent-substrate" >}}` title="Agent Substrate" subtitle="Watch your agent's Actor suspend between turns, then checkpoint the conversation." >}} {{< /cards >}} diff --git a/docs-site/content/kagent/1.x/observability/launch-ui.md b/docs-site/content/kagent/1.x/observability/launch-ui.md index 412b3b7c..f1b90a02 100644 --- a/docs-site/content/kagent/1.x/observability/launch-ui.md +++ b/docs-site/content/kagent/1.x/observability/launch-ui.md @@ -92,7 +92,7 @@ The **Agents** tab authors the `Agent` custom resource directly. Create one to p ## Read a conversation -Opening an agent and sending a message creates a {{< gloss "Session" >}}Session{{< /gloss >}}, which is one conversation scheduled onto a Substrate {{< gloss "Actor" >}}Actor{{< /gloss >}}. The conversation view shows the transcript, the tool calls the agent made along the way, and the controls that branch the conversation. +Opening an agent and sending a message creates a {{< gloss "Session" >}}Session{{< /gloss >}}, which is one conversation scheduled onto a Substrate {{< gloss "Actor" >}}Actor{{< /gloss >}}. The conversation view shows the transcript, the tool calls the agent made along the way, and the checkpoint controls for the conversation. {{< reuse-image-light src="img/kagent-ui-chat.png" alt="A conversation with an agent, showing a named snapshot and the controls on its mark" caption="Figure: A conversation with an agent" >}} {{< reuse-image-dark srcDark="img/kagent-ui-chat-dark.png" alt="A conversation with an agent, showing a named snapshot and the controls on its mark" caption="Figure: A conversation with an agent" >}} @@ -103,12 +103,12 @@ To take a checkpoint, select the save icon beside the message box. kagent pins t A checkpoint appears in the transcript as a mark carrying the snapshot name and three controls. Select the mark to open the record behind it. The record holds the checkpoint's ID, turn, state, and age. -- **Fork** creates a second Session from the checkpoint, continuing from the point that the checkpoint pinned. A {{< gloss "Fork" >}}fork{{< /gloss >}} inherits the checkpoint's {{< gloss "Revision" >}}Revision{{< /gloss >}}, so later edits to the Agent do not change what it runs, and new turns append only to the fork. The fork takes the snapshot name as its own. For the same operation over the gRPC API, see [Fork the conversation into a second agent]({{< link path="examples/agent-substrate#fork-the-conversation-into-a-second-agent" >}}). +- **Fork** is temporarily unavailable in the current release. The API rejects checkpoint forks with `FAILED_PRECONDITION` while suspended Actor snapshots include process memory. For more information, see [Forking is temporarily unavailable]({{< link path="examples/agent-substrate#forking-is-temporarily-unavailable" >}}). - **Rename** replaces the snapshot name that kagent generates on creation from the Session ID and the turn the checkpoint pins. Clearing the name restores that generated default. - **Delete** removes the checkpoint and releases the snapshot it pinned. Agent Substrate is then free to collect that snapshot. > [!NOTE] -> A checkpoint is always taken at the latest turn boundary, so the UI offers **Fork** on your own most recent message and not on earlier ones. +> A checkpoint is always taken at the latest turn boundary, so the UI offers checkpoint controls on your own most recent message and not on earlier ones. ## Attach files to a message diff --git a/docs-site/content/kagent/1.x/operations/operational-considerations.md b/docs-site/content/kagent/1.x/operations/operational-considerations.md index b64da518..743f7ed5 100644 --- a/docs-site/content/kagent/1.x/operations/operational-considerations.md +++ b/docs-site/content/kagent/1.x/operations/operational-considerations.md @@ -5,67 +5,52 @@ weight: 10 author: kagent.dev --- -A default {{< reuse "kagent-docs/snippets/name-product.md" >}} installation is built for evaluation. It runs one controller replica against a bundled database, and places no constraints on the nodes that run agents. Production changes each of those. +A default {{< reuse "kagent-docs/snippets/name-product.md" >}} installation is built for evaluation. It runs one controller replica against a development database that `kagent install` creates, and places no constraints on the nodes that run agents. Production changes each of those defaults. ## Choose a database -kagent stores conversations, {{< gloss "Session" >}}Sessions{{< /gloss >}}, and compiled {{< gloss "Revision" >}}revisions{{< /gloss >}} in PostgreSQL. A bundled instance ships with the chart so that an evaluation needs no external prerequisites, and production deployments supply their own. +kagent stores conversations, {{< gloss "Session" >}}Sessions{{< /gloss >}}, and compiled {{< gloss "Revision" >}}revisions{{< /gloss >}} in PostgreSQL. The kagent chart no longer deploys or initializes PostgreSQL. The chart reads the connection string from a Kubernetes Secret that you create or that `kagent install` creates for its development database. -Two independent settings determine what runs and what the controller talks to: +For production, run PostgreSQL outside the cluster's lifecycle so that a kagent uninstall cannot delete the data. Create a database role for kagent, or set `database.postgres.role` to an empty string so that kagent uses the login user directly. If you keep the default `kagent_owner` role, grant the role to the login user and give the role `USAGE, CREATE` on the `public` schema. -- `database.postgres.bundled.enabled` determines whether the chart deploys the bundled PostgreSQL pod and its PersistentVolumeClaim (PVC). This setting does not affect which database the controller connects to. -- `database.postgres.url` and `database.postgres.urlFile` determine what the controller connects to. When either is set, the controller uses it. When both are empty, the controller connects to the bundled instance. - -The controller resolves its connection in the order `urlFile`, then `url`, then the bundled connection string. Because the two settings are independent, a bundled pod can keep running while the controller points at an external database, which gives you a window to migrate data across. - -| `bundled.enabled` | `url` or `urlFile` | Bundled pod deployed | Controller connects to | -| ----------------- | ------------------ | -------------------- | ---------------------- | -| `true` | Omitted | Yes | The bundled instance | -| `false` | Set | No | The external instance | -| `true` | Set | Yes | The external instance | -| `false` | Omitted | No | Nothing. The chart fails to render. | - -The last row fails at template time with `No database connection configured`, rather than installing a controller that cannot start. - -The bundled instance claims its PersistentVolumeClaim from the cluster's default StorageClass. Set `database.postgres.bundled.storageClassName` to choose a different one. +`kagent install` creates a development PostgreSQL deployment in the kagent namespace. That database authenticates kagent and Substrate with Pod Certificates, creates the Kagent and Substrate roles, and writes the connection Secrets for both charts. The certificate authorities that the CLI creates are valid for one year, are not renewed automatically, and are kept when you run `kagent install` again. ### Use an external PostgreSQL instance -For production, run PostgreSQL outside the cluster's lifecycle so that a kagent uninstall cannot delete the data. +1. Store the connection string in a Secret in the kagent namespace. -1. Set the connection in your Helm values file. To keep credentials out of Helm values, mount the connection string from a Kubernetes Secret and reference the mount path by using `urlFile`. + ```bash + kubectl create secret generic my-postgres-connection -n kagent \ + --from-literal=connectionString='postgres://:@:5432/?sslmode=require' + ``` + +2. Set the connection Secret in your Helm values file. ```yaml database: postgres: - urlFile: /var/secrets/db-url + connectionStringSecretRef: + name: my-postgres-connection + key: connectionString + role: "" vectorEnabled: true skipMigrations: false pool: maxConns: 20 minConns: 2 - bundled: - enabled: false controller: replicas: 3 - volumes: - - name: db-secret - secret: - secretName: my-postgres-url-secret - volumeMounts: - - name: db-secret - mountPath: /var/secrets - readOnly: true ``` | Setting | Description | | ------- | ----------- | - | `database.postgres.url` or `database.postgres.urlFile` | The connection string, or the path to a file holding it. `urlFile` keeps the credentials out of Helm values. | - | `database.postgres.vectorEnabled` | Set to `true` only when the instance has the `pgvector` extension installed. The setting enables the vector migration, and features that depend on it, such as [long-term memory]({{< link path="agents/agent-memory" >}}), fail without the extension. The bundled image does not include `pgvector`. | + | `database.postgres.connectionStringSecretRef` | The Secret and key that hold the PostgreSQL connection string. Secret changes require a controller restart. | + | `database.postgres.role` | The PostgreSQL role that kagent assumes on every connection. Set it to `""` to use the login user directly. | + | `database.postgres.vectorEnabled` | Set to `true` only when the instance has the `pgvector` extension installed. The setting enables the vector migration, and features that depend on it, such as [long-term memory]({{< link path="agents/agent-memory" >}}), fail without the extension. The development database that `kagent install` creates does not include `pgvector`. | | `database.postgres.pool` | Connection pool sizing, through `maxConns`, `minConns`, `maxConnIdleTime`, and `maxConnLifetime`. Omit the fields to keep the pgx library defaults. | | `database.postgres.skipMigrations` | Set to `true` to stop the controller from running migrations at startup. The controller then verifies that the database is already migrated and fails if it is not. Apply the migrations from a pipeline before you install or upgrade. | -2. Apply the values to the kagent Helm release. +3. Apply the values to the kagent Helm release. ```bash helm upgrade --install kagent \ @@ -75,6 +60,8 @@ For production, run PostgreSQL outside the cluster's lifecycle so that a kagent --values kagent.yaml ``` +If the connection string references client certificate files under `/run/postgres.podcert.ate.dev`, set `database.postgres.clientCertificate.enabled=true`. The controller rereads those files before it opens a new physical connection, so rotated Pod Certificates can take effect without a controller restart. `database.postgres.pool.maxConnLifetime` controls how long a connection that opened with an older certificate can stay in use. + ## Run multiple controller replica To ensure that a controller failure does not stop reconciliation, set `controller.replicas` to a number higher than `1`. @@ -89,7 +76,7 @@ Leader election keeps the replicas from conflicting. One replica holds a Kuberne > [!NOTE] > Leader election is always on, including at a single replica, because a rolling update briefly runs two controllers at once. The chart grants the lease permissions unconditionally and exposes no setting to turn election off. `KAGENT_LEADER_ELECT=false` remains available for local testing. -PostgreSQL supports multiple controller replicas without further configuration. The bundled instance is still a single pod backed by one PVC, so an installation that runs several controllers for availability, against a bundled database, has only moved the single point of failure. +PostgreSQL supports multiple controller replicas without further configuration. A development database that `kagent install` creates is still a single pod backed by one PersistentVolumeClaim, so an installation that runs several controllers for availability against that database has only moved the single point of failure. ## Reserve node pools for Workers @@ -122,12 +109,12 @@ A leader-only worker sweeps once a minute and deletes every Session whose idle c The `168h` default is seven days. There is no per-agent override and no maximum, so this one value governs every conversation in the installation. -Idle time runs from whichever is later: the Session's creation, or its most recently stored A2A event. Reads, renames, lifecycle calls, and retried writes do not reset the clock, so a conversation that is only ever listed still expires. A {{< gloss "Fork" >}}fork{{< /gloss >}} keeps its source's event timestamps. Its own creation time gives it a full lifetime, so it does not inherit an almost-expired one. +Idle time runs from whichever is later: the Session's creation, or its most recently stored A2A event. Reads, renames, lifecycle calls, and retried writes do not reset the clock, so a conversation that is only ever listed still expires. Work in progress is never deleted. A Session with a running task survives past the interval, and so does one with a turn waiting at `INPUT_REQUIRED` or `AUTH_REQUIRED`. A pending lifecycle operation or a checkpoint being captured also holds a Session open. > [!IMPORTANT] -> **Expiry bounds conversations, not history.** Deleting an idle Session removes the Session, its shares, its runtime row, and its creation receipt, and `GetSession` then returns not-found. The A2A context, its tasks, its event history, and any explicit {{< gloss "Checkpoint" >}}checkpoints{{< /gloss >}} stay in PostgreSQL, and a retained checkpoint can still be forked after the Session that it was taken on has expired. Sizing a database for a long-running installation means planning for that audit history separately, because no setting on this page bounds it. +> **Expiry bounds conversations, not history.** Deleting an idle Session removes the Session, its shares, its runtime row, and its creation receipt, and `GetSession` then returns not-found. The A2A context, its tasks, its event history, and any explicit {{< gloss "Checkpoint" >}}checkpoints{{< /gloss >}} stay in PostgreSQL. Sizing a database for a long-running installation means planning for that audit history separately, because no setting on this page bounds it. Unlike an explicit client deletion, which keeps a tombstone, an expired Session releases its creation request ID. The same caller can reuse that request ID to start a fresh conversation. diff --git a/docs-site/content/kagent/1.x/operations/uninstall.md b/docs-site/content/kagent/1.x/operations/uninstall.md index 15c9c488..040cad47 100644 --- a/docs-site/content/kagent/1.x/operations/uninstall.md +++ b/docs-site/content/kagent/1.x/operations/uninstall.md @@ -5,20 +5,19 @@ weight: 50 author: kagent.dev --- -Helm removes what its releases own, but does not uninstall the identity material and some storage that it does not own. +Helm removes what its releases own, but does not uninstall the identity material, development database resources, and some storage that it does not own. Helm removes: - Every `kagent.dev` and `ate.dev` custom resource definition, and with them every Harness, AgentTemplate, WorkerPool, and SandboxConfig in the cluster -- kagent's bundled PostgreSQL volume, holding all conversation state - The object storage volume holding every Actor snapshot -- The `podcertificate-controller-system` namespace, with the service DNS and pod identity CA pools inside it Helm leaves behind: -- The actor identity pools that the install created in `ate-system` with `kubectl ate`, and the `ate-api-authentication` ConfigMap beside them -- Agent Substrate's PostgreSQL volume, `data-postgres-0`, because a StatefulSet volume claim outlives its release -- The `kagent` and `ate-system` namespaces +- The development PostgreSQL Deployment, Service, Secret, and PersistentVolumeClaim that `kagent install` created in the kagent namespace +- The actor identity pools and the `ate-api-authentication` ConfigMap that the install created in `ate-system` +- The service DNS, pod identity, and PostgreSQL certificate authority pools that the install created in `podcertificate-controller-system` +- The `kagent`, `ate-system`, and `podcertificate-controller-system` namespaces This guide includes both Helm steps to uninstall its owned components, and manual steps to remove separate material that can block a later reinstallation. @@ -46,7 +45,7 @@ Remove the kagent release before the CRDs release, because deleting the definiti ``` > [!NOTE] -> The `kagent uninstall` command removes the same two releases in the same order, and it is a convenience rather than a different path. It does not touch Agent Substrate, so the rest of this page still applies. Prefer Helm, for the same reason that the install guide does: the CLI does not manage the Agent Substrate layer. +> The `kagent uninstall` command is a convenience path that removes the same two kagent releases in the same order. It does not remove Agent Substrate or the development PostgreSQL resources that `kagent install` created, so the rest of this page still applies. ## Uninstall Agent Substrate @@ -57,41 +56,56 @@ Agent Substrate is a separate installation in the `ate-system` namespace, and no helm uninstall substrate -n ate-system ``` -2. Uninstall the Agent Substrate CRDs chart, which deletes the `workerpools`, `sandboxconfigs`, and `csidriverconfigs` definitions. +2. Uninstall the Substrate PodCertificate chart. + ```bash + helm uninstall substrate-podcert -n podcertificate-controller-system + ``` + +3. Uninstall the Agent Substrate CRDs chart, which deletes the `workerpools`, `sandboxconfigs`, and `csidriverconfigs` definitions. ```bash helm uninstall substrate-crds -n ate-system ``` ## Remove the identity material -The install created the actor identity pools with the `kubectl ate` plugin instead of Helm, so no release owns them and no uninstall removes them. A later install that tries to create a pool that already exists fails with a message naming the secret. +The `kagent install` command created the identity pools outside Helm, so no release owns them and no uninstall removes them. A later install that tries to create a pool that already exists fails with a message naming the secret. ```console Error: while uploading pool state to secret: secrets "actor-id-jwt-pool" already exists ``` -The service DNS and pod identity CA pools do not need to be manually removed. Because the install created them inside `podcertificate-controller-system`, a namespace that the Agent Substrate chart owns, `helm uninstall substrate` deletes that namespace and the pools along with it. - 1. Delete the actor identity pools and the material derived from them. ```bash kubectl delete secret actor-id-jwt-pool actor-id-ca-pool actor-id-ca-certs -n ate-system kubectl delete configmap ate-api-authentication -n ate-system ``` -2. Delete the Agent Substrate database volume, which a StatefulSet volume claim keeps alive after its release is gone. +2. Delete the service DNS, pod identity, and PostgreSQL CA pools. + ```bash + kubectl delete secret -n podcertificate-controller-system \ + service-dns-ca-pool pod-identity-ca-pool postgres-ca-pool + ``` + +3. Delete the development PostgreSQL resources that `kagent install` created. ```bash - kubectl delete pvc data-postgres-0 -n ate-system + kubectl delete -n kagent \ + deployment/kagent-postgresql \ + service/kagent-postgresql \ + configmap/kagent-postgresql \ + secret/kagent-postgres \ + pvc/kagent-postgresql \ + --ignore-not-found ``` > [!IMPORTANT] -> Deleting `data-postgres-0` matters even if you plan to reinstall immediately. Agent Substrate folds its schema changes into a single baseline migration before release, so a database that survives from an earlier version keeps that migration marked as applied and never picks up the new schema. The cluster then looks healthy and fails later, at the first checkpoint operation. +> Deleting the development PostgreSQL PersistentVolumeClaim removes all conversation state that the development install stored. Back up anything that you need before you delete it. ## Remove the namespaces Deleting the namespaces removes anything that the preceding steps missed, including volumes left by optional components. ```bash -kubectl delete namespace kagent ate-system +kubectl delete namespace kagent ate-system podcertificate-controller-system ``` Confirm that nothing remains. diff --git a/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md b/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md index 67106980..3addd6c2 100644 --- a/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md +++ b/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md @@ -58,19 +58,26 @@ Your Kubernetes resources do carry forward, so export them before anything repla ## Install kagent 1.0 -Install 1.0 the same way as a first-time installation, with one addition: point it at the empty database that you provisioned. The full procedure covers Agent Substrate and the identity material that it needs before you install kagent 1.0. +Install 1.0 the same way as a first-time installation, with one addition: point it at the empty database that you provisioned. The full procedure installs Agent Substrate, kagent, and the identity material that they need. -1. Follow all steps in the [1.0 installation guide]({{< link path="setup/installation" >}}). Set the following Helm values on the kagent install, rather than changing them afterward. +1. Store the connection string for the empty database in a Secret in the new cluster. + ```bash + kubectl create secret generic kagent-upgrade-postgres -n kagent \ + --from-literal=connectionString='postgres://:@:5432/?sslmode=require' + ``` + +2. Follow all steps in the [1.0 installation guide]({{< link path="setup/installation" >}}). Set the following Helm values on the kagent install, rather than changing them afterward. | Value | Why | | ----- | --- | - | `database.postgres.url` | Your new database's connection string. Setting it takes precedence over the bundled instance. Use `urlFile` instead to read the string from a file. | - | `database.postgres.bundled.enabled=false` | Turns off the bundled PostgreSQL instance. The bundled instance is for development and evaluation, and it is not suitable for production. | + | `database.postgres.connectionStringSecretRef.name=kagent-upgrade-postgres` | Reads the connection string from the Secret that you created. | + | `database.postgres.connectionStringSecretRef.key=connectionString` | Names the key in the Secret that holds the connection string. | + | `database.postgres.role=""` | Uses the database login user directly. If you created a separate role such as `kagent_owner`, set that role name instead. | | `database.postgres.vectorEnabled=true` | Applies the pgvector migrations, which [long-term memory]({{< link path="agents/agent-memory" >}}) depends on. Your database must have the pgvector extension installed. | The controller applies migrations at startup. To apply them from a pipeline instead, set `database.postgres.skipMigrations=true` and run `kagent db migrate up` yourself. The controller then verifies the schema and fails if it is not already current. For sizing and connection guidance on the database itself, see [Use an external PostgreSQL instance]({{< link path="operations/operational-considerations#use-an-external-postgresql-instance" >}}). -2. Verify the schema before continuing. +3. Verify the schema before continuing. ```bash kagent db migrate status --db-url "postgres://:@:5432/" ``` diff --git a/docs-site/content/kagent/1.x/setup/installation.md b/docs-site/content/kagent/1.x/setup/installation.md index 62cea1ec..22b43d42 100644 --- a/docs-site/content/kagent/1.x/setup/installation.md +++ b/docs-site/content/kagent/1.x/setup/installation.md @@ -5,7 +5,7 @@ weight: 10 author: kagent.dev --- -{{< reuse "kagent-docs/snippets/name-product.md" >}} 1.0 runs every agent on [Agent Substrate]({{< link path="about/architecture/agent-substrate" >}}), so an installation sets up two systems in the same cluster. Agent Substrate provides the sandboxed compute that agents run on, and kagent provides the Harness, AgentTemplate, and Agent API that you author against. Install Agent Substrate first, because the kagent controller connects to it at startup. +{{< reuse "kagent-docs/snippets/name-product.md" >}} 1.0 runs every agent on [Agent Substrate]({{< link path="about/architecture/agent-substrate" >}}), so an installation sets up two systems in the same cluster. Agent Substrate provides the sandboxed compute that agents run on, and kagent provides the Harness, AgentTemplate, and Agent API that you author against. The `kagent install` command installs kagent, Agent Substrate, and the development PostgreSQL database together. > [!NOTE] > These steps install kagent 1.0 fresh. kagent 1.0 has no in-place upgrade from the 0.10.x version line, and installing its custom resource definitions replaces the ones that a 0.10.x installation uses. To move an existing installation, start with [Upgrade from 0.x]({{< link path="operations/upgrade-from-0x#in-place-upgrade-blockers" >}}). @@ -15,15 +15,10 @@ author: kagent.dev 1. Install the following CLI tools. * [`helm`](https://helm.sh/docs/intro/install/), the Kubernetes package manager. Use Helm 3. * [`kubectl`](https://kubernetes.io/docs/tasks/tools/#kubectl), the Kubernetes command line tool. - * [`jq`](https://jqlang.org/download/), to read the cluster's token issuer and the root certificate out of the generated CA pool. - * [`openssl`](https://www.openssl.org), to convert that certificate to PEM format. - * [`kubectl-ate`](https://github.com/kagent-dev/substrate/releases), the Agent Substrate command line tool, published as a `kubectl` plugin with each Agent Substrate release. + * The kagent CLI, matched to the release that these docs cover. ```bash - curl -fsSL -o kubectl-ate \ - "https://github.com/kagent-dev/substrate/releases/download/v{{< reuse "kagent-docs/versions/agent-substrate.md" >}}/kubectl-ate-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" - chmod +x kubectl-ate - sudo mv kubectl-ate /usr/local/bin/ - kubectl ate --help + curl https://raw.githubusercontent.com/kagent-dev/kagent/refs/heads/main/scripts/get-kagent | bash -s -- --version v{{< reuse "kagent-docs/versions/kagent.md" >}} + kagent version ``` 2. Set your model provider API key. The examples in this guide use OpenAI. For other providers, see [Configure model providers]({{< link path="setup/model-providers" >}}). @@ -74,172 +69,24 @@ author: kagent.dev {{% /tab %}} {{< /tabs >}} -## Install Agent Substrate - -Deploy the Agent Substrate control plane and data plane into the `ate-system` namespace, then create the identity material that its components authenticate with. Agent Substrate signs pod identities and service certificates from certificate authority (CA) pools that you generate, and it authenticates callers against a JSON Web Token (JWT) authority pool. - -> [!IMPORTANT] -> Creating the identity material is required, and no Helm chart performs it for you. Agent Substrate authenticates its components with mutual Transport Layer Security (mTLS), and the identity material that mTLS depends on is created by the `kubectl-ate` plugin, not by Helm. - -1. Install the Agent Substrate custom resource definitions (CRDs). - ```bash - helm upgrade --install substrate-crds \ - oci://ghcr.io/kagent-dev/substrate/helm/substrate-crds \ - --version {{< reuse "kagent-docs/versions/agent-substrate.md" >}} \ - --namespace ate-system --create-namespace - ``` - -2. Install the Agent Substrate control plane and data plane. Do not add `--wait` to this command, because the pods cannot become ready until you create the identity material in the following steps. - - The `credentialProvider.namespacePolicies` value lets agents use the model provider API key. Agents do not hold the key themselves. Instead, the Agent Substrate egress gateway reads the key from a Kubernetes Secret and adds it to each model request. By default, Agent Substrate denies every agent access to every Secret. The following grant lets agents in the `kagent` atespace read Secrets in the `kagent` namespace, where the kagent chart stores the key. Without this grant, all pods report healthy, but every model call fails with a `403` error. - ```bash - helm upgrade --install substrate \ - oci://ghcr.io/kagent-dev/substrate/helm/substrate \ - --version {{< reuse "kagent-docs/versions/agent-substrate.md" >}} \ - --namespace ate-system \ - -f - < [!NOTE] - > An in-cluster issuer, such as `https://kubernetes.default.svc` or `https://kubernetes.default.svc.cluster.local`, publishes no discovery document that a public client can reach, so `certificateAuthorityFile` and `discoveryTokenFile` point the API server at its own projected ServiceAccount certificate authority and token. Omit both lines on a cluster that advertises an external issuer, such as a GKE cluster. `certificateAuthorityFile` replaces the client's root certificate authorities with the cluster's own, so retaining it fails the Transport Layer Security (TLS) handshake against an external issuer. - -8. Roll Agent Substrate out again so that its pods mount the identity material, and wait for them to become ready. - ```bash - helm upgrade substrate \ - oci://ghcr.io/kagent-dev/substrate/helm/substrate \ - --version {{< reuse "kagent-docs/versions/agent-substrate.md" >}} \ - --namespace ate-system --reuse-values --wait --timeout 10m - ``` - -9. Verify that Agent Substrate is running. - ```bash - kubectl get pods -n ate-system - ``` - Example output: - ```console - NAME READY STATUS RESTARTS AGE - ate-api-server-7b66644b7d-87gcr 1/1 Running 0 12m - ate-api-server-7b66644b7d-hxfnp 1/1 Running 0 12m - ate-controller-5dd748fd67-pzg9x 1/1 Running 0 12m - atelet-9qbx8 1/1 Running 0 12m - atenet-egress-68bd5b8768-9pjsp 2/2 Running 0 12m - atenet-router-555b6598fb-vzp6w 2/2 Running 0 12m - k8s-credential-provider-8cf8d559f-ntgtq 1/1 Running 0 12m - postgres-0 2/2 Running 0 12m - rustfs-6c4c677cb6-5c42d 1/1 Running 0 12m - rustfs-bucket-init-qbbln 0/1 Completed 0 12m - ``` - ## Install kagent -The kagent chart connects the controller to Agent Substrate and creates a WorkerPool for agents to run on. A WorkerPool is platform capacity that you provision once, and every Harness references it. No Harness can run until a WorkerPool exists. The values in the following steps are evaluation defaults, including a bundled PostgreSQL instance, one controller replica, and one Worker. For a production installation, add the production values from [Operational considerations]({{< link path="operations/operational-considerations" >}}) to the same command. +The kagent CLI installs the CRDs, Agent Substrate, the Substrate PodCertificate controller, a development PostgreSQL database, and kagent in the correct order. It also creates the Substrate identity material and database connection Secrets that the releases need. -> [!IMPORTANT] -> Install kagent 1.0 with Helm. The `kagent install` command does not yet provision Agent Substrate and cannot produce a working 1.0 installation. - -1. Install the kagent CRDs. +1. Install kagent. The following command enables gRPC server reflection so that guides that use `grpcurl` can discover the controller API. ```bash - helm upgrade --install kagent-crds \ - {{< reuse "kagent-docs/snippets/helm-path.md" >}}/{{< reuse "kagent-docs/snippets/helm-kagent-crds.md" >}} \ - --version {{< reuse "kagent-docs/versions/kagent.md" >}} \ - --namespace kagent --create-namespace --wait - ``` - -2. Install kagent with the Agent Substrate integration enabled. - ```bash - helm upgrade --install kagent \ - {{< reuse "kagent-docs/snippets/helm-path.md" >}}/{{< reuse "kagent-docs/snippets/helm-kagent.md" >}} \ - --version {{< reuse "kagent-docs/versions/kagent.md" >}} \ - --namespace kagent --create-namespace --timeout 10m \ - -f - <}}" - EOF + KAGENT_HELM_EXTRA_ARGS="--set controller.grpc.reflection=true" \ + kagent install --namespace kagent ``` - The `controller.grpc.reflection` setting lets a gRPC client discover the controller's methods without a local copy of kagent's proto files. The kagent CLI does not need it, because the CLI ships with generated clients for every kagent API. Leave reflection on to explore the API with a general-purpose client such as [grpcurl](https://github.com/fullstorydev/grpcurl), and turn it off for a production installation. - + The command uses your provider API key, installs Agent Substrate into `ate-system`, deploys PostgreSQL as `kagent-postgresql` in the kagent namespace, and connects kagent and Substrate to that database with Pod Certificates. The development database does not include the `pgvector` extension and is not intended for production. -3. Wait for the controller to roll out. +2. Wait for the controller to roll out. ```bash kubectl rollout status deployment/kagent-controller -n kagent --timeout=300s ``` - The controller can restart a few times during a first install while it waits for its bundled PostgreSQL database to accept connections. The controller logs `dial tcp ...:5432: connect: connection refused` and then recovers on its own. A restart loop that reports an `ate-api` dial failure instead indicates an incomplete identity bootstrap. + For production database requirements and direct Helm installation, see [Operational considerations]({{< link path="operations/operational-considerations#choose-a-database" >}}). ## Verify the installation From 45d9245dd078babec25b9c422297c009ffec5ffa Mon Sep 17 00:00:00 2001 From: Rachael Graham Date: Tue, 13 Oct 2026 12:46:45 -0500 Subject: [PATCH 2/3] rewrite Signed-off-by: Rachael Graham --- .../content/kagent/1.x/about/architecture/agent-substrate.md | 2 +- .../kagent/1.x/about/substrate-runtime/suspend-and-resume.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs-site/content/kagent/1.x/about/architecture/agent-substrate.md b/docs-site/content/kagent/1.x/about/architecture/agent-substrate.md index cf727f3c..263323b9 100644 --- a/docs-site/content/kagent/1.x/about/architecture/agent-substrate.md +++ b/docs-site/content/kagent/1.x/about/architecture/agent-substrate.md @@ -78,7 +78,7 @@ A **WorkerPool** keeps **Workers** running and ready, and a Worker hosts the **A 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. -- A **{{< gloss "Tag" >}}Tag{{< /gloss >}}** pins this snapshot, and a **New Actor** can be seeded from the tag at the moment that it is created. Resuming an existing Actor never goes through a tag. +- A **{{< gloss "Tag" >}}Tag{{< /gloss >}}** pins this snapshot so that Agent Substrate does not collect it. Seeding a **New Actor** from a tag is unavailable in this release. 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. diff --git a/docs-site/content/kagent/1.x/about/substrate-runtime/suspend-and-resume.md b/docs-site/content/kagent/1.x/about/substrate-runtime/suspend-and-resume.md index d3c6a6da..bf92097e 100644 --- a/docs-site/content/kagent/1.x/about/substrate-runtime/suspend-and-resume.md +++ b/docs-site/content/kagent/1.x/about/substrate-runtime/suspend-and-resume.md @@ -17,7 +17,7 @@ An agent spends most of its life waiting. It waits on a person to reply, and it - **Pause**: Takes a short-term snapshot whose files stay on the node. Pausing pins the Actor to that node, because the following resume is prioritized onto the node that holds the snapshot files. - **Resume**: Restores a suspended or paused Actor onto a Worker, from its latest snapshot. The common path restores from a snapshot rather than cold-booting the workload. -The following diagram traces an Actor through those operations, and shows the further path that opens once a snapshot is [pinned by a tag](#checkpoints). +The following diagram traces an Actor through those operations, and shows what happens once a snapshot is [pinned by a tag](#checkpoints).

{{< reuse "kagent-docs/snippets/snapshot-cycle-diagram.md" >}} @@ -85,7 +85,7 @@ Because kagent suspends at every turn boundary, every message to a Session pays ## Checkpoints -A **checkpoint** marks one point in a conversation and keeps it. You can create a checkpoint when a Session reaches a state worth returning to, such as a long investigation that is only partway through. You can then start a second Session from that point, which is known as a {{< gloss "Fork" >}}fork{{< /gloss >}}. The fork continues the conversation from where the checkpoint marked it, new turns append only to the fork, and the fork gets its own conversation and task identifiers rather than inheriting the source's. To create a checkpoint and fork a Session from it, follow the [Agent Substrate example]({{< link path="examples/agent-substrate" >}}). +A **checkpoint** marks one point in a conversation and keeps it. You can create a checkpoint when a Session reaches a state worth returning to, such as a long investigation that is only partway through. Starting a second Session from that point, which is known as a {{< gloss "Fork" >}}fork{{< /gloss >}}, is unavailable in this release. kagent captures process memory in every snapshot, so `ForkSession` rejects a checkpoint with `FAILED_PRECONDITION` rather than restore an Actor that still holds the source Session's identifiers. To create and inspect a checkpoint, follow the [Agent Substrate example]({{< link path="examples/agent-substrate#forking-is-temporarily-unavailable" >}}). Create a checkpoint only after a turn finishes. The request names the task that the turn ended on, and it fails when a newer turn has already started or while that turn's snapshot is still being written. From ab5dacec5e83cd6f1364e3825338ff1f0939be3e Mon Sep 17 00:00:00 2001 From: Rachael Graham Date: Tue, 13 Oct 2026 14:49:37 -0500 Subject: [PATCH 3/3] wording pass Signed-off-by: Rachael Graham --- docs-site/content/kagent/1.x/observability/launch-ui.md | 2 +- docs-site/content/kagent/1.x/operations/uninstall.md | 6 +++--- docs-site/content/kagent/1.x/setup/installation.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs-site/content/kagent/1.x/observability/launch-ui.md b/docs-site/content/kagent/1.x/observability/launch-ui.md index 2093c7b9..41d5244e 100644 --- a/docs-site/content/kagent/1.x/observability/launch-ui.md +++ b/docs-site/content/kagent/1.x/observability/launch-ui.md @@ -92,7 +92,7 @@ The **Agents** tab authors the `Agent` custom resource directly. Create one to p ## Read a conversation -Opening an agent and sending a message creates a {{< gloss "Session" >}}Session{{< /gloss >}}, which is one conversation scheduled onto a Substrate {{< gloss "Actor" >}}Actor{{< /gloss >}}. The conversation view shows the transcript, the tool calls the agent made along the way, and the checkpoint controls for the conversation. +Opening an agent and sending a message creates a {{< gloss "Session" >}}Session{{< /gloss >}}, which is one conversation scheduled onto an Agent Substrate {{< gloss "Actor" >}}Actor{{< /gloss >}}. The conversation view shows the transcript, the tool calls the agent made along the way, and the checkpoint controls for the conversation. {{< reuse-image-light src="img/kagent-ui-chat.png" alt="A conversation with an agent, showing a named snapshot and the controls on its mark" caption="Figure: A conversation with an agent" >}} {{< reuse-image-dark srcDark="img/kagent-ui-chat-dark.png" alt="A conversation with an agent, showing a named snapshot and the controls on its mark" caption="Figure: A conversation with an agent" >}} diff --git a/docs-site/content/kagent/1.x/operations/uninstall.md b/docs-site/content/kagent/1.x/operations/uninstall.md index 040cad47..95978576 100644 --- a/docs-site/content/kagent/1.x/operations/uninstall.md +++ b/docs-site/content/kagent/1.x/operations/uninstall.md @@ -5,7 +5,7 @@ weight: 50 author: kagent.dev --- -Helm removes what its releases own, but does not uninstall the identity material, development database resources, and some storage that it does not own. +Helm removes what its releases own. No release owns the identity material, the development database resources, or the volume behind that database, so a Helm uninstall leaves all three in the cluster. Helm removes: @@ -56,7 +56,7 @@ Agent Substrate is a separate installation in the `ate-system` namespace, and no helm uninstall substrate -n ate-system ``` -2. Uninstall the Substrate PodCertificate chart. +2. Uninstall the Agent Substrate PodCertificate chart. ```bash helm uninstall substrate-podcert -n podcertificate-controller-system ``` @@ -68,7 +68,7 @@ Agent Substrate is a separate installation in the `ate-system` namespace, and no ## Remove the identity material -The `kagent install` command created the identity pools outside Helm, so no release owns them and no uninstall removes them. A later install that tries to create a pool that already exists fails with a message naming the secret. +The `kagent install` command created the identity pools outside Helm, so no release owns them and no uninstall removes them. A later install that tries to create a pool that already exists fails with a message naming the Secret. ```console Error: while uploading pool state to secret: secrets "actor-id-jwt-pool" already exists diff --git a/docs-site/content/kagent/1.x/setup/installation.md b/docs-site/content/kagent/1.x/setup/installation.md index 22b43d42..3fac438f 100644 --- a/docs-site/content/kagent/1.x/setup/installation.md +++ b/docs-site/content/kagent/1.x/setup/installation.md @@ -71,7 +71,7 @@ author: kagent.dev ## Install kagent -The kagent CLI installs the CRDs, Agent Substrate, the Substrate PodCertificate controller, a development PostgreSQL database, and kagent in the correct order. It also creates the Substrate identity material and database connection Secrets that the releases need. +The kagent CLI installs the CRDs, Agent Substrate, the Agent Substrate PodCertificate controller, a development PostgreSQL database, and kagent in the correct order. It also creates the Substrate identity material and database connection Secrets that the releases need. 1. Install kagent. The following command enables gRPC server reflection so that guides that use `grpcurl` can discover the controller API. ```bash @@ -79,7 +79,7 @@ The kagent CLI installs the CRDs, Agent Substrate, the Substrate PodCertificate kagent install --namespace kagent ``` - The command uses your provider API key, installs Agent Substrate into `ate-system`, deploys PostgreSQL as `kagent-postgresql` in the kagent namespace, and connects kagent and Substrate to that database with Pod Certificates. The development database does not include the `pgvector` extension and is not intended for production. + The command reads your provider API key, installs Agent Substrate into `ate-system`, and deploys PostgreSQL as `kagent-postgresql` in the kagent namespace. It then connects kagent and Agent Substrate to that database with Pod Certificates. The development database runs the stock `postgres` image, which omits the `pgvector` extension that [long-term memory]({{< link path="agents/agent-memory" >}}) needs. 2. Wait for the controller to roll out. ```bash