diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5eebca4..22c1819 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -10,8 +10,9 @@ jobs:
       matrix:
         node: ['18.18.x']
         pkg: ['sdk', 'cli']
+        os: [ubuntu-latest, windows-latest, macos-latest]
     runs-on:
-      labels: ubuntu-latest
+      labels: ${{ matrix.os }}
     steps:
       - name: Checkout
         uses: actions/checkout@v4
diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md
index 61556b2..de4aa8a 100644
--- a/packages/cli/CHANGELOG.md
+++ b/packages/cli/CHANGELOG.md
@@ -5,6 +5,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Fixed
+
+- Improve handling of Windows CRLF line-endings 
+
 ## [0.1.0] - 2024-04-22
 
 Initial release.
diff --git a/packages/cli/src/commander.test.ts b/packages/cli/src/commander.test.ts
index 9a1f797..0691575 100644
--- a/packages/cli/src/commander.test.ts
+++ b/packages/cli/src/commander.test.ts
@@ -390,8 +390,10 @@ describe('link', () => {
     expect(file).toMatch(idLineRegex);
     // other than the added `id: xxxx` field, everything else should be identical,
     // although in practice, we'd expect some formatting changes
-    expect(file.replace(idLineRegex, '')).toStrictEqual(
-      await readFile(UNUSUAL_MARKDOWN_FILE, { encoding: 'utf8' }),
+    //
+    // We also normalize line endings to LF to avoid issues with CRLF on Windows
+    expect(file.replace(idLineRegex, '').replaceAll('\r\n', '\n')).toStrictEqual(
+      (await readFile(UNUSUAL_MARKDOWN_FILE, { encoding: 'utf8' })).replaceAll('\r\n', '\n'),
     );
   });
 });
diff --git a/packages/cli/src/frontmatter.spec.ts b/packages/cli/src/frontmatter.spec.ts
new file mode 100644
index 0000000..f40ed13
--- /dev/null
+++ b/packages/cli/src/frontmatter.spec.ts
@@ -0,0 +1,10 @@
+import { describe, expect, it } from 'vitest';
+import { extractFrontMatter } from './frontmatter.js';
+
+describe('extractFrontMatter()', () => {
+  it(String.raw`should handle \r\n (␍␊)`, () => {
+    const text = '---\r\nid: test\r\n---\r\ninfo\r\n';
+    const result = extractFrontMatter(text);
+    expect(result.metadata.id).toBe('test');
+  });
+});
diff --git a/packages/cli/src/frontmatter.ts b/packages/cli/src/frontmatter.ts
index eb72aaa..49cbbf4 100644
--- a/packages/cli/src/frontmatter.ts
+++ b/packages/cli/src/frontmatter.ts
@@ -3,7 +3,7 @@
  */
 import { parseDocument, type Document, YAMLMap, isMap } from 'yaml';
 
-const frontMatterRegex = /^-{3}\s*[\n\r](.*?)[\n\r]-{3}\s*[\n\r]+/s;
+const frontMatterRegex = /^-{3}\s*[\n\r](.*?[\n\r])-{3}\s*[\n\r]+/s;
 const urlIDRegex = /(?<baseURL>.*)\/d\/(?<documentID>[\w-]+)/;
 
 type UrlID = `${string}/d/${string}`;