We shipped a lot in 2024. This post collects the headlines: the features that landed, the rough edges we sanded down, and the work we are most excited about heading into 2025.
What’s new
Voice capture got faster and quieter. Most of our work this year went into the ingestion path — getting from a button press to a confidently-typed transcript in under a second, on devices that other tools wheeze on.
- Streaming dictation with sub-300 ms first-token latency on Apple Silicon.
- Offline transcription for sensitive workflows. No data leaves the device.
- Workspace routing that picks the right destination based on the active app.
Speak naturally. Keldr captures your intent, refines it into finished work, and routes the result across every tool you use.
A quick code sample
Below is a sketch of how the new BlogWithSlug route is wired up. Keldr does
not actually use this on the dashboard side, but it is a good example of the
patterns we now follow on the website:
"use client";
import { useRouter } from "next/navigation";
import { BlogWithSlug } from "@/lib/blog";
export default function BlogLayout({
blog,
children,
}: {
blog: BlogWithSlug;
children: React.ReactNode;
}) {
const router = useRouter();
return (
<div className="mt-16 lg:mt-32">
<div className="xl:relative">
<div className="mx-auto max-w-2xl">
<article>
<header className="flex flex-col">
<h1>{blog.title}</h1>
<time
dateTime={blog.date}
className="order-first flex items-center text-base text-zinc-400"
>
<span className="h-4 w-0.5 rounded-full bg-zinc-200" />
<span className="ml-3">{blog.date.toDateString()}</span>
</header>
<div className="mt-8 prose prose-zinc dark:prose-invert" data-mdx-content>
{children}
</div>
</article>
</div>
</div>
</div>
);
} And the corresponding Svelte version, which is closer to what powers this page:
<script lang="ts">
import type { BlogPost } from "$lib/blog/posts"
let { post, children }: { post: BlogPost; children: any } = $props()
</script>
<article class="prose prose-zinc">
<h1>{post.title}</h1>
<time datetime={post.isoDate}>{post.formattedDate}</time>
{@render children?.()}
</article> Tables look fine too
| Area | Before | After |
|---|---|---|
| First-token (ms) | 720 | 280 |
| Cold-start (ms) | 1900 | 540 |
| CPU at idle (%) | 4.1 | 0.9 |
A custom callout from markdown
You can drop Svelte/HTML straight into markdown and it picks up Tailwind:
What’s next
We are heading into 2025 with three big bets: deeper integrations, smarter routing, and a much richer dashboard experience. Subscribe to updates from the footer if you want to follow along.