Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions src/data/cv.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export interface Position { title: string; dates: string; note?: string }
// `note` is the one-line description shown on /cv/. `summary` (a paragraph) and
// `highlights` (bullet points) carry the longform version of a role, used only by the
// text exports: cv.txt, llms.txt, and llms-full.txt.
export interface Position { title: string; dates: string; note?: string; summary?: string; highlights?: string[] }
// `icon` is a filename in src/assets/icons; omit it to fall back to an initial monogram.
// `logo` is a full-wordmark filename in src/assets/logos; on the home page it replaces
// the org name entirely. Omit it (e.g. while a logo is outstanding) to fall back to
Expand All @@ -15,11 +18,35 @@ export interface Cv { experience: Org[]; education: Edu[]; languages: string[] }

export const CV: Cv = {
experience: [
{ org: 'Lineage Labs', logo: 'lineage-labs-logo-dark.svg', positions: [{ title: 'Co-Founder', dates: 'Feb 2026 – present', note: 'Building trust rails for AI agents.' }] },
{ org: 'Concordium', icon: 'Concordium Symbol_Black.svg', logo: 'Concordium_Logo_Black_full.svg', positions: [{ title: 'Director of Product', dates: 'Dec 2023 – Feb 2026' }] },
{ org: 'Lineage Labs', logo: 'lineage-labs-logo-dark.svg', positions: [{
title: 'Co-Founder', dates: 'Feb 2026 – present',
note: 'Building trust rails for AI agents.',
summary: 'Designed, engineered and deployed WaySpace, an agentic knowledge architecture using LLM-based indexing and hybrid search (symbolic parsing + agentic web scraping). Designed an agent identity infrastructure (WayID) to secure human-to-agent interactions.',
}] },
{ org: 'Concordium', icon: 'Concordium Symbol_Black.svg', logo: 'Concordium_Logo_Black_full.svg', positions: [{
title: 'Director of Product', dates: 'Dec 2023 – Feb 2026',
summary: 'Led product specification for protocol-level identity architectures and verifiable credentials, establishing an open standard for AI provenance and data authenticity using zero-knowledge proofs. Managed an 8-person product team alongside 50+ engineers to deliver low-latency core infrastructure, cross-platform SDKs, and consumer-facing wallet suite and ID app (for iOS, Android, browser).',
highlights: [
'Unified company product strategy of identity-first L1 blockchain.',
'Oversaw the product specification, design, and rollout of flagship initiative for protocol-level tokens for stablecoin issuance.',
'Revamped the outdated crypto wallet suite (iOS, Android, browser).',
'Drove developer relations and ecosystem growth through keynote talks, technical documentation, and workshops.',
'Oversaw product launches of: a novel Self-Sovereign Identity system for AI provenance certificates (using zero-knowledge proofs, DIDs, and Verifiable Credentials) and a standalone identity mobile app (Android, iOS).',
],
}] },
{ org: 'Pendulum', icon: 'Pendulum_logo.svg', logo: 'Pendulum_Logo_wordmark_full.svg', positions: [{ title: 'Head of Product', dates: 'Nov 2021 – Jun 2023', note: 'Headed product development of a forex-focused Polkadot parachain from idea to launch, including Spacewalk, the first bridge between Stellar and Polkadot.' }] },
{ org: 'SatoshiPay', logo: 'satoshipay_full.svg', positions: [
{ title: 'Head of Product', dates: 'Nov 2021 – Jun 2023', note: 'Led product development of a cross-border money transfer app on decentralised ledger technology, including compliance (KYC/AML) and financial-services partnerships.' },
// The longform covers the whole SatoshiPay/Pendulum tenure under its final title,
// so it sits on this position rather than being split across the two brands.
{ title: 'Head of Product', dates: 'Nov 2021 – Jun 2023',
note: 'Led product development of a cross-border money transfer app on decentralised ledger technology, including compliance (KYC/AML) and financial-services partnerships.',
summary: 'Oversaw engineering for a novel, 1-click online payment mechanism, a forex-optimised blockchain, and automated ETL telemetry pipelines for real-time app and network diagnostics. Managed complex roadmap for multi-stakeholder projects, covering technical protocol design, tokenomics, and user-facing apps (such as Solar, an Electron-based Stellar wallet). Built KYC/AML compliance process from scratch. Served as part of working group defining protocol standards in collaboration with the Stellar Development Foundation.',
highlights: [
'Managed product team of 6 working with 15+ engineers.',
'Worked in Bitcoin, Stellar, and Polkadot ecosystems.',
'Oversaw product launches of: 1-click paywall system on Germany\'s biggest independent finance news website with 10k+ users joining within the first weeks, Pendulum blockchain (a Substrate-based parachain), which won the fastest parachain auction at the time, and the first payment channel implementations in Bitcoin.',
],
},
{ title: 'Product Lead', dates: 'Jun 2017 – Nov 2021', note: 'Led development of a 1-click payment mechanism, first on Bitcoin then Stellar, and product management of Solar Wallet for desktop, Android, and iOS.' },
{ title: 'Product Consultant', dates: 'Apr 2015 – May 2017', note: 'Product and business strategy, product design, project management.' },
] },
Expand Down
15 changes: 15 additions & 0 deletions src/lib/txt.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getCollection, type CollectionEntry } from 'astro:content';
import { CREDITS, type Credit } from '../data/credits';
import { CV } from '../data/cv';

// Shared plumbing for the plain-text endpoints (llms.txt, llms-full.txt,
// cv.txt). All of them are generated from the same data that renders the
Expand All @@ -23,6 +24,20 @@ export function publishedCredits(): Credit[] {
return CREDITS.filter((c) => !c.title.startsWith('PLACEHOLDER'));
}

// Experience as a markdown list, one item per position: the one-line note and the
// longform summary run together, with the highlights nested beneath.
export function experienceMarkdown(): string[] {
return CV.experience.flatMap((org) =>
org.positions.flatMap((p) => {
const blurb = [p.note, p.summary].filter(Boolean).join(' ');
return [
`- ${p.title}, ${org.org} (${p.dates})${blurb ? ` — ${blurb}` : ''}`,
...(p.highlights ?? []).map((h) => ` - ${h}`),
];
}),
);
}

export function postUrl(site: string, post: CollectionEntry<'posts'>): string {
return `${site}/${post.data.date.getUTCFullYear()}/${post.id}/`;
}
Expand Down
2 changes: 2 additions & 0 deletions src/pages/cv.txt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export async function GET(context: APIContext) {
for (const p of org.positions) {
lines.push(`${p.title}, ${org.org} (${p.dates})`);
if (p.note) lines.push(` ${p.note}`);
if (p.summary) lines.push(` ${p.summary}`);
for (const h of p.highlights ?? []) lines.push(` - ${h}`);
lines.push('');
}
}
Expand Down
7 changes: 2 additions & 5 deletions src/pages/llms-full.txt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CV } from '../data/cv';
import {
publishableBody,
absolutize,
experienceMarkdown,
isoDate,
postUrl,
projectUrl,
Expand Down Expand Up @@ -52,11 +53,7 @@ export async function GET(context: APIContext) {
'',
];

for (const org of CV.experience) {
for (const p of org.positions) {
lines.push(`- ${p.title}, ${org.org} (${p.dates})${p.note ? ` — ${p.note}` : ''}`);
}
}
lines.push(...experienceMarkdown());

lines.push('', '### Education', '');
for (const e of CV.education) {
Expand Down
10 changes: 8 additions & 2 deletions src/pages/llms.txt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { APIContext } from 'astro';
import { SITE } from '../data/site';
import { CV } from '../data/cv';
import {
experienceMarkdown,
isoDate,
postUrl,
projectUrl,
Expand All @@ -12,7 +13,8 @@ import {
} from '../lib/txt';

// Curated index following the llms.txt convention (https://llmstxt.org/):
// a short map of the site for agents. The complete content lives in
// a short map of the site for agents, plus the CV's experience section so a
// single fetch answers who this is. The complete content lives in
// /llms-full.txt, and a plain-text CV in /cv.txt.
export async function GET(context: APIContext) {
const site = siteUrl(context.site);
Expand All @@ -39,10 +41,14 @@ export async function GET(context: APIContext) {
'## Docs',
'',
`- [Full site content](${site}/llms-full.txt): profile, CV, projects, and complete essay texts in one document`,
`- [CV](${site}/cv.txt): plain-text curriculum vitae`,
`- [CV](${site}/cv.txt): plain-text curriculum vitae with education and languages`,
`- [RSS feed](${site}/feed.xml): essay feed`,
`- [Sitemap](${site}/sitemap-index.xml)`,
'',
'## Experience',
'',
...experienceMarkdown(),
'',
'## Projects',
'',
...projects.map(
Expand Down