Skip to content

Latest commit

 

History

History
156 lines (114 loc) · 8.74 KB

File metadata and controls

156 lines (114 loc) · 8.74 KB

ADR-0010: Natural-Language → Flow Authoring (Platform Capability)

Status: Draft (2026-05-24) Authors: HotCRM (objectstack-ai/hotcrm) — surfacing requirements from the v1 launch story Consumers: @objectstack/service-ai, @objectstack/spec (automation), objectui (plugin-designer, plugin-chatbot), every app that ships flows


Context

HotCRM v1 launches on three "wow moments":

  1. Live Schema — agents pick up newly added fields on the next turn. Already shipped via the built-in describe_object tool re-reading metadata on every call.
  2. NL → Flow — admins describe an automation in English and get a runnable Flow. This ADR.
  3. Chat-first record pages — context-aware Copilot is the dominant surface on every record. Shipped at the app layer (objectui floating chatbot + AI Briefing slots).

Wow #2 is not CRM-specific. Every app (HR, Finance, Support, Marketing) needs the same capability: "when X happens to record Y, do Z" → runnable Flow definition. Building it in HotCRM would mean every app re-implements the prompt, the schema-grounding tool calls, the validation loop, and the persistence step.

Today an app can already wire the moving parts manually (skill instructions + describe_object + a custom action), but the result is brittle: every app authors its own "is this a valid Flow?" check, hallucinated field names slip through, and there's no shared way to take a validated Flow JSON and register it as a real, runnable workflow.

We propose moving the capability into the platform.

Goals

  • One built-in skill any agent can declare (flow_author or similar) that turns NL into a FlowSchema-shaped JSON, grounded in real metadata.
  • One built-in tool (propose_flow) that validates the candidate Flow against FlowSchema and returns structured errors the agent can self-correct from.
  • One built-in tool (register_flow) that persists a validated Flow into the metadata service, scoped to the active package (re-using ADR-0003 / ADR-0008 / ADR-0009 machinery).
  • Idempotent + replayable — running the same conversation twice doesn't create duplicate flows; updates target the same name.
  • Source-of-truth choice — apps can opt in to "AI-authored flows write through to the database package" (live) or "AI-authored flows emit a snippet for human PR" (GitOps).

Non-Goals

  • Visual flow editor / no-code designer (already covered by objectui/plugin-designer).
  • Inferring the intent of the trigger from telemetry — the user still has to say it in words.
  • Generating UI screens for type: 'screen' flows beyond the field list (deferred to a later RFC).
  • Replacing the existing defineFlow() TypeScript authoring path.

Proposed Components

1. propose_flow — Built-in AI Tool

Lives in @objectstack/service-ai/src/tools/propose-flow.tool.ts.

defineTool({
  name: 'propose_flow',
  label: 'Propose Flow',
  description:
    'Validate a candidate Flow definition. Returns { ok: true, name, preview } ' +
    'on success or { ok: false, errors[] } on failure so the calling agent can ' +
    'self-correct before showing the user.',
  category: 'automation',
  builtIn: true,
  parameters: {
    type: 'object',
    properties: {
      flow: {
        type: 'object',
        description: 'Candidate Flow JSON matching FlowSchema',
      },
    },
    required: ['flow'],
  },
});

The handler runs FlowSchema.safeParse(flow) (from @objectstack/spec/automation) and surfaces every Zod issue as a flat errors: string[]. No I/O, no side effects.

2. register_flow — Built-in AI Tool

defineTool({
  name: 'register_flow',
  description: 'Persist a validated Flow into the active package. Idempotent on flow.name.',
  category: 'automation',
  builtIn: true,
  parameters: {
    type: 'object',
    properties: {
      flow: { type: 'object', description: 'Flow JSON, must pass propose_flow first.' },
      packageId: { type: 'string', description: 'Optional. Defaults to conversation.activePackage.' },
    },
    required: ['flow'],
  },
});

Handler:

  1. Re-validate with FlowSchema.parse().
  2. Resolve target package via the same resolvePackageId(ctx, explicitPackageId) helper used by create_object / add_field (read-only filesystem packages rejected).
  3. ctx.metadataService.register('flow', flow.name, flow) — same path manual code uses.
  4. Return { ok: true, name, packageId }.

Side effects: writes through to the metadata repo (ADR-0008) → change is captured in the audit log, the runtime hot-reloads the flow, and any record-triggered flows become live on the next save.

3. flow_author — Built-in Skill

Lives in @objectstack/service-ai/src/skills/flow-author.skill.ts. App agents opt in by name: skills: ['flow_author', ...].

Skill bundle:

  • tools: list_objects, describe_object, propose_flow, register_flow
  • instructions: enforce the describe → compose → propose → fix → register loop, including the rule "never invent a field name; always describe_object first".
  • triggerPhrases: "when a", "whenever", "automate", "every time", "set up a flow".
  • permissions: automation:flow:write.

The skill is platform-owned so every app inherits the same hardened prompt as we tighten it. Apps still pick whether their agents enable it.

4. Spec changes — minimal

Existing FlowSchema already validates the candidate. We need:

  • Confirm FlowSchema.safeParse returns issue paths usable verbatim by an LLM (issues[].path.join('.')).
  • Add a defineFlow.toJSON() convenience or document that JSON.stringify(defineFlow(x)) is round-trippable.

No new spec surface area.

Source-of-Truth Modes

Two deployment modes apps choose between via package configuration:

Mode Where Flows Land Suitable For
live (default) register_flow writes to the active database package. Hot-reloaded. Hosted SaaS tenants — admins iterate in-product, AI-authored flows go live immediately.
gitops register_flow is gated; instead the agent surfaces the validated JSON in a fenced code block + a path src/flows/<name>.flow.ts for human PR. Self-hosted enterprise — every metadata change must land in source control.

Mode toggled per package via pkg.aiAuthoring: 'live' | 'gitops' in the package manifest (ADR-0003). Skill instructions branch on this flag.

Open Questions

  1. Trigger ambiguity. "When an opportunity is won" — should the trigger be update with condition stage == 'closed_won', or a stage-transition event if we add one? Skill instructions should default to update + condition and ask one clarifying question if the user used a verb that maps to multiple options.
  2. Screen flows. Agents can produce the type: 'screen' shape, but register_flow for screen flows means the flow appears in nav menus instantly. Do we require an extra assignedProfiles parameter, or default to system_administrator only?
  3. Roll-back. ADR-0008's metadata change log already captures every write. Do we need a sibling unregister_flow tool, or rely on the standard "revert to checkpoint" path?
  4. Cross-object references. When the user says "when a deal is won, create a case", describe_object('crm_case') reveals required fields (e.g. priority). Should the skill auto-fill required fields with sensible defaults from option lists, or stop and ask?
  5. Test/dry-run. Should register_flow accept a dryRun: true parameter that returns the projected effect (which records would trigger, what they'd write) without committing? Strongly recommended for production safety.

HotCRM Migration Path

HotCRM has a placeholder live_data skill that grounds Copilot answers in the live schema. Once flow_author ships:

  1. Add 'flow_author' to sales_copilot.skills[].
  2. Drop the explicit cut we made when removing the in-CRM flow_designer draft (commit retained in branch feat/wow-2-flow-designer-draft).
  3. Update content/docs/ai-copilot/live-schema.mdx with a Wow #2 sibling page.

No CRM data model changes.

Decision

Pending platform review. HotCRM v1 launch (W9) will ship without Wow #2 unless this ADR lands and the tools/skill are released; the launch deck currently leans on Wow #1 + Wow #3 alone.

References

  • @objectstack/spec/automation/flow.zod.tsFlowSchema, defineFlow.
  • @objectstack/service-ai/src/tools/metadata-tools.ts — pattern to mirror for propose_flow / register_flow.
  • @objectstack/service-ai/src/tools/describe-object.tool.ts — single-source-of-truth tool file pattern.
  • ADR-0003 — package-as-first-class-citizen (target for register_flow).
  • ADR-0008 — metadata repository + change log (provides idempotency + audit).
  • HotCRM content/docs/ai-copilot/live-schema.mdx — Wow #1 marketing copy that sets up Wow #2.