> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firetone.com.au/llms.txt
> Use this file to discover all available pages before exploring further.

# Apps, actions and skills

> What lets "press 1 to book" and "I'd like to book" reach the same code, and what decides which of those a virtual agent may do.

Three words, and the middle one is the one that matters.

|            |                                                                                                                                |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **App**    | a capability with a life outside the call: a table, a screen, permissions. Tickets, satisfaction. Switched on per organisation |
| **Action** | one operation an app performs, described once: a name, the arguments it takes, the outcomes it can have                        |
| **Skill**  | an action offered to a virtual agent, as a tool it may choose to use                                                           |

An action has **two callers**: a model deciding mid-conversation, and an IVR
flow node the designer wired. *"Press 1 to book an appointment"* and *"I'd
like to book an appointment"* must reach the same code, or the two paths
drift and one of them is wrong.

That is the whole reason action and skill are separate ideas. The action is
described once; the skill is that description handed to a model.

## What an action carries

* **A name**, unique across every app, because it is also what a model sees.
* **One sentence of description**, shown to the model *and* in the flow
  designer's node palette. Both readers are deciding whether this is the
  thing they want.
* **The arguments it takes**, as a schema. One schema, three consumers: the
  model's tool definition, the designer's form for the node, and the check on
  the server. The form therefore cannot drift from what the handler actually
  accepts.
* **Its outcomes**, which become the **flow node's outlets** and the results a
  model is told about. Every action has at least *ok* and *error*.

<Note>
  Some actions are **agent-only** — they need a live conversation, such as
  summarising what a caller said. They are not offered in the node palette,
  because a flow drawn with one could not run.
</Note>

## What a virtual agent may actually do

The set offered to an agent is an **intersection**, and both halves are
needed:

1. the **apps switched on for the organisation**, and
2. the **skills listed on that profile**.

An app that is off contributes nothing even where a profile lists its
skills — otherwise switching an app off would leave agents still calling into
it. And a skill the profile does not list is not offered even where the app
is on, because two agents in one organisation should differ: a front desk
books appointments and transfers, an after-hours agent takes a message and
nothing else.

<Note>
  The check is made **again when the action runs**, not trusted from when the
  tool list was built. A call can outlive a settings change, and a model told
  about an action at the start of a call will happily use it ten minutes
  after the app was switched off.
</Note>

A **flow node** is filtered only by which apps are on, never by a profile. A
flow node is not an agent, and the designer placing one *is* the decision.

## What exists today

| Action                                            |                                                  |
| ------------------------------------------------- | ------------------------------------------------ |
| `transfer_to_human`                               | hand the call to a person                        |
| `end_call`                                        | finish the conversation                          |
| `request_callback`                                | promise a call back, and raise the ticket for it |
| `search_knowledge`                                | look something up in the knowledge base          |
| `identify_customer`                               | attach the caller to a customer record           |
| `remember`, `learn`                               | keep something the caller said                   |
| `conference_add`                                  | bring somebody else onto the call                |
| `ticket_create`, `ticket_lookup`, `ticket_update` | the tickets app                                  |
| `collect_csat`                                    | ask for a rating, spoken or by keypad            |

The first set are **core**: things done to the call itself. A transfer is not
a record, it is an event, and it is over the moment it happens, so it has no
app, no table and no screen. The rest belong to an app and appear only where
that app is on.

## Arguments are checked before anything runs

Arguments from a model are model output, and an unchecked one reaches a
database or the switch. They are validated against the action's own schema
first: the required fields, their types, any list of allowed values, and any
upper and lower bound.

<Warning>
  A bound the schema states must be a bound the check keeps. This was once
  not true — the rating action declared 1 to 5, a score of 99 passed
  validation, and the handler quietly discarded it, so a model's mistake
  looked like a caller who would not answer. A schema that states a rule and
  does not hold it is worse than one that states nothing.
</Warning>
