Skip to content

davccavalcante/alkaline

Alkaline

status: stable license version node tests coverage runtime deps

Alkaline

Star History Chart

Embeddable durable execution for Massive Intelligence (IM) agents and non-human entities (NHEs). The durable workflow kernel you import instead of operate.

Alkaline is a zero-runtime-dependency, TypeScript-first engine that gives a long-running agent durable state, deterministic replay, opt-in retries, native loop prevention, an enforced token budget, and a multi-agent task board, with no sidecar service to run.

The mental model is the SQLite of durable workflows. You embed it, it runs in your process, it persists to a swappable battery cell (in memory, in a node:sqlite file, or in your own Postgres or Redis), and it survives a crash and resumes exactly where it left off. No cluster, no hyperscaler, no lock-in.

It is purpose-built for agents. Where general durable-execution libraries stop at persist and retry, Alkaline adds the guardrails an autonomous entity needs: graph cycle detection so a workflow cannot loop forever, a token budget so a runaway agent halts instead of draining a balance, and a Hermes-Agent-style durable task board so many entities coordinate without a fragile in-process swarm.

Core promise: zero required runtime dependencies, single-function setup, ergonomic TypeScript types, ESM and CJS dual distribution, SLSA provenance on every release.


Why durable execution, and why embeddable

Long-running agents break in production. A worker crash loses state. A deploy restarts a six-hour research run from zero. A miswired loop hits maxTurns fifty times and the token bill climbs. Durable execution crossed into the early majority in 2025 precisely because agents demand it, and the category now treats automatic state persistence, replay, and retries as fundamental.

Every major option, Temporal, Inngest, Cloudflare Workflows, AWS Durable Functions, Vercel Workflow DevKit, is excellent and every one asks you to run or adopt a platform. Alkaline takes the opposite trade: maximum simplicity, single-writer scale. You pnpm add it and your agent gains persistence, replay, retry, cycle detection, depth limits, and a token budget, as a library, not a service.

Install

pnpm add @takk/alkaline
# or: npm install @takk/alkaline
# or: yarn add @takk/alkaline
# or: bun add @takk/alkaline

Node 20 or newer. Zero runtime dependencies. Ships dual ESM and CommonJS with full type declarations, and runs in Node, edge runtimes, and the browser; the core never imports a Node built-in.

Quickstart

import { createRuntime, defineWorkflow } from '@takk/alkaline';

const research = defineWorkflow({
  name: 'research',
  async handler(ctx, input: { topic: string }) {
    // Steps are memoized: on replay the recorded result is returned, never re-run.
    const sources = await ctx.step('search', () => searchTheWeb(input.topic));
    // Retry is opt-in and per step: at-least-once execution, exactly-once effect.
    const summary = await ctx.step(
      'summarize',
      () => callTheModel(sources),
      { retry: { maxAttempts: 3, backoffMs: 500 } },
    );
    return summary;
  },
});

const runtime = createRuntime();
const run = await runtime.start('research', { topic: 'durable execution' });
const summary = await run.result();

If the process is killed between any two steps, the next runtime.start or runtime.resume with the same execution id replays the recorded history and continues from the last completed step. searchTheWeb is never called twice.

The battery: swappable, rechargeable state cells

The state store is the battery. Swap it or recharge it at runtime; the engine does not care which cell it is running on.

import { createRuntime } from '@takk/alkaline';
import { createSqliteStore } from '@takk/alkaline/sqlite';

// Start ephemeral, in memory.
const runtime = createRuntime();
// ... run some workflows ...

// Recharge into a durable file cell, then hot-swap to it.
const durable = createSqliteStore({ path: './agent.alkaline' });
await runtime.swapStore(durable); // migrates the contents by default

Four cells ship, all zero-dependency.

Cell Import Notes
Memory core createMemoryStore Universal, ephemeral, the zero-config default.
SQLite @takk/alkaline/sqlite Backed by the built-in node:sqlite (Node 22.5+), a single file, no driver to install.
Postgres @takk/alkaline/postgres You inject your own client; Alkaline bundles no driver.
Redis @takk/alkaline/redis You inject your own client; Alkaline bundles no driver.
import { createPostgresStore } from '@takk/alkaline/postgres';
import { Pool } from 'pg';

const store = createPostgresStore({ client: new Pool({ connectionString: process.env.DATABASE_URL }) });
const runtime = createRuntime({ store });

Alkaline follows the SQLite mental model: one writer per execution. For a single embedded agent or a single self-hosted server this is exactly right. Distributed multi-writer leasing is on the roadmap, not pretended to exist today.

Loop prevention, the agent-native guardrails

An autonomous entity that loops forever is the failure mode this kernel exists to prevent. Two guardrails are built in.

Cycle detection. Child workflows carry depth headers. A workflow that calls itself, or forms a cycle through its ancestry, fails fast with ERR_CYCLE_DETECTED, and a chain deeper than the configured limit fails with ERR_DEPTH_EXCEEDED.

const planner = defineWorkflow({
  name: 'planner',
  async handler(ctx, goal: string): Promise<string> {
    return await ctx.child('planner', goal); // ERR_CYCLE_DETECTED: planner is already in the path
  },
});

Token budget. Declare a budget and charge against it; the workflow halts the moment a charge would pass it.

const agent = defineWorkflow({
  name: 'agent',
  async handler(ctx) {
    ctx.spend(800, 'prompt');
    ctx.spend(400, 'completion'); // throws ERR_BUDGET_EXCEEDED if this passes the budget
    return 'done';
  },
});

await runtime.start('agent', null, { budget: 1000 });

Signals, queries, pause, resume

Drive a live execution from the outside, the way Temporal does.

const approval = defineWorkflow({
  name: 'approval',
  queries: { status: (state) => state ?? 'pending' },
  async handler(ctx) {
    ctx.setState('awaiting');
    const decision = await ctx.waitForSignal<string>('decision'); // suspends durably
    ctx.setState(decision);
    return decision;
  },
});

const run = await runtime.start('approval', null); // status: suspended
await runtime.query(run.id, 'status'); // 'awaiting'
await runtime.signal(run.id, 'decision', 'approved'); // resumes, completes

runtime.pause, runtime.resume, and runtime.cancel round out the lifecycle.

continueAsNew, for runs that never end

Long-horizon agents accumulate unbounded history, the exact pain that saturates a workflow log. ctx.continueAsNew ends the current run and restarts the same execution id with fresh input and an empty history, carrying a compact summary forward.

const monitor = defineWorkflow({
  name: 'monitor',
  async handler(ctx, cursor: number): Promise<never> {
    const next = await ctx.step('poll', () => pollAndProcess(cursor));
    await ctx.sleep('interval', 60_000);
    return ctx.continueAsNew(next); // history resets; the agent runs forever, bounded
  },
});

Durable MCP tool calls

A Model Context Protocol tool call is exactly the kind of expensive, non-deterministic effect durable execution tames. Wrap it once and a crash never double-invokes it.

import { durableTool } from '@takk/alkaline/mcp';

const flow = defineWorkflow({
  name: 'tool-use',
  async handler(ctx) {
    const call = durableTool(ctx, (request) => mcpClient.call(request.name, request.args));
    return await call({ name: 'search', args: { q: 'alkaline' } }, { costTokens: 200 });
  },
});

This pairs naturally with @takk/mcpcustoms, which vets a tool call before it runs; Alkaline makes the call that survives durable.

The task board

The board is the NPM-standalone equivalent of the Hermes Agent Kanban: a durable, multi-agent queue with explicit states, heartbeats, and zombie reclaim.

import { createBoard } from '@takk/alkaline/board';
import { createSqliteStore } from '@takk/alkaline/sqlite';

const store = createSqliteStore({ path: './board.alkaline' });
const board = createBoard({ store, leaseMs: 30_000 });

const task = await board.createTask({ title: 'collect telemetry' });
await board.claim(task.id, 'agent-1'); // todo -> in_progress, with a lease
await board.heartbeat(task.id);        // extend the lease while working
// ... if agent-1 crashes and the lease expires ...
await board.reclaimZombies();          // the task returns to todo for another worker

Tasks carry states (todo, in_progress, blocked, done, failed), a cycle-checked dependency link graph, comments, and an append-only event log.

Edge

Edge runtimes do not run Temporal; they run Alkaline. Import @takk/alkaline/edge for the full kernel minus the SQLite cell, with no node: import anywhere, and inject a Redis or Postgres HTTP client for durable storage.

Replay and inspection

Because every execution is event-sourced, you can read its full durable trace back, render it, and pinpoint where two histories diverge, the fastest way to debug a determinism breach.

import { inspectExecution, formatTrace } from '@takk/alkaline/replay';

const trace = await inspectExecution(runtime.store, run.id);
if (trace) console.log(formatTrace(trace));

CLI

npx @takk/alkaline list --db ./agent.alkaline
npx @takk/alkaline show exe_... --db ./agent.alkaline

When to use Alkaline, and when not to

Honest comparison. Pick the tool that fits.

You want Reach for
Durable execution embedded in your agent, no service to run, agent-native guardrails (cycle detection, token budget, multi-agent board), edge-ready, zero-dependency Alkaline
General-purpose durable execution as a Postgres-backed library, broad language support, hot code upgrades DBOS Transact
Battle-tested distributed durable execution at large multi-writer scale, with a cluster or Temporal Cloud Temporal
Serverless durable functions tied to a platform, with a hosted dashboard Inngest, Vercel Workflow DevKit, Cloudflare Workflows

Alkaline is deliberately the simplest of these. It trades distributed multi-writer scale for single-process embeddability and an agent-first feature set.

Honest guarantees

Alkaline gives deterministic replay with divergence detection, not a sandbox: it records every effect routed through the context and detects, on replay, when the workflow code diverges from history. Keep all non-determinism inside ctx.step, ctx.now, ctx.random, and ctx.uuid, and replay is faithful. A step with a retry policy executes its effect at least once; the memoized result makes the successful outcome exactly-once. This is defense for long-running entities, engineered honestly, not a promise that physics cannot keep.

Quality

  • Zero runtime dependencies, 69 tests across 13 suites, green on Node 20, 22, and 24.
  • TypeScript strict mode at maximum, Biome lint and format, publint and are-the-types-wrong clean across all entry points.
  • Dual ESM and CommonJS, bundle sizes well under budget, the core and edge bundles verified free of any Node built-in.
  • The Postgres and Redis cells are tested against faithful in-memory client fakes; a real-server integration matrix is on the roadmap.

Positioning

Alkaline is part of a 2026-2030 infrastructure aligned with the author's research on MAIC (Massive Artificial Intelligence Consciousness, the universe and the framework), HIM (Hybrid Entity Intelligence Model, the spirit and the model), and NHE (Noumenal Higher-order Entity, the reincarnated body and the agent). The market moved from prompt to agent; the next turn is the non-human entity (MAIC, HIMs, NHEs) as a category. Alkaline is the durable body that keeps such an entity alive across crashes, deploys, and days, automation beyond OpenClaw, beyond Hermes Agent, beyond Claude Code.

Author

David C Cavalcante, Product Engineer, AI Engineer, ML Engineer, LLM Engineer, LLM Architecture, and Artificial Intelligence Researcher at Takk Innovate Studio.

License

Apache-2.0. See LICENSE and NOTICE.

Sponsor this project

Packages

 
 
 

Contributors