diff --git a/.editorconfig b/.editorconfig
index d27d2a6..e22c7ec 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -5,6 +5,10 @@ root = true
[*.{cs,vb}]
dotnet_analyzer_diagnostic.severity = warning
+# License header
+dotnet_diagnostic.IDE0073.severity = error
+file_header_template = SPDX-License-Identifier: BUSL-1.1
+
# 1) Unnecessary usings
dotnet_diagnostic.IDE0005.severity = error
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 31a7532..9a45553 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,10 +1,8 @@
name: CI
on:
- push:
- branches: [ main, master ]
pull_request:
- branches: [ main, master ]
+ branches: [ "**" ]
jobs:
build-and-test:
@@ -13,21 +11,13 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- - name: Setup .NET (8 LTS and 10 preview)
+ - name: Setup .NET (8 LTS and 10 GA)
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
10.0.x
- dotnet-quality: 'preview'
-
- - name: Cache NuGet packages
- uses: actions/cache@v4
- with:
- path: ~/.nuget/packages
- key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
- restore-keys: |
- ${{ runner.os }}-nuget-
+ dotnet-quality: 'ga'
- name: Restore
run: dotnet restore src/Coven.sln
@@ -36,16 +26,4 @@ jobs:
run: dotnet build src/Coven.sln --configuration Release --no-restore
- name: Test
- env:
- DOTNET_CLI_TELEMETRY_OPTOUT: 1
- run: dotnet test src/Coven.sln --configuration Release --no-build --logger "trx;LogFileName=test_results.trx" --collect:"XPlat Code Coverage"
-
- - name: Upload Test Results
- if: always()
- uses: actions/upload-artifact@v4
- with:
- name: test-results
- path: |
- **/TestResults/*.trx
- **/TestResults/**/coverage.cobertura.xml
-
+ run: dotnet test src/Coven.sln --configuration Release --no-build
diff --git a/.github/workflows/prerelease-on-pr.yml b/.github/workflows/prerelease-on-pr.yml
deleted file mode 100644
index d4a458a..0000000
--- a/.github/workflows/prerelease-on-pr.yml
+++ /dev/null
@@ -1,110 +0,0 @@
-name: prerelease-on-pr
-
-on:
- pull_request:
- branches: [ main ]
- types: [opened, reopened, synchronize, ready_for_review]
- workflow_dispatch: {}
-
-permissions:
- contents: write
- pull-requests: write
-
-concurrency:
- group: pr-prerelease-${{ github.event.pull_request.number }}
- cancel-in-progress: false
-
-env:
- NUGET_SOURCE: https://api.nuget.org/v3/index.json
- HAS_NUGET_KEY: ${{ secrets.NUGET_API_KEY != '' }}
- IS_SAME_REPO: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
-
-jobs:
- prerelease:
- if: ${{ github.actor != 'github-actions[bot]' }}
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout PR head
- uses: actions/checkout@v4
- with:
- ref: ${{ github.event.pull_request.head.ref }}
- fetch-depth: 0
- fetch-tags: true
-
- - name: Ensure tools (jq)
- run: |
- if ! command -v jq >/dev/null; then
- sudo apt-get update && sudo apt-get install -y jq
- fi
-
- - name: Setup .NET SDK
- uses: actions/setup-dotnet@v4
- with:
- dotnet-version: '10.0.x'
- dotnet-quality: 'preview'
-
- - name: Cache NuGet
- uses: actions/cache@v4
- with:
- path: ~/.nuget/packages
- key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
- restore-keys: ${{ runner.os }}-nuget-
-
- - name: Make scripts executable
- run: chmod +x build/ci/prerelease/*.sh
-
- - name: Determine changed packages
- id: affected
- run: |
- build/ci/prerelease/detect-changed.sh \
- --base "${{ github.event.pull_request.base.sha }}" \
- --head "${{ github.event.pull_request.head.sha }}" \
- --shared-regex '^$'
-
- - name: Stop early if nothing changed
- if: steps.affected.outputs.any != 'true'
- run: echo "No package roots changed; skipping prerelease."
-
- - name: Compute prerelease version
- if: steps.affected.outputs.any == 'true'
- id: ver
- run: |
- build/ci/prerelease/compute-version.sh \
- --pr "${{ github.event.pull_request.number }}" \
- --run "${{ github.run_number }}" \
- --sha "${{ github.sha }}"
-
- - name: Build (sanity)
- if: steps.affected.outputs.any == 'true'
- run: dotnet build ./src/ -c Release --nologo
-
- - name: (Optional) Build CodeFix bundle for analyzers
- if: steps.affected.outputs.any == 'true'
- run: |
- if [[ -f src/Coven.Analyzers.CodeFixes/Coven.Analyzers.CodeFixes.csproj ]]; then
- dotnet build src/Coven.Analyzers.CodeFixes/Coven.Analyzers.CodeFixes.csproj -c Release -f netstandard2.0
- fi
-
- - name: Pack changed packages
- if: steps.affected.outputs.any == 'true'
- run: |
- build/ci/prerelease/pack.sh \
- --paths "${{ steps.affected.outputs.paths }}" \
- --version "${{ steps.ver.outputs.version }}"
-
- - name: Upload nupkgs (artifact)
- if: steps.affected.outputs.any == 'true'
- uses: actions/upload-artifact@v4
- with:
- name: nupkgs-prerelease
- path: artifacts/nupkg/*
- if-no-files-found: error
- retention-days: 7
-
- - name: Publish prerelease to NuGet.org
- if: steps.affected.outputs.any == 'true' && env.HAS_NUGET_KEY == 'true' && env.IS_SAME_REPO == 'true'
- env:
- NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
- run: |
- build/ci/prerelease/publish.sh --source "$NUGET_SOURCE"
diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml
index c473fc4..ab4ae15 100644
--- a/.github/workflows/promote.yml
+++ b/.github/workflows/promote.yml
@@ -1,74 +1,40 @@
-# Promote a stable release
-# - Computes a stable semantic version (from input or bump based on build/VERSION).
-# - Selects which packages to include (ids -> paths via build/packages.manifest.json).
-# - Packs with the exact stable version and creates a GitHub Release (non-prerelease).
-# - Optional: publish to NuGet.org if NUGET_API_KEY is provided.
-
name: promote
on:
workflow_dispatch:
inputs:
- version:
- description: "Stable version to release (overrides bump)"
- required: false
- type: string
bump:
description: "Semver bump to compute from build/VERSION"
- required: false
+ required: true
default: patch
type: choice
options: [patch, minor, major]
- commit:
- description: "Commit SHA or ref to build from"
- required: false
- type: string
- packages:
- description: "Comma-separated package IDs to promote (default: all manifest packages)"
- required: false
- type: string
- publish_nuget:
- description: "Publish to NuGet.org if NUGET_API_KEY is set"
- required: false
- type: boolean
- default: false
permissions:
contents: write
concurrency:
- group: promote-${{ inputs.version || github.ref_name }}
+ group: promote-${{ github.ref_name }}
cancel-in-progress: false
jobs:
build-pack-release:
runs-on: ubuntu-latest
- # Compute booleans once to avoid expression edge-cases with secrets in 'if:'
- env:
- SHOULD_PUBLISH_NUGET: ${{ inputs.publish_nuget }}
- HAS_NUGET_API_KEY: ${{ secrets.NUGET_API_KEY != '' }}
steps:
- name: Checkout (full history + tags)
uses: actions/checkout@v4
with:
- ref: ${{ inputs.commit || github.ref }}
fetch-depth: 0
fetch-tags: true
- - name: Setup .NET SDK
+ - name: Setup .NET SDK (10 GA)
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- dotnet-quality: 'preview'
+ dotnet-quality: 'ga'
- - name: Cache NuGet
- uses: actions/cache@v4
- with:
- path: ~/.nuget/packages
- key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
- restore-keys: |
- ${{ runner.os }}-nuget-
+
- name: Plan release (version and selection)
id: plan
@@ -76,55 +42,24 @@ jobs:
run: |
set -euo pipefail
base=$(tr -d '\r\n' < build/VERSION)
-
- # Compute version
- if [[ -n "${{ inputs.version }}" ]]; then
- version="${{ inputs.version }}"
- else
- bump="${{ inputs.bump }}"
- IFS='.' read -r MA MI PA <<< "${base%%-*}"
- MA=${MA:-0}; MI=${MI:-0}; PA=${PA:-0}
- case "$bump" in
- major) MA=$((MA+1)); MI=0; PA=0 ;;
- minor) MI=$((MI+1)); PA=0 ;;
- patch|*) PA=$((PA+1)) ;;
- esac
- version="$MA.$MI.$PA"
- fi
+ bump="${{ inputs.bump }}"
+ IFS='.' read -r MA MI PA <<< "${base%%-*}"
+ MA=${MA:-0}; MI=${MI:-0}; PA=${PA:-0}
+ case "$bump" in
+ major) MA=$((MA+1)); MI=0; PA=0 ;;
+ minor) MI=$((MI+1)); PA=0 ;;
+ patch|*) PA=$((PA+1)) ;;
+ esac
+ version="$MA.$MI.$PA"
echo "version=$version" >> "$GITHUB_OUTPUT"
- # Compute selected package paths from manifest
- if [[ -n "${{ inputs.packages }}" ]]; then
- mapfile -t want < <(echo "${{ inputs.packages }}" | tr ',' '\n' | sed 's/^\s*//; s/\s*$//;' | awk 'NF')
- if [[ ${#want[@]} -eq 0 ]]; then
- selected_paths=""
- else
- jq_query='['
- for id in "${want[@]}"; do jq_query+=\""${id}\","; done
- jq_query=${jq_query%,}
- jq_query+=']'
- selected_paths=$(jq -r --argjson ids "${jq_query}" \
- '.packages | map(select(.id as $i | $ids | index($i))) | .[].path' \
- build/packages.manifest.json | paste -sd, -)
- fi
- else
- selected_paths=$(jq -r '.packages[].path' build/packages.manifest.json | paste -sd, -)
- fi
-
- if [[ -z "$selected_paths" ]]; then
- echo "any=false" >> "$GITHUB_OUTPUT"
- echo "paths=" >> "$GITHUB_OUTPUT"
- else
- echo "any=true" >> "$GITHUB_OUTPUT"
- echo "paths=$selected_paths" >> "$GITHUB_OUTPUT"
- fi
+ paths=$(jq -r '.packages[].path' build/packages.manifest.json | paste -sd, -)
+ echo "paths=$paths" >> "$GITHUB_OUTPUT"
- # Determine previous stable version from tags vMAJOR.MINOR.PATCH
prev=$(git tag --list 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sed 's/^v//' | sort -V | tail -n1 || true)
echo "prev=$prev" >> "$GITHUB_OUTPUT"
- name: Validate version monotonicity
- if: steps.plan.outputs.any == 'true'
shell: bash
run: |
set -euo pipefail
@@ -141,14 +76,9 @@ jobs:
exit 1
fi
fi
-
- - name: Build CodeFix (same TFM/Configuration)
- run: |
- dotnet build src/Coven.Analyzers.CodeFixes/Coven.Analyzers.CodeFixes.csproj \
- -c Release -f netstandard2.0
+
- name: Pack stable
- if: steps.plan.outputs.any == 'true'
shell: bash
run: |
set -euo pipefail
@@ -163,27 +93,16 @@ jobs:
for csproj in "$d"/*.csproj; do
echo "Packing: $csproj"
-
- # Heuristic: treat as analyzer if PackageType=Analyzer OR it already packs to analyzers/*
- if grep -qiE '\s*Analyzer\s*|PackagePath="analyzers' "$csproj"; then
- echo " Detected analyzer -> no .snupkg; suppress NU5128 warning"
- dotnet pack "$csproj" -c Release -o artifacts/nupkg \
- /p:Version="$version" \
- /p:ContinuousIntegrationBuild=true \
- /p:NoWarn=NU5128
- else
- dotnet pack "$csproj" -c Release -o artifacts/nupkg \
- /p:Version="$version" \
- /p:ContinuousIntegrationBuild=true \
- /p:IncludeSymbols=true \
- /p:SymbolPackageFormat=snupkg
- fi
+ dotnet pack "$csproj" -c Release -o artifacts/nupkg \
+ /p:Version="$version" \
+ /p:ContinuousIntegrationBuild=true \
+ /p:IncludeSymbols=true \
+ /p:SymbolPackageFormat=snupkg
done
done
- name: Upload artifacts
- if: steps.plan.outputs.any == 'true'
uses: actions/upload-artifact@v4
with:
name: nupkgs-stable
@@ -191,7 +110,6 @@ jobs:
if-no-files-found: error
- name: Create GitHub release
- if: steps.plan.outputs.any == 'true'
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.plan.outputs.version }}
@@ -204,7 +122,7 @@ jobs:
artifacts/nupkg/*.snupkg
- name: Publish to NuGet.org
- if: ${{ env.SHOULD_PUBLISH_NUGET == 'true' && env.HAS_NUGET_API_KEY == 'true' }}
+ if: ${{ secrets.NUGET_API_KEY != '' }}
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
diff --git a/Directory.Build.props b/Directory.Build.props
index ad74752..a971c76 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -10,10 +10,22 @@
LICENSE
+
+
+ https://github.com/goldenwitch/coven
+ git
+ https://github.com/goldenwitch/coven
+ README.md
+ true
+
+
+
diff --git a/build/ReleaseProcess.md b/build/ReleaseProcess.md
index ecd086e..4ef7c50 100644
--- a/build/ReleaseProcess.md
+++ b/build/ReleaseProcess.md
@@ -1,13 +1,12 @@
Release process overview
-- Prereleases (PRs): On pull requests targeting `main`, we compute a prerelease version and pack only affected packages based on git deltas. Artifacts (`.nupkg/.snupkg`) are uploaded; optional publish to NuGet.org occurs if secrets are available and the PR originates from this repo.
-- Promotion: A manual workflow promotes a chosen ref to a stable version and can publish to NuGet.org.
+- CI on PRs: Every pull request restores, builds, and tests the solution.
+- Promotion: A manual workflow promotes a stable version by bumping `major`, `minor`, or `patch` from `build/VERSION`. All manifest packages are included. If NuGet API key is present, packages are published to NuGet.org.
Versioning
- Base version: `build/VERSION` (e.g., `0.1.0`).
-- Prerelease: `-preview.pr..` (from `build/ci/prerelease/compute-version.sh`). When not on a PR, a date-based variant is used.
-- Stable: exact value entered when promoting (e.g., `0.1.1`).
+- Stable: computed by bumping `major|minor|patch` from `build/VERSION`. Monotonicity vs latest `vMAJOR.MINOR.PATCH` tag is enforced.
Package manifest
@@ -21,23 +20,23 @@ Package manifest
]
}
-- Current entries include `Coven.Core` at `src/Coven.Core`, `Coven.Spellcasting` at `src/Coven.Spellcasting`, and `Coven.Chat` at `src/Coven.Chat`. Test projects are omitted.
+- Current entries include (test/sample/toy projects omitted):
+ - `Coven.Core` at `src/Coven.Core`
+ - `Coven.Core.Streaming` at `src/Coven.Core.Streaming`
+ - `Coven.Daemonology` at `src/Coven.Daemonology`
+ - `Coven.Transmutation` at `src/Coven.Transmutation`
+ - `Coven.Spellcasting` at `src/Coven.Spellcasting`
+ - `Coven.Chat` at `src/Coven.Chat`
+ - `Coven.Chat.Console` at `src/Coven.Chat.Console`
+ - `Coven.Chat.Discord` at `src/Coven.Chat.Discord`
+ - `Coven.Agents` at `src/Coven.Agents`
+ - `Coven.Agents.OpenAI` at `src/Coven.Agents.OpenAI`
-Prerelease change detection
-
-1) Determine changed files between the PR base and head SHAs.
-2) Mark a package as affected only if a changed file is under its manifest `path` (recursive).
-3) Workflow-only or shared-infra edits do not force rebuilds; if no package paths changed, prerelease packing/publishing is skipped.
Promotion to stable
- Trigger the “promote” workflow (Actions → promote).
-- Version: either provide `version` explicitly or choose a `bump` (patch/minor/major) computed from `build/VERSION`.
-- Package selection: provide a comma-separated list of package IDs to promote a subset; omit to promote all manifest packages.
-- Monotonic versioning: the workflow ensures the chosen version is strictly greater than the latest existing stable tag (`vMAJOR.MINOR.PATCH`).
-- If `NUGET_API_KEY` is set and `publish_nuget: true`, packages are pushed to NuGet.org.
-
-Notes
-
-- CI installs .NET SDK 10 (preview) for `net10.0` targets.
-- We no longer mutate package references, update samples, or push commits back from prerelease runs.
+- Choose bump: `patch`, `minor`, or `major`; the version is computed from `build/VERSION`.
+- All packages in `build/packages.manifest.json` are packed.
+- Monotonic versioning: the workflow ensures the computed version is strictly greater than the latest existing stable tag (`vMAJOR.MINOR.PATCH`).
+- If `NUGET_API_KEY` is set, packages are pushed to NuGet.org.
diff --git a/build/ci/prerelease/compute-version.sh b/build/ci/prerelease/compute-version.sh
deleted file mode 100755
index 9690fd2..0000000
--- a/build/ci/prerelease/compute-version.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env bash
-# build/ci/prerelease/compute-version.sh
-set -euo pipefail
-
-LABEL="preview"; PR=""; RUN=""; SHA=""
-VERFILE=""
-
-while [[ $# -gt 0 ]]; do
- case "$1" in
- --pr) PR="$2"; shift 2;;
- --run) RUN="$2"; shift 2;;
- --sha) SHA="$2"; shift 2;;
- --label) LABEL="$2"; shift 2;;
- --version-file) VERFILE="$2"; shift 2;;
- -h|--help) echo "usage: $0 --pr N --run N --sha sha [--label preview] [--version-file path]"; exit 0;;
- *) echo "unknown arg: $1"; exit 2;;
- esac
-done
-
-if [[ -z "$VERFILE" ]]; then
- if [[ -f build/VERSION ]]; then VERFILE=build/VERSION
- elif [[ -f Build/VERSION ]]; then VERFILE=Build/VERSION
- else echo "VERSION file not found."; exit 1; fi
-fi
-
-base="$(tr -d '\r\n' < "$VERFILE")"
-base="${base%%-*}" # strip any existing pre-release
-short="${SHA:0:7}"
-: "${RUN:=0}"
-
-if [[ -n "$PR" ]]; then
- version="${base}-${LABEL}.pr${PR}.${RUN}.${short}"
-else
- # Fallback shape when not on PR
- stamp="$(date -u +%Y%m%d)"
- version="${base}-${LABEL}.${stamp}.${RUN}.${short}"
-fi
-
-if [[ -n "${GITHUB_OUTPUT:-}" ]]; then echo "version=$version" >> "$GITHUB_OUTPUT"; else echo "$version"; fi
diff --git a/build/ci/prerelease/detect-changed.sh b/build/ci/prerelease/detect-changed.sh
deleted file mode 100755
index 764b654..0000000
--- a/build/ci/prerelease/detect-changed.sh
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env bash
-# build/ci/prerelease/detect-changed.sh
-set -euo pipefail
-
-usage() {
- cat < --head [--manifest ] [--shared-regex ] [--changed-file-list ]
-Outputs: any=, ids=, paths= to \$GITHUB_OUTPUT if set; otherwise prints JSON.
-EOF
-}
-
-BASE=""; HEAD=""; MANIFEST=""; CHANGED_FILE_LIST=""
-SHARED_REGEX='^(build/|Build/|Directory\.Build\.|global\.json$|NuGet\.config$|\.config/nuget\.config|\.github/workflows/)'
-
-while [[ $# -gt 0 ]]; do
- case "$1" in
- --base) BASE="$2"; shift 2;;
- --head) HEAD="$2"; shift 2;;
- --manifest) MANIFEST="$2"; shift 2;;
- --shared-regex) SHARED_REGEX="$2"; shift 2;;
- --changed-file-list) CHANGED_FILE_LIST="$2"; shift 2;;
- -h|--help) usage; exit 0;;
- *) echo "Unknown arg: $1"; usage; exit 2;;
- esac
-done
-
-# Resolve manifest
-if [[ -z "$MANIFEST" ]]; then
- if [[ -f build/packages.manifest.json ]]; then MANIFEST=build/packages.manifest.json
- elif [[ -f Build/packages.manifest.json ]]; then MANIFEST=Build/packages.manifest.json
- else
- echo "packages.manifest.json not found under build/ or Build/." >&2; exit 1
- fi
-fi
-command -v jq >/dev/null || { echo "jq is required."; exit 1; }
-
-# Gather changed files
-if [[ -n "$CHANGED_FILE_LIST" ]]; then
- CHANGED="$(cat "$CHANGED_FILE_LIST" || true)"
-else
- [[ -n "$BASE" && -n "$HEAD" ]] || { echo "--base and --head required"; exit 2; }
- CHANGED="$(git diff --name-only "$BASE" "$HEAD" || true)"
-fi
-
-# Build id->path map from manifest
-mapfile -t MAP < <(jq -r '.packages[] | "\(.id)|\(.path)"' "$MANIFEST")
-
-# Force all if shared inputs changed
-if echo "$CHANGED" | grep -E -q "$SHARED_REGEX"; then
- ids="$(printf '%s\n' "${MAP[@]}" | cut -d'|' -f1 | paste -sd, -)"
- paths="$(printf '%s\n' "${MAP[@]}" | cut -d'|' -f2 | paste -sd, -)"
- any=true
-else
- ids=""; paths=""
- while IFS= read -r f; do
- for pair in "${MAP[@]}"; do
- id="${pair%%|*}"; pth="${pair##*|}"
- pfx="${pth%/}/"
- if [[ "$f" == "$pfx"* ]]; then
- [[ ",$ids," == *",$id,"* ]] || ids="${ids:+$ids,}$id"
- [[ ",$paths," == *",$pth,"* ]] || paths="${paths:+$paths,}$pth"
- fi
- done
- done <<< "$CHANGED"
- any=$([[ -n "$ids" ]] && echo true || echo false)
-fi
-
-if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
- {
- echo "any=$any"
- echo "ids=$ids"
- echo "paths=$paths"
- } >> "$GITHUB_OUTPUT"
-else
- jq -n --arg any "$any" --arg ids "$ids" --arg paths "$paths" '{any:$any, ids:$ids, paths:$paths}'
-fi
diff --git a/build/ci/prerelease/pack.sh b/build/ci/prerelease/pack.sh
deleted file mode 100755
index dc188e7..0000000
--- a/build/ci/prerelease/pack.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env bash
-# build/ci/prerelease/pack.sh
-set -euo pipefail
-
-PATHS=""; VERSION=""
-while [[ $# -gt 0 ]]; do
- case "$1" in
- --paths) PATHS="$2"; shift 2;;
- --version) VERSION="$2"; shift 2;;
- -h|--help) echo "usage: $0 --paths csv --version semver"; exit 0;;
- *) echo "unknown arg: $1"; exit 2;;
- esac
-done
-
-[[ -n "$PATHS" && -n "$VERSION" ]] || { echo "--paths and --version required"; exit 2; }
-
-mkdir -p artifacts/nupkg
-IFS=',' read -ra dirs <<< "$PATHS"
-shopt -s nullglob
-
-for d in "${dirs[@]}"; do
- d="${d//[$'\r\n']/}"
- [[ -z "$d" ]] && continue
- for csproj in "$d"/*.csproj; do
- echo "Packing: $csproj"
- if grep -qiE '\s*Analyzer\s*|PackagePath="analyzers' "$csproj"; then
- dotnet pack "$csproj" -c Release -o artifacts/nupkg \
- /p:Version="$VERSION" \
- /p:ContinuousIntegrationBuild=true \
- /p:NoWarn=NU5128
- else
- dotnet pack "$csproj" -c Release -o artifacts/nupkg \
- /p:Version="$VERSION" \
- /p:ContinuousIntegrationBuild=true \
- /p:IncludeSymbols=true \
- /p:SymbolPackageFormat=snupkg
- fi
- done
-done
diff --git a/build/ci/prerelease/publish.sh b/build/ci/prerelease/publish.sh
deleted file mode 100755
index d80a579..0000000
--- a/build/ci/prerelease/publish.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-# build/ci/prerelease/publish.sh
-set -euo pipefail
-SRC="https://api.nuget.org/v3/index.json"
-while [[ $# -gt 0 ]]; do
- case "$1" in
- --source) SRC="$2"; shift 2;;
- -h|--help) echo "usage: NUGET_API_KEY=... $0 [--source url]"; exit 0;;
- *) echo "unknown arg: $1"; exit 2;;
- esac
-done
-: "${NUGET_API_KEY:?NUGET_API_KEY is required}"
-shopt -s nullglob
-for pkg in artifacts/nupkg/*.nupkg; do
- echo "Pushing $pkg"
- dotnet nuget push "$pkg" --skip-duplicate --api-key "$NUGET_API_KEY" --source "$SRC"
-done
diff --git a/build/packages.manifest.json b/build/packages.manifest.json
index ac178d8..98f34ba 100644
--- a/build/packages.manifest.json
+++ b/build/packages.manifest.json
@@ -1,7 +1,16 @@
{
"packages": [
- { "id": "Coven.Core", "path": "src/Coven.Core" },
- { "id": "Coven.Spellcasting", "path": "src/Coven.Spellcasting" },
- { "id": "Coven.Chat", "path": "src/Coven.Chat" }
+ { "id": "Coven.Core", "path": "src/Coven.Core" },
+ { "id": "Coven.Core.Streaming", "path": "src/Coven.Core.Streaming" },
+ { "id": "Coven.Daemonology", "path": "src/Coven.Daemonology" },
+ { "id": "Coven.Transmutation", "path": "src/Coven.Transmutation" },
+ { "id": "Coven.Spellcasting", "path": "src/Coven.Spellcasting" },
+
+ { "id": "Coven.Chat", "path": "src/Coven.Chat" },
+ { "id": "Coven.Chat.Console", "path": "src/Coven.Chat.Console" },
+ { "id": "Coven.Chat.Discord", "path": "src/Coven.Chat.Discord" },
+
+ { "id": "Coven.Agents", "path": "src/Coven.Agents" },
+ { "id": "Coven.Agents.OpenAI", "path": "src/Coven.Agents.OpenAI" }
]
}
diff --git a/src/Coven.Agents.OpenAI/OpenAIAgentSession.cs b/src/Coven.Agents.OpenAI/OpenAIAgentSession.cs
index 702e9ee..17ad4c6 100644
--- a/src/Coven.Agents.OpenAI/OpenAIAgentSession.cs
+++ b/src/Coven.Agents.OpenAI/OpenAIAgentSession.cs
@@ -92,7 +92,7 @@ public async Task StartAsync()
await foreach ((long position, AgentEntry entry) in _agentJournal.TailAsync(0, ct))
{
// Early filtering: ignore drafts and acks to avoid loops/noise
- if (entry is AgentEntryDraft or AgentAck)
+ if (entry is IDraft or AgentAck)
{
continue;
}
diff --git a/src/Coven.Agents.OpenAI/OpenAIEntry.cs b/src/Coven.Agents.OpenAI/OpenAIEntry.cs
index 0c2aa2b..d03526e 100644
--- a/src/Coven.Agents.OpenAI/OpenAIEntry.cs
+++ b/src/Coven.Agents.OpenAI/OpenAIEntry.cs
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: BUSL-1.1
+using Coven.Core;
+
namespace Coven.Agents.OpenAI;
///
@@ -7,7 +9,7 @@ namespace Coven.Agents.OpenAI;
///
public abstract record OpenAIEntry(
string Sender
-);
+) : Entry;
/// Outgoing request payload destined for OpenAI.
public sealed record OpenAIEfferent(
@@ -31,7 +33,7 @@ public sealed record OpenAIAfferentChunk(
string ResponseId,
DateTimeOffset Timestamp,
string Model
-) : OpenAIEntry(Sender);
+) : OpenAIEntry(Sender), IDraft;
// Streaming thought chunks (afferent): model streams thoughts back
/// Incoming thought chunk from OpenAI.
@@ -41,7 +43,7 @@ public sealed record OpenAIAfferentThoughtChunk(
string ResponseId,
DateTimeOffset Timestamp,
string Model
-) : OpenAIEntry(Sender);
+) : OpenAIEntry(Sender), IDraft;
/// Full thought message from OpenAI (non-chunked).
public sealed record OpenAIThought(
@@ -63,7 +65,7 @@ string Text
public sealed record OpenAIEfferentThoughtChunk(
string Sender,
string Text
-) : OpenAIEntry(Sender);
+) : OpenAIEntry(Sender), IDraft;
/// Marks completion of a streaming response from OpenAI.
public sealed record OpenAIStreamCompleted(
@@ -71,4 +73,4 @@ public sealed record OpenAIStreamCompleted(
string ResponseId,
DateTimeOffset Timestamp,
string Model
-) : OpenAIEntry(Sender);
+) : OpenAIEntry(Sender), IDraft;
diff --git a/src/Coven.Agents/AgentEntry.cs b/src/Coven.Agents/AgentEntry.cs
index 3cef59f..dbe368c 100644
--- a/src/Coven.Agents/AgentEntry.cs
+++ b/src/Coven.Agents/AgentEntry.cs
@@ -1,16 +1,18 @@
// SPDX-License-Identifier: BUSL-1.1
+using Coven.Core;
+
namespace Coven.Agents;
///
/// Base entry type for agent journals (prompts, responses, thoughts, acks, and streaming chunks).
///
-public abstract record AgentEntry(string Sender);
+public abstract record AgentEntry(string Sender) : Entry;
///
/// Marker base for draft entries that should not be forwarded out of the agent journal directly.
///
-public abstract record AgentEntryDraft(string Sender) : AgentEntry(Sender);
+public abstract record AgentEntryDraft(string Sender) : AgentEntry(Sender), IDraft;
/// Represents a user or upstream prompt destined for an agent.
public sealed record AgentPrompt(string Sender, string Text) : AgentEntry(Sender);
diff --git a/src/Coven.Chat.Console/ConsoleChatDaemon.cs b/src/Coven.Chat.Console/ConsoleChatDaemon.cs
index baa8c22..22dce89 100644
--- a/src/Coven.Chat.Console/ConsoleChatDaemon.cs
+++ b/src/Coven.Chat.Console/ConsoleChatDaemon.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Coven.Daemonology;
diff --git a/src/Coven.Chat.Console/ConsoleChatSession.cs b/src/Coven.Chat.Console/ConsoleChatSession.cs
index 6456772..4143950 100644
--- a/src/Coven.Chat.Console/ConsoleChatSession.cs
+++ b/src/Coven.Chat.Console/ConsoleChatSession.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Coven.Transmutation;
using Microsoft.Extensions.Logging;
diff --git a/src/Coven.Chat.Console/ConsoleChatSessionFactory.cs b/src/Coven.Chat.Console/ConsoleChatSessionFactory.cs
index 2285f02..e2297f3 100644
--- a/src/Coven.Chat.Console/ConsoleChatSessionFactory.cs
+++ b/src/Coven.Chat.Console/ConsoleChatSessionFactory.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Coven.Transmutation;
using Microsoft.Extensions.Logging;
diff --git a/src/Coven.Chat.Console/ConsoleClientConfig.cs b/src/Coven.Chat.Console/ConsoleClientConfig.cs
index 3e048f4..6a1b826 100644
--- a/src/Coven.Chat.Console/ConsoleClientConfig.cs
+++ b/src/Coven.Chat.Console/ConsoleClientConfig.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
namespace Coven.Chat.Console;
///
diff --git a/src/Coven.Chat.Console/ConsoleEntry.cs b/src/Coven.Chat.Console/ConsoleEntry.cs
index 9df7f67..2aa6012 100644
--- a/src/Coven.Chat.Console/ConsoleEntry.cs
+++ b/src/Coven.Chat.Console/ConsoleEntry.cs
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: BUSL-1.1
+using Coven.Core;
+
namespace Coven.Chat.Console;
///
@@ -8,7 +10,7 @@ namespace Coven.Chat.Console;
public abstract record ConsoleEntry(
string Sender,
string Text
-);
+) : Entry;
/// Acknowledgement entry for internal synchronization.
public sealed record ConsoleAck(
diff --git a/src/Coven.Chat.Console/ConsoleGatewayConnection.cs b/src/Coven.Chat.Console/ConsoleGatewayConnection.cs
index 6c5dfbb..6ad742a 100644
--- a/src/Coven.Chat.Console/ConsoleGatewayConnection.cs
+++ b/src/Coven.Chat.Console/ConsoleGatewayConnection.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
diff --git a/src/Coven.Chat.Console/ConsoleLog.cs b/src/Coven.Chat.Console/ConsoleLog.cs
index 77e12f3..a3c22b4 100644
--- a/src/Coven.Chat.Console/ConsoleLog.cs
+++ b/src/Coven.Chat.Console/ConsoleLog.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Microsoft.Extensions.Logging;
namespace Coven.Chat.Console;
diff --git a/src/Coven.Chat.Console/ConsoleScrivener.cs b/src/Coven.Chat.Console/ConsoleScrivener.cs
index 9016abc..f08ef27 100644
--- a/src/Coven.Chat.Console/ConsoleScrivener.cs
+++ b/src/Coven.Chat.Console/ConsoleScrivener.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
diff --git a/src/Coven.Chat.Console/ConsoleTransmuter.cs b/src/Coven.Chat.Console/ConsoleTransmuter.cs
index 7c13107..4244518 100644
--- a/src/Coven.Chat.Console/ConsoleTransmuter.cs
+++ b/src/Coven.Chat.Console/ConsoleTransmuter.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Transmutation;
namespace Coven.Chat.Console;
diff --git a/src/Coven.Chat.Console/ServiceCollectionExtensions.cs b/src/Coven.Chat.Console/ServiceCollectionExtensions.cs
index 02f2766..d336090 100644
--- a/src/Coven.Chat.Console/ServiceCollectionExtensions.cs
+++ b/src/Coven.Chat.Console/ServiceCollectionExtensions.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Coven.Daemonology;
diff --git a/src/Coven.Chat.Discord/DiscordChatDaemon.cs b/src/Coven.Chat.Discord/DiscordChatDaemon.cs
index 9f1bfd1..98a8fb1 100644
--- a/src/Coven.Chat.Discord/DiscordChatDaemon.cs
+++ b/src/Coven.Chat.Discord/DiscordChatDaemon.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Coven.Daemonology;
diff --git a/src/Coven.Chat.Discord/DiscordChatSession.cs b/src/Coven.Chat.Discord/DiscordChatSession.cs
index 1156a80..018060c 100644
--- a/src/Coven.Chat.Discord/DiscordChatSession.cs
+++ b/src/Coven.Chat.Discord/DiscordChatSession.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Coven.Core.Streaming;
using Coven.Transmutation;
diff --git a/src/Coven.Chat.Discord/DiscordChatSessionFactory.cs b/src/Coven.Chat.Discord/DiscordChatSessionFactory.cs
index eb38081..877a9a1 100644
--- a/src/Coven.Chat.Discord/DiscordChatSessionFactory.cs
+++ b/src/Coven.Chat.Discord/DiscordChatSessionFactory.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Coven.Core.Streaming;
using Coven.Transmutation;
diff --git a/src/Coven.Chat.Discord/DiscordClientConfig.cs b/src/Coven.Chat.Discord/DiscordClientConfig.cs
index 3726880..4701b9a 100644
--- a/src/Coven.Chat.Discord/DiscordClientConfig.cs
+++ b/src/Coven.Chat.Discord/DiscordClientConfig.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
namespace Coven.Chat.Discord;
///
diff --git a/src/Coven.Chat.Discord/DiscordEntry.cs b/src/Coven.Chat.Discord/DiscordEntry.cs
index d275e67..bcd3541 100644
--- a/src/Coven.Chat.Discord/DiscordEntry.cs
+++ b/src/Coven.Chat.Discord/DiscordEntry.cs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+
+using Coven.Core;
+
namespace Coven.Chat.Discord;
///
@@ -6,7 +10,7 @@ namespace Coven.Chat.Discord;
public abstract record DiscordEntry(
string Sender,
string Text
-);
+) : Entry;
/// Acknowledgement entry for internal synchronization.
public sealed record DiscordAck(
diff --git a/src/Coven.Chat.Discord/DiscordGatewayConnection.cs b/src/Coven.Chat.Discord/DiscordGatewayConnection.cs
index 602d375..e2fd73f 100644
--- a/src/Coven.Chat.Discord/DiscordGatewayConnection.cs
+++ b/src/Coven.Chat.Discord/DiscordGatewayConnection.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using System.Globalization;
using Coven.Core;
using Discord;
diff --git a/src/Coven.Chat.Discord/DiscordLog.cs b/src/Coven.Chat.Discord/DiscordLog.cs
index d26e819..8ca8277 100644
--- a/src/Coven.Chat.Discord/DiscordLog.cs
+++ b/src/Coven.Chat.Discord/DiscordLog.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Microsoft.Extensions.Logging;
namespace Coven.Chat.Discord;
diff --git a/src/Coven.Chat.Discord/DiscordScrivener.cs b/src/Coven.Chat.Discord/DiscordScrivener.cs
index 38a4c13..b6d24b2 100644
--- a/src/Coven.Chat.Discord/DiscordScrivener.cs
+++ b/src/Coven.Chat.Discord/DiscordScrivener.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
diff --git a/src/Coven.Chat.Discord/DiscordTransmuter.cs b/src/Coven.Chat.Discord/DiscordTransmuter.cs
index c9daa89..4ec33d0 100644
--- a/src/Coven.Chat.Discord/DiscordTransmuter.cs
+++ b/src/Coven.Chat.Discord/DiscordTransmuter.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Transmutation;
namespace Coven.Chat.Discord;
diff --git a/src/Coven.Chat.Discord/ServiceCollectionExtensions.cs b/src/Coven.Chat.Discord/ServiceCollectionExtensions.cs
index 2bba83a..eb8982d 100644
--- a/src/Coven.Chat.Discord/ServiceCollectionExtensions.cs
+++ b/src/Coven.Chat.Discord/ServiceCollectionExtensions.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Coven.Core.Streaming;
using Microsoft.Extensions.DependencyInjection.Extensions;
diff --git a/src/Coven.Chat/ChatEntry.cs b/src/Coven.Chat/ChatEntry.cs
index fb26494..d0efd29 100644
--- a/src/Coven.Chat/ChatEntry.cs
+++ b/src/Coven.Chat/ChatEntry.cs
@@ -1,16 +1,18 @@
// SPDX-License-Identifier: BUSL-1.1
+using Coven.Core;
+
namespace Coven.Chat;
///
/// Base entry type for chat journals (incoming/outgoing messages, acks, and streaming drafts/chunks).
///
-public abstract record ChatEntry(string Sender);
+public abstract record ChatEntry(string Sender) : Entry;
///
/// Marker base for draft entries that should not be forwarded by adapters directly.
///
-public abstract record ChatEntryDraft(string Sender) : ChatEntry(Sender);
+public abstract record ChatEntryDraft(string Sender) : ChatEntry(Sender), IDraft;
/// Outgoing chat message intended for users.
public sealed record ChatEfferent(string Sender, string Text) : ChatEntry(Sender);
diff --git a/src/Coven.Chat/ServiceCollectionExtensions.cs b/src/Coven.Chat/ServiceCollectionExtensions.cs
index 0db1070..f76e83d 100644
--- a/src/Coven.Chat/ServiceCollectionExtensions.cs
+++ b/src/Coven.Chat/ServiceCollectionExtensions.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Coven.Core.Streaming;
using Coven.Daemonology;
diff --git a/src/Coven.Core/Entry.cs b/src/Coven.Core/Entry.cs
new file mode 100644
index 0000000..41a72aa
--- /dev/null
+++ b/src/Coven.Core/Entry.cs
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: BUSL-1.1
+
+namespace Coven.Core;
+
+///
+/// Marker base type for journal entries.
+///
+public abstract record Entry;
+
+///
+/// Marker interface for draft entries.
+///
+public interface IDraft { }
diff --git a/src/Coven.Daemonology.Tests/ContractDaemonFailureTests.cs b/src/Coven.Daemonology.Tests/ContractDaemonFailureTests.cs
index be0bf91..620fea9 100644
--- a/src/Coven.Daemonology.Tests/ContractDaemonFailureTests.cs
+++ b/src/Coven.Daemonology.Tests/ContractDaemonFailureTests.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Coven.Daemonology.Tests.Infrastructure;
diff --git a/src/Coven.Daemonology.Tests/ContractDaemonStatusTests.cs b/src/Coven.Daemonology.Tests/ContractDaemonStatusTests.cs
index a26ce97..115a4d0 100644
--- a/src/Coven.Daemonology.Tests/ContractDaemonStatusTests.cs
+++ b/src/Coven.Daemonology.Tests/ContractDaemonStatusTests.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
using Coven.Daemonology.Tests.Infrastructure;
diff --git a/src/Coven.Daemonology.Tests/Infrastructure/TestDaemon.cs b/src/Coven.Daemonology.Tests/Infrastructure/TestDaemon.cs
index 133c943..fe77d40 100644
--- a/src/Coven.Daemonology.Tests/Infrastructure/TestDaemon.cs
+++ b/src/Coven.Daemonology.Tests/Infrastructure/TestDaemon.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
namespace Coven.Daemonology.Tests.Infrastructure;
diff --git a/src/Coven.Daemonology/ContractDaemon.cs b/src/Coven.Daemonology/ContractDaemon.cs
index a2bfaf4..0b9c87d 100644
--- a/src/Coven.Daemonology/ContractDaemon.cs
+++ b/src/Coven.Daemonology/ContractDaemon.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Core;
namespace Coven.Daemonology;
diff --git a/src/Coven.Daemonology/DaemonEvent.cs b/src/Coven.Daemonology/DaemonEvent.cs
index fcd590e..eb86f96 100644
--- a/src/Coven.Daemonology/DaemonEvent.cs
+++ b/src/Coven.Daemonology/DaemonEvent.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
namespace Coven.Daemonology;
///
diff --git a/src/Coven.Daemonology/IDaemon.cs b/src/Coven.Daemonology/IDaemon.cs
index b442ca1..ba5704a 100644
--- a/src/Coven.Daemonology/IDaemon.cs
+++ b/src/Coven.Daemonology/IDaemon.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
namespace Coven.Daemonology;
///
diff --git a/src/Coven.Daemonology/Status.cs b/src/Coven.Daemonology/Status.cs
index 10db99f..d473eb9 100644
--- a/src/Coven.Daemonology/Status.cs
+++ b/src/Coven.Daemonology/Status.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
namespace Coven.Daemonology;
///
diff --git a/src/Coven.Transmutation/IBatchTransmuter.cs b/src/Coven.Transmutation/IBatchTransmuter.cs
index 77caede..805bef7 100644
--- a/src/Coven.Transmutation/IBatchTransmuter.cs
+++ b/src/Coven.Transmutation/IBatchTransmuter.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
namespace Coven.Transmutation;
///
diff --git a/src/Coven.Transmutation/IBiDirectionalTransmuter.cs b/src/Coven.Transmutation/IBiDirectionalTransmuter.cs
index bc03017..dacae4f 100644
--- a/src/Coven.Transmutation/IBiDirectionalTransmuter.cs
+++ b/src/Coven.Transmutation/IBiDirectionalTransmuter.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
namespace Coven.Transmutation;
///
diff --git a/src/Coven.Transmutation/ITransmuter.cs b/src/Coven.Transmutation/ITransmuter.cs
index d868092..2da059f 100644
--- a/src/Coven.Transmutation/ITransmuter.cs
+++ b/src/Coven.Transmutation/ITransmuter.cs
@@ -1,4 +1,6 @@
-namespace Coven.Transmutation;
+// SPDX-License-Identifier: BUSL-1.1
+
+namespace Coven.Transmutation;
///
/// Defines a one-way transmutation from to ,
diff --git a/src/Coven.Transmutation/LambdaTransmuter.cs b/src/Coven.Transmutation/LambdaTransmuter.cs
index fec5232..9f9995f 100644
--- a/src/Coven.Transmutation/LambdaTransmuter.cs
+++ b/src/Coven.Transmutation/LambdaTransmuter.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
namespace Coven.Transmutation;
///
diff --git a/src/samples/01.DiscordAgent/Program.cs b/src/samples/01.DiscordAgent/Program.cs
index da704d8..aa69ce7 100644
--- a/src/samples/01.DiscordAgent/Program.cs
+++ b/src/samples/01.DiscordAgent/Program.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Agents.OpenAI;
using Coven.Chat.Discord;
using Coven.Core;
diff --git a/src/samples/01.DiscordAgent/RouterBlock.cs b/src/samples/01.DiscordAgent/RouterBlock.cs
index 77aa41c..56da619 100644
--- a/src/samples/01.DiscordAgent/RouterBlock.cs
+++ b/src/samples/01.DiscordAgent/RouterBlock.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Agents;
using Coven.Chat;
using Coven.Core;
diff --git a/src/toys/Coven.Toys.ConsoleChat/EchoBlock.cs b/src/toys/Coven.Toys.ConsoleChat/EchoBlock.cs
index e1b3766..df6f9f3 100644
--- a/src/toys/Coven.Toys.ConsoleChat/EchoBlock.cs
+++ b/src/toys/Coven.Toys.ConsoleChat/EchoBlock.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Chat;
using Coven.Core;
using Coven.Daemonology;
diff --git a/src/toys/Coven.Toys.ConsoleChat/Program.cs b/src/toys/Coven.Toys.ConsoleChat/Program.cs
index c9f5040..a852e83 100644
--- a/src/toys/Coven.Toys.ConsoleChat/Program.cs
+++ b/src/toys/Coven.Toys.ConsoleChat/Program.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Chat.Console;
using Coven.Core;
using Coven.Core.Builder;
diff --git a/src/toys/Coven.Toys.ConsoleOpenAI/Program.cs b/src/toys/Coven.Toys.ConsoleOpenAI/Program.cs
index e1f7643..669ec08 100644
--- a/src/toys/Coven.Toys.ConsoleOpenAI/Program.cs
+++ b/src/toys/Coven.Toys.ConsoleOpenAI/Program.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Agents.OpenAI;
using Coven.Chat.Console;
using Coven.Core;
diff --git a/src/toys/Coven.Toys.ConsoleOpenAI/RouterBlock.cs b/src/toys/Coven.Toys.ConsoleOpenAI/RouterBlock.cs
index aa8eb1a..515c57b 100644
--- a/src/toys/Coven.Toys.ConsoleOpenAI/RouterBlock.cs
+++ b/src/toys/Coven.Toys.ConsoleOpenAI/RouterBlock.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Agents;
using Coven.Chat;
using Coven.Core;
diff --git a/src/toys/Coven.Toys.ConsoleOpenAIStreaming/Program.cs b/src/toys/Coven.Toys.ConsoleOpenAIStreaming/Program.cs
index 7048acc..1385fe3 100644
--- a/src/toys/Coven.Toys.ConsoleOpenAIStreaming/Program.cs
+++ b/src/toys/Coven.Toys.ConsoleOpenAIStreaming/Program.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Agents;
using Coven.Agents.OpenAI;
using Coven.Chat.Console;
diff --git a/src/toys/Coven.Toys.ConsoleOpenAIStreaming/RouterBlock.cs b/src/toys/Coven.Toys.ConsoleOpenAIStreaming/RouterBlock.cs
index 1e593ff..85bb459 100644
--- a/src/toys/Coven.Toys.ConsoleOpenAIStreaming/RouterBlock.cs
+++ b/src/toys/Coven.Toys.ConsoleOpenAIStreaming/RouterBlock.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Agents;
using Coven.Chat;
using Coven.Core;
diff --git a/src/toys/Coven.Toys.DiscordChat/EchoBlock.cs b/src/toys/Coven.Toys.DiscordChat/EchoBlock.cs
index ebbef1f..719d69f 100644
--- a/src/toys/Coven.Toys.DiscordChat/EchoBlock.cs
+++ b/src/toys/Coven.Toys.DiscordChat/EchoBlock.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Chat;
using Coven.Core;
using Coven.Daemonology;
diff --git a/src/toys/Coven.Toys.DiscordChat/Program.cs b/src/toys/Coven.Toys.DiscordChat/Program.cs
index 2a1f2bd..2db829f 100644
--- a/src/toys/Coven.Toys.DiscordChat/Program.cs
+++ b/src/toys/Coven.Toys.DiscordChat/Program.cs
@@ -1,4 +1,6 @@
-using Coven.Chat.Discord;
+// SPDX-License-Identifier: BUSL-1.1
+
+using Coven.Chat.Discord;
using Coven.Core;
using Coven.Core.Builder;
using Coven.Toys.DiscordChat;
diff --git a/src/toys/Coven.Toys.DiscordStreaming/Program.cs b/src/toys/Coven.Toys.DiscordStreaming/Program.cs
index e86e1bf..f658525 100644
--- a/src/toys/Coven.Toys.DiscordStreaming/Program.cs
+++ b/src/toys/Coven.Toys.DiscordStreaming/Program.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Chat.Discord;
using Coven.Core;
using Coven.Core.Builder;
diff --git a/src/toys/Coven.Toys.DiscordStreaming/StreamingBlock.cs b/src/toys/Coven.Toys.DiscordStreaming/StreamingBlock.cs
index 1c0a7c6..fb5a3d1 100644
--- a/src/toys/Coven.Toys.DiscordStreaming/StreamingBlock.cs
+++ b/src/toys/Coven.Toys.DiscordStreaming/StreamingBlock.cs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: BUSL-1.1
+
using Coven.Chat;
using Coven.Core;
using Coven.Daemonology;