# Run one bounded AI agent overnight and inspect its morning digest
> A documented n8n recipe for one read-only night work order: approved notes, a bounded agent, saved state and failure alerts, then human review of the morning draft.
By BIG CHANGE Editorial
Published: 2026-10-21T18:10:38.964Z
Updated: 2026-10-21T18:10:38.964Z
Canonical: https://bigchange.ai/blog/n8n-bounded-overnight-ai-agent-morning-digest-guide

AI-generated conceptual illustration by BIG CHANGE.
An unattended AI agent needs a narrow job and a morning check. This n8n recipe schedules one read-only agent to turn up to three approved work notes into an internal action digest. It records the schedule slot, source versions, execution and draft in one work-order row. A person decides what, if anything, to do with the draft.
## The big change
- **What changed:** A published n8n schedule can hand one approved work order to a read-only AI agent and save an internal morning draft.
- **Why it matters:** A fixed source allowlist, durable run row and finite model settings give an owner evidence to inspect before acting on unattended output.
- **What to watch:** The schedule, model and error alert each need an actual production readback; cost limits do not guarantee one charge or a hard dollar ceiling.
This is a build guide based on [n8n's current documentation](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.scheduletrigger), checked October 21, 2026. BIG CHANGE did not run an n8n instance, call a model, test an alert or observe a night slot. Labels, model availability, retention, plan limits and provider prices must be checked in the reader's own account.
## Before you set the clock
You need an n8n role that can create Data Tables and publish workflows; a permitted model credential; a mailbox and SMTP credential for failure alerts; and a human reviewer. Check that your n8n plan allows the workflow timeout you intend to use, that saved production executions and the needed detail are available under your data policy, and that the model provider permits these notes. Keep sensitive material out of execution history and email. If production execution data is redacted or purged before morning, arrange an authorized way to inspect the source and tool trace; otherwise the acceptance check below cannot pass.
Prepare **real, permitted inputs**, not sample facts invented for a test. Create an `ApprovedSources` Data Table with `sourceId`, `version`, `approved`, `noteText` and `lastReviewedAt`. Each note is at most 500 words. Only the owner puts reviewed notes here. Create a `NightWorkOrders` table with `slotKey`, `scheduledAt`, `deadlineAt`, `status`, `reviewer`, `inputVersion`, `sourceId1`–`sourceId3`, their corresponding `sourceVersion1`–`sourceVersion3`, `executionId`, `startedAt`, `finishedAt`, `result`, `failureReason` and, if available, observed usage. Empty source pairs stay empty. Use one `ready` row for one intended local night slot. Set its `slotKey` and times from this approved work order, in a consistent date-time format with timezone offset. The trigger's eventual start time does not redefine the slot.
This design expects one owner to maintain unique slot keys and prevent simultaneous manual starts. n8n's [Data Table operations](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.datatable/rows) document filtered Get and Update, but do not promise an atomic claim. Inspect existing `running`, `done` or ambiguous rows and their saved executions before any replay. Never use Upsert to create a replacement result on a retry.
## 1. Publish a source-only lookup workflow
Create a sub-workflow named `Approved note lookup` with a [When Executed by Another Workflow trigger and declared inputs](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.executeworkflowtrigger): `slotKey` and `sourceId`, both strings. Put **Edit Fields** immediately after the trigger, name it `Lookup request`, and map those two fields from `{{ $json.slotKey }}` and `{{ $json.sourceId }}`. Its only successful output will be one approved note; every rejected lookup returns `{ "status": "noMatch" }` with no note text. Connect Data Table **Row → Get** named `Get active work order`: `NightWorkOrders`, **Must Match → All Conditions**, `slotKey Equals {{ $('Lookup request').first().json.slotKey }}`, `status Equals running`, **Return All off**, **Limit 2**, **Settings → Always Output Data on**. A Get replaces the current item, so later nodes use `Lookup request` by name rather than assuming `$json.slotKey` is still the request.
Connect **Aggregate → All Item Data**, name it `Collect active rows`, set **Put Output in Field** to `rows` and **Include → All fields**. In an **If** node named `One active row?`, choose **Boolean → is true** and paste this expression as the left value:
```text
{{ Array.isArray($json.rows) && $json.rows.length === 1 && $json.rows[0].slotKey === $('Lookup request').first().json.slotKey && $json.rows[0].status === 'running' }}
```
Connect **false** to **Edit Fields** returning only `status=noMatch` and no `noteText`. The `rows.length === 1` check rejects two matches; the matching identity rejects the empty item made by Always Output Data. On **true**, add **Edit Fields** named `Active row` with one object field `workOrder = {{ $json.rows[0] }}`. Then add **If**, `Allowed source ID?`, **Boolean → is true** with:
```text
{{ Boolean($('Lookup request').first().json.sourceId) && [1,2,3].some(i => $('Active row').first().json.workOrder['sourceId'+i] === $('Lookup request').first().json.sourceId && Boolean($('Active row').first().json.workOrder['sourceVersion'+i])) }}
```
Its **false** branch returns `noMatch` without reading note text. On **true**, use **Edit Fields** named `Expected source` to set `sourceId = {{ $('Lookup request').first().json.sourceId }}` and `version` from the matching fixed pair. For the version field use:
```text
{{ [1,2,3].map(i => ({ id: $('Active row').first().json.workOrder['sourceId'+i], version: $('Active row').first().json.workOrder['sourceVersion'+i] })).find(p => p.id === $('Lookup request').first().json.sourceId).version }}
```
Now **Get** `ApprovedSources` in `Get approved source` with **All Conditions** `sourceId Equals {{ $('Expected source').first().json.sourceId }}`, `version Equals {{ $('Expected source').first().json.version }}` and `approved Equals true`; **Return All off**, **Limit 2**, **Always Output Data on**. Aggregate **All Item Data** into `rows` in `Collect source rows`. In **If** named `One approved short source?`, use **Boolean → is true**:
```text
{{ Array.isArray($json.rows) && $json.rows.length === 1 && $json.rows[0].sourceId === $('Expected source').first().json.sourceId && $json.rows[0].version === $('Expected source').first().json.version && $json.rows[0].approved === true && typeof $json.rows[0].noteText === 'string' && $json.rows[0].noteText.trim().length > 0 && $json.rows[0].noteText.trim().split(/\s+/).length <= 500 }}
```
Again, **false** returns only `noMatch`. On **true**, **Edit Fields** returns `status=approved` and `sourceId`, `version`, `noteText` from `{{ $json.rows[0].sourceId }}`, `{{ $json.rows[0].version }}` and `{{ $json.rows[0].noteText }}`. Check each expression's preview against a permitted real row in the reader's instance. The `noMatch` branches must reach an output node, never fall through to the approved return.
Publish this database-sourced lookup workflow. n8n's [Call n8n Workflow Tool](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolworkflow) documentation says an unpublished database workflow fails in production, even if a manual test appeared to work.
## 2. Build one scheduled work-order run
Create `Night digest` with **Schedule Trigger → Days**, one day at the intended local hour and minute. Set **Workflow settings → Timezone** explicitly. Record that zone, the trigger's daily setting and the work order's `scheduledAt`/`deadlineAt`. In workflow settings, save failed and successful production executions, enable **Save execution progress** if allowed by your data policy, set **Timeout Workflow → Timeout After** to a finite duration supported by your plan, and select the separate error workflow from step 4. A saved draft workflow does not activate the schedule; publication does. A queue or outage can delay it, so the due-row gate checks the deadline.
After the trigger, add Data Table **Row → Get**, `Get due work orders`: `NightWorkOrders`, **Must Match → All Conditions** `status Equals ready`, `scheduledAt Less Than Or Equal {{ $now.toISO() }}`, `deadlineAt Greater Than Or Equal {{ $now.toISO() }}`; **Return All off**, **Limit 2**, **Always Output Data on**. Store both time fields as date-time values and check the expression preview in the intended workflow timezone. Add **Aggregate → All Item Data** named `Collect due rows`, **Put Output in Field → rows**, **Include → All fields**. In **If** named `One due row?`, choose **Boolean → is true** and use:
```text
{{ Array.isArray($json.rows) && $json.rows.length === 1 && Boolean($json.rows[0].slotKey) && Boolean($json.rows[0].reviewer) && Boolean($json.rows[0].inputVersion) && $json.rows[0].status === 'ready' && [1,2,3].some(i => Boolean($json.rows[0]['sourceId'+i]) && Boolean($json.rows[0]['sourceVersion'+i])) && [1,2,3].every(i => Boolean($json.rows[0]['sourceId'+i]) === Boolean($json.rows[0]['sourceVersion'+i])) }}
```
Connect **false** to **Stop And Error** before any model request. This catches zero results (including the empty `{}` sentinel), two results and incomplete source pairs. If several valid work orders are due, this one-slot design stops for the owner to resolve them. On **true**, **Edit Fields** named `Trusted work order` maps each field from the sole array item: `slotKey={{ $json.rows[0].slotKey }}`, `reviewer={{ $json.rows[0].reviewer }}`, `inputVersion={{ $json.rows[0].inputVersion }}`, `deadlineAt={{ $json.rows[0].deadlineAt }}`, plus `sourceId1`–`sourceId3` and `sourceVersion1`–`sourceVersion3` using the same `$json.rows[0].fieldName` pattern. Keep this as exactly one item; later nodes refer to it by name because another Get replaces current input.
Use Data Table **Row → Update** named `Mark running`, with **All Conditions** `slotKey Equals {{ $('Trusted work order').first().json.slotKey }}` and `status Equals ready`. Set `status=running`, `executionId` from the current saved execution, and `startedAt` from current time; preserve the approved input/version fields. Turn **Settings → Always Output Data on** for this Update: even when it changes zero rows, the following Get must run and reject that state. This is an update, not an insert. Immediately **Get** by exact `slotKey`, `executionId` and `status=running`, **Limit 2**, **Always Output Data on**. Aggregate All Item Data into `rows` in `Collect running rows`; then **If → Boolean → is true** in `One running row?` checks:
```text
{{ Array.isArray($json.rows) && $json.rows.length === 1 && $json.rows[0].slotKey === $('Trusted work order').first().json.slotKey && String($json.rows[0].executionId) === String($execution.id) && $json.rows[0].status === 'running' && $json.rows[0].inputVersion === $('Trusted work order').first().json.inputVersion && [1,2,3].every(i => $json.rows[0]['sourceId'+i] === $('Trusted work order').first().json['sourceId'+i] && $json.rows[0]['sourceVersion'+i] === $('Trusted work order').first().json['sourceVersion'+i]) }}
```
Its **false** branch goes to **Stop And Error**. If the update affected nothing, state changed, or readback is ambiguous, the agent must not run. Prevent overlapping manual runs; filtered Update and readback are not a database compare-and-swap guarantee.
## 3. Constrain the AI draft and verify it outside the model
Connect the single readback item to **AI Agent** and one account-approved **OpenAI Chat Model**. In the agent, set **Prompt → Define below**. Map a fixed instruction containing the named `Trusted work order`'s slot key, reviewer and approved source IDs/versions; do not rely on an absent `chatInput` from Schedule Trigger. In **System Message**, tell the agent: “For this work order, request only the approved notes through the lookup tool. Return at most three proposed actions, each with its source ID and version, plus gaps or uncertainty. Do not present a claim without a retrieved source. This is a draft for the named human reviewer. Do not send, post, update tasks or make purchases.” These instructions shape output; the workflow gates enforce authority.
Attach only **Call n8n Workflow Tool**, pointing to the published `Approved note lookup` workflow. Map its `slotKey` input as fixed `{{ $('Trusted work order').first().json.slotKey }}`. Let the model supply only `sourceId`; the lookup tests that ID against the work order before returning text. Do not attach email, browser, file, code, write or payment tools. Set **Max Iterations = 3** and **Return Intermediate Steps = on**. Turn **Require Specific Output Format** on and connect **Structured Output Parser** to its parser port. In the parser choose **Schema Type → Define using JSON Schema** and enter:
```json
{
"type": "object",
"additionalProperties": false,
"required": ["slotKey", "actions", "gaps", "reviewRequired"],
"properties": {
"slotKey": { "type": "string", "minLength": 1 },
"actions": {
"type": "array",
"maxItems": 3,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["text", "sourceId", "version"],
"properties": {
"text": { "type": "string", "minLength": 1 },
"sourceId": { "type": "string", "minLength": 1 },
"version": { "type": "string", "minLength": 1 }
}
}
},
"gaps": { "type": "array", "items": { "type": "string" } },
"reviewRequired": { "const": true }
}
}
```
Use string versions consistently in the tables. The parser checks shape; it cannot prove that a citation supports a sentence.
On the OpenAI Chat Model, select a model actually available to your approved account. Under **Options**, set **Maximum Number of Tokens** for completion to 600, a reviewed per-request **Timeout** in milliseconds, and **Max Retries = 0**. Turn off optional built-in web, file and code tools. Also leave each relevant node's **Retry On Fail** off. Choose a workflow timeout longer than an expected single request yet finite for the overall run. Confirm the chosen model accepts these options and inspect real provider usage in the account. Three iterations and 600 completion tokens bound part of the job, not all input or tool tokens and not currency spending. If a strict nightly dollar ceiling is necessary, verify that the provider or gateway actually enforces it before publishing; a budget alert is not an enforcement control.
Before unattended use, run a permitted manual test and open the **AI Agent output**. n8n documents the structured parser and **Return Intermediate Steps**, but does not specify one stable JSON path or inner shape for every model and node version. Add **Edit Fields** named `Evidence map` after the agent. Use the expression editor's input panel to map the actual parsed object to an object field `draft`. Map every `Approved note lookup` call result into an array field `lookupResults`, each entry containing exactly `status`, `sourceId` and `version`; include `noMatch` so a rejected call remains visible. Set a Boolean `traceComplete` only when the inspected intermediate steps expose every lookup call and its returned status. If your instance cannot expose or map that evidence, route the run to **Stop And Error** and leave the workflow unpublished until the trace can be checked. Do not substitute model-written citations for tool results or assume `$json.output`/`$json.intermediateSteps` is the path without seeing it.
Connect `Evidence map` to **If** named `Valid cited draft?`, select **Boolean → is true**, and paste this expression. The three mapped fields are the contract to inspect in the test execution; all work-order values still come from the named trusted node:
```text
{{ Boolean($json.traceComplete) && $json.draft?.slotKey === $('Trusted work order').first().json.slotKey && $json.draft?.reviewRequired === true && Array.isArray($json.draft?.actions) && $json.draft.actions.length <= 3 && Array.isArray($json.draft?.gaps) && Array.isArray($json.lookupResults) && $json.lookupResults.length >= 1 && $json.lookupResults.length <= 3 && $json.lookupResults.every(r => r.status === 'approved' && [1,2,3].some(i => r.sourceId === $('Trusted work order').first().json['sourceId'+i] && r.version === $('Trusted work order').first().json['sourceVersion'+i])) && $json.draft.actions.every(a => typeof a.text === 'string' && a.text.trim().length > 0 && $json.lookupResults.some(r => r.status === 'approved' && r.sourceId === a.sourceId && r.version === a.version)) }}
```
Connect **false** to **Stop And Error**. On **true**, insert **If** named `Before deadline?` immediately before `Mark done`, select **Boolean → is true**, and use:
```text
{{ Boolean($('Trusted work order').first().json.deadlineAt) && DateTime.fromISO($('Trusted work order').first().json.deadlineAt, { setZone: true }).isValid && DateTime.fromISO($('Trusted work order').first().json.deadlineAt, { setZone: true }).toMillis() >= $now.toMillis() }}
```
Its **false** branch goes to **Stop And Error** with a deadline-expired reason; only **true** may finish. [n8n's date guidance](https://docs.n8n.io/build/work-with-data/handle-special-data-types/work-with-dates-and-times) parses date strings with Luxon, and `$now` is the current workflow time. Compare instants with the offset-bearing `deadlineAt` from the trusted work order. A `noMatch`, missing lookup, extra call, unauthorized ID, changed version, empty or malformed output also stops. In the manual test inspect the lookup sub-workflow's actual returned row and source version, then configure a current-source reread if approval can change during a run. Parser or agent nodes that stop on error never reach `Evidence map` or a downstream row Update; the saved execution and error workflow must account for those failures. This gate checks the mapped trace and IDs, while the human still checks whether each proposed action follows from its note.
Only a passing, still-on-time draft reaches `Mark done`, a Data Table **Row → Update** with **All Conditions** `slotKey`, `executionId` and `status=running`. Set `status=done`, the checked `result` and `finishedAt`. Turn **Settings → Always Output Data on** for this Update. Get that exact row back with **Limit 2** and **Always Output Data on**, aggregate into `rows`, and send any count other than one, identity mismatch or status other than `done` to **Stop And Error**. The readback still runs if Update changed zero rows. No email or task action is connected to this result. Save any provider usage exposed by the reader's execution or account; do not infer a bill from node settings.
## 4. Wire and test the failure notice
Make a separate workflow starting with **Error Trigger**. In the main workflow settings, select it as **Error Workflow**. First use **If → Boolean → is true** with `{{ Boolean($json.execution?.id) }}`; the **false** branch sends a generic owner alert with unknown row state and makes no row update. On **true**, **Get** `NightWorkOrders` by `executionId Equals {{ $('Error Trigger').first().json.execution.id }}`, **Limit 2**, **Always Output Data on**. Aggregate **All Item Data** to field `rows` in `Collect error rows`. An **If** node, **Boolean → is true**, uses `{{ Array.isArray($json.rows) && $json.rows.length === 1 && String($json.rows[0].executionId) === String($('Error Trigger').first().json.execution.id) && $json.rows[0].status === 'running' && Boolean($json.rows[0].slotKey) }}`. Its **false** branch sends the generic alert and leaves rows unchanged. Only **true** may **Update** by `slotKey`, `executionId` and `status=running` to `failed`, with a short reason and time. Turn **Always Output Data on** for this Update, then Get that exact row with **Limit 2** and **Always Output Data on**. Send the specific failed-row notice only after one matching `failed` readback; a zero-row update or ambiguous readback goes to the generic unknown-state alert. Keep the exact saved execution ID in either notice. A trigger-stage error may have no execution ID. The error workflow itself can fail, and an unstarted schedule may produce no error notice.
Use a reader-owned **Send Email** SMTP node to alert the owner. Include the execution ID or trigger failure, workflow name, status and a link to a saved execution when present. Exclude note text and credentials. This email is a workflow action after an error, never an agent tool.
Manually test permitted inputs, including zero and two due rows, unauthorized and missing sources, a changed version, an invalid draft, state readback and the execution trace. Manual execution **does not trigger Error Trigger**. After publishing, arrange one controlled **automatic** production test in an approved slot with a deliberately absent approved source. Confirm the saved failed production execution, the exact work row marked `failed`, and the alert in the owner mailbox. If correlation is missing, confirm the row stayed unchanged and the generic alert arrived. Restore normal inputs by creating a fresh valid slot for the real night run; never silently replay the failed one. This is a test for the reader to perform, not a result BIG CHANGE observed.
## 5. Inspect the night slot in the morning
Find the intended `slotKey` in `NightWorkOrders`, its saved production execution, the lookup sub-workflow executions and the model/tool trace. Match start time, status, `executionId`, approved source IDs and versions, returned note rows, parsed draft and `finishedAt`. Read each proposed action against its real note. Accept, edit or reject each one explicitly before acting elsewhere. A `done` status means the gate passed, not that the prose is true.
If there is no execution, inspect schedule publication, the workflow timezone, instance health and queue before starting a new controlled slot. If the row remains `running`, is `failed`, or conflicts with an execution, inspect its exact saved run and provider usage before any retry. Preserve the ambiguous state until reconciled; do not launch two manual starts together. Record actual duration and spend only from the reader's n8n and provider evidence. Output and execution retention may be limited by the instance, while the Data Table row remains the durable state to review under the reader's retention policy.
## Sources & further reading
- [Schedule Trigger](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.scheduletrigger) explains the daily schedule, timezone behavior and publication prerequisite; it does not promise exact-time delivery.
- [Workflow settings](https://docs.n8n.io/build/manage-workflows/configure-workflow-settings) documents execution saving, timeout, timezone and error-workflow controls, including plan-dependent timeout limits.
- [Data Table row operations](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.datatable/rows) describes Get filters and limits and Update conditions; it does not document an atomic claim.
- [Aggregate](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.aggregate), [If](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.if) and [previous-node expressions](https://docs.n8n.io/build/work-with-data/reference-data/reference-previous-nodes) support the explicit one-row gates and trusted references after a Get.
- [Tools Agent](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent/tools-agent), [Call n8n Workflow Tool](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolworkflow), [OpenAI Chat Model](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.lmchatopenai) and [Structured Output Parser](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.outputparserstructured) document the prompt, tool, iteration, request and output-shape controls; none verifies the draft's factual claims.
- [Error Trigger](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.errortrigger), [error workflows](https://docs.n8n.io/build/flow-logic/handle-errors-gracefully) and [execution history](https://docs.n8n.io/workflows/executions/all-executions) support failure correlation and next-morning inspection. Error Trigger does not fire for a manual run.
## Sources
- [n8n Docs: Schedule Trigger](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.scheduletrigger) — Checked October 21, 2026. Documents a daily trigger, timezone and publication prerequisite; no exact-time guarantee.
- [n8n Docs: Configure workflow settings](https://docs.n8n.io/build/manage-workflows/configure-workflow-settings) — Checked October 21, 2026. Documents saved executions, progress, timezone, error workflow and plan-dependent timeout; reader checks retention and redaction.
- [n8n Docs: Data Table row operations](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.datatable/rows) — Checked October 21, 2026. Documents filtered Get and Update, Get Limit; does not guarantee atomic claims or exactly-once billing.
- [n8n Docs: Aggregate](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.aggregate) — Checked October 21, 2026. Documents All Item Data aggregation used by one/two-row gates.
- [n8n Docs: If](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.if) — Checked October 21, 2026. Documents Boolean is true conditions and true/false branches used by all fail-closed gates.
- [n8n Docs: Work with nodes](https://docs.n8n.io/build/understand-workflows/workflow-components/work-with-nodes) — Checked October 21, 2026. Documents Always Output Data and Retry On Fail; an empty sentinel must not count as a real row.
- [n8n Docs: Reference previous nodes](https://docs.n8n.io/build/work-with-data/reference-data/reference-previous-nodes) — Checked October 21, 2026. Documents named-node first() references used after Data Table Get changes the current item.
- [n8n Docs: n8n metadata](https://docs.n8n.io/build/code-in-n8n/use-built-in-shortcuts/n8n-metadata) — Checked October 21, 2026. Documents $execution.id for exact saved-execution correlation.
- [n8n Docs: Work with dates and times](https://docs.n8n.io/build/work-with-data/handle-special-data-types/work-with-dates-and-times) — Checked October 21, 2026. Documents Luxon DateTime.fromISO and $now used by the final trusted-deadline gate.
- [n8n Docs: When Executed by Another Workflow](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.executeworkflowtrigger) — Checked October 21, 2026. Documents sub-workflow input definition for trusted slotKey and model-requested sourceId.
- [n8n Docs: Tools Agent](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent/tools-agent) — Checked October 21, 2026. Documents defined prompt, system message, iteration, intermediate-step and format controls; not tool-use or truth guarantees.
- [n8n Docs: Call n8n Workflow Tool](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolworkflow) — Checked October 21, 2026. Documents mapped inputs and need to publish a database-sourced production lookup workflow.
- [n8n Docs: OpenAI Chat Model](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.lmchatopenai) — Checked October 21, 2026. Documents account-dependent model list, completion-token maximum, request timeout and Max Retries; no hard monetary cap.
- [n8n Docs: Structured Output Parser](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.outputparserstructured) — Checked October 21, 2026. Documents schema validation, not factual citation verification.
- [n8n Docs: Error Trigger](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.errortrigger) — Checked October 21, 2026. Documents automatic failure trigger, manual-run exclusion and possibly absent saved execution ID.
- [n8n Docs: Handle errors gracefully](https://docs.n8n.io/build/flow-logic/handle-errors-gracefully) — Checked October 21, 2026. Supports separate linked error workflow and Stop And Error handling; alert delivery is a reader test.
The BIG CHANGE newsletter
The big picture. At your pace.
Recent stories on AI and robotics, the shifts worth watching and practical ideas to use. Choose a daily briefing, weekly digest or monthly perspective.
Next scheduled send (UTC): . Your first edition arrives at the next scheduled send after you confirm.
Your privacy, your choice.
Necessary storage supports site security and remembers your choices. Optional Google Analytics stays off until you allow it. You can read every story with necessary storage only. Privacy details