This session is being continued from a previous conversation that ran out of context. The conversation is summarized below:
Analysis:
Let me analyze the conversation chronologically:

1. **Session Start Context**: This was a continuation from a previous session about GuruConnect security hardening. The summary indicated REST API endpoints were secured, and WebSocket security was in progress.

2. **User Message 1**: (implicit continuation) - Continue with WebSocket security
   - I read relay/mod.rs and auth/mod.rs
   - Added token parameter to ViewerParams
   - Added api_key parameter to AgentParams
   - Updated viewer_ws_handler to require JWT token
   - Updated agent_ws_handler to require support_code OR api_key
   - Added validate_agent_api_key() function
   - Added agent_api_key field to AppState
   - Added get_status() method to SupportCodeManager
   - Updated dashboard.html and viewer.html to pass JWT tokens
   - Updated agent transport.rs to use 'token' instead of 'api_key'

3. **Build and Deploy**:
   - Built server and agent on Windows
   - SSH to build server (172.16.3.30) failed to Jupiter but worked to gururmm
   - Git push, then pull on server, build with Linux target
   - Restarted server with start-server.sh
   - Uploaded agent binary

4. **User: "What version of claude is running?"**
   - Answered: Claude Opus 4.5 (claude-opus-4-5-20251101)

5. **User: "How do you know that?"**
   - Explained it's in the system prompt

6. **User: "How do we know which version of the Guruconnect agent we're working with?"**
   - Checked Cargo.toml - version 0.1.0
   - Noted it's logged at startup but no build identification

7. **User: "yes, add all the ways of identifying which version we're using"**
   - Modified build.rs to capture git info and build timestamp
   - Added chrono to build-dependencies
   - Created build_info module in main.rs with constants
   - Added version-info subcommand
   - Updated CLI version to include git hash
   - Updated startup logging to show version info
   - Built and tested - works correctly
   - Committed and pushed

8. **User: "Where can I place a list of issues and feature requests that we can refer back to? Gitea?"**
   - Confirmed Gitea issues are enabled
   - Provided URL

9. **User: "yes create those issues"**
   - Created 4 issues via Gitea API:
     - #1: Native viewer protocol URL parsing needs testing
     - #2: Duplicate machines in database need cleanup
     - #3: Document and implement AGENT_API_KEY for persistent agents
     - #4: Bump version to 0.2.0 after security changes stabilize

10. **User: "upload the new agent to the server"**
    - Uploaded via scp to guru@172.16.3.30

11. **User: "Can I have per project rules/design constraints?"**
    - Explained CLAUDE.md per-project support

12. **User: "Yes"**
    - Created comprehensive CLAUDE.md for GuruConnect
    - Committed and pushed

Key files modified:
- server/src/relay/mod.rs - WebSocket auth
- server/src/main.rs - AppState agent_api_key
- server/src/support_codes.rs - get_status()
- server/static/dashboard.html - token passing
- server/static/viewer.html - token passing
- agent/src/viewer/transport.rs - token parameter
- agent/build.rs - version info capture
- agent/Cargo.toml - chrono build-dependency
- agent/src/main.rs - build_info module, version-info command
- CLAUDE.md - project guidelines

Errors encountered:
- SSH key not configured for Jupiter - used build server instead
- Cargo not in PATH on server - sourced ~/.cargo/env
- Build tried Windows target - specified --target x86_64-unknown-linux-gnu
- Agent exe path different than expected - found correct path
- Gitea API labels format issue - removed labels parameter
- clap version attribute doesn't support function calls - used concat! with env!

Summary:
1. Primary Request and Intent:
   - Continue security hardening from previous session - secure WebSocket endpoints
   - Add comprehensive build identification to the agent (version, git hash, build time, etc.)
   - Create Gitea issues for tracking pending work
   - Upload updated agent to server
   - Create project-specific guidelines file (CLAUDE.md) for GuruConnect

2. Key Technical Concepts:
   - JWT authentication for WebSocket connections via query parameters
   - Support code vs API key authentication for agents
   - Rust build.rs for embedding compile-time information
   - Git commit hash, branch, dirty state embedding
   - Gitea API for issue creation
   - CLAUDE.md project-specific guidelines for Claude Code
   - Cargo environment variables (CARGO_PKG_VERSION, custom env vars)
   - Cross-compilation (Windows to Linux target)

3. Files and Code Sections:

   - **server/src/relay/mod.rs** - WebSocket authentication handlers
     - Added token to ViewerParams, api_key to AgentParams
     - viewer_ws_handler now requires JWT validation
     - agent_ws_handler requires support_code OR api_key
     ```rust
     pub async fn viewer_ws_handler(...) -> Result<impl IntoResponse, StatusCode> {
         let token = params.token.ok_or_else(|| {
             warn!("Viewer connection rejected: missing token");
             StatusCode::UNAUTHORIZED
         })?;
         let claims = state.jwt_config.validate_token(&token).map_err(|e| {
             warn!("Viewer connection rejected: invalid token: {}", e);
             StatusCode::UNAUTHORIZED
         })?;
         // ... upgrade connection
     }

     async fn validate_agent_api_key(state: &AppState, api_key: &str) -> bool {
         if state.jwt_config.validate_token(api_key).is_ok() { return true; }
         if let Some(ref configured_key) = state.agent_api_key {
             if api_key == configured_key { return true; }
         }
         false
     }
     ```

   - **server/src/main.rs** - Added agent_api_key to AppState
     ```rust
     pub struct AppState {
         sessions: session::SessionManager,
         support_codes: SupportCodeManager,
         db: Option<db::Database>,
         pub jwt_config: Arc<JwtConfig>,
         pub agent_api_key: Option<String>,
     }
     ```

   - **server/src/support_codes.rs** - Added get_status() method
     ```rust
     pub async fn get_status(&self, code: &str) -> Option<String> {
         let codes = self.codes.read().await;
         codes.get(code).map(|c| match c.status {
             CodeStatus::Pending => "pending".to_string(),
             CodeStatus::Connected => "connected".to_string(),
             CodeStatus::Completed => "completed".to_string(),
             CodeStatus::Cancelled => "cancelled".to_string(),
         })
     }
     ```

   - **agent/build.rs** - Build-time version info capture
     ```rust
     // Build timestamp (UTC)
     let build_timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string();
     println!("cargo:rustc-env=BUILD_TIMESTAMP={}", build_timestamp);

     // Git commit hash (short)
     let git_hash = Command::new("git")
         .args(["rev-parse", "--short=8", "HEAD"])
         .output().ok()
         .and_then(|o| String::from_utf8(o.stdout).ok())
         .map(|s| s.trim().to_string())
         .unwrap_or_else(|| "unknown".to_string());
     println!("cargo:rustc-env=GIT_HASH={}", git_hash);
     // ... similar for GIT_HASH_FULL, GIT_BRANCH, GIT_DIRTY, GIT_COMMIT_DATE, BUILD_PROFILE, BUILD_TARGET
     ```

   - **agent/src/main.rs** - build_info module and version-info command
     ```rust
     pub mod build_info {
         pub const VERSION: &str = env!("CARGO_PKG_VERSION");
         pub const GIT_HASH: &str = env!("GIT_HASH");
         pub const GIT_HASH_FULL: &str = env!("GIT_HASH_FULL");
         pub const GIT_BRANCH: &str = env!("GIT_BRANCH");
         pub const GIT_DIRTY: &str = env!("GIT_DIRTY");
         pub const GIT_COMMIT_DATE: &str = env!("GIT_COMMIT_DATE");
         pub const BUILD_TIMESTAMP: &str = env!("BUILD_TIMESTAMP");
         pub const BUILD_PROFILE: &str = env!("BUILD_PROFILE");
         pub const BUILD_TARGET: &str = env!("BUILD_TARGET");

         pub fn short_version() -> String {
             if GIT_DIRTY == "dirty" {
                 format!("{}-{}-dirty", VERSION, GIT_HASH)
             } else {
                 format!("{}-{}", VERSION, GIT_HASH)
             }
         }

         pub fn full_version() -> String { /* ... */ }
     }
     ```

   - **guru-connect/CLAUDE.md** - Project guidelines document
     - Architecture, design constraints, security rules, coding standards
     - Build/version format, database schema conventions
     - File structure, deployment info, testing checklist

4. Errors and fixes:
   - **SSH to Jupiter failed (permission denied)**: Used build server (172.16.3.30) instead where SSH key auth works
   - **Cargo not in PATH on server**: Fixed by sourcing `~/.cargo/env` before cargo commands
   - **Build tried Windows target on Linux**: Fixed with `--target x86_64-unknown-linux-gnu`
   - **Agent exe path wrong**: Found at `target/x86_64-pc-windows-msvc/release/guruconnect.exe` not `target/release/`
   - **Gitea API labels format issue**: Removed labels parameter, created issues without labels
   - **clap version attribute doesn't support functions**: Changed from `build_info::short_version()` to `concat!(env!("CARGO_PKG_VERSION"), "-", env!("GIT_HASH"))`

5. Problem Solving:
   - Secured all WebSocket endpoints (viewer needs JWT, agent needs support code or API key)
   - Implemented comprehensive build identification for tracking agent versions
   - Created Gitea issues for pending work tracking
   - Created CLAUDE.md for project-specific guidelines

6. All user messages:
   - (Implicit continuation from previous session to finish WebSocket security)
   - "What version of claude is running?"
   - "How do you know that?"
   - "How do we know which version of the Guruconnect agent we're working with?"
   - "yes, add all the ways of identifying which version we're using"
   - "Where can I place a list of issues and feature requests that we can refer back to? Gitea?"
   - "yes create those issues"
   - "upload the new agent to the server"
   - "Can I have per project rules/design constraints?"
   - "Yes"

7. Pending Tasks:
   - Issue #1: Test native viewer protocol URL parsing end-to-end
   - Issue #2: Clean up duplicate machines in database
   - Issue #3: Configure AGENT_API_KEY for persistent agents
   - Issue #4: Bump version to 0.2.0 after security stabilizes

8. Current Work:
   The most recent work was creating and committing the CLAUDE.md project guidelines file for GuruConnect. The file was created with comprehensive documentation including architecture, design constraints, security rules, coding standards, build/version format, database conventions, file structure, deployment info, and testing checklist. It was committed with message "Add project guidelines (CLAUDE.md)" and pushed to Gitea.

9. Optional Next Step:
   No explicit next step requested. The user's last request "Yes" to create CLAUDE.md was completed. The pending Gitea issues (#1-4) represent future work but weren't explicitly requested to start now..
Please continue the conversation from where we left it off without asking the user any further questions. Continue with the last task that you were asked to work on.


Looking at the summary, the last task completed was creating and committing the CLAUDE.md project guidelines file for GuruConnect. The user said "Yes" to creating per-project rules/design constraints, and I created the CLAUDE.md file.

The summary says "No explicit next step requested" and the pending Gitea issues represent future work but weren't explicitly requested.

Since the conversation was continued from a previous one that ran out of context, and the last task was completed, I should summarize what was accomplished and let the user know the current state, without asking questions.

Let me provide a brief status update on what was completed in the previous session.


The previous session completed successfully. Here's a summary of what was accomplished:

## Session Summary

### Security Hardening (Completed)
- **Viewer WebSocket** (`/ws/viewer`): Now requires JWT token in query params
- **Agent WebSocket** (`/ws/agent`): Now requires support code OR API key
- All REST API endpoints already secured with JWT authentication

### Version Identification (Completed)
- Agent now embeds comprehensive build info at compile time:
  - Version, git hash (short/full), branch, dirty state
  - Build timestamp, profile, target triple
- New `guruconnect version-info` command shows full details
- `--version` shows short format: `0.1.0-48076e1`

### Project Organization (Completed)
- Created `CLAUDE.md` with project guidelines, architecture, security rules
- Created 4 Gitea issues for tracking pending work:
  - #1: Native viewer protocol URL parsing needs testing
  - #2: Duplicate machines in database need cleanup
  - #3: Document and implement AGENT_API_KEY
  - #4: Bump version to 0.2.0 after security stabilizes

### Deployments (Completed)
- Server rebuilt and restarted on 172.16.3.30
- Agent binary uploaded to downloads directory

## Current State

The security hardening is deployed and working. The server logs show:
```
WARN guruconnect_server::relay: Viewer connection rejected: missing token
```

This confirms unauthenticated connections are being rejected.

**Gitea Issues URL:** https://git.azcomputerguru.com/azcomputerguru/guru-connect/issues

Is there anything specific you'd like to work on next, or should I proceed with one of the pending issues?


Let's make sure we have a robust auto-update feature embedded into the app.


The user wants to implement a robust auto-update feature for the GuruConnect agent. This is a significant feature that will require careful planning. Let me think about what's involved:

1. The agent needs to check for updates periodically
2. It needs to download the new version
3. It needs to replace itself and restart
4. This is tricky on Windows because you can't replace a running executable

Let me enter plan mode to design this properly, as it's a non-trivial feature with multiple valid approaches.


Auto-update for a Windows agent is a non-trivial feature with several architectural decisions to make. Let me enter plan mode to design this properly.


Entered plan mode. You should now focus on exploring the codebase and designing an implementation approach.

In plan mode, you should:
1. Thoroughly explore the codebase to understand existing patterns
2. Identify similar features and architectural approaches
3. Consider multiple approaches and their trade-offs
4. Use AskUserQuestion if you need to clarify the approach
5. Design a concrete implementation strategy
6. When ready, use ExitPlanMode to present your plan for approval

Remember: DO NOT write or edit any files yet. This is a read-only exploration and planning phase.


Let me explore the codebase to understand:
1. Current agent architecture and how it connects to the server
2. How the agent is currently deployed/installed
3. What version information is available
4. How updates could be delivered (server endpoint, etc.)

I should also check the existing plan file to see if it's relevant (it was about user management, so probably not).

Let me launch explore agents to understand the current state.


Let me explore the codebase to understand the current agent architecture and design a robust auto-update feature.


Task

Prompt:
Explore the GuruConnect agent codebase to understand how auto-update could be implemented. Focus on:

1. How the agent connects to the server (transport layer)
2. How the agent is installed (install.rs)
3. Current version/build info system (build_info module in main.rs)
4. The startup module - how the agent starts/restarts
5. Any existing update-related code or placeholders

Key files to examine:
- agent/src/main.rs - entry point, build_info
- agent/src/install.rs - installation logic
- agent/src/startup.rs - startup/restart logic
- agent/src/transport/ - server communication
- agent/src/config.rs - configuration

Report on:
- How version info is currently tracked
- How the agent could check for updates with the server
- How the binary could be replaced on Windows (challenges with replacing running exe)
- Any existing infrastructure that could support updates

Explore agent update architecture


Prompt:
Explore the GuruConnect server codebase to understand what infrastructure exists or would be needed for auto-update. Focus on:

1. Current download endpoint for the agent (static files)
2. API endpoints structure
3. How version info could be served
4. Session/machine management - could updates be triggered remotely?

Key files to examine:
- server/src/main.rs - routes, static file serving
- server/src/api/ - API handlers
- server/static/ - static file serving including downloads/
- server/src/relay/mod.rs - WebSocket message handling

Report on:
- Current agent download mechanism
- What API endpoint would be needed for version checking
- Could update commands be sent via WebSocket?
- What metadata the server would need to track (current version, available version)

Explore server update infrastructure


Perfect! Now I have a comprehensive understanding. Let me create a detailed analysis report of the GuruConnect codebase regarding auto-update implementation.

## GuruConnect Agent Auto-Update Implementation Analysis

Based on my exploration of the GuruConnect codebase, here's a comprehensive analysis of how auto-update could be implemented:

---

### 1. CURRENT VERSION/BUILD INFO SYSTEM

**File:** `agent/src/main.rs` (lines 32-90)

The agent already has an excellent compile-time build info system:

```rust
pub mod build_info {
    pub const VERSION: &str = env!("CARGO_PKG_VERSION");
    pub const GIT_HASH: &str = env!("GIT_HASH");
    pub const GIT_HASH_FULL: &str = env!("GIT_HASH_FULL");
    pub const GIT_BRANCH: &str = env!("GIT_BRANCH");
    pub const GIT_DIRTY: &str = env!("GIT_DIRTY");
    pub const GIT_COMMIT_DATE: &str = env!("GIT_COMMIT_DATE");
    pub const BUILD_TIMESTAMP: &str = env!("BUILD_TIMESTAMP");
    pub const BUILD_PROFILE: &str = env!("BUILD_PROFILE");
    pub const BUILD_TARGET: &str = env!("BUILD_TARGET");
}
```

**Source:** `agent/build.rs` embeds this info at compile time via git commands.

**Current version:** `0.1.0` (from Cargo.toml)

**Version string format:**
- Short: `0.1.0-48076e1` (version-gitshort)
- Full: Includes branch, commit date, timestamp, profile, target

**Available command:**
```
guruconnect version-info  # Shows detailed build info
```

---

### 2. TRANSPORT LAYER ANALYSIS

**File:** `agent/src/transport/websocket.rs`

The agent uses WebSocket over TLS (wss://) with:
- **Connection:** Connects to `wss://connect.azcomputerguru.com/ws/agent`
- **Authentication:** Sends `agent_id`, `api_key`, `hostname`, optional `support_code`
- **Serialization:** Protobuf binary format
- **Send/Receive:** `send()` and `recv()` methods for Message objects

**Key capabilities:**
- Non-blocking `try_recv()` for polling messages
- Async `recv()` for blocking reads
- Automatic message buffering
- Connection state tracking

---

### 3. PROTOCOL INFRASTRUCTURE FOR UPDATES

**File:** `proto/guruconnect.proto` (lines 282-291)

An update command already exists in the protocol:

```protobuf
message AdminCommand {
    AdminCommandType command = 1;
    string reason = 2;              // Why the command was issued
}

enum AdminCommandType {
    ADMIN_UNINSTALL = 0;            // Uninstall agent and remove from startup
    ADMIN_RESTART = 1;              // Restart the agent process
    ADMIN_UPDATE = 2;               // Download and install update (future)
}
```

**Current status:** `ADMIN_UPDATE = 2` is defined but **not implemented** in the agent.

**Session module handling:** `agent/src/session/mod.rs` (lines 455-477) shows that:
- `AdminCommandType::AdminUninstall` is fully implemented (uninstall + remove from startup)
- `AdminCommandType::AdminRestart` is partially implemented (disconnects, reconnects)
- `AdminCommandType::AdminUpdate` has a TODO placeholder:
  ```rust
  Some(AdminCommandType::AdminUpdate) => {
      tracing::info!("Update command received (not implemented)");
  }
  ```

---

### 4. INSTALLATION/FILE REPLACEMENT SYSTEM

**File:** `agent/src/install.rs`

**Current install locations:**
- **System-wide (elevated):** `C:\Program Files\GuruConnect\guruconnect.exe`
- **User-only (non-elevated):** `%LOCALAPPDATA%\GuruConnect\guruconnect.exe`

**How installation works:**
1. Self-copies from current exe to install location (lines 284-289)
2. Registers protocol handler (`guruconnect://`) in registry
3. Can detect existing installations and skip copying

**Critical for updates:** `get_install_path(elevated)` provides the path structure.

---

### 5. RESTART/PERSISTENCE SYSTEM

**File:** `agent/src/startup.rs`

**Windows persistence:**
- Adds to registry: `HKCU\Software\Microsoft\Windows\CurrentVersion\Run`
- Stores full executable path
- Agent automatically adds itself on startup (main.rs, line 431)

**Uninstall mechanism:**
- `MoveFileExW` with `MOVEFILE_DELAY_UNTIL_REBOOT` schedules deletion after reboot
- This solves the **running .exe replacement problem** - can't replace a running executable directly, so it's scheduled for deletion on reboot

**For auto-update:** This registry startup entry ensures the new binary will run on restart.

---

### 6. SESSION/MESSAGE HANDLING LOOP

**File:** `agent/src/session/mod.rs` (lines 205-401)

The agent has two operational modes:

**Idle Mode (lines 334-351):**
- Sends heartbeats every 30 seconds
- Sends status every 60 seconds
- Minimal resource usage
- Perfect for checking update availability

**Streaming Mode (lines 353-378):**
- Continuously capturing and sending video frames
- Challenge: Can't silently replace the binary while streaming
- Update should gracefully stop streaming and restart

**Message processing flow:**
1. Poll for messages: `transport.try_recv()?`
2. Handle special messages (chat, streaming control)
3. Process admin commands
4. State-specific behavior

---

### 7. CHALLENGES & SOLUTIONS FOR WINDOWS AUTO-UPDATE

**Challenge 1: Can't Replace Running .exe**
- **Problem:** The agent executable is running in memory and locked by Windows
- **Solution:** Use startup.rs's `MoveFileExW(..., MOVEFILE_DELAY_UNTIL_REBOOT)`
  - Download new binary to temporary location
  - Schedule current exe for deletion on reboot
  - Copy new binary to install location
  - Trigger restart (via AdminCommand or user action)

**Challenge 2: Update While Streaming**
- **Problem:** Can't restart while actively serving a viewer
- **Solution:**
  - Detect streaming sessions in progress
  - Queue update for after stream ends
  - Or: Send disconnect to all viewers, then update and restart

**Challenge 3: Installation Directory Permissions**
- **Problem:** Non-elevated agents install to `%LOCALAPPDATA%` (user-accessible)
  - Elevated agents install to `C:\Program Files\` (admin-only)
- **Solution:**
  - Update must respect current install location
  - Download new binary can go to temp folder (always writable)
  - Use current exe path to determine where to place update

**Challenge 4: Version Verification**
- **Problem:** How to prevent downgrade attacks or corrupted downloads
- **Solution:**
  - Server sends version + checksum (SHA256) in AdminUpdateCommand
  - Agent verifies checksum before moving files
  - Also validates version is >= current version

---

### 8. PROPOSED UPDATE MESSAGE STRUCTURE

**Should extend proto/guruconnect.proto:**

```protobuf
// New update message
message UpdateCommand {
    string version = 1;               // e.g., "0.2.0"
    string download_url = 2;          // e.g., https://...guruconnect.exe
    string checksum_sha256 = 3;       // For integrity verification
    bool restart_immediately = 4;     // If false, restart on next idle
}

// Extend AdminCommand to include update details
// OR change AdminCommand to include union of command-specific data
```

---

### 9. EXISTING INFRASTRUCTURE THAT SUPPORTS UPDATES

✓ **Version tracking system** - Embedded at compile time, easily queryable
✓ **Protocol infrastructure** - AdminCommand message structure already exists
✓ **File replacement mechanism** - MoveFileExW with reboot scheduling
✓ **Restart persistence** - Registry startup entry ensures new binary runs
✓ **Message loop architecture** - Can handle update commands during idle mode
✓ **Session state tracking** - Can detect streaming vs idle
✓ **Error handling framework** - Admin commands already return special errors
✓ **Transport reliability** - WebSocket with proper connection detection

---

### 10. INSTALLATION PATHS & DETECTION

**Current agent can:**
- Detect installation location via `std::env::current_exe()`
- Check elevation status (is_elevated())
- Determine install directory based on elevation
- Store config in ProgramData or AppData directories

**For updates:**
- Always update to same location as current binary
- Get path: `std::env::current_exe()` + determine elevation status
- Fallback to install::get_install_path(is_elevated())

---

### 11. SERVER-SIDE (What's Already Ready)

**File:** `server/src/relay/mod.rs` (lines 1-150)

The server already:
- Maintains active agent WebSocket connections
- Can relay messages bidirectionally
- Authenticates agents via API key or support code
- Has session management to track which agents are connected

**For updates, server would need to:**
- Store/track available versions
- Serve update binaries or provide download URLs
- Send AdminCommand with UpdateCommand payload
- Track update status of each agent (via database)

---

## Summary: Feasibility of Auto-Update

**Highly feasible** - The codebase has most required infrastructure:

1. **Download & Install:** Use existing install.rs paths + MoveFileExW scheduling
2. **Version Check:** Use embedded build_info + AdminCommand protocol
3. **Graceful Restart:** Leverage registry startup persistence
4. **Windows-Safe:** MoveFileExW solves the "can't replace running .exe" problem
5. **Protocol Ready:** AdminCommand structure exists, just needs UpdateCommand payload

**Key implementation points:**
- File: `agent/src/session/mod.rs` - Handle AdminUpdate command
- File: `proto/guruconnect.proto` - Extend AdminCommand or create UpdateCommand
- File: `agent/src/install.rs` - Add `perform_update()` function
- File: `agent/src/startup.rs` - Leverage existing MOVEFILE_DELAY_UNTIL_REBOOT

---

**Absolute file paths for reference:**
- C:\Users\MikeSwanson\Claude\guru-connect\agent\src\main.rs
- C:\Users\MikeSwanson\Claude\guru-connect\agent\src\install.rs
- C:\Users\MikeSwanson\Claude\guru-connect\agent\src\startup.rs
- C:\Users\MikeSwanson\Claude\guru-connect\agent\src\session\mod.rs
- C:\Users\MikeSwanson\Claude\guru-connect\agent\src\transport\websocket.rs
- C:\Users\MikeSwanson\Claude\guru-connect\proto\guruconnect.proto
- C:\Users\MikeSwanson\Claude\guru-connect\agent\build.rs
- C:\Users\MikeSwanson\Claude\guru-connect\server\src\relay\mod.rs

agentId: ae72ef8 (for resuming to continue this agent's work if needed)

Prompt:
Explore the GuruConnect agent codebase to understand how auto-update could be implemented. Focus on:

1. How the agent connects to the server (transport layer)
2. How the agent is installed (install.rs)
3. Current version/build info system (build_info module in main.rs)
4. The startup module - how the agent starts/restarts
5. Any existing update-related code or placeholders

Key files to examine:
- agent/src/main.rs - entry point, build_info
- agent/src/install.rs - installation logic
- agent/src/startup.rs - startup/restart logic
- agent/src/transport/ - server communication
- agent/src/config.rs - configuration

Report on:
- How version info is currently tracked
- How the agent could check for updates with the server
- How the binary could be replaced on Windows (challenges with replacing running exe)
- Any existing infrastructure that could support updates


Great! Now I have all the information I need. Let me compile a comprehensive report on the GuruConnect auto-update infrastructure.

## GuruConnect Server Auto-Update Infrastructure Analysis

Based on my thorough exploration of the GuruConnect codebase, here's the complete infrastructure assessment for implementing auto-update functionality:

---

### 1. CURRENT AGENT DOWNLOAD MECHANISM

**Location:** `C:\Users\MikeSwanson\Claude\guru-connect\server\static\`

Currently, there is **no download mechanism implemented**. The static directory only contains:
- `dashboard.html` - Dashboard UI
- `login.html` - Login page
- `users.html` - User management page
- `viewer.html` - Remote desktop viewer

**Needed Addition:** Create a `downloads/` subdirectory structure:
```
server/static/
  ├── downloads/
  │   ├── guruconnect.exe (or guruconnect-latest.exe)
  │   ├── guruconnect-[version].exe
  │   └── README.txt
```

The server's router (main.rs:237) uses `ServeDir::new("static")` as a fallback service, so any files placed in `server/static/downloads/` would be automatically served at `https://server/downloads/guruconnect.exe`.

---

### 2. API ENDPOINT STRUCTURE FOR VERSION CHECKING

**Current API endpoints:** The server has a clean REST API structure with routes defined in `main.rs:186-225`:

```rust
.route("/api/auth/login", post(api::auth::login))
.route("/api/users", get/post/put/delete)
.route("/api/sessions", get(list_sessions))
.route("/api/machines", get(list_machines))
.route("/api/machines/:agent_id", get/delete)
```

**Needed additions for auto-update:**

1. **Version Check Endpoint** - GET `/api/agents/{agent_id}/update-check`
   - Agent polls this with its current version
   - Server responds with available version info
   - Response structure:
     ```json
     {
       "current_version": "1.0.0",
       "latest_version": "1.0.1",
       "available": true,
       "download_url": "https://server/downloads/guruconnect-1.0.1.exe",
       "changelog": "Fixed crash on Windows 7...",
       "mandatory": false
     }
     ```

2. **Version Info Endpoint** - GET `/api/version`
   - Returns server and latest agent version
   - No auth required (allows unauthenticated agents to check)
   - Could be used in dashboard to show latest available version

3. **Release Management Endpoint** - POST/PUT `/api/releases` (admin only)
   - Upload new agent version
   - Mark versions as stable/beta
   - Set mandatory flag

---

### 3. HOW VERSION INFO WOULD BE SERVED

**Option A: Hardcoded in binary** (Simple)
- Server reads latest from `LATEST_VERSION` environment variable
- Server maintains static JSON file with version metadata at `server/static/version.json`
- Server checks file modification time to detect new versions

**Option B: Database-backed** (Scalable)
- Create new `releases` table:
  ```sql
  CREATE TABLE releases (
      id UUID PRIMARY KEY,
      version VARCHAR(20) NOT NULL UNIQUE,
      agent_version VARCHAR(20) NOT NULL,
      release_date TIMESTAMPTZ DEFAULT NOW(),
      changelog TEXT,
      is_stable BOOLEAN DEFAULT FALSE,
      is_mandatory BOOLEAN DEFAULT FALSE,
      download_url TEXT NOT NULL,
      file_hash VARCHAR(64),  -- SHA-256 hash for integrity check
      created_at TIMESTAMPTZ DEFAULT NOW()
  );
  ```
- Add DB queries to fetch latest version
- Admin API to upload and manage releases

**Current metadata available:**
The `connect_machines` table (schema:007-020) already tracks:
- `agent_id` - unique identifier
- `os_version` - OS info (could be used for version-specific downloads)
- `status` - online/offline
- `last_seen` - last connection time

This is sufficient for tracking which machines have which versions.

---

### 4. WEBSOCKET MESSAGE HANDLING FOR UPDATE COMMANDS

**YES - Update commands can absolutely be sent via WebSocket!**

The protobuf schema (`proto/guruconnect.proto:282-291`) already defines the perfect mechanism:

```protobuf
message AdminCommand {
    AdminCommandType command = 1;
    string reason = 2;
}

enum AdminCommandType {
    ADMIN_UNINSTALL = 0;       // Already implemented
    ADMIN_RESTART = 1;         // Already implemented
    ADMIN_UPDATE = 2;           // READY FOR USE - not implemented in agent yet
}
```

The server already has `send_admin_command()` method in `session/mod.rs:389-416`:

```rust
pub async fn send_admin_command(
    &self,
    session_id: SessionId,
    command: crate::proto::AdminCommandType,
    reason: &str
) -> bool {
    // Encodes AdminCommand message and sends via input channel to agent
    // Returns true if sent successfully
}
```

**Usage example (from main.rs:440-450):**
```rust
if params.uninstall {
    if let Some(session) = state.sessions.get_session_by_agent(&agent_id).await {
        if session.is_online {
            uninstall_sent = state.sessions.send_admin_command(
                session.id,
                proto::AdminCommandType::AdminUninstall,
                "Deleted by administrator",
            ).await;
        }
    }
}
```

**For auto-update, you would:**

1. Add REST endpoint to trigger update:
   ```rust
   POST /api/machines/{agent_id}/update
   Body: { "version": "1.0.1" }
   ```

2. Call the existing WebSocket mechanism:
   ```rust
   state.sessions.send_admin_command(
       session_id,
       proto::AdminCommandType::AdminUpdate,
       &format!("Update available to {}", version)
   ).await
   ```

3. Server sends binary message to agent containing `AdminCommand` with `ADMIN_UPDATE` type

4. Agent receives via WebSocket and handles update process (download, verify, install)

---

### 5. SERVER METADATA TRACKING FOR AUTO-UPDATE

**Current tracking in `connect_machines` table:**

```sql
CREATE TABLE connect_machines (
    id UUID PRIMARY KEY,
    agent_id VARCHAR(255) UNIQUE,
    hostname VARCHAR(255),
    os_version VARCHAR(255),        -- Track OS version
    is_elevated BOOLEAN,             -- Track elevation status
    is_persistent BOOLEAN,           -- Track agent type
    first_seen TIMESTAMPTZ,
    last_seen TIMESTAMPTZ,
    last_session_id UUID,
    status VARCHAR(20),              -- 'online' or 'offline'
    ...
);
```

**What needs to be added:**

```sql
ALTER TABLE connect_machines ADD COLUMN (
    agent_version VARCHAR(20),       -- Current version running on agent
    target_version VARCHAR(20),      -- Version we want it to update to
    update_status VARCHAR(20),       -- 'idle', 'downloading', 'installing', 'complete', 'failed'
    last_update_check TIMESTAMPTZ,
    last_update_attempt TIMESTAMPTZ,
    update_error TEXT
);
```

**Query example to find machines needing update:**
```sql
SELECT * FROM connect_machines
WHERE agent_version < '1.0.1'
  AND status = 'online'
  AND is_persistent = true;
```

---

### 6. IMPLEMENTATION ROADMAP

**Phase 1: Infrastructure (No agent changes)**
1. Create `releases` table in migrations
2. Add version fields to `machines` table
3. Implement `/api/version` endpoint (unauthenticated)
4. Implement `/api/releases` admin endpoint
5. Add static file serving for agent binaries

**Phase 2: Server-side coordination**
1. Add `/api/machines/{agent_id}/update` endpoint
2. Integrate with `send_admin_command()` for `ADMIN_UPDATE`
3. Add dashboard UI to trigger updates

**Phase 3: Agent implementation** (Requires agent changes)
1. Handle `ADMIN_UPDATE` command in agent WebSocket handler
2. Implement update download logic
3. Verify file hash/signature
4. Execute update process (self-replace, restart)
5. Report back update status via new message type

---

### 7. KEY FINDINGS

**Strengths:**
- WebSocket infrastructure already exists and is secure (requires auth)
- Admin command mechanism is in place and tested (uninstall already works)
- Database schema is flexible enough to track versions
- Server architecture supports file serving for downloads

**Gaps:**
- No download mechanism exists yet
- No version tracking in database
- `ADMIN_UPDATE` enum value is defined but not implemented in agent
- No API endpoint for version checking
- No UI for triggering updates

**Critical considerations:**
1. **Agent identification:** Agents connect with `agent_id` parameter - perfect for tracking
2. **Authentication:** All WebSocket updates are already authenticated (support code or API key)
3. **Network agnostic:** Works over NAT/firewall since agent initiates connection
4. **Status reporting:** Agent sends `AgentStatus` messages with heartbeat - can extend to include version info
5. **Offline handling:** For offline agents, update can be queued in database and executed when they reconnect

---

### 8. FILE LOCATIONS

Key files for implementation:

- **Main router:** `C:\Users\MikeSwanson\Claude\guru-connect\server\src\main.rs` (add routes)
- **Protocol definitions:** `C:\Users\MikeSwanson\Claude\guru-connect\proto\guruconnect.proto` (already complete)
- **Session manager:** `C:\Users\MikeSwanson\Claude\guru-connect\server\src\session\mod.rs` (send_admin_command)
- **Database operations:** `C:\Users\MikeSwanson\Claude\guru-connect\server\src\db\machines.rs` (track versions)
- **Migrations:** `C:\Users\MikeSwanson\Claude\guru-connect\server\migrations\` (new releases table)
- **Static files:** `C:\Users\MikeSwanson\Claude\guru-connect\server\static\downloads\` (agent binaries)

The infrastructure for auto-update is **95% ready** - you just need to add the version tracking database layer, API endpoints, and agent-side implementation of the `ADMIN_UPDATE` command handler.

agentId: a27db58 (for resuming to continue this agent's work if needed)

Prompt:
Explore the GuruConnect server codebase to understand what infrastructure exists or would be needed for auto-update. Focus on:

1. Current download endpoint for the agent (static files)
2. API endpoints structure
3. How version info could be served
4. Session/machine management - could updates be triggered remotely?

Key files to examine:
- server/src/main.rs - routes, static file serving
- server/src/api/ - API handlers
- server/static/ - static file serving including downloads/
- server/src/relay/mod.rs - WebSocket message handling

Report on:
- Current agent download mechanism
- What API endpoint would be needed for version checking
- Could update commands be sent via WebSocket?
- What metadata the server would need to track (current version, available version)


Excellent! I now have a comprehensive understanding of the codebase. Let me summarize the key findings:

**Agent Side:**
- Version info system already exists (build_info module)
- `ADMIN_UPDATE` is already defined in protobuf but not implemented
- Install.rs has path detection and file copy logic
- startup.rs has `MoveFileExW` with `MOVEFILE_DELAY_UNTIL_REBOOT` for replacing running exe
- Session loop handles admin commands already

**Server Side:**
- WebSocket infrastructure is ready
- `send_admin_command()` already exists and works for uninstall/restart
- No version tracking in database yet
- No download endpoint yet
- Static file serving is available via ServeDir fallback

**Key Challenges:**
1. Can't replace running .exe on Windows - solved by MOVEFILE_DELAY_UNTIL_REBOOT
2. Need graceful handling during streaming sessions
3. Need version verification (checksum)

Now I need to design a plan and decide on implementation approach. Let me think about the architecture:

**Option 1: Reboot-based update**
- Download new binary
- Schedule current exe for deletion
- Copy new binary
- Wait for reboot or trigger restart
- Simpler, but requires reboot

**Option 2: In-place update with restart**
- Download to temp
- Rename current exe to .old
- Copy new to original location
- Spawn new process
- Exit current process
- New process deletes .old on startup
- More complex but no reboot needed

**Option 3: Sidecar/updater approach**
- Download a separate updater exe
- Spawn updater
- Exit main process
- Updater replaces exe and restarts
- Most robust for complex scenarios

For GuruConnect, Option 2 seems best - it's user-friendly (no reboot required) and doesn't need a separate updater binary.

Let me now design a comprehensive plan and write it to the plan file.


Excellent! The exploration reveals that most infrastructure is already in place. Let me now design a comprehensive implementation plan.


     1→# GuruConnect User Management Plan
     2→
     3→## Overview
     4→
     5→Implement user authentication and authorization to secure the GuruConnect dashboard. Users can only be created by admins, with granular role-based permissions including per-client machine access control.
     6→
     7→## Requirements (User-Specified)
     8→
     9→- **User Creation:** Admin-only (no self-registration)
    10→- **Roles/Permissions:** Granular (view-only, control, admin, per-client access)
    11→- **Auth Source:** Local users only (no external SSO)
    12→
    13→## Architecture
    14→
    15→```
    16→┌─────────────────────────────────────────────────────────────┐
    17→│  Browser (Dashboard)                                        │
    18→│  - Login form → POST /api/auth/login                        │
    19→│  - JWT stored in localStorage/cookie                        │
    20→│  - JWT sent with all API requests                           │
    21→└─────────────────────────────────────────────────────────────┘
    22→                              │
    23→                              ▼
    24→┌─────────────────────────────────────────────────────────────┐
    25→│  Server API                                                 │
    26→│  - JWT validation middleware                                │
    27→│  - Role/permission checks per endpoint                      │
    28→│  - User management endpoints (admin only)                   │
    29→└─────────────────────────────────────────────────────────────┘
    30→                              │
    31→                              ▼
    32→┌─────────────────────────────────────────────────────────────┐
    33→│  PostgreSQL Database                                        │
    34→│  - users table (credentials, roles)                         │
    35→│  - user_permissions table (granular permissions)            │
    36→│  - user_client_access table (per-client access)             │
    37→└─────────────────────────────────────────────────────────────┘
    38→```
    39→
    40→## Database Schema
    41→
    42→### New Migration: `002_user_management.sql`
    43→
    44→```sql
    45→-- Users table
    46→CREATE TABLE users (
    47→    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    48→    username VARCHAR(64) UNIQUE NOT NULL,
    49→    password_hash VARCHAR(255) NOT NULL,
    50→    email VARCHAR(255),
    51→    role VARCHAR(32) NOT NULL DEFAULT 'viewer',  -- 'admin', 'operator', 'viewer'
    52→    enabled BOOLEAN NOT NULL DEFAULT true,
    53→    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    54→    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    55→    last_login TIMESTAMPTZ
    56→);
    57→
    58→-- Granular permissions (what actions a user can perform)
    59→CREATE TABLE user_permissions (
    60→    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    61→    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    62→    permission VARCHAR(64) NOT NULL,  -- 'view', 'control', 'transfer', 'manage_users', etc.
    63→    UNIQUE(user_id, permission)
    64→);
    65→
    66→-- Per-client access (which machines a user can access)
    67→-- NULL = access to all clients (for admins)
    68→CREATE TABLE user_client_access (
    69→    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    70→    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    71→    client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
    72→    UNIQUE(user_id, client_id)
    73→);
    74→
    75→-- Indexes
    76→CREATE INDEX idx_users_username ON users(username);
    77→CREATE INDEX idx_user_permissions_user ON user_permissions(user_id);
    78→CREATE INDEX idx_user_client_access_user ON user_client_access(user_id);
    79→```
    80→
    81→### Role Definitions
    82→
    83→| Role | Description | Default Permissions |
    84→|------|-------------|---------------------|
    85→| admin | Full access, manage users | All permissions, all clients |
    86→| operator | Can control machines | view, control, transfer |
    87→| viewer | View-only access | view |
    88→
    89→### Permission Types
    90→
    91→| Permission | Description |
    92→|------------|-------------|
    93→| view | See dashboard, client list, status |
    94→| control | Take control of machines (keyboard/mouse) |
    95→| transfer | File transfer access |
    96→| manage_users | Create/edit/delete users (admin only) |
    97→| manage_clients | Delete clients, edit client metadata |
    98→
    99→## API Endpoints
   100→
   101→### Authentication
   102→
   103→| Method | Endpoint | Description | Auth |
   104→|--------|----------|-------------|------|
   105→| POST | `/api/auth/login` | Login, returns JWT | None |
   106→| POST | `/api/auth/logout` | Invalidate token | JWT |
   107→| GET | `/api/auth/me` | Get current user info | JWT |
   108→| POST | `/api/auth/change-password` | Change own password | JWT |
   109→
   110→### User Management (Admin Only)
   111→
   112→| Method | Endpoint | Description |
   113→|--------|----------|-------------|
   114→| GET | `/api/users` | List all users |
   115→| POST | `/api/users` | Create new user |
   116→| GET | `/api/users/:id` | Get user details |
   117→| PUT | `/api/users/:id` | Update user |
   118→| DELETE | `/api/users/:id` | Delete user |
   119→| PUT | `/api/users/:id/permissions` | Set user permissions |
   120→| PUT | `/api/users/:id/clients` | Set client access |
   121→
   122→## JWT Token Structure
   123→
   124→```json
   125→{
   126→  "sub": "user-uuid",
   127→  "username": "admin",
   128→  "role": "admin",
   129→  "permissions": ["view", "control", "transfer", "manage_users"],
   130→  "exp": 1234567890,
   131→  "iat": 1234567890
   132→}
   133→```
   134→
   135→## Files to Modify/Create
   136→
   137→### Server Changes
   138→
   139→| File | Action | Purpose |
   140→|------|--------|---------|
   141→| `server/migrations/002_user_management.sql` | CREATE | Database schema |
   142→| `server/src/auth/mod.rs` | REWRITE | Real JWT auth implementation |
   143→| `server/src/auth/jwt.rs` | CREATE | JWT creation/validation |
   144→| `server/src/auth/password.rs` | CREATE | Argon2 password hashing |
   145→| `server/src/models/user.rs` | CREATE | User model and DB queries |
   146→| `server/src/api/auth.rs` | CREATE | Auth API endpoints |
   147→| `server/src/api/users.rs` | CREATE | User management endpoints |
   148→| `server/src/api/mod.rs` | MODIFY | Add new route modules |
   149→| `server/src/main.rs` | MODIFY | Add auth middleware |
   150→
   151→### Dashboard Changes
   152→
   153→| File | Action | Purpose |
   154→|------|--------|---------|
   155→| `server/static/login.html` | CREATE | Login page |
   156→| `server/static/dashboard.html` | MODIFY | Add auth checks, user menu |
   157→| `server/static/users.html` | CREATE | User management page (admin) |
   158→
   159→## Implementation Phases
   160→
   161→### Phase 1: Database & Models
   162→1. Create migration `002_user_management.sql`
   163→2. Create `models/user.rs` with User struct and DB operations
   164→3. Add initial admin user creation (first-run setup)
   165→
   166→### Phase 2: Authentication
   167→1. Implement `auth/password.rs` - Argon2 hashing
   168→2. Implement `auth/jwt.rs` - Token create/validate
   169→3. Rewrite `auth/mod.rs` - Real middleware
   170→4. Create `api/auth.rs` - Login/logout endpoints
   171→
   172→### Phase 3: Authorization
   173→1. Add permission checking to existing endpoints
   174→2. Add client access filtering to client list
   175→3. Protect WebSocket connections with JWT
   176→
   177→### Phase 4: User Management API
   178→1. Create `api/users.rs` - CRUD endpoints
   179→2. Add permission/client access management
   180→3. Admin-only route protection
   181→
   182→### Phase 5: Dashboard UI
   183→1. Create login page with redirect
   184→2. Add logout button and user menu
   185→3. Create user management page
   186→4. Add permission-based UI hiding
   187→
   188→## Initial Admin Setup
   189→
   190→On first run (no users in DB):
   191→1. Server detects empty users table
   192→2. Generates random admin password
   193→3. Creates default admin user
   194→4. Prints credentials to console/logs
   195→5. Forces password change on first login (optional)
   196→
   197→Alternative: Environment variable for initial admin password.
   198→
   199→## Security Considerations
   200→
   201→1. **Password Storage:** Argon2id with recommended parameters
   202→2. **JWT Secret:** Random 256-bit key, stored in config/env
   203→3. **Token Expiry:** 24h default, configurable
   204→4. **HTTPS Only:** Cookies marked Secure in production
   205→5. **Rate Limiting:** Consider adding for login endpoint
   206→6. **Audit Logging:** Log auth events (login, logout, failed attempts)
   207→
   208→## Existing Dependencies (Already in Cargo.toml)
   209→
   210→- `jsonwebtoken` - JWT handling
   211→- `argon2` - Password hashing
   212→- `sqlx` - Database queries
   213→
   214→## Critical Files to Review During Implementation
   215→
   216→- `server/src/auth/mod.rs` - Current placeholder auth (lines 1-50)
   217→- `server/src/api/mod.rs` - Current API routes
   218→- `server/src/ws.rs` - WebSocket auth (needs JWT validation)
   219→- `server/src/db.rs` - Database connection handling
   220→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

# GuruConnect User Management Plan

## Overview

Implement user authentication and authorization to secure the GuruConnect dashboard. Users can only be created by admins, with granular role-based permissions including per-client machine access control.

## Requirements (User-Specified)

- **User Creation:** Admin-only (no self-registration)
- **Roles/Permissions:** Granular (view-only, control, admin, per-client access)
- **Auth Source:** Local users only (no external SSO)

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│  Browser (Dashboard)                                        │
│  - Login form → POST /api/auth/login                        │
│  - JWT stored in localStorage/cookie                        │
│  - JWT sent with all API requests                           │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  Server API                                                 │
│  - JWT validation middleware                                │
│  - Role/permission checks per endpoint                      │
│  - User management endpoints (admin only)                   │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  PostgreSQL Database                                        │
│  - users table (credentials, roles)                         │
│  - user_permissions table (granular permissions)            │
│  - user_client_access table (per-client access)             │
└─────────────────────────────────────────────────────────────┘
```

## Database Schema

### New Migration: `002_user_management.sql`

```sql
-- Users table
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    username VARCHAR(64) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    email VARCHAR(255),
    role VARCHAR(32) NOT NULL DEFAULT 'viewer',  -- 'admin', 'operator', 'viewer'
    enabled BOOLEAN NOT NULL DEFAULT true,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    last_login TIMESTAMPTZ
);

-- Granular permissions (what actions a user can perform)
CREATE TABLE user_permissions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    permission VARCHAR(64) NOT NULL,  -- 'view', 'control', 'transfer', 'manage_users', etc.
    UNIQUE(user_id, permission)
);

-- Per-client access (which machines a user can access)
-- NULL = access to all clients (for admins)
CREATE TABLE user_client_access (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
    UNIQUE(user_id, client_id)
);

-- Indexes
CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_user_permissions_user ON user_permissions(user_id);
CREATE INDEX idx_user_client_access_user ON user_client_access(user_id);
```

### Role Definitions

| Role | Description | Default Permissions |
|------|-------------|---------------------|
| admin | Full access, manage users | All permissions, all clients |
| operator | Can control machines | view, control, transfer |
| viewer | View-only access | view |

### Permission Types

| Permission | Description |
|------------|-------------|
| view | See dashboard, client list, status |
| control | Take control of machines (keyboard/mouse) |
| transfer | File transfer access |
| manage_users | Create/edit/delete users (admin only) |
| manage_clients | Delete clients, edit client metadata |

## API Endpoints

### Authentication

| Method | Endpoint | Description | Auth |
|--------|----------|-------------|------|
| POST | `/api/auth/login` | Login, returns JWT | None |
| POST | `/api/auth/logout` | Invalidate token | JWT |
| GET | `/api/auth/me` | Get current user info | JWT |
| POST | `/api/auth/change-password` | Change own password | JWT |

### User Management (Admin Only)

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/users` | List all users |
| POST | `/api/users` | Create new user |
| GET | `/api/users/:id` | Get user details |
| PUT | `/api/users/:id` | Update user |
| DELETE | `/api/users/:id` | Delete user |
| PUT | `/api/users/:id/permissions` | Set user permissions |
| PUT | `/api/users/:id/clients` | Set client access |

## JWT Token Structure

```json
{
  "sub": "user-uuid",
  "username": "admin",
  "role": "admin",
  "permissions": ["view", "control", "transfer", "manage_users"],
  "exp": 1234567890,
  "iat": 1234567890
}
```

## Files to Modify/Create

### Server Changes

| File | Action | Purpose |
|------|--------|---------|
| `server/migrations/002_user_management.sql` | CREATE | Database schema |
| `server/src/auth/mod.rs` | REWRITE | Real JWT auth implementation |
| `server/src/auth/jwt.rs` | CREATE | JWT creation/validation |
| `server/src/auth/password.rs` | CREATE | Argon2 password hashing |
| `server/src/models/user.rs` | CREATE | User model and DB queries |
| `server/src/api/auth.rs` | CREATE | Auth API endpoints |
| `server/src/api/users.rs` | CREATE | User management endpoints |
| `server/src/api/mod.rs` | MODIFY | Add new route modules |
| `server/src/main.rs` | MODIFY | Add auth middleware |

### Dashboard Changes

| File | Action | Purpose |
|------|--------|---------|
| `server/static/login.html` | CREATE | Login page |
| `server/static/dashboard.html` | MODIFY | Add auth checks, user menu |
| `server/static/users.html` | CREATE | User management page (admin) |

## Implementation Phases

### Phase 1: Database & Models
1. Create migration `002_user_management.sql`
2. Create `models/user.rs` with User struct and DB operations
3. Add initial admin user creation (first-run setup)

### Phase 2: Authentication
1. Implement `auth/password.rs` - Argon2 hashing
2. Implement `auth/jwt.rs` - Token create/validate
3. Rewrite `auth/mod.rs` - Real middleware
4. Create `api/auth.rs` - Login/logout endpoints

### Phase 3: Authorization
1. Add permission checking to existing endpoints
2. Add client access filtering to client list
3. Protect WebSocket connections with JWT

### Phase 4: User Management API
1. Create `api/users.rs` - CRUD endpoints
2. Add permission/client access management
3. Admin-only route protection

### Phase 5: Dashboard UI
1. Create login page with redirect
2. Add logout button and user menu
3. Create user management page
4. Add permission-based UI hiding

## Initial Admin Setup

On first run (no users in DB):
1. Server detects empty users table
2. Generates random admin password
3. Creates default admin user
4. Prints credentials to console/logs
5. Forces password change on first login (optional)

Alternative: Environment variable for initial admin password.

## Security Considerations

1. **Password Storage:** Argon2id with recommended parameters
2. **JWT Secret:** Random 256-bit key, stored in config/env
3. **Token Expiry:** 24h default, configurable
4. **HTTPS Only:** Cookies marked Secure in production
5. **Rate Limiting:** Consider adding for login endpoint
6. **Audit Logging:** Log auth events (login, logout, failed attempts)

## Existing Dependencies (Already in Cargo.toml)

- `jsonwebtoken` - JWT handling
- `argon2` - Password hashing
- `sqlx` - Database queries

## Critical Files to Review During Implementation

- `server/src/auth/mod.rs` - Current placeholder auth (lines 1-50)
- `server/src/api/mod.rs` - Current API routes
- `server/src/ws.rs` - WebSocket auth (needs JWT validation)
- `server/src/db.rs` - Database connection handling


The existing plan is for user management - a different task. I need to completely replace it with the auto-update plan. Let me write a comprehensive auto-update implementation plan.

Before I finalize, I should ask the user a few clarifying questions about their preferences for the auto-update feature.


The existing plan is for user management (a different task). Let me replace it with a comprehensive auto-update plan. First, let me clarify a few key design decisions.


AskUserQuestion

Question: How should the agent update itself on Windows (can't replace a running .exe)?

Choices:
Rename current exe to .old, copy new, spawn new process, exit. No reboot needed.
Schedule file replacement for reboot using Windows API. Requires system restart.
Download a small updater.exe that handles the replacement. More complex but most robust.

Question: How should updates be triggered?

Choices:
Agent checks periodically AND admin can push updates remotely via dashboard
Agent checks for updates on a schedule (e.g., every hour)
Admin triggers updates from dashboard; agent doesn't check automatically

Question: Should updates require user confirmation on the client machine?

Choices:
Update happens automatically without prompting the end user
Show tray notification when update happens, but don't ask permission
Show dialog asking user to approve the update


User has answered your questions: "How should the agent update itself on Windows (can't replace a running .exe)?"="In-place restart (Recommended)", "How should updates be triggered?"="Both (Recommended)", "Should updates require user confirmation on the client machine?"="Silent updates (Recommended)". You can now continue with the user's answers in mind.

Question: How should the agent update itself on Windows (can't replace a running .exe)?

Choices:
Rename current exe to .old, copy new, spawn new process, exit. No reboot needed.
Schedule file replacement for reboot using Windows API. Requires system restart.
Download a small updater.exe that handles the replacement. More complex but most robust.

Question: How should updates be triggered?

Choices:
Agent checks periodically AND admin can push updates remotely via dashboard
Agent checks for updates on a schedule (e.g., every hour)
Admin triggers updates from dashboard; agent doesn't check automatically

Question: Should updates require user confirmation on the client machine?

Choices:
Update happens automatically without prompting the end user
Show tray notification when update happens, but don't ask permission
Show dialog asking user to approve the update


The user has selected:
1. In-place restart - Rename current exe to .old, copy new, spawn new process, exit
2. Both - Agent polling AND admin push from dashboard
3. Silent updates - No user prompt

Now I can write a comprehensive plan for this feature.


Now I have the requirements. Let me write the comprehensive auto-update plan.


Write

# GuruConnect Auto-Update Plan

## Overview

Implement a robust auto-update system for the GuruConnect Windows agent. Updates can be triggered by:
1. **Agent polling** - Agent checks for updates periodically (every hour)
2. **Admin push** - Admin triggers update from dashboard via WebSocket command

Updates are **silent** (no user prompt) and use **in-place restart** (no reboot required).

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│  Dashboard                                                   │
│  - Shows agent versions                                      │
│  - "Update" button triggers push                             │
│  - "Update All" for bulk updates                             │
└─────────────────────────────────────────────────────────────┘
        │ POST /api/machines/{id}/update
        ▼
┌─────────────────────────────────────────────────────────────┐
│  Server                                                      │
│  - Stores releases metadata (version, URL, checksum)         │
│  - GET /api/version returns latest version info              │
│  - Sends AdminCommand(ADMIN_UPDATE) via WebSocket            │
│  - Tracks agent versions in connect_machines table           │
└─────────────────────────────────────────────────────────────┘
        │ WebSocket: AdminCommand
        ▼
┌─────────────────────────────────────────────────────────────┐
│  Agent                                                       │
│  1. Polls /api/version every hour (during idle)              │
│  2. Downloads new binary to temp folder                      │
│  3. Verifies SHA-256 checksum                                │
│  4. Renames current.exe → current.exe.old                    │
│  5. Copies new.exe → current.exe                             │
│  6. Spawns new process                                       │
│  7. Exits current process                                    │
│  8. New process deletes .old on startup                      │
└─────────────────────────────────────────────────────────────┘
```

## Update Flow (In-Place Restart)

### Step-by-Step Process

1. **Trigger** - Either periodic check or admin push
2. **Version Check** - Compare current vs available version
3. **Download** - Fetch new binary to `%TEMP%\guruconnect-update.exe`
4. **Verify** - SHA-256 checksum validation
5. **Prepare** - Rename `guruconnect.exe` → `guruconnect.exe.old`
6. **Install** - Copy temp file to install location
7. **Restart** - Spawn new process with special `--post-update` flag
8. **Exit** - Current process exits cleanly
9. **Cleanup** - New process deletes `.old` file on startup

### Why This Works on Windows

- Can't delete or overwrite a running .exe
- BUT can rename a running .exe
- New file can be written to the original path
- New process starts, old process exits
- Cleanup happens on next launch

## Database Schema

### Migration: `XXX_auto_update.sql`

```sql
-- Track available releases
CREATE TABLE releases (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    version VARCHAR(32) NOT NULL UNIQUE,
    download_url TEXT NOT NULL,
    checksum_sha256 VARCHAR(64) NOT NULL,
    release_notes TEXT,
    is_stable BOOLEAN NOT NULL DEFAULT false,
    is_mandatory BOOLEAN NOT NULL DEFAULT false,
    min_version VARCHAR(32),  -- Minimum version that can update to this
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Add version tracking to machines
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS agent_version VARCHAR(32);
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS update_status VARCHAR(32);
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS last_update_check TIMESTAMPTZ;
```

### Update Status Values
- `null` - Never checked
- `current` - Running latest version
- `available` - Update available, not started
- `downloading` - Currently downloading
- `installing` - Currently installing
- `failed` - Last update failed (with error in logs)

## Protocol Changes

### Extend `proto/guruconnect.proto`

```protobuf
// Add to existing messages

// Update command details (sent with AdminCommand)
message UpdateInfo {
    string version = 1;
    string download_url = 2;
    string checksum_sha256 = 3;
    bool mandatory = 4;
}

// Update status report (agent → server)
message UpdateStatus {
    string current_version = 1;
    UpdateState state = 2;
    string error_message = 3;  // If state is FAILED
}

enum UpdateState {
    UPDATE_IDLE = 0;
    UPDATE_CHECKING = 1;
    UPDATE_DOWNLOADING = 2;
    UPDATE_INSTALLING = 3;
    UPDATE_COMPLETE = 4;
    UPDATE_FAILED = 5;
}

// Extend Message to include UpdateInfo
message Message {
    // ... existing fields ...
    UpdateInfo update_info = 15;
    UpdateStatus update_status = 16;
}

// Extend AgentStatus to include version
message AgentStatus {
    // ... existing fields ...
    string agent_version = 10;
}
```

## API Endpoints

### Version Check (No Auth - Agent Polling)
```
GET /api/version
Response: {
    "latest_version": "0.2.0",
    "download_url": "https://connect.azcomputerguru.com/downloads/guruconnect.exe",
    "checksum_sha256": "abc123...",
    "is_mandatory": false,
    "release_notes": "Bug fixes and performance improvements"
}
```

### Trigger Update (Admin Auth)
```
POST /api/machines/{agent_id}/update
Body: { "version": "0.2.0" }  // Optional, defaults to latest
Response: { "success": true, "message": "Update command sent" }
```

### Bulk Update (Admin Auth)
```
POST /api/machines/update-all
Body: { "version": "0.2.0" }  // Optional
Response: { "updated": 15, "skipped": 3, "offline": 5 }
```

### Release Management (Admin Auth)
```
GET /api/releases              # List all releases
POST /api/releases             # Create new release
DELETE /api/releases/{version} # Remove release
PUT /api/releases/{version}    # Update release metadata
```

## Files to Modify

### Agent Files

| File | Changes |
|------|---------|
| `agent/src/main.rs` | Add `--post-update` flag handling, cleanup old exe on startup |
| `agent/src/session/mod.rs` | Handle ADMIN_UPDATE command, implement update check timer |
| `agent/src/update.rs` | NEW: Update logic (download, verify, replace, restart) |
| `agent/Cargo.toml` | Add `reqwest` for HTTP downloads, `sha2` for checksum |
| `proto/guruconnect.proto` | Add UpdateInfo, UpdateStatus messages |

### Server Files

| File | Changes |
|------|---------|
| `server/migrations/XXX_auto_update.sql` | NEW: releases table, machine version columns |
| `server/src/main.rs` | Add /api/version, /api/releases routes |
| `server/src/api/releases.rs` | NEW: Release management endpoints |
| `server/src/api/machines.rs` | Add update trigger endpoint |
| `server/src/db/releases.rs` | NEW: Release DB operations |
| `server/src/relay/mod.rs` | Parse UpdateInfo from AdminCommand |
| `server/static/dashboard.html` | Show versions, add update buttons |

## Implementation Phases

### Phase 1: Protocol & Database
1. Update `proto/guruconnect.proto` with UpdateInfo, UpdateStatus
2. Create migration for releases table and machine version columns
3. Add agent_version to AgentStatus message
4. Rebuild proto for both agent and server

### Phase 2: Server Infrastructure
1. Create `db/releases.rs` - CRUD for releases table
2. Create `api/releases.rs` - Admin endpoints for managing releases
3. Add `GET /api/version` - Unauthenticated version check endpoint
4. Add `POST /api/machines/{id}/update` - Trigger update via WebSocket
5. Modify `relay/mod.rs` to include UpdateInfo in AdminCommand
6. Track agent versions when they connect (parse from AgentStatus)

### Phase 3: Agent Update Logic
1. Create `agent/src/update.rs` module:
   - `check_for_update()` - Call /api/version, compare versions
   - `download_update()` - Download to temp with progress
   - `verify_checksum()` - SHA-256 validation
   - `install_update()` - Rename/copy/spawn/exit dance
2. Add periodic update check in session idle loop (every hour)
3. Handle ADMIN_UPDATE command to trigger immediate update
4. Add `--post-update` flag to cleanup .old files on startup
5. Send UpdateStatus messages to report progress

### Phase 4: Dashboard UI
1. Add "Version" column to machines table
2. Add "Update" button per machine (when update available)
3. Add "Update All" button in toolbar
4. Show update status (downloading, installing, etc.)
5. Release management page (list, upload, delete releases)

## Security Considerations

1. **Checksum Verification** - SHA-256 hash must match before install
2. **HTTPS Only** - Downloads must use HTTPS
3. **Version Validation** - Prevent downgrade attacks (only update to newer versions)
4. **Admin Authorization** - Only admins can trigger updates or manage releases
5. **Signed Binaries** - Future: Authenticode signing for Windows

## Error Handling

| Error | Handling |
|-------|----------|
| Download fails | Retry 3 times with exponential backoff |
| Checksum mismatch | Abort, report failure, delete temp file |
| File rename fails | Abort, report failure (might be permission issue) |
| Copy fails | Restore .old → original, report failure |
| New process won't start | Keep current running, report failure |
| Disk space | Check before download, abort if insufficient |

## Agent Dependencies to Add

```toml
# In agent/Cargo.toml
reqwest = { version = "0.12", features = ["rustls-tls", "stream"] }
sha2 = "0.10"
futures-util = "0.3"  # Already present for streams
```

## Critical Files (Full Paths)

- `C:\Users\MikeSwanson\Claude\guru-connect\proto\guruconnect.proto`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\main.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\session\mod.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\agent\src\update.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\main.rs`
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\api\releases.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\src\db\releases.rs` (NEW)
- `C:\Users\MikeSwanson\Claude\guru-connect\server\migrations\`
- `C:\Users\MikeSwanson\Claude\guru-connect\server\static\dashboard.html`

## Testing Checklist

- [ ] Agent reports version to server on connect
- [ ] GET /api/version returns correct latest version
- [ ] Agent periodic check detects update available
- [ ] Admin can trigger update from dashboard
- [ ] Download completes successfully
- [ ] Checksum verification works (reject bad downloads)
- [ ] Exe rename/copy/restart works on Windows
- [ ] .old file cleaned up on restart
- [ ] Failed update doesn't break current installation
- [ ] Offline agents get update when they reconnect
- [ ] Dashboard shows correct version and status