Skip to content

Durable workflows

CampusSDK workflows let one installed application replay ordinary async code without repeating completed side effects. CampusOS stores the run, bounded input and result values, named activity records, leases, and structural history. Workflow definitions and branching code remain in the application.

JavaScript

Create or recover a run with one stable idempotency key:

js
const result = await campus.runWorkflow({
  definition: 'call-then-fallback',
  version: 1,
  input: {
    contact: '@mary',
    paymentSats: 500,
    voiceNote: "I'm outside",
  },
  idempotencyKey: agentInvocation.id,
  durationSeconds: 3600,
}, async (flow, input) => {
  const call = await flow.activity(
    'call',
    'calls.call',
    { to: input.contact, mode: 'voice' },
    async (callInput, activity) => {
      return calls.call(callInput, {
        idempotencyKey: activity.idempotencyKey,
      })
    },
  )

  if (call.outcome === 'answered') return { outcome: 'answered' }

  if (call.outcome === 'declined' || call.outcome === 'no-answer') {
    const [voiceNote, payment] = await Promise.all([
      flow.activity(
        'voice-note',
        'drop.compose-voice-note',
        { to: input.contact, script: input.voiceNote },
        (noteInput, activity) => drop.composeVoiceNote(noteInput, {
          idempotencyKey: activity.idempotencyKey,
        }),
      ),
      flow.activity(
        'payment',
        'wallet.pay-contact',
        { to: input.contact, amountSats: input.paymentSats, memo: 'Taxi' },
        (paymentInput, activity) => wallet.payContact(paymentInput, {
          idempotencyKey: activity.idempotencyKey,
        }),
      ),
    ])
    return { outcome: 'fallback-completed', voiceNote, payment }
  }

  return { outcome: call.outcome }
})

step is the durable identity inside one run. Reusing a step with another activity name or input is a conflict. A completed step returns its stored result without calling its executor again.

The activity ID passed as idempotencyKey must be forwarded to the domain effect. Activities are at-least-once: a process can fail after an external effect succeeds but before CampusOS records the result. The domain API's idempotency boundary closes that ambiguity.

Activity claims have a 60-second lease. The JavaScript SDK renews a live executor every 20 seconds and fences a stale executor after another process reclaims the step.

Recovery

Call runWorkflow again with the same definition, version, input, and idempotency key when the workload starts again. CampusOS returns the original run. The workflow function runs from the beginning, while every completed flow.activity resolves from history.

The initial release does not wake a stopped workload or serialize arbitrary JavaScript continuations. Automatic wake/resume is a separate Runtime trigger; until it exists, an application resumes workflows from its normal startup, schedule, or already-running event loop.

Stored state

CampusOS stores:

  • definition name and version;
  • originating account, app, and installation;
  • input up to 32 KiB and final result up to 64 KiB;
  • at most 256 named activities per run;
  • activity input, result, attempt, lease, and timestamps;
  • ordered structural history;
  • workflow status, expiry, and cleanup timestamps.

CampusOS does not store application source, JavaScript continuations, Wallet private keys, media, or encryption keys. Applications should pass an app-local record reference instead of plaintext workflow input when the input itself is sensitive.

Runs last at most seven days. Terminal runs and their histories are retained for seven days, and each installation may retain at most 256 runs.

Service routes

The workload SDK uses installation-authenticated service routes:

text
POST   /services/workflows
GET    /services/workflows
GET    /services/workflows/:workflow-id
DELETE /services/workflows/:workflow-id
GET    /services/workflows/:workflow-id/history
POST   /services/workflows/:workflow-id/activities/:step/claim
POST   /services/workflows/:workflow-id/activities/:activity-id/renew
POST   /services/workflows/:workflow-id/activities/:activity-id/complete
POST   /services/workflows/:workflow-id/complete

No workflow identifier, activity identifier, or lease token grants domain authority. Every Calls, Drop, Wallet, MCP, or third-party operation still passes its ordinary permission and user-authorization checks.

Software belongs to people. Campus gives it a durable place to run.