# Routines and groups

Your team of Mets does not just answer: **it learns routines**. A routine is a business process
—create and post on your social media, advertise what you sell, follow up with your customers— that
the team repeats every time: three steps and, at each step, two paths to choose from. Those routines
run in **groups**, where the business's people and their Mets talk and work together (in Met,
"Conversaciones" → "Grupos"). And every time a routine runs, it leaves a **task**.

With the API you **read** all three. Starting a routine, choosing a path, creating a group or adding
someone is done in Met.

## Before you start

Your key needs `routines:read` for routines and `groups:read` for groups. Keys issued before they
existed do not carry them: add them in **Ajustes › Desarrolladores** or issue a new one. They also
work with a test key (`met_test_`), because they only read. The tasks' `origin` field asks for
nothing new: it comes with `tasks:read`, like the rest of the task.

## The business's routines

```ts
import { Met } from '@meteor.ia/sdk';

const met = new Met(process.env.METEOR_API_KEY!);

const { data: routines } = await met.routines.list();
for (const r of routines) {
  console.log(r.id, '—', r.name);
  for (const step of r.steps) {
    console.log(`  ${step.number}. ${step.title}:`, step.paths.map((c) => `${c.title} (${c.done_by})`).join(' / '));
  }
}
```

Each routine carries:

- `id`, `name` and `achieves` (what it achieves, in one or two sentences).
- `steps`: the steps, in order, with the question the Met asks the person at each one.
- `paths` at each step: the paths to choose from, with `done_by` —`met` is done by a Met
  (`met_name` says which), `person` is done by the person, `automatic` is done by Meteor with no AI—.

**Why the paths say who does them.** A routine spends AI only where it is needed: choosing a path
is a button and calls no model, the assignment to the Met is put together from a template, each AI
step is a single delegation to a single Met, its output is validated before it is shown, whatever
publishes or spends ad budget waits for a person's approval, and when it closes you see the Energy of
the whole run. It is the same pattern you can build with your own flows: it is explained in
[Architecture: when a flow, when a Met](architecture-flows-and-mets.html).

**Only the routines available in your business come out.** Some open up gradually: while one is
not available to you, it does not appear in the list and `met.routines.retrieve(id)` answers 404.

**Ids are text, not a closed list.** Today the open routines are `redes`, `anuncios` and
`seguimiento` (and there are others in pilot), but the product adds routines and paths every week.
Treat an id you do not know as one more, not as an error.

## Groups

```ts
for await (const g of met.groups.iterate()) {
  const people = g.members.people.map((p) => `${p.name} (${p.role})`);
  const mets = g.members.mets.map((m) => (m.main ? `${m.name} ★` : m.name));
  console.log(g.title, '·', g.purpose ?? 'no purpose', '·', people.join(', '), '·', mets.join(', '));
}
```

Each group carries what it is for (`purpose`), the routine that runs in it (`routine`, the `id` of
a routine, or `null`) and its members, **separated**:

- `members.people`: the people, with their `role` —`owner` created it, `approver` approves what the
  group's Mets leave waiting, `member` everyone else—.
- `members.mets`: the Mets. The business's main Met comes first, with `main: true`; a people-only
  group does not carry it.

**You only see your groups.** The list carries the groups you are part of —or that the person your
key represents is part of—. Other people's groups are not visible, not even with an administrator
key: it is the same rule as conversations.

**A two-person conversation is not a group.** If only two people are in it, with no purpose or
routine, the app shows it as the conversation with that person, and it does not appear here: not in
the list nor in the detail (`404`). Giving it a purpose, adding someone else or a Met is enough to
make it a group.

The list is always `{ data, has_more, next_cursor }`, from newest group to oldest: pass
`next_cursor` in `starting_after` until `has_more` is `false`, or use `iterate()`.

## Where a task came from

Each task adds `origin`:

```ts
const task = await met.tasks.retrieve('b3e1c0d2-4f5a-4e6b-8c7d-9a0b1c2d3e4f');
if (task.origin?.type === 'routine') {
  console.log('Left by routine', task.origin.routine, 'in group', task.origin.group_id);
}
```

| `origin.type` | What it means |
|---|---|
| `routine` | A routine's run (or its weekly schedule). `routine` says which. |
| `group` | A Met left it while working in a group. |
| `conversation` | A Met left it in a conversation with Mets. |

`group_id` and `conversation_id` only arrive if **you can see** that group or that conversation; if
not, they arrive as `null` and the rest of the origin stays. `origin: null` means the task does not
keep where it came from: a person, the API or an automation created it. If it could not be worked
out in a response, the field does not come. `type` also grows: treat a value you do not know as
"another origin".

## From the MCP connector

The connector has `met_list_routines`, `met_list_groups` and `met_get_group`. Their scopes are not
requested on their own when you connect Claude: an app that wants them has to ask for
`routines:read` and `groups:read` when it registers.

## What you cannot do (yet)

- Start a routine, choose a path or schedule it.
- Create a group, add or remove someone.
- Read a group's messages.

All of that stays in Met.
