Skip to content

Integrations & storage

Vocabulary: a connector is an I/O channel the assistant uses to talk to a human (Discord, Telegram, email, …). An integration is a link to a third-party service (storage today; more later). They're managed separately — connectors under Connectors, integrations under Integrations in the dashboard.

Unlike connectors, integrations aren't supervised processes — they're config + a driver loaded on demand. Their secrets live in the TRUST vault, never in the config.

The storage substrate

shared/storage.js defines one backend-agnostic driver contract that both data silos and backups ride on:

put(path, data) · get(path) · stat(path) · list(prefix, {recursive})
remove(path) · move(from, to) · mkdir(path) · mint(path, {verb, ttl})

mint() is the control-plane→data-plane handoff: it returns a short-lived, scoped capability (an S3/WebDAV presigned URL) so a peer transfers bytes direct to the backend — the owner never proxies the bytes.

Drivers

Type Backends Notes
local local disk built-in, always available; silos are local-first
webdav Nextcloud, ownCloud, any WebDAV base_url + username + password (a vault key) + root
s3 AWS S3, Backblaze B2, DigitalOcean Spaces, Cloudflare R2, MinIO one driver via endpoint/region/bucket + keys; presigned mint

Object-storage credentials never need a box to run. A self-hosted node (a Linux box running WebDAV or SFTP, optionally provisioned by asmltr from bare SSH) is the alternative — see the roadmap.

The registry

integrations/registry.js stores integration configs. Secret fields are stored as *_ref — a vault key name, not the secret — and resolved from the vault only when the integration is opened:

{
  "type": "webdav",
  "name": "3DPP Nextcloud",
  "config": {
    "base_url": "https://files.example.com/remote.php/dav/files/user",
    "username": "assistant@example.com",
    "root": "asmltr-silos",
    "password_ref": "nextcloud_password"   // ← vault key name; the secret lives in the vault
  }
}

Manage integrations via the dashboard Integrations plane (add/configure/test/delete) or the API:

Method Path Description
GET /v2/integrations list (configs only; *_ref are key names, never secrets)
POST /v2/integrations create { type, name, config }
PATCH /v2/integrations/{id} update
DELETE /v2/integrations/{id} remove
POST /v2/integrations/{id}/test open + a cheap connectivity check → { ok }

Encryption at rest

EncryptedStorage is a composable wrapper over any driver — AES-256-GCM, so the backend (and anyone browsing it, e.g. in Nextcloud's web UI) sees only ciphertext. The per-silo data key comes from the vault's KMS: asmltr asks the vault to generate a data key (getting the plaintext once + a wrapped blob it stores next to the data), and unwraps the blob on demand. The KMS master key never leaves the vault; the plaintext data key lives only transiently in the runtime crypto layer — never in the model's context — and is zeroed after use.

Encryption is chosen per silo: at-rest (ciphertext, opaque to the backend + humans) vs. none (plaintext, so a human can edit files directly in the storage UI). See the roadmap for the full silo model.