I have been working on taskchampion-rb, a Ruby binding for
TaskChampion, the task database engine that powers Taskwarrior. The goal
is straightforward: make TaskChampion’s durable, synchronizable task
storage available to Ruby programs without making Ruby developers leave
the shape and idioms of Ruby behind.
TaskChampion itself is written in Rust. It provides the storage and sync
model behind modern Taskwarrior: local-first task replicas, operations
that can be synchronized between clients, and a data model designed for
task properties such as status, priority, tags, dates, annotations, user
defined attributes, dependencies, and history. taskchampion-rb wraps
that core and exposes it as a native Ruby gem.
With the v0.9.0 release, the gem has grown far enough that it is useful
for real experiments and early applications. This release adds support
for removing and updating task annotations, filling in one more piece of
the task editing workflow.
What it does
At its core, taskchampion-rb lets Ruby code open a TaskChampion replica,
create and modify tasks, commit those changes, query stored tasks, and
sync task data through TaskChampion’s storage model.
The API is intentionally Ruby-shaped. Methods use snake_case, predicate
methods end in ?, status and access-mode values are exposed in a way
that feels natural from Ruby, and missing values come back as nil.
For example:
require "taskchampion"
require "securerandom"
replica = Taskchampion::Replica.new_on_disk("tasks", true, :read_write)
operations = Taskchampion::Operations.new
task = replica.create_task(SecureRandom.uuid, operations)
task.set_description("Try taskchampion-rb", operations)
task.set_status(Taskchampion::Status.pending, operations)
task.set_priority("H", operations)
task.add_tag(Taskchampion::Tag.new("ruby"), operations)
task.add_annotation("Created from Ruby", operations)
replica.commit_operations(operations)
That operations object is important. Task changes are collected as operations and then committed to the replica, matching TaskChampion’s underlying model. This makes the Ruby API a wrapper around the real data engine rather than a parallel reimplementation of task storage.
What it is good for
taskchampion-rb is useful anywhere Ruby needs to work with Taskwarrior-
style task data directly.
It can be used to build command-line tools that read or modify a task database, automation scripts that create tasks from external systems, small web applications for viewing or triaging tasks, background jobs that process task metadata, or integration code that needs the same task storage semantics as Taskwarrior.
Because it uses TaskChampion underneath, the gem is especially interesting for local-first tools. A Ruby application can work against an on-disk replica, make changes offline, and sync those changes later. It can also use in-memory replicas for tests, experiments, and short-lived workflows.
The gem already supports the pieces needed for a broad task workflow:
- In-memory and on-disk replicas
- Task creation and mutation through committed operations
- Pending, completed, deleted, and recurring statuses
- Tags, priorities, dates, and custom values
- User defined attributes
- Annotation creation, updates, and removal
- Undo/history-oriented operation tracking
- Local and remote sync workflows exposed through the Ruby API
- Thread-bound objects that fail clearly when used from the wrong thread
That last point matters for native bindings. The Rust core has its own
ownership and safety constraints, and the Ruby wrapper makes those
constraints explicit. Objects such as replicas, tasks, and operation
collections belong to the thread that created them. If they are used from
another thread, the gem raises a Taskchampion::ThreadError instead of
allowing surprising shared-state behavior.
Why build it
Taskwarrior has a long history as a reliable power-user task tool, and
TaskChampion is the reusable engine that makes its newer storage model
available outside the Taskwarrior binary itself. Ruby has a strong
tradition of small tools, integration scripts, web apps, and developer-
friendly libraries. taskchampion-rb is meant to connect those worlds.
I want Ruby developers to be able to build against TaskChampion without having to shell out to another command, parse command output, or maintain a separate task database format. A Ruby program should be able to open a replica, inspect tasks, apply changes, and sync them using the same core engine that Taskwarrior uses.
Where it stands
This is still an early project, but v0.9.0 is a useful milestone. The
core binding structure is in place, the main task and replica APIs are
available, operations are exposed, sync workflows are represented, and
annotations can now be added, updated, and removed.
There is still work ahead: broader API coverage, more documentation, cross-platform polish, and the kind of hardening that comes from real applications using the gem. But the shape is there now. Ruby can talk to TaskChampion directly, and that opens the door to a much wider set of Taskwarrior-compatible tools.
The project is available on GitHub at https://github.com/timcase/taskchampion-rb.