T.H.E.R.O.N.
← Back Documentation Plugins

Local API

Automate Theron from your own scripts: create projects, start tasks and answer their questions, create, fill and read task lists, and react to what happens – e.g. a script that syncs a Trello board with Theron, or one that creates tasks from incoming tickets.

Enable

Theron → Settings → Local API: tick Enable local API, choose a port (default 8767), copy the token and save. The API runs while the app runs.

  • Only reachable from this computer (127.0.0.1). Requests with another Host header are refused, so web pages can't reach it.
  • Every request needs the header Authorization: Bearer <token>. Regenerate invalidates the old token.
  • Requests and answers are JSON (Content-Type: application/json). Errors come as {"error": "…"} with 400 (invalid input), 401 (token), 404 (unknown id), 409 (not possible right now, e.g. the project has no process or the task has no open question).
  • Input via the API counts as local input – like typing in the app. Messages are shown as “Local API” in the chat.
export THERON=http://127.0.0.1:8767/v1  THERON_TOKEN=…
curl -H "Authorization: Bearer $THERON_TOKEN" $THERON/status

Endpoints

Method & pathWhat it does
GET /statusVersion and the id of the newest event.
GET /processesProcesses (id, name, steps) – for process_id.
GET /projects
POST /projects
List / create a project: {name, description?, rules?, workspace?, process_id?}. workspace is an absolute path and is created if missing.
GET /projects/{id}
PATCH /projects/{id}
Read / change single fields.
GET /projects/{id}/tasksThe project's tasks, newest first.
POST /projects/{id}/tasksStart a task: {text, title?} – or {tasklist_id} to work through a task list. Needs a process with at least one step.
GET /tasks/{id}?events=50Status (running, waiting_input, done, failed, stopped), summary, goal_reached, the open question in pending_input and optionally the latest events.
POST /tasks/{id}/messagesSend a message to Theron: {text}.
POST /tasks/{id}/answerAnswer the open question: {text, request_id?} (one of pending_input.options or free text).
POST /tasks/{id}/stopStop – {"soon": true} lets the running steps finish first.
GET /projects/{id}/tasklistsTask lists with progress.
POST /projects/{id}/tasklistsCreate a task list, optionally with epics and requirements in one go (see below).
GET /tasklists/{id}
PATCH · DELETE
The full list: epics in execution order with their requirements, status, result and protocol.
POST /tasklists/{id}/epicsAdd an epic: {name, description?, depends_on?, requirements?}.
POST /tasklists/{id}/startStart a task that works through the list.
GET /epics/{id}
PATCH · DELETE
Epic: name, description, depends_on, closed.
POST /epics/{id}/requirementsAdd a requirement: {title, description?, acceptance?, tech_rules?, depends_on?}.
GET /requirements/{id}
PATCH · DELETE
Requirement – status: open, in_progress, hitl, done, failed, skipped, closed; also result.
GET /eventsEvent stream with long polling – see below.

All paths start with /v1. depends_on is a list of epic or requirement ids that have to be done first.

Create a filled task list

curl -X POST $THERON/projects/3/tasklists -H "Authorization: Bearer $THERON_TOKEN" \
  -H "Content-Type: application/json" -d '{
  "name": "Sprint 12",
  "epics": [{"name": "Checkout", "requirements": [
    {"title": "Pay with PayPal", "acceptance": "Payment is booked, order confirmed"},
    {"title": "Invoice as PDF"}]}]}'

Events

GET /events?since=<id>&wait=30 returns the events after since (oldest first) and next – pass it as since in the next call. With wait (max. 60 s) the request waits until something happens. since=-1 starts with what happens from now on. Filters: project, task, types=a,b.

TypeMeaning
statusTask status changed (status, phase).
input_requestTheron asks: request_id, question, options, recommended.
input_resolvedA question was answered.
completeTask finished: summary, goal_reached.
requirement_start · requirement_status · requirement_done Task list progress, with requirement_id (and success when done).
alert⚑ message from the process (level, text, stop).
orchestrator · userChat messages.
agent_start · agent_end · handoverAgent steps.

Example: sync with Trello (Python)

Cards of a Trello list become requirements; when Theron finishes one, the card moves to “Done”. Only the standard library is needed; the Trello calls are left as functions to fill in.

import json, os, urllib.request

API, TOKEN = "http://127.0.0.1:8767/v1", os.environ["THERON_TOKEN"]

def theron(method, path, body=None):
    req = urllib.request.Request(API + path, method=method, data=json.dumps(body).encode() if body else None,
                                 headers={"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"})
    with urllib.request.urlopen(req, timeout=90) as r:
        return json.load(r)

cards = trello_cards("To do")                       # your Trello call: [{"id", "name", "desc"}, …]
tl = theron("POST", "/projects/3/tasklists", {"name": "Trello", "epics": [{"name": "Board", "requirements": [
    {"title": c["name"], "description": c["desc"]} for c in cards]}]})
card_of = {r["id"]: c["id"] for c, r in zip(cards, tl["epics"][0]["requirements"])}   # same order
task = theron("POST", f"/tasklists/{tl['id']}/start", {})

since = theron("GET", "/status")["last_event"]
while True:
    page = theron("GET", f"/events?since={since}&wait=60&task={task['id']}")
    since = page["next"]
    for ev in page["events"]:
        if ev["type"] == "requirement_done" and ev["success"]:
            trello_move(card_of[ev["requirement_id"]], "Done")
        elif ev["type"] == "input_request":
            print("Theron asks:", ev["question"], ev["options"])   # answer: POST /tasks/{id}/answer
        elif ev["type"] == "complete":
            raise SystemExit(ev["summary"])

Lokale API

Steuere Theron aus eigenen Skripten: Projekte anlegen, Tasks starten und ihre Rückfragen beantworten, Task-Listen anlegen, befüllen und lesen und auf Ereignisse reagieren – z. B. ein Skript, das ein Trello-Board mit Theron synchronisiert, oder eines, das aus eingehenden Tickets Tasks erzeugt.

Aktivieren

Theron → Einstellungen → Lokale API: Lokale API aktivieren anhaken, Port wählen (Standard 8767), Token kopieren und speichern. Die API läuft, solange die App läuft.

  • Nur von diesem Rechner erreichbar (127.0.0.1). Anfragen mit anderem Host-Header werden abgewiesen – Webseiten kommen also nicht heran.
  • Jede Anfrage braucht den Header Authorization: Bearer <Token>. Neu erzeugen macht den alten Token ungültig.
  • Anfragen und Antworten sind JSON (Content-Type: application/json). Fehler kommen als {"error": "…"} mit 400 (ungültige Eingabe), 401 (Token), 404 (unbekannte ID), 409 (gerade nicht möglich, z. B. Projekt ohne Prozess oder keine offene Rückfrage).
  • Eingaben über die API gelten als lokale Eingaben – wie in der App getippt. Im Chat stehen sie als „Lokale API“.
export THERON=http://127.0.0.1:8767/v1  THERON_TOKEN=…
curl -H "Authorization: Bearer $THERON_TOKEN" $THERON/status

Endpunkte

Methode & PfadWas passiert
GET /statusVersion und ID des neuesten Ereignisses.
GET /processesProzesse (ID, Name, Schritte) – für process_id.
GET /projects
POST /projects
Projekte auflisten / anlegen: {name, description?, rules?, workspace?, process_id?}. workspace ist ein absoluter Pfad und wird bei Bedarf angelegt.
GET /projects/{id}
PATCH /projects/{id}
Lesen / einzelne Felder ändern.
GET /projects/{id}/tasksDie Tasks des Projekts, neueste zuerst.
POST /projects/{id}/tasksTask starten: {text, title?} – oder {tasklist_id}, um eine Task-Liste abzuarbeiten. Braucht einen Prozess mit mindestens einem Schritt.
GET /tasks/{id}?events=50Status (running, waiting_input, done, failed, stopped), summary, goal_reached, die offene Rückfrage in pending_input und auf Wunsch die letzten Ereignisse.
POST /tasks/{id}/messagesNachricht an Theron: {text}.
POST /tasks/{id}/answerOffene Rückfrage beantworten: {text, request_id?} (eine der pending_input.options oder freier Text).
POST /tasks/{id}/stopStoppen – {"soon": true} lässt laufende Schritte erst fertig werden.
GET /projects/{id}/tasklistsTask-Listen mit Fortschritt.
POST /projects/{id}/tasklistsTask-Liste anlegen, auf Wunsch gleich mit Epics und Requirements (siehe unten).
GET /tasklists/{id}
PATCH · DELETE
Die ganze Liste: Epics in Ausführungsreihenfolge mit ihren Requirements, Status, Ergebnis und Protokoll.
POST /tasklists/{id}/epicsEpic hinzufügen: {name, description?, depends_on?, requirements?}.
POST /tasklists/{id}/startTask starten, der die Liste abarbeitet.
GET /epics/{id}
PATCH · DELETE
Epic: name, description, depends_on, closed.
POST /epics/{id}/requirementsRequirement hinzufügen: {title, description?, acceptance?, tech_rules?, depends_on?}.
GET /requirements/{id}
PATCH · DELETE
Requirement – status: open, in_progress, hitl, done, failed, skipped, closed; dazu result.
GET /eventsEreignisse per Long-Polling – siehe unten.

Alle Pfade beginnen mit /v1. depends_on ist eine Liste von Epic- bzw. Requirement-IDs, die vorher erledigt sein müssen.

Befüllte Task-Liste anlegen

curl -X POST $THERON/projects/3/tasklists -H "Authorization: Bearer $THERON_TOKEN" \
  -H "Content-Type: application/json" -d '{
  "name": "Sprint 12",
  "epics": [{"name": "Checkout", "requirements": [
    {"title": "Mit PayPal bezahlen", "acceptance": "Zahlung gebucht, Bestellung bestätigt"},
    {"title": "Rechnung als PDF"}]}]}'

Ereignisse

GET /events?since=<id>&wait=30 liefert die Ereignisse nach since (älteste zuerst) und next – das gibst du beim nächsten Aufruf als since mit. Mit wait (max. 60 s) wartet die Anfrage, bis etwas passiert. since=-1 beginnt bei allem, was ab jetzt passiert. Filter: project, task, types=a,b.

TypBedeutung
statusStatus des Tasks geändert (status, phase).
input_requestTheron fragt: request_id, question, options, recommended.
input_resolvedEine Rückfrage wurde beantwortet.
completeTask abgeschlossen: summary, goal_reached.
requirement_start · requirement_status · requirement_done Fortschritt der Task-Liste, mit requirement_id (und success am Ende).
alert⚑ Meldung aus dem Prozess (level, text, stop).
orchestrator · userChat-Nachrichten.
agent_start · agent_end · handoverSchritte der Agents.

Beispiel: Synchronisation mit Trello (Python)

Karten einer Trello-Liste werden zu Requirements; ist eines erledigt, wandert die Karte nach „Done“. Es reicht die Standardbibliothek; die Trello-Aufrufe sind als Funktionen zum Ausfüllen gelassen.

import json, os, urllib.request

API, TOKEN = "http://127.0.0.1:8767/v1", os.environ["THERON_TOKEN"]

def theron(method, path, body=None):
    req = urllib.request.Request(API + path, method=method, data=json.dumps(body).encode() if body else None,
                                 headers={"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"})
    with urllib.request.urlopen(req, timeout=90) as r:
        return json.load(r)

cards = trello_cards("To do")                       # dein Trello-Aufruf: [{"id", "name", "desc"}, …]
tl = theron("POST", "/projects/3/tasklists", {"name": "Trello", "epics": [{"name": "Board", "requirements": [
    {"title": c["name"], "description": c["desc"]} for c in cards]}]})
card_of = {r["id"]: c["id"] for c, r in zip(cards, tl["epics"][0]["requirements"])}   # gleiche Reihenfolge
task = theron("POST", f"/tasklists/{tl['id']}/start", {})

since = theron("GET", "/status")["last_event"]
while True:
    page = theron("GET", f"/events?since={since}&wait=60&task={task['id']}")
    since = page["next"]
    for ev in page["events"]:
        if ev["type"] == "requirement_done" and ev["success"]:
            trello_move(card_of[ev["requirement_id"]], "Done")
        elif ev["type"] == "input_request":
            print("Theron fragt:", ev["question"], ev["options"])   # Antwort: POST /tasks/{id}/answer
        elif ev["type"] == "complete":
            raise SystemExit(ev["summary"])
© 2026 Mike Bertram · mibexx Imprint