attach
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/SIGINThandlers that deregister cleanly.
AgentHandle — a small surface for firing emit triggers and tearing the whole setup down.
When to use it
Useattach() 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.
new Agent({...}).start() — it’s simpler.
Functional usage
Signature
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()mountsapp.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)orhandle.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.
