pywin32==312 ; sys_platform == "win32"  # >=311 required by mcp 2.x (see the claude-agent-sdk note below)
psutil==7.2.2
email-validator==2.3.0
cryptography==50.0.1
# Pillow is a DIRECT dependency: screenshot_capture + owlette_service compress
# captures to JPEG with it. It used to arrive transitively through pystray, which
# 3.0.0 dropped along with the rest of the python UI (customtkinter, CTkListbox,
# CTkMessagebox, CTkToolTip) when the Tauri desktop app replaced it — so it has
# to be pinned here or the screenshot path breaks on the next clean build.
Pillow==13.0.0
packaging==26.3  # >=24.0 required by the wheel that get-pip bootstraps
setuptools==84.1.0  # >=78.1.1 fixes PackageIndex.download path traversal (CVE-2025-47273); >=84.1.0 the namespace_packages.txt path escape (GHSA-xmj3-9gf7-h52w)
requests==2.34.2  # >=2.32.0/.4/2.33.0 CVE fixes; 2.34.0 also fixes greedy no_proxy matching
tzlocal==5.4.4  # Convert Windows registry tz names to IANA (e.g. "Pacific Standard Time" -> "America/Los_Angeles") for dashboard timezone display
# DIRECT dependency (R5). Windows ships no IANA database, so zoneinfo.ZoneInfo
# can only resolve "America/Los_Angeles" out of this package. It arrived
# transitively through tzlocal's Windows marker — a coincidence, not a contract:
# the day that changes, shared_utils.is_within_schedule stops raising and starts
# SILENTLY evaluating every site-time schedule against the machine's local clock
# (the `except ... falling back to local time` branch), which is a wrong-hours
# bug with no error to chase. Pinned directly so it can never be dropped.
tzdata==2026.4

# Screenshot capture
mss==9.0.2  # Fast cross-platform screenshot library

# Temperature monitoring
# HardwareMonitor wraps LibreHardwareMonitorLib 0.9.6, which uses the signed
# PawnIO driver the installer deploys — replaced WinTmp, whose bundled LHM
# still extracted the blocklisted WinRing0 driver at runtime (python.sys).
HardwareMonitor==1.2.1 ; sys_platform == "win32"
pythonnet==3.2.0 ; sys_platform == "win32"  # HardwareMonitor's CLR bridge (was transitive via WinTmp) — pinned like everything else
wmi==1.5.1 ; sys_platform == "win32"  # DIRECT dependency (hardware_profile + shared_utils disk/BIOS probes); used to arrive transitively through WinTmp
nvidia-ml-py==13.615.71  # NVML bindings — the GPU load/VRAM/temperature source (shared_utils, mcp_tools)

# swoop doorbell — the one persistent WebSocket the agent holds to the signalling
# room (swoop_doorbell.py). Approved in plan.md, "Approved new dependencies".
# Reason for the pin: the agent is a threaded Windows service with no asyncio
# loop, and this is the maintained pure-python client that drives protocol PING
# frames from run_forever() on a plain daemon thread — the asyncio clients would
# drag an event loop into the service for one socket. Pinned exactly like every
# other line here, because this ships to the fleet.
# Exit condition: unpin when the agent gains an event loop of its own, or when
# the pin blocks a security fix, or when the protocol needs per-frame control
# this client does not expose.
websocket-client==1.9.2

# hoot (cortex on the wire) — the local Claude Code agent behind hoot turns.
# Unblocked 2026-09-12: pywin32 306 -> 312 lifts the freeze this pin sat under
# for 83 minor versions. The old chain was pywin32==306 -> mcp capped at 1.10.1
# (the last release with no pywin32 dependency) -> claude-agent-sdk capped at
# 0.1.69, since 0.1.70 needs mcp>=1.19.0.
#
# The previous comment said pywin32 310 was sufficient and not to go higher.
# That was true only while 0.2.132 capped mcp<2.0.0. 0.2.152 declares
# mcp<3.0.0,>=1.23.0, so mcp 2.x is in range and mcp 2.0.0+ needs pywin32>=311.
#
# mcp is pinned explicitly even though it arrives transitively: under a range,
# pip silently backtracks to whatever the pywin32 pin allows and exits 0, which
# is exactly how this went unnoticed. The pin makes a regression visible.
#
# The SDK vendors the Claude CLI (_bundled/claude.exe), but installer size is
# unaffected: build_installer_full.bat deletes it behind a verify-and-fail guard
# and agents fetch their own sha256-pinned copy (see cortex_cli_fetch.py).
# Bumping this MOVES THAT PIN: 0.1.69 carried CLI 2.1.121, 0.2.159 carries
# 2.1.281 — re-run scripts/upload-cortex-cli.mjs for dev AND prod after this
# lands, or hoot keeps fetching the old CLI.
# Only pin a release that ships a win_amd64 wheel: 0.2.157 and 0.2.160-0.2.163
# ship none, and pip then builds the sdist, which has no CLI, and exits 0.
claude-agent-sdk==0.2.159
mcp==2.2.0

# Error monitoring (optional — only active when DSN configured in config.json)
sentry-sdk==2.71.0

# Firebase integration - now using REST API with OAuth tokens (no Admin SDK needed)
# firebase-admin==6.4.0  # REMOVED - replaced with REST API client
# google-cloud-firestore==2.14.0  # REMOVED - replaced with REST API client
# google-auth==2.22.0  # REMOVED - leftover from the Admin SDK; no agent code imports google.*
# google-api-python-client==2.98.0  # REMOVED - same
# google-auth-oauthlib==1.0.0  # REMOVED - same. Dropping the three removed 17
#   packages and, because google-auth 2.22.0 was the only thing pinning
#   urllib3<2.0, unpinned the HTTP transport from the EOL 1.26.20 to 2.x.