# Lokální API a klíče

> Všechno, co mod umí, pro programy, za klíči, které nesou jen to, cos jim dal.

Source: https://stygion.eu/cs/docs/keystone/api
Updated: 2026-10-09

Keystone odpovídá na HTTP na `127.0.0.1:25586`. Panel je jeden volající, tvoje
vlastní nástroje můžou být další.

```
[api]
enabled = true
address = "127.0.0.1"
port = 25586
reachable-at = ""     # od 0.1.1
```

**Loopback je výchozí a je to ta bezpečná volba.** Cokoliv jiného je dostupné
každému, kdo dosáhne na ten stroj, a API umí všechno, co umí mod. Když ho
potřebuješ z jiného stroje, dej ho za SSH tunel, ne na adresu do světa.

`reachable-at` neřídí, kde se poslouchá — řídí, jakou adresu si mod napíše do
odkazu na editor a do `openapi.json`. Podrobně na stránce [Panel](/docs/keystone/panel).

## Klíče

```
/keystone key new <jméno> <scope> [scope ...]
/keystone key list
/keystone key revoke <id>
/keystone key own <id>
```

Klíč se vypíše **jednou**, když vznikne, a nikdy víc — stejně jako člověk vidí
heslo. Každý klíč má jméno, takže auditní stopa říká, kdo co udělal, a limit na
minutu. `/keystone key new` nedá nic, co by jeho autor sám nemohl dostat.

`Authorization: Bearer <klíč>` u každého volání. Bez klíče přijde `404`, ne
`403`: route, která řekne „zakázáno", právě nepřihlášenému volajícímu prozradila,
že existuje. S pravým klíčem, který nemá scope, jaký ta cesta chce, přijde `403`
a věta, který scope chybí — ten volající už o povrchu ví.

**Klíč si pamatuje, jestli ho dostal vlastník.** `/keystone key list` vlastníkovy
klíče označí a řekne, kdy vznikly. Klíč z doby, kdy se vlastníci nezapisovali (třeba
klíč, kterým obchod zapisuje hodnosti), vlastníkův není, dokud vlastník neřekne
`/keystone key own <id>`; log je při každém startu vyjmenuje. Klíč pojmenovaný
jako jeden z vlastních klíčů modu se do něj nikdy nerozšíří. API nečte nikoho,
než ho zná, a od nikoho víc než megabajt; volání přes MCP prochází stejným
limitem, vlastnickou kontrolou a auditem jako každé jiné.

## Scopy

Klíč nese jen to, co jsi mu dal. Žádost o scope, za kterým na tomhle serveru nic
není, se odmítne — a v tom odmítnutí je vypsané, co existuje, takže se překlep
chytí při výrobě klíče, ne až při použití.

| Scope | Dosáhne na |
|---|---|
| `status.read` | Jestli server běží, kdo je na něm, jak mu je. |
| `players.read` | Lidi — a taky na to, které herní účty má propojený jeden Discord účet. |
| `permissions.read` · `permissions.write` | Skupiny a co smí. |
| `operations.read` · `operations.run` | Rozvrh a spuštění ručně. |
| `settings.read` · `settings.write` | Každé nastavení. |
| `console.read` | Log serveru. |
| `chat.read` | Co se říká. |
| `events.read` | Živý proud (níž). |
| `audit.read` | Kdo co změnil. |
| `keys.read` | Které klíče existují — nikdy jejich tajemství. |
| `backup.read` · `backup.restore` | Zálohy a jejich vrácení. |
| `perks.read` · `perks.write` | Co si kdo zasloužil. |
| `assistant.read` · `assistant.write` | Asistent ve hře. |
| `languages.write` | Překlady, které čtou hráči. |
| `server.read` | Stroj pod tím. |

**Některé scopy jsou vlastníkovy:** `settings.write`, `permissions.write`,
`perks.write`, `backup.restore`, `operations.run`, `assistant.write` a
`languages.write`. Router je hlídá u každého požadavku — i když klíč nese `*`, i
přes MCP — a projdou jen s klíčem vydaným konzoli nebo operátoru úrovně 4. Proto
se skupině, která dosáhla na panel, ukáže editor jen ke čtení a moderaci.

**Dej klíči tu nejužší sadu, která odvede práci.** Monitorovací skript chce
`status.read` a nic dalšího.

## Co tam je

`GET /v1/openapi.json` vypíše každou cestu, kterou tenhle server doopravdy má —
mod si ten dokument píše ze svých vlastních rout, takže se nemůže mýlit v tom,
co existuje. Když chceš seznam, ptej se serveru, ne téhle stránky.

Zhruba: `/v1/status`, `/v1/players` (a `/v1/players/group`, `/v1/players/ungroup`,
`/v1/players/perk`, `/v1/players/check`, `/v1/players/grants`), `/v1/groups`,
`/v1/operations` (`/run`, `/cancel`, `/history`), `/v1/backups` (`/restore`),
`/v1/settings` (`/history`, `/rollback`), `/v1/console`, `/v1/chat`, `/v1/events`,
`/v1/audit`, `/v1/keys`, `/v1/bans`, `/v1/tickets`, `/v1/votes`, `/v1/skins`,
`/v1/progress`, `/v1/metrics` (`/history`), `/v1/bench`, `/v1/catalog`,
`/v1/entities`, `/v1/gate` (`/maintenance`), `/v1/accounts`, `/v1/discord`
(`/links`), `/v1/assistant/*` a `/v1/reload`.

- `POST /v1/settings` s `check=true` jen zeptá, jestli by hodnota prošla, a nic
  nezapíše. Seznam se vrací jako `a, b`, ne `[a, b]`, tedy tak, jak jde zapsat zpět.
- `POST /v1/players/ungroup` (`permissions.write`, pole `player` a `group`) vezme
  zpět jen ty členství ve skupině, které zadal volající klíč — co napsal admin,
  dal Discord nebo jiný klíč, zůstane — a odpoví `{player, group, removed}`;
  `removed: 0` není chyba. `/v1/players/group` a `/ungroup` najdou i hráče, který
  není online, ale na serveru už byl, protože hodnosti se kupují a končí, zatímco
  jsou lidé pryč. Jméno, které server nezná, nebo skupina, která neexistuje, je 400.
- `tick` v `/v1/metrics` je to, co tick stojí teď (z vlastních časů ticku serveru),
  ne 1000 ÷ TPS.

## Živý proud

`GET /v1/events` se scopem `events.read` drží spojení otevřené a píše do něj
události, jak se dějí — díky tomu je panel panel, a ne stránka, kterou musíš
obnovovat. Ověřuje se stejně jako všechno ostatní a bez klíče odpovídá `404`.

## Addony na JVM

Když stavíš addon v Javě, nemluvíš přes HTTP — kompiluješ proti `keystone-api`,
který jede uvnitř toho samého jaru (`META-INF/jarjar/`) a **nemá žádné vlastní
závislosti**, ani logovací. Registruje se přes něj vlastní modul, příkaz,
oprávnění nebo zdroj hodností.

## Co se zapisuje

Každá změna přes API je auditní řádek: kdo, co, kdy. Citlivé příkazy se z něj,
z konzole i z logu maskují — vlastní automaticky, cizí ty, které pojmenuješ v
`keystone.mask-commands`.
