Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Tutorial: Build A Support Agent

Build a support agent that reads example tickets and customers from JSONPlaceholder, follows a triage skill, and saves investigation notes. The demo API needs no connection credentials. Model access is provided by your Amodal organization.

1. Create The Repo

Create a GitHub repo with this tree:

amodal.json
amodal/
  connections/support-demo/
    spec.json
    policy.json
    surface.md
  knowledge/
    support-policy.md
  skills/
    triage/SKILL.md
  stores/
    investigation-notes.json
agents/
  default/
    AGENT.md
    agent.json
evals/
  ticket-triage.md
  account-owner.md

Connect the repo to an agent in Amodal, or use Build With A Coding Agent to create and connect it with the Platform API.

2. Add amodal.json

{
  "name": "support-demo",
  "version": "0.1.0",
  "description": "Tutorial agent for support-ticket triage"
}

Add the default chat instructions in agents/default/AGENT.md:

# Support Agent
 
Help the support operator investigate tickets using the support-demo connection.
Load the Triage skill and the support-policy knowledge document before working.
Check the ticket and its customer before recommending an action. Save an investigation note when the operator asks.
Do not include customer email addresses in your answer.

Select its capabilities in agents/default/agent.json:

{
  "name": "Default",
  "tools": ["load_skill", "load_knowledge"],
  "skills": ["Triage"],
  "connections": ["support-demo"],
  "stores": {
    "investigation-notes": "rw"
  }
}

The runtime selects default when a chat request omits agent. AGENT.md is required; a directory containing only agent.json is ignored. Skill entries use the parsed skill name: Triage matches the # Skill: Triage heading below.

Model selection is platform state, not an amodal.json field. If you do not choose a model, the platform default is Gemini 3.5 Flash.

3. Add A Public Connection

amodal/connections/support-demo/spec.json:

{
  "baseUrl": "https://jsonplaceholder.typicode.com",
  "format": "rest",
  "testPath": "/todos/1"
}

This API is public, so there is no auth block and no secret to configure.

amodal/connections/support-demo/surface.md:

# Support Demo API
 
This is a fake support system backed by JSONPlaceholder.
 
Use these read-only endpoints:
 
- `GET /todos/{id}`: load a fake support ticket.
  - `id` is the ticket ID.
  - `userId` is the related customer ID.
  - `title` is the issue summary.
  - `completed` means the issue is resolved.
 
- `GET /users/{id}`: load the fake customer account.
  - `id` is the customer ID from the ticket's `userId`.
  - Summarize `name` and `company.name`; omit `email`.
 
When asked about a ticket, first load `/todos/{id}`. If the ticket includes a `userId`, load `/users/{userId}` before recommending action.

amodal/connections/support-demo/policy.json:

{
  "endpoints": {
    "*": {
      "returns": [],
      "confirm": "never",
      "reason": "This tutorial only reads from the API."
    },
    "GET /todos/{id}": {
      "returns": ["Ticket"]
    },
    "GET /users/{id}": {
      "returns": ["Customer"]
    }
  }
}

The fallback * rule blocks write requests. The GET entries name expected response entities; they do not limit which GET paths can be requested. The prompt asks the model to omit email addresses. This tutorial does not configure enforced field redaction; see Security before using real customer data.

4. Add Knowledge

amodal/knowledge/support-policy.md:

---
description: Rules for reporting support investigations and recommending next actions.
---
 
# Support Policy
 
- State which ticket and customer records were checked.
- Treat `completed: true` as resolved and `completed: false` as still open.
- Separate confirmed facts from assumptions.
- Do not expose credentials, payment tokens, or private internal notes.
- When data is missing, ask for the missing ticket or customer identifier.
- End with one concise next step for the support operator.

The initial prompt lists knowledge documents by name and description. Their bodies are read with load_knowledge, which this agent declares in its tools list. Put reference policy here and task instructions in skills. Instructions that must apply before any tool call belong in AGENT.md.

5. Add A Skill

amodal/skills/triage/SKILL.md:

# Skill: Triage
 
Use this workflow for support-ticket questions.
Trigger: When the user asks about a ticket, customer issue, support case, or next operator action.
 
## Behavior
 
1. Identify the ticket ID from the user message.
2. Load `GET /todos/{id}` from the `support-demo` connection.
3. If the ticket has a `userId`, load `GET /users/{userId}`.
4. Summarize confirmed facts:
   - ticket ID
   - issue title
   - open/resolved state
   - customer name or company when available
5. Recommend one next support action.
6. If useful, write a short record to `investigation-notes`.
 
## Constraints
 
- Do not invent ticket fields that are not returned by the API.
- Do not call write endpoints; this demo connection is read-only.
- If the API call fails, explain that the ticket could not be loaded.

6. Add A Store

amodal/stores/investigation-notes.json:

{
  "name": "investigation-notes",
  "entity": {
    "name": "InvestigationNote",
    "key": "{ticket_id}",
    "schema": {
      "ticket_id": { "type": "string" },
      "summary": { "type": "string" },
      "next_action": { "type": "string" },
      "confidence": {
        "type": "enum",
        "values": ["low", "medium", "high"]
      }
    }
  },
  "history": { "versions": 3 },
  "trace": true
}

This gives the agent a structured place to persist a concise note per ticket. The generated store tools will be named store__investigation_notes__get, store__investigation_notes__set, store__investigation_notes__query, and so on.

7. Add Evals

evals/ticket-triage.md:

# Eval: Ticket Triage
 
Tests whether the agent checks ticket data before recommending action.
 
## Setup
 
Context: Ticket 1 exists in the demo support API.
 
## Query
 
"Triage ticket 1. What should the operator do next?"
 
## Assertions
 
- Should load or reference ticket 1 before answering
- Should identify whether the ticket is open or resolved
- Should provide one concise next action
- Should NOT invent private customer data

evals/account-owner.md:

# Eval: Account Owner
 
Tests whether the agent follows the ticket's userId to the customer record.
 
## Setup
 
Context: Ticket 1 has a related userId.
 
## Query
 
"Who owns ticket 1 and what is the issue?"
 
## Assertions
 
- Should check the ticket record
- Should use the ticket's userId to check the related customer
- Should summarize the issue title
- Should avoid unnecessary personal details

8. Deploy

Commit and push the repo. In Amodal:

  1. Open the agent.
  2. Open Source and confirm the source files are visible.
  3. Open Deploys > Source and deploy the selected version.
  4. Wait for the build and runtime to be ready.
  5. Use Make production when the tested deploy should serve the persistent agent URL.

Before chatting, check Connections. The support-demo connection should show the files from amodal/connections/support-demo/ and the health check should be able to reach /todos/1.

9. Smoke Test

Ask these in the deployed chat:

Triage ticket 1. What should the support operator do next?

Who owns ticket 1, and what company are they associated with?

Triage ticket 2 and save a short investigation note.

The answer should identify the checked ticket, use its returned title and completion state, load the related customer, and give one next support action.

If the answer is generic and does not mention tool data, inspect:

  • Sessions: confirm there is a request tool call.
  • Logs: check for connection, auth, or provider errors.
  • Prompt: confirm the Triage skill and support policy loaded.
  • Guardrails: confirm the connection policy blocks writes.
  • Deploys: confirm production points at the deploy that contains these files.

10. Run Evals

Open Evals and run the two eval files. Review the first run before using it as a baseline. After changing source, redeploy and rerun the evals.

Good first iterations:

  • Tighten amodal/skills/triage/SKILL.md so the agent always loads the related customer.
  • Add a knowledge rule that unresolved tickets should end with a next operator action.
  • Add another eval for ticket 2.
  • Ask the agent to save an investigation note and verify the store tool call appears in the session.

11. What To Build Next

Once this tutorial works, replace the demo API with your real system:

  • Change amodal/connections/support-demo/spec.json to your API base URL and auth.
  • Update surface.md with your real endpoints and field meanings.
  • Tighten policy.json before enabling write endpoints.
  • Add secrets in Amodal instead of committing credentials.
  • Add evals for your highest-risk support behaviors.