Repository navigation
batch: teach scope, run authorizations, redaction, merge queue, main dedupe, Desktop program map, tray fold - #1421
Merged
Merged
Conversation
This commit implements the openadapt-tray system tray application for OpenAdapt, based on the design document at docs/design/openadapt-tray.md. Features: - Cross-platform system tray icon using pystray (lightweight alternative to Qt) - Start/Stop recording menu items that delegate to openadapt CLI - Global hotkeys (Ctrl+Shift+R for recording, Ctrl+Shift+D for dashboard) - Triple-ctrl stop sequence for legacy compatibility - State machine for application state management - Platform-specific handlers for macOS, Windows, and Linux - Native dialogs using AppleScript (macOS), ctypes (Windows), and zenity/kdialog (Linux) - Notification support across all platforms - Configuration persistence in platform-appropriate locations - IPC client for communication with other OpenAdapt processes - Placeholder icons (colored circles) for different states Package structure: - src/openadapt_tray/ - Main package code - app.py - Main TrayApplication class - menu.py - Menu construction - icons.py - Icon management - notifications.py - Cross-platform notifications - shortcuts.py - Global hotkey handling - config.py - Configuration management - ipc.py - Inter-process communication - state.py - Application state machine - platform/ - Platform-specific handlers - assets/icons/ - State icons (idle, recording, training, error) - tests/ - Test suite (78 passing tests) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add standard badges for license and Python version. PyPI badges are commented out until the package is published. Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: add README badges for license and Python version Add standard badges for license and Python version. PyPI badges are commented out until the package is published. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * feat: implement desktop-notifier notification system Implement modern, native notification system using desktop-notifier library based on comprehensive review in task a95f1e8. Replaces legacy AppleScript/ PowerShell implementations with cross-platform solution. Key features: - Native notifications on macOS (Notification Center), Windows (WinRT), and Linux (DBus) - Click callbacks for notification interactions - Urgency levels (low, normal, critical) - Action buttons (platform-dependent) - Reply fields (macOS only) - Custom icons and duration control - Async and sync APIs - Graceful fallback to platform-specific implementations - Full backward compatibility with existing API Changes: - Completely rewrote src/openadapt_tray/notifications.py (390 lines) - Added desktop-notifier backend with event loop management - Maintained fallback to AppleScript/PowerShell/notify-send - Implemented sync wrapper around async desktop-notifier API - Added resource cleanup on app shutdown - Updated src/openadapt_tray/app.py - Added notifications.cleanup() call in quit() method - Updated pyproject.toml - Added desktop-notifier>=6.2.0 dependency - Updated README.md - Added native notifications to features list - Added desktop-notifier to dependencies Documentation: - Added NOTIFICATIONS.md: Comprehensive notification system guide (9.4 KB) - Usage examples for all features - Architecture and backend detection - Platform-specific notes and troubleshooting - Complete API reference - Migration guide - Added examples/notification_examples.py: 10 comprehensive examples - Basic notifications - Callbacks and urgency levels - Action buttons and reply fields - Conditional and state-based notifications - Added test scripts: - test_notification_simple.py: Quick non-interactive test - test_notification.py: Interactive test with user interaction - examples/README.md: Example documentation - Added IMPLEMENTATION_SUMMARY.md: Complete implementation documentation Testing: - Verified backend detection and fallback mechanisms - Tested basic, critical, and callback notifications - Confirmed backward compatibility with existing API - Manual testing available via test_notification_simple.py Benefits: - Modern native notification experience - Better platform integration - Rich interactive features - Clean, maintainable API - No breaking changes Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: detect app bundle on macOS and fall back to AppleScript Fixes critical bug where desktop-notifier fails with "'NoneType' object is not iterable" when not running from an app bundle on macOS. Changes: - Add app bundle detection in _detect_backend() method - Check both APP_BUNDLE env var and bundle path structure - Automatically fall back to AppleScript if not in app bundle - Add os import for environment variable checking - Fix README.md desktop-notifier version (6.0.0 -> 6.2.0) The AppleScript fallback works perfectly for non-bundled execution (e.g., development, CLI usage) while desktop-notifier can still be used when running from a proper macOS app bundle. Tested: All notifications now work correctly via AppleScript fallback. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: Improve notification backend detection and make IPC optional Fixes two critical startup issues: 1. Notification Center app bundle requirement: - Try to initialize desktop-notifier even outside app bundle - Gracefully fall back to AppleScript if initialization fails - Provides better error messages for debugging 2. IPC connection blocking startup: - Wrap IPC connection in try-except to prevent startup failures - Add informative messages for connection status - App now runs in standalone mode if IPC server unavailable These changes make the tray app more resilient and provide better user experience when running outside of a full app bundle or when the OpenAdapt backend is not running. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * feat: Add automated screenshot capture workflow Simplifies screenshot capture and organization workflow with two new files: 1. rename_screenshots.py: - Automatically finds recent screenshots from Desktop - Interactive renaming with confirmation - Moves to docs/screenshots/ with standardized names - Backs up existing files to prevent data loss - Supports both "Screen Shot" and "Screenshot" formats (macOS variations) - Shows timestamps to help verify correct screenshot order 2. SCREENSHOT_SIMPLE.md: - Step-by-step guide for simplified screenshot workflow - Takes 10-15 minutes total - Just take screenshots with Cmd+Shift+4, run script, commit - No manual renaming needed - Includes troubleshooting section - Covers required and optional screenshots User workflow: 1. Take 5-8 screenshots with Cmd+Shift+4 2. Run: python rename_screenshots.py 3. Commit: git add docs/screenshots && git commit This makes documentation screenshots much easier to capture and organize, reducing manual work from 30+ minutes to 10-15 minutes. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- publish.yml: Triggered on tags, publishes to PyPI - release.yml: Auto-bumps version on PR merge, creates tags Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaces manual commit parsing with python-semantic-release: - Automatic version bumping based on conventional commits - feat: -> minor, fix:/perf: -> patch - Creates GitHub releases automatically - Publishes to PyPI on release Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The python-semantic-release action runs in a Docker container where uv is not available. Let the workflow handle building instead. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace `branch = "main"` (v7/v8 key) with `[tool.semantic_release.branches.main]` table (v9 key). The old key is silently ignored by v9, causing releases to never trigger on the main branch. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Reposition the Experimental tray around record, compile, replay, and governed hosted repair, with protected-main and pre-1.0 release safeguards.
Replace the undefined release lock variable with an offline exact-root synchronizer and preserve v0.1.0 as the failed-attempt audit record.
Supersedes the original whole-file rewrite: main's README (from #5) already covers the loop status/launcher role, so this PR now only fixes the claims that went stale when the hosted lifecycle merged and 0.1.1 shipped to PyPI: - hosted behavior is on main and released, not 'feat/hosted-rewire branch code' - version is 0.1.1 (pre-alpha classifier), not 0.0.1 - add the PyPI badge and a real pip install quickstart - keep the honest boundary: no released openadapt-desktop build provides the companion IPC service yet Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Match the AGENTS.md / org-profile / LIMITS.md canonical one-liner
('retained evidence'); the tray README said 'recorded evidence'.
Claude-Session: https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ot) (#9) Adds CodeQL SAST, gitleaks secret scanning, dependency review, Dependabot, and a vulnerability-disclosure policy as part of SOC 2 readiness. Additive and non-breaking. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Replace the plain solid colored circle with the OpenAdapt brand mark (the chat/robot face from the openadapt.ai favicon), color-stylized per recording-lifecycle state so the state stays readable at a glance while the brand is finally shown in the menu bar / system tray. - Add the vector mark (assets/mark.svg) and a high-res transparent raster master (assets/mark-master.png), plus a 512px copy packaged inside the wheel (src/openadapt_tray/assets/mark-master.png) so the installed app can render the mark. The wheel previously shipped no assets, so it always fell back to a generated circle. - IconManager now tints the mark's alpha silhouette per state (idle=brand blue, recording=red, starting/stopping=amber, compiling=purple, error=red). One tint implementation is shared by the runtime and the generator, so committed PNGs and runtime icons never diverge. The needs-attention badge is preserved. - Give every TrayState its own icon file. This fixes a latent bug where COMPILING referenced a nonexistent compiling.png (fell back to a circle) and starting/stopping showed red instead of amber. - Rewrite scripts/generate_icons.py to re-render the master from the SVG (rsvg-convert/cairosvg/inkscape) and tint per-state 1x + @2x PNGs and a multi-size logo.ico. Remove the stale training.png icons. Icons verified valid at menu-bar sizes (22px + 44px, light and dark); 137 tests pass, ruff clean. Claude-Session: https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#10) Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 4.9.0 to 5.0.0. - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](actions/dependency-review-action@2031cfc...a1d282b) --- updated-dependencies: - dependency-name: actions/dependency-review-action dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [python-semantic-release/publish-action](https://github.com/python-semantic-release/publish-action) from 9.15.2 to 10.6.1. - [Release notes](https://github.com/python-semantic-release/publish-action/releases) - [Changelog](https://github.com/python-semantic-release/publish-action/blob/main/releaserc.toml) - [Commits](python-semantic-release/publish-action@b9c41d4...5a5718c) --- updated-dependencies: - dependency-name: python-semantic-release/publish-action dependency-version: 10.6.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](actions/checkout@9c091bb...3d3c42e) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.3.0 to 7.0.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](actions/setup-python@ece7cb0...5fda3b9) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [python-semantic-release/python-semantic-release](https://github.com/python-semantic-release/python-semantic-release) from 9.15.2 to 10.6.1. - [Release notes](https://github.com/python-semantic-release/python-semantic-release/releases) - [Changelog](https://github.com/python-semantic-release/python-semantic-release/blob/master/CHANGELOG.rst) - [Commits](python-semantic-release/python-semantic-release@7b3f716...39dd205) --- updated-dependencies: - dependency-name: python-semantic-release/python-semantic-release dependency-version: 10.6.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ntract (#18) Rewrite the README around the shared OpenAdapt positioning (governed demonstration compiler; substrates first-class with an honest maturity ladder; local-first; MIT open-core) and describe what the tray actually does: start/stop recording, recent captures, needs-attention count and routing, open desktop app or cloud dashboard, sync channel, login, and settings. Document the per-state OpenAdapt-mark icon (one mark tinted per recording/compile lifecycle state) and how the tray fits with openadapt-desktop and the cloud. Update the stale cross-repo claim: the openadapt-desktop main branch now serves the exact discovery-socket and command contract this tray expects, so the README no longer says no build implements it. It still states plainly that the two surfaces have not been validated together end to end and that no signed desktop build ships the server yet. Update the metadata test to assert that honest boundary instead of the retired string. Cross-link docs.openadapt.ai. No em dashes. Claude-Session: https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* chore(deps-dev): bump uv from 0.11.26 to 0.11.29 Bumps [uv](https://github.com/astral-sh/uv) from 0.11.26 to 0.11.29. - [Release notes](https://github.com/astral-sh/uv/releases) - [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md) - [Commits](astral-sh/uv@0.11.26...0.11.29) --- updated-dependencies: - dependency-name: uv dependency-version: 0.11.29 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * chore(deps-dev): synchronize uv 0.11.29 lock --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: abrichr <richard.abrich@mldsai.com>
…er (#26) Bumping only one of init/analyze leaves the pair at mismatched versions, which CodeQL rejects with a configuration error. Bump both in one commit and group future codeql-action updates so Dependabot cannot split them again. Claude-Session: https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 8.3.2 to 9.0.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](astral-sh/setup-uv@11f9893...c771a70) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 9.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
) Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.14.0 to 1.14.1. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](pypa/gh-action-pypi-publish@cef2210...ba38be9) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-version: 1.14.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
# Conflicts: # .github/workflows/packages.yml # CLAUDE.md # llms-full.txt
# Conflicts: # llms-full.txt
HIGH - The statement names its signer (signer_fingerprint); a signature by any other key is auth_signer_mismatch. The stored GitHub copy no longer vouches for identity: identity_verified only with --live (github.com, HTTPS, no redirects, no proxy) or caller-pinned --allowed-signers; otherwise 'identity not verified (self-asserted github:<u>)'. The operator profile links only verified identities; profile gets --live. MEDIUM - before_run only when auth log time < started_at <= Seal log time, both anchored; otherwise after_run or not_anchored. - authorize sign signs a private 0600 copy of exactly the shown bytes, passes -- to ssh-keygen, and writes the .sig only if the file is unchanged. - The profile counts a Seal or Rekor entry once (excluded.duplicate). LOW - Summary strips control characters and ANSI; an unbound QUALIFICATION.md is marked 'not covered by its digest'. - sign exits non-zero when the new signature doesn't verify. - The authorization's anchor must be by a Seal key in scope. - scope.reusable (default false): one run per item; verify over several runs and the profile reject reuse (auth_item_reused). - report.json is read with the duplicate-key-rejecting loader everywhere. - Items and scope_item are short labels (a lower-case prefix and a number). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…els, reuse scope - The operator profile counts a report once: the same Seal, Rekor entry, or report re-sealed with a new issued_at and anchored again (by subject_sha256), keeping the Seal the log recorded first. - Items and scope_item are one or two lower-case letters and up to three digits (r3); mrn12345-style labels are refused. A Seal's item must be one the statement lists. - Docs: reuse is seen only among Seals verified together. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
flow: compile named sections for every program; the program map and Desktop fold them
Conflict: packages/desktop/src/lib/engine.ts, where this branch's EDIT_PROGRAM_SECTIONS (from #1405) and main's GET_CHECK_SETUP / ANSWER_CHECK_SETUP were added at the same place; both are kept. llms-full.txt regenerated with scripts/build_llms_full.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One CI run instead of eight. Every PR folded in here was reviewed separately; their own threads have the reviews.
Conflicts resolved here:
offline_seal.seal_runandlocal-seal runkeep both flow: run authorizations signed with a GitHub SSH key, and operator profiles #1401's authorization andreplace_unanchored, and flow: redact session tokens from run reports before they are sealed #1407'sallow_unredacted.seal_authorizedpassesallow_unredactedthrough, which is the same resolution the redaction session tested.packages.ymlscope keepsprogram-graphin the Desktop filter and adds build(monorepo): fold openadapt-tray into packages/tray (with history) #1356'strayoutput.Local checks: 244 sealing, authorization, redaction, hint and deferred-report tests; 35 workflow tests; ruff; gitleaks on the new commits; prospect-name check. Merging this closes the eight PRs.
🤖 Generated with Claude Code