diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
index ed89fe6..dfbc0ef 100644
--- a/.github/codeql/codeql-config.yml
+++ b/.github/codeql/codeql-config.yml
@@ -1,7 +1,6 @@
paths:
- src
- tests
- - frontend
- tools
- .github
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 23df3ab..31f301e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -18,7 +18,7 @@ permissions:
jobs:
format:
name: Verify Code Format
- runs-on: self-hosted
+ runs-on: [self-hosted, Linux]
timeout-minutes: 15
steps:
- name: Checkout Source
@@ -26,6 +26,15 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v6
+ # actions/setup-dotnet's install script defaults to a system-wide
+ # location (e.g. C:\Program Files\dotnet) that self-hosted runner
+ # service accounts often can't write to. Redirect installs into the
+ # per-step runner temp directory, which is always writable
+ # regardless of runner OS or account. (The `runner` context is
+ # only available inside a step, not at the job- or workflow-level
+ # `env:` -- confirmed via GitHub's own workflow validation error.)
+ env:
+ DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet
with:
dotnet-version: '10.0.x'
cache: true
@@ -34,30 +43,99 @@ jobs:
NuGet.config
- name: Restore Dependencies
+ shell: bash
run: dotnet restore Trackdub.slnx -m:1
- name: Verify Format Style Limits
+ shell: bash
run: dotnet format Trackdub.slnx --verify-no-changes
- build:
- name: Build & Test (${{ matrix.name }})
+ repository-boundary:
+ name: Verify Repository Boundary
+ runs-on: [self-hosted, Linux]
+ timeout-minutes: 5
+ steps:
+ - name: Checkout Source
+ uses: actions/checkout@v7
+
+ - name: Scan for stale license/desktop-boundary claims
+ shell: bash
+ run: python3 scripts/ci/check-repository-boundary.py
+
+ build-windows:
+ name: Build & Test (Windows)
+ timeout-minutes: 45
+ runs-on: [self-hosted, Windows]
+ steps:
+ - name: Checkout Source
+ uses: actions/checkout@v7
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v6
+ env:
+ DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet
+ with:
+ dotnet-version: '10.0.x'
+ cache: true
+ cache-dependency-path: |
+ **/packages.lock.json
+ NuGet.config
+
+ - name: Restore Dependencies
+ shell: bash
+ run: dotnet restore Trackdub.slnx -m:1
+
+ - name: Compile
+ shell: bash
+ run: dotnet build Trackdub.slnx -c Release --no-restore -m:1
+
+ - name: Test
+ shell: bash
+ run: dotnet test Trackdub.slnx -c Release --no-build -m:1
+
+ build-linux:
+ name: Build & Test (Linux)
timeout-minutes: 45
- runs-on: ${{ matrix.runner }}
- strategy:
- fail-fast: false
- matrix:
- include:
- - name: Windows
- runner: self-hosted
- - name: Linux
- runner: self-hosted
+ runs-on: [self-hosted, Linux]
+ steps:
+ - name: Checkout Source
+ uses: actions/checkout@v7
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v6
+ env:
+ DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet
+ with:
+ dotnet-version: '10.0.x'
+ cache: true
+ cache-dependency-path: |
+ **/packages.lock.json
+ NuGet.config
+
+ - name: Restore Dependencies
+ shell: bash
+ run: dotnet restore Trackdub.slnx -m:1
+
+ - name: Compile
+ shell: bash
+ run: dotnet build Trackdub.slnx -c Release --no-restore -m:1
+
+ - name: Test
+ shell: bash
+ run: dotnet test Trackdub.slnx -c Release --no-build -m:1
+
+ build-macos:
+ name: Build & Test (macOS)
+ timeout-minutes: 45
+ runs-on: [self-hosted, macOS]
steps:
- name: Checkout Source
uses: actions/checkout@v7
- name: Setup .NET
uses: actions/setup-dotnet@v6
+ env:
+ DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet
with:
dotnet-version: '10.0.x'
cache: true
@@ -66,10 +144,13 @@ jobs:
NuGet.config
- name: Restore Dependencies
+ shell: bash
run: dotnet restore Trackdub.slnx -m:1
- name: Compile
+ shell: bash
run: dotnet build Trackdub.slnx -c Release --no-restore -m:1
- name: Test
+ shell: bash
run: dotnet test Trackdub.slnx -c Release --no-build -m:1
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..6ab2b58
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,28 @@
+# Contributing
+
+Trackdub (this repository) is the Apache-2.0 public core: the SDK, CLI,
+pipeline, inference, media processing, infrastructure, and neutral licensing
+mechanisms. See [docs/repository-policy.md](docs/repository-policy.md) and
+[AGENTS.md](AGENTS.md) for organization, dependency-direction rules, and
+build/test commands before opening a change.
+
+## Inbound contribution terms
+
+- Contributions to this repository are submitted under the
+ [Apache License, Version 2.0](LICENSE).
+- By submitting a contribution, you certify that you have the right to submit
+ it under that license (for example, it is your own original work, or you
+ otherwise hold the necessary rights).
+- No separate Contributor License Agreement (CLA) is currently required to
+ contribute here.
+- This forward-looking contribution policy is separate from, and does not
+ affect, any historical intellectual-property ownership review of code
+ already in the repository.
+
+## Before submitting a change
+
+- Run `dotnet build Trackdub.slnx -m:1` and `dotnet test Trackdub.slnx -m:1`.
+- Run `dotnet format Trackdub.slnx --verify-no-changes`.
+- Follow the coding style and dependency-direction rules in
+ [AGENTS.md](AGENTS.md).
+- Use imperative commit titles: `Add ...`, `Fix ...`, `Remove ...`.
diff --git a/LICENSE b/LICENSE
index 261061c..0a97c85 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright 2026 tonythethompson
+ Copyright 2024-2026 Trackdub LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/docs/legal/CONTRIBUTOR-LICENSE-AGREEMENT.md b/docs/legal/CONTRIBUTOR-LICENSE-AGREEMENT.md
deleted file mode 100644
index 9a6f12d..0000000
--- a/docs/legal/CONTRIBUTOR-LICENSE-AGREEMENT.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# Contributor License Agreement Placeholder
-
-This project is intended to support GPLv3 + commercial dual licensing.
-
-To preserve that option, outside contributors should sign a contributor agreement before their code is merged.
-
-At minimum, the agreement should grant the project owner the right to:
-
-- use the contribution in the GPL community edition
-- relicense the contribution under commercial terms
-- sublicense as needed for commercial customers
-- modify, distribute, and maintain the contribution
-- include the contribution in future versions
-
-This is a placeholder. Use a lawyer-reviewed CLA or copyright assignment before accepting external contributions if dual licensing matters.
diff --git a/docs/legal/LICENSE-HISTORY.md b/docs/legal/LICENSE-HISTORY.md
new file mode 100644
index 0000000..5acc0de
--- /dev/null
+++ b/docs/legal/LICENSE-HISTORY.md
@@ -0,0 +1,19 @@
+# License History
+
+Trackdub is split into two repositories with different licenses:
+
+- **`trackdubllc/Trackdub`** (this repository) — the public core: SDK, CLI,
+ pipeline, inference, media processing, infrastructure, and neutral
+ licensing mechanisms. Licensed under [Apache License, Version 2.0](../../LICENSE)
+ (see the root [NOTICE](../../NOTICE)).
+- **The Trackdub desktop product** — a separate, private repository that
+ depends on this public core. It owns the desktop application shell,
+ product policy (export tiers, watermarking, entitlements), activation,
+ packaging, and release signing. It is proprietary and is not covered by
+ the Apache-2.0 license in this repository.
+
+This repository was established with a fresh root history as the public
+core. It carries only Apache-2.0-compatible source and does not contain
+desktop product code, activation-server code, or proprietary packaging
+logic. Detailed historical ownership evidence for code predating this split
+is retained privately and is out of scope for this public document.
diff --git a/docs/legal/THIRD_PARTY_NOTICES.md b/docs/legal/THIRD_PARTY_NOTICES.md
index 05fbf86..2775cde 100644
--- a/docs/legal/THIRD_PARTY_NOTICES.md
+++ b/docs/legal/THIRD_PARTY_NOTICES.md
@@ -28,17 +28,6 @@ Each entry should include:
- attribution required?
- notes
-## Inter
-
-- name: Inter
-- version / revision: 4.1
-- source URL: https://github.com/rsms/inter/releases/download/v4.1/Inter-4.1.zip
-- license: SIL Open Font License 1.1
-- commercial use allowed? yes
-- redistribution allowed? yes
-- attribution required? license notice retained in `src/Trackdub.App/Assets/Fonts/Inter-LICENSE.txt`
-- notes: Packaged as `InterVariable.ttf` and `InterVariable-Italic.ttf` for Trackdub UI typography.
-
## FFmpeg / ffprobe Windows x64 binaries
- name: FFmpeg / ffprobe Windows x64 binaries (BtbN FFmpeg-Builds, `lgpl-shared`)
@@ -70,40 +59,7 @@ Each entry should include:
- commercial use allowed? yes
- redistribution allowed? yes, provided LGPL-2.1 obligations are met (dynamic linking, no source modifications)
- attribution required? yes
-- notes: .NET bindings for the LibVLC media framework. The application links to LibVLC dynamically (LGPL compliance). No modifications are made to the LibVLC or LibVLCSharp source. Used in `Trackdub.Media.Playback` and `Trackdub.App.Avalonia`.
-
-## LibVLCSharp.Avalonia
-
-- name: LibVLCSharp.Avalonia
-- version / revision: centrally pinned in Directory.Packages.props
-- source URL: https://www.nuget.org/packages/LibVLCSharp.Avalonia
-- license: LGPL-2.1-or-later
-- commercial use allowed? yes
-- redistribution allowed? yes, same terms as LibVLCSharp
-- attribution required? yes
-- notes: Avalonia-specific VideoView control for rendering LibVLC video output. Used in `Trackdub.App.Avalonia` only.
-
-## VideoLAN.LibVLC.Windows (LibVLC native runtime — Windows)
-
-- name: VideoLAN.LibVLC.Windows
-- version / revision: centrally pinned in Directory.Packages.props
-- source URL: https://www.nuget.org/packages/VideoLAN.LibVLC.Windows
-- license: LGPL-2.1-or-later
-- commercial use allowed? yes
-- redistribution allowed? yes, provided LGPL-2.1 notice and dynamic-linking obligations are met
-- attribution required? yes
-- notes: Bundled LibVLC native runtime for Windows (~100 MB). Extracted at build time into the application output directory. The application links dynamically — no static linking or source modification. Scoped to the Avalonia app project.
-
-## VideoLAN.LibVLC.Mac (LibVLC native runtime — macOS)
-
-- name: VideoLAN.LibVLC.Mac
-- version / revision: centrally pinned in Directory.Packages.props
-- source URL: https://www.nuget.org/packages/VideoLAN.LibVLC.Mac
-- license: LGPL-2.1-or-later
-- commercial use allowed? yes
-- redistribution allowed? yes, same terms as the Windows runtime package
-- attribution required? yes
-- notes: Bundled LibVLC native runtime for macOS. Extracted at build time into the application output directory. The application links dynamically — no static linking or source modification. Scoped to the Avalonia app project.
+- notes: .NET bindings for the LibVLC media framework. Trackdub links to LibVLC dynamically (LGPL compliance). No modifications are made to the LibVLC or LibVLCSharp source. Used in `Trackdub.Media.Playback` as one of two composited playback backends (libmpv is the primary compositor; LibVLC is the fallback). Bundling the native LibVLC runtime and any Avalonia-specific video-rendering control is a packaging concern of the consuming desktop product, not the public core, and is documented in that product's own third-party notices.
## LibVLC on Linux (system-installed)
@@ -114,7 +70,7 @@ Each entry should include:
- commercial use allowed? yes
- redistribution allowed? n/a — not bundled; users install via their system package manager
- attribution required? yes (license notice in documentation)
-- notes: On Linux, no NuGet runtime package is available. The application uses the system-installed `libvlc.so` located by `LibVlcRuntimeLocator`. Users must install VLC (e.g., `sudo apt install vlc` or equivalent) for playback to function.
+- notes: On Linux, no NuGet runtime package is available. `Trackdub.Media.Playback`'s `LibVlcRuntimeLocator` falls back to the system-installed `libvlc.so`. End users must install VLC (e.g., `sudo apt install vlc` or equivalent) for the LibVLC playback backend to function.
## Trackdub.OnnxRuntime.Dnnl.Native (generated package)
diff --git a/scripts/ci/check-repository-boundary.py b/scripts/ci/check-repository-boundary.py
new file mode 100644
index 0000000..d85fc82
--- /dev/null
+++ b/scripts/ci/check-repository-boundary.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python3
+"""Scan the public-core legal/policy surface for stale monorepo-era claims.
+
+Guards against regressions like the GPLv3/dual-license CLA wording and the
+false "Implemented in Application layer" IExportTierGate claim found during
+the open-core split: license text that contradicts the Apache-2.0 LICENSE,
+and desktop/cloud project names bleeding into files a public consumer of
+this core would read as authoritative.
+
+This intentionally does not scan docs/architecture, docs/specs,
+docs/operations, docs/development, docs/decisions, docs/audits, docs/plans,
+or tools/**: those contain legitimate historical/internal-engineering
+references to pre-split monorepo projects (Trackdub.App.Avalonia,
+Trackdub.Api, Trackdub.Worker, Trackdub.WebhookDelivery, the activation
+service) that are a separate, larger documentation cleanup — not part of
+this check.
+"""
+
+from __future__ import annotations
+
+import re
+import subprocess
+import sys
+from pathlib import Path
+
+REPO_ROOT = Path(__file__).resolve().parents[2]
+
+# License-claim patterns: must never appear anywhere in the tracked tree
+# (excluding historical planning/audit records and third-party notices,
+# which may legitimately discuss or quote other licenses).
+LICENSE_CLAIM_PATTERNS = [
+ # Matches GPL/GPLv3/GPL-3.0-only/"GPL 3.0" etc., case-insensitively,
+ # while excluding LGPL/AGPL (a letter immediately before "GPL").
+ re.compile(r"(? list[Path]:
+ output = subprocess.run(
+ ["git", "ls-files"],
+ cwd=REPO_ROOT,
+ check=True,
+ capture_output=True,
+ text=True,
+ ).stdout
+ return [REPO_ROOT / line for line in output.splitlines() if line]
+
+
+def matches_any(rel_posix: str, prefixes: list[str]) -> bool:
+ return any(rel_posix == p.rstrip("/") or rel_posix.startswith(p) for p in prefixes)
+
+
+def scan(files: list[Path], patterns: list[re.Pattern[str]]) -> list[str]:
+ violations: list[str] = []
+ for path in files:
+ try:
+ text = path.read_text(encoding="utf-8")
+ except (UnicodeDecodeError, OSError):
+ continue
+ for lineno, line in enumerate(text.splitlines(), start=1):
+ for pattern in patterns:
+ if pattern.search(line):
+ rel = path.relative_to(REPO_ROOT)
+ violations.append(f"{rel}:{lineno}: matched /{pattern.pattern}/: {line.strip()}")
+ return violations
+
+
+def main() -> int:
+ all_files = tracked_files()
+ violations: list[str] = []
+
+ license_files = [
+ f
+ for f in all_files
+ if not matches_any(f.relative_to(REPO_ROOT).as_posix(), LICENSE_CLAIM_EXCLUDE_DIRS)
+ and f.relative_to(REPO_ROOT).as_posix() not in LICENSE_CLAIM_EXCLUDE_FILES
+ ]
+ violations += scan(license_files, LICENSE_CLAIM_PATTERNS)
+
+ boundary_files = [
+ f
+ for f in all_files
+ if matches_any(f.relative_to(REPO_ROOT).as_posix(), BOUNDARY_SCAN_PATHS)
+ ]
+ violations += scan(boundary_files, BOUNDARY_PATTERNS)
+
+ if violations:
+ print("Repository-boundary scan failed:")
+ for v in violations:
+ print(f" {v}")
+ print()
+ print(
+ "Stale license or desktop/cloud-boundary wording found in the public-core "
+ "legal/policy surface. See docs/legal/LICENSE-HISTORY.md and "
+ "docs/repository-policy.md."
+ )
+ return 1
+
+ print("Repository-boundary scan passed.")
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/src/Trackdub.Cli/Trackdub.Cli.csproj b/src/Trackdub.Cli/Trackdub.Cli.csproj
index dae9e1f..8595969 100644
--- a/src/Trackdub.Cli/Trackdub.Cli.csproj
+++ b/src/Trackdub.Cli/Trackdub.Cli.csproj
@@ -6,6 +6,11 @@
true
trackdub
Trackdub.Cli
+ Trackdub
+ Trackdub command-line interface for the local-first AI dubbing pipeline.
+ Apache-2.0
+ https://github.com/trackdubllc/Trackdub
+ https://github.com/trackdubllc/Trackdub
diff --git a/src/Trackdub.Contracts/IExportTierGate.cs b/src/Trackdub.Contracts/IExportTierGate.cs
index f4ed061..5b7b4e5 100644
--- a/src/Trackdub.Contracts/IExportTierGate.cs
+++ b/src/Trackdub.Contracts/IExportTierGate.cs
@@ -1,7 +1,8 @@
namespace Trackdub.Contracts;
///
-/// Checks tier gates before export begins. Implemented in Application layer.
+/// Checks tier gates before export begins. The public core ships no concrete
+/// implementation; a consuming product supplies its own tier policy.
///
public interface IExportTierGate
{
diff --git a/src/Trackdub.OnnxRuntime.Dnnl.Native/Trackdub.OnnxRuntime.Dnnl.Native.csproj b/src/Trackdub.OnnxRuntime.Dnnl.Native/Trackdub.OnnxRuntime.Dnnl.Native.csproj
index 31ae1c1..5b19bb4 100644
--- a/src/Trackdub.OnnxRuntime.Dnnl.Native/Trackdub.OnnxRuntime.Dnnl.Native.csproj
+++ b/src/Trackdub.OnnxRuntime.Dnnl.Native/Trackdub.OnnxRuntime.Dnnl.Native.csproj
@@ -8,6 +8,8 @@
Trackdub
DNNL-enabled ONNX Runtime native assets for Trackdub.
MIT
+ https://github.com/trackdubllc/Trackdub
+ https://github.com/trackdubllc/Trackdub
false
$(NoWarn);NU5128
diff --git a/tests/Trackdub.Media.Tests/WavePcm16Tests.cs b/tests/Trackdub.Media.Tests/WavePcm16Tests.cs
index a19116e..28246de 100644
--- a/tests/Trackdub.Media.Tests/WavePcm16Tests.cs
+++ b/tests/Trackdub.Media.Tests/WavePcm16Tests.cs
@@ -399,7 +399,7 @@ await WavePcm16.WriteSamplesAsync(
using (var destinationLock = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None))
{
- Exception ex = await Assert.ThrowsAsync(() =>
+ Exception ex = await Assert.ThrowsAnyAsync(() =>
WavePcm16.WriteSamplesAsync(
path,
[0.9f, -0.9f, 0.9f, -0.9f],