Skip to content
Merged
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
20 changes: 15 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,21 @@ jobs:
global-json-file: global.json
- shell: powershell
run: |
$tokens = $null
$errors = $null
[System.Management.Automation.Language.Parser]::ParseFile("$PWD\scripts\Test-Milestones.ps1", [ref]$tokens, [ref]$errors) | Out-Null
if ($errors) { throw ($errors | Out-String) }
$scriptRoots = @(
"$PWD\scripts",
"$PWD\src\OpenSynapse.PowerShell"
)
foreach ($script in Get-ChildItem $scriptRoots -Recurse -File | Where-Object { $_.Extension -in @('.ps1', '.psm1') }) {
$tokens = $null
$errors = $null
[System.Management.Automation.Language.Parser]::ParseFile($script.FullName, [ref]$tokens, [ref]$errors) | Out-Null
if ($errors) { throw ($errors | Out-String) }
}
& "$PWD\scripts\Test-InstallerDefinitions.ps1"
& "$PWD\scripts\Test-Milestones.ps1"
- run: dotnet restore OpenSynapse.sln
- run: dotnet format OpenSynapse.sln --verify-no-changes --no-restore
- run: dotnet build OpenSynapse.sln --configuration Release --no-restore
- run: dotnet test tests/OpenSynapse.Core.Tests/OpenSynapse.Core.Tests.csproj --configuration Release --no-build
- run: dotnet test OpenSynapse.sln --configuration Release --no-build --no-restore
- shell: powershell
run: .\scripts\Publish-OpenSynapse.ps1
4 changes: 2 additions & 2 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ OpenSynapse controls supported Windows system and Razer device capabilities whil
## Language

**Operating Mode**:
A named set of desired system states. OpenSynapse currently defines Performance and Quiet.
A named set of desired system states. OpenSynapse currently defines Performance, Balanced, and Quiet.
_Avoid_: Profile, preset

**Mode Selection**:
The user's instruction for choosing an Operating Mode. It may name a mode directly or delegate the choice to Auto.
_Avoid_: Mode, profile

**Auto**:
A Mode Selection that resolves to Performance on AC power and Quiet on battery or an unknown source.
A Mode Selection that resolves to Performance only on verified high-power AC and Quiet on low-power, battery, ambiguous, or unknown input.
_Avoid_: Auto mode

**Capability**:
Expand Down
15 changes: 15 additions & 0 deletions OpenSynapse.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSynapse.Core.Tests", "tests\OpenSynapse.Core.Tests\OpenSynapse.Core.Tests.csproj", "{FC81F739-55A3-45D4-8804-525103EE97BB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSynapse.Agent.Tests", "tests\OpenSynapse.Agent.Tests\OpenSynapse.Agent.Tests.csproj", "{4B759D92-1D8F-460A-8D89-A8974BF21A30}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -73,6 +75,18 @@ Global
{FC81F739-55A3-45D4-8804-525103EE97BB}.Release|x64.Build.0 = Release|Any CPU
{FC81F739-55A3-45D4-8804-525103EE97BB}.Release|x86.ActiveCfg = Release|Any CPU
{FC81F739-55A3-45D4-8804-525103EE97BB}.Release|x86.Build.0 = Release|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Debug|x64.ActiveCfg = Debug|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Debug|x64.Build.0 = Debug|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Debug|x86.ActiveCfg = Debug|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Debug|x86.Build.0 = Debug|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Release|Any CPU.Build.0 = Release|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Release|x64.ActiveCfg = Release|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Release|x64.Build.0 = Release|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Release|x86.ActiveCfg = Release|Any CPU
{4B759D92-1D8F-460A-8D89-A8974BF21A30}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -82,5 +96,6 @@ Global
{F946D864-5D2F-4DC8-8701-2C996F9435C7} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{7DA3B07C-2DA5-4088-8BBE-250FE32D703A} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{FC81F739-55A3-45D4-8804-525103EE97BB} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{4B759D92-1D8F-460A-8D89-A8974BF21A30} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
EndGlobalSection
EndGlobal
68 changes: 44 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
OpenSynapse is a local-first, open-source Windows control center for supported Razer hardware and system policies. Its goal is to replace opaque background software with explicit capabilities, inspectable state changes, and reliable rollback.

> [!WARNING]
> OpenSynapse is experimental, distributed as source only, and has no stable release. The current DeathAdder implementation still requires verification on target hardware. Keep Razer Synapse closed while testing device control.
> The power/display runtime is now based directly on the field-tested PowerPilot 2.4.1 implementation. DeathAdder writes remain hardware-gated and still require verification on a connected target device. Keep Razer Synapse closed while testing device control.

## Principles

Expand All @@ -23,9 +23,9 @@ OpenSynapse currently implements the M0–M3 development slice. Implementation d

| Area | Current capability | Maturity |
| --- | --- | --- |
| Windows policies | Auto, Performance, and Quiet selection; power plans; refresh rate; Advanced Color/HDR; internal brightness; display scaling | Implemented, target-Windows validation pending |
| State restoration | Atomic captured state and verified power-plan rollback | Implemented, target-Windows validation pending |
| Desktop control | Non-elevated WPF panel and tray UI connected to a per-user elevated agent | Implemented, target-Windows validation pending |
| Windows policies | Adapter-aware Auto, Hyper, Balance, and Quiet selection; power plans; refresh rate; Advanced Color/HDR; internal brightness; display scaling; optional wake-device control | Live installation validated on the target RZ09-0528 |
| State restoration | Atomic captured state, legacy .NET rollback, PowerPilot takeover, and verified power-plan rollback | Migration validated on the target system |
| Desktop control | Single elevated PowerShell 5.1/WinForms tray process, installed as a delayed highest-privilege per-user task | Installed and live-validated |
| Razer mouse | Discovery, status, DPI, and standard-receiver polling control | Experimental |

### Device matrix
Expand All @@ -41,57 +41,77 @@ OpenSynapse currently implements the M0–M3 development slice. Implementation d

## Architecture

OpenSynapse separates the ordinary desktop UI from privileged Windows operations:
The release runtime intentionally follows PowerPilot 2.4.1's proven single-process model:

```text
OpenSynapse.App ── current-user named pipe ──> OpenSynapse.Agent
│ │
└──────── shared request models ──────────────┤
├─ Windows policy APIs / powercfg
└─ capability-gated Razer HID
OpenSynapse scheduled task (highest privileges, STA)
└─ OpenSynapse.ps1 (WinForms UI, tray, automation)
└─ dynamically compiled OpenSynapse.Native.cs
├─ display, battery and GPU telemetry
├─ Windows policy APIs / powercfg
└─ capability-gated DeathAdder HID reports
```

The agent owns mode selection, captured state, rollback, and hardware writes. The UI never writes privileged system or HID state directly. See [Architecture](docs/ARCHITECTURE.md) and the shared [domain language](CONTEXT.md).
This removes the WPF-to-Agent startup and named-pipe failure mode that made the previous migration appear online while its control backend was unavailable. See [Architecture](docs/ARCHITECTURE.md).

## Build and test

Requirements:

- Windows 11
- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0), matching [`global.json`](global.json)
- An elevated PowerShell terminal only for system-policy and hardware smoke tests
- Windows PowerShell 5.1
- Administrator approval for installation and policy changes

```powershell
dotnet restore OpenSynapse.sln
dotnet build OpenSynapse.sln --no-restore
dotnet test tests/OpenSynapse.Core.Tests/OpenSynapse.Core.Tests.csproj --no-build
powershell -ExecutionPolicy Bypass -File scripts\Test-InstallerDefinitions.ps1
powershell -ExecutionPolicy Bypass -File scripts\Test-Milestones.ps1
```

Start the elevated agent, then launch the UI from a normal terminal:
The retained .NET solution contains protocol/unit-test code from the previous implementation and can still be tested separately, but it is no longer the published desktop runtime.

### Publish and install

Create the renamed PowerPilot-compatible package, then install it:

```powershell
dotnet run --project src/OpenSynapse.Agent -- serve
dotnet run --project src/OpenSynapse.App
powershell -ExecutionPolicy Bypass -File scripts\Publish-OpenSynapse.ps1
powershell -ExecutionPolicy Bypass -File scripts\Install-OpenSynapse.ps1
```

On a disposable or fully understood Windows configuration, run the reversible elevated smoke test:
The package is written to `artifacts\publish\OpenSynapse` and `artifacts\OpenSynapse-2.4.2.zip`. The installer first asks the obsolete .NET Agent to restore its captured state when that binary is available; otherwise it restores the legacy power, display, brightness and wake state directly. If an installed PowerPilot runtime exists, its configuration and recovery state are archived, its own verified uninstaller restores Windows, and that configuration is promoted to OpenSynapse. The installer then removes the obsolete split runtime, copies the PowerShell implementation under `%ProgramFiles%\OpenSynapse`, registers one delayed highest-privilege per-user task, and creates an OpenSynapse Start menu shortcut. To uninstall and restore the captured state:

```powershell
powershell -ExecutionPolicy Bypass -File scripts\Test-Milestones.ps1
powershell -ExecutionPolicy Bypass -File scripts\Uninstall-OpenSynapse.ps1
```

On a disposable or fully understood Windows configuration, run the full reversible administrator suite:

```powershell
powershell -ExecutionPolicy Bypass -File scripts\Test-Milestones.ps1 -AdminRelease

# Optional: re-write the mouse's currently reported values to verify HID transport.
powershell -ExecutionPolicy Bypass -File scripts\Test-Milestones.ps1 -TestMouseWrites
```

The script verifies Performance/Quiet application, named-pipe lifecycle, agent shutdown, power-plan rollback, and captured-state cleanup. The mouse option requires a readable DeathAdder V3 Pro and does not intentionally select new values.
The mouse option requires a readable DeathAdder V3 Pro and writes its currently reported values back without intentionally choosing new settings.

## Configuration

The tray runtime stores policy in `%LOCALAPPDATA%\OpenSynapse\config.json` and rollback state in `state.json`. It retains PowerPilot 2.4.1's Smart Auto, application rules, supply debounce, display policy, battery telemetry, health backoff, and reversible state model.

The PowerPilot-compatible defaults enable Quiet maintenance. Wake devices are matched by configured name fragments (initially MediaTek Wi-Fi, HID-compliant mouse, and USB4); tracked permissions are restored when leaving Quiet, exiting, or uninstalling. Quiet may also close configured high-drain helper processes and pause configured Armoury Crate/ASUS services. Review these lists in `config.json` if those applications or devices must remain active.

## Safety and privacy

- Razer writes require an exact supported VID/PID and Consumer HID usage page.
- DPI and polling inputs are validated before packet construction.
- Responses must match the request transaction, command class, command ID, and checksum.
- Privileged IPC is restricted to the current Windows user.
- Captured system state is stored atomically under `%LOCALAPPDATA%\OpenSynapse`.
- The installed runtime runs as a single per-user highest-privilege scheduled task; no named-pipe IPC is required.
- Configuration and captured system state are stored separately and atomically under `%LOCALAPPDATA%\OpenSynapse`.
- Quiet wake-device and service changes retain rollback state; configured process termination is limited to the local allowlists inherited from PowerPilot.
- Runtime events are written locally to bounded `OpenSynapse.log` and `telemetry.jsonl` files.
- Adapter classification invokes `nvidia-smi` with a read-only query and fails safe to Quiet when the power limit cannot be verified.
- The current implementation contains no telemetry, analytics, updater, account system, or runtime network client.

Please report security issues through the private process in [SECURITY.md](SECURITY.md), not a public issue.
Expand Down
Loading
Loading