Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

11 KiB

PRD — Workflow Markdown Text Composer

  • Slug: workflow-markdown-text-composer
  • Date: 2026-03-14
  • Status: Draft

Summary

Add a standard workflow transform action for composing one or more named markdown text outputs from literal content plus simple workflow references. Authoring should use a constrained BlockNote-based inline chip editor for a high-quality WYSIWYG experience, while persistence and runtime should use an Alga-owned template document model and emit plain markdown strings.

Problem

Workflow authors currently have two poor options when they need richer text composition:

  • write a single literal string directly in a consuming field such as ai.infer.prompt
  • wire a single reference into that field from elsewhere

That breaks down when authors need to build prompts, email bodies, summaries, or notification text from several pieces of workflow context. Prompt-specific templating inside ai.infer would solve the symptom in one place but would create improper layering and leave email and notification composition unsolved.

The workflow system already has a transform category for building derived values. Text composition belongs there, but the current text transforms are scalar utilities such as concat, replace, join, or trim. They do not provide:

  • multi-output authoring
  • inline reference placeholders
  • markdown-capable editing
  • explicit missing-reference failure semantics

There is also a UX gap. Placeholder-string editing in a plain text box is easy for engineering, but not ideal for authors. We already have BlockNote infrastructure and custom inline content patterns in the repo, which can support a more natural authoring surface if we keep BlockNote confined to the UI layer.

Goals

  • Introduce a dedicated standard transform action for text composition rather than adding prompt-specific behavior to ai.infer.
  • Support multiple related text outputs in a single step.
  • Let authors use freeform output labels while preserving stable downstream reference paths.
  • Provide a constrained BlockNote-based editor with inline reference placeholders for authoring.
  • Persist an Alga-owned template document model rather than BlockNote JSON.
  • Render composed outputs to markdown strings at runtime.
  • Fail execution explicitly when any referenced value is missing.
  • Surface composed outputs in downstream workflow reference browsing and validation.

Non-goals

  • No AI-specific prompt builder embedded into consuming actions.
  • No inline launch of the composer from ai.infer.prompt or other fixed-value fields in this phase.
  • No generic expression segments, nested transform invocation, or arbitrary code execution inside templates.
  • No media, attachments, tables, or other document-heavy BlockNote concepts in the composer.
  • No HTML output from the transform itself; markdown-to-HTML conversion remains the responsibility of downstream consumers.
  • No broad reusable rich-editor platform for all workflow fields in this phase.

Users and Primary Flows

  • Workflow authors building AI prompts, email bodies, customer-facing summaries, internal notes, or notification text from payload and prior step outputs.

Primary flows:

  • Author adds a transform.compose_text step and saves it as composed.
  • Author creates several related outputs in the same step such as “Prompt”, “Email Body”, and “Summary”.
  • Author writes markdown-friendly text with inline reference placeholders chosen from the workflow source browser.
  • Author maps downstream action fields by reference, for example vars.composed.prompt.
  • Workflow runtime resolves references, renders markdown strings, and fails the step if a referenced value is missing.

UX / UI Notes

  • The composer exists only as a dedicated transform action editor.
  • The editor shows a list of outputs, each with:
    • freeform author label
    • generated stable reference key
    • constrained BlockNote editing surface
  • The UI should present the author label prominently and the stable reference key secondarily, including a copyable downstream reference path.
  • The editing surface should feel WYSIWYG:
    • inline reference chips instead of raw placeholder syntax
    • markdown-safe text formatting only
    • no media insertion affordances
  • Authors should be able to:
    • add, rename, delete, and reorder outputs
    • add literal text
    • insert simple references from existing workflow data context
    • see validation issues for duplicate labels, duplicate keys, or invalid references
  • The UI may show a serialized markdown preview or reference summary, but v1 does not need resolved runtime-value preview.

Requirements

Functional Requirements

  • The workflow runtime must register a new dedicated transform action for text composition under the Transform category.
  • The action must support multiple named outputs inside one step.
  • Each authored output must have a freeform display label.
  • Each authored output must also have a stable, reference-safe key used for downstream paths and schema fields.
  • Stable keys must be generated automatically from display labels and remain stable across later label edits unless the user explicitly regenerates them.
  • The persisted action config must store an Alga-owned template document model rather than BlockNote JSON.
  • The template document model must support markdown-capable text structure plus inline reference nodes without leaking BlockNote-specific node shapes.
  • Reference nodes must only allow simple workflow references, not arbitrary expressions or nested transform definitions.
  • The dedicated editor must use a constrained BlockNote-based surface for authoring and must round-trip between BlockNote UI state and the Alga-owned template document model.
  • The constrained editor must disable media and other unsupported content types.
  • Runtime execution must resolve references against workflow context and render each output to a markdown string.
  • Runtime execution must fail the step if any referenced value is missing, identifying the output and reference that failed.
  • The action result must be a plain object of markdown strings keyed by stable reference-safe keys.
  • Workflow output schema derivation must reflect the configured composed outputs so downstream reference browsing and validation expose the correct fields.
  • Downstream actions such as ai.infer, email actions, and notifications must consume composed outputs via ordinary reference mode with no special-case integration.

Non-functional Requirements

  • The composer must stay reusable and not introduce AI-specific layering into workflow actions.
  • BlockNote must remain an authoring-only dependency for this feature; runtime contracts and stored step config must remain independent of BlockNote internals.
  • The chosen markdown-capable editing subset must be intentionally constrained to features that round-trip cleanly through the Alga-owned model and markdown renderer.
  • Validation and schema derivation must remain deterministic so downstream references do not drift after author label edits.

Architecture

  • Runtime layer:
    • new transform.compose_text action definition
    • config schema for outputs and template document structure
    • runtime renderer from template document model to markdown strings
    • missing-reference failure handling
  • Designer layer:
    • dedicated compose-text step editor
    • constrained BlockNote schema with inline reference placeholder node
    • serialization/deserialization between editor content and template document model
    • output list management and stable key affordances
  • Schema / reference layer:
    • dynamic output schema derivation for configured composed outputs
    • workflow data context and reference browser support for vars.<saveAs>.<stableKey>

Data / API / Integrations

Recommended persisted config shape:

type ComposeTextStepConfig = {
  actionId: 'transform.compose_text';
  version: 1;
  outputs: Array<{
    id: string;
    label: string;
    stableKey: string;
    document: TemplateDocument;
  }>;
};

type TemplateDocument = {
  version: 1;
  blocks: TemplateBlock[];
};

type TemplateBlock =
  | { type: 'paragraph'; children: TemplateInlineNode[] }
  | { type: 'bullet_list_item'; children: TemplateInlineNode[] }
  | { type: 'ordered_list_item'; children: TemplateInlineNode[] }
  | { type: 'heading'; level: 1 | 2 | 3; children: TemplateInlineNode[] }
  | { type: 'blockquote'; children: TemplateInlineNode[] }
  | { type: 'code_block'; text: string };

type TemplateInlineNode =
  | { type: 'text'; text: string; marks?: Array<'bold' | 'italic' | 'code' | 'link'>; href?: string }
  | { type: 'reference'; path: string; label: string };

Notes:

  • The exact block subset can be refined, but it must remain markdown-compatible and must exclude media-heavy nodes.
  • label is author-facing and freeform.
  • stableKey is reference-safe and immutable by default so downstream vars.<saveAs>.<stableKey> paths do not break when the author changes the display label.
  • The registry output schema may be broad at definition time, but publish-time/designer-time output schema resolution must override it with a config-derived object schema containing one string field per configured stableKey.

Security / Permissions

  • No new permissions are introduced.
  • Existing workflow authoring and workflow read/update permission gates continue to govern access.
  • The composer must not allow arbitrary expression execution or secret resolution outside the existing workflow reference/runtime mechanisms.

Observability

  • No new observability or metrics work is in scope for this phase.

Rollout / Migration

  • Add the new transform action without changing existing actions.
  • Existing workflows remain untouched.
  • New workflows may adopt transform.compose_text incrementally.
  • AI prompt composition, email body composition, and similar use cases should migrate by adding an upstream compose-text step rather than modifying consuming action contracts.

Open Questions

  • Exact markdown-capable formatting subset for v1 should be finalized during implementation, but it should remain deliberately narrower than a full document editor.
  • Whether the UI should expose explicit “regenerate stable key” behavior on rename or keep that as an advanced secondary control needs a final UX call.
  • Whether a serialized markdown preview adds enough value in v1 to justify the extra UI surface remains optional.

Acceptance Criteria (Definition of Done)

  • Workflow authors can add a dedicated transform action that composes one or more markdown text outputs from literal content and simple references.
  • The authoring experience uses a constrained BlockNote-based editor with inline reference placeholders and no media affordances.
  • The stored step config uses an Alga-owned template document model rather than BlockNote JSON.
  • Each output has a freeform author label and a stable downstream reference-safe key.
  • Runtime execution renders each configured output to a markdown string.
  • Missing referenced values fail the step explicitly instead of silently producing empty strings.
  • Downstream workflow authoring surfaces expose composed outputs under vars.<saveAs>.<stableKey>.
  • Consuming actions continue to use ordinary string references and require no prompt-specific or email-specific composition logic.