Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/connector-authoring-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
---

docs-only: hand-written connector authoring guide at
`content/docs/automation/connectors.mdx` (#4289) — the declarative
`connectors:` path (ADR-0097) finally has a page: the three entry shapes,
per-provider `providerConfig` contracts (`rest` / `openapi` / `mcp`),
`credentialRef`-based auth with the enterprise-tier `oauth2` absence stated
explicitly, boot/reload failure modes, and the showcase pointer. The two
connector-auth entries in `packages/spec/variant-docs.json` flip from
`exempt` to governed, so future auth variants must update the guide.
Releases nothing.
1 change: 1 addition & 0 deletions content/docs/ai/connect-mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,4 @@ skill and a guided `/objectstack:connect` command.
- [Actions](/docs/ui/actions) — defining the actions you expose
- [Your app as an MCP server](/docs/api#your-app-as-an-mcp-server) — the API-level view
- [AI Agents](/docs/ai/agents) — building agents *inside* your app (the other direction)
- [Connectors](/docs/automation/connectors) — the outbound counterpart: *consuming* an external MCP server as a flow-dispatchable connector (`provider: 'mcp'`)
363 changes: 363 additions & 0 deletions content/docs/automation/connectors.mdx

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion content/docs/automation/flows.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Each node performs a specific action in the flow.
| `map` | Sequential multi-instance — run a per-item subflow for each element, one at a time (each may pause); batch approval (ADR-0039) |
| `connector_action` | Execute an external connector action |

`connector_action` dispatches against the runtime **connector registry**, which connector plugins populate. The three **generic executors** — `rest`, `openapi`, and `mcp` — double as provider factories: with them in your app's `plugins:`, a declarative `connectors:` entry that names a `provider` is materialized into a live, dispatchable connector at boot with no plugin code (ADR-0097). Scaffolded projects (`npm create objectstack`) ship all three executors by default — paired with the `automation` capability that performs the materialization — and the showcase wires them too. Brand connectors (Slack, …) are installed separately. One security note: a declarative `mcp` instance using a **stdio** transport spawns a local process from metadata and is therefore denied by default — the host opts in with `new ConnectorMcpPlugin({ declarativeStdio: ['<trusted-command>'] })`; `http` transports need no opt-in.
`connector_action` dispatches against the runtime **connector registry**, which connector plugins populate. The three **generic executors** — `rest`, `openapi`, and `mcp` — double as provider factories: with them in your app's `plugins:`, a declarative `connectors:` entry that names a `provider` is materialized into a live, dispatchable connector at boot with no plugin code (ADR-0097). Scaffolded projects (`npm create objectstack`) ship all three executors by default — paired with the `automation` capability that performs the materialization — and the showcase wires them too. Brand connectors (Slack, …) are installed separately. One security note: a declarative `mcp` instance using a **stdio** transport spawns a local process from metadata and is therefore denied by default — the host opts in with `new ConnectorMcpPlugin({ declarativeStdio: ['<trusted-command>'] })`; `http` transports need no opt-in. [Connectors](/docs/automation/connectors) is the full authoring guide — provider config contracts, `credentialRef` auth, and failure modes.

### Node Structure

Expand Down
4 changes: 3 additions & 1 deletion content/docs/automation/index.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Automation
description: Hooks, flows, workflows, approvals, scheduled jobs, and durable webhooks — the process engine that reacts to your data.
description: Hooks, flows, workflows, approvals, scheduled jobs, durable webhooks, and connectors — the process engine that reacts to your data.
---

# Automation
Expand Down Expand Up @@ -33,6 +33,7 @@ export const OpportunityStageHook: Hook = {
- **Workflows** model a record's lifecycle as a **finite state machine**: states, transitions, and guards ([Workflows](/docs/automation/workflows)).
- **Approvals** are flow nodes with approver resolution, approve/reject decisions, and escalation ([Approvals](/docs/automation/approvals)).
- **Webhooks** deliver events to external systems through a **durable outbox** — exponential/linear/fixed retry with dead-lettering, HMAC signing, and an admin redeliver endpoint ([Webhook Delivery](/docs/automation/webhooks)).
- **Connectors** package external systems behind named actions that flows dispatch — registered by plugins, or **declared as pure metadata** (`provider: 'rest' | 'openapi' | 'mcp'`) and materialized at boot, with reference-based credentials ([Connectors](/docs/automation/connectors)).
- **Scheduled jobs** run on `setInterval` or cron via the job service, alongside `schedule`-type flows.

Rule of thumb: model *state* with workflows, model *steps* with flows, use hooks for *code-level* reactions, and webhooks to *notify the outside world*.
Expand All @@ -46,6 +47,7 @@ Rule of thumb: model *state* with workflows, model *steps* with flows, use hooks
<Card href="/docs/automation/workflows" title="Workflows" description="State-machine lifecycle modeling" />
<Card href="/docs/automation/approvals" title="Approvals" description="Approval nodes: approvers, decisions, escalation" />
<Card href="/docs/automation/webhooks" title="Webhook Delivery" description="Durable outbox, retries, HMAC signing" />
<Card href="/docs/automation/connectors" title="Connectors" description="Declarative rest/openapi/mcp instances, credentialRef auth" />
</Cards>

## Related
Expand Down
3 changes: 2 additions & 1 deletion content/docs/automation/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"flows",
"workflows",
"approvals",
"webhooks"
"webhooks",
"connectors"
]
}
4 changes: 2 additions & 2 deletions content/docs/capabilities/integrations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ A business system earns its keep by fitting into the systems — and habits —
- **Generated REST APIs** — every object gets standard endpoints automatically, so your website, mini-program, or ERP reads and writes through the same permission gate as people.
- **Webhooks out** — data changes notify external systems (*deal won → billing system opens an invoice*).
- **Triggers in** — external systems start platform [flows](/docs/capabilities/automation).
- **Connectors** — ready-made Slack and generic REST connectors drop into flows.
- **Connectors** — ready-made Slack and generic REST connectors drop into flows; an HTTP API, OpenAPI document, or MCP server can be [declared as metadata](/docs/automation/connectors) and goes live at boot, no plugin code.
- **Federated external databases** — point at an existing database and query it in place: no migration, visible in views, usable in flows.
- **Marketplace templates** — install complete apps (HotCRM among them) with one click: objects, views, flows, dashboards, and seed data included, then customize in Studio.
- **Deploy anywhere** — cloud or fully self-hosted; your data and your app definition stay yours.
Expand All @@ -27,4 +27,4 @@ Interface text — labels, options, messages — is translatable per language, a

> **In HotCRM**: the interface ships in four languages (English, Chinese, Japanese, Spanish); the Slack connector and web-to-lead intake demonstrate both directions of integration.

**For developers**: [API & SDK](/docs/api), [connectors and webhooks](/docs/automation), and [translations](/docs/ui/translations).
**For developers**: [API & SDK](/docs/api), [connectors](/docs/automation/connectors), [webhooks](/docs/automation/webhooks), and [translations](/docs/ui/translations).
11 changes: 6 additions & 5 deletions packages/spec/variant-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
" - the remaining exemptions now state the gap plainly instead of pointing at the",
" generated page as if it settled the question. Connector authentication is the one",
" worth acting on: it is tenant-authored (ADR-0097 declarative `connectors:`) and the",
" repo has no hand-written connector guide at all."
" repo has no hand-written connector guide at all. (Since closed: #4289 wrote",
" content/docs/automation/connectors.mdx and both connector-auth entries are governed.)"
],
"entries": [
{
Expand Down Expand Up @@ -80,14 +81,14 @@
{
"key": "type:api-key|basic|bearer|none|oauth2",
"label": "connector authentication",
"exempt": "generated-reference-only",
"reason": "DOCUMENTATION GAP, not a non-authorable surface — the strongest candidate among the exemptions for a real guide. Connector auth IS tenant-authored (ADR-0097 materializes a declarative `connectors:` entry naming a `provider` into a live connector at boot), but the repo has no hand-written connector page at all: the only prose is one paragraph inside automation/flows.mdx about the `connector_action` node. Until a guide exists there is nothing for this entry to bind to; when one is written, bind it and delete this exemption."
"docs": ["content/docs/automation/connectors.mdx"],
"note": "The runtime auth shape (ConnectorAuthConfigSchema) — five variants including the enterprise-tier `oauth2`. Was exempt generated-reference-only while no hand-written connector page existed; #4289 wrote the guide and bound it, per the old exemption's own instruction."
},
{
"key": "type:api-key|basic|bearer|none",
"label": "connector auth (environment-artifact projection)",
"exempt": "generated-reference-only",
"reason": "The declarative connector-instance auth shape (ADR-0097), reached via EnvironmentArtifactSchema.metadata.connectors[].auth. It carries a `credentialRef` rather than an inline secret, and omits `oauth2` because the authorization-code/refresh lifecycle is the enterprise tier (ADR-0015) — not because the artifact narrows it. Inherits the gap above; a connector guide would govern both."
"docs": ["content/docs/automation/connectors.mdx"],
"note": "The declarative connector-instance auth shape (ADR-0097), reached via EnvironmentArtifactSchema.metadata.connectors[].auth: `credentialRef` references only, and `oauth2` deliberately absent (enterprise tier, ADR-0015) — the guide states that absence explicitly so authors don't read it as an omission."
},
{
"key": "strategy:isolated_db|isolated_schema|shared_schema",
Expand Down
Loading