Projects

Side projects and open source. Most of it is Rust.

Runes

2024 – now

Tasks, docs, and decision tracking. Distributed, version-controlled, for humans and agents.

A local-first tracker where every task, doc, and decision is a markdown file with KDL frontmatter. Your editor, your VCS, and the same files an agent can read and write.

Tech
Rust, Git, Jj, Pijul
Role
Creator
rn show output for a closed task, with KDL frontmatter and a markdown body

temporal-fun

2025 – now

Ergonomics for the Temporal date-time API.

A modern date utility library built for the Temporal API. It is the open source layer that powers scheduling in Howie, the AI secretary, where getting dates and times right is table stakes.

Tech
TypeScript, Temporal
Role
Creator, at Howie
temporal-fun//parse
import { date, dateTime, zoned, instant }
  from 'temporal-fun';

date('2025-03-20')          // PlainDate
date('2025-03-20T15:30')    // PlainDate
dateTime('2025-03-20')      // midnight
instant('2025-03-20T15:30Z')

zoned('2025-03-20T15:30[America/New_York]')
zoned('2025-03-20', 'America/New_York')
zoned(new Date(), 'America/New_York')
import { fmtShort, fmtMedium, fmtLong, fmtTz,
  fmtRelativeToNow } from 'temporal-fun';

setLocales('en-US');
const d = zoned('2025-03-24T08:30',
                'America/New_York');

fmtShort(d)          // "3/24/25, 8:30 AM EDT"
fmtMedium(date(d))   // "Mar 24, 2025"
fmtLong(date(d))     // "March 24, 2025"
fmtRelativeToNow(d)  // "2 days ago"
fmtTz(d)             // "EDT"
fmtMedium(date(d), 'en-GB') // "24 Mar 2025"
import { isBefore, isSameWeek, min, round,
  startOfWeek, endOfMonth, eachDayOfInterval }
  from 'temporal-fun';

isBefore(a, b)            // boolean
isSameWeek(a, b, 1)       // weeks start Monday
min([a, b, c])            // earliest

startOfWeek(today(), 1)   // this Monday
endOfMonth(today())       // PlainDate
round(dt, 'hour')         // nearest hour

eachDayOfInterval({ start, end }) // days

Breq // Toren

2026 – now

Workspace management for agentic development.

Toren orchestrates git worktrees and jj workspaces for agentic workflows. Per-workspace setup, teardown, & services. Per-workspace task and implementation tracking. Provides the building blocks for building custom agentic workflows including terminal multiplexing to the browser.

Tech
Rust, Git, Jj, Terminal Multiplexers, Axum
Role
Creator

Subbier

2026 – now

Manage multiple agent subscriptions.

Monitor Claude and Codex subscription usage across several accounts. Also proxies and load-balances API traffic through subscriptions.

Tech
Rust
Role
Creator
Subbier menubar dropdown showing Codex and Claude subscription usage Subbier terminal TUI showing subscription usage and proxy traffic

Dangles

2026 – now

Tracking hockey development progress.

A mobile-first tracker for hockey stickhandling skill development — my kids and I play hockey.

Tech
Rust, Axum, SvelteKit, Postgres, AWS
Role
Creator
lockindangles.com landing page: Track Your Path to 10,000 Touches

Inara

2026 – now

Postgres schema explorer TUI

A companion for Postgres. Explicitly not a full-blown client.

Tech
Rust, SQLx, Postgres
Role
Creator
Inara schema view of a Postgres table with a HUD showing row count, size, indexes, and unindexed foreign keys Inara column HUD showing an enum type, fill rate, values, and ordering Inara goto menu: jump to incoming refs, FK target, parent table, indexes, type definition, or migrations

Are We Learning Yet?

2016 – now

Cataloging the state of Rust ML and AI.

Rust is a systems language, but is it a machine learning language? A community-maintained catalog of the Rust ML and AI ecosystem, inspired by Are We Web Yet.

Tech
Rust, Cobalt
Role
Creator, co-maintainer
arewelearningyet.com: a curated guide to AI and machine learning in Rust

Maglev

2024 – now

Axum-based web framework focused on building JSON APIs.

A batteries-included library on Axum and SQLx. JWT auth, error handling, config, encryption utilities, graceful shutdown, background workers. Just a library. It extends Axum rather than replacing it.

Tech
Rust, Axum, SQLx
Role
Creator
Status
Undermaintained
Maglev//errors
use maglev::HttpError;

#[derive(Debug, thiserror::Error, HttpError)]
pub enum Error {
    #[error("post {0} not found")]
    #[http_error(NOT_FOUND, "post not found")]
    NotFound(Uuid),

    #[error("auth: {0}")]
    #[http_error(UNAUTHORIZED, "unauthorized")]
    Auth(#[from] maglev::auth::AuthError),

    #[error("db: {0}")]
    #[http_error(INTERNAL_SERVER_ERROR)]
    Sqlx(#[from] sqlx::Error),
}
use maglev::auth::{AuthError, Jwt};
use maglev::auth::ClaimsExtractor;

pub struct Author { pub id: Uuid }

impl<S: Send + Sync> ClaimsExtractor<S>
    for Author {
    type Claims = Claims;
    type Rejection = AuthError;

    async fn try_extract(c: Claims, _: &S)
        -> Result<Self, AuthError> {
        Ok(Author { id: c.sub })
    }
}

// Any handler can now ask for the author:
async fn me(me: Jwt<Author>) -> Json<Author>
async fn create_post(
    author: Jwt<Author>,
    State(db): State<PgPool>,
    Json(new): Json<NewPost>,
) -> Result<Json<Post>, Error> {
    let post = sqlx::query_as!(
        Post,
        "INSERT INTO posts
           (author_id, title, body)
         VALUES ($1, $2, $3)
         RETURNING *",
        author.id, new.title, new.body
    )
    .fetch_one(&db)
    .await?;

    Ok(Json(post))
}
let jwt = JwtConfig::new(&config.hmac_key)
    .duration(Duration::minutes(30))
    .build();

let registry = JobRegistry::new()
    .register::<PublishScheduledPosts>();
Worker::new(queue, registry, ctx.clone())
    .concurrency(2)
    .start();

let app = Router::new()
    .route("/posts", post(create_post))
    .with_state(ctx);

maglev::serve(([0, 0, 0, 0], 8080), app)
    .await?;