> For the complete documentation index, see [llms.txt](https://docs.amigo.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.amigo.ai/developer-guide/guides/build-a-kb-agent-end-to-end.md).

# Build a KB Agent End to End

This guide walks the whole path: get your data into the platform, scope access so each user only sees what their role permits, build the agent, test it, and keep changing it safely. It assumes you are new to the platform and points you to the exact pages and commands at each step. You can do every step yourself.

{% hint style="info" %}
**Read this guide first.** It covers the whole build path. When you reach step 3, the retrieval-architecture decision and the measurement-driven build loop are covered in depth in the companion deep-dive, [Knowledge-Base Agent: Retrieval and Build Methodology](/developer-guide/guides/building-a-knowledge-base-agent.md).
{% endhint %}

**What you'll build:** an agent that answers your team's questions from your own knowledge base, where each user sees only the documents and tools their role allows, and any per-user integration is called as that user.

**The path:**

1. **Load your data** so the platform can serve it.
2. **Assign roles** so each user sees the right data (skip if you don't need per-user scoping).
3. **Build the agent** that finds and grounds answers.
4. **Test it** for answer quality and for correct permissions.
5. **Change, test, and deploy** as you keep improving it.

A few terms used throughout: the **world model** is the platform's normalized store of your data; an **entity** is one record in it (a person, an encounter); a **skill** or **tool** is something the agent can do or call; a **context graph** is the agent's conversation state machine. If any of these are new, skim [Core Concepts](/developer-guide/getting-started/core-concepts.md) first.

## Before you start

* A workspace and platform credentials. See [Authentication & API Keys](/developer-guide/platform-api/platform-api/authentication.md).
* The `forge platform` CLI (used for the commands below), or the console. Either works.
* All commands below use `--env <env>`, which points the CLI at your workspace credentials. The example values (emails, ids, role names) are placeholders; replace them with your own.

## Step 1: Load your data

You are loading two kinds of data: the **documents** your agent answers from (your knowledge base), and, if you'll scope access per user, the **people** who use it (and their roles). There are three self-serve ways to get data into the world model.

### FHIR data (already in a healthcare format)

Push a FHIR bundle and it projects into the world model automatically, no custom code:

```bash
# a FHIR bundle (patients, practitioners, encounters, ...)
curl -X POST "https://api.platform.amigo.ai/v1/${WORKSPACE_ID}/fhir/import" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  --data @bundle.json

# or stream many resources as NDJSON
curl -X POST "https://api.platform.amigo.ai/v1/${WORKSPACE_ID}/fhir/import-stream" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/x-ndjson" \
  --data-binary @resources.ndjson
```

This is the best path for clinicians and patients, which are typically already FHIR (a clinician is a `Practitioner`). See [FHIR](/developer-guide/platform-api/data-world-model/fhir.md).

### A live connection (a connector)

Register a data source and the platform syncs it on a schedule:

```bash
# register a source: a REST API, a SQL / warehouse zone, or a FHIR store
curl -X POST "https://api.platform.amigo.ai/v1/${WORKSPACE_ID}/data-sources" \
  -H "Authorization: Bearer ${API_KEY}" -H "Content-Type: application/json" \
  --data '{ "name": "staff_directory", "source_type": "rest_api", "connection_config": { ... } }'

# trigger a sync now (otherwise it runs on its schedule)
curl -X POST "https://api.platform.amigo.ai/v1/${WORKSPACE_ID}/data-sources/${DATA_SOURCE_ID}/sync" \
  -H "Authorization: Bearer ${API_KEY}"
```

Best for data that changes and should stay fresh. See [Connector Runner](/developer-guide/platform-api/data-world-model/connector-runner.md).

### A file upload

For a one-off file, upload it directly (`POST /v1/{workspace_id}/intake/files`), or create a shareable link so a non-technical teammate can drag-and-drop without an API key:

```bash
curl -X POST "https://api.platform.amigo.ai/v1/${WORKSPACE_ID}/intake/links" \
  -H "Authorization: Bearer ${API_KEY}" -H "Content-Type: application/json" \
  --data '{ "customer_slug": "acme", "display_name": "NPS export" }'
# returns an upload_url you can send to the uploader
```

See [Data Intake](/developer-guide/platform-api/data-world-model/intake.md) and [Intake Upload Links](/developer-guide/platform-api/data-world-model/intake-links.md).

{% hint style="info" %}
**An uploaded file needs one more step before an agent can query it.** FHIR imports and connectors become agent-queryable on their own. A raw file upload (for example a CSV) is stored and logged, but turning it into a structured table the agent can query is not yet automatic, so work with your Amigo contact to set that table up. Once the table exists, you expose it to the agent as a warehouse tool (step 3).
{% endhint %}

### Keeping data current and controlling what's exposed

* **Update:** connectors re-sync on their schedule (or on demand with the `/sync` call above); re-importing a FHIR bundle updates the affected resources.
* **History:** check what a connector synced with `GET /v1/{workspace_id}/data-sources/{id}/sync-history`, and a FHIR resource's version history with `GET /v1/{workspace_id}/fhir/resources/{resource_type}/{resource_id}/history`.
* **Exposure:** which data a given user's agent can actually reach is controlled by role grants (step 2) and by which tables the agent's tools query (step 3), not by the raw data load.

## Step 2: Assign roles so each user sees the right data

Skip this step if every session is the same and there is no per-user scoping.

If different users should see different things (a clinician sees their caseload, a specialist sees specialist procedures, an administrator can't read clinical detail), use **external principals**. The model never decides who the user is: you map each user to an entity and its roles, and the platform scopes the agent's tools and data to those roles and passes the user's identity through to your integrations. Set it up in four commands.

### 2.1 Register your roles

A role is a named bundle that grants attach to. Create one per role your system uses:

```bash
forge platform external-role create --env <env> \
  -b '{"name":"clinician","external_name":"Clinician","description":"Every credentialed clinician"}'

forge platform external-role create --env <env> \
  -b '{"name":"specialist","external_name":"Specialist","description":"Specialist-credentialed clinicians"}'
```

`name` is the internal slug you'll reference; `external_name` is your system's label. List them to get their ids: `forge platform external-role list --env <env>`. (Endpoint: `POST /v1/{workspace_id}/external-roles`.)

### 2.2 Map each user to an entity and roles

Each user is a person entity in the world model (loaded in step 1; `entity_id` is that person's world-model id, which you can look up via [Data & World Model](/developer-guide/platform-api/data-world-model.md)). Bind the user's identity and roles to it:

```bash
forge platform role-assignment upsert --env <env> \
  -b '{
    "source": "staff_directory",
    "external_subject_key": "clinician@example.com",
    "display_name": "Jordan Lee",
    "entity_id": "<clinician-entity-id>",
    "roles": ["clinician"],
    "roles_verified": true,
    "provisioned_via": "roster_sync"
  }'
```

`external_subject_key` is the user's stable identity (usually their email); it's what gets passed through to your integrations. Re-running with the same `(source, external_subject_key)` updates in place, so a roster sync is idempotent. A multi-role user just lists multiple roles and gets the union. (Endpoint: `PUT /v1/{workspace_id}/external-role-assignments`.)

### 2.3 Grant each role its scopes

A grant says "this role may use this resource." `resource_type` is one of `kb_scope` (a scope tag on your documents), `skill` (a skill slug), or `integration_endpoint` (an endpoint id); `access` is `read` or `write`:

```bash
# clinicians can read the general KB scope
forge platform role-grant create --env <env> \
  -b '{"role_id":"<clinician-role-id>","resource_type":"kb_scope","resource_key":"general","access":"read"}'

# ...and call a lookup skill
forge platform role-grant create --env <env> \
  -b '{"role_id":"<clinician-role-id>","resource_type":"skill","resource_key":"clinician-lookup","access":"read"}'

# scope an endpoint param to the caller's own id, so they only see their own data
forge platform role-grant create --env <env> \
  -b '{"role_id":"<clinician-role-id>","resource_type":"integration_endpoint","resource_key":"<endpoint-id>","access":"read","param_binding":"providerId=principal.subject_id"}'
```

A resource is unrestricted until a grant references it; once any grant does, only the granted roles may use it. (Endpoint: `POST /v1/{workspace_id}/role-grants`.)

### 2.4 Anchor the conversation to the user's entity

In production the user's SSO session anchors the conversation automatically. To start one yourself (for testing, or operator-started sessions), pass the entity explicitly:

```bash
forge platform conversation create --env <env> \
  --service-id <text-service-id> \
  --entity-id <clinician-entity-id>
```

From here, every tool call and integration is scoped to that user's roles for the life of the session. For the full reference, see [External Principals](/developer-guide/platform-api/integrations/external-principals.md).

## Step 3: Build the agent

A KB agent has three moving parts: an **index** of your documents the agent can see, a **tool** to fetch a document by id, and a **retrieval strategy**. For a small knowledge base, the simplest strategy wins: preload the whole catalog (titles and ids) so the agent picks the documents it needs and fetches them by id. For a larger corpus, switch to hybrid search.

Build it measurement-first: write the conversations you want the agent to handle as tests, start from a bare-bones agent, and add only what a failing test demands. The agent ends up with exactly the complexity its tests require, and nothing speculative.

### Adding what the agent can do

The agent acts through **skills** and **tools**. A skill is an LLM-driven capability; a tool or platform function calls out to data or an API. Common additions:

* Query a table you loaded in step 1 (for example, ad-hoc analytics): create a **warehouse tool**, a SQL [platform function](/developer-guide/platform-api/functions.md) that selects from your table. The agent calls it like any tool.
* Call an external system: configure an [integration](/developer-guide/platform-api/integrations.md) and expose its endpoints as tools.
* Add a capability: author a [skill](/developer-guide/platform-api/workspaces/skills.md).

{% hint style="info" %}
**If an endpoint the agent needs doesn't exist yet, it has to be built first.** The platform can call an endpoint, but it can't invent one. An API your agent should use that doesn't exist in your systems today is net-new work (by your team or with Amigo) before it can be wired in as an integration.
{% endhint %}

{% hint style="success" %}
The retrieval-architecture decision (catalog-preload vs hybrid search) and the full measurement-driven build loop are covered in depth in [Knowledge-Base Agent: Retrieval and Build Methodology](/developer-guide/guides/building-a-knowledge-base-agent.md). For the moving parts: [Agents](/developer-guide/platform-api/workspaces/agents.md) covers the agent persona, [Agents & Context Graphs](/developer-guide/classic-api/core-api/agents-and-context-graphs.md) covers the context graph (the conversation state machine), and [Skills](/developer-guide/platform-api/workspaces/skills.md) covers capabilities.
{% endhint %}

## Step 4: Test it

Test two things separately.

**Answer quality.** Does the agent fetch the right document, ground its reply in it, and decline when the knowledge base has no answer? Build a fixed question set with known-good answers and run it. That question set is the durable asset: every future change becomes a quick re-run instead of a guess. See [Simulation Coverage](/developer-guide/platform-api/safety/simulation-coverage.md) and [Tool Testing](/developer-guide/platform-api/functions/tool-testing.md).

**Permissions.** Anchor a conversation as a given role and confirm the agent only reaches what that role permits.

{% hint style="info" %}
**Test permissions at the right layer.** Tool and integration-endpoint grants are enforced by the platform: a disallowed tool call returns a structured refusal you can see in the transcript. Knowledge-base document scoping is enforced today by the agent's own behavior reading the user's role context, so verify it by checking the agent's fetches against the role rather than expecting a platform-level block.
{% endhint %}

## Step 5: Change, test, and deploy over time

Once the agent is live you'll keep changing it. Do that safely with version sets and regression tests.

* **Version sets** pin which agent, context graph, and model a service uses, like git branches for your configuration. `edge` always points at your latest; `release` is what production serves. You iterate on a version set, then promote it to `release` to deploy. See [Version Sets & Promotion](/developer-guide/operations/devops/version-sets-best-practices.md).
* **Regression-test before you promote.** Re-run the test set from step 4 against the changed version and compare it to a saved baseline; promote only if it holds. The [methodology guide](/developer-guide/guides/building-a-knowledge-base-agent.md) covers running the suite, saving baselines, and reading the diff.

So the lifecycle is one loop: **change** on a version set, **regression-test** against your suite, **promote** to `release` to deploy. Repeat.

## You're done

You loaded data, scoped access, built an agent, tested it, and have a safe way to keep changing it, end to end. From here: expand your test set as you find gaps, add live-lookup tools for real-time data, and move to hybrid search as the knowledge base grows past the catalog-preload size.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.amigo.ai/developer-guide/guides/build-a-kb-agent-end-to-end.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
