From 2a1ccfac737bb3adb36a1a882cc1a003546a1e81 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Mon, 1 Jun 2026 15:21:56 -0700 Subject: [PATCH] Add memory-dream skill + additive cross-machine memory sync memory-dream: read-only memory lint/consolidation analyzer (index, backlinks, stale refs, dup clusters, profile drift); additive-only --apply-safe, all merges/deletes are proposals. sync-memory.sh: additive repo<->harness-profile union (no delete/overwrite, conflicts surfaced), wired to a SessionStart hook. Migrates the useful profile-only memories into the synced repo store. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/memory/MEMORY.md | 2 + .claude/memory/feedback_client_tone.md | 16 + .claude/memory/feedback_entra_app_owner.md | 20 + .claude/memory/feedback_gururmm_builds.md | 14 + .../feedback_no_toml_config_endpoints.md | 16 + .claude/memory/feedback_python_windows.md | 11 + .../feedback_scheduling_via_coord_todo.md | 12 + .claude/memory/feedback_syncro_billing.md | 16 + .../memory/feedback_syncro_comment_dedup.md | 20 + .claude/memory/feedback_syncro_html.md | 17 + .claude/memory/feedback_syncro_labor_tax.md | 14 + .claude/memory/feedback_syncro_line_items.md | 24 + .claude/memory/feedback_syncro_live_rates.md | 18 + .../memory/project_azcomputerguru_hosting.md | 11 + .claude/memory/project_cascades_billing.md | 14 + .claude/memory/project_dataforth_email.md | 13 + ...project_memory_consolidation_automation.md | 14 + .claude/memory/project_pluto_build_server.md | 18 + .claude/memory/reference_gitea_internal.md | 32 + .claude/scripts/sync-memory.sh | 333 +++++++ .claude/settings.json | 11 + .claude/skills/memory-dream/SKILL.md | 131 +++ .../memory-dream/scripts/memory_dream.py | 903 ++++++++++++++++++ .../skills/memory-dream/scripts/selftest.py | 195 ++++ 24 files changed, 1875 insertions(+) create mode 100644 .claude/memory/feedback_client_tone.md create mode 100644 .claude/memory/feedback_entra_app_owner.md create mode 100644 .claude/memory/feedback_gururmm_builds.md create mode 100644 .claude/memory/feedback_no_toml_config_endpoints.md create mode 100644 .claude/memory/feedback_python_windows.md create mode 100644 .claude/memory/feedback_scheduling_via_coord_todo.md create mode 100644 .claude/memory/feedback_syncro_billing.md create mode 100644 .claude/memory/feedback_syncro_comment_dedup.md create mode 100644 .claude/memory/feedback_syncro_html.md create mode 100644 .claude/memory/feedback_syncro_labor_tax.md create mode 100644 .claude/memory/feedback_syncro_line_items.md create mode 100644 .claude/memory/feedback_syncro_live_rates.md create mode 100644 .claude/memory/project_azcomputerguru_hosting.md create mode 100644 .claude/memory/project_cascades_billing.md create mode 100644 .claude/memory/project_dataforth_email.md create mode 100644 .claude/memory/project_memory_consolidation_automation.md create mode 100644 .claude/memory/project_pluto_build_server.md create mode 100644 .claude/memory/reference_gitea_internal.md create mode 100644 .claude/scripts/sync-memory.sh create mode 100644 .claude/skills/memory-dream/SKILL.md create mode 100644 .claude/skills/memory-dream/scripts/memory_dream.py create mode 100644 .claude/skills/memory-dream/scripts/selftest.py diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md index f45f3cb..735f693 100644 --- a/.claude/memory/MEMORY.md +++ b/.claude/memory/MEMORY.md @@ -29,6 +29,7 @@ - [Howard Enos](user_howard.md) — Mike's brother, technician, full access. Machines: ACG-TECH03L, Howard-Home (authoritative in users.json). ## Feedback +- [Scheduling = coord todo, not schedulers](feedback_scheduling_via_coord_todo.md) — Defer future work as a coord todo (POST /api/coord/todos; needs text + created_by_user + created_by_machine) for a later session to pick up. NOT /schedule remote CCR agents (no vault/creds there) or local scheduled tasks. - [Identify RMM agent by IP](feedback_rmm_identify_by_ip.md) — When the target machine is known by external IP, match the IP to find the agent; don't recon every candidate. (GuruRMM doesn't store agent IPs yet — todo 7459428e.) - [Attribution is read, never inferred](feedback_attribution_from_identity.md) — Who-did-what (user+machine) comes ONLY from identity.json + users.json + git authorship. Never infer from hostname patterns, the userEmail hint, or memory. The "5070" box is Mike's. sync.sh reconciles git config to identity.json; /save renders the User block via whoami-block.sh. - [GuruRMM agent parity rule](feedback_gururmm_agent_parity.md) — "Add feature X to the agent" = Windows + Linux + macOS in the same change, no exceptions. Stub + TODO if real impl not feasible. @@ -79,6 +80,7 @@ - [Mac gururmm setup pending](project_mac_gururmm_setup_pending.md) — ACTION REQUIRED: run `bash scripts/install-hooks.sh` in gururmm repo on Mikes-MacBook-Air before any RMM work ## Project +- [Automate memory consolidation/lint (phased)](project_memory_consolidation_automation.md) — Eventually auto-run /memory-dream; lint+additive fixes can automate early, merges/deletes stay human-approved. Engine: .claude/skills/memory-dream/ + .claude/scripts/sync-memory.sh. - [RMM webhook docs-only build guard](project_rmm_webhook_docs_guard.md) — RMM build webhook skips docs-only pushes (host guard in /opt/gururmm/webhook-handler.py, SPEC-020 Phase 0); repo copy is stale, don't redeploy it - [GuruConnect v2 direction](project_guruconnect_v2_direction.md) — v2 re-architecture (SPEC-002, 2026-05-29): greenfield-salvage-cores, NATIVE-first (full key fidelity Win+R/Ctrl+Alt+Del + bidirectional file cut/paste/drag are Mike's headline must-haves; WebRTC fallback only), standalone-first + RMM contract, hardened single-tenant but tenancy-ready schema. Willing to scrap v1 entirely. - [Apple MDM + Developer certs (GuruRMM mobile)](project_apple_mdm_certs.md) — ACG holds both Apple Developer+signing and Apple MDM Push certs (acquired 2026-05-29) for SPEC-017 mobile support. MDM push cert RENEWS ANNUALLY on the same Apple ID or all enrolled iOS devices break. Capture Apple ID + expiry. diff --git a/.claude/memory/feedback_client_tone.md b/.claude/memory/feedback_client_tone.md new file mode 100644 index 0000000..811ea95 --- /dev/null +++ b/.claude/memory/feedback_client_tone.md @@ -0,0 +1,16 @@ +--- +name: Client communication tone +description: How to write client-facing Syncro comments — expert partner, not intake questionnaire +type: feedback +originSessionId: 4ccedc24-2f39-497e-9a89-ca09aba03982 +--- +Write client comments from the position of a senior MSP that has managed the client for years. State findings, state what we did or are doing, ask only for the one specific thing we genuinely don't know. + +**Why:** ACG has managed clients like GlazTech for 10-15 years. We know their locations, key staff, infrastructure, and service accounts. Comments that ask "can you tell us about your setup?" or list basic discovery questions make us look like we just walked in the door. + +**How to apply:** +- Lead with what we found and what we already know +- Frame questions as targeted confirmations, not open-ended discovery ("Is FaxFinder authenticating via SMTP basic auth, or has that been migrated to OAuth?" — not "What does the FaxFinder account do?") +- Never ask the client to explain their own infrastructure to us unless Mike explicitly says we don't have context +- Steve Eastman (seastman@glaztech.com) is GlazTech's internal IT person — desktop-level tech, guides technical direction, ~200 users across 9 locations. We implement what he directs. Treat him as a peer, not an end user. +- If we're missing context (IPs, staff roles, auth methods), check session logs and vault first. Ask Mike privately before asking the client. diff --git a/.claude/memory/feedback_entra_app_owner.md b/.claude/memory/feedback_entra_app_owner.md new file mode 100644 index 0000000..d4c4059 --- /dev/null +++ b/.claude/memory/feedback_entra_app_owner.md @@ -0,0 +1,20 @@ +--- +name: Add Mike as owner on all Entra apps +description: Apps created via management SP have no user owner — must add Mike manually or publisher verification fails +type: feedback +originSessionId: 045c6ef2-5711-4aca-b86f-55506c9b6ada +--- +After creating any Entra app registration via the ComputerGuru-Management service principal, always add Mike (f34ebe40-9565-4135-af4c-2e808df57a25) as an owner immediately. + +**Why:** Apps created via client credentials have no user owner. Microsoft requires a user owner to perform publisher verification (MPN badge). Without this step, the portal shows "A verified publisher cannot be added to this application." + +**How to apply:** After every `POST /v1.0/applications` call, immediately run: +```bash +curl -sk -X POST \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + "https://graph.microsoft.com/v1.0/applications/{APP_OBJ_ID}/owners/\$ref" \ + -d '{"@odata.id":"https://graph.microsoft.com/v1.0/directoryObjects/f34ebe40-9565-4135-af4c-2e808df57a25"}' +``` + +Mike's user object ID: `f34ebe40-9565-4135-af4c-2e808df57a25` diff --git a/.claude/memory/feedback_gururmm_builds.md b/.claude/memory/feedback_gururmm_builds.md new file mode 100644 index 0000000..3490a5a --- /dev/null +++ b/.claude/memory/feedback_gururmm_builds.md @@ -0,0 +1,14 @@ +--- +name: feedback-gururmm-builds +description: "GuruRMM builds must go through the Gitea webhook pipeline, never run manually via SSH" +metadata: + node_type: memory + type: feedback + originSessionId: 541d4004-8c45-4290-89f5-0ba9ee4e64a9 +--- + +Never run `build-agents.sh` directly via SSH. All builds go through the normal Gitea webhook pipeline (push to main triggers the build automatically). + +**Why:** Manual runs execute as the SSH user (`guru`) instead of root, breaking log writes, artifact cleanup, and service restarts. The pipeline exists precisely to handle this correctly. + +**How to apply:** To trigger a build, push a commit to the gururmm main branch on Gitea. If a test build is needed without a real change, use an empty commit: `git commit --allow-empty -m "chore: trigger build"`. diff --git a/.claude/memory/feedback_no_toml_config_endpoints.md b/.claude/memory/feedback_no_toml_config_endpoints.md new file mode 100644 index 0000000..87d18fe --- /dev/null +++ b/.claude/memory/feedback_no_toml_config_endpoints.md @@ -0,0 +1,16 @@ +--- +name: No TOML/config file approach for endpoints +description: User explicitly prohibits TOML or config-file-based endpoint configuration — this will never be approved +type: feedback +originSessionId: 50d853e9-1d2f-4094-9b7b-f509fb95891f +--- +Never propose storing endpoint URLs, server addresses, API targets, or connection parameters in TOML files, config files, INI files, or any file-based config approach when it comes to deployed agents or endpoints. + +**Why:** User stated directly: "I cannot stand the toml/config file approach to anything when it comes to endpoints" and "that approach will never be approved by me/the user." + +**How to apply:** When designing agent deployment, enrollment, or configuration: +- Embed endpoint/server data directly in the binary (compile-time constants, build flags, or baked into the installer) +- Use registry keys (Windows) for anything that must be configurable post-install +- Use MSI properties for install-time configuration +- Never write agent.toml, config.toml, settings.ini, or equivalent files containing server URLs or connection endpoints +- This applies to GuruRMM agent and any future agent/endpoint projects diff --git a/.claude/memory/feedback_python_windows.md b/.claude/memory/feedback_python_windows.md new file mode 100644 index 0000000..e7b4758 --- /dev/null +++ b/.claude/memory/feedback_python_windows.md @@ -0,0 +1,11 @@ +--- +name: Python on Windows — use py launcher +description: Windows Store python/python3 aliases disabled; always use py or jq on DESKTOP-0O8A1RL +type: feedback +originSessionId: bdd13bc7-44b1-4e16-aba8-a3332b0c8b8e +--- +Always use `py` (Windows launcher) for Python on this machine, never `python3` or bare `python`. + +**Why:** Windows Store app execution aliases for python.exe and python3.exe were disabled (2026-04-20). `python3` now fails cleanly (command not found). `py` at `C:\Windows\py.exe` is the correct entry point and reliably finds Python 3.14 at `C:\Program Files\Python314\python.exe`. + +**How to apply:** In any script, doc, or inline command that needs Python: use `py`. For simple JSON extraction from curl output, prefer `jq` (available at `C:\Users\guru\AppData\Local\Microsoft\WinGet\Links\jq.exe`) — no Python needed at all. diff --git a/.claude/memory/feedback_scheduling_via_coord_todo.md b/.claude/memory/feedback_scheduling_via_coord_todo.md new file mode 100644 index 0000000..ce9a313 --- /dev/null +++ b/.claude/memory/feedback_scheduling_via_coord_todo.md @@ -0,0 +1,12 @@ +--- +name: feedback_scheduling_via_coord_todo +description: Defer/schedule future work as a coord todo for a later session to pick up - NOT remote CCR routines or local scheduled tasks +metadata: + type: feedback +--- + +When something needs to happen later ("check this tomorrow", "verify in 24-48h", "follow up next week"), create a **coord todo** (`POST /api/coord/todos`) assigned to the right user/project. A future ClaudeTools session picks it up at session-start. Do NOT use the `/schedule` skill (remote anthropic_cloud CCR agents) or local OS scheduled tasks. + +**Why:** Mike's directive 2026-06-01. Remote cloud routines have NO access to the local SOPS vault, the age key, B2/Discord/API creds, or identity.json - so any credentialed task fails there. Local scheduled tasks need the box powered on and run blind. The coord API is the team's shared source of truth and every session already reads pending todos on startup, so a todo is the reliable, credential-available, multi-machine handoff. + +**How to apply:** `POST http://172.16.3.30:8001/api/coord/todos`. REQUIRED fields the CLAUDE.md doc omits: `text` (the todo body - NOT `title`/`description`), `created_by_user`, `created_by_machine` (read user+machine from `.claude/identity.json`). Optional: `project_key`, `assigned_to_user`, `auto_created`, `source_context`, `parent_id`. Put enough context in `text` (commands, exact targets, the when) that a cold session can act without re-deriving. See [[reference_coord_messages_api_shape]]. diff --git a/.claude/memory/feedback_syncro_billing.md b/.claude/memory/feedback_syncro_billing.md new file mode 100644 index 0000000..d7991c4 --- /dev/null +++ b/.claude/memory/feedback_syncro_billing.md @@ -0,0 +1,16 @@ +--- +name: Syncro - preview all comments before posting +description: Every Syncro comment must be previewed and confirmed before posting, no exceptions +type: feedback +originSessionId: 4ccedc24-2f39-497e-9a89-ca09aba03982 +--- +**Rule:** ALWAYS show the full comment text to Mike and wait for explicit confirmation before posting ANY comment to a Syncro ticket. No exceptions — not for billing comments, not for resolution notes, not for client-facing messages, not for internal notes. + +**Why:** Mike has called this out multiple times. Comments posted without preview have had wrong tone, missing context, or incorrect content. Once posted they can't be deleted via API and require manual GUI cleanup. + +**How to apply:** +- Draft the comment, show it in chat as a formatted block +- Say "Good to post?" or similar and wait for a yes +- Only then call POST /tickets/{id}/comment +- This applies to every single comment regardless of how routine it seems +- Also always ask for minutes + labor type before logging any time entry — never assume a default diff --git a/.claude/memory/feedback_syncro_comment_dedup.md b/.claude/memory/feedback_syncro_comment_dedup.md new file mode 100644 index 0000000..f1d8fe6 --- /dev/null +++ b/.claude/memory/feedback_syncro_comment_dedup.md @@ -0,0 +1,20 @@ +--- +name: Syncro duplicate prevention — tickets AND comments +description: Never retry ANY Syncro POST (ticket create or comment) without first GETting to confirm the action didn't already succeed — Syncro has no idempotency on any endpoint +type: feedback +originSessionId: 7034be43-1464-4085-b765-dc1226b1f8e0 +--- +Never retry a POST /comment to Syncro without first doing GET /tickets/{id} to confirm the comment did not already post. The server has no idempotency — one POST always creates one comment, regardless of whether the client saw an error. + +**ALSO: Always show the full comment draft to the user and wait for explicit confirmation before posting ANY comment — including internal/hidden notes.** This rule has been violated twice. There are no exceptions. + +**ALSO: This applies to ticket CREATION too — not just comments.** When a POST /tickets response looks wrong (null fields, jq error, etc.), do GET /customers/{id}/tickets BEFORE retrying. The response wrapper is `{"ticket": {...}}` — always use `.ticket.id` not `.id`. Duplicate tickets were created twice by retrying a succeeded POST. Violated 2026-04-22. + +**Why:** A comment was duplicated on ticket #32185 because the first POST succeeded but jq threw a parse error on the response (em-dash in subject caused shell interpolation issue), making the request look failed. A retry posted a second copy. Comments cannot be deleted via API — duplicates require manual GUI removal. + +**How to apply:** +- Always write comment payloads to a temp file (`/tmp/syncro_comment.json`) before posting — avoids shell quoting/encoding failures that produce misleading errors +- If any POST /comment tool call returns an error or ambiguous result, immediately GET /tickets/{id} and check `.ticket.comments` for the subject/timestamp before retrying +- A jq parse error, curl error, or timeout on the response does NOT mean the POST failed — verify first +- **CRITICAL — jq path:** POST /comment response is `{"comment": {...}}` — ALWAYS use `.comment.id`, `.comment.created_at` etc. Using `.id` returns null and looks like failure even when the comment landed. This caused a duplicate on 2026-04-23 (#32142). When GETting to verify, check ALL comments not just `[-3:]` — the new comment may not be the most recent if other activity occurred. +- When GETting to verify after an ambiguous POST, search by subject: `.ticket.comments[] | select(.subject == "...")` diff --git a/.claude/memory/feedback_syncro_html.md b/.claude/memory/feedback_syncro_html.md new file mode 100644 index 0000000..5884666 --- /dev/null +++ b/.claude/memory/feedback_syncro_html.md @@ -0,0 +1,17 @@ +--- +name: Syncro comment HTML formatting +description: Use
for line breaks in Syncro comments, not