Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
b1f4794
chore(docs): remove outdated demo notes (#169)
librowski Sep 22, 2026
052c396
Design System 2.0 (#170)
librowski Sep 24, 2026
86cb192
fix: address the Design System 2.0 clickthrough findings (#180)
librowski Sep 28, 2026
5d656a4
chore(ui): collapse the pre-release changesets into one first-release…
librowski Sep 28, 2026
5e768a8
fix(ui): let the Select popup grow to fit its widest option (#185)
librowski Sep 29, 2026
6423cac
docs(ui): add a UI API Reference and link prop types to it (#179)
librowski Sep 30, 2026
c2d5a23
feat(temporal): durable pause. A run stops at a node and waits for a …
piotrblaszczyk Sep 8, 2026
91bbc14
fix(execution-core): register the wait before announcing it (#129)
piotrblaszczyk Sep 10, 2026
25a3932
feat(backend): decision request. A node asks a human to decide before…
piotrblaszczyk Sep 14, 2026
f4a34b9
Feat/wb 501 decision endpoint (#133)
piotrblaszczyk Sep 15, 2026
ff8cd85
feat(ai-studio): human decision node. A run parks on the canvas until…
piotrblaszczyk Sep 17, 2026
6884a58
fix(backend): decision request requires an explicit port on resume an…
piotrblaszczyk Sep 22, 2026
a1b8ff1
feat: a rejection ends the run as a result, not a dead end (#167)
piotrblaszczyk Sep 22, 2026
3d4375d
feat(ai-studio): a running execution survives reload
jimmeryn Sep 22, 2026
3efd1ab
fix(ai-studio): treat a refused execution stream as lost at once
jimmeryn Sep 22, 2026
3befce1
fix(ai-studio): address review of the reload-surviving run
jimmeryn Sep 24, 2026
d2db900
feat(ai-studio): the decider approves or rejects in the properties si…
piotrblaszczyk Sep 24, 2026
502ae4e
feat: AI Agent structured output (#172)
dawidaksamski Sep 25, 2026
14bea90
feat(backend): executions:list auth action for the executions collection
DominikaPacholec-Synergy Sep 18, 2026
bd34205
feat(backend): list-executions query. Filters, tenant scope and a key…
DominikaPacholec-Synergy Sep 18, 2026
9b5c2a5
feat(backend): GET /api/executions lists runs newest first, filtered …
DominikaPacholec-Synergy Sep 21, 2026
7c2f5f7
feat(types): execution list response types
DominikaPacholec-Synergy Sep 21, 2026
ba22b94
docs(backend): GET /api/executions, the executions listing
DominikaPacholec-Synergy Sep 21, 2026
727b238
fix(backend): executions list refuses cursors Postgres would, treats …
DominikaPacholec-Synergy Sep 21, 2026
305e863
fix(backend): executions list refuses a tenant context with no id, an…
DominikaPacholec-Synergy Sep 23, 2026
150e6d6
fix(backend): executions list refuses a non-string tenant id, pins th…
DominikaPacholec-Synergy Sep 28, 2026
f347c4a
docs(backend): restore the executions-created-at-millis follow-up marker
DominikaPacholec-Synergy Sep 28, 2026
7207e60
feat(ai-studio): the decider's fields read and write the contract's o…
jimmeryn Sep 25, 2026
ca61b36
feat(ai-studio): pick decider's fields, stored in the contract's format
jimmeryn Sep 25, 2026
536c0dc
fix(ai-studio): the final review's findings on the decision fields
jimmeryn Sep 25, 2026
d741e12
test(ai-studio): the decision fields come back beside the settled dec…
jimmeryn Sep 25, 2026
f8c9463
feat(ai-studio): the decider's fields sit in their own collapsible se…
jimmeryn Sep 25, 2026
3df78aa
fix(ai-studio): the decision form sends what it shows when the picks …
jimmeryn Sep 25, 2026
9dc9310
refactor(ai-studio): the field mode row moves to its own file
jimmeryn Sep 25, 2026
dbfe83f
fix(ai-studio): a re-opened decision form starts new fields from prop…
jimmeryn Sep 28, 2026
ccce7bb
test(ai-studio): pin the run lock and required pruning in decision fi…
jimmeryn Sep 28, 2026
c7a8e83
docs(ai-studio): say which field types the decision fields leave out
jimmeryn Sep 28, 2026
3042e59
feat(ai-studio): the decision fields say when the block before declar…
jimmeryn Sep 28, 2026
5d99e2e
fix(ai-studio): the decision form follows the selection between decis…
jimmeryn Sep 28, 2026
aec0975
fix(ai-studio): the decision fields hint each cause a source is missing
jimmeryn Sep 28, 2026
a552c23
chore(ai-studio): the form control comment says what reading data breaks
jimmeryn Sep 28, 2026
af1720a
fix(ai-studio): the decision fields hide from Run until Reset
jimmeryn Sep 28, 2026
c18e1ce
fix: harden HITL before the merge to main (#183)
piotrblaszczyk Sep 29, 2026
b547304
fix(ai-studio): a required field the decider empties holds Approve ba…
piotrblaszczyk Sep 30, 2026
7f58552
feat(ai-studio): the waiting-for-decision flow follows the design pro…
piotrblaszczyk Sep 30, 2026
6fe3778
fix(lint): stylelint and the docs lint work on Windows (#175)
jimmeryn Sep 30, 2026
eaf15e6
feat: a link opens a workflow or a run in AI Studio (#186)
dawidaksamski Oct 1, 2026
a524aad
docs(release): prepare main for SDK 3.0, UI 1.0 and Temporal 0.2.0 (#…
librowski Oct 2, 2026
d168d73
chore(deploy): cap the bundled Temporal server at 2 CPUs and 1.5 GB (…
librowski Oct 2, 2026
4bbe651
chore(release): sdk 3.0.0, ui 1.0.0, temporal 0.2.0 (#196)
piotrblaszczyk Oct 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 0 additions & 7 deletions .changeset/move-ui-library-in-repo.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/sdk-date-picker-trigger-height.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/sdk-is-start-node-flag.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/sdk-single-top-layer.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/sdk-ssr-modal-portal.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/ui-base-ui-1-7.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/ui-export-prop-types.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/ui-export-use-edge-style-params.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/ui-layer-root-defaults.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/ui-react-18-peer.md

This file was deleted.

42 changes: 25 additions & 17 deletions .github/workflows/deploy-ai-studio.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,35 +90,43 @@ jobs:
# The VM runs the repo's compose files, shipped here on every deploy (base64,
# so the script stays free of quoting). Compose is run from the project
# directory, not with -f: that is what applies docker-compose.override.yml
# by default and honours COMPOSE_FILE from the VM's .env.
# by default.
#
# The retired-key check runs before anything is written, so a refused deploy
# leaves the VM exactly as it was. It lives here rather than in the compose
# file because Compose 2.21 and older evaluate a nested `${A:+${B:?}}` guard
# eagerly and fail on every command, key set or not.
#
# The image tags are written into that .env rather than exported: an export
# dies with this shell, and the next `docker compose up -d worker` on the VM
# would fall back to the local ai-studio-* names. Only the two image lines
# are replaced; the rest of .env is the VM's own and stays untouched.
# .env is generated in full from the repo secrets/vars on every deploy,
# so nothing on the VM is edited by hand. It holds the image tags too: an
# export dies with this shell, and the next `docker compose up -d worker`
# on the VM would fall back to the local ai-studio-* names.
- name: Refresh docker compose on Azure VM
env:
IMAGE: ${{ env.REGISTRY }}/${{ env.APP }}:${{ needs.build-and-push.outputs.image_tag }}
# repo-level secrets for credentials, vars for the rest — no `environment:`,
# which would change the OIDC subject the Azure federated credential trusts
AI_API_KEY: ${{ secrets.AI_API_KEY }}
TAVILY_API_KEY: ${{ secrets.TAVILY_API_KEY }}
APP_DB_PASSWORD: ${{ secrets.APP_DB_PASSWORD }}
TEMPORAL_DB_PASSWORD: ${{ secrets.TEMPORAL_DB_PASSWORD }}
AI_BASE_URL: ${{ vars.AI_BASE_URL }}
AI_MODEL: ${{ vars.AI_MODEL }}
RATE_LIMIT_EXECUTE_PER_MINUTE: ${{ vars.RATE_LIMIT_EXECUTE_PER_MINUTE || '10' }}
RATE_LIMIT_EXECUTE_PER_DAY: ${{ vars.RATE_LIMIT_EXECUTE_PER_DAY || '50' }}
run: |
# the databases keep the password they were created with — an empty one
# would fall back to the compose default and lock the apps out
: "${APP_DB_PASSWORD:?set secret APP_DB_PASSWORD}" "${TEMPORAL_DB_PASSWORD:?set secret TEMPORAL_DB_PASSWORD}"
# .env is generated in full on every deploy; single quotes keep values literal
ENV_B64=$(for k in AI_API_KEY AI_BASE_URL AI_MODEL TAVILY_API_KEY \
RATE_LIMIT_EXECUTE_PER_MINUTE RATE_LIMIT_EXECUTE_PER_DAY \
APP_DB_PASSWORD TEMPORAL_DB_PASSWORD; do
printf "%s='%s'\n" "$k" "${!k}"
done | cat - <(printf "RUNTIME_IMAGE='%s'\nWEB_IMAGE='%s'\n" "$IMAGE-runtime" "$IMAGE-web") | base64 -w0)
COMPOSE_B64=$(base64 -w0 deploy/ai-studio/docker-compose.yml)
OVERRIDE_B64=$(base64 -w0 deploy/ai-studio/docker-compose.override.yml)
SCRIPT=$(cat <<EOF
set -e
cd /app/ai-studio
if [ -f .env ] && grep -Eq '^OPENROUTER_API_KEY=.+' .env; then
echo "OPENROUTER_API_KEY is still set in the VM's .env. It was renamed to AI_API_KEY and is no longer read; rename it and set AI_BASE_URL and AI_MODEL too (values in deploy/ai-studio/.env.example), then deploy again."
exit 1
fi
echo "$COMPOSE_B64" | base64 -d > docker-compose.yml
echo "$OVERRIDE_B64" | base64 -d > docker-compose.override.yml
touch .env
{ grep -vE '^(RUNTIME_IMAGE|WEB_IMAGE)=' .env || true; printf 'RUNTIME_IMAGE=%s\nWEB_IMAGE=%s\n' "$IMAGE-runtime" "$IMAGE-web"; } > .env.tmp
chmod --reference=.env .env.tmp && chown --reference=.env .env.tmp && mv .env.tmp .env
(umask 077; echo "$ENV_B64" | base64 -d > .env)
az acr login --name synergycodes
docker compose pull
docker compose up -d --no-build --force-recreate --remove-orphans
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/pr-check-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ name: PR Check (docs)
# Typecheck is deliberately absent: apps/docs tolerates known starlight
# virtual-module type errors.

# PRs into main and release get checks. Add an integration branch here for
# the time it is the base of stacked PRs.
on:
pull_request:
branches:
- main
- release # merging into release is what deploys the docs site
- release # the docs site is deployed by hand from release, so its PRs get the same checks
paths:
- 'apps/docs/**'
- 'packages/ui/**'
Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@ name: PR Check
# determinism tests guard Temporal replay safety and so must not be able to
# regress silently. Plus the deploy compose files, which ship to the demo VM on
# every deploy, and global format consistency. apps/docs has its own path-filtered workflow
# (pr-check-docs.yml); demo and ai-studio are not checked here — they're
# internal and have their own broken-state tolerances.
# (pr-check-docs.yml); demo and ai-studio are not built or type-checked here — they're
# internal and have their own broken-state tolerances — but their CSS goes
# through the style lint below like every other workspace's.

# PRs into main and release get checks. Add an integration branch here for
# the time it is the base of stacked PRs.
on:
pull_request:
branches:
- main
- release # the release PR is the last stop before a tag, so it gets the same checks
# Integration branch for the human-in-the-loop work: feature PRs land there first.
- feat/human-in-the-loop

permissions:
contents: read
Expand Down Expand Up @@ -262,6 +267,9 @@ jobs:
# the check:built-css guard.
run: pnpm build:ui

- name: Style lint (token usage + fallbacks)
run: pnpm lint:styles

execution:
name: Execution pipeline lint + typecheck + test
runs-on: ubuntu-latest
Expand Down
9 changes: 3 additions & 6 deletions .github/workflows/release-temporal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ name: Release Temporal
# after merging the version-bump PR (which ran `pnpm release:version <pkg>`). See
# packages/RELEASE.md (the release flow is shared between all published packages).
#
# One-time npm setup: @workflowbuilder/temporal needs its own GitHub Actions trusted
# publisher registered on npmjs.com pointing at THIS workflow file
# (.github/workflows/release-temporal.yml). npm only offers that on a package that
# already exists, so the first version is published by hand and this workflow then
# only creates the GitHub Release for it: packages/RELEASE.md § "First release
# of a new package".
# @workflowbuilder/temporal 0.1.0 is on npm; from 0.2.0 this workflow publishes via OIDC.
# Its npm Trusted Publisher must point at .github/workflows/release-temporal.yml.
# See packages/RELEASE.md for the shared release procedure.

on:
push:
Expand Down
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ CLAUDE.local.md
# generation (see astro.config.mjs).
apps/docs/src/content/docs/api/

# UI Library props + CSS-variable data, generated from @workflowbuilder/ui by
# apps/docs/scripts/generate-ui-api.mjs (TypeDoc + CSS extraction) on every
# docs build / dev. Source of truth is the library, so keep it out of git.
# UI API Reference, emitted the same way from the types in apps/docs/src/generated/ui-types.ts.
apps/docs/src/content/docs/ui-api/

# Generated from @workflowbuilder/ui by apps/docs/scripts/generate-ui-api.mjs
# on every docs build / dev. Source of truth is the library, so keep it out of git.
apps/docs/src/generated/
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
apps/icons/src/utils/icons.gen.ts
# Astro auto-generated content collections + types (gitignored, regenerated on build/dev)
**/.astro/
# Designer changelog checked in verbatim — reformatting corrupted token paths in emphasis markers
packages/tokens/migration/
# Recorded Temporal Event Histories. Machine-written, and deliberately kept byte-identical
# to what `temporal workflow show --output json` emits so the two stay interchangeable.
packages/temporal/test/replay/histories/
13 changes: 13 additions & 0 deletions .stylelintrc.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// The csstools rule import()s an importFrom path as given, which Windows rejects
// (C:\ reads as a URL scheme); an object source never reaches that code path.
import customProperties from './tools/stylelint/custom-properties.mjs';

/** @type {import('stylelint').Config} */
export default {
plugins: ['stylelint-value-no-unknown-custom-properties', './tools/stylelint/no-system-token-fallbacks.mjs'],
ignoreFiles: ['**/node_modules/**', '**/dist/**', 'apps/docs/**'],
rules: {
'csstools/value-no-unknown-custom-properties': [true, { importFrom: [customProperties] }],
'wb/no-system-token-fallbacks': true,
},
};
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Each workspace has its own context. Read the relevant file before extending a wo
| Workspace | Authoritative docs |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| `packages/sdk` | `packages/sdk/README.md` |
| `packages/ui` | `packages/ui/README.md` (+ `packages/ui/css-layers.md`) |
| `packages/ui` | `packages/ui/README.md` (+ `packages/ui/css-layers.md`, `packages/ui/built-css-pitfalls.md`) |
| `packages/tokens` | `packages/tokens/README.md` |
| `packages/ai-config` | `packages/ai-config/README.md` |
| `packages/execution-core` | `packages/execution-core/README.md` |
Expand Down Expand Up @@ -141,7 +141,7 @@ This repo is public, but ticket IDs (`WB-123`) point to a private ClickUp — fo
- Write the comment self-sufficiently: state the limitation and the direction of the fix in plain words.
- End it with a stable kebab-case slug naming the work: `(follow-up: temporal-payload-codec)`.
- Add a matching `Code marker: <slug>` line to the ClickUp task's description, so picking the task up later starts with `grep -r "follow-up: <slug>"` — grep survives file moves.
- Ticket IDs belong in commit messages and PR descriptions, where `git blame` leads to full context.
- Ticket IDs stay out of branch names, commit messages, PR titles, and PR descriptions too: they are public, and the IDs lead nowhere for external readers. Describe the change in plain words instead.

## Getting Started

Expand Down Expand Up @@ -174,13 +174,13 @@ If you're new to this repo and want to build your own consumer app or POC, follo

### Releasing the `@workflowbuilder/*` packages

Three workspaces publish to npm: `@workflowbuilder/sdk` (on npm), `@workflowbuilder/ui` (the component library, built on Base UI) and `@workflowbuilder/temporal` (the Temporal Plugin). The last two are publishable but not on npm yet. Their first version is published by hand, because npm cannot register a trusted publisher for a package that does not exist; see [`packages/RELEASE.md`](packages/RELEASE.md) § "First release of a new package". Everything else under `apps/` and `packages/` is `private: true`, and Changesets skips it through `privatePackages` in `.changeset/config.json`. There is no `ignore` list on purpose: Changesets refuses the CLI `--ignore` flag while one exists, and `pnpm release:version` depends on that flag. Each package publishes via its own scoped release tag (`@workflowbuilder/sdk@X.Y.Z`, `@workflowbuilder/ui@X.Y.Z`, `@workflowbuilder/temporal@X.Y.Z`) and its own workflow (`release-sdk.yml`, `release-ui.yml`, `release-temporal.yml`), and each is released on its own: `pnpm release:version <pkg>` consumes only that package's changesets, `pnpm release:tag <pkg>` pushes only that package's tag. Never run bare `pnpm changeset version` or `pnpm changeset tag`. See `packages/RELEASE.md`.
Three workspaces publish to npm: `@workflowbuilder/sdk` (on npm), `@workflowbuilder/ui` (the component library, built on Base UI) and `@workflowbuilder/temporal` (the Temporal Plugin, on npm). Only `@workflowbuilder/ui` is publishable but not on npm yet. Its first version is published by hand, because npm cannot register a trusted publisher for a package that does not exist; see [`packages/RELEASE.md`](packages/RELEASE.md) § "First release of a new package". Everything else under `apps/` and `packages/` is `private: true`, and Changesets skips it through `privatePackages` in `.changeset/config.json`. There is no `ignore` list on purpose: Changesets refuses the CLI `--ignore` flag while one exists, and `pnpm release:version` depends on that flag. Each package publishes via its own scoped release tag (`@workflowbuilder/sdk@X.Y.Z`, `@workflowbuilder/ui@X.Y.Z`, `@workflowbuilder/temporal@X.Y.Z`) and its own workflow (`release-sdk.yml`, `release-ui.yml`, `release-temporal.yml`), and each is released on its own: `pnpm release:version <pkg>` consumes only that package's changesets, `pnpm release:tag <pkg>` pushes only that package's tag. Never run bare `pnpm changeset version` or `pnpm changeset tag`. See `packages/RELEASE.md`.

**`@workflowbuilder/temporal` declares every `@temporalio/*` package its `dist` imports as a peer and lists none of those in its own `devDependencies`.** pnpm installs a missing peer as an ordinary dependency of the package, and that survives the `--prod` install in `deploy/ai-studio/Dockerfile`. A peer that is also a devDependency counts as satisfied, `--prod` then removes it, and the production image fails at import time while every local install works and pnpm prints no warning. The packages the tests alone use (`@temporalio/common`, `@temporalio/testing`, `@temporalio/worker`) belong in its devDependencies. `@temporalio/worker` is also an optional peer, because a consumer that runs a Worker supplies it, but nothing in `dist` imports it, so `--prod` dropping it costs nothing.

**Changesets for bundled execution packages.** `@workflow-builder/execution-core` and `@workflow-builder/types` are private and source-only, and `@workflowbuilder/temporal` bundles both into its `dist` (they reach it through `packages/temporal/src/core-contract.ts`, the one file allowed to import them by relative path). A change in either that alters execution behaviour or the published types therefore needs a changeset for `@workflowbuilder/temporal` - that release is how it reaches consumers. A pure refactor needs none. `pr-check.yml` warns when those paths change without one.

**Changesets for `@workflowbuilder/temporal` follow the SDK rules.** One changeset (`.changeset/temporal-plugin-package.md`) is queued to seed the first release notes; the release PR that consumes it rewrites the generated section to describe the package as it ships. `pr-check.yml` warns when `packages/execution-core` or `packages/types` change without a changeset for it.
**Changesets for `@workflowbuilder/temporal` follow the SDK rules.** `pr-check.yml` warns when `packages/execution-core` or `packages/types` change without a changeset for it.

**Commit format is enforced.** Every commit goes through `commitlint` via the `commit-msg` husky hook — Conventional Commits format only (`<type>(<scope>): <subject>`, types from `feat / fix / perf / refactor / docs / test / chore / build / ci / style / revert`). Bad messages are rejected before they land in git history.

Expand Down
Loading
Loading