Saga-Pattern Transactions (TypeScript)
SkillAI & modelsAdding saga-pattern transactions with compensation to a TypeScript Golem agent. Use when the user asks about transactions, sagas, compensation, rollback, or multi-step operations that need undo logic.
Available today. Use it from your connected AI after setup.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the Saga-Pattern Transactions (TypeScript) skill
What this skill tells your AI
The instructions your AI receives, as published by golemcloud/golem in golem-skills/skills/ts/golem-add-transactions-ts/SKILL.md and read by ahel’s review.
Overview
Golem supports the saga pattern for multi-step operations where each step has a compensation (undo) action. If a step fails, previously completed steps are automatically compensated in reverse order. The building blocks are compensable (a step) and the fallibleSaga / infallibleSaga runners, all imported from @golemcloud/golem-ts-sdk.
Defining Compensable Steps
A step is a Compensable with an async execute and an async compensate. Both return the SDK Result<T, E> type. compensable<In, Out, Err>(execute, compensate) builds one:
import { compensable, Result } from '@golemcloud/golem-ts-sdk';
const reserveInventory = compensable<string, string, string>(
async (sku) => {
// Execute: reserve the item, returning a reservation id (or a typed error).
const reservationId = await callInventoryApi(sku);
return Result.ok(reservationId);
},
async (sku, reservationId) => {
// Compensate: cancel the reservation. Compensations should not throw.
await cancelReservation(reservationId);
return Result.ok(undefined);
},
);
const chargePayment = compensable<number, string, string>(
async (amount) => {
const chargeId = await callPaymentApi(amount);
return Result.ok(chargeId);
},
async (amount, chargeId) => {
await refundPayment(chargeId);
return Result.ok(undefined);
},
);
Fallible Sagas
fallibleSaga runs steps and, if any step returns Result.err, compensates the already-completed steps in reverse order and reports the failure. saga.execute(step, input) returns the step's Result; return a Result from the saga body. The overall result is a SagaResult<Out, Err> (a Result whose error describes whether rollback completed fully or partially):
import { fallibleSaga, Result } from '@golemcloud/golem-ts-sdk';
const outcome = await fallibleSaga<{ reservation: string; charge: string }, string>(async (saga) => {
const reservation = await saga.execute(reserveInventory, 'SKU-123');
if (reservation.isErr()) return reservation;
const charge = await saga.execute(chargePayment, 49.99);
if (charge.isErr()) return charge;
return Result.ok({ reservation: reservation.val, charge: charge.val });
});
// outcome.isOk() → the saga committed
// outcome.isErr() → outcome.val is a SagaFailure describing the error + rollback status
Infallible Sagas
infallibleSaga runs a sequence whose steps are expected to succeed. If a step returns Result.err, the already-run steps' compensations run in reverse order and the entire saga is retried. Here saga.execute(step, input) returns the step's success value directly (an err triggers rollback + retry rather than being returned):
import { infallibleSaga } from '@golemcloud/golem-ts-sdk';
const result = await infallibleSaga(async (saga) => {
const reservation = await saga.execute(reserveInventory, 'SKU-123');
const charge = await saga.execute(chargePayment, 49.99);
return { reservation, charge };
});
// Resolves once the whole sequence succeeds.
Using a Saga Inside an Agent Method
import { z } from 'zod';
import { defineAgent, method, compensable, fallibleSaga, Result } from '@golemcloud/golem-ts-sdk';
export const OrderAgent = defineAgent({
name: 'OrderAgent',
id: { name: z.string() },
methods: {
placeOrder: method({ input: { sku: z.string(), amount: z.number() }, returns: z.boolean() }),
},
});
OrderAgent.implement({
init: () => ({}),
methods: {
async placeOrder({ sku, amount }) {
const outcome = await fallibleSaga<string, string>(async (saga) => {
const reservation = await saga.execute(reserveInventory, sku);
if (reservation.isErr()) return reservation;
return await saga.execute(chargePayment, amount);
});
return outcome.isOk();
},
},
});
Guidelines
- Keep compensation logic idempotent — it may be called more than once
- Compensation runs in reverse order of execution
- Steps signal expected failures with
Result.err; athrowinside a saga is an unexpected defect and traps (the saga is retried) - Use
fallibleSagawhen failure is an acceptable outcome the caller should observe - Use
infallibleSagawhen the operation must eventually succeed (failures roll back and retry)
Signals
- GitHub stars
- 2k
- Forks
- 210
- Last commit
- Sep 2026
Advanced
- Item type
- skill
- Key
golem-add-transactions-ts- Source
- github.com/golemcloud/golem