---
name: tllt
description: Use when managing TilliT configuration via the `tllt` CLI — bootstrap a connection (`tllt configure`), snapshot live config (`tllt --json import`), diff snapshots (`tllt --json diff`), or apply changes (`tllt --json deploy`). Invoke whenever the user references TilliT tenants, profiles, the Digital Operations / Scheduler APIs, or wants to import / diff / deploy TilliT entities.
---

# TilliT CLI — agent guide

You are driving `tllt` (`@gotillit/tllt`), a tool for managing TilliT
configuration across three APIs: **Digital Operations (DO)**, **Scheduler**, and
**Wire Flow** (BPMN workflows).

## Setup

If `tllt` is not installed, install it globally:

```bash
npm install -g @gotillit/tllt
```

Verify with `tllt --version`. If the command isn't found after install, the
global bin directory may not be in PATH — run `npm bin -g` to find it.

## How to use this tool effectively

1. **Always pass `--json`.** Structured results go to **stdout**; human progress
   goes to stderr. On failure you get `{"ok": false, "error": "..."}` and a
   non-zero exit code. (Or set `TILLIT_JSON=1`.)
2. **Everything is flag-driven** — never rely on interactive prompts. Supply all
   required flags and commands run non-interactively.
3. **Select a connection with `--profile <name>`** (or rely on the default).

Entity snapshots use `.rdata` files; diff/deploy convert them back to API JSON.
Legacy JSON snapshots remain readable. Schema and routing sidecars stay JSON.
The files follow the platform's RData grammar (the one WMS and APS use), so they
load in the platform toolchain too. See `docs/workflow.md` for the syntax.

## The golden path

```bash
tllt configure --tenant <t> --environment <env> --region <eu|us|au> --auth basic \
  --username <u> --password <p> --default      # bootstrap a connection (once)

tllt --json import --profile <t>-<env>   # snapshot live config to files
tllt --json diff --from <A> --to <B>     # changeset to make B look like A
tllt --json deploy --from <A> --to <B> --dry-run   # preview
tllt --json deploy --from <A> --to <B> --yes --reconcile   # apply + normalize
```

Deploy with `--reconcile`: the server normalizes records on write, so the
snapshot you deployed from drifts and future diffs show phantom updates.
`--reconcile` re-imports the touched entities and folds the normalized values
back into your `--from` snapshot. A value the target did **not** keep is left
in the snapshot and reported under `reconciled.notApplied`, and the deploy
returns `ok: false`. Treat that as a failed change, not noise. Records the
server re-keyed or the import filter hides are renamed or dropped and listed
(`rekeyed`, `filteredOut`).

Deploy validates everything before writing anything. On `code:
"validation_failed"` nothing was applied; each entry in `failures` has a `code`
(`unresolved_ref`, `missing_required`, `target_missing`, …) and a `detail`
naming the field, the key and near-miss `candidates`. Fix the snapshot and
re-run. `--allow-partial` applies the valid changes anyway. `diff` and
`--dry-run` list each update's changed `fields` (`before` = target, `after` =
desired), so you don't need to open both files.

## All commands

| Command     | What it does                                                      |
| ----------- | ----------------------------------------------------------------- |
| `configure` | Bootstrap or update a connection (alias: `init`)                  |
| `profiles`  | List configured connections (alias: `connections`)                |
| `schema`    | Describe an entity data model (fields, types, required, enums)    |
| `import`    | Snapshot a connection's current config into local files            |
| `diff`      | Compare two snapshots and show the changeset                      |
| `deploy`    | Apply the difference between two snapshots to the live target     |
| `api`       | Authenticated pass-through call to the tenant APIs                |
| `check`     | Read-only tenant integrity checks (duplicates, ghosts, collisions)|
| `rename`    | Rename a record id-preservingly, keeping every FK intact          |
| `wireflow`  | Manage Wire Flow BPMN workflows (list, pull, push, activate, …)   |
| `install`   | Install or refresh this skill in `~/.claude/skills/tllt`          |

Run `tllt <command> --help` for full flag reference on any command.

## Reading the full documentation

The detailed docs ship with the npm package. To find them:

```bash
TLLT_DOCS="$(npm root -g)/@gotillit/tllt/docs"
```

Then read files from `$TLLT_DOCS/`:

- `commands.md` — every command, flag, and JSON shape
- `schemas.md` — how to learn each entity's data model (read before editing records)
- `authentication.md` — basic vs api-key/Cognito auth
- `workflow.md` — snapshot layout, diff/deploy semantics
- `apis.md` — the three APIs and what each owns
- `scheduler.md` — how scheduler config differs (important & different)
- `wireflow.md` — Wire Flow: BPMN authoring traps, deploy vs activate, failure shapes

The full agent guide is at `$(npm root -g)/@gotillit/tllt/AGENTS.md`.

## Wire Flow

`tllt wireflow list|pull|validate|push|test|versions|activate|create` manages BPMN
workflows (BPMN XML + config in S3 — not schema-driven, so `import`/`deploy` skip
them). **`push` deploys but does not activate**: the timer keeps running the
previously activated version until `tllt wireflow activate <id>`. Its API sits
beside the gateway at `{region}/wire-flow/api`, not under `{region}/api`.
See `docs/wireflow.md` before touching any BPMN.

## Things that will bite you if you forget

- Before creating/editing a record, **read its schema** — either the
  `_schema.json` in the same folder or `tllt schema <Entity>`. It tells you
  required fields, enums, and what each nested `{name}` reference points at.
- A **connection = environment + tenant**; the profile name is `{tenant}-{environment}`.
- Each connection records a **region** (`eu`, `us`, or `au`). API calls are
  routed through `${baseUrl}/{region}/api[...]`. Re-run
  `tllt configure --region eu|us|au` if a saved profile errors with a
  missing-region message.
- `deploy` matches records across environments by **natural key** (the `name`,
  used as the filename), because volatile `id`/`createdAt`/`updatedAt` are
  stripped on import.
- `deploy` **never deletes** unless you pass `--prune`.
- **If another system owns an entity** (e.g. Operations maintained by a
  master-data sync), pass `--protect-entity` on deploy to prevent accidental
  pruning.
- **Scheduler config is organised per `DataTemplate`** and driven through the
  normalized REST API (`/{locationCode}/{dataTemplateId}/{entity}`). Snapshots
  nest under the template name; global entities (`Location`, `DataTemplate`,
  `OptimisationProfile`) sit at the top. Deploy creates a missing template and
  applies records in dependency order (parents first).
- **For scheduler records, `schema` IS authoritative.** Write shapes match the
  published schema. Nested references are stored by natural key
  (`{ "name": "Bottling" }`) and the CLI resolves them to the target's id on
  deploy.
- **Translations and Articles have side-channels**: the UI reads translations
  from a compiled S3 file and article bodies live behind presigned URLs. Deploy
  handles both automatically; direct API scripts must do the same.
- **`tllt api` with `--paginate`** for full lists — raw GETs cap at 20 rows and
  lie about counts.
- **`tllt check`** after any bulk load or multi-session work on a tenant to
  catch duplicates, ghost order shells, route-less operations, and case collisions.
