Orchestrator
A Bijection orchestrator component for Bijection.
git clone https://github.com/bijectionhq/orchestrator.git
cd orchestrator
git checkout fc8a0457434cf9f2b810fb6956648f97a70aac55Bijection repository access is required. Request access.
Description
A Bijection orchestrator component for Bijection.
Explore the package README for API concepts, configuration, and examples. Check the Bijection source for adaptation-specific setup.
Review the source and its dependencies before adopting this package. Source availability does not establish npm publication or runtime qualification.
Getting started
- Get the source at the revision above and read its package documentation.
- Check the required Bijection SDK version, dependencies, and external service credentials.
- Follow the package setup instructions and the guide to using components.
- Exercise the component in your deployment according to your project’s verification rules.
Open source
Maintained source: bijectionhq/orchestrator. Based on AkshatGiri/convex-orchestrator. License: Apache-2.0. Consult the repository for license terms, notices, and contributor attribution.
From the upstream publisher
A convex orchestrator component for Convex.
Upstream overview
From the upstream package documentation.
A durable workflow orchestration system built on Convex that executes step functions on your local machines while storing workflow state durably. Workers pull workflow tasks from Convex, execute activities locally, and record results with automatic leasing and heartbeat mechanisms. Provides workflow primitives like durable sleep, signals, and step execution with replay safety.
Use cases
From the upstream package documentation.
- Multi-step user onboarding flows that need to survive server restarts, like sending welcome emails, waiting for verification, then provisioning access
- Long-running approval workflows where you need to pause execution until human approval signals are received
- Data processing pipelines with multiple dependent steps that require durability and the ability to resume from failure points
- Scheduled reminder systems that send emails or notifications after specific time delays, with replay-safe sleep mechanisms
- Complex business processes that involve external API calls, waiting periods, and conditional logic that must be resilient to worker crashes
How it works
From the upstream package documentation.
The component stores workflow state in Convex (workflows and steps tables) while actual step execution happens on worker machines that pull tasks from Convex. You define workflows using the workflow() function and ctx.step() for durable operations, then run workers locally using createWorker() with your workflow definitions.
Workers use a leasing system with heartbeats to claim workflows and prevent duplicate execution. If a worker dies, another can reclaim the workflow and resume from the last completed step. The ctx.step() calls are replay-safe - successful results are stored durably and returned on subsequent replays.
Durable primitives include ctx.sleep() for time-based delays and ctx.waitForSignal() for external events, both using stable markers to ensure replay safety. You expose the component's API through your Convex app using exposeApi() and exposeApiWithWorker(), with the latter requiring authorization for production use.
Upstream package FAQ
How does convex-orchestrator handle worker failures?
convex-orchestrator tracks task execution state in Convex and implements automatic retry logic. If a worker fails to complete a task within the configured timeout, the orchestrator marks the task as available for retry and another worker can pick it up. This ensures fault tolerance without losing workflow progress.
What's the difference between this and regular Convex functions?
Regular Convex functions have execution time limits and run on Convex servers. convex-orchestrator enables long-running workflows where the coordination happens in Convex but actual work executes on your own machines. This allows for computationally intensive or time-consuming operations that wouldn't fit within Convex function constraints.
Can I scale workers independently with convex-orchestrator?
Yes, convex-orchestrator decouples workflow coordination from execution. You can run multiple worker processes on different machines that all poll the same Convex database for tasks. This allows you to scale processing capacity up or down based on workload without affecting the workflow orchestration logic.
How does convex-orchestrator compare to Temporal?
convex-orchestrator is inspired by Temporal's worker model but uses Convex as the coordination layer instead of requiring a separate Temporal server. It provides similar durable execution guarantees but with simpler deployment since you only need Convex and your worker processes, not additional infrastructure.
Use with agents and CLI
Give your coding agent the component’s source identity and setup guidance.
Help me integrate Orchestrator with Bijection.
Read: https://bijection.com/components/orchestrator/SKILL.md
Check SDK compatibility and dependency availability.
Follow this project's execution and verification rules.Upstream README.md
View repository ↗Documentation from AkshatGiri/convex-orchestrator, recorded October 23, 2026. APIs and setup may differ in the Bijection adaptation.
@akshatgiri/convex-orchestrator
Durable workflow orchestration on Convex where step execution happens on your machines (workers pull work from Convex), inspired by Temporal’s worker model.
This project is early-stage. The API may change.
What you get
- Durable workflow runs stored in Convex (
workflows+stepstables) - A worker SDK (
createWorker,workflow,ctx.step) that executes activities locally and records step results durably - Leasing + heartbeats so workflows can be reclaimed if a worker dies
- Simple dashboard primitives: list workflows, view workflow + steps
Install
npm i @akshatgiri/convex-orchestrator
Add the component to your Convex app
// convex/convex.config.ts
import { defineApp } from "convex/server";
import convexOrchestrator from "@akshatgiri/convex-orchestrator/convex.config.js";
const app = defineApp();
app.use(convexOrchestrator);
export default app;
Expose API from your app
Create a module in your Convex app (for example convex/orchestrator.ts) and export:
// convex/orchestrator.ts
import { components } from "./_generated/api.js";
import { exposeApi, exposeApiWithWorker } from "@akshatgiri/convex-orchestrator";
// Safe to expose to clients (dashboard + starters)
export const {
startWorkflow,
getWorkflow,
listWorkflows,
getWorkflowSteps,
signalWorkflow,
} = exposeApi(components.convexOrchestrator);
// Worker operations (DO NOT expose without auth in production)
export const {
claimWorkflow,
heartbeat,
completeWorkflow,
failWorkflow,
getOrCreateStep,
scheduleSleep,
waitForSignal,
completeStep,
failStep,
subscribePendingWorkflows,
} = exposeApiWithWorker(components.convexOrchestrator, {
authorize: async (ctx) => {
// TODO: implement real auth (service token / identity / secret)
// Returning true is fine for local dev, unsafe for production.
void ctx;
return true;
},
});
Define workflows
import { workflow } from "@akshatgiri/convex-orchestrator";
const greet = workflow("greet", async (ctx, input: { name: string }) => {
const greeting = await ctx.step("greeting", async () => `Hello, ${input.name}!`);
return { greeting };
});
Run a worker (on your machine)
import { ConvexClient } from "convex/browser";
import { createWorker } from "@akshatgiri/convex-orchestrator";
import { api } from "./convex/_generated/api.js";
const client = new ConvexClient(process.env.CONVEX_URL!);
const worker = createWorker(client, api.orchestrator, {
workflows: [greet],
maxConcurrentWorkflows: 4,
});
await worker.start();
Start a workflow
From any Convex client:
await client.mutation(api.orchestrator.startWorkflow, {
name: "greet",
input: { name: "World" },
});
Execution model (important)
ctx.step("name", fn)is durable: the first successful result is stored and returned on replay.ctx.sleep("marker", durationMs)/ctx.sleepUntil("marker", timestamp)are durable and replay-safe (the marker is persisted).ctx.sleep*is not allowed insidectx.stepcallbacks.await ctx.waitForSignal("marker", "signalName")parks the workflow untilsignalWorkflow(...)is called and is replay-safe.- Steps are at-least-once from the perspective of your side effects. Make your step code idempotent.
- Workers hold a lease and heartbeat while executing. If the lease expires, another worker may reclaim the workflow; the original worker should stop writing results.
Durable sleep / timers
Workflows replay from the top on resume, so sleep must have a durable marker to avoid re-sleeping forever.
const reminder = workflow("reminder", async (ctx, input: { email: string }) => {
await ctx.step("send-welcome", () => activities.sendEmail(input.email, "Welcome!"));
// Replay-safe: uses the marker to persist sleepUntil durably.
await ctx.sleep("followup-delay", 24 * 60 * 60 * 1000);
await ctx.step("send-followup", () => activities.sendEmail(input.email, "How's it going?"));
});
The marker must be stable/deterministic across replays (e.g. a literal string for that sleep site).
Signals
const approval = workflow("approval", async (ctx) => {
await ctx.step("request-approval", () => activities.sendApprovalEmail());
const decision = await ctx.waitForSignal<{ approved: boolean }>(
"approval-decision",
"approved",
);
if (decision.approved) {
await ctx.step("provision", () => activities.provisionAccess());
}
});
Send the signal from your app (auth it appropriately):
await client.mutation(api.orchestrator.signalWorkflow, {
workflowId,
signal: "approved",
payload: { approved: true },
});
Demo (this repo)
npm i
npm run dev
In another terminal:
bun example/worker.ts
bun example/trigger.ts greet
Limitations / TODOs
- No cancellations/terminations yet (cancel a workflow run, cancel a sleep, cancel waitForSignal, etc.)
- No retries/backoff yet (step-level retry policy, transient vs permanent failures, jitter)
- No workflow versioning yet (pin long-lived runs to a workflow build/version; safe schema evolution for step outputs)
- Signals need more semantics (timeouts, buffering/multiple signals, retention/GC for the signal inbox)
- No built-in worker authentication/authorization (you must enforce this in your app)
- Observability is minimal (no structured logs/metrics/tracing yet)
- Production hardening still needed (rate limiting/backpressure for high worker concurrency, idempotency patterns for side effects)
Contributing
Issues/PRs welcome: https://github.com/akshatgiri/convex-orchestrator/issues