Case Study

DavBlu Tasks

An invitation-only issue tracker with typed Issues, Parents and Blockers, where AI agents take the next Ready Issue with one CLI command.

Period
– present
Role
Founder & sole engineer
  • Same day

    First commit to production

  • 2 days

    Full feature set shipped in

  • 24, against a real PostgreSQL

    Automated tests

  • 7 ADRs

    Architecture decisions recorded

Issue list of a demo Project, showing each Issue's type, Labels and Blocked status, with filters for Ready and Blocked.

DavBlu Tasks: an issue tracker for AI agents, live in production on the day of its first commit

Problem

I run my work with several AI coding agents, and each one needs to know what to do next. GitLab Issues gave them no Issue types, no Parent and Child links and no Blockers, so I sequenced the work by hand.

Reading issues through GitLab's API and web pages also spent a large share of each agent's context. An agent needed one cheap command that answers: which open Issue is blocked by nothing?

What was built

I built DavBlu Tasks alone, from a glossary and 7 ADRs to production, with Next.js, Drizzle on PostgreSQL 18 and Better Auth. Nobody can sign up: the deployment creates the Owner from its configuration, and everyone else joins through a single-use Invitation link.

Every Issue has a type (task, bug, spec or epic), Labels, Markdown Comments and a full Activity record. Parent and Blocker links never form a cycle: each link write takes a Postgres advisory lock, then checks the graph in the same transaction. One SQL expression derives Blocked and Ready, so the list and the Issue page always agree.

Agents use dtask, a single-file CLI with no dependencies that the app serves itself, so its version always matches the server. It calls a Hono REST API under /api/v1, with bearer tokens, one error shape and keyset cursors that skip no Issue while other agents write. Its output is one line per Issue, sized for an agent's context.

Browsers and agents reach the app through Traefik on my VPS. The app talks to Postgres on a private network with no published port. GitLab CI checks every push and deploys main with Docker Compose.

Claude Code agents wrote the code from my specs, glossary and ADRs. I made the design decisions, reviewed the changes, and gated every deploy on lint, typecheck and 24 tests against a real Postgres.

Outcome

DavBlu Tasks runs at tasks.davblu.dev. I shipped the first commit and the production deploy on 23 September 2026, and the full feature set the next day.

My agents now take work with dtask ready and close it with a comment. The tracker also holds its own Issues: this product's work moved off GitLab Issues into it.

Every push to main deploys only after lint, typecheck and tests pass, and the deploy succeeds only when the health check answers. Production secrets stay encrypted in the repository with dotenvx. The source is private; the product is live.

Shipping Timeline

From zero to production.

  1. 01 · Architecture

    Glossary and founding ADRs

    Invitation-only access, committed encrypted configuration, Markdown storage, a CLI for agents.

  2. 02 · Deploy

    Live at tasks.davblu.dev

    GitLab CI deploys main with Docker Compose behind Traefik, gated by a health check.

  3. 03 · Build

    Owner sign-in, Invitations, Projects and Issues

    No sign-up on any surface; everyone else arrives by a single-use link.

  4. 04 · Build

    Comments, Activity, Parents and Blockers, Markdown editor

    Cycle-free links under an advisory lock; Ready and Blocked derived on every read.

  5. 05 · Build

    API tokens, REST API v1 and the dtask CLI

    A single-file CLI served by the app itself, with compact output for agents.

  6. 06 · Support

    The tracker takes over its own Issues

    Work on DavBlu Tasks moved from GitLab Issues into DavBlu Tasks.

Engineering

How it is built.

Architecture

Architecture of DavBlu Tasks: browsers and AI agents, Traefik, the Next.js app, PostgreSQL and GitLab CI.

Stack

  • Better Auth
  • Hono
  • Drizzle ORM
  • TypeScript
  • React
  • Next.js
  • Tailwind CSS
  • Node.js
  • PostgreSQL
  • Docker
  • GitLab CI/CD
  • Traefik
  • Encrypted secrets (SOPS, dotenvx)
  • Vitest
  • Agent skills (Claude Code)

Decisions

A CLI over an MCP server
Chose a CLI over an MCP server because it works in every agent harness and shell, and loads no tool schemas into context. Cost: no native tool integration, though an MCP server can wrap the same REST API later.
PostgreSQL over SQLite
Chose PostgreSQL over SQLite because several agents write at once through the API. A named volume is no harder to keep than a database file. Cost: a second container to run and back up.
One advisory lock over serializable retries
Chose one advisory lock for every Parent and Blocker write over serializable transactions with retries, because two concurrent writes can each pass a cycle check. Cost: link writes take turns, a few milliseconds each.
  • Epic page listing its 5 Children, each marked Ready or Blocked, above the Epic's Activity record.
  • Issue page showing its Parent, 2 Blockers, the Issues it blocks, a Comment thread and its Activity.
  • dtask in a terminal: an agent closes 2 Blockers, and the next Issue under the Epic becomes Ready.