# Session Log — 2026-05-29 ## User - **User:** Mike Swanson (mike) - **Machine:** GURU-5070 - **Role:** admin ## Session Summary Shaped a pre-implementation spec for native integrated remote control in the GuruRMM ecosystem, then restructured how the guru-connect product is tracked in the monorepo. The session began as a "fix lint errors" request that was redirected into a GuruRMM feature request for the guru-connect (GC) project: native, integrated remote control comparable to ScreenConnect/Splashtop, built entirely on our own Rust stack to avoid third-party agents and supply-chain exposure. Research established that GC already implements the full remote-control engine (DXGI/GDI capture, input injection, viewer, `guruconnect://` protocol handler, persistent/unattended + support-code/attended modes, protobuf over WSS) and that GuruRMM already has the orchestration rails (per-agent command dispatch, stable `device_id` identity, the AgentDetail action-button pattern, and a half-built generic `tunnel` scaffold). Two parallel Explore agents mapped the exact integration surfaces with file:line references. The feature is therefore ~80% wiring against existing capability, not greenfield. Architecture decisions were captured via the user: broker model (RMM orchestrates the separate GC agent), both unattended and attended access, multi-monitor in scope, file transfer / session recording / non-Windows agents out of scope, priority P2. The `/shape-spec` skill produced four files in `projects/msp-tools/guru-connect/specs/native-remote-control/` (shape, plan, references, standards). The user then clarified that GC is a standalone product with its own pipeline/cadence, and the real intent is a durable, versioned integration contract so the two products stay integration-compatible without coupling. The spec was rewritten around a GC-owned, semver'd integration contract (`/api/integration/v1/`, capability discovery, embedded session viewer). A concrete blocker was identified: GC's `security_headers.rs` sets `frame-ancestors 'none'`, which must be relaxed to a scoped RMM-origin allowlist for the embedded viewer. RMM-side hints were added (ADR-008 + `docs/GURU_CONNECT_INTEGRATION.md`) recording that RMM consumes GC via the contract and does no active dev on GC. The spec and hints were committed across both repos (commit-only, no push). The user then asked to wire GC as a submodule like guru-rmm. Investigation revealed the remote `azcomputerguru/guru-connect` repo was ~4 months stale (frozen 2026-01-18) while the local monorepo copy was far ahead (entire `middleware`/`metrics`/`utils` modules, token blacklist, Phase-1 security/deploy work, the new spec). Per the user's decisions (publish local to the existing repo as a snapshot commit; preserve history), the Gitea Agent published the local working state to GC main (fast-forward `5b7cf5f..e3e95f8`, history preserved, KEEP paths `.gitignore`/`.cargo`/`server/static/downloads` retained), then converted the vendored directory into a submodule pinned at `e3e95f8`. Confirmed that GC `deploy.yml` triggers only on `v*.*.*` tags / manual dispatch, so the push ran CI build/test but did not deploy to production. Finally, the user confirmed RMM and GC are the only versionable products; everything else stays in the monorepo. This policy was recorded to memory (`project_versionable_products.md`). ## Key Decisions - Broker architecture: RMM orchestrates the separate GC agent (two agents coexist) rather than merging GC into the RMM agent — reuses GC's existing engine, ships sooner, keeps GC standalone. - The deliverable is a GC-owned, semver'd integration contract + capability discovery, not one-off broker wiring — so the two products stay in-sync via the contract without sharing pipelines or releasing in lockstep. - Stable cross-product identity = RMM `device_id` passed as the GC `agent_id`, so brokered sessions deterministically match the endpoint. - Supply-chain guard made concrete: the RMM agent downloads the GC binary only from GC's release channel and verifies SHA-256 before launch (reusing GC's `releases.checksum_sha256`). - Embedded viewer over native-only: relax `frame-ancestors`/`X-Frame-Options` on the viewer route to a scoped RMM-origin allowlist; keep `'none'` everywhere else. - Spec lives in the GC repo (GC owns the contract); RMM gets ADR-008 + a pointer doc reminding it not to perform active dev on GC. - Submodule reconciliation: publish the local (authoritative) state up to the stale GC repo as a snapshot commit on top of existing main (preserve history), then submodule-add — nothing lost. - Only GuruRMM and GuruConnect are versionable products (own repos/submodules); all other projects stay in the claudetools monorepo. Split only for an independent pipeline OR a versioned external consumer. - All git operations committed but NOT pushed (claudetools), per the established pattern of leaving the push to the user; the GC repo push was mandatory for the submodule to resolve. ## Problems Encountered - Initial "fix lint errors" request was ambiguous (clean tree, multiple lintable projects). Asked which project; user redirected to the GC feature request instead. - CLAUDE.md warns that a Gitea repo named `guru-connect` is an "abandoned duplicate." Verified by inspecting the remote repo's contents (`proto/guruconnect.proto`, `agent/`, `server/`, `dashboard/`) that `azcomputerguru/guru-connect` is the real GC product, not the abandoned RMM duplicate the warning refers to. - The remote GC repo was 4 months stale and the local monorepo copy had diverged substantially (whole modules + Phase-1 work never pushed). A naive `submodule add` would have reverted that work. Resolved by diffing local vs remote, surfacing the divergence, and publishing local→remote before converting. - Production-deploy risk on push: checked GC's `.gitea/workflows`; confirmed `deploy.yml` triggers only on `v*.*.*` tags / `workflow_dispatch`, so pushing to main runs CI but does not deploy. ## Configuration Changes Created (committed `afbe5a8`, then moved into the GC repo via the submodule conversion): - `projects/msp-tools/guru-connect/specs/native-remote-control/shape.md` - `projects/msp-tools/guru-connect/specs/native-remote-control/plan.md` - `projects/msp-tools/guru-connect/specs/native-remote-control/references.md` - `projects/msp-tools/guru-connect/specs/native-remote-control/standards.md` guru-rmm submodule (committed `7701d26` in the submodule): - Modified `docs/ARCHITECTURE_DECISIONS.md` — added ADR-008 (GC is a separate product consumed via versioned contract) - Created `docs/GURU_CONNECT_INTEGRATION.md` — RMM-side boundary/pointer doc Repo structure: - `.gitmodules` — added `projects/msp-tools/guru-connect` submodule entry (branch main) - `projects/msp-tools/guru-connect` — converted from vendored directory to submodule (gitlink mode 160000 at `e3e95f8`) Memory: - Created `.claude/memory/project_versionable_products.md` - Updated `.claude/memory/MEMORY.md` index (Project section) ## Credentials & Secrets None discovered or created this session. The spec references secrets to be sourced from env/SOPS at implementation time (`CONNECT_INTEGRATION_KEY`, `CONNECT_SERVER_URL`, per-machine GC agent keys, `CONNECT_EMBED_ALLOWED_ORIGINS`) — none provisioned yet. ## Infrastructure & Servers - Gitea (internal): http://172.16.3.20:3000 — used for repo inspection + GC push (per internal-API preference) - GC relay server: 172.16.3.30:3002, proxied via NPM to connect.azcomputerguru.com - GuruRMM server: 172.16.3.30:3001, dashboard rmm.azcomputerguru.com - GC repo CI: `.gitea/workflows/{build-and-test,test,deploy}.yml` — deploy only on `v*.*.*` tags / manual dispatch ## Commands & Outputs Repo divergence check (local vs remote GC), shallow clone + `diff -rq` — confirmed local far ahead; cleaned up temp clone afterward. GC publish (Gitea Agent): - `git push origin main` → `5b7cf5f..e3e95f8 main -> main` (fast-forward, 73 files changed, 15611 insertions, 5760 deletions; `Cargo.lock` dropped — not tracked in the authoritative copy) Submodule conversion (Gitea Agent): - `git rm -r --cached projects/msp-tools/guru-connect` + `rm -rf` + `git submodule add -b main ` - `git submodule status` → `e3e95f8 ... guru-connect (heads/main)`, `7701d26 ... guru-rmm (heads/main)` ## Pending / Incomplete Tasks - claudetools commits are LOCAL, not pushed: `53e14da` (submodule conversion) + `1fc2401`/`afbe5a8` (spec + pointer bump) from earlier. Push when ready. - GC repo housekeeping: re-add `Cargo.lock` (dropped in the snapshot; wanted for reproducible builds). - GC submodule URL uses the internal IP `172.16.3.20:3000`; guru-rmm uses the public `git.azcomputerguru.com`. Off-network clones (Howard's Mac) won't resolve the internal IP — consider switching to the public hostname for parity. - GC CI run kicked off by the publish push may be red (the snapshot may not build cleanly; Cargo.lock removed). Check the Actions run. - Implementation of the feature itself has not started — Task 0 of the spec (commit the spec) is effectively satisfied; Tasks 1+ are not begun. ## Reference Information - Spec: `projects/msp-tools/guru-connect/specs/native-remote-control/` (4 files) — now in the GC repo at `e3e95f8` - ADR: `projects/msp-tools/guru-rmm/docs/ARCHITECTURE_DECISIONS.md` ADR-008 - RMM pointer: `projects/msp-tools/guru-rmm/docs/GURU_CONNECT_INTEGRATION.md` - GC repo: `azcomputerguru/guru-connect`; published `5b7cf5f → e3e95f8` - guru-rmm submodule commit: `7701d26` - claudetools commits: `afbe5a8` (spec), `1fc2401` (submodule ptr bump for ADR), `53e14da` (GC submodule conversion) - Roadmap context: `projects/msp-tools/guru-rmm/docs/FEATURE_ROADMAP.md:635-675`, `docs/UI_GAPS.md:155-186` - Key GC integration files: `server/src/middleware/security_headers.rs:30,37-39` (frame-ancestors), `server/static/viewer.html`, `server/src/relay/mod.rs:187` (agent key validation), `server/src/main.rs:300` (`/api/version`) - Key RMM files: `server/src/api/commands.rs:87-157` (command dispatch), `agent/src/device_id.rs`, `dashboard/src/pages/AgentDetail.tsx:1893-1931`