Apps im Überblick
Liefere ein Web-Frontend mit deinen Agenten aus. Jedes Deployment baut es aus deinem Projekt, jedes Environment stellt es unter einer eigenen URL bereit, und der Browser ruft Agenten und Projektdaten über connic auf.
Auf dieser Seite
Eine App ist ein statisches Frontend, etwa eine Single-Page-App mit React oder Vue, die in deinem Projekt liegt: die Einstellungen in apps/<key>.yaml, der Quellcode in apps/<key>/. Ein Deployment baut sie und stellt sie im Environment des Deployments unter https://<key>-<id>.connic.app oder einer Custom Domain bereit. Verlangt die App eine Anmeldung, meldet connic Besucher an, bevor auch nur eine Datei ausgeliefert wird. Der Browser-Code der App erreicht Agenten und Daten über Pfade auf ihrem eigenen Host und braucht deshalb keinen API Key.
App deklarieren
Jede Datei in apps/ deklariert eine App, und ein gleichnamiger Ordner enthält ihren Quellcode. Der Dateiname ohne .yaml ist der Key der App: apps/portal.yaml wird aus apps/portal/ gebaut.
my-agent-project/
├── agents/
├── connectors/
│ └── portal-chat.yaml
└── apps/
├── portal.yaml # Einstellungen der App; der Dateiname ist ihr Key
└── portal/ # Quellcode der App
├── package.json
├── package-lock.json
└── src/name: Support portal # optional, Standard ist der Dateiname
build:
command: npm run build
output: dist # Ordner mit index.html, innerhalb von apps/portal/
auth: # optional; ohne auth legst du die Anmeldung im Dashboard fest
mode: oidc
issuer: ${PORTAL_ISSUER}
client_id: ${PORTAL_CLIENT_ID}
client_secret: ${PORTAL_CLIENT_SECRET}
allowed_domains: [example.com]
connectors: # apps_only-Connectors, die die App aufruft
- portal-chat
access: # Daten für den Browser; alles andere ist verboten
database:
tickets:
read: doc.author_id == user.id
insert: true
set:
author_id: user.id
environments: # weglassen, um in jedes Environment zu deployen
Staging:
auth:
mode: connic
Production:
domain: portal.example.com
dev: # connic-dev-Environments, die die Liste nicht nennt
auth:
mode: connic| Feld | Typ | Status | Beschreibung |
|---|---|---|---|
| name | string | Optional | Anzeigename, 1 bis 200 Zeichen.Standard: Dateiname |
| build | object | Erforderlich | Wie connic die App baut. Siehe Build. |
| command | string | Erforderlich | Build-Befehl, läuft nach der Installation in apps/<key>/. Eine Zeile, bis zu 500 Zeichen. |
| output | string | Erforderlich | Ordner, in den der Build schreibt, relativ zu apps/<key>/, etwa dist. Er muss eine index.html enthalten. |
| install | string | Optional | Installationsbefehl. Standard ist der Befehl zum Lockfile: npm ci, pnpm install --frozen-lockfile oder yarn install --frozen-lockfile. |
| node | string | Optional | Node.js-Version: 22 oder 24.Standard: 24 |
| auth | object | Optional | Wer die App öffnen darf: mode ist public, connic oder oidc, dazu die Felder dieses Modus. Ohne auth legst du die Anmeldung im Dashboard fest. Siehe Anmeldung. |
| connectors | string[] | Optional | Keys der Connector-Dateien, die die App aufruft. Siehe Agenten aufrufen. |
| domain | string | Optional | Hostname oder ID einer aktiven Custom Domain des Projekts. Ohne domain legst du die Domain im Dashboard fest. Siehe Domains. |
| content_security_policy | string | Optional | Ersetzt die Standard-Content-Security-Policy. Eine Zeile, bis zu 4.000 Zeichen. |
| lookups | map | Optional | Dokumente, die Regeln einmal pro Anfrage über einen Namen nachschlagen. Siehe Lookups. |
| access | object | Optional | Was der Browser lesen und ändern darf, pro Ressource und Operation. Ohne access kann die App keine Projektdaten nutzen. Siehe Zugriffsregeln. |
| environments | map | Optional | Namen der Environments, die die App bekommen, jeweils mit optionalen Overrides. Ohne environments geht die App in jedes Environment. Siehe Environments und Overrides. |
| dev | object | Optional | Overrides für die Environments von connic dev, die environments nicht nennt. Mit environments bekommen sie die App nur, wenn dev gesetzt ist. Siehe Environments und Overrides. |
Die Dateien liegen direkt in apps/ und enden auf .yaml. Ein Dateiname beginnt mit einem Buchstaben oder einer Ziffer, enthält nur Buchstaben, Ziffern, - und _ und hat höchstens 100 Zeichen. Jede Datei braucht ihren Quellordner, und jeder Ordner in apps/ braucht seine Datei. connic lint prüft die Dateien, ihre Regeln und die aufgelisteten Connectors offline, und connic deploy führt den Lint vorher aus.
Environments und Overrides
Ohne environments bekommt jedes Environment die App mit denselben Einstellungen. Mit dem Feld bekommen sie nur die aufgelisteten Environments. Die Namen müssen exakt passen, und ein Name, den es im Projekt nicht gibt, lässt das Deployment scheitern. Production: {} stellt die Datei unverändert bereit. Jedes Environment bekommt eine eigene App mit eigener URL, eigener Anmeldung und eigenen Statistiken.
Ein Override kann name, auth, connectors, domain, content_security_policy, lookups und access setzen. Jedes Feld ersetzt den ganzen Wert aus dem Kopf der Datei: auth in Staging oben ersetzt alle OIDC-Einstellungen, und ein access-Override ersetzt alle Regeln. Um domain, content_security_policy, lookups oder access in einem Environment zu entfernen, setze den Wert dort auf null. build ist in jedem Environment gleich.
dev nimmt dieselben Felder und gilt für jedes Environment von connic dev, das environments nicht nennt, kurze Tests eingeschlossen. Mit environments bekommen diese Dev-Environments die App nur, wenn dev gesetzt ist; dev: {} übernimmt den Kopf der Datei unverändert. Dev-Environments haben eigene Variablen, deshalb läuft die Anmeldung im Beispiel oben dort über connic-Konten, statt die OIDC-Variablen zu lesen.
Variablen
${NAME} liest eine Variable des Ziel-Environments, und zwar in domain sowie in issuer, client_id und client_secret von auth. connic löst sie beim Start des Deployments auf; fehlt eine Variable, scheitert das Deployment. client_secret muss eine einzelne Referenz ${NAME} sein.
Build-Befehle können ${NAME} nicht nutzen, und während des Builds gibt es keine Variablen. Was sich pro Environment unterscheidet, liest die App zur Laufzeit aus /_connic/config.json.
Build
Jedes Framework, das einen statischen Ordner mit einer index.html schreibt, funktioniert, etwa Vite mit React, Vue, Svelte oder Solid, Angular, Astro, Next.js mit output: "export", SvelteKit mit adapter-static oder Nuxt mit nuxt generate. connic liefert die Dateien so aus, wie sie sind. Server-Rendering, API-Routen und Server-Middleware laufen deshalb nicht; diese Arbeit übernehmen Agenten hinter Connectors und die Data API.
Jedes Deployment baut seine Apps in einem Node.js-Image der Version aus build.node, als Nutzer ohne Root-Rechte und mit CI=true. Es kopiert package.json und das Lockfile, führt den Installationsbefehl aus, kopiert den Rest von apps/<key>/, führt build.command aus und prüft, ob build.output eine index.html enthält. pnpm und yarn laufen über Corepack. Die Ausgabe des Builds steht im Deployment-Log, und ein fehlgeschlagener Build lässt das Deployment scheitern. Jedes Deployment behält seinen eigenen Build, ein Rollback liefert also wieder den älteren Build aus.
Quellcode
apps/<key>/ braucht eine package.json und ein Lockfile: package-lock.json, pnpm-lock.yaml oder yarn.lock. Deployments laden den Quellcode der Apps mit dem restlichen Projekt hoch, bis zu 20 MiB für alle Apps zusammen. Der Upload lässt node_modules, versteckte Dateien und Ordner sowie die Ordner dist, build, out und coverage direkt in einem App-Ordner aus.
Der Quellcode einer App darf nur diese Dateitypen enthalten, und Code muss UTF-8-Text sein: .js .mjs .cjs .jsx .ts .mts .cts .tsx .vue .svelte .astro .html .htm .css .scss .sass .less .json .jsonc .md .mdx .txt .yaml .yml .toml .svg .xml .webmanifest .graphql .gql .lock .png .jpg .jpeg .gif .webp .avif .ico .woff .woff2 .ttf .otf .mp3 .mp4 .webm .pdf. Jede andere Datei, auch eine ohne Endung, lässt den Upload scheitern.
Tarife und Limits
Apps gehören zum Pro- und Enterprise-Tarif. Dort hat ein Environment bis zu 5 Apps, die Build-Ausgabe einer App darf bis zu 25 MiB groß sein, die Apps eines Deployments dürfen zusammen bis zu 20.000 Dateien haben, und die App-Builds eines Deployments haben 10 Minuten Zeit. Ein Deployment über einem Limit scheitert und nennt das Limit.
Auslieferung
Die App beantwortet jeden Pfad ihres Hosts. / und Pfade, die auf / enden, liefern die index.html dieses Ordners. Ein Pfad ohne Dateiendung versucht zuerst die Datei selbst, dann <path>.html, dann <path>/index.html und zuletzt die index.html im Wurzelordner. So überstehen clientseitige Routen ein Neuladen. Eine fehlende Datei mit Endung bekommt die 404.html der App mit Status 404, oder ein schlichtes 404, wenn die App keine hat.
Dateien, deren Name einen Hash des Inhalts trägt, etwa assets/index-B3k9x2Qa.js von Vite oder alles unter _next/static/, halten Browser ein Jahr lang vor. Alle anderen Dateien werden bei jeder Anfrage neu geprüft, ein Deployment erscheint also beim nächsten Seitenaufruf. Apps in Dev-Environments werden gar nicht gecacht.
Eine App, die das aktive Deployment nicht mehr deklariert, wird stillgelegt: Sie wird nicht mehr ausgeliefert, und ihre Besucher werden abgemeldet. Ihre URL behält sie, und wenn ein späteres Deployment sie wieder deklariert, ist sie unter derselben Adresse zurück.
Security-Header
Jede Datei kommt mit X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, HSTS und dieser Content-Security-Policy:
default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self'; object-src 'none'Der Standard lädt Skripte, Styles, Bilder und Schriften nur vom eigenen Host der App und schickt Anfragen nur dorthin, was Connectors und die Data API abdeckt. Für andere Hosts setzt du content_security_policy; der Wert ersetzt den Standard vollständig. Statische Exporte von Next.js nutzen Inline-Skripte und brauchen script-src 'self' 'unsafe-inline'.
Reservierte Pfade
Pfade unter /_connic/ gehören connic und erreichen nie die Dateien der App. Unbekannte Pfade unter /_connic/ antworten mit 404.
| Pfad | Zweck |
|---|---|
| /_connic/config.json | Key und Name der App, das Environment, der Anmeldemodus, die Keys der Connectors und die Pfade für An- und Abmeldung. Siehe /_connic/config.json. |
| /_connic/login, /_connic/logout | Anmeldung starten und abmelden. Siehe Anmeldung. |
| /_connic/c/<key> | Die Connectors der App. Siehe Agenten aufrufen. |
| /_connic/me, /_connic/db/…, /_connic/files/…, /_connic/runs…, /_connic/sessions/…, /_connic/approvals… | Die Data API. |
/_connic/config.json
Derselbe Build kann in mehreren Environments laufen, also liest die App zur Laufzeit, was sich unterscheidet. Bei öffentlichen Apps sind login_url und logout_url null.
{
"app": {"key": "portal", "name": "Support portal"},
"environment": "Production",
"auth": "oidc",
"connectors": ["portal-chat"],
"login_url": "/_connic/login",
"logout_url": "/_connic/logout"
}Agenten aufrufen
Eine App erreicht Agenten über Connectors. Liste ihre Keys in connectors auf. Jeder muss ein Sync-Webhook oder ein WebSocket-Connector sein, dessen Datei apps_only: true setzt und der in dieselben Environments deployt wird wie die App. Eine App mit dev braucht ihre Connectors auch in Dev-Environments, deshalb braucht eine Connector-Datei mit environments ebenfalls dev.
type: webhook
mode: sync
apps_only: true # nur Apps, die diesen Connector auflisten, können ihn aufrufen
agents:
- supportDie App ruft den Connector auf ihrem eigenen Host unter /_connic/c/<key> auf. connic prüft zuerst die Session des Besuchers und leitet die Anfrage dann mit App und Besucher weiter. Anfragen von anderen Websites bekommen 403: Der Origin einer Anfrage muss der eigene der App sein, und WebSocket-Verbindungen müssen ihn mitschicken. Ein apps_only-Connector nimmt nichts anderes an: Seine eigene URL lehnt direkte Anfragen ab, und sein Secret wird nicht verwendet. apps_only lässt sich nur in connectors/*.yaml setzen.
const response = await fetch("/_connic/c/portal-chat", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ message: "Wo ist meine Bestellung?" }),
});
if (response.status === 401) {
location.assign(`/_connic/login?return=${encodeURIComponent(location.pathname)}`);
}
const result = await response.json();Ein WebSocket-Connector braucht keine Nachricht mit dem Secret, die erste Nachricht ist also bereits eine Chat-Nachricht. Sein Pfad nimmt ein weiteres Segment an, eine Connection-ID, die der Client wählt, etwa /_connic/c/portal-chat/<connection id>. Jeder Endnutzer hat eigene Connection-IDs. Eine Verbindung mit der ID einer offenen Verbindung ersetzt diese, und Antworten, die der Besucher ohne Verbindung verpasst hat, kommen, sobald er sich mit derselben ID neu verbindet; siehe Neu verbinden. Query-Strings werden weitergegeben. Ein Key, den die App nicht auflistet, antwortet mit 404.
const socket = new WebSocket(`wss://${location.host}/_connic/c/portal-chat`);
socket.onopen = () => socket.send(JSON.stringify({ message: "Wo ist meine Bestellung?" }));App und Endnutzer im Run
Runs, die eine App startet, tragen zwei Schlüssel im Kontext. connic setzt sie aus der weitergeleiteten Anfrage und nie aus dem Payload, deshalb können Middleware und Tools ihnen vertrauen:
context["app"]
# {"id": "0b9c3f1e-5d2a-4e8b-9f1c-7a6d2e4b8c10", "key": "portal"}
context["end_user"]
# {"id": "8d2f6c1a-4b7e-4f0a-9c3d-2e5b7a9f1c64", "email": "ada@example.com",
# "name": "Ada Lovelace", "groups": ["support"], "signed_in": True}In einer öffentlichen App ist end_user.id die Besucher-ID des Browsers, email und name sind None, groups ist leer und signed_in ist False. Nutze context.end_user.id als Nutzer für die Anmeldung pro Nutzer bei MCP-Servern, oder zeige Besuchern ihre eigenen Runs mit der Zugriffsregel run.context.end_user.id == user.id.
Im Dashboard
Die Seite Apps listet die Apps des gewählten Environments auf, Dev-Environments eingeschlossen, mit URL, Anmeldung und den Besuchern, Aufrufen, Anmeldungen und Datenanfragen der letzten 7 Tage. Ein Klick auf eine App öffnet ihre Details:
- Settings: die Standard-URL, die Custom Domain, die Anmeldung und die Zeile „Powered by connic“ am Ende jeder Seite. Eine Einstellung, die die Datei deklariert, trägt das Badge In code und lässt sich nur im Code ändern.
- Stats: Besucher, Aufrufe, Anmeldungen, Datenanfragen, fehlgeschlagene Anmeldungen, abgelehnte Anfragen und Connector-Aufrufe der letzten 30 Tage. Ein Aufruf ist eine Seite, die die App ausgeliefert hat, und ein Besucher zählt einmal pro UTC-Tag.
- Access: die Lookups und Zugriffsregeln der deployten Datei, nur lesbar.
Apps zu sehen erfordert die Berechtigung View apps, ihre Einstellungen zu ändern Manage apps, die die Standardgruppe Admin hat. Siehe Team und Berechtigungen. connic MCP bietet dasselbe mit list_apps, get_app, update_app und get_app_stats.