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

This tutorial creates a small but working agent repo. It uses the public JSONPlaceholder API as a fake support system, so the first deploy does not need secrets, OAuth, or customer data.

By the end, the agent should be able to:

  • read a fake ticket from https://jsonplaceholder.typicode.com/todos/{id}
  • read the related fake customer from /users/{id}
  • follow a triage skill before recommending action
  • write structured investigation notes to a store
  • run evals before promotion
  • show useful sessions, tool calls, logs, and deploy history in Amodal

1. Create The Repo

Create a new 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
evals/
  ticket-triage.md
  account-owner.md

Connect the repo to a new 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",
  "session_types": {
    "default": {
      "prompt": "Help support operators triage demo tickets. Check available data before recommending action. Separate facts from assumptions.",
      "skills": ["triage"],
      "connections": ["support-demo"],
      "stores": {
        "investigation-notes": "rw"
      }
    }
  }
}

Model selection is platform state, not an amodal.json field. If you do not choose a model, the platform default is Gemini 2.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`.
  - `name`, `email`, and `company.name` are safe to summarize.
 
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": {
    "GET /todos/{id}": {
      "returns": ["Ticket"]
    },
    "GET /users/{id}": {
      "returns": ["Customer"]
    }
  },
  "fieldRestrictions": [
    {
      "entity": "Customer",
      "field": "email",
      "policy": "retrieve_but_redact",
      "sensitivity": "pii_name",
      "reason": "Email can help identify the account but should not be repeated unless necessary."
    }
  ]
}

4. Add Knowledge

amodal/knowledge/support-policy.md:

# 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.

Knowledge files are loaded into the agent context at session start. Keep stable policy here; keep step-by-step reasoning in skills.

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 files are visible.
  3. Deploy the current commit.
  4. Open Deploys and wait for the build to complete.
  5. Promote the deploy if it is not already active.

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.

A good answer for ticket 1 should say that it checked ticket 1, identify the issue title, recognize that completed: false means the ticket is still open, load the related user 1, 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 knowledge loaded.
  • Guardrails: confirm the source-backed connection policy lists only read endpoints.
  • Deploys: confirm production points at the deploy that contains these files.

10. Run Evals

Open Evals and run the two eval files. The first run should become your baseline. After that, change one thing at a time, redeploy, and rerun 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.

The mechanics stay the same: repo files define behavior, Amodal deploys a materialized runtime, sessions show what happened, and evals catch regressions before promotion.