External integrations¶
Inbox and Alerts are core ALMa features. They do not become optional merely because no external service is connected. Integration plugins are the adapters that let those core features exchange information with Slack, SMTP, or a future channel.
| Capability | Core owner | Integration responsibility |
|---|---|---|
send |
Alerts selects papers, schedules, deduplicates, and records outcomes | Render and deliver the finished digest |
receive |
Inbox resolves papers, lands corpus rows, deduplicates, and owns triage | Fetch external messages and acknowledge outcomes |
Slack implements both directions. SMTP currently implements send only. One
Slack activation controls both adapters because they share one external
integration and credential; status still reports each direction separately.
One explicit manifest registry¶
alma.plugins.registry.PLUGINS is the only integration catalogue. Every entry is
a PluginManifest with:
- stable identity and version;
send/receivecapabilities;- one explicit activation flag;
- one strict Pydantic configuration model;
- generated JSON Schema, storage mapping, masked secret reads, and status;
- optional Alert sender, Inbox adapter, and connectivity-test action.
Registration is explicit. An unregistered id cannot enter an Alert row, deliver a digest, or put a message into Inbox. Signal Lab is not in this registry: it is a native intelligence feature.
The capability protocols remain separate. Outbound integrations implement the
manifest's AlertSender callback; inbound integrations implement
alma.application.inbox_schema.InboundChannel. A send-only integration does not
grow fake receive methods.
Activation is not deletion¶
Turning an integration off in Settings → Plugins retains its configuration and secrets. ALMa then:
- excludes it from new delivery choices and automated Alert sends;
- excludes its inbound adapter from Inbox capture sweeps;
- hides its direction-status pills on Home.
A manual connectivity test remains available after reactivation. Activation never purges Inbox papers or Alert history.
One transport and one credential¶
Everything Slack goes through alma.slack.client.SlackNotifier: token,
slack_sdk client, channel resolution, posting, history reads, and reactions.
The Slack manifest and Inbox adapter call that transport; neither owns another
HTTP client.
Secrets live only in alma.core.secrets. Settings shows masked values and the
server-generated schema marks secret fields with x-alma-secret. A legacy
config/slack.* file is imported once by storage migration and never read by
runtime code.
API¶
| Method | Path | Purpose |
|---|---|---|
GET |
/api/v1/plugins |
All manifests, capabilities, schema, activation, and status |
GET |
/api/v1/plugins/{id} |
One manifest |
PUT |
/api/v1/plugins/{id}/enabled |
Activate/deactivate without deleting config |
GET |
/api/v1/plugins/{id}/config |
Read validated config with masked secrets |
PUT |
/api/v1/plugins/{id}/config |
Strictly validate and replace config |
POST |
/api/v1/plugins/{id}/test |
Run the manifest test through Activity |
GET |
/api/v1/inbox/status |
Core Inbox capture status |
POST |
/api/v1/inbox/sweep |
Core Inbox action: poll active receive adapters |
The same Pydantic model validates writes and produces config_schema; the
frontend does not maintain a duplicate field list.
For the package contract and extension checklist, see Building an integration.