Skip to content
Closed
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
88 changes: 88 additions & 0 deletions .github/CI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# CI — Win-CodexBar

Win-CodexBar runs one hosted workflow: the **PR check** on Blacksmith Windows.
Release stays **local**. See `CONTEXT.md` for the shared CI budget glossary
and `docs/adr/0001` and `docs/adr/0002` for the decisions.

## Workflows

### PR check — `.github/workflows/pr-check.yml`

Runs on `pull_request`, on `push` to `main`/`master`, and on
`workflow_dispatch`. Runner: `blacksmith-4vcpu-windows-2025`
(Windows Server 2025; VS Build Tools available per Blacksmith docs).

Exact commands run, in order:

```powershell
cargo fmt --all --check
cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
cargo clippy --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml --all-targets -- -D warnings
cargo test --manifest-path rust/Cargo.toml
cargo test --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml
pnpm --dir apps/desktop-tauri test
pnpm --dir apps/desktop-tauri run build
```

This is the **local-check slice** from `scripts/local-check.ps1` only. It does
**not** run `tauri:build` release, installer packaging, smoke install, or
upload. Those stay on the local release path.

`concurrency.cancel-in-progress` is on, keyed by ref, so superseded pushes
cancel the in-flight run.

### Interaction guard — `.github/workflows/interaction-guard.yml`

Unchanged except for the budget gate (below). Runner stays
`blacksmith-2vcpu-ubuntu-2404`. Permissions are unchanged
(`contents: read`, `issues: write`, `pull-requests: write`).

## CI budget mode

Both workflows carry the gate `if: vars.CI_BUDGET_MODE != 'off'`, so they run
when the variable is unset (`normal`), `normal`, or `thin`, and **skip only
when `off`**.

Set `CI_BUDGET_MODE` in **Settings → Secrets and variables → Actions →
Variables**. Do not hard-code it in a workflow.

| Mode | PR check | Interaction guard | Release |
|--------|----------|--------------------|---------|
| normal | runs | runs | local |
| thin | runs | runs | local |
| off | skip | skip | local |

## Intent share (60/30/10)

The Blacksmith Pool minutes intent is divided: roughly **60% Win-CodexBar**,
**30% linear-cli**, **10% buffer**. This is an intent allocation of the
pool's minutes, not a measure of time spent in `normal`/`thin`/`off` modes.
Win-CodexBar's single Blacksmith Windows PR check is the only recurring
Windows job. If you add a second recurring job, reassess the 60% share before
merging.

## Blacksmith billing — Windows bills 2x

On the Blacksmith **free tier**, **Windows minutes bill at 2x**: one Windows
minute consumes two free-tier minutes. `blacksmith-4vcpu-windows-2025` is
Windows Server 2025. Because the PR check is a thin slice (fmt + clippy +
test) and never runs release builds, this is the only recurring Windows
cost. Keep it that way.

## $0 spend alert

Treat any non-zero monthly Blacksmith bill as an alert. If spend appears:

1. Set `CI_BUDGET_MODE=off` to stop both workflows immediately.
2. Investigate which run(s) consumed minutes (Actions tab → billed runs).
3. Trim or fix, then restore `CI_BUDGET_MODE=normal` (or `thin`).

The default posture is **$0 spend**. The PR check should stay within free-tier
minutes; if it does not, prefer reducing the check slice before paying.

## Release

Release is **local only**. There is no hosted release workflow. Follow
`docs/BUILDING.md` and `docs/release/ci-cd.md`: tag, run release-doctor, run
`windows-release-build.ps1 -SmokeInstall`, then upload assets to GitHub
Releases manually.
1 change: 1 addition & 0 deletions .github/workflows/interaction-guard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ permissions:

jobs:
guard:
if: vars.CI_BUDGET_MODE != 'off'
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
Expand Down
82 changes: 82 additions & 0 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: PR check

on:
push:
branches: [main, master]
paths-ignore:
- 'docs/**'
- '**/*.md'
- 'CONTEXT.md'
- '.github/CI.md'
pull_request:
paths-ignore:
- 'docs/**'
- '**/*.md'
- 'CONTEXT.md'
- '.github/CI.md'
workflow_dispatch:

concurrency:
group: pr-check-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

jobs:
pr-check:
name: Local check
if: vars.CI_BUDGET_MODE != 'off'
runs-on: blacksmith-4vcpu-windows-2025

steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-pc-windows-msvc
components: rustfmt, clippy

- name: Cache cargo
uses: Swatinem/rust-cache@v2
with:
workspaces: |
rust
apps/desktop-tauri/src-tauri

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
cache-dependency-path: apps/desktop-tauri/pnpm-lock.yaml

- name: Install frontend deps
run: pnpm --dir apps/desktop-tauri install --frozen-lockfile

- name: Rust format check
run: cargo fmt --all --check

- name: Shared Rust clippy
run: cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings

- name: Tauri Rust clippy
run: cargo clippy --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml --all-targets -- -D warnings

- name: Shared Rust tests
run: cargo test --manifest-path rust/Cargo.toml

- name: Tauri Rust tests
run: cargo test --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml

- name: Frontend tests
run: pnpm --dir apps/desktop-tauri test

- name: Frontend type check / build
run: pnpm --dir apps/desktop-tauri run build
69 changes: 69 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Shared CI Budget glossary

This glossary is shared with the sister repo (`linear-cli`) so operators can
reason about CI spend across both projects with one vocabulary.

## Blacksmith Pool

The shared Blacksmith free-tier minute pool that both Win-CodexBar and the
sister repo (`linear-cli`) draw from. All `blacksmith-*` runners bill against
this one pool. The intent-share (60%) and $0 spend alert are defined against
the combined draw on this pool, not per repo.

## CI budget mode

A repository variable `CI_BUDGET_MODE` controls how much CI runs per change.
It is intentionally coarse: `normal`, `thin`, or `off`.

| Mode | PR check | Interaction guard | Release |
|--------|----------|--------------------|----------------------------------|
| normal | runs | runs | local (Win-CodexBar only) |
| thin | runs | runs | local (Win-CodexBar only) |
| off | **skip** | **skip** | local (Win-CodexBar only) |

> Note: Win-CodexBar's Release is **always local** (no release workflow on
> Blacksmith). The sister repo `linear-cli` has a Blacksmith dispatch-only
> release workflow, so its Release column differs by design. Budget mode does
> not gate Win-CodexBar's local release — it is operator-driven regardless of
> mode.

- `normal` — default. Unset is treated as `normal`.
- `thin` — Win-CodexBar's PR check survives `thin`: it is the single Windows
Blacksmith job and stays within the 60% intent share, so it still runs. The
sister repo (`linear-cli`) skips its PR check entirely under `thin`
(`if: mode != 'off' && mode != 'thin'`); its default PR check is already a
single Linux-only job, so there is no matrix to trim — `thin` simply drops
the whole job.
- `off` — emergency stop. Both the PR check and the interaction guard skip.
Use this when the bill approaches the `$0 spend` alert threshold or when a
runaway workflow is burning minutes.

Set it in **Settings → Secrets and variables → Actions → Variables**, not in
code. The workflows read it as `vars.CI_BUDGET_MODE`.

## Intent share (60/30/10)

The Blacksmith Pool minutes intent is divided: roughly **60% Win-CodexBar**,
**30% linear-cli**, and **10% buffer**. This is an intent allocation of the
pool's minutes, not a measure of time spent in `normal`/`thin`/`off` modes.
Win-CodexBar's single Blacksmith Windows PR check is the only recurring
Windows job; release builds stay local. If you add a second recurring job
here, reassess the 60% share before merging.

## Blacksmith billing note

On the Blacksmith free tier, **Windows minutes bill at 2x** (one Windows
minute consumes two free-tier minutes). `blacksmith-4vcpu-windows-2025` is a
Windows Server 2025 runner with VS Build Tools available, so Rust + Tauri
builds work without extra setup. The PR check is a thin slice (fmt + clippy +
test) and never runs `tauri:build` release, installer packaging, smoke
install, or upload.

## Local check slice

The PR check mirrors `scripts/local-check.ps1`'s default slice only:
`cargo fmt --check`, `cargo clippy -D warnings` on both crates, `cargo test`
on both crates, and the frontend `pnpm test` / `tsc --noEmit` (via
`pnpm run build`). It deliberately excludes `tauri:build` release, the
installer, smoke install, and release upload — those stay on the local
Windows release path.
7 changes: 4 additions & 3 deletions docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ Useful release flags:
.\scripts\release-doctor.ps1 -Version 0.27.5
```

There is no hosted CI/CD for this repository right now. Run local checks before
PRs; the Windows release script is the primary path for installer and portable
artifacts.
A hosted **PR check** runs on Blacksmith Windows for pull requests and pushes
to `main`/`master`; see `.github/CI.md` for its scope and budget modes. The
Windows release script remains the primary path for installer and portable
artifacts; there is no hosted release workflow.

## macOS Windows Cross Build

Expand Down
36 changes: 36 additions & 0 deletions docs/adr/0001-pr-check-blacksmith-local-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# ADR 0001: PR check on Blacksmith Windows, release stays local

Date: 2026-07-24
Status: Accepted

## Context

Win-CodexBar had no hosted CI. Contributors ran `scripts/local-check.ps1`
before PRs, and the canonical release path was `scripts/windows-release-build.ps1`
on a local Windows server. We want hosted feedback on PRs without paying for
release-grade CI.

## Decision

Add a single PR check workflow (`.github/workflows/pr-check.yml`) that runs on
**Blacksmith Windows** (`blacksmith-4vcpu-windows-2025`). It mirrors only the
local-check slice:

- `cargo fmt --all --check` (workspace)
- `cargo clippy --all-targets -- -D warnings` on both `rust` and
`apps/desktop-tauri/src-tauri`
- `cargo test` on both crates
- `pnpm test` and `pnpm run build` (which runs `tsc --noEmit`) in
`apps/desktop-tauri`

Release stays **LOCAL**: no release workflow on Blacksmith. `tauri:build`
release, installer packaging, smoke install, and upload to GitHub Releases
continue to use `scripts/windows-release-build.ps1` on the operator's Windows
server, exactly as documented in `docs/BUILDING.md`.

## Consequences

- PRs get hosted fmt/clippy/test feedback on the real Windows target.
- No release CI spend. Release remains a deliberate, operator-driven step.
- The Blacksmith Windows runner has VS Build Tools available, so the Rust +
Tauri toolchain works without extra provisioning.
33 changes: 33 additions & 0 deletions docs/adr/0002-ci-budget-modes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# ADR 0002: CI budget modes

Date: 2026-07-24
Status: Accepted

## Context

Win-CodexBar and its sister repo (`linear-cli`) share Blacksmith CI minute
budget. We need a single, coarse control to keep spend within the 60%
intent share and to stop runaway spend fast. Per-workflow toggles are too
fine-grained for an emergency stop.

## Decision

Introduce a repository variable `CI_BUDGET_MODE` with three modes:
`normal`, `thin`, and `off`. Unset is treated as `normal`.

- **PR check** (`pr-check.yml`): runs when mode is unset, `normal`, or `thin`;
skips only when `off`.
Gate: `if: vars.CI_BUDGET_MODE != 'off'`
- **Interaction guard** (`interaction-guard.yml`): same gate. Keeps its
existing `blacksmith-2vcpu-ubuntu-2404` runner.
- **Release**: unaffected — release stays local regardless of mode.

`thin` is a no-op for Win-CodexBar's PR check because it is already a single
job (no cross-OS matrix to trim). The mode exists for parity with the sister
repo and as a future dial if a second job is added.

## Consequences

- One variable controls both workflows; `off` is an immediate, full stop.
- Operators set `CI_BUDGET_MODE` in repo Settings → Variables, not in code.
- The glossary in `CONTEXT.md` is the shared definition across both repos.
Loading