[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-83526":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":17,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":18,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":21,"hasPages":23,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":25,"readmeContent":26,"aiSummary":10,"trendingCount":16,"starSnapshotCount":16,"syncStatus":27,"lastSyncTime":28,"discoverSource":29},83526,"absurd","earendil-works\u002Fabsurd","earendil-works","An experiment in durability","https:\u002F\u002Fearendil-works.github.io\u002Fabsurd",null,"Python",2122,88,15,18,0,34,102,27.85,"Apache License 2.0",false,"main",true,[],"2026-06-12 02:04:34","\u003Cdiv style=\"text-align: center\" align=\"center\">\n  \u003Cimg src=\"logo.jpg\" width=\"350\" alt=\"Une photo d'un éléphant avec le titre : « Ceci n'est pas un éléphant »\">\n  \u003Cbr>\u003Cbr>\n\u003C\u002Fdiv>\n\n# Absurd\n\nAbsurd is the simplest durable execution workflow system you can think of.\nIt's entirely based on Postgres and nothing else.  It's almost as easy to use as\na queue, but it handles scheduling and retries, and it does all of that without\nneeding any other services to run in addition to Postgres.\n\n*… because it's absurd how much you can over-design such a simple thing.*\n\nMore about it can be found [in the announcement post](https:\u002F\u002Flucumr.pocoo.org\u002F2025\u002F11\u002F3\u002Fabsurd-workflows\u002F).\n\nYou can read in the docs [how Absurd compares to PGMQ, Cadence, Temporal,\nInngest, and DBOS](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fcomparison\u002F).\n\n## What is Durable Execution?\n\nDurable execution (or durable workflows) is a way to run long-lived, reliable\nfunctions that can survive crashes, restarts, and network failures without losing\nstate or duplicating work.  Durable execution can be thought of as the combination\nof a queue system and a state store that remembers the most recently seen state.\n\nInstead of running your logic in memory, a durable execution system decomposes\na task into smaller pieces (step functions) and records every step and decision.\nWhen the process stops (fails, intentionally suspends, or a machine dies), the\nengine can replay those events to restore the exact state and continue where it\nleft off, as if nothing happened.\n\nIn practice, that makes it possible to build dependable systems for things like\nLLM-based agents, payments, email scheduling, order processing--really anything\nthat spans minutes, days, or even years.  Rather than bolting on ad-hoc retry\nlogic and database checkpoints, durable workflows give you one consistent model\nfor ensuring progress without double execution.  It's the promise of\n\"exactly-once\" semantics in distributed systems, but expressed as code you can\nread and reason about.\n\n## Installation\n\nAbsurd just needs a single `.sql` file ([`absurd.sql`](sql\u002Fabsurd.sql)) which\nneeds to be applied to a database of your choice.  You can plug it into your\nfavorite migration system of choice.  Additionally if that file changes, we\nalso release [migrations](sql\u002Fmigrations) which should make upgrading easy.\nSee the [quickstart guide](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fquickstart\u002F) for a short tutorial and the\n[documentation index](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002F) for everything else.\n\n## Client SDKs\n\nCurrently SDKs exist for the following languages:\n\n* [TypeScript](sdks\u002Ftypescript) (and JavaScript)\n* [Python](sdks\u002Fpython)\n* [Go](sdks\u002Fgo\u002Fabsurd) *(experimental bootstrap)*\n\n## Push vs Pull\n\nAbsurd is a pull-based system, which means that your code pulls tasks from\nPostgres as it has capacity.  It does not support push at all, which would\nrequire a coordinator to run and call HTTP endpoints or similar.  Push systems\nhave the inherent disadvantage that you need to take greater care of system load\nconstraints.  If you need this, you can write yourself a simple service that\nconsumes messages and makes HTTP requests.\n\n## High-Level Operations\n\nAbsurd's goal is to move the complexity of SDKs into the underlying stored\nfunctions.  The SDKs then try to make the system convenient by abstracting the\nlow-level operations in a way that leverages the ergonomics of the language you\nare working with.\n\nA *task* dispatches onto a given *queue* from where a *worker* picks it up\nto work on.  Tasks are subdivided into *steps*, which are executed in sequence\nby the worker.  Tasks can be suspended or fail, and when that happens, they\nexecute again (a *run*).  The result of a step is stored in the database (a\n*checkpoint*).  To not repeat work, checkpoints are automatically loaded from\nthe state storage in Postgres again.\n\nAdditionally, tasks can *sleep* or *suspend for events*.  Events are cached\n(first emit wins), which means they are race-free.\n\n## Components\n\nAbsurd comes with two basic tools that help you work with it.  One is\ncalled [`absurdctl`](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Ftools\u002Fabsurdctl\u002F) which allows you to initialize and\nmigrate the schema, inspect schema versions, create\u002Fdrop\u002Flist queues, and spawn\nor retry tasks.  The other is [habitat](habitat) which is a Go application that\nserves up a web UI to show you the current state of running and executed tasks.\n\n```bash\nuvx absurdctl init -d database-name\nuvx absurdctl schema-version -d database-name\nuvx absurdctl migrate -d database-name\nuvx absurdctl create-queue -d database-name default\n```\n\nUse [`uvx`](https:\u002F\u002Fdocs.astral.sh\u002Fuv\u002Fguides\u002Ftools\u002F) `absurdctl ...` for\none-off commands, or install it persistently with `uv tool install absurdctl`.\nIf you prefer a standalone file, you can also download `absurdctl` from GitHub\nReleases and put it on your `PATH`:\n\n```bash\ncurl -fsSL \\\n  https:\u002F\u002Fgithub.com\u002Fearendil-works\u002Fabsurd\u002Freleases\u002Flatest\u002Fdownload\u002Fabsurdctl \\\n  -o absurdctl\nchmod +x absurdctl\ninstall -m 755 absurdctl ~\u002F.local\u002Fbin\u002Fabsurdctl\n```\n\nInstall the SDK for your language of choice:\n\n```bash\n# TypeScript \u002F JavaScript\nnpm install absurd-sdk\n\n# Python\nuv add absurd-sdk\n\n# Go\ngo get github.com\u002Fearendil-works\u002Fabsurd\u002Fsdks\u002Fgo\u002Fabsurd@latest\n```\n\n\u003Cdiv style=\"text-align: center\" align=\"center\">\n  \u003Cimg src=\"habitat\u002Fscreenshot.png\" width=\"550\" alt=\"Screenshot of habitat\">\n\u003C\u002Fdiv>\n\n## Example\n\nHere's what that looks like in TypeScript.\n\n```typescript\nimport { Absurd } from 'absurd-sdk';\n\nconst app = new Absurd();\n\n\u002F\u002F A task represents a series of operations.  It can be decomposed into\n\u002F\u002F steps, which act as checkpoints.  Once a step has been passed\n\u002F\u002F successfully, the return value is retained and it won't execute again.\n\u002F\u002F If it fails, the entire task is retried.  Code that runs outside of\n\u002F\u002F steps will potentially be executed multiple times.\napp.registerTask({ name: 'order-fulfillment' }, async (params, ctx) => {\n\n  \u002F\u002F Each step is checkpointed, so if the process crashes, we resume\n  \u002F\u002F from the last completed step\n  const payment = await ctx.step('process-payment', async () => {\n    \u002F\u002F If you need an idempotency key, you can derive one from ctx.taskID.\n    return {\n      paymentId: `pay-${params.orderId}`,\n      amount: params.amount,\n    };\n  });\n\n  const inventory = await ctx.step('reserve-inventory', async () => {\n    return { reservedItems: params.items };\n  });\n\n  \u002F\u002F Wait indefinitely for a warehouse event - the task suspends\n  \u002F\u002F until the event arrives.  Events are cached like step checkpoints\n  \u002F\u002F (first emit wins), which means this is race-free.\n  const shipment = await ctx.awaitEvent(`shipment.packed:${params.orderId}`);\n\n  \u002F\u002F Ready to send a notification!\n  await ctx.step('send-notification', async () => {\n    return {\n      sentTo: params.email,\n      trackingNumber: shipment.trackingNumber,\n    };\n  });\n\n  return {\n    orderId: params.orderId,\n    payment,\n    inventory,\n    trackingNumber: shipment.trackingNumber,\n  };\n});\n\n\u002F\u002F Start a worker that pulls tasks from Postgres\nconst worker = await app.startWorker();\n\n\u002F\u002F Spawn a task - it will be executed durably with automatic retries.  If\n\u002F\u002F triggered from within a task, you can also await it.\nconst { taskID } = await app.spawn('order-fulfillment', {\n  orderId: '42',\n  amount: 9999,\n  items: ['widget-1', 'gadget-2'],\n  email: 'customer@example.com'\n});\n\nawait app.emitEvent('shipment.packed:42', {\n  trackingNumber: 'TRACK123',\n});\n\nconsole.log(await app.awaitTaskResult(taskID, { timeout: 10 }));\n\nawait worker.close();\nawait app.close();\n```\n\n## Documentation\n\nMore detail lives in the docs:\n\n- [Quickstart](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fquickstart\u002F)\n- [TypeScript SDK](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fsdks\u002Ftypescript\u002F)\n- [Python SDK](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fsdks\u002Fpython\u002F)\n- [Go SDK](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fsdks\u002Fgo\u002F) *(experimental)*\n- [Database Setup and Migrations](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fdatabase\u002F)\n- [Concepts](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fconcepts\u002F) — includes retry semantics, worker claims, and idempotency keys\n- [Living with Code Changes](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fpatterns\u002Fliving-with-code-changes\u002F)\n- [Cleanup and Retention](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fcleanup\u002F)\n\n## Working With Agents\n\nAbsurd is built so that agents such as Claude Code or pi can efficiently work\nwith the state in the database.  The easiest setup is to install the bundled\nAbsurd skill into a project or user skills directory:\n\n```\nabsurdctl install-skill              # installs to .agents\u002Fskills\nabsurdctl install-skill .pi\u002Fskills   # if you want a different path\n```\n\nSee [Working With Agents](https:\u002F\u002Fearendil-works.github.io\u002Fabsurd\u002Fagents\u002F) for the recommended setup.\n\n## AI Use Disclaimer\n\nThis codebase has been built with a lot of support of AI.  A combination of hand\nwritten code, Codex and Claude Code was used to create this repository.  To the\nextent to which it can be copyrighted, the Apache 2.0 license should be assumed.\n\n## License and Links\n\n- [Examples](https:\u002F\u002Fgithub.com\u002Fearendil-works\u002Fabsurd\u002Ftree\u002Fmain\u002Fsdks\u002Ftypescript\u002Fexamples)\n- [Issue Tracker](https:\u002F\u002Fgithub.com\u002Fearendil-works\u002Fabsurd\u002Fissues)\n- License: [Apache-2.0](https:\u002F\u002Fgithub.com\u002Fearendil-works\u002Fabsurd\u002Fblob\u002Fmain\u002FLICENSE)\n",2,"2026-06-11 04:11:17","high_star"]