Build Roadmap

MSPclaw: What's Done,
What's Next

SuperOps bridge is working end-to-end. The core engine, playbooks, and WebSocket protocol are solid. Four focused sprints to get from demo-ready to production-ready.

github.com/thisisprabha/MSPclaw SuperOps integration: bridge.py working v0.3 shipped 2026-06-04, macOS only
01

What's Already Built

v0.3 shipped — production-hardened v0.3 added API auth, human approval gates, full audit trail, device memory, feedback metrics, structured escalation, and technician registry. The engine is now production-ready. What's still missing is integration plumbing: asset mapping and webhook trigger.
ComponentWhat existsStatus
Orchestration engine ReAct reasoning loop (Thought/Action/Observation), max 12 steps, LLM-agnostic (OpenAI / Gemini / Claude / Ollama). Retry logic + error recovery added in v0.3. DONE
Playbook matcher 15 YAML playbooks: password reset, printer, WiFi, VPN, slow PC, onboarding, offboarding, disk, email, software install. Keyword + OS matching. DONE
WebSocket dispatcher Persistent server-to-agent connections. Handles approvals, questions, async resume, duplicate question detection. DONE
Agent daemon Runs on client Mac. 17 tools: real macOS diagnostics + mock enterprise APIs (AD, M365, Jamf, VPN, printer, SharePoint). DONE
SuperOps bridge GraphQL read (getTicket, getTicketList) + write-back (createTicketNote). WebSocket loop with approval handling. bridge.py working. DONE
Auth / API key Bearer token required on all endpoints. Read from MSPCLAW_API_KEY env var. Shipped in v0.3 (server/auth.py). JWT + RBAC planned for v0.4. DONE v0.3
Human approval gates Destructive tools (reset_password, disable_ad_account) require live tech approval before execution. Auto-deny after 5 minutes. Configured per playbook via requires_approval list. DONE v0.3
Audit trail Append-only JSONL per day + SQLite audit_events table. Records all tool calls, approvals, questions, resolutions. CLI: mspclaw audit. DONE v0.3
Device memory Agent remembers user name, department, floor from prior sessions. Never re-asks known info. Enriches brain context from second session onward. CLI: mspclaw devices. DONE v0.3
Resolution feedback Users confirm if the fix worked (yes/no/partial). Per-playbook resolution rates tracked. CLI: mspclaw stats shows success rate per playbook. DONE v0.3
Structured escalation When stuck, brain packages: what was tried + why it failed + suggested next steps. Webhook notification to Slack/Teams. Stored in escalations table. DONE v0.3
Technician registry YAML-backed tech registry (techs.yaml). Tracks name, email, role, Slack ID. Used for approval attribution and escalation routing. CLI: mspclaw tech add/list/remove. DONE v0.3
Asset mapping Still hardcoded to one MACHINE_ID in bridge.py. Multi-client routing not built. This is the current blocker for multi-tenant use. BLOCKER
Webhook trigger Bridge still runs manually (python bridge.py ticket_id). No auto-trigger from SuperOps on ticket create. NEXT
Real enterprise APIs M365 password reset, AD unlock, Jamf, printer, VPN are all realistic mocks. No real API calls yet. NEXT
Windows playbooks All 15 playbooks are macOS only. Windows paths, commands, and tools not yet written. LATER
ConnectWise / Halo connectors Bridge template documented in GUIDE.md. REST calls documented. Not implemented. LATER
Docker / deployment Manual install scripts only. No container builds yet. LATER

02

How the Full Loop Works Now

Current working flow (SuperOps + MSPclaw + macOS agent)
1. MANUAL python bridge.py <ticket_id>
|
2. PULL bridge.py calls SuperOps GraphQL → gets ticket subject
|
3. SEND bridge.py opens WebSocket to MSPclaw server → sends subject + client_id
|
4. MATCH MSPclaw matches subject to playbook (keyword scoring)
|
5. REASON Brain (Claude/OpenAI) runs ReAct loop → decides tool calls
|
6. EXECUTE Dispatcher sends tool calls → agent on Mac runs them → returns results
|
7. APPROVE Bridge handles approval_request messages (auto or interactive)
|
8. WRITE bridge.py gets final_answer → calls createTicketNote on SuperOps
|
GAP: Step 1 is manual. Step 3 uses one hardcoded client_id. No Windows.

03

The Asset Mapping Problem (Blocker)

Right now MACHINE_ID is hardcoded in bridge.py. In a real MSP with 50 client companies and 500 devices, you need to know: when ticket T comes in from client C, which registered agent should execute the playbook?

The mapping needed SuperOps ticket has a client/company field. Each company's devices should map to a registered MSPclaw agent. The bridge needs a lookup table: company_id → list of client_ids (agent machine IDs). For user-reported tickets, you also need: requester's device → specific client_id.
# What bridge.py needs instead of hardcoded MACHINE_ID # Option A: Company-level mapping (simpler, v1) COMPANY_AGENT_MAP = { "superops_company_id_123": "macbook-prabha.local-abc123", # one agent per company "superops_company_id_456": "macbook-client2.local-def456", } # Option B: Device-level mapping (v2, more precise) DEVICE_AGENT_MAP = { "device_hostname_or_serial": "mspclaw_client_id", } # bridge.py fetches ticket, extracts company_id, looks up agent ticket = fetch_ticket(ticket_id) company_id = ticket["client"]["clientId"] client_id = COMPANY_AGENT_MAP.get(company_id) # Or: DB table in MSPclaw server (better long-term) # Agents register with server and store their company mapping # Server exposes GET /agents?company_id=123 for bridge to query

For v1, a simple config file or environment variable mapping is fine. The MSPclaw DB already has a Client table that could store this mapping. Long-term: agents register with a company_id and the server exposes a lookup endpoint.


04

Sprint 1: Fix Asset Mapping

Unblock multi-client routing. Without this, MSPclaw only works for one device. This is the single highest-priority task.

Sprint 1 tasks Estimated: 1-2 days
Add company_id field to agent registration
When agent daemon starts and registers with the server, it sends its company_id (mapped to the MSP client it belongs to). Server stores this in the Client table.
agent/main.py + server/db/models.py
DO FIRST
Expose GET /agents endpoint on server
Bridge queries this to find the right client_id for a given company. Returns list of registered agents for a company_id.
server/main.py
DO FIRST
Update bridge.py to resolve client_id dynamically
Pull company_id from SuperOps ticket (client.clientId field). Query /agents endpoint. Use returned client_id for the WebSocket job. Fallback to config file if server unreachable.
bridge.py (superops-playground)
DO FIRST
Add company lookup to SuperOps getTicket query
Current query doesn't fetch the client/company field. Add client { clientId name } to the GraphQL query in bridge.py.
bridge.py: getTicket query
DO FIRST

05

Sprint 2: Webhook Trigger (Auto-trigger on Ticket Create)

Right now the bridge runs manually. The goal is: new ticket created in SuperOps automatically triggers MSPclaw with no human intervention.

SuperOps webhook support SuperOps supports outbound webhooks on ticket events. You configure a webhook URL in SuperOps settings. On ticket create, SuperOps POSTs the ticket payload to your URL. The bridge needs an HTTP listener to receive this and kick off the loop.
Sprint 2 tasks Estimated: 1-2 days
Add POST /webhook/superops to MSPclaw server
Receives SuperOps ticket created payload. Extracts subject, client company_id, ticket_id. Looks up agent. Starts playbook job. Returns 200 immediately (async job).
server/main.py
NEXT
Write-back after job completes
When job reaches "resolved" state, server automatically calls SuperOps createTicketNote with the final_answer. No manual bridge.py needed.
server/brain/orchestrator.py + new superops_client.py
NEXT
Playbook filter: only trigger on L1 categories
Not every ticket should trigger MSPclaw. Add a category/keyword filter so only tickets that match a known playbook get routed. Others are skipped silently.
server/playbooks/loader.py + webhook handler
NEXT
Webhook signature validation
Verify the request actually came from SuperOps (HMAC signature or shared secret). Basic security before exposing to the internet.
server/main.py
NEXT
Configure SuperOps webhook in settings
In SuperOps admin: Settings > Integrations > Webhooks. Set URL to https://your-server/webhook/superops. Trigger: Ticket Created. That's it.
SuperOps admin UI (no code)
NEXT

06

Sprint 3: Swap Mocks for Real APIs

Mock enterprise tools in agent/tools/mock_enterprise.py return realistic JSON but don't call real APIs. Priority order: password/AD first (highest ticket volume), then printer, then the rest.

Sprint 3 tasks, in priority order Estimated: 1-2 weeks
Microsoft Entra ID: check_ad_user, reset_password, unlock_account
Replace mock with real Microsoft Graph API calls. Needs M365 app registration (app_id, tenant_id, client_secret). Covers password reset and account locked playbooks.
agent/tools/enterprise_m365.py (new)
HIGH
Microsoft Graph: check_m365_license, disable_ad_account, provision_user
Same app registration as above. Covers onboarding and offboarding playbooks.
agent/tools/enterprise_m365.py
HIGH
Print server: check_printer_status, restart_print_spooler
Real Windows print server calls or local spooler management via PowerShell. Covers printer playbook.
agent/tools/enterprise_print.py (new)
MEDIUM
Jamf Pro: check_jamf_device, push_jamf_policy, install_software_jamf
Jamf REST API (api/v1/). Needs Jamf URL + API client credentials. Covers software install and device management playbooks.
agent/tools/enterprise_jamf.py (new)
MEDIUM
Exchange / M365: check_email_flow
Microsoft Graph mail API. Check mailbox status, message trace. Covers email not working playbook.
agent/tools/enterprise_m365.py
MEDIUM
VPN: check_vpn_status
Depends on VPN vendor (GlobalProtect, Cisco, etc.). Varies by client. Implement as pluggable adapter.
agent/tools/enterprise_vpn.py (new)
LOW

07

Sprint 4: Windows Playbooks + User-Facing Replies

Sprint 4 tasks Estimated: 1 week
Windows agent: port tools to PowerShell equivalents
get_system_info, check_disk_usage, list_top_processes, check_temp_files. All have direct PowerShell equivalents. Windows agent runs as a service (NSSM or Task Scheduler).
agent/tools/windows/ (new directory)
LATER
Windows playbooks: slow PC, disk cleanup, printer
Copy macOS playbooks, update os: field to windows, update tool names to Windows equivalents. Start with the 5 highest-volume L1 scenarios.
playbooks/windows/ (new directory)
LATER
User-facing reply templates
For user-reported tickets, the write-back should include a public note to the requester, not just an internal note. Add a template field to playbooks: requester_reply_template. Bridge picks PUBLIC vs PRIVATE per playbook.
playbooks/*.yaml + bridge.py
LATER
Ticket status update on resolution
After auto-resolve, call SuperOps updateTicket to set status = Resolved (or In Progress if escalating). Currently only notes are written back.
superops_client.py (or bridge.py)
LATER

08

Marketplace (After Sprints 1-4)

The playbook YAML format is already marketplace-ready. The structure and the keyword matching engine exist. What's needed is the registry + community contribution layer.

ItemWhat it requiresWhen
playbook-registry.json Add a registry file listing all community playbooks with PSA/OS support matrix. Mirrors TacticalRMM community_scripts.json pattern. PHASE 2
Playbook builder tool Visual step editor, trigger form, dry-run test mode. Separate web app or bundled with MSPclaw server UI. PHASE 2
GitHub-based contribution flow Community submits playbooks via PR to a community-playbooks repo. CI runs test matrix. Maintainer promotes to official tier. PHASE 2

09

More PSA Connectors

The bridge template from GUIDE.md means each new PSA is ~200 lines of Python. SuperOps is done. Build these in order of MSP install base.

#PSAAuthNote endpointsEffort
1 SuperOps DONE Bearer + CustomerSubDomain GraphQL createTicketNote DONE
2 ConnectWise clientId + Basic (pubkey:privkey) POST /service/tickets/{id}/notes ~1 day
3 Halo PSA OAuth2 bearer POST /api/tickets/{id}/notes ~1 day
4 Datto Autotask API key + integration code POST .../TicketNotes ~1 day
5 Freshdesk API key as Basic auth POST /api/v2/tickets/{id}/notes ~1 day