{"url":"https://ticulate.com/nick/skyops","live":true,"project":{"slug":"skyops","owner":"Nick","ownerHandle":"nick","name":"SkyOps","summary":"The operations platform Castle Rock Sky uses to run its MSP — M365, HaloPSA, Huntress, ImmyBot, ScreenConnect, DNSFilter and ConnectSecure in one console for technicians, account managers and clients.","status":"ontrack","visibility":"public","next":"Add ConnectSecure as a sixth asset collector, feeding asset_view into the nightly pipeline joined on serial number","started":null,"target":null,"updated":"13 Aug","updatedAt":"2026-08-13T17:30:15.119Z","done":14,"total":15,"health":"753 Pester tests passing, main clean, last shipped PR #115","logo":null,"links":[],"purpose":{"why":"Castle Rock Sky's MSP work is spread across a dozen vendor consoles — M365, HaloPSA, Huntress, ImmyBot, ScreenConnect, DNSFilter, SherWeb, ConnectSecure. SkyOps pulls them into one place and turns the data into views someone can act on, rather than tabs someone has to reconcile by hand. Built for internal use first, designed with a future as a vendor product for other MSPs.","who":"Three distinct audiences, and the difference between them drives most design decisions. Technicians get remediation and automation, embedded in HaloPSA via iframe. Account managers get QBRs and the renewal/refresh conversations — which is why end-of-life is its own report rather than a section of a security one. Clients get a restricted self-service portal and an AI assistant embedded in the Halo client portal.","success":"A technician, an account manager or a client can answer their own question without opening a vendor console — and every tenant-touching action is audit-logged for the HIPAA/SEC clients."}},"features":[{"id":"connectsecure-eol-os","name":"End of Life (operating systems)","area":"ConnectSecure","state":"live","version":null,"shipped":"2026-08-03","summary":"Devices running an unsupported OS, or one going unsupported within two quarters, grouped by client.","detail":"Built for account managers: a replacement and refresh conversation, not a patching one. Live fleet: 26 devices out of support (24 Windows 10, 294 days past; 2 Server 2012 R2, 1,029 days past) and 2 approaching. Classification comes from an OS lifecycle table in config, deliberately NOT ConnectSecure's own is_deprecated flag — that returns zero assets for this tenant, so a report trusting it would have shown a clean fleet.","review":{"status":"none"},"links":[]},{"id":"connectsecure-eol-software","name":"End-of-Life Software","area":"ConnectSecure","state":"live","version":null,"shipped":"2026-08-03","summary":"Unsupported applications across the fleet, grouped into product families.","detail":"The vendor emits one entry per installed component, so 158 devices produce 139 near-duplicate 'products' — and the findings that matter (Office 2019, Silverlight, Access 2010, SQL Server 2012 Native Client) sit at the bottom with a count of 1. Grouped into 15 families they become visible. Counts are distinct machines, not component installs.","review":{"status":"none"},"links":[]},{"id":"ask-artie","name":"Ask Artie — AI self-service assistant","area":"Client-facing","state":"live","version":null,"shipped":"2026-07-31","summary":"Claude-powered troubleshooting chat embedded in the HaloPSA client portal.","detail":"Anonymous and ticket-anchored: every conversation is tied to a Halo ticket and survives a reboot or a closed tab, with per-turn hidden notes keeping the ticket current even if a session is interrupted. Artie can troubleshoot, open a ticket, check on one, and resolve one. Ticket creation is deferred to the user's first message so there are no ghost tickets. Safety is enforced in code: a category blocklist forces escalation-only for security and phishing categories regardless of what the model decides.","review":{"status":"none"},"links":[]},{"id":"intune-deploy-script","name":"Device Management Scripts report","area":"Reports","state":"live","version":null,"shipped":"2026-07-28","summary":"Checks each tenant's Intune actually deploys the ImmyBot agent to newly enrolled devices.","detail":"Detects by script CONTENT rather than name, because names are inconsistent across clients and a name match produces false 'missing' results. Flags a pinned installer, wrong Immy instance, bad run-as or signature settings, and unassigned scripts. A tenant without consent reads as 'unavailable', never 'missing' — a permission gap must not look like an undeployed agent.","review":{"status":"none"},"links":[]},{"id":"qbr","name":"QBR / per-client report","area":"Reports","state":"live","version":null,"shipped":null,"summary":"Printable client-facing quarterly business review.","detail":"Pulls licensed users, managed endpoints, RMM patching, security baseline, DNS health and conversation items into one document. The account manager curates section visibility before printing; auto-named PDF on print.","review":{"status":"none"},"links":[]},{"id":"asset-pipeline","name":"Asset pipeline","area":"Assets","state":"live","version":null,"shipped":null,"summary":"Nightly Collect → Transform → Writeback producing a canonical per-device record.","detail":"Five sources today — ScreenConnect, Huntress, ImmyBot, Entra and CyberDrain — joined on serial number, with writeback to Halo. Feeds Unified Assets, Managed Endpoints, ScreenConnect Assets and ImmyBot RMM.","review":{"status":"none"},"links":[]},{"id":"remediation-pipeline","name":"Remediation pipeline","area":"Automation","state":"live","version":null,"shipped":null,"summary":"Findings become deduped Halo tickets, with suppression.","detail":"A detector registry runs per tenant; each finding produces a ticket keyed on findingType plus resourceId, so a repeat scan updates rather than re-opens. Suppression and per-tenant caps bound the blast radius. Detectors today: EDR coverage gaps, stale users, DNS health.","review":{"status":"none"},"links":[]},{"id":"immybot-cockpit","name":"ImmyBot RMM cockpit + patch report","area":"Vendor","state":"live","version":null,"shipped":null,"summary":"Tenant overview, coverage gap detection, per-device drill-down and a standalone patch report.","detail":null,"review":{"status":"none"},"links":[]},{"id":"dnsfilter-cockpit","name":"DNSFilter cockpit + traffic reporting","area":"Vendor","state":"live","version":null,"shipped":null,"summary":"Bulk sub-org provisioning, baseline policy, and per-tenant traffic and threat reporting.","detail":null,"review":{"status":"none"},"links":[]},{"id":"projects","name":"Projects — signed-deal lifecycle","area":"Internal","state":"live","version":null,"shipped":null,"summary":"A signed PandaDoc proposal auto-creates a SkyOps project; phases, time and audit follow it through to archive.","detail":"Idempotent webhook creates a draft with contract total and recipients. Admin links it to a tenant and a Halo master ticket; templated phase libraries instantiate rows. Time tracked in Halo aggregates back into the project view.","review":{"status":"none"},"links":[]},{"id":"tenant-admin","name":"Tenant administration","area":"Internal","state":"live","version":null,"shipped":null,"summary":"Onboard a client and manage per-vendor mappings — Halo client/site, Huntress org, ScreenConnect group, ImmyBot tenant, DNSFilter org, ConnectSecure company.","detail":null,"review":{"status":"none"},"links":[]},{"id":"expense-tool","name":"HR / Expense tool","area":"Internal","state":"live","version":null,"shipped":null,"summary":"Employee records, mileage, expense reports with receipt upload and signed-URL viewing.","detail":null,"review":{"status":"none"},"links":[]},{"id":"m365-automation","name":"M365 automation","area":"M365","state":"beta","version":null,"shipped":null,"summary":"User, group, mailbox and licence operations — read-only in production.","detail":"Read paths are live. Write paths exist and are exercised on the staging slot against a developer tenant, but production cannot perform them: the prod Entra app holds read-only Graph permissions and the code enforces the same posture independently.","review":{"status":"none"},"links":[]},{"id":"connectsecure-vulns","name":"Active Vulnerabilities","area":"ConnectSecure","state":"live","version":null,"shipped":"2026-08-01","summary":"Fleet-wide critical and high CVEs, ranked by exploit likelihood rather than severity alone.","detail":"Ranking combines severity with EPSS exploit probability, so a widely-exploited High outranks a Critical nobody is attacking. On the live fleet the top finding is CVE-2023-44487 (HTTP/2 Rapid Reset, EPSS 1.0) and CVE-2024-1709 — the ScreenConnect auth bypass — both of which a severity-only sort buries under 481 Criticals. 6,016 Critical/High CVEs; 149 urgent. Scopes to one client via the tenant selector, and each row opens a drawer showing affected devices and the software to update. Server-side severity filtering keeps the whole thing inside ConnectSecure's 300 requests/minute limit.","review":{"status":"none"},"links":[]},{"id":"audit-compliance","name":"Audit & compliance","area":"Platform","state":"live","version":null,"shipped":null,"summary":"Every tenant-mutating action writes an append-only audit row; 7-year retention target for HIPAA/SEC clients.","detail":null,"review":{"status":"none"},"links":[]}],"roadmap":{"doing":[{"note":"Feed asset_view (serial number, BIOS, encryption state, architecture, security grade) into the nightly asset pipeline, joined on serial number, to close remaining gaps in the unified asset view.","title":"ConnectSecure as a sixth asset collector"}],"planned":[{"note":"Register a 'vulnerability' detector in Invoke-RemediationScan. Using the CVE id as resourceId yields one ticket per CVE per tenant, inheriting dedup and re-open suppression from the existing pipeline.","title":"Halo ticketing for vulnerabilities"},{"note":"Six open issues: Exchange Online checks, Microsoft Secure Score, DLP and sensitivity labels, external collaboration and B2B, geo-fence parameterisation.","title":"Security Baseline expansion"},{"note":"External deadline: the API retires 14 September 2026.","title":"Azure Monitor Data Collector API migration"},{"note":"Currently a panel on the ImmyBot cockpit; promote when the value justifies it.","title":"Maintenance coverage gap as a dedicated portfolio view"}],"considering":[{"note":"API spec already saved at tools/auvikapi.json; needs a probe and a scope.","title":"Auvik integration"},{"title":"NinjaOne integration for backup health visibility"},{"title":"WordPress monitoring and backup visibility for managed sites"},{"title":"Templated New Client Onboarding intake with auto-provisioning"},{"note":"Blocked on the prod Entra permission expansion and its re-consent round.","title":"M365 write paths — offboarding, group changes, licence assignment"},{"title":"Self-service client portal expansion"}]},"updates":[{"timestamp":"03 Aug","at":"2026-08-03T12:00:00.000Z","statusChange":null,"title":"ConnectSecure integration shipped — vulnerability, EOL and EOL-software reporting","body":"Three separate reports rather than one master view, because the audiences differ: Active Vulnerabilities is a remediation job, End of Life is an account-manager replacement conversation, and End-of-Life Software is an uninstall-or-upgrade job. All three share one refresh (~142s) and one tenant-to-company mapping, but each pass is wrapped independently so a failure in one cannot discard the others' caches.","tags":["connectsecure","reports"],"links":[]},{"timestamp":"03 Aug","at":"2026-08-03T12:00:00.000Z","statusChange":null,"title":"ConnectSecure integration shipped — vulnerability, EOL and EOL-software reporting","body":"Three separate reports rather than one master view, because the audiences differ: Active Vulnerabilities is a remediation job, End of Life is an account-manager replacement conversation, and End-of-Life Software is an uninstall-or-upgrade job. All three share one refresh (~142s) and one tenant-to-company mapping, but each pass is wrapped independently so a failure in one cannot discard the others' caches.","tags":["connectsecure","reports"],"links":[]},{"timestamp":"27 Jul","at":"2026-07-27T12:00:00.000Z","statusChange":null,"title":"Ask Artie shipped and made ticket-anchored","body":"Conversations were originally tied to a throwaway session, so suggesting a reboot lost all context. They are now anchored to a Halo ticket with no idle expiry, and each turn appends a hidden note so the ticket stays current even if the session is interrupted. Artie also gained the ability to open, check and resolve tickets rather than only advise.","tags":["ask-artie"],"links":[]},{"timestamp":"27 Jul","at":"2026-07-27T12:00:00.000Z","statusChange":null,"title":"Ask Artie shipped and made ticket-anchored","body":"Conversations were originally tied to a throwaway session, so suggesting a reboot lost all context. They are now anchored to a Halo ticket with no idle expiry, and each turn appends a hidden note so the ticket stays current even if the session is interrupted. Artie also gained the ability to open, check and resolve tickets rather than only advise.","tags":["ask-artie"],"links":[]}],"feedback":[]}