This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docs/archive/DESIGN-0.26.0.md
2026-03-11 14:45:37 +00:00

14 KiB
Raw Blame History

DESIGN — v0.26.0: Workflow Engine

Status: Shipped (v0.26.0v0.26.5, 15 changesets) Branch: 0.26.0 Scope: Team-owned staged processes, AI intake, human assignment, visitor experience Depends on: Dynamic surfaces (v0.25.0), multi-participant channels (v0.23.x), anonymous identity (v0.24.3), permissions (v0.24.2)


Phasing

Six sub-releases. Each is shippable and testable independently. Deferred tech debt from v0.21v0.25 absorbed into v0.26.0 (phase 0).

v0.26.0  Foundation: cleanup + context-aware tool system
           │
v0.26.1  Workflow definitions + versioning (schema + CRUD)
           │
v0.26.2  Workflow instances + stage transitions (runtime)
           │
v0.26.3  Visitor experience (surfaces + branded chat)
           │
v0.26.4  AI intake + assignment queue
           │
v0.26.5  Team collaboration + workflow builder UI

v0.26.0 — Foundation

Cleanup debt, then build the tool infrastructure that workflows need.

Deferred Cleanup (absorb from v0.21v0.25)

Session cleanup job

  • Background goroutine: delete session_participants older than N days with no associated messages
  • Configurable via SESSION_EXPIRY_DAYS env var (default: 30)
  • Runs on startup + every 6h
  • Closes v0.24.3 deferred item

Stale code TODOs

  • surfaces.go:108-109 — surface delete: clean up static assets + templates from SURFACE_ASSET_DIR/{id}/ and SURFACE_TEMPLATE_DIR/{id}/
  • completion.go:164 — remove misleading TODO comment (pricing IS populated in recordUsage() at line ~1996)
  • intrinsic.go:19 — remove stale "TODO: 0.9.2" comment (shipped in v0.22.0)

Roadmap housekeeping

  • Mark shipped items in "Technical Debt + Deferred Items" section:
    • Rate limit tracking (v0.22.4)
    • Auto-disable policy (v0.22.4)
    • Tool health recording (v0.22.4)
    • PDF export via pandoc (v0.22.4)
    • Persona tool grant enforcement (v0.25.0)
  • Clean up stale deferred-into version markers

Context-Aware Tool System

Absorbed from v0.25.0 roadmap. Prerequisite for workflow tool scoping.

ToolContext struct (tools/types.go)

  • Fields: ChannelType, WorkspaceID, WorkflowID, TeamID, PersonaID, IsVisitor
  • Populated from channel record in completion handler before tool execution

Require predicates

  • Availability() Require method on Tool interface
  • BaseTool embed: defaults to AlwaysAvailable (backward compat)
  • Built-in predicates: RequireWorkspace, RequireWorkflow, RequireTeam, DenyVisitor, All()
  • tools.AvailableFor(tctx, disabled) replaces AllDefinitionsFiltered()

Self-declaring tools

  • Workspace tools: RequireWorkspace + DenyVisitor
  • Git tools: RequireWorkspace + DenyVisitor
  • workspace_create: available only when no workspace bound
  • Memory/notes tools: DenyVisitor
  • Eliminates WorkspaceToolNames() / GitToolNames() manual suppression

ExecutionContext extension

  • Add WorkflowID, TeamID to existing ExecutionContext
  • Populated from channel record in completion handler

Persona tool grant enforcement hardening

  • v0.25.0 shipped the second-pass allowlist in completion.go:917
  • For workflows: version snapshot must include persona tool grants at snapshot time (frozen for running instances)

Route Namespaces

Two distinct namespaces. No collision.

/s/:slug — Extension Surfaces (application extensions)

  • Single-page, self-contained sub-applications
  • Examples: custom dashboard, kanban board, form builder
  • One template, one JS entry point, scoped CSS
  • Registered via surface manifest (v0.25.0 surface_registry)

/w/:scope/:slug — Workflows (business logic automation)

  • :scope is team-slug or global — workflows belong to a team or are org-wide. Prevents slug collisions across teams.
  • Multi-page: landing, visitor chat, team review, admin tracking — different views depending on who is accessing (visitor vs. team member vs. admin)
  • Involves customers and team members, possibly spanning multiple teams
  • Purpose-built Go templates per view, not a single-page pattern

Both use Go template rendering. They share base.html but have independent template trees and JS entry points.

Migration

  • 023_v0260_foundation.sql: session cleanup additions (if schema changes needed), no new tables in this phase

v0.26.1 — Workflow Definitions + Versioning

Schema and CRUD for defining workflows. No runtime yet.

Tables

workflows

  • id, team_id (nullable — NULL = global), name, slug (unique within scope: UNIQUE(team_id, slug) with partial index for global), description
  • branding (JSONB: accent color, logo URL, tagline)
  • entry_mode (enum: public_link, team_only)
  • is_active, version (auto-increment on edit)
  • on_complete (JSONB, nullable — v0.27.0 chaining hook, NULL for now. Future schema: {"action": "start_workflow", "target_slug": "...", "data_map": {...}}. Column exists early so the table doesn't need migration when chaining lands.)
  • retention (JSONB — {"mode": "archive"|"delete", "delete_after_days": N}. Default: {"mode": "archive"})
  • created_by, created_at, updated_at

workflow_stages

  • id, workflow_id, ordinal, name
  • persona_id (FK — persona drives this stage)
  • assignment_team_id (FK — which team handles human review)
  • form_template (JSONB — fields the persona should collect)
  • history_mode (enum: full, summary, fresh — default full)
  • auto_transition (bool — advance automatically when form complete)
  • transition_rules (JSONB — conditions, round-robin config)

workflow_versions

  • id, workflow_id, version_number
  • snapshot (JSONB — full serialized definition + stages + tool grants)
  • created_at

API

  • Team-admin CRUD: create/edit/delete workflows and stages
  • Reorder stages (PATCH ordinal)
  • workflow.create permission required
  • Publish action: snapshot current definition → workflow_versions
  • Slug validation: lowercase, alphanumeric + hyphens, unique within scope (same slug can exist under different teams). URL resolves as /w/team-slug/workflow-slug or /w/global/workflow-slug.

Design Decisions (to flesh out)

  • Branding schema: minimal (accent + logo + tagline) or extensible JSONB?
  • Stage persona: must be team-scoped persona? Or any accessible persona?

Migration

  • 023_v0261_workflows.sql: workflows, workflow_stages, workflow_versions

v0.26.2 — Workflow Instances + Stage Transitions

Channels become workflow runtime containers.

Channel Extensions

  • workflow_id, workflow_version columns on channels (populated on workflow channel creation)
  • current_stage (ordinal), stage_data (JSONB)
  • workflow_status enum: active, completed, stale, cancelled
  • last_activity_at tracking

Entry Point

  • Public link: /w/:scope/:slug → creates workflow channel, adds anonymous session participant (v0.24.3), binds stage 1 persona, auto-creates workspace. :scope is team slug or global.
  • Team-only: same flow but requires authenticated user

Stage Transitions

  • AI-triggered: workflow_advance tool (see v0.26.4)
  • Human-triggered: button in channel header
  • Rejection: return to previous stage with reason text
  • On transition: swap active persona, notify assignment team, update channel metadata, create channel-scoped note with collected data

History mode (per-stage, configurable in workflow_stages):

  • full — new persona sees complete conversation history with a system boundary message (same pattern as @mention context boundaries, v0.23.0). Simplest to implement, best for continuity-sensitive workflows.
  • summary — utility-role summarization of prior stages injected as a system message. New persona starts with context but not raw history.
  • fresh — new persona sees nothing from prior stages. Clean slate. Simplest for independent review stages.

Default: full. Stored as history_mode enum on workflow_stages.

Staleness Sweep

  • Background goroutine (like health accumulator pattern)
  • Marks idle instances as stale after configurable threshold
  • Stale UX: visitor sees "Continue or Start Over" (start over = new instance on latest version)

Migration

  • Adds columns to channels, or separate workflow_instances table (TBD — inline columns simpler, separate table cleaner)

v0.26.3 — Visitor Experience

Purpose-built surfaces for anonymous workflow participants.

Landing Page

  • GET /w/:scope/:slug — branded page with persona avatar, description, "Start"
  • Go template: workflow-landing.html
  • Reads workflow.branding JSONB for accent color, logo, tagline
  • System dark/light mode (no theme toggle — visitors don't have prefs)

Visitor Chat

  • GET /w/:scope/:slug/c/:channelId — bubble chat (NOT full ChatPane)
  • workflow-chat.js: lightweight WebSocket client
    • Message send/receive
    • Markdown rendering (marked.js + DOMPurify, already available)
    • Typing indicator
    • Stage transition animation (visual feedback on advance)
  • Scoped: no sidebar, no settings, no navigation
  • Session auth via AuthOrSession middleware (v0.24.3)

Tool Scoping

  • DenyVisitor predicates prevent visitors from accessing workspace, git, memory, notes tools
  • Persona tool grants further restrict per-stage

Design Decisions (to flesh out)

  • Visitor can upload files? (attachments to workflow channel)
  • Visitor can see previous stage history? (probably not — each stage is a clean persona conversation)
  • Mobile-first layout for visitor surfaces

v0.26.4 — AI Intake + Assignment Queue

The AI does the data collection. Humans review and act.

workflow_advance Tool

  • RequireWorkflow availability predicate
  • Input: collected form data (JSONB matching form_template)
  • Validates all required fields present
  • Triggers stage transition (same path as human-triggered)
  • Creates channel-scoped note with structured form response

Form Template → System Prompt

  • Stage form_template JSONB injected into persona system prompt: "Collect the following information from the visitor: [field list]"
  • Persona conducts conversational intake
  • When all fields gathered → calls workflow_advance with data
  • Rejection: persona sees rejection reason in conversation, re-collects

Assignment Queue

workflow_assignments table

  • id, channel_id, stage (ordinal), team_id
  • assigned_to (nullable user_id), status (unassigned/claimed/completed)
  • created_at, claimed_at, completed_at

Claim model

  • Unassigned workflow channels visible to all team members
  • Optimistic lock: UPDATE ... WHERE status = 'unassigned'
  • Round-robin auto-assignment (optional, per-stage transition_rules)

Notifications

  • New workflow assignment → notification to team (existing infra)
  • WebSocket push to online team members
  • Claim confirmation notification to claimer

Migration

  • workflow_assignments table

v0.26.5 — Team Collaboration + Workflow Builder UI

Frontend surfaces for building and managing workflows.

Team Member View

  • Assigned member sees full history (AI intake + artifacts + notes)
  • Persona remains active — assists both visitor and team member
  • Member can: advance stage, reject (with reason), add notes, invoke tools, reassign, escalate

Workflow Builder

  • Team admin panel section
  • Stage list editor: add/remove/reorder stages
  • Per-stage config: persona picker, assignment team, form template editor
  • Branding editor: accent color, logo upload, tagline
  • Publish button (creates version snapshot)
  • Read-only tool grants display per stage persona

Channel Header (Workflow Mode)

  • Workflow stage indicator (step N of M, stage name)
  • Advance / Reject buttons (permission-gated)
  • Assignment info (who claimed, when)
  • History mode indicator (full/summary/fresh)

Queue UI

Prototype both approaches in v0.26.5, decide based on usage:

Option A: Sidebar section for team members — shows unassigned workflow channels for user's teams, count badge, click opens in main pane. Low friction, always visible.

Option B: Dedicated surface (/workflows or team-admin view) for tracking and management — full table with filters, assignment history, metrics. Better for high-volume operations.

Likely outcome: both. Sidebar for team members (day-to-day claims), dedicated surface for team admins (tracking, reporting, bulk ops).


Resolved Decisions

  1. Workflow channel lifecycle. Configurable per-workflow retention policy. Default: archive (read-only, ai_mode='off', no new messages). Optional: auto-delete after N days. Stored as retention JSONB on workflows table.

  2. Multi-stage persona conversations. Three modes, configurable per-stage via history_mode enum on workflow_stages:

    • full — complete history + boundary message (default, simplest)
    • summary — utility-role summarization injected as system message
    • fresh — clean slate, no prior context First and third are simplest to implement; ship those first, summary can land as a follow-up.
  3. Visitor re-entry. Resume if session cookie matches and instance is active. Otherwise start new on latest version.

  4. Workflow-to-workflow chaining. Deferred to v0.27.0 (tasks/agents). on_complete JSONB column on workflows table ships as nullable in v0.26.1 migration so the schema is pre-wired. v0.27.0 populates it and adds the trigger logic. No migration needed when chaining lands.

  5. Route namespaces. /s/:slug for extension surfaces (single-page sub-apps). /w/:scope/:slug for workflows (multi-page, role-dependent views). No collision. See "Route Namespaces" in v0.26.0.


Cross-Cutting Concerns

Testing strategy: Integration tests per phase. v0.26.0 tool context tests. v0.26.1 workflow CRUD + versioning tests. v0.26.2 stage transition tests. v0.26.4 assignment claim concurrency test.

Migration numbering: Single migration per phase (023, 024, ...) or consolidated? Leaning toward: one per phase, squash at tag time if needed.

Backward compat: Non-workflow channels unaffected. ToolContext with BaseTool defaults means existing tools work without changes. Workflow columns on channels are nullable.