Documentation Index
Fetch the complete documentation index at: https://docs.svantic.com/llms.txt
Use this file to discover all available pages before exploring further.
attach
import { attach } from '@svantic/sdk';
What it is
attach() is the one-call glue between an Express app and an agent. A single call does the work of four otherwise-separate steps:
- Mount the agent’s A2A endpoints on your Express app (
expose).
- Activate triggers registered on the agent via
agent.add_triggers() — webhooks become Express routes, schedules become cron timers, emit triggers become event-bus listeners.
- Connect to Svantic (
MeshConnector.connect), with automatic retries.
- Install
SIGTERM / SIGINT handlers that deregister cleanly.
It returns an AgentHandle — a small surface for firing emit triggers and tearing the whole setup down.
When to use it
Use attach() when you’re embedding an agent into a service you already run:
- You have an existing Express app with middleware, routes, and lifecycle.
- You want triggers (webhooks, cron, emit) without writing the plumbing.
- You want a single object (
AgentHandle) to own teardown.
For standalone agents that don’t need to share an Express process, prefer new Agent({...}).start() — it’s simpler.
Functional usage
import express from 'express';
import { Agent, attach, type RuntimeTrigger } from '@svantic/sdk';
const app = express();
app.use(express.json());
// 1. Build the agent and its capabilities.
const agent = new Agent({
name: 'orders',
description: 'Order automation.',
public_url: 'https://api.acme.com',
});
agent.define_capability({ /* fetch_order */ });
agent.define_capability({ /* cancel_order */ });
// 2. Register triggers on the agent. Forge generates these for you,
// but you can hand-write them too.
agent.add_triggers([
{
type: 'webhook',
path: '/hooks/stripe',
prompt: 'Payment {{id}} of {{amount}} just settled; update the order.',
payload_map: {
id: 'data.object.id',
amount: 'data.object.amount_total',
},
},
{
type: 'schedule',
cron: '0 9 * * MON-FRI',
prompt: 'Email ops the overnight order summary.',
},
{
type: 'emit',
event: 'order_cancelled',
prompt: 'Order {{order_id}} was cancelled; issue the refund.',
},
]);
// 3. Wire everything — A2A endpoints, triggers, Svantic connection.
const handle = await attach(app, {
agent,
mesh: {
client_id: process.env.SVANTIC_CLIENT_ID!,
client_secret: process.env.SVANTIC_CLIENT_SECRET!,
},
});
app.listen(4000);
// 4. Fire emit triggers from anywhere in the service.
app.post('/orders/:id/cancel', async (req, res) => {
await db.orders.cancel(req.params.id);
handle.emit('order_cancelled', { order_id: req.params.id });
res.sendStatus(204);
});
// 5. Teardown (attach also handles SIGTERM / SIGINT automatically).
await handle.detach();
See the Attach to Express and Triggers guides for the end-to-end story.
Signature
function attach(app: Express, config: AttachConfig): Promise<AgentHandle>
AttachConfig
| Field | Type | Purpose |
|---|
agent | Agent | The agent to mount. Capabilities and triggers must be registered before calling attach. |
mesh? | MeshConnectorConfig (retries/retry-delay optional) | Svantic connection config. Omit to skip mesh registration entirely — useful for local-only dev. |
RuntimeTrigger
One trigger definition. Every trigger carries a prompt template (with {{…}} placeholders) that is fired when the trigger matches.
| Field | Type | Purpose |
|---|
type | 'webhook' | 'schedule' | 'emit' | Dispatcher kind. |
event? | string | For emit triggers — the event name. |
path? | string | For webhook triggers — the HTTP path mounted on the Express app (POST). |
cron? | string | For schedule triggers — a standard 5-field cron expression. See cron matching for supported syntax. |
queue? | string | Reserved for future queue-backed triggers. |
verify? | string | Optional verification strategy (e.g. webhook HMAC). Name only — verification is plumbed by the Forge-generated code. |
secret_env? | string | Name of the env var holding the verification secret. |
payload_map? | Record<string, string> | Dot-notation extraction map applied before interpolation. E.g. { customer: 'event.data.customer.id' }. |
prompt | string | Prompt template with {{key}} placeholders. |
Trigger kinds
- webhook —
attach() mounts app.post(trigger.path). The request body is the payload.
- schedule — fires every minute; runs when the cron expression matches the current minute.
- emit — listens on an internal event bus. Trigger with
handle.emit(event, payload) or handle.ask(event, payload).
AgentHandle
Returned by attach().
| Member | Type | Purpose |
|---|
emit(event, payload?) | void | Fire an emit trigger without waiting for a result. |
ask(event, payload?) | Promise<unknown> | Fire an emit trigger and await the handler’s return value. Rejects after 30 s. |
detach() | Promise<void> | Stop crons, remove event listeners, disconnect from Svantic, close the agent. Removes the internal SIGTERM/SIGINT handlers. |
mesh | MeshConnector | null | The underlying connector, or null when config.mesh was omitted. |
agent | Agent | The underlying agent. |
attach() installs SIGTERM and SIGINT handlers that call detach() for you; you don’t need to wire signal handling yourself.
Exported helpers
interpolate_prompt(template, payload, payload_map?)
Replace {{key}} placeholders in template with values from payload. When payload_map is provided, values are first extracted via dot-notation (e.g. event.data.customer.id) and flattened.
Unknown placeholders are left as-is ({{key}}) so they’re easy to spot in logs.
cron_matches_now(expr, now?)
Returns true when the cron expression matches the given instant (default: now). Supports:
* wildcard,
- single values (
5),
- comma lists (
0,15,30,45),
- ranges (
9-17),
- steps (
*/15, 9-17/2),
- weekday names (
MON–SUN) in the day-of-week field.
Only 5-field cron (minute hour day-of-month month day-of-week) is supported.
Example
import express from 'express';
import { Agent, attach } from '@svantic/sdk';
const app = express();
app.use(express.json());
const agent = new Agent({ name: 'orders', description: 'Order automation.' });
agent.define_capability({ /* … */ });
agent.add_triggers([
{
type: 'webhook',
path: '/hooks/stripe',
prompt: 'A payment for {{amount}} just settled; update the order.',
payload_map: { amount: 'data.object.amount_total' },
},
{
type: 'schedule',
cron: '0 9 * * MON-FRI',
prompt: 'Email the ops team the overnight order summary.',
},
]);
const handle = await attach(app, {
agent,
mesh: {
client_id: process.env.SVANTIC_CLIENT_ID!,
client_secret: process.env.SVANTIC_CLIENT_SECRET!,
},
});
app.listen(4000);
// later, from anywhere in the service:
handle.emit('order_cancelled', { order_id: 'ord_42' });
See also