diff --git a/product/process/workflows/forest-runtime.mdx b/product/process/workflows/forest-runtime.mdx index 2622472..2d7b258 100644 --- a/product/process/workflows/forest-runtime.mdx +++ b/product/process/workflows/forest-runtime.mdx @@ -83,7 +83,7 @@ It inherits your agent's secrets and Forest connection, so you only configure: | `port` | Loopback port the executor listens on internally (default `3400`). | | `ai` | Bring your own LLM instead of Forest's AI server: `{ provider: 'anthropic' \| 'openai', model, apiKey }`, or `{ provider: 'bedrock', model, region }`. [Bedrock](#amazon-bedrock) takes no `apiKey` — it signs in through AWS — and its `region` falls back to `AWS_REGION` / `AWS_DEFAULT_REGION`, one of which is required. Omit to keep using Forest's server. | | `encryptionKey` | At-rest key (AES-256-GCM) for [OAuth-protected MCP connector](#oauth-protected-mcp-connectors) credentials. Generate with `openssl rand -hex 32`. Omit if you don't use them. | -| `pollingIntervalS`, `stepTimeoutS`, `aiInvokeTimeoutS`, `stopTimeoutS`, `maxChainDepth`, `schemaCacheTtlS` | The same tuning knobs as [standalone](#tuning), in camelCase — same defaults. Log verbosity follows your agent's own logger, so there's no separate log-level option here. | +| `pollingIntervalS`, `automationPollingIntervalS`, `stepTimeoutS`, `aiInvokeTimeoutS`, `stopTimeoutS`, `maxChainDepth`, `schemaCacheTtlS` | The same tuning knobs as [standalone](#tuning), in camelCase — same defaults. Log verbosity follows your agent's own logger, so there's no separate log-level option here. | Embedded has full configuration parity with standalone: your own AI provider (`ai`), the encryption key, and every tuning knob are all settable here. It only inherits your agent's secrets and Forest connection; set nothing and AI steps use Forest's AI server. @@ -267,6 +267,75 @@ AI_MODEL=eu.anthropic.claude-sonnet-5 AWS_REGION=eu-west-1 ``` +## Automated inboxes + +An [inbox](/product/manage/inbox) backed by a segment can start a workflow on its own, on every +record that enters it, with no one clicking anything. Forest Runtime is what sweeps the segment. + +**It decides nothing.** It reads your data and reports what it saw; Forest starts the runs, applies +the limit of concurrent runs, and refuses a record a workflow is already handling. A runtime that +cannot reach Forest, or that you turn off, stops the automation — it never starts work twice. + +### How a sweep works + +Every `AUTOMATION_POLL_INTERVAL_S`, for each automated inbox: + +1. It asks Forest which automated inboxes to sweep, and which records are already being handled. +2. It asks your agent whether the records whose workflow has finished are still in the segment. +3. It asks your agent for the first page of the segment, to find records nobody has handled yet. +4. It reports both answers back. Forest starts a workflow per new record. + +```mermaid +flowchart LR + R["Forest Runtime
(your infrastructure)"] -- "which inboxes?" --> O["Forest orchestrator"] + R -- "who is in the segment?" --> A["Your Forest agent"] --> DB[("Your business
database")] + R -- "what I saw" --> O -- "starts the workflows" --> O +``` + +A record leaves the automation when it **leaves the segment**. That is the only signal that it was +treated: a record whose workflow finished while it is still in the segment is handed to a human in +the workflow's fallback inbox instead of being run again. + +### Requirements + +- Forest Runtime on the version that ships automated inboxes or above. An older one is not served + the configuration, and the inbox shows as configured but inactive in its settings. +- A **segment-backed inbox**, with automation enabled on it. It is configured on the inbox, not in + the workflow's Process section. + +### Running several instances + +Nothing to configure. Each instance identifies itself and Forest hands the sweep to one of them, so +several instances do not sweep the same segment in parallel. + +Two consequences worth knowing: + +- If Forest cannot run that election, every instance sweeps. That costs duplicate reads on your + database, and it is deliberate — the alternative would stop every automation silently. No record + is ever run twice. +- After you restart or redeploy your runtime, the new process waits for the previous one's turn to + lapse before it starts sweeping. Expect up to ten minutes with no sweep. + +### What the sweep can read + +- **The service account's permissions apply.** The runtime reads the segment as the account the + automation runs as, so a restrictive scope on that account's role hides records from the sweep. +- **Relative dates** in a segment filter (`previous 30 days`, `today`…) are evaluated in your + project's timezone, or UTC when it has none. +- **SQL segments** need a connection name on agents that support several connections. On + `forest-rails` and `forest-express-sequelize`, which run the query against their single database, + none is needed. + +### In your logs + +| Line | Level | Meaning | +| --- | --- | --- | +| `Automated inbox polled` | `Info` | A sweep completed. Carries how many records were started, skipped or handed to a human. | +| `Automated inbox poll failed` | `Error` | One inbox failed to sweep this cycle. The others are unaffected. | +| `Could not reach the agent, reporting nothing for this inbox` | `Error` | Your agent did not answer. Nothing is reported, so the inbox reads as not swept rather than as swept with nothing to do. | +| `Automated inbox no longer served, dropping it for this cycle` | `Info` | Forest stopped serving this inbox — disabled, or its configuration is no longer valid. | +| `The orchestrator does not serve automated inboxes` | `Warn` | Said once. Expected if your runtime is newer than Forest; check `FOREST_SERVER_URL` if it persists. | + ## OAuth-protected MCP connectors If your workflows include [MCP Tasks](/product/process/workflows/overview) backed by OAuth-protected connectors, Forest Runtime stores each user's OAuth credentials in its database, encrypted at rest. Provide the encryption key: @@ -320,6 +389,7 @@ Beyond the required variables, these optional knobs have sensible defaults and r | --- | --- | --- | | `HTTP_PORT` | `3400` | Port Forest Runtime's HTTP server listens on. | | `POLLING_INTERVAL_S` | `30` | How often it polls the orchestrator for pending steps. | +| `AUTOMATION_POLL_INTERVAL_S` | `300` | How often it sweeps automated inboxes. Each sweep reads your database, so it runs an order of magnitude slower than the step poll. | | `LOG_LEVEL` | `Info` | `Debug`, `Info`, `Warn`, or `Error`. `Debug` adds one line per MCP server with its tool count and load time. | | `STEP_TIMEOUT_S` | `300` | Max duration of a single step. | | `AI_INVOKE_TIMEOUT_S` | `30` | Max duration of a single AI provider invocation. | diff --git a/product/process/workflows/triggers.mdx b/product/process/workflows/triggers.mdx index 0adf761..6b77102 100644 --- a/product/process/workflows/triggers.mdx +++ b/product/process/workflows/triggers.mdx @@ -3,7 +3,7 @@ title: "Workflow triggers" description: "Choose how a workflow starts, manually from the interface, or automatically from an external system via a webhook." --- -A workflow can be started in two independent ways. Both are configured in the **Process** section of the workflow settings page, beneath the version card. Each trigger type has its own row with an on/off toggle, and the two can be enabled independently. +A workflow can be started in three ways. Two of them are configured in the **Process** section of the workflow settings page, beneath the version card: each has its own row with an on/off toggle, and the two can be enabled independently. The third is configured elsewhere — see [From an inbox](#from-an-inbox) below. - **Manual** — users start the workflow from a matching record in the interface (List View, Summary/Details, or a Workspace). This is the default. See [Executing workflows](/product/execute/workflows). - **Webhook** — external systems start the workflow via an authenticated HTTP POST. **Disabled by default.** @@ -67,6 +67,14 @@ You have three independent levers to stop a webhook, without necessarily touchin Turning the toggle back on re-enables the *same* URL and token — it is a pause, not a reset. +## From an inbox + +An [inbox](/product/manage/inbox) backed by a segment can start a workflow by itself, on every record that enters it. Unlike the two above, it is configured **on the inbox**, not in the workflow's Process section — the workflow does not know it is being triggered this way. + +- It runs as a chosen account, so what the workflow can read and write is bounded by that account's permissions, like a webhook run. +- It needs [Forest Runtime](/product/process/workflows/forest-runtime#automated-inboxes) on your infrastructure: Forest never reads your database itself, so something on your side has to watch the segment. +- A record leaves the automation when it **leaves the segment**. A record whose workflow finished while it is still there is handed to a human in the workflow's fallback inbox rather than run again. + ## Auditing Every webhook-triggered run is recorded in the workflow run history and in your **Activity Logs**, attributed to the token's user and marked as **webhook-triggered** so you can distinguish automated runs from manual ones.