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

# Skripting und Automatisierung

> Die Social-media-studio-CLI in Skripten, CI/CD-Pipelines und Automatisierungs-Workflows einsetzen

Die CLI ist für Automatisierung gebaut: Sie gibt standardmäßig strukturiertes JSON aus, akzeptiert Zugangsdaten aus Umgebungsvariablen und verwendet Standard-Exit-Codes. Jeder Befehl entspricht 1:1 einem REST-Endpunkt von Social media studio, sodass alles, was die App kann, auch skriptbar ist.

> [!NOTE]
>
> Das Binary heißt `so-me` (der Entwicklungs-Build heißt `so-me-dev`). Alle Beispiele unten verwenden `so-me`. Unterbefehle verwenden die Doppelpunkt-Syntax — `posts:list`, `media:upload`, `agent export-tools`.

## Ausgabemodi

Die Ausgabeformatierung wird über globale Flags gesteuert, die für **jeden** Befehl gelten. Sie müssen zusammen mit deinen übrigen Argumenten in der Kommandozeile stehen (Commander behandelt sie als globale Optionen).

| Flag | Beschreibung |
| - | - |
| `--json` | Ausgabe als formatiertes JSON. **Das ist der Standard** — du musst es selten explizit angeben. |
| `--table` | Gibt die Ergebnisse statt als JSON als lesbare ASCII-Tabelle aus. |
| `--verbose` | Gibt bei einem Fehler die vollständigen Fehlerdetails aus (einschließlich des JS-Stacktraces, sofern verfügbar). |

```bash theme={null}
# JSON ist der Standard
so-me posts:list

# Explizit JSON (wie oben)
so-me posts:list --json

# Lesbare Tabelle
so-me posts:list --table

# Ausführliche Fehlerausgabe (nützlich beim Debuggen)
so-me posts:create -c "test" --platform INVALID --verbose
```

> [!WARNING]
>
> Verwende `--table` für Menschen, nicht für Skripte. Die Tabellenansicht kürzt lange Felder und wählt eine Teilmenge der Spalten aus, sie ist daher **nicht** maschinenlesbar. Leite in der Automatisierung immer das Standard-JSON an `jq` weiter.

Das Standardformat kann auch in der CLI-Konfiguration gespeichert werden (`outputFormat`), aber `--table` in der Kommandozeile gewinnt für diesen Aufruf immer.

## JSON-Ausgabe und jq

Leite jeden Befehl an [`jq`](https://jqlang.github.io/jq/) weiter, um Daten zu extrahieren und umzuformen.

> [!WARNING]
>
> **Listen-Endpunkte geben einen paginierten Umschlag zurück**, kein bloßes Array. Die Form ist `{ "data": [ ... ], "meta": { ... } }`, du musst also mit `.data[]` darauf zugreifen. Befehle für einzelne Objekte (`posts:get`, `posts:create`, `posts:update`, …) geben das Objekt direkt zurück, Felder wie `.id` liegen also auf oberster Ebene.

```bash theme={null}
# Den Text jedes geplanten Beitrags abrufen (beachte .data[] — Listenantworten sind paginiert)
so-me posts:list --status SCHEDULED | jq '.data[].text'

# Die ID des ersten Beitrags holen
so-me posts:list | jq -r '.data[0].id'

# posts:create gibt ein einzelnes Objekt zurück, daher liegt .id auf oberster Ebene
POST_ID=$(so-me posts:create -c "Hello!" --platform TWITTER | jq -r '.id')
echo "Created post: $POST_ID"

# Beiträge nach Plattform zählen
so-me posts:list | jq '.data | group_by(.socialMedia)
  | map({platform: .[0].socialMedia, count: length})'

# Paginierungs-Metadaten lesen
so-me posts:list --limit 100 | jq '.meta'
```

## Paginierung

Listenbefehle akzeptieren zwei Paginierungs-Flags. Es gibt bei Listenbefehlen **kein** Flag `--cursor` oder `--all` — paginiere, indem du `--page` erhöhst.

| Flag | Standard | Hinweise |
| - | - | - |
| `--page <number>` | `1` | Seitennummer, beginnend bei 1. |
| `--limit <number>` | je nach Befehl | Einträge pro Seite. `posts:list` ist auf `100` begrenzt; die Standardwerte unterscheiden sich je Befehl (z. B. `20` bei `posts:list`/`drafts:list`, `50` bei `accounts:list`/`inbox:list`/`teams:list`). |

```bash theme={null}
# Zweite Seite mit 50 Beiträgen
so-me posts:list --page 2 --limit 50

# Jede Seite durchlaufen, bis ein leeres data-Array zurückkommt
page=1
while :; do
  rows=$(so-me posts:list --page "$page" --limit 100 | jq -c '.data')
  [ "$rows" = "[]" ] && break
  echo "$rows" | jq -r '.[].id'
  page=$((page + 1))
done
```

> [!NOTE]
>
> Das Flag `--all` gibt es **nur** bei `agent export-tools`, wo es „jedes Tool-Format ausgeben“ bedeutet — es hat nichts mit Paginierung zu tun.

## Shell-Skripte

### Erstellen und planen

```bash theme={null}
#!/bin/bash
set -euo pipefail

# Einen Beitrag erstellen (wird sofort veröffentlicht, wenn kein -s/--date angegeben ist) und dann planen
POST_ID=$(so-me posts:create \
  -c "Automated post from CI" \
  --platform LINKEDIN \
  | jq -r '.id')

so-me posts:schedule "$POST_ID" \
  -s "$(date -u -d '+1 hour' +%Y-%m-%dT%H:%M:%SZ)"

echo "Post $POST_ID scheduled"
```

> [!NOTE]
>
> `posts:create` löst das Social-Konto automatisch aus `--platform` auf, wenn du `-a/--accounts` nicht angibst. Passen mehrere Konten, fragt der Befehl interaktiv nach — in nicht interaktiver CI gibst du daher mit `-a` eine explizite Konto-ID an oder verlässt dich darauf, dass für diese Plattform nur ein Konto verbunden ist.

### Fehlgeschlagene Beiträge in einem Rutsch löschen

```bash theme={null}
#!/bin/bash
set -euo pipefail

# IDs fehlgeschlagener Beiträge sammeln (denk dran: .data[] bei Listenantworten)
FAILED_IDS=$(so-me posts:list --status FAILED --limit 100 | jq -r '.data[].id')

if [ -z "$FAILED_IDS" ]; then
  echo "No failed posts found"
  exit 0
fi

# posts:delete akzeptiert eine oder mehrere IDs, und -y überspringt die Bestätigungsabfrage
echo "$FAILED_IDS" | xargs so-me posts:delete -y
```

### Alle Entwürfe umwandeln

```bash theme={null}
#!/bin/bash
set -euo pipefail

# Jeden Entwurf in einen geplanten Twitter-Beitrag umwandeln
DRAFT_IDS=$(so-me drafts:list --limit 100 | jq -r '.data[].id')

for id in $DRAFT_IDS; do
  so-me drafts:convert "$id" \
    --platform TWITTER \
    --post-type TEXT \
    -s "$(date -u -d '+2 hours' +%Y-%m-%dT%H:%M:%SZ)"
  echo "Converted draft $id"
done
```

## Authentifizierung für CI

Die CLI sucht Zugangsdaten in dieser Reihenfolge: das Flag `--api-key`, dann die Umgebungsvariable `SOME_API_KEY`, dann der von `auth:login` gespeicherte API-Schlüssel. Für die Automatisierung ist die Umgebungsvariable vorzuziehen, damit nichts auf die Festplatte geschrieben wird.

| Variable | Entsprechendes Flag | Beschreibung |
| - | - | - |
| `SOME_API_KEY` | `--api-key <key>` | API-Schlüssel, mit dem jede Anfrage authentifiziert wird. |
| `SOME_API_URL` | `--api-url <url>` | API-Basis-URL. Standard ist `https://api.so-me.studio` (`so-me-dev` verwendet standardmäßig `http://localhost:8000`). |

```bash theme={null}
# Rein über die Umgebung authentifizieren — kein auth:login nötig
export SOME_API_KEY="sk_live_xxx"
so-me auth:whoami        # Schlüssel verifizieren und authentifizierten Benutzer + Organisation anzeigen
so-me posts:list

# Oder pro Befehl übergeben (überschreibt gespeicherte Zugangsdaten und die Umgebungsvariable)
so-me posts:list --api-key sk_live_xxx --api-url https://api.so-me.studio
```

### GitHub Actions

```yaml theme={null}
name: Schedule Weekly Post
on:
  schedule:
    - cron: '0 9 * * 1'  # Every Monday at 9 AM UTC

jobs:
  post:
    runs-on: ubuntu-latest
    steps:
      - name: Install CLI
        run: npm install -g @social-media-scheduler/cli

      - name: Create and schedule post
        env:
          SOME_API_KEY: ${{ secrets.SOME_API_KEY }}
        run: |
          so-me posts:create \
            -c "Weekly update: check out what's new!" \
            --platform TWITTER \
            -s "$(date -u -d '+1 hour' +%Y-%m-%dT%H:%M:%SZ)"
```

> [!TIP]
>
> Speichere deinen API-Schlüssel als Repository-Secret (`SOME_API_KEY`). Die CLI liest ihn automatisch aus der Umgebung — schreibe den Schlüssel niemals fest in eine Workflow-Datei und committe ihn nicht ins Repository.

## Fehlerbehandlung

### Exit-Codes

Bei einem Fehler setzt die CLI einen Exit-Code ungleich null (`process.exitCode = 1`), sodass `&&`, `set -e` und `if`-Abfragen wie erwartet funktionieren.

| Code | Bedeutung |
| - | - |
| `0` | Erfolg |
| `1` | Fehler — API-Fehler, Validierungsfehler, Netzwerkfehler, fehlende Zugangsdaten usw. |

### Ausführliche Fehler

Mit `--verbose` siehst du die vollständigen Fehlerdetails, einschließlich des Stacktraces, sofern einer verfügbar ist:

```bash theme={null}
so-me posts:create -c "test" --platform INVALID --verbose
```

Häufige Fehlerbedingungen, die der API-Client meldet:

| HTTP-Status | CLI-Meldung |
| - | - |
| `401` | `Invalid API key. Run 'so-me auth:login' or set SOME_API_KEY.` (serverspezifische Meldungen bleiben erhalten, wenn sie aussagekräftiger sind) |
| `403` | `Insufficient permissions. Your plan may not include this feature.` |
| `429` | `Rate limit exceeded. Try again later.` |
| Netzwerk | `Could not connect to API at <url>. Check your internet connection.` |

### Umgang mit Rate Limits

Eine ratenbegrenzte Anfrage (HTTP 429) beendet sich mit Exit-Code 1. Füge in Skripten eine Wiederholungslogik mit Backoff hinzu:

```bash theme={null}
#!/bin/bash
MAX_RETRIES=3
RETRY_DELAY=10

for i in $(seq 1 $MAX_RETRIES); do
  so-me posts:list && break
  echo "Request failed, retrying in ${RETRY_DELAY}s... (attempt $i/$MAX_RETRIES)"
  sleep $RETRY_DELAY
done
```

## Agent-Tool-Definitionen

Die CLI kann den Tool-Katalog von Social media studio in Formaten exportieren, die KI-Agent-Frameworks verarbeiten können. `agent export-tools` ruft die kanonische Tool-Liste **live** vom MCP-Server ab (ein JSON-RPC-Aufruf `tools/list` an `POST /mcp`) und gibt sie im gewählten Format aus. Der MCP-Server ist die einzige Quelle der Wahrheit, daher stimmen exportierte Definitionen immer mit dem Live-Katalog überein.

```bash theme={null}
so-me agent export-tools --format <format> [options]
```

**-f, --format \<format>** `string`

Eines von `mcp`, `openai`, `anthropic`, `hermes`, `openclaw`. Erforderlich, sofern nicht `--all` angegeben ist.

**-o, --out \<path>** `string`

Schreibt die Ausgabe in eine Datei (und legt eventuelle Begleitdateien daneben ab). Sieht der Pfad wie ein Verzeichnis aus (keine Dateiendung oder ein abschließender Schrägstrich), wird der Standarddateiname des Formats angehängt. Wenn weggelassen, wird die Hauptausgabe auf stdout geschrieben.

**--all** `boolean` (default: false)

Gibt **jedes** unterstützte Format aus. Behandelt `--out` als Verzeichnis (Standard `./agent-tools`) und schreibt jedes Format in ein eigenes Unterverzeichnis.

### Unterstützte Formate

| Format | Hauptausgabe | Standarddateiname | Begleitdateien |
| - | - | - | - |
| `mcp` | Roher MCP-Katalog (`{ "tools": [...] }`) | `tools.mcp.json` | — |
| `openai` | Function-Calling-Tools der OpenAI Chat Completions (`{ "tools": [{ "type": "function", "function": { ... } }] }`) | `tools.openai.json` | — |
| `anthropic` | Tools der Anthropic Messages API (flache Form mit `input_schema`) | `tools.anthropic.json` | — |
| `hermes` | OpenAI-kompatibles Tool-JSON (Nous Hermes 4) | `tools.json` | `system_prompt.md`, `tools.md` |
| `openclaw` | Markdown-Skill-Referenz (gruppierte Tool-Tabellen + vollständiger JSON-Schema-Anhang) | `tools.md` | — |

### Beispiele

```bash MCP (stdout) theme={null}
# Den rohen MCP-Tool-Katalog auf stdout ausgeben
so-me agent export-tools --format mcp
```

```bash OpenAI theme={null}
# Funktionsdefinitionen im OpenAI-Stil in eine Datei schreiben
so-me agent export-tools --format openai --out tools.openai.json
```

```bash Anthropic theme={null}
# Das Anthropic-Tool-Use-Format schreiben
so-me agent export-tools --format anthropic --out tools.anthropic.json
```

```bash Hermes theme={null}
# Hermes-Kit — schreibt tools.json plus die Begleitdateien system_prompt.md und tools.md
so-me agent export-tools --format hermes --out ./hermes/
```

```bash OpenClaw theme={null}
# OpenClaw-Skill-Referenz (Markdown). Schreibt tools.md, wenn --out ein Verzeichnis ist
so-me agent export-tools --format openclaw --out tools.md
```

```bash Alle Formate theme={null}
# Jedes Format ausgeben. Jedes landet in einem eigenen Unterverzeichnis unter ./agent-tools,
# z. B. ./agent-tools/mcp/tools.mcp.json, ./agent-tools/hermes/tools.json usw.
so-me agent export-tools --all --out ./agent-tools
```

> [!NOTE]
>
> Jedes Format wird aus derselben `tools/list`-Antwort abgeleitet, daher bleiben exportierte Definitionen mit dem Live-Tool-Katalog synchron. Tool-Namen sind in snake\_case (z. B. `create_post`) und spiegeln die `resource:verb`-Befehle der CLI wider. Über den MCP-Transport werden dieselben Tools als `mcp_so-me-studio_<tool_name>` registriert (z. B. `mcp_so-me-studio_create_post`).

## Selbst gehostete Instanzen

Richte die CLI über das Flag oder die Umgebungsvariable auf eine eigene API-URL aus:

```bash theme={null}
# Per Flag (pro Befehl)
so-me posts:list --api-url https://api.yourdomain.com

# Per Umgebungsvariable (für die ganze Sitzung)
export SOME_API_URL=https://api.yourdomain.com
so-me posts:list
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.