Ordnerstruktur
Was wohin gehört im Workspace-Ordner.
Dein Workspace ist ein Ordner voller PHP-Dateien.
Wichtig vorab: Du bestimmst die Struktur
Datei- und Ordner-Namen sind reine Doku-Hilfe, nicht Schema. Der Loader liest alle *.php-Dateien im Tenant-Verzeichnis (rekursiv) und merged sie anhand der Array-Pfade, die jede Datei zurückgibt — die Datei-Struktur spielt keine Rolle.
Das heißt konkret:
- Du kannst alle Configs in eine Datei (z.B.
everything.php) packen - Oder pro Bereich aufteilen (
apis.php,assistants/<x>.php,tools/<group>/<x>.php, …) - Oder Datei-Namen frei vergeben —
mein-fancy-name.phpmit'tools.foo' => [...]wird genauso gemerged - Mehrere Dateien können Patches für denselben Array-Pfad enthalten — der Loader merged sie alphabetisch (Pfad-Reihenfolge) per
array_replace_recursive
Was zählt, ist was am Ende im finalen Tenant-Array steht, nicht woher es kommt.
Die unten gezeigte Struktur ist nur die Konvention, die wir empfehlen — Klarheit beim Lesen, leicht zu navigieren. Du darfst jederzeit abweichen.
Empfohlene Struktur
apis.php
assistants/
bestellungen.php
inventur.php
prompts/
tone.php
persona.php
public.php
scheduled.php
tools/
shop/
orders/
getOrder.php
listOrders.php
google/
drive/
uploadFile.php
kb/
searchFaq.php
Top-Level-Dateien
apis.php
Zentrale Definition externer APIs. Siehe apis.php.
public.php
Konfiguration für den nicht-eingeloggten Widget-Chat. Tools-Allowlist plus optionaler Greeting/Suggestions/Toggles/Inputs:
<?php
return [
'public.tools' => ['searchFaq', 'createLead'], // Tool-Allowlist (fail-closed)
'public.greeting' => 'Hallo! Wie kann ich helfen?',
'public.suggestions' => ['FAQ', 'Beratung anfragen'],
'public.llm' => 'cheap', // optional, Profile aus llm.php
];
Public-Chats dürfen nur Tools aus public.tools aufrufen — harte Grenze für
Widgets auf deiner öffentlichen Website. Leere Liste oder fehlend ⇒ keine Tools.
scheduled.php
Liste automatisch laufender Tool-Aufrufe. Siehe Scheduled Tasks.
Daneben optional task_log (Ausführungsprotokoll): aggregate_tools schreibt erfolgreiche Sub-Aufrufe dieser Tools in geplanten Läufen nur als eine Sammelzeile pro Lauf (z. B. reine Config-Auswertungen, die jeder Lauf aufruft), aggregate_entry_types (Default ['scheduled']), retention_days und retention_rules für die Aufbewahrung. Fehler und Root-Aufrufe werden immer einzeln geloggt. Details: Scheduled Tasks → Ausführungsprotokoll.
Ordner
assistants/
Eine Datei pro Assistant. Dateiname ohne .php ist der Slug.
Schema pro File:
return [
'assistants.<slug>' => [
'name' => 'Bestellungen',
'description' => 'Bestellungen prüfen und bearbeiten',
'icon' => '📦',
'tools' => ['getOrders', 'addLineItem', 'setSuggestions'],
'greeting' => 'Hallo! Welche Bestellung soll ich nachschauen?',
'suggestions' => ['Letzte Bestellung', 'Heute', 'Diese Woche'],
'toggles' => [],
'inputs' => ['Bestellnummer (B...)'],
'prompt' => '...', // System-Prompt für diesen Assistant
],
];
Siehe Assistenten anlegen.
prompts/
Wiederverwendbare Prompt-Snippets. Jede Datei exportiert ein oder mehrere Prompt-Strings unter prompts.<key>:
// prompts/tone.php
return [
'prompts.tone' => 'Antworte kurz, direkt, ohne Floskeln.',
];
Nutzung in Tasks:
'assistants.support.prompt' => $tonePrompt . "\n\n" . <<<PROMPT
...
PROMPT,
tools/
Deine Tool-Definitionen. Unterordner-Struktur ist frei — Konvention: nach API gruppieren, dann nach Kategorie. Siehe Tool als Config-Datei.
Beispiele: alternative Strukturen
Alle drei Layouts laden identisch in den Tenant-Config — der Loader interessiert sich nur für die Array-Pfade:
A — Eine Datei für alles (für kleine Tenants):
main.php # 'apis' + 'tools' + 'assistants' + 'public' + 'scheduled' alles drin
B — Konvention (empfohlen, siehe oben):
apis.php
public.php
scheduled.php
assistants/<id>.php
tools/<group>/<x>.php
C — Pro Use-Case alles zusammen:
gutscheine.php # 'assistants.gutscheine' + 'tools.createDiscountCode' + 'apis.shopify' alles in einem File
inventur.php # 'assistants.inventur' + zugehörige Tools alles in einem File
C ist gut für selbständige Use-Cases die als Bundle gepflegt werden — alles für Gutscheine an einem Ort. Nachteil: gemeinsam genutzte Tools landen redundant in mehreren Files.
D — Assistant + assistant-lokale Tools im selben Ordner (Recipe-Bundle):
assistants/
gutscheine/
gutscheine.php # 'assistants.gutscheine' Config
tools/
createDiscountCode.php
deactivateDiscountCode.php
inventur/
inventur.php
tools/
updateStock.php
D ist ideal für Recipes — alles für einen Use-Case in einem Ordner, einfach zu kopieren oder zu veröffentlichen. Tools, die mehrere Assistants teilen, bleiben in tools/ (Schicht 2) oder kommen aus _shared/tools/ (Schicht 1, plattformweit). Mehr dazu unter tools/.
Such dir das aus, was zu deinem Workflow passt — du kannst Strukturen auch jederzeit umorganisieren ohne Schema zu brechen.
Was nicht in den Workspace gehört
Diese Pfade werden von tm sync automatisch ignoriert:
logs/— Server-Logs (kommen beim Sync zurück)tmp/— temporäre Dateiennode_modules/— falls du lokale Build-Tools nutzt.git/,.claude/— lokale Tool-Konfigurationdocs/— Doku, wird separat synchronisiert
Gemeinsame Tools aus _shared ersetzen (tenant_override)
Tools und Assistenten aus config/tenants/_shared/ stehen in jedem Workspace. Legt ein Workspace eine Datei mit einem gleichnamigen Tool an, mischt der Loader normalerweise beide Fassungen (array_replace_recursive) — gut für kleine Anpassungen wie 'assistants.buchhaltung.hidden' => false.
Hat die _shared-Fassung 'tenant_override' => 'replace' (z. B. die Buchhaltungs-Vorlage), gilt bei einer vollständigen eigenen Definition nur die Workspace-Fassung: ein Tool mit handler oder api bzw. ein Assistent mit prompt ersetzt die _shared-Fassung ganz, statt sich mit ihr zu mischen (sonst würden sich Parameter-Schemata und required-Listen vermengen). Teil-Patches ohne diese Schlüssel mischen weiter. Sicherheits-Flags der _shared-Fassung bleiben dabei erhalten: internal, untrusted_output und mask_secrets können durch Ersetzen nicht abgeschaltet werden.
Buchhaltungs-Store (accounting.store)
Die Buchhaltungs-Vorlage (Belege & E-Rechnung) liest und schreibt nur über recordsQuery. Wo die Daten liegen, entscheidet die Workspace-Config:
return [
'accounting' => [
'store' => 'local', // Standard: SQLite im Workspace (files/accounting/store/)
// 'store' => 'supabase', // Supabase des Workspace (apis.supabase), z. B. meco
],
];
local braucht keine Einrichtung. Der Ordner files/accounting/store/ (ebenso belege/ und export/) ist für readFile/writeFile und die Builder-Tools gesperrt. Firmennamen, Ablage und die Empfänger-Adresse beim Steuerberater stehen nicht in der Workspace-Config, sondern werden im Chat mit saveAccountingSettings nach Ja gespeichert. Prompts der Vorlage lassen sich per accounting.prompts.<name> überschreiben (Standard: config/tenants/_shared/accounting/prompts.php).
Shared Code
Wenn du mehrere Tools mit gemeinsamer Logik hast, leg Helferfunktionen in ein eigenes lib/-Verzeichnis:
lib/
helpers.php
tools/
shop/
orders/
getOrder.php // require_once __DIR__.'/../../../lib/helpers.php';
Alternativ: eine einzelne Tools-Datei, die mehrere zusammengehörige Tools und private Funktionen enthält.
Versionskontrolle
Der ganze Workspace-Ordner gehört in Git (außer .tmrc mit deinen Tokens). Typisches .gitignore:
.tmrc
logs/
tmp/
node_modules/
Branches und PRs funktionieren ganz normal — vor dem Merge tm sync am Ziel-Branch, fertig.
Mehrere Entwickler
Wenn mehrere an einem Workspace arbeiten:
- Einer sorgt für das Git-Repo als Quelle der Wahrheit
- Jeder
tm logint in seiner lokalen Kopie (eigene.tmrc) git pull→tm syncnach Änderungen vom Teamtm watchnur laufen lassen, wenn du aktiv arbeitest — sonst pusht es bei jedem Speichern mit alten Dateien
Nach dem Anlegen einer neuen Datei
tm sync
Bei Syntax-Fehlern: die fehlerhafte Datei wird abgewiesen, andere gehen durch. Fehler stehen im Output.