From 828cba5909d7b5bd170f17994f30700d85f31927 Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:14:05 -0400 Subject: [PATCH 01/11] feat(advanced-workflows): add skill templates for workflow and capability-map skills --- .../_capability-map-template.md | 35 ++++++++++++++ .../_workflow-skill-template.md | 48 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 advanced-workflows/advanced-workflows/_capability-map-template.md create mode 100644 advanced-workflows/advanced-workflows/_workflow-skill-template.md diff --git a/advanced-workflows/advanced-workflows/_capability-map-template.md b/advanced-workflows/advanced-workflows/_capability-map-template.md new file mode 100644 index 00000000..4a53404e --- /dev/null +++ b/advanced-workflows/advanced-workflows/_capability-map-template.md @@ -0,0 +1,35 @@ +--- +name: " Tool Map" +description: > + Maps abstract operations to concrete Conduit tool names per curated + vendor, for use by advanced-workflow skills that need access. +when_to_use: >- + Fetched by another skill in this plugin, never used standalone. Use when: + tool names, vendor gotchas. +--- + +## Curated vendors + +This role is curated for every vendor `agent-routine-catalog.astro` lists with +an Archetype-A or -B agent for this job (not a fixed top-N — read the catalog, +list what it actually shows): , [, , ...]. Each +row's tool names are verified against that vendor's real subagent file +(`//agents/.md`), never invented. A connected +vendor the catalog doesn't cover at all needs guided discovery: inspect the +org's available tools for this connector, reason from naming and shape, and +tell the human this vendor isn't fully vetted yet — don't present it as +equally reliable. + +## Operation map + +| Abstract operation | tool | tool | tool | +|---|---|---|---| +| | `` | `` | `` | + +## Vendor-specific gotchas + +### +- + +### +- diff --git a/advanced-workflows/advanced-workflows/_workflow-skill-template.md b/advanced-workflows/advanced-workflows/_workflow-skill-template.md new file mode 100644 index 00000000..8b888f4f --- /dev/null +++ b/advanced-workflows/advanced-workflows/_workflow-skill-template.md @@ -0,0 +1,48 @@ +--- +name: "" +description: > + +when_to_use: >- + Use when [specific trigger]. Use when: keyword one, keyword two, keyword three. +--- + +## What this does + +<1 paragraph, generalized to role language — never name one vendor as if it's the only option.> + +## Source + + + +## Prerequisites + +| Requirement | Notes | +|-------------|-------| +| **A connected connector** | One of: . See the `-tool-map` skill for the exact tool names once connected. | +| **A connected chat-delivery connector** | Slack (shipped) or Microsoft Teams (blocked — see `chat-delivery-adapters`). | + +## Detecting the customer's stack + +1. Check which vendor is connected (via the org's active Conduit vendor connections). If more than one match, ask the human which to use. If none, tell the human what's needed — never guess, never fail silently. +2. Fetch `skill://advanced-workflows/-tool-map/SKILL.md` for that vendor's concrete tool names and gotchas. +3. Fetch `skill://advanced-workflows/chat-delivery-adapters/SKILL.md` for the connected delivery target's adapter contract. + +## Run it now + + + +## Set up as a recurring routine + + + +## Known gotchas + + + +## How it works + + + +## Extending it + + From efdec6262336d68c7800abb38b795600f9bb3f76 Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:19:09 -0400 Subject: [PATCH 02/11] feat(advanced-workflows): add psa-tool-map capability skill --- .../skills/psa-tool-map/SKILL.md | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md diff --git a/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md b/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md new file mode 100644 index 00000000..ecf13362 --- /dev/null +++ b/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md @@ -0,0 +1,51 @@ +--- +name: psa-tool-map +description: > + Maps abstract PSA/ticketing operations (list new tickets, get ticket + detail, update priority + status, list statuses, list priorities) to + concrete Conduit tool names for Autotask, HaloPSA, and ConnectWise PSA. +when_to_use: >- + Fetched by another advanced-workflow skill that needs PSA access, never + used standalone. Use when: PSA tool names, Autotask tools, HaloPSA tools, + ConnectWise PSA tools, ticket status IDs, ticket priority IDs. +--- + +## Curated vendors + +This role is curated for: Autotask, HaloPSA, ConnectWise PSA. A connected +PSA not listed here needs guided discovery: inspect the org's available +tools for that connector, reason from naming and shape, and tell the human +this vendor isn't fully vetted yet. + +## Operation map + +| Abstract operation | Autotask | HaloPSA | ConnectWise PSA | +|---|---|---|---| +| List new/untriaged tickets | `autotask__autotask_search_tickets` | `halopsa__halopsa_tickets_list` | not yet verified — use guided discovery | +| Get ticket detail | `autotask__autotask_get_ticket_details` | `halopsa__halopsa_tickets_get` | not yet verified — use guided discovery | +| Update ticket (priority/status/etc.) | `autotask__autotask_update_ticket` | `halopsa__halopsa_tickets_update` | not yet verified — use guided discovery | +| Add a ticket note/action | `autotask__autotask_create_ticket_note` | `halopsa__halopsa_tickets_add_action` | not yet verified — use guided discovery | +| List valid ticket statuses (discover once, don't call per-run) | `autotask__autotask_list_ticket_statuses` | no dedicated list tool observed — confirm via `halopsa__halopsa_tickets_list` field values before baking in IDs | not yet verified | +| List valid ticket priorities (discover once, don't call per-run) | `autotask__autotask_list_ticket_priorities` | no dedicated list tool observed — confirm via ticket field values before baking in IDs | not yet verified | + +## Vendor-specific gotchas + +### Autotask +- Priority IDs are typically **not** ordered by severity — discover them + by name, never assume numeric ordering. +- Status/priority/queue IDs are tenant-specific — always discover once at + build time, never hardcode across tenants. +- Don't call `list_*` discovery tools on every routine run — it's slow + enough to hit the 60-second tool timeout. Discover once, bake the IDs + into the routine prompt. + +### HaloPSA +- No dedicated "list statuses"/"list priorities" tool was found in this + vendor's observed tool surface — confirm the actual field values by + reading a sample ticket via `halopsa_tickets_get` before baking any ID + into a routine, don't assume symmetry with Autotask's shape. + +### ConnectWise PSA +- Tool surface not yet verified against a live connection. Treat as + guided-discovery-only until confirmed; do not present this vendor as + equally vetted to Autotask/HaloPSA in any workflow skill that cites it. From f23b36d0e6ad8c42cfc6cd07e9b2a28547bbacc6 Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:25:49 -0400 Subject: [PATCH 03/11] fix(advanced-workflows): populate ConnectWise PSA tool names in psa-tool-map Found real, registered tool names in connectwise/manage/GOVERNANCE.md's VENDOR_TOOL_CONFIG listing (slug connectwise-psa) after the original search only checked for the double-underscore naming pattern borrowed from Autotask/HaloPSA and missed GOVERNANCE.md's cw_-prefixed names. Replaces 'not yet verified' placeholders with connectwise-psa__cw_* tool names and adds ConnectWise-specific gotchas (note visibility default, sole closure route requiring human approval, closure ordering, shared rate limit). --- .../skills/psa-tool-map/SKILL.md | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md b/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md index ecf13362..57f107ff 100644 --- a/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md +++ b/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md @@ -21,12 +21,12 @@ this vendor isn't fully vetted yet. | Abstract operation | Autotask | HaloPSA | ConnectWise PSA | |---|---|---|---| -| List new/untriaged tickets | `autotask__autotask_search_tickets` | `halopsa__halopsa_tickets_list` | not yet verified — use guided discovery | -| Get ticket detail | `autotask__autotask_get_ticket_details` | `halopsa__halopsa_tickets_get` | not yet verified — use guided discovery | -| Update ticket (priority/status/etc.) | `autotask__autotask_update_ticket` | `halopsa__halopsa_tickets_update` | not yet verified — use guided discovery | -| Add a ticket note/action | `autotask__autotask_create_ticket_note` | `halopsa__halopsa_tickets_add_action` | not yet verified — use guided discovery | -| List valid ticket statuses (discover once, don't call per-run) | `autotask__autotask_list_ticket_statuses` | no dedicated list tool observed — confirm via `halopsa__halopsa_tickets_list` field values before baking in IDs | not yet verified | -| List valid ticket priorities (discover once, don't call per-run) | `autotask__autotask_list_ticket_priorities` | no dedicated list tool observed — confirm via ticket field values before baking in IDs | not yet verified | +| List new/untriaged tickets | `autotask__autotask_search_tickets` | `halopsa__halopsa_tickets_list` | `connectwise-psa__cw_search_tickets` | +| Get ticket detail | `autotask__autotask_get_ticket_details` | `halopsa__halopsa_tickets_get` | `connectwise-psa__cw_get_ticket` | +| Update ticket (priority/status/etc.) | `autotask__autotask_update_ticket` | `halopsa__halopsa_tickets_update` | `connectwise-psa__cw_update_ticket` | +| Add a ticket note/action | `autotask__autotask_create_ticket_note` | `halopsa__halopsa_tickets_add_action` | `connectwise-psa__cw_add_ticket_note` | +| List valid ticket statuses (discover once, don't call per-run) | `autotask__autotask_list_ticket_statuses` | no dedicated list tool observed — confirm via `halopsa__halopsa_tickets_list` field values before baking in IDs | `connectwise-psa__cw_list_statuses` | +| List valid ticket priorities (discover once, don't call per-run) | `autotask__autotask_list_ticket_priorities` | no dedicated list tool observed — confirm via ticket field values before baking in IDs | `connectwise-psa__cw_list_priorities` | ## Vendor-specific gotchas @@ -46,6 +46,26 @@ this vendor isn't fully vetted yet. into a routine, don't assume symmetry with Autotask's shape. ### ConnectWise PSA -- Tool surface not yet verified against a live connection. Treat as - guided-discovery-only until confirmed; do not present this vendor as - equally vetted to Autotask/HaloPSA in any workflow skill that cites it. +- Tool names are `cw_`-prefixed, not `connectwise_manage_`-prefixed — + verified against `connectwise/manage/GOVERNANCE.md`'s `VENDOR_TOOL_CONFIG` + listing, registered under the gateway slug `connectwise-psa` (so gateway + names are `connectwise-psa__cw_*`, e.g. `connectwise-psa__cw_search_tickets`). +- `cw_add_ticket_note` writes a **customer-visible** note by default — + pass `internalAnalysisFlag: true` explicitly for an internal-only note, + or an agent's internal analysis gets emailed to the contact immediately. + There is no delete-note tool to undo a mistaken send. +- `cw_update_ticket` is the **only** route to closing a ticket (it takes + raw JSON Patch, so `op: "remove"` can strip a field outright). Closing + stops the SLA clock and can fire close notifications/satisfaction + surveys, and Conduit's access tiers gate the whole tool at `write` + regardless of which field the patch touches — there's no way to allow + priority/owner patches while blocking status/closure patches at the + gateway level. Treat `cw_update_ticket` as requiring a named human + approver per invocation; never grant it to unattended/nightly + automation. +- Closure must pass through `Completed` before `Closed`, with a populated + `resolution` field, or the patch fails with an error that reads like a + permissions failure rather than a workflow-ordering one. +- The 60-requests/minute rate limit is shared across all operators on the + same ConnectWise API member — a wide `cw_search_*` discovery sweep by + one routine can 429 everyone else's concurrent calls. From f2f9ce9cbebb135a65da1b169e5bd9516d4797af Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:31:48 -0400 Subject: [PATCH 04/11] feat(advanced-workflows): add chat-delivery-adapters skill, Teams marked blocked IT Glue tool names corrected to the unprefixed form (search_documents, create_document, update_document_section) per kaseya/it-glue/GOVERNANCE.md, which is authoritative and contradicts the itglue__-prefixed names in Conduit's docs. Also added publish_document to the IT Glue adapter since GOVERNANCE.md flags unpublished section edits as invisible to a human, which the adapter's stated purpose (deliver to a human) depends on. --- .../skills/chat-delivery-adapters/SKILL.md | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md diff --git a/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md b/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md new file mode 100644 index 00000000..f0916e8e --- /dev/null +++ b/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md @@ -0,0 +1,78 @@ +--- +name: chat-delivery-adapters +description: > + The delivery-adapter contract every advanced-workflow skill uses to post + its finished report somewhere a human will see it — Slack, an IT Glue + document, or (blocked) Microsoft Teams. +when_to_use: >- + Fetched by another advanced-workflow skill once it has a finished report + to deliver, never used standalone. Use when: delivery adapter, Slack + delivery, Teams delivery, IT Glue document delivery, report delivery. +--- + +## The contract + +Every workflow's body produces a **report payload**; a delivery adapter +takes that payload and writes it somewhere a human will see it. Detect +which delivery target is connected the same way you detect a data-role +vendor: if more than one is connected, ask the human which to use; if +none is connected, tell the human what's needed — don't guess, don't fail +silently. + +## Shipped adapters + +### Slack summary +- **Connector**: Slack (first-party claude.ai connector, not Conduit-routed). +- **permitted_tools**: `slack_send_message`. +- **Write snippet**: post a one-paragraph summary to the destination channel. +- **Limits**: plain text, no rich layout — best for a short result. + +### Slack canvas +- **Connector**: Slack. +- **permitted_tools**: `slack_create_canvas`, `slack_send_message`. +- **Write snippet**: create a canvas titled `` with + the full report; post a summary message linking it. +- **Limits**: one canvas per run — each run leaves its own dated artefact + rather than updating a single document in place. + +### IT Glue document +- **Connector**: Conduit (`itglue` vendor connection). +- **permitted_tools**: `search_documents`, `create_document`, + `update_document_section`, `publish_document`. +- **Write snippet**: search for an existing document named `` + in the target IT Glue org; if found, update its section, else create it; + then call `publish_document` — section edits are invisible to a human + until the document is published. +- **Limits**: needs a target org ID baked in. Updates in place, so reruns + converge on a single document rather than accumulating artefacts. + IT Glue's tools carry no vendor prefix (verified against the `itglue` + plugin's `GOVERNANCE.md`) — don't guess an `itglue_`-style name for any + tool not listed here. + +## Blocked + +### Microsoft Teams +**Blocked — do not use.** Conduit's `m365` vendor Chat/Team Graph scopes +are a documented phase-2 addition and are not live yet (the vendor is +currently `hidden` pending `--org-mode` on its sidecar). If a workflow's +prerequisites mention Teams as a delivery target, mark it explicitly as +"coming soon, not yet available" rather than instructing an agent to +attempt it — there is no working send-to-Teams tool today. + +## Documented but not shipped + +- **Notion** — the first-party Notion connector (`notion-create-pages`, + `notion-update-page`) or the Conduit `notion` vendor connection would + both work; deferred only because Slack and IT Glue cover current need. +- **Hudu** — an IT-Glue-like documentation target; whether the Conduit + `hudu` connection exposes a write tool is unverified. Confirm before + treating it as an adapter. +- **SharePoint** — blocked. The available Microsoft 365 connector is + search/read only. +- **Email** — deferred, no adapter built yet. + +## Adding a new adapter + +Pick a connector that can write to the target, confirm it exposes a write +tool (don't assume), and document: Connector, permitted_tools, write +snippet, limits. The workflow body producing the report never changes. From 475e5c5dacb20cd2393b9fd43df6b992beaa3e48 Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:38:15 -0400 Subject: [PATCH 05/11] fix(advanced-workflows): restore itglue__ gateway prefix on IT Glue tool names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior commit f2f9ce9 dropped the itglue__ vendor prefix, reading kaseya/it-glue/GOVERNANCE.md's bare classification-table keys (create_document, etc.) as the servable tool name. That table is an internal VENDOR_TOOL_CONFIG permission-tier lookup, not the wire-format name — Conduit's unified-router.ts prefixes every served tool with {vendor}__ unconditionally and rejects any inbound call without a __ separator. Restores itglue__search_documents, itglue__create_document, itglue__update_document_section, itglue__publish_document, and corrects the in-body note that previously told editors not to add a prefix. --- .../skills/chat-delivery-adapters/SKILL.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md b/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md index f0916e8e..ea8a099d 100644 --- a/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md +++ b/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md @@ -37,17 +37,20 @@ silently. ### IT Glue document - **Connector**: Conduit (`itglue` vendor connection). -- **permitted_tools**: `search_documents`, `create_document`, - `update_document_section`, `publish_document`. +- **permitted_tools**: `itglue__search_documents`, `itglue__create_document`, + `itglue__update_document_section`, `itglue__publish_document`. - **Write snippet**: search for an existing document named `` in the target IT Glue org; if found, update its section, else create it; - then call `publish_document` — section edits are invisible to a human - until the document is published. + then call `itglue__publish_document` — section edits are invisible to a + human until the document is published. - **Limits**: needs a target org ID baked in. Updates in place, so reruns converge on a single document rather than accumulating artefacts. - IT Glue's tools carry no vendor prefix (verified against the `itglue` - plugin's `GOVERNANCE.md`) — don't guess an `itglue_`-style name for any - tool not listed here. + Conduit prefixes every served tool name with `{vendor}__` at the gateway + (`itglue__` here) regardless of what the vendor's own internal + classification table calls it — the `itglue` plugin's `GOVERNANCE.md` + documents bare names like `create_document` for its internal + permission-tier lookup, but the servable/callable name always carries + the `itglue__` prefix, same as every other vendor. ## Blocked From 5cd9ee874bb6c2bdc7c2ae7a3972f2ac96c72906 Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:41:12 -0400 Subject: [PATCH 06/11] feat(advanced-workflows): add generic ticket-triage-agent workflow skill --- .../skills/ticket-triage-agent/SKILL.md | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md diff --git a/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md b/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md new file mode 100644 index 00000000..9d94d294 --- /dev/null +++ b/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md @@ -0,0 +1,112 @@ +--- +name: ticket-triage-agent +description: > + Build (or run once) a ticket-triage agent that classifies new PSA + tickets by priority, advances them to In Progress, and posts a summary + to the connected chat tool. Works with any curated PSA — Autotask, + HaloPSA, or ConnectWise PSA. +when_to_use: >- + Use when a customer wants new support tickets automatically triaged and + prioritized. Use when: ticket triage, ticket dispatch, priority + classification, PSA automation. +--- + +## What this does + +Finds new/untriaged PSA tickets, classifies each by priority from its +content, updates the record, moves it to In Progress, and posts a +one-line summary to chat. Can run as a one-off right now, or be installed +as an hourly Claude-managed scheduled routine. + +## Prerequisites + +| Requirement | Notes | +|-------------|-------| +| **A connected PSA** | Autotask, HaloPSA, or ConnectWise PSA (curated — see `psa-tool-map` for tool names; another connected PSA works via guided discovery). Must be able to read and update tickets — priority and status. | +| **A connected chat-delivery target** | Slack (shipped) — see `chat-delivery-adapters`. Teams is not yet available. | +| **Scheduled routines access** (only if installing as a routine) | Via the `/schedule` capability; managed at claude.ai/code/routines. | + +## Detecting the customer's stack + +1. Check which curated PSA is connected. More than one → ask which to + use. None → tell the human a PSA connection is needed, don't guess. +2. Fetch `skill://advanced-workflows/psa-tool-map/SKILL.md` for that + vendor's exact tool names, status/priority discovery approach, and + gotchas. +3. Fetch `skill://advanced-workflows/chat-delivery-adapters/SKILL.md` for + the connected delivery target's write tool and limits. + +## Run it now + +1. Using the PSA's "list new/untriaged tickets" tool, find tickets in the + New (or equivalent untriaged) status. +2. For each, get its detail (title, description, requester). +3. Classify PRIORITY using the rubric below. +4. Call the PSA's "update ticket" tool once per ticket: set priority AND + advance status to In Progress in the same call — the status change is + the idempotency guard, so a second run won't reprocess it. +5. Post a one-line summary per ticket to the connected chat-delivery + target. +6. If an update call fails, leave the ticket in its original status and + post a "needs a human" message instead — never skip silently. + +Priority rubric: +- **Critical**: server/site down, multiple users affected, or a security + incident. +- **High**: a single user fully blocked from working. +- **Medium**: service degraded but the user can still work. +- **Low**: requests, questions, cosmetic issues. +- When torn between two, pick the lower-severity one. + +## Set up as a recurring routine + +1. Confirm the PSA connector works (a lightweight test/ping call from the + tool-map skill, if one exists for the connected vendor). +2. Discover the tenant's status and priority IDs **once**, by name — per + the tool-map skill's guidance for the connected PSA. Do not bake + `list_*` discovery calls into the routine itself. +3. Confirm the chat-delivery connector and destination channel. +4. Create a Claude-managed scheduled routine named "Ticket Triage Agent": + - Schedule: hourly (`0 * * * *`) — Claude-managed routines reject any + cadence faster than hourly. + - Attach the PSA connector with `permitted_tools` populated with + exactly the tools this workflow needs (list, get-detail, update) — + an attached connector with an empty `permitted_tools` list runs with + no tools and silently does nothing. + - Attach the chat-delivery connector with its `permitted_tools`. + - Routine prompt: the "Run it now" steps above, with the discovered + status/priority IDs baked in by name (never re-discovered per run). +5. Create one test ticket, trigger a manual run, and verify: the ticket + moved to In Progress + reprioritized, one chat message posted, and a + second run does not reprocess it. + +## Known gotchas + +- **One-hour minimum cadence.** Claude-managed routines reject any cron + faster than hourly. +- **`permitted_tools` must be populated per connector**, or the routine + runs with no tools and no error. +- **Routine tool calls prompt for permission** the first time each new + tool is touched — pre-allow them or expect an approval prompt on first + run. +- **Don't call list/discovery tools every run** — enumerate once at build + time; per-run discovery calls are slow enough to hit the tool timeout. + +## How it works + +### Idempotency is structural +The agent only picks up tickets in the untriaged status, and triaging a +ticket moves it out of that status — the transition itself is the +"already handled" marker. No database or timestamp window is needed. + +### Failures escalate to a human +An unclassifiable ticket or a failed update call leaves the ticket +untouched and posts a "needs a human" message — never silently skipped, +never mis-prioritized without a person being told. + +## Extending it + +This classifies priority only, deliberately — enumerating queue/category +lists per run is what triggers slow discovery calls. To add queue or +category routing, bake those lists into the routine prompt the same way +status/priority IDs are baked in. From 11aed23f8a69a9009c83f32a088a2e1f967ec081 Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:47:26 -0400 Subject: [PATCH 07/11] fix(advanced-workflows): add missing Source section to ticket-triage-agent Task 3's _workflow-skill-template.md mandates a Source section citing agent-routine-catalog.astro provenance, right after 'What this does'. The Task 6 brief omitted it. Cites the ticket-dispatcher agent (autotask, Archetype B, 'the canonical archetype-B fit') plus the equivalent service-desk-ops agents the catalog lists for halopsa and connectwise-psa -- the same three PSAs psa-tool-map curates. --- .../skills/ticket-triage-agent/SKILL.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md b/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md index 9d94d294..0bf16682 100644 --- a/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md +++ b/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md @@ -18,6 +18,14 @@ content, updates the record, moves it to In Progress, and posts a one-line summary to chat. Can run as a one-off right now, or be installed as an hourly Claude-managed scheduled routine. +## Source + +Generalizes the `ticket-dispatcher` agent (`autotask` plugin, Archetype +B — "the canonical archetype-B fit") plus the equivalent +`service-desk-ops` agents the catalog lists for `halopsa` and +`connectwise-psa` — the same three PSAs `psa-tool-map` curates tool +names for. + ## Prerequisites | Requirement | Notes | From f9db12347a75aa497292d3996b77b7b1e10bbb58 Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:57:34 -0400 Subject: [PATCH 08/11] feat(advanced-workflows): register plugin in marketplace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add plugin.json and README.md for the advanced-workflows plugin, add its marketplace.json entry (new "automation" category), and regenerate the docs site's generated data. Also fixes docs/scripts/generate-plugins.ts's path derivation (derivePath/deriveVendor/pluginDir), which assumed every plugin nests under msp-claude-plugins/ — advanced-workflows is the first plugin family to live at the repo root instead. Verified byte-identical output for all 82 pre-existing plugin entries. --- .claude-plugin/marketplace.json | 9 +++++- .../.claude-plugin/plugin.json | 6 ++++ .../advanced-workflows/README.md | 12 +++++++ msp-claude-plugins/docs/public/og-image.png | Bin 92490 -> 91607 bytes .../docs/scripts/generate-plugins.ts | 20 +++++++++--- msp-claude-plugins/docs/src/data/plugins.ts | 30 +++++++++++++++++- 6 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 advanced-workflows/advanced-workflows/.claude-plugin/plugin.json create mode 100644 advanced-workflows/advanced-workflows/README.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 5678c546..bc058677 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -2,7 +2,7 @@ "$schema": "https://www.schemastore.org/claude-code-marketplace.json", "name": "msp-claude-plugins", "description": "Community-driven Claude Code plugins for Managed Service Providers. Integrates with PSA, RMM, and documentation tools.", - "version": "1.32.0", + "version": "1.33.0", "owner": { "name": "WYRE Technology", "email": "aaron@sachshaus.net" @@ -35,6 +35,13 @@ "msp" ] }, + { + "name": "advanced-workflows", + "source": "./advanced-workflows/advanced-workflows", + "description": "Vendor-generic MSP automation workflows that adapt to the customer's connected stack.", + "category": "automation", + "tags": ["workflows", "automation", "msp"] + }, { "name": "atera", "source": "./msp-claude-plugins/atera/atera", diff --git a/advanced-workflows/advanced-workflows/.claude-plugin/plugin.json b/advanced-workflows/advanced-workflows/.claude-plugin/plugin.json new file mode 100644 index 00000000..83c41f39 --- /dev/null +++ b/advanced-workflows/advanced-workflows/.claude-plugin/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "advanced-workflows", + "version": "1.0.0", + "description": "Vendor-generic MSP automation workflows: ticket triage, patch drift reporting, QBR prep, and more — each detects the customer's connected PSA/RMM/chat stack and adapts.", + "author": "WYRE Technology" +} diff --git a/advanced-workflows/advanced-workflows/README.md b/advanced-workflows/advanced-workflows/README.md new file mode 100644 index 00000000..83ba5c94 --- /dev/null +++ b/advanced-workflows/advanced-workflows/README.md @@ -0,0 +1,12 @@ +# Advanced Workflows + +Vendor-generic MSP automation skills. Each workflow detects which PSA/RMM/ +chat-delivery vendor a customer has connected and adapts — see the +`*-tool-map` skills for exactly which vendors are curated per role. + +**Access note:** this plugin has no single vendor to "follow" for access +gating (that's the point — it's vendor-generic), so on Conduit's catalog +it defaults open to every member of every connected org, the same +fallback every other vendor-less catalog pack uses. Org admins who want +tighter control can add an explicit grant/deny the same way they would +for any catalog pack. diff --git a/msp-claude-plugins/docs/public/og-image.png b/msp-claude-plugins/docs/public/og-image.png index 637ed2c793e2d12ab6279357ad7b06a35cc538b3..b26e4c05031eb44a98227eb2ecafff7668d402bc 100644 GIT binary patch delta 33979 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:Nau9lA@`^4oTJh9#uz^Q)q4B-KDa8IN`$V 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 delta 33937 zcmce;c_5VC|2J-T6Db)&(Sl+SvLstc${><4Lm9iQm4vZg%2Je6jIv~@NCq=hvP_XR zTefW32_@Uuch9*-b>H{r`+2^<=da&C%9!h1=e*a~dpqs5%r(u-|qks|4#q0(mZmoeW0mYjOiQuXBjrhr6b4+1cgP4L4+3A|7OJ_~+FY@}$;q8I`- zXW8)xX?neC)~Nj)y95YK$C$zQ*;pmO^We`6IC@g4=n3&1R zB}ch2?c!&<27ki6-59J*V4{Nw5yDE3ECF~c-~pJc$9KF~D(ShBEh zZ^vhaH|A^mz|k&~(a)5de5_ZBsuR3-+s~Eta+n4H}y-994=g3 z*D35rImlb*qpb&@gqg<61kG7KKz@oj;5E!U@Rxex^u98r4UKuwe`6kg#~^{Oq-L~QqBP8O0vFhAsk7GL{(NB0R z#v8*Kt}PDBv+7?|lo~8O0^D>kYeo0GqRIUZu!Wlw1N(1b#(paeO(6!((v&8UrZo7! z1`rzX!>9kp!$4`cWGRFHaZVbwPz=eibO#@#y^mfKKFGlSJD80qLrxxnM|A(?J$DAt zQ-M(_jJx=C=x8E)?FGDq$ce+WGXzs>l(uyDKhFSf!;Lbt{hxf=BAkYJQ?$c-9hsvr zwJYK^%eck$Md-x)34G}cxG)KjEQxuE_ZfZjwSpv&h$rYXO!=*q)Rh8&sTqC4c8uET)8b zAiSBozPMOs7L`%%EmrD06C?w9r==yK!zTEt9ZZxN#Xk0}@eZuld3VkLOYbT8CjLGnCIO~{03Y~R-h`f%`--Fk6aAu*DSa1ZkSVH>VK4M7 z2YxF%mlb7(af_D{52nYO8iCcJS=C=Z77`oisVaY2zdOm{!l!;`FJo5-mrGS0u%Gt0 zFzuI_ffYm?*d8px^uVRSwuRp*X8vdv0o{Lerw;>-Ebtiz4#WFp)*4g| zf;kCJSr7aKKC|W#FDd^Q0mH6dO7Vtm_TMywi5ZCTn~;zvX_f7o&UlyXEh?0n%fQJ^ zTKi?UxFb!Xthjg}iO7|l@`ZbN7Y5us3ow(^9Rvgqz7@Ge8zj|Xi${SN%@Lf{2w)%0 zd|8d4ABZ;0&AmQQLZsUshZ#ICflQ{>9Qq$m!S?VEe`#D>VuFRX=o)2)9S9H$up1~< zvnVSzJ|4UuEDhsE{RGxO>i~h|+cijK1EP|v8-%$66cPSXc~p)ZPZXJvi6^Y;5Llu{ z8i7-$-x8>>Gg0Rmc=m%QxFZcmtuTFy$#1XjGC9CYL%){}!wk|R zOEI~ex=-$CjbP)hl`(=B4PVgE7oU#(OD*iJL`Wg`D@8Z$m!IaemUSs@Ji1X1S9PWz zKMF)~=st5s1sxWR7A?knlW?p-3$GurLyShT9JMIH z8#^QQN{}12ip-AVSJ;>++}mi%1Y@dysJEy}cw9xnkw0}`LY2D@N2hv^zW*oq5lm2G*)M44IkT9(sgyW%idMF%bi z3j5v9@;m>R!&Mz&P$7s9( zkHZ?kx);a)3t9iyhX)C=w1-ds*N3HWKWISyZ@2?k0ki)S%>Gi^E4Vpn;-r>NMbS|B z?*ArbCnGUmVT{24Uxkc~(#*1jUjN%3KlKxQ{-ziD+5kEMsr^bnhbL?yh6xg9OD`vj z6sF1FF?uH6??rNuu_M4wVN9T!N4H=W52+W&vwFE1!+Cs(yCun zg6$26)cmCPGyQoDAkdcW{l9$ob4e~830spJ-=Kg9!mxnb#*dkd zt+CwZ7X-9us84pjPj799CkF(Bhk>9DU{H4D0{}B8L&FmbC3kub3aN00_FoCIQoo(g z2*mUs4rNQt3f*Xcp;Yh!EhZ~ep#54xl$j6wg(T)%;&wk2|E{pphuiryyN9Te>)^d} z4}XLWhK)##WI39octd|M#~1Be+BC?d)A&Slwnq4x-EZtE2%vn3P9tTE`JeF;hzvTD zJ!)Azj_fVZJvrK3dU*0|BMkmQA{Km;Hu3IG@(o zc;^hTuKmo6U5uiGqZfd~j^VVn^nDWWx5~kch8al{89dMqlVxD5W-1 z*rO~*2z)>=c%ebyWJHBPhzuKI*rVzL%Cb>wu9dLAKK@WSMyz}Kn~xaEWhDc(721gk zcixl_YVG2)~d1C~6XQSI(0{NjN|06hBPE`Vy~C7x_w0ZV_A*@z;?^!w3Y z7!;gAw1|^|w8jGCsbHm-TYBXSR#`Ov>-0gu9mx}Mm{1s6BKDPn>_h&o+dCtGV+XM& zCy1~=+|d^6M`HsAT5Wt_ugte65aZ30a zF>yD&&L(&5n?~ISzUE0aK9vpjYP>u&Z@;C)c;GogOdBc9QTsS{!!T%Pm^RIns{&JA z3QPnVb_0Stwk$$9aG4Ty)|5dO0F?!I{?cC|fGw;Tro*?0!jpI5;kN6jinnP zcm&$X;`sYM{3DK#coT>D_~q|U1|2QJuAGGp2m0I&pcK@@5O5*eZjFG4{}q6s7(iM8 z{vOSg!Vw;KUoLIoU#}Y^EdN6Cutf)%FIqO^5A;Q;8i$DBOyw78cG2qOvDq3m#a(}} zDf|rE1DNm-?5DPtz|%tGayVvW-)2dX#VaWlUf-%2~Fa1YUfp(C>4G=JZ^$t03hb(umrirE5VZ6 zp(k2yFVB7`7ko&|Td*@6!iB1HAozh6jz0HK<|KGR>!E6K!78L>^vDL|7OeOt4(^A~~{^mDKC8{B8 z`NOItfK>u1DcS!I9?{Nww-Ilo0O2o|1SoVNj1PVy5KCHPNoDN0XE_xzE3ZZ0(KkxXDfL+Eg? z{so9dPQX$D%hlHEgDEuSjzpIb$vZwGVIlup-e@8V{T4s4YgOaF>7@w(ChU9Ap9aw% z4DzkR8l$jCqjZ%^4j}*HUt$8oUEb`cZRO8-rZbFNq__N~w(0@&Po-4 z8wBqy{O}*{!6*9Pv_X@H%J7dr@DmkhuH zd15^Upx+IepO7J|O|#}zX)qw$e?`t;=3YzWWbfnx_+!slEdsdlNTU)YgnTF=Su$O- z>tD*AY(=v?H2N#h%mbSxa2L1lAZ!9krNSH>0P|0GDIXNdE)}Ul{=FmE2EdlMuD(`W ze2f;4a+hpnXlW&)crl9HUh=KIq%WMVzw?Yo_akc{i)gN^KsDy>18p(%e>Pt}2Pska zF;fQD--m)cD}a0LPq)fh1PWu9X{mnXAMOWWeX(@gUEcA~Wam$s3J#foSBDMIH8^$z z=fh%5shqBR1uGl!X{t2l0u#TdEy(`y6$W>46iBSu2*er5`%4`K38 zMaPuif%I-R{DER1aVfWAZ+iMrjL}+&8EUuj88^pPdZk$jMUTHkw`XI7AU&gkks&SL zZSAa{9!KwSv$mZ#+t@8|sYyF;>{T@GSPb~YdW0~Up5ze%C#lnepG`V!tb_lTew5In zN=W3~8DwoUTuT-R*B7*wxO93qBwGtybOO0T>6AnxNNmIP7EzyG;9cq{a-3vMZql>a z!|z=f&<#-B*X@^{FY`fK=8GHJ27arXs<~s&HJTDI#c6GqrH#C+#897w#Cb?Yvlr8y zdRxADP7Bl*&+W}x9V}K8njPv}voQ0SeJ8(OVUX_K;#ed2_K9#_AcQHULq3>xvh38# z_|bhjYI{%eGGFm?g`|y_?d=USi<=?#2?b}QE?T7B%Bd9(I6(lZO^vHO==#ocuB_P? zM&mUWR*svkE<@)>Q>UW4j2ryJS-!n>C__q@jO`^3u3*kLbqvdURw3m_*B-xFiPG?0 z_x9TSyrL9G9W-|uI}T~bw(fHBOO468EDnuxhwnAq&qR9mDEyVn*ImZSt2)^{=djQZJIkWHl!=|xWrl}wr+!x% zjpe*K(VxH85Sqn*HUX)!vh=<8w3~ac!%i-M62dW|^d{*82r!YPOL{k6tY`T%kPtkZ04q*NZ>GSo@rP*4&Tyof^K7IQ_Lzj*)~d za#}me=h(vswXYquxITn2F18gG-JVefTc%f`#3wI|GR)t^w?Xq<=!T+aZHTpFCau{& z6Ec;uig0|Pn1X{N&MW@%n}b|8fp%v@q3CB>iDQo^+Px+N@%S6f*9F-7Wy5}=~w|9eo`2Kf!PLk2MzWk4Vh5E)3DRZyQXD75=u7`+y3U@1a z?Y!jpfT@<{y_$yUU8jYDBl2o}U+7Fu)>@x}-eI?61t2KLu2#2q`E6QNx1c30%`bXt zuvy}jW6$}rzE#hJe0|9AwA9D|+E1O+eC}Sm{hQ)C-yzmQYKGremL#H_EuAD)ca7{K zqZ+F8JE5v54o9pehX-1d_eVJnbZH!&ub;ZtvUpgTSZzo_<#J(Sq~qqFv_tE~D8Y!g z5E(8OS>P-BFL%~MiWA*7~nTIH4l~>?c2~F5yfC_~VVQ9L5p!&0bnY znQF{>ll+NwwXiSs@ePR4HzWS^PG=#9>h;-gO<=m&J66)_m?Gx9(%vGtcuJJ`b!4ZW?+`5DUbeiSG$QwPY z$YDi~XKiQ_~r5{H3x!yqte*1cbQ+n&xs=D0MD^{|+7*XiYqe2ci0>_V|D zpS{aR?r;v6i#Zyz`Jssudwe=vjde~j)0ZIz4-$&i4|YasTwVToxiqo1ro=r9k5D4V zi3tRbMAF?A4uPIsKsnYe%!aNFe9|l72Iy=n#I$=Iz-D!L0MWJIb>ed6=bz_W%8fiF zz64_27;iU+cdcwNyigeOd`}N-lQ_P@vwIhHkFAwH$9gSGt;5QXq8N>Z*vnHFT&~B8 zQLG_ZKI*K!ij;k8LwOx>M-{Q-3%kHuYIF)THvrK~GH31z=XCTlWyexijEbgBdm=j# zi9fj z6y~$`TrtTc0t0+OVGQ?=`f#p|n-eKvn4sFO^jZB0m2M~I%)^h#yyW!JVyBYk zFwFX_c2nHyrq%9W^3Q*%Q*5nUE&uufCEV%M=*IN=%N!PR4UE`KDMgpo{bdbB_H_T+ z@2T!nY!C_irmh+5zt|wZ@M>GMhP^naEojOVk^nxO_#y^_=b1 zKt$`or;nin;|fG}kj%V17S)FNYg)}-{0-*{@4_g?QH zq?GW2TGaQVbF}!&jY<32eVyBHZA?ojUuBZYxBe^~w@z=;o$M4hJBCT?e%BNzDg<&$ zG!d<_UzZL}3B`<`%FhtRbA7<{OB_$VwW2+&hT^(pt-^6mW%*&D(&NV;E-+)qUl2!@ zS`7U4V&5K3x47}4{RQIw^BjZX?3FUeuayD->i!Ojbv1v}t4YqTpee_}4@CKV>qj&5 z=W&nXS~BZAjaDC9<*lZeQNs1JUJMJw9Jqm7kyXf2%dQKm$w)fgSvDf!THX}j;1I_u zKU=3JO|j7-$-!~f5c*)Nw!BX!Ry(oxxo9NEB4fg=ZaAm_0^0H*dN0D5X2qqI+ac!ACYJBIc zd_qy*vy+Hje%mb!KJ%Ze7c|IF_v*S`KeG+XJQNeR;9DhZ$(bEz`_*5N4Le9n|H8`R z(#8mb2i?g}AsOc&#Z!E$KeuCW(=`eIeM)ay0-#`*<{(w_}E zhRY$d5aQh5y|)TA$RCTnH|B{}VLaEd8j})OVZ!n)0{1DTTbq%$i<6S?s<7xU$ow}o zAR0Li4f`Nl)Qz8LGCcyb|CZ237~#&Iuj zI@jCT;wn73B&%b#qLw-6?K%rA!_N4ruD||e;DyMV2oi+djiM&n9?eiO9v~bX-Yb|t z_1vz@JKM(d!}8wEdl}_&9)a^@{fa#05&v!uip;FUjcF8rFRtg~`r7X0rEMA1nuq+C zmv1Y)wyL6(7#~f7#Bl(LAI^pli#gAQ(;T|l(G$`TT~k2t=3;Bd#HhllDl%fN{!QNc zRhv%BJ5WD@%d*~oLJ)OC;3wt1NlEyaC`Xz1{q{GL*pfkX8`<=du1_bW9z+-{be1}F zAZ3v1Um;*bAyw~;OfrnX+^;)UR{Z)Z>Pi$q{DqrJ67dVcUF}$AY~~Nu8w1&stNu$0 zCja&mfruJ>h1}|%K02p7$mPs7TuwPx#*liL!Et=g6cxZ{hjonKsmHgo{Lbyd<=7e< z3$srkA z;-AoT@$=Y~ahbJ|_r;Ic%(?q_vE;=^K$s77&Yf9MT0&(3?kb6wyaq^IF{htUby4UV zzM|AHe024q-#Q;pyqUD}7XRNZV_f*mKDaLmD-02AczLIsHN56DTLUY4lN7Vn^>(r` z3*qgKTdFN3YF|~;JzrgcE3S0;56KV2jK%Euth)LNQl$9o?)7GT{_g3lujIvv8neo_bPQpYzr)R8^42t}LPJIfgF`nxw6+xpo9zB%{IYky)e zIV=eYj&qX5gaaOPv$n2K-ctk7TJyCF?t2>)-yH0pmUxd(Xm*-gT?dD`ex?rdK^wQF z^+Jr@Lm-gfTsyDUJib$H0vSUe^1Q%eHE+c+gU*>6VPT{_VcgJF8OMcnvBz9-zf7{Q z5wi@tEw+sg2{(Hr!o9Hvt$Mkky$;pU2O{|e;y1K(m_Wv}egEX4f^%{l*WV1HyGv5K z54q)i``AZqt`(CgDyE7^e9$_I%aJTxaE}timJm;rBNdv0Fp|slYh{)#?3LH8T0lNv zo$pcav62~%;(X7 ziI*cv?u;fsU-OCEpEymz+wofJD|_A@WNlwME%usD7jE*{DlOE*9Sa50`)v!2Tqme08ht%|58J0$cC&AV&&e7@yG4Y!*Z-K?0;CyuCr(#XRR0s%;&ilJY{ zQw>97%`giW>#`1StF&h}Q9SsHX7bv;#i@rK-`GzHsJg`PHmv8Q?x8Yfhy)&%C)JfB zSuN}Req0z!>Z+c^k`W2D zLZ*YP#)1skOS-W_mFhR*n0AA*xcwkP_ezUuxQ@i|hxf99!`sia7_9d7xD20xX2Q?O zR;SvM;!mR8^IAU5Hy~^KE_!{?28abZKQY*2+?X58&C+gmA0xh?Jyy8Nmz{KBIl8Ln zgNgK(xR+7^xQmW)yPv$fc+`jltaoyH$fI0=0&30K5)kq}rw@_Jh%?e=jKSOfi3gsD z2B)Z#-ygy$H9@D!P(O}b&k=DFq&gV#dYq7NcRCckH(Fq&SZ)I~@MT~R8 zFLc$5O>iljk7Oh#STGft>N4ZQb^@g@Gh5>_F2_PvrKZo$7_12qXJ;aNK2(|Dc-O$s&!mqC}pHtP&i(=f8iDS6aVmyZhxv7aotlMM1 z^O5~3S#kVqSTk#pf672uJjhqiloKa;O~e;751I5dTuG=3!L&XtidHIBt$OOSme<_& zh?z9l;++4O>y=>t{a6SzUwz*!GvB0~m!AmXD$rOu*D=exc<$zqS8?@XoGSHZRlB|M z+ZK+`{0eGiF;aPxeou{FpK)MFoe>9E!THl%{mO`iXtZIc$c9v-=@{=s3>|2{{>Y5& z?J{ujl836|0%mN6^QsrLyz-r z!rO<x`T z@zl3>*Qr-I2Ik2hTQ8`li01`f*OoR^UzJ z!PYgIPa*B+N=X9&Qn`|p6$73mlX^}pNOzTabjL^?QClet=FTwB2g$5zC6(Gf)Zt8A1e!Bx-Qva8+_7Jnq|gKiMw1 zt!wG#$HFE&BFUusy~%+vhVdvqufyUz0O~&xeDUU#y&4@rtK>_53FSFylD37BxP=I1(_GiMd9Y6 zNp;N)N=5>-E~4)<8G13TcqwPZU8#)tEny&S0G<3VO}<8HX2X7r#6-qnqa3O8y`x`u z6HJdl+5m?e4WLn1Ugx%KTkPJSy+Es0dq9D}y%t)LgcXI6Zr9#RfJ~PJj>)=qx?{ro z@g66gmcpToK*zN3;k&OJApes9pJh-bq&@zs_no*oHf0B*KW;ko)sJ<=61vRZ+b@q^ zdONr_j&xREH%R4lWWw2PpXk43?HPaN*lam62aZ7KNs^AZh%WDswN!Ax6c#cf#c=X|jnadVFm!fUure`79Ojv~StP3^X*&3o)WNH_-DRwxh? zBPA%$KpuHdl|sCcR&pKr55beir|u+ca*;0WdT6MrtUv4c^;IONcZ2#ZcxWp?Cpky;2;bv^P(?*ku=?HQRW!2fP*4MX3PygER zr$7qtW9UF(l-;u=<4IoAT)T)t+8)RPAQE}W(JoGpW#8iGOLG!Qcu^Lbb`esKlHM@z zs(2}7X`BPV`0D_Q5yyPsm(2_Z*=*<;qj;>*H`!A*ElG4Ak(_~uuXuuq+22` z=N^j(uGZ3xSgh?-$W$%QxzTu>5-w<{KP$aq*vdKyoGM%kLg0STXSND&7Re#+?l{ zc{fp_z*bVD@WfkGfb>j{F7tf60nz6}L-E`}iQTWGt&M8@g^uPy%&j-n>(?)N1y49+ z@RG2*D`)pWH4ozhs5NF=z(LbfP~M4!x67mGN~e1GIjN%v5(682?%&6TUX&vd@VU`N z_(%p_?SvQJWh`lh%_7;DIJJar zF`4wVpidM`j|mNa&K-Z>cYZRRIc)#|ij#JJxwm8{uK^f_Ra|;vi?3kAg4CspSZlud zRqV{o#`fmYxMdZo3Zm9UMi1OZPDYio)2t~FUI=v*7fX-5&y^8@Od4X4RCGqw`q%j^ zyW5p0bK#U9kBSnS=AzbSXWKwMAv(ILq&WIoRH0b-*Ehlisez4;1pNe6?tR6ZF~EI@ zv@=pf#R~4Rp!HtlE_lcfQb!5A9<2!zW0438E%DBS4i$ShLTzfJj<^GP*WQ~2t$a7Q zRAr|d&PYJsRxb6M;)TjaM`L-bw=h2Tt>tMKEYmigMbHbh1+9L~q{3 zfV{(gw`H}|w1H1C+h+SgtQ=M4uGe<&K1wo%Y0E%Ch9L2n9;YYjN_>@nMq*U;)xIym z>lpc|Zu27iy8%3NNonp$dD0hpUbqQz)rNZzozzQ@yg|*lRw{u$^flWTdcOa4;#^Ub zrSWy;)*~99)Y1ud>yJ0}gOFYN6~s4#CT0s8#px@FFZaAZ{g7G#I~HlmjF5q?HRIRU zx1oBpeS5mAoPFE5DFhkzF~tQ}uz41{aLPu??#M;|h#t3-d#{MZcq-*^By?7Jn%n8_ zEjPW0o~%J`TqP0%IN$UBX1-DVjgjjNaw)-X^{ILhvqV)C{$u)bj0#&EIqlzjp-IQpu0R#0RZ! z7V<+=YTgUGueWcO`BOYB)|5nFV4N$FyowHqe7UXT+TR5fUzq*e4&Aw*S+I%8NPKPX z=&2kt#A(=secfIUDpK+!1}?JST0n;RG{@r5XTgGG48@x98=u9ha(hk(_u02n;_h3= z0 z(jJH(+m!Z(h@T>Yh;jgLclAl?o2oCAl-=)UJ;LuG;qGn8DrCESmU7ydcYKR{ar=-I zrs+h2=gcW{{P15v;=L(zW;=sVb~Z9MG(Yl!o{x>boe9z~92z?qZGCl)F8x-M?$Z6) zeqWS;@$Fau_IG0gTWhD%Z%T{|qwBwZg^-pJeuK=}Ly{k;$Z(yk2Xr*KM4uQWI19Az zG4YVDaY}IA4HyJET7d|5?whUw3>s!8YYLJ&xIrQ7ifKnCQVKtOw&nPSSoPXn4LKgt zjJ8x7pt*UgU|7>d3s4htWX-$19Vf1HI0cjyYuCH&iU#IADFu8&&^2M_Z$n4E!<^~5 z>oqESaEFNdcX=l>_k=Vd-z1>3%vl@X8fxSsvWuYe8@`|j?D%bE7s_2k`fc+eRRu|n zlKFgoc56!&dmJ;5u>BB@GyBOW|Ac2$qynd@67SZ@N`?rJmi*#Y z1vZ!S=3}9|p}>IFN|e;VvtHI~lebd9LG3~BqusW%lraF=B0!3#zc4N}$OmM?0u1+N zZH7ZXj8NxZ@5iI%9J4Y+FG%YDJZJgtWItgKeqII?%KHO0a(ORYts30>qK;P30`aQT z(A`UmRU>`73pk`gMVl1HJm=yUN^f6+B8%1wymGpd_ix(YR3ocd(%qe1L`>OBMi9AH znKIoB-e-)hAtg9I2HWsVOW>!+tWaI;ZW^qQ-!H0^O|$=MXd}D8S~JW5@;5A~w|5t> z1unk*GqIdxeCDb$QIL!s`LF`A-!b|)k|3zrxDE-GjQc?cKa9x$XDEum<-8b?C;A8- z;>eu$&is0MjkI1^QRFd1V8FUG9>w~MbQdBzXP=OY}XTb_mgvSmy^e+bPvAu$ni+A z@uC|4q_XxsppC~vcahi|n`u=65A2|hQ>?>uvJK}iojbxmHH$6KpDlQl?#1IWMJ z&zZe?(dXwoqke?0_v%o$#>Q(7r zY6VZc(Me~GRf9=$&Ir2HR3*sflXURGwxr}X^Q%kxL*b_iLEUAcHpyLWBm@JofH2s* z0{NVt=t;ej-KT8hna~bO7Yl_yx+7JJ?PTe;)e{3tkZo_`=ejwwJH}rAxN12ZVdyb= z?uaw9C79<29qwEPPiTV^(-~mQj{Q8v`h1YiL8Sz65=p1fGfG#FX9&My-^LxOI`mS)$wg`JO;RALVSTdz_T=Tqx%LjfADZpT}I-uJ{aK&GB}m;mv)j zBh~Kjg@{4!Vy$q8iB6D{LYWb6R&%mS)q27W9s@rKfwY~xWsb)9^oJ`pt6WX@Ku*T_ z{&kJX=*$5+Nia?>M8byFeJx$52<43_gI6AXR7|aVl+e0+ID7Rjf+XuzjN3c)gowikJc8dsZDo4iD`~YQ}L*oG#_$=QF7gYFL3|~;3 z^T~YpbGeI97R?*uLqVM-rkuXIsfU=R%{X|MA%_I9YqLMYD@l#_;9Q#n^C+vKr;5ca zNrrLTQIajFkWre}pad**ZT=M$<8x4>nD?QKTe;^)z8h)TOui{PgdQ+*xn7XrIre6B3Kna1YK=ol zP3BOa8h)cf*i%D{GceVDdZlA8iH;1qL03iy2dRuikl6V7c&hy##x&x!@zbKw_f*#t zQ<~q|)gh26g6C>zF$m~369S!iDEc(|(?j_N8IquPMxlZ;vo#pQI8)V_5xG(BZ!unf zx;s!nngZIXbdFlA=qcdP4ZZ?EIGYv7PftFK8@<$;us4GmUf*EmzNulXRt(B2JxH9g z=Xt@hf<0k&!?&RqABUri2hb+#dT1!CR{YG>W#P|>#@e8ngK<&z@rPMw)RBJYvlU$F zX<@#k^cB-l1rN|K*&2vQDB@hvJamvADOM0&IJptBinn=J{7fJx!=AW0Wb%2sfKGB; zarX|`F&|JEovcwd$f!grYUoZB6nU3b2Qp_Se&3}EY&JLC`r1#BvZX@6Y6fDiG|Ep6 za-pAI8l|j&1MkV$PGYZY&W$fdduUvU>>DX1E}eWUKjneAGcD6P>%{=*Ug#y5nYb8T zINA#e)}S04Z6ecl1T;0FkvmdHNbl~iUK>BrAqX4wd&$5RKV9u0YAhcm=zSk_#?^Oc z03*B`Pu)`lxy|oHSDCwSl8lS-M?^U@X2bQ}#1SC%3);#wTisq3FR=ml(2B&x=4{(P zwMX*I*9CL5C(qpCs-)PfXtTTow8!{l4CXvZ_b;OT)uG;LO=mdH&#tPSZfKX4%jl|Z ze#+#{JsSHLshX?w$-7$1*6xXn1|q0Yo_7j(4O!%e^BbN7nP4YSx-4K!Ap{O{2Hau< zMA^FfAvZ)GTt6boAH%tz_bS|V&^&&3g{yOP&xTJK@%xMG85eU6T3Kz+fWEDj3gU}8 zZM(b&Uu|CB05Q(>(uG7}r|r(QTID==gMW^OSN#QCg#jrIExZoJkBtgD@BR#W=LC8^ zqCrLPT*1NPgwb=<;8x?JepBXaZz)%>AlX+Ig1HX@9n`#kovN>ecP7>px(a-?z+g) zGJD{bpew|m&j$AggUBIFpV;U&xe+da5l(AfcpKd#f5y=aao^&k!Zy$5=%FcRb+6a5 zyR`=i=)mD^5ChypzC~3q*2*l&Pesu~FFP3G=5uR?y|`Y_d=`EMYQGszKE%#wA4$6x zw;jaV_cBH%4MShOUOsAezg9p(bpqL1%OdsH>P7{af~%3BTn|==(9)RNV|6v51vrZY zV2tdoUbzYte2BFG{EUZ8tFGEGR+R*hxy{` z=p?12G80v9AkFuh96cEuizM?@KF=2Y9sUp)BX zXZ>1xaccesf!3SPLGBRarqqtq{nh0yBm4XuJB7WF1>6J@cOQcq1PQWgu8{Ykmo6xK z#REjIXt{hUxrA8~^dCoW)h7J47-Gf&VAifTZiQx@?rpy~_`syQCImwdY$36~0x4P% zEklmsHD4`g9L3Fs@_}k3&Rv@Y$5X9cRg}L7$Xy23(xoQ51ErHY9;KAF@l&3f;dnC0Ij7- z*iDM>v>K;{d!`^>evsfky>c&WjJ09xQ^#Ju!^d-sci}uGe1=0Xd^p_FA+>;GDC^lS*`Bzz-xn!V zNOzYn2!vyQi|_o-f?%1(>6(HBnc~y)pM!mlu79bDesG?|PGVpH-`fv!Q;b)z+Jr!ltU%F*m0be4h-QdY5@53*mf~$>r&GR^%cK=8LUG1qT~ zupf*-{AM=<_P_TBM(UyMEX3mE$-smKcR^RSR z%@vQl;8L@rb&<$R^3mk=twU<8L={%~O_Ai?`p`8(id9=WqOT`$wGf8JgLx#G@-@pIO+EAKieM;n`i3&d`LCO%EaBm|1X$705x z%XV3$fF3>L2e(sQH@m)ocn*Z;dZsvMP|%eXM+jAsxk)}^S(cK7w;Janh>?x?FD=~F z7j!^>{?BYBhw_zO#P(p3sqq%UsmRvjo&%E%YE~(r}q*(EX$4K7vlV$_~g8S_jBH+#?R(oawqmgKnvXZ z>TCBOvHAACknQ?>e!cmd5_X+DOysvGXD)z|6|&^5wg0_+hE_ZD%f={CPdY zoDy%Am-M`?htCmec2|nl>wrQkCn?Dsc1ND(Cd!4LOZoJ|dcT96ZMpOWBQB)MmUzbj zRN_ERpylyl{;2(LyzL|`!H#}x2ZJ-j9getI#6!Ft`d%qg8Qk(RU2~i=bMJTpZ0zsp zTMqsiA%}+o_2KKJ_DyFP?4!*gg+TCxCBT9pe)S{Lrc|cwLC&9nBvJxy3xPvUb=rL` zDc-GTw1HCm>S&-%sR+@=P6m#_*jXo#cJ0H~4J?5ee_NM-&*pG*fs5Y2Kn!hHU~Tw? zs_OJ4Q2zlYU+zEd2@w5XmrnTSR1~}pZCa+3HZAjrE(vx+RB%ZQyxEmc`P=sY%C&E8 zohk!wm#vC6O2pttoBu2y+RDd|9Xz<=`W}1Q zWmBuZnOk=*7=oLpVpT7+Y>jM!SP&nzept3mq%JFwo+TW0xLFAF`&wES$%oDA1-E}=bp%6sJ4%(-RCj!=y-xbIuLGm zSqiKDNIgPk8PsZtF^i56ZN0KCEKLnM#&_j^Ba#zyFX28p-~M!w|RT zAJV|$GiU{qiTgfHmYHZW_Url}A4-jY>}}92GbO(`&&oqE<9>9Mc2$yu%yjrbX|$=c z!`c@F?Y<5Hmc2B&`aw;3UkC-Tdq{U_^LIvY9YOw&yGvr>+xNgl9{;#N4qSai1^38- zf80Q2yKwb@8g*jx!lUy_3g4(TaM&_7JvMxIs_C-EngVBC<~zT4A7j|=5?1Z`jk@lG ztGl`^OZr<=_<9W!-ysyD)}TQ|?doDcdiTaF|CdicHFg&o7K~S4#$798t#a1fnldXv z+OXuQ1X##N{si-Xxy(hJafL&c8bt1&0@My3C;ZzR^({41`QopOKw0A&FjQbbumB`0 zKjO|@I7cx!sHjRBM=fLjQX;7e0O6dkN6H4Glgne;wH{xEdS7nCOd8gd2#gN@*XuRz z4l_#%*GIWFB);HMUzL4(&UB~Y?|V6Z^tm>wSRw@C&N>e64QEGIHeY z&#*<-r+w=lh}mb58Cj&yjmw z_v;$>^<4M$=+gdpi%Y2*f&RGOM?J?qhgYW{CYJZ!&D@Jx+G{FKef%}Lb`8(-`I(+J zJ|gzh*qx|{4tsjN!SWM!UWvip++^9KpZ zglIlH=m%^(*q(t8e$Ba6Kp+3`tC&bSL>XGl^?Qi5-L_L8{iff(B6g4KlFmcY^b3#v z8+2ASj4<+SA;ntCKhh3#3LS_CUkc7Ti```CM+Sc{H#Ssx3R7pmViI9l@D)_vq*zcS z=tdjiy{`Dz{oj1TYqVC*?~(@f5}9ufNXAc;!d&nT;?GpTJT{p zvPHOF(&#Lqz2Ik=yo8v0IwOCd`5hkqRD+O`MR9CqyiN3nZ`R^USzp$5w2Zu-g*N-- zg%srCY)*3G*3{Xy6JxT!9C{;ZuaV@%h%~uQO?W*OYc{Osnb-IN$|?s$2~Ap;M#fDX zfZzWklcC)?=Fy>P6TkgOi%2@@@kkRE*N@np=veAUtoZ=}XxFzQTGu!XyJ@Ytc2pIT zZ&7p7;cQgw-6?fGM0(i*V*Ln%KG6=h4{Z)TB!pi)^laYdWX# zwXKQ&Qe~&BX%{WY|IqSYEvyeI>V$h%PnXSzyFN^Hf7~_bsuoiB7^f5()Mm~0v);66 z3!IzwekkcXw54W=x9&}!vjoe?79`v$<#Y4u;Ie^HX|lPnQ6{WENCAln(NC$11%a0@GkIc_6w7xtXu~c>U-c5%0s>0&e+9fN~$r*1kAB5AKE84+#ZtC5 zAS9u=lX41te7DSMH|7#ndi$bY=fy=&YL>IFL?yqRuZ&Ndsji>KY7l2BB{9+W;?qd9 zd~WnM@{;=M_NC3ALzTHmF1_c?PsX`cRrRy_3O8q~DM^)@-cy3Cy%}dYUbN5BHe0}& z-cY}_JyGLl>f_9B&tEO?Tr@258;w&BL(7h3EH;T>s&t^Vx)~X&N7~Db-dP=^z8YEm z`nhm}a35@VrEvJ$+m&zo2URbpxg{>jH;Dq002$XsBNL^@E@5Bg`CVxG}~ ztPJ`?sB2Pui)WOq^T}IR{7^(|o38q!U69nA1lvw&-nyn-n`W-OwL7B!E`d6%OtdR+ z-3|bvVZMXP4weo{5jC9eUg+gPnwWubVc z{_$&Au@@U1ZzsA+-$Jw1-*)!EDb%lrb49-hMbII<3QOUJ>2CM3YfnOX% ze{+sR<+5QS)FLI^#UcqiB4pLSXDw>B@Lsz$>~&8(T6wWyO8Q1_ts0}H*j3~(E;VJ` zFJUEU!<$qxJk~d+SgrqLARDpy1MfWc&3pB2Y`pR)XWV&1l}pOh>F$(kbB>);-Y++%*#Z%`?vja*lkk7tC~w=b$VUxkvjMD9VL`~{wL1T)uyqIhLcMl>phgz<6DxU7k9?ax<{Ge=yIy5CP&^H1 z#yD`*WCqe|pJTfc+Sz$LY|ujLG?Buwk~)Fj?V8+C(U7aYf^g}alNbJkJrGD;3_`XC zu~nZ+dHN|Ffn26Kqv~FU`d+&I71@^SO=y=H%WJbymW#d?&vqfKv4aEP_K6NwT^cf);{_0*ZdjX5?oxcOBkc)o4oaD()b1Xe zzsYR!sB4;6)QVM^KFt#i*ZR{u%$vK2Yv1?Q3OnPOAU@aZZ%w>F8%O$?Dc$nx=9_zN z#0>G%pdLq=XuQe)!u0;JL>5g;R&0PgNX-!VM`iq?L40`=d42D*0*ZTcdrVXghXj&; zAej2!M52frbDN=lVk_1o?}b%rbatOKjmO&CD(cTt`}COV#Irf$59s@?sXM$c0RQ{2LB~L??udj+&F|e|ht}>bMiYukM3%#d z6J$ebZ>JS$2yGU=|123@Ss{xw(x|WX+EwB#8K_3I$61J0A%!rACeFA)p~6_MdIuRJ zVtw{YV%+~ECXkpTX)oO8u?^@A3}AtnvR*^=b33bnl*+0F-8X-R5_e;0C(rJI{TcYE z%-z2{H>6Oi z#VyJ8T4Pf^$-1LyxdD*sb$0Xqonn%*s%)x!fiA4JCV<3TS;1?j{|onzd#vO-DU+^kHJy$(;p*c}Goz<3g}<-A8%QfrV7Sd|K| zjHWF0#<*Q%@x;^RCDqv?A83l1yrE-=9L`>s-D2&Xbu{;TAXkjDA*i<;Kh`|{94j^; z$KXx75EdNS1gb&+@%-=J+-BXlSZ8Jq9JeCbqKgMS0uRs5m3+_LxvhHe+l(WSgpL4` z$^jYI!Sy!$#tJRddvXSK`R2;BHqlE1Te?ynN+HPTlD8_d29g4E59E}3h$FN}*dlKN z?oc`_Ylai&)hxBiVfZ{n6>HuZ{1J#OjJsQc<(GH(An>kmXOg0$@PS;>T+}I0I^Vr4 z1yA1RWSqA8^OLTCmE9W_s3(KTU*MRIRdLL%#DZ?`SrF9m zgV$NwWRH;KhQvoU41(*hL=7=M4RwGP*WIG9V2)`9m;3fGMwx`&tWcNT+)5>0O)Fki#-;fWXo3u{ zdF5_esn2o%?C@@1?B}sbxeccmJ)0}OgX!p`+@BZHmYLwFMWa)m7Ka}% zyw{haJ1httgoM%;G3%p4u*r`DS+7rO&B;#a@Z&iX==0us}QYxeL#nK8YHI{;s zjSc=XV9FD>;eqW6?8r`u0qKPR;?a|gVQpmVX_ewW0EeSI1mz{JO#momVGG(-HtV>(9$u-|CZx2>cm zHCg9?KX1H-VxLzUFW>yd;A})8#!G4%?%z&qyO z5cg>IW~b4CX5s+v_UR;|y~{kbiL%Gcm1(1UWyr@RJbj7O!g?*)4WcFZim-q=msp9KQq zG@8f9oI@RU&bEn{Mgxbh&II?Bdmc6@6NJRPUq<)j%h4^RHx0&Vz#&LAAyrH22c@Tv zI&M_PgKODJHW*FP1+2A(&lG96@4Z-cDU4LIfMenCwO@3y4Ste*DEQ&7#`{eFK;k0ei0q7s%` z-uj0V_iUIiK(MQ5Uv7WIQbTpT{z?aBF*2R3K5foA#RQ?b_7O`SZNJ@WEU1*c|3@&` z&Yqs9$u?R5z*$`7l3;KnTLIucX>T)RaQ?+IXLqtF_WQi#b^!whsV8dHu6l@f|Mb3C z?TqM^(zp{ql=SQ6ZReH4_Hd}n3$RzWzEN&hdE z4!pH>v1v!^+d`N=K5)I;Z|pCT7YA&QH#s0K;c3jXgPp_R^DD(8cD?#fLqQl&HaS`4}Y5{q_SFqBd)6?DGj>Re~6WkMy7UImM z%`Bx#9;!Qk7tty0JIXYA;%z=~)>11D3vZe(?+nX17aP&X2noFutXNjuAgQO)k&aO( z1*oWDePob^yA8d`oz-(=_$FT5;0+&N{=^v430!0C3&kHsZPjx3|9kpm}l+@6N7_$$g zMz4hZo@Kri+$Ug|$0{{21iAeWX{qW<>{X}4Vnat){3%_(2<3X4=8dqY>UCi>mmy@S zscCH&#(5eFfIOlg67QU}(ZZ97tXn%?IN=p6;Uvn0ea(YyW5Nt!1G{T%-N%*O2wtpG z6(20!FO$A3-ApSBh4W7VXO}#Ga8Xwmax_gCL<8=`uTQw#swv@-uY7t}TxmcTA5~He z7?ed0YFA5^$d5~_WuuBE8D=5x=ih^G2ipmC*Gyk=_j=^#^__Rbt_!fg#uQyv1~Tst z++;9$^lJ*mRnH+!@M6Xw90(aPOb}{2qm&ZE$lC0P0F-vPy|S;eNUfdTNu6wDdFjnz zYmro?!g3FNhGHk<{bl6*jq`uMBUn9LT#m6lcM0KKdlf<6srUTj=@Mi6&+x6h7~kxk zY)zkG$L!>B^2_0PgE^Wh5>dD89TEt_0c1@>R_=kjUr0YdMAJ;uKz6BO>A$OgO-Noc94;oens9ZkMsp*%I^B$ zhz|%}hH9|%hXudp4iqGU74dd?W=ztSX3(nb&lXRiwZ2$#_Tq7f?xmC4|ET*c2kO;( zaZKK4Tx#eDJ!t}3r|$K&S0^mMbBaRK)CXtyadot?-7H6!^zuOII~^R~G$*-|>s zQ;k09gk>u1T}HM0^TtI77(E;RO&dM@;O75qnhDvryRvG~GYoz-iQ1gnVgoFpm2eJ7 zMEi$pCdaa5b!Fh|^Dv{E7`c-fB0kuQVN52@0|}ESHk^eXH5R;1=d3tcBWk6R!x@Q9 z<>szUYAFB$TOnwZ-J7NMJsQ=+;uL2*lGiz862x*^MReMy!xVkmO69!wMnCyWm;`PtZWkO1Mus{&l6dc_c;4W%Qb#Tnp02O@09OB; zX9X#YuXzzeRkRsew3r0(J%(m+ zMAeetsAjA9d;K|7+9z`n(T&Fw0mK6sa%Ig~j!{?tpV-%w=GFZV0K8Q_R0coz?C2P$ zy=RB8+Qp2aYX1=9VyT7Kjg$qs{`6@f9Sy=ivYCf7o7i>y0ddt69}_rOrNlj@3!FaO z$;l5_AiLirHTo0I`n{6O>B*U!{`k$k3Rw6#g#K-KBUGeEQXM$H0f~Y4dZZ!&#@4WE znZV;+?S8tF9)@muw;&#UTyaHxD*tYtLWmas5ox;A-t{~0Ofr}~(z5Ijd1)MWl?j(* zbnI=UlajK=-Y|4~G*nrg9kaf8s%LoXiSejMHm7p}Uod!**B^Bqg8GN~CDs9JU@73r?m0dvH6BL*)LrjJ``Cy8UlU3I_4H6lIdC})C&dq74baje#b?6xfr z;zptU$Kwe^nIqOGO>Xo22)B5;TDiP0UAowZ)$?gi0Mew~l$zkC@%-p<7e#QSE8xrL z&K=rL6_ATdx8+uli4~hNIx0D559YbHUp~Os2F&h#30AypOZM2`FZBJPePBL(6KfDG zY>FT`!xM{W=&!Gh4}LxB*_-EAaQglF4TE!2qyu?cI%p*%cR;ytDD|=xX!a&Fl)+@> z4~i9#*7uvdCd$O7C!-0u)q&E3h~mSY&~Ks3k9%Hgz95bxs|a`egd8AWRlKJj`;{H8 zAe_iI-+A+V)64qx@~t^kZaZj$*1GylH1;|tT|nrn7TLah)-T(nm&EHkqTLfxmlt>K zN0u`O!N&E*1uK>2&ecKc%k$9VE*5qCx9@tdg;d)xn4FGo8faJ4q}h4cJl}|%PGK~0 z1SE=i&Bt+M>xR^3MMOK-;L^;)g3-tpNfGQ9g3c*i(%ivzO-{p&eE*%y>P{L;ZLF0< zO*Hpi%BfQVaaWDDt`<0z%LbC*R#NrRA^Ln$BmH0N5qY7ac+2VD#uZWrHIADd{yMt! z-bD^bv^x81QqOD4cCzGXtJ+*qWzPE+2^)j@=su+O?uDy$qfRfN7q|VhPzr5a$iU{> z!PRHq#D(kglTJ%@#uX7$Dv`SplRObT-`+wsUiR{Am?(=#J=+xvC1W@rF?1uIk1Tfv zt#3HZYa^qJ%PnRP!<7kc-jY=s;3*Lswoy=q7 zjZmJmgf*)ldtLs0`A5M^#<&Nn*+~njSDp`#wX*X?oY238pw?Zf=RFRot~+2?C~?z= zz^G+!4Th=O`Kkk9j38L6Jhj**=#b*8D02a6BdtPBM=U2>?iUUrs8QCe%h92o<7H8_ zK{Qe*2@{={1!X93Y=1TB_+d;kCUKltc2Ec-H#y7}3I*|d zrB=t7c%yIsS*bh$WF76%pGU$5k%m~BrNkN-G)4lB*`tQ%q_n=+l z;iq{bUxOz>ZO1Wr3MPZ+JlC0!Mk)6NDh12Ol)XkPjKrkA0Cbc5(e+Ok2)cY+EL2}F zOZ8Pb{BUC>f3o(u?3aj<$S>D&WJb=_dg1k+{wv}3iIcJYDV?-y_718Q& zeyt@xC5&#R;Fu?BUMSu68ssZG@jzuF1jwY9R4Xa;VMFo3$`WQ$@Rnyc?bba;-4g2& zYbpi3I`Ml!bXDs>MqjbM+)q6t2c2pb>W zGY74db@C&_`;+e>V;1@|rb-^QIELWIVZ7411Gnu{!DsKLi=Ij@SAWv6S);cWI3(kD$a&qn_B@=uNb%Fg;@H1 z-TeTbP)@86Dp`u}SUP2@eNoBjY%LHu58lH5l4PapZ#|r2 zdT7)y6kc_2XR=jOacO)9HAERXEIuvbj9{|vXjY+i6`Z+6(tE6(?XE7!ivyB<`ns3y zw6UML45A|IWhi@DbD9gh*y|x$N?$||XC^{&x2q2o+7lylSRk*pT&p{(qA0%#>q_QD zaxSdwt*?&uwd6-CT2J1j{sK{^-G;W+DPHla-Wu*qUImskqEx`P`bO858Xu7lv1(xe zq?c`s0bk*U;3L54!NNKFEi8RGmWb&f?r3+H-^dZUe6L5N_k2aaO4xtdz>dGnDV&j; zVc+^plDJ?<=c{N#R zNl4=u^cC1s4Le+YNq#kGy%cw-$yDqB^>2s;Rcc9lt{#U(CmXP+iO+=ElXl`$7~)>4 zxguekZ`AEIHmA9}hRdeE)TDGss$%B}i)M4Ei|cDEqLtTDsPf5*Rr%63Ae{B04fRhK zzEBVOYtM4+Z#I-sH@ndGq2{Ks%)-zxVH$ECssfvzVwSn8GVwM_edE0&9_eFTAN^~> zaV5HNHvU|Y6}6D1H50C@inC#ivpx9jiaa94iO-xu95Pv4lgthQ^HfmYLrTxNdv*_n?`y`kTsh&P?q+$5Fs^?}rG9B9Ye4hn z^rC~-=(uD(N2r)AgYIuR<#qfu;Vrx8W@B?U`N4KzRxQPZm`=-bOM%sclk0_!$;fiz z55Nx*eT)TKy*rJIdYrZfFs5GPHX(7tv}ccd z=|Dm&C4jJj{Jxs;ADzZuN=fLqOdlsM*KBlVmsvx5M|fhDOnG9O^UbQ%m@+d*&9hTy z_V!5dX{NXbI-}B3hz-kZtIf<>B(uq}%Mq#7jV@KYu0LB|35*{!`TA^`vtCq&$I!l! zHl&2f=>sh{hu2SNdQr=-ug|GySt^Hw^=F=hyt-Il@RL#U!&<(mRm%vg@Ro0l>YnX~k@t$|rE_&1Mv8#o3 zSX3>1;)S4b<28}^*+^9O^A2Qyk=((-t%plBbBku*jgHy5-Z1H={%qRKM)W^3GnADK z)J{D>-(ji9ya~-NxhIRRbWWHxZHuO8Vx(SCEHB1?e`*wy)iTyn@PY<1{5`Jf9O0N$ zA?Ct*!z3&s#YLp@wiVa$-17tDbCl$NYx*PZ9lfVj+vBqnA>IhV2%}C_8PY8FXY_zWBJNr($r?|9u~3mZpet21JYr4 z&B|3i{^8x$ine-*7LphzOTo&) znp~R%ajC?!8v&+QVw*oNAPdLcwB|q$g%~AU*CZ}jWhpDpZ|=i_xR z1H;{7yoD>tJD#jGPX&Goy6|1x=&z1!v4Madm@QlV0*(c`h2$(gEBP#n4FYX)CPW*Z z&f2linDz8lhQ9{~q;E)kx@kpXfNsfJJxu-fj9}y7;kvk;8Xwv!RDS;QW#OfeYD#kP zwT9nkU@#bU-(NU>@J45f&2>^C;2Op-=;x+7 zSFEbo)lz6eUjU~-NkPa`#l@S~R-GBK^^(ARn1G82_BU|WDyk31rr@yFU_Y^Tt_|re zTWe>aI*QzXZHjZLCV#VWeIk$w)X)(~14;?yzeE+`C;H;%JDX~?KP9zctzM;bbB8Z< zN0i5RBJx};S)n8cAcBh>bFo1(qN8A(VL}urhcynT`382`J)GkW zC2K&op1a;Srv}*AM0*19O$QKvk1p$h*~#-`uQIl>zhDI@miO4K8}`szEtEWoI>^85 z9CEM%4F48T&p==kzL}Hx1-SKsyPhUw;M6C*2^{QFLTSAI^r}fpzZ^q&DimNqqNQyq z85ef?AQ$0HQ4tZz|YG>bLN5D zPc4%DY~KrlqeQSPOmSRY|5EZlf(q5s>*h585BQ;u)AaJFIo`ilpseeGED)Xwqe1;S zP>8JIY3buWw43&N9LeA8NRLfqhi`G6OU=nJ%s27~v+jz$N%+`6VC_&+Tcj5ZdyJQFXHZ-ChUszd2Z3Z+FuNvMyP<^0Txq%ll~vU`N2m`qBP83frtOH zK;>YKGXUzx4FED=IGyhECW9AvTI++tm2SQQuT9ZOC*ke1uEUFtGH2ww)Xx@A_-%Rk z99YOj4IkX)m<&yyqXu3DHA(Uwjs7AXgOY#q#cH?#X6lBq0y%tgH61~D8n7%T^wcv( z!52q0=>OyWb(ydTu3tZiy&n23kE|GCr2Q0`DMOkOjrk(82vhmnSLG&dw{<~va+5rau(O@wVzykRVWw!PC^uw2|olpGuqacVG-EG0h zEBL;Jj;C}wp5#5(CCuOeE}sZxNhq*k_gLxEx^}FejhX*F*pZ!HL73I{1~ltvzQQJ- zru^x#n)I&g3*P7e+KYnVNIuCKp``i>Tyt0r$mw z*Tn)APANA1B6kL_{H#|EGf&9a(5Y_Dm;bsZA&s^IIz9dhAdehCg0tw4=8R%DK0WmJ zi9-Kh%k%$%y2ic#y%`Dvr!b-y%owjDSxZi1Z!=<+>m{{a+fM2WKcs!Gij6_*8OprK z0YCS%OX zbU2{4dwF7xgekzMz*_rfY2Kw@=pR-nYsq=6A=7`9R)KEu)0aS)^%JvypXd>Q&|T(? zT*y0-lc3-Kzo_x*;*Ww%h7$zhUBdeQ&+mId+ChZaO~pMAfWeR092glWK>y;!Bn8n^ z`g+c6TVOyi-EVLViH|v29u9fwJyA}t;WR(dQ;VsWAn`{2DA^nTO^6E&$obpHwf6F=<55Id(J&wof53;N$^ET=I|YwtpU)@KsQlAc}c8PZY}K z6mFq-wzL)v^`Rx=+wxnq=zaf%jpG*RRWn9@Kt&!27JtwgZfq6f2|$VfQXyZiQ2eF* z&6~sXfE97D+W+Zki-FkIfo}M@ybUQ>t+uOu)-Cyvuh}9e6yyr|do9H|+TUP4(#fC) zjgVu$@8w>`WBV*0@tH9tTViX5Du?p?s;S*L)2CiDiBb;!PpZ%-jTBA>ObL6B-X<}C z;D+qtK)KF%i!S2q4S+YG{5zh-l4g_t@wiAF&a=wMoE3O*g&2&^^^C4V_ouy+IZzT?|zp#;~!M5pNK5 zfYz9Q1?%S}-=Oc8+ppzdNS4{wQ26#(ImJ zPOY;@QVSDF15{^au?YSSukb5~^4+ q7lX3vV+Q}hCu1XjH0BiMkp01nL9b58_i_f{Py3<%gQ9y@um2A#EJ$?# diff --git a/msp-claude-plugins/docs/scripts/generate-plugins.ts b/msp-claude-plugins/docs/scripts/generate-plugins.ts index 793fb8d2..aa2b5b3a 100644 --- a/msp-claude-plugins/docs/scripts/generate-plugins.ts +++ b/msp-claude-plugins/docs/scripts/generate-plugins.ts @@ -19,7 +19,7 @@ const OUTPUT_PATH_SHARED = path.join(DOCS_DIR, 'src', 'data', 'sharedSkills.ts') const VALID_CATEGORIES = new Set([ 'psa', 'rmm', 'documentation', 'security', 'sales', 'accounting', 'productivity', 'email-security', 'incident-management', 'monitoring', - 'network', 'crm', 'marketplace', 'marketing', 'infrastructure', + 'network', 'crm', 'marketplace', 'marketing', 'infrastructure', 'automation', ]); function normalizeCategory(raw: string): string { @@ -32,8 +32,12 @@ function normalizeCategory(raw: string): string { // ── Vendor derivation ────────────────────────────────────────────────── /** Derive a display-friendly vendor name from the source path. */ function deriveVendor(sourcePath: string): string { - // sourcePath looks like "./msp-claude-plugins/kaseya/autotask" - const parts = sourcePath.replace('./msp-claude-plugins/', '').split('/'); + // sourcePath looks like "./msp-claude-plugins/kaseya/autotask" for a + // nested vendor plugin, or "./advanced-workflows/advanced-workflows" for + // a cross-vendor plugin family living directly at the repo root — strip + // the msp-claude-plugins/ segment only when present, but always strip the + // leading "./" so the repo-root case doesn't leave "." as the top level. + const parts = sourcePath.replace(/^\.\/(msp-claude-plugins\/)?/, '').split('/'); const topLevel = parts[0]; const vendorMap: Record = { @@ -293,7 +297,8 @@ function scanApiInfo(_pluginDir: string): ApiInfo { // ── Derive path from source ──────────────────────────────────────────── function derivePath(source: string): string { // "./msp-claude-plugins/kaseya/autotask" → "kaseya/autotask" - return source.replace('./msp-claude-plugins/', ''); + // "./advanced-workflows/advanced-workflows" → "advanced-workflows/advanced-workflows" + return source.replace(/^\.\/(msp-claude-plugins\/)?/, ''); } // ── Features from skills ─────────────────────────────────────────────── @@ -427,7 +432,12 @@ function main(): void { } const pluginRelPath = derivePath(entry.source); - const pluginDir = path.join(REPO_ROOT, 'msp-claude-plugins', pluginRelPath); + // entry.source is already a path relative to REPO_ROOT (e.g. + // "./msp-claude-plugins/kaseya/autotask" or, for a repo-root plugin + // family like advanced-workflows, "./advanced-workflows/advanced-workflows") — + // join it directly rather than assuming every plugin nests under + // msp-claude-plugins/. + const pluginDir = path.join(REPO_ROOT, entry.source); // Read plugin.json if it exists const pluginJsonPath = path.join(pluginDir, '.claude-plugin', 'plugin.json'); diff --git a/msp-claude-plugins/docs/src/data/plugins.ts b/msp-claude-plugins/docs/src/data/plugins.ts index 114ab3ff..4e025769 100644 --- a/msp-claude-plugins/docs/src/data/plugins.ts +++ b/msp-claude-plugins/docs/src/data/plugins.ts @@ -5,7 +5,7 @@ export interface Plugin { name: string; vendor: string; description: string; - category: 'accounting' | 'bcdr' | 'crm' | 'documentation' | 'email-security' | 'incident-management' | 'infrastructure' | 'legal' | 'marketplace' | 'monitoring' | 'network' | 'productivity' | 'psa' | 'rmm' | 'sales' | 'security' | 'workflow-pack'; + category: 'accounting' | 'automation' | 'bcdr' | 'crm' | 'documentation' | 'email-security' | 'incident-management' | 'infrastructure' | 'legal' | 'marketplace' | 'monitoring' | 'network' | 'productivity' | 'psa' | 'rmm' | 'sales' | 'security' | 'workflow-pack'; maturity: 'production' | 'beta' | 'alpha'; features: string[]; skills: Skill[]; @@ -113,6 +113,34 @@ export const plugins: Plugin[] = [ path: 'abnormal/abnormal-security', compatibility: { claudeCode: true, claudeDesktop: true, validated: false } }, + { + id: 'advanced-workflows', + name: 'Advanced Workflows', + vendor: 'Advanced-workflows', + description: 'Vendor-generic MSP automation workflows that adapt to the customer\'s connected stack.', + category: 'automation', + maturity: 'alpha', + features: [ + 'Chat Delivery Adapters', + 'Psa Tool Map', + 'Ticket Triage Agent' + ], + skills: [ + { name: 'chat-delivery-adapters', description: 'The delivery-adapter contract every advanced-workflow skill uses to post its finished report somewhere a human will see it — Slack, an IT Glue document, or (blocked) Microsoft Teams.' }, + { name: 'psa-tool-map', description: 'Maps abstract PSA/ticketing operations (list new tickets, get ticket detail, update priority + status, list statuses, list priorities) to concrete Conduit tool names for Autotask, HaloPSA, and ConnectWise PSA.' }, + { name: 'ticket-triage-agent', description: 'Build (or run once) a ticket-triage agent that classifies new PSA tickets by priority, advances them to In Progress, and posts a summary to the connected chat tool.' } + ], + agents: [], + commands: [], + apiInfo: { + baseUrl: '', + auth: '', + rateLimit: '', + docsUrl: '' + }, + path: 'advanced-workflows/advanced-workflows', + compatibility: { claudeCode: true, claudeDesktop: true, validated: false } + }, { id: 'atera', name: 'Atera', From c528c3dddd1accee8ea04e95bc29b7aca090d83a Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 10:01:25 -0400 Subject: [PATCH 09/11] fix(advanced-workflows): relocate plugin to match the repo's /msp-claude-plugins// nesting convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The advanced-workflows plugin (Task 3's templates, Tasks 4-6's three skills, Task 7's plugin.json/README) was placed one level too shallow, at /advanced-workflows/advanced-workflows/ instead of nested under msp-claude-plugins/ like every other plugin in this repo (verified against halopsa, kaseya, etc.). That was a plan-authoring mistake, not a deliberate new pattern. - git mv the whole tree to msp-claude-plugins/advanced-workflows/advanced-workflows/ and remove the now-empty /advanced-workflows/ parent. - Revert docs/scripts/generate-plugins.ts's Task 7 special-casing entirely (confirmed byte-identical to the pre-Task-7 commit) — once correctly nested, the plugin needs no generator changes at all. - Update marketplace.json's advanced-workflows entry source to ./msp-claude-plugins/advanced-workflows/advanced-workflows. Re-ran npm run generate (plugin + all 3 skills resolve correctly, and regenerated plugins.ts/og-image.png are byte-identical to before this fix — the two approaches converged on the same output, just one via the canonical mechanism), npm run build (162 pages, no errors), and the marketplace drift check (passed, 84 entries). All three green. --- .claude-plugin/marketplace.json | 2 +- .../.claude-plugin/plugin.json | 0 .../advanced-workflows/README.md | 0 .../_capability-map-template.md | 0 .../_workflow-skill-template.md | 0 .../skills/chat-delivery-adapters/SKILL.md | 0 .../skills/psa-tool-map/SKILL.md | 0 .../skills/ticket-triage-agent/SKILL.md | 0 .../docs/scripts/generate-plugins.ts | 20 +++++-------------- 9 files changed, 6 insertions(+), 16 deletions(-) rename {advanced-workflows => msp-claude-plugins/advanced-workflows}/advanced-workflows/.claude-plugin/plugin.json (100%) rename {advanced-workflows => msp-claude-plugins/advanced-workflows}/advanced-workflows/README.md (100%) rename {advanced-workflows => msp-claude-plugins/advanced-workflows}/advanced-workflows/_capability-map-template.md (100%) rename {advanced-workflows => msp-claude-plugins/advanced-workflows}/advanced-workflows/_workflow-skill-template.md (100%) rename {advanced-workflows => msp-claude-plugins/advanced-workflows}/advanced-workflows/skills/chat-delivery-adapters/SKILL.md (100%) rename {advanced-workflows => msp-claude-plugins/advanced-workflows}/advanced-workflows/skills/psa-tool-map/SKILL.md (100%) rename {advanced-workflows => msp-claude-plugins/advanced-workflows}/advanced-workflows/skills/ticket-triage-agent/SKILL.md (100%) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index bc058677..a1c76d16 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -37,7 +37,7 @@ }, { "name": "advanced-workflows", - "source": "./advanced-workflows/advanced-workflows", + "source": "./msp-claude-plugins/advanced-workflows/advanced-workflows", "description": "Vendor-generic MSP automation workflows that adapt to the customer's connected stack.", "category": "automation", "tags": ["workflows", "automation", "msp"] diff --git a/advanced-workflows/advanced-workflows/.claude-plugin/plugin.json b/msp-claude-plugins/advanced-workflows/advanced-workflows/.claude-plugin/plugin.json similarity index 100% rename from advanced-workflows/advanced-workflows/.claude-plugin/plugin.json rename to msp-claude-plugins/advanced-workflows/advanced-workflows/.claude-plugin/plugin.json diff --git a/advanced-workflows/advanced-workflows/README.md b/msp-claude-plugins/advanced-workflows/advanced-workflows/README.md similarity index 100% rename from advanced-workflows/advanced-workflows/README.md rename to msp-claude-plugins/advanced-workflows/advanced-workflows/README.md diff --git a/advanced-workflows/advanced-workflows/_capability-map-template.md b/msp-claude-plugins/advanced-workflows/advanced-workflows/_capability-map-template.md similarity index 100% rename from advanced-workflows/advanced-workflows/_capability-map-template.md rename to msp-claude-plugins/advanced-workflows/advanced-workflows/_capability-map-template.md diff --git a/advanced-workflows/advanced-workflows/_workflow-skill-template.md b/msp-claude-plugins/advanced-workflows/advanced-workflows/_workflow-skill-template.md similarity index 100% rename from advanced-workflows/advanced-workflows/_workflow-skill-template.md rename to msp-claude-plugins/advanced-workflows/advanced-workflows/_workflow-skill-template.md diff --git a/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md b/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md similarity index 100% rename from advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md rename to msp-claude-plugins/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md diff --git a/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md b/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md similarity index 100% rename from advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md rename to msp-claude-plugins/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md diff --git a/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md b/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md similarity index 100% rename from advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md rename to msp-claude-plugins/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md diff --git a/msp-claude-plugins/docs/scripts/generate-plugins.ts b/msp-claude-plugins/docs/scripts/generate-plugins.ts index aa2b5b3a..793fb8d2 100644 --- a/msp-claude-plugins/docs/scripts/generate-plugins.ts +++ b/msp-claude-plugins/docs/scripts/generate-plugins.ts @@ -19,7 +19,7 @@ const OUTPUT_PATH_SHARED = path.join(DOCS_DIR, 'src', 'data', 'sharedSkills.ts') const VALID_CATEGORIES = new Set([ 'psa', 'rmm', 'documentation', 'security', 'sales', 'accounting', 'productivity', 'email-security', 'incident-management', 'monitoring', - 'network', 'crm', 'marketplace', 'marketing', 'infrastructure', 'automation', + 'network', 'crm', 'marketplace', 'marketing', 'infrastructure', ]); function normalizeCategory(raw: string): string { @@ -32,12 +32,8 @@ function normalizeCategory(raw: string): string { // ── Vendor derivation ────────────────────────────────────────────────── /** Derive a display-friendly vendor name from the source path. */ function deriveVendor(sourcePath: string): string { - // sourcePath looks like "./msp-claude-plugins/kaseya/autotask" for a - // nested vendor plugin, or "./advanced-workflows/advanced-workflows" for - // a cross-vendor plugin family living directly at the repo root — strip - // the msp-claude-plugins/ segment only when present, but always strip the - // leading "./" so the repo-root case doesn't leave "." as the top level. - const parts = sourcePath.replace(/^\.\/(msp-claude-plugins\/)?/, '').split('/'); + // sourcePath looks like "./msp-claude-plugins/kaseya/autotask" + const parts = sourcePath.replace('./msp-claude-plugins/', '').split('/'); const topLevel = parts[0]; const vendorMap: Record = { @@ -297,8 +293,7 @@ function scanApiInfo(_pluginDir: string): ApiInfo { // ── Derive path from source ──────────────────────────────────────────── function derivePath(source: string): string { // "./msp-claude-plugins/kaseya/autotask" → "kaseya/autotask" - // "./advanced-workflows/advanced-workflows" → "advanced-workflows/advanced-workflows" - return source.replace(/^\.\/(msp-claude-plugins\/)?/, ''); + return source.replace('./msp-claude-plugins/', ''); } // ── Features from skills ─────────────────────────────────────────────── @@ -432,12 +427,7 @@ function main(): void { } const pluginRelPath = derivePath(entry.source); - // entry.source is already a path relative to REPO_ROOT (e.g. - // "./msp-claude-plugins/kaseya/autotask" or, for a repo-root plugin - // family like advanced-workflows, "./advanced-workflows/advanced-workflows") — - // join it directly rather than assuming every plugin nests under - // msp-claude-plugins/. - const pluginDir = path.join(REPO_ROOT, entry.source); + const pluginDir = path.join(REPO_ROOT, 'msp-claude-plugins', pluginRelPath); // Read plugin.json if it exists const pluginJsonPath = path.join(pluginDir, '.claude-plugin', 'plugin.json'); From 8b006df4dc00c955a9d763adb1040e1897becc96 Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:05:57 -0400 Subject: [PATCH 10/11] fix(advanced-workflows): plugin.json author must be an object, not a string --- .../advanced-workflows/.claude-plugin/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msp-claude-plugins/advanced-workflows/advanced-workflows/.claude-plugin/plugin.json b/msp-claude-plugins/advanced-workflows/advanced-workflows/.claude-plugin/plugin.json index 83c41f39..fda16cfa 100644 --- a/msp-claude-plugins/advanced-workflows/advanced-workflows/.claude-plugin/plugin.json +++ b/msp-claude-plugins/advanced-workflows/advanced-workflows/.claude-plugin/plugin.json @@ -2,5 +2,5 @@ "name": "advanced-workflows", "version": "1.0.0", "description": "Vendor-generic MSP automation workflows: ticket triage, patch drift reporting, QBR prep, and more — each detects the customer's connected PSA/RMM/chat stack and adapts.", - "author": "WYRE Technology" + "author": { "name": "WYRE Technology" } } From e699a3a9199211c30b2e7ccbec6c0ad06989e754 Mon Sep 17 00:00:00 2001 From: Aaron Sachs <898627+asachs01@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:08:09 -0400 Subject: [PATCH 11/11] fix(advanced-workflows): use prose frontmatter names, not bare slugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check-doc-references.mjs flags a slug-shaped name that isn't the skill's canonical - id as a second, colliding id. Switch to prose titles (matching the msp-plugin-development convention's own worked example) rather than the compound canonical id — Conduit's own ingest overwrites frontmatter.name with the directory slug regardless, so this is purely this repo's own doc-reference-integrity concern. --- .../advanced-workflows/skills/chat-delivery-adapters/SKILL.md | 2 +- .../advanced-workflows/skills/psa-tool-map/SKILL.md | 2 +- .../advanced-workflows/skills/ticket-triage-agent/SKILL.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md b/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md index ea8a099d..e679c754 100644 --- a/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md +++ b/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/chat-delivery-adapters/SKILL.md @@ -1,5 +1,5 @@ --- -name: chat-delivery-adapters +name: "Chat Delivery Adapters" description: > The delivery-adapter contract every advanced-workflow skill uses to post its finished report somewhere a human will see it — Slack, an IT Glue diff --git a/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md b/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md index 57f107ff..8e7c2740 100644 --- a/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md +++ b/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/psa-tool-map/SKILL.md @@ -1,5 +1,5 @@ --- -name: psa-tool-map +name: "PSA Tool Map" description: > Maps abstract PSA/ticketing operations (list new tickets, get ticket detail, update priority + status, list statuses, list priorities) to diff --git a/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md b/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md index 0bf16682..9d1299b8 100644 --- a/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md +++ b/msp-claude-plugins/advanced-workflows/advanced-workflows/skills/ticket-triage-agent/SKILL.md @@ -1,5 +1,5 @@ --- -name: ticket-triage-agent +name: "Ticket Triage Agent" description: > Build (or run once) a ticket-triage agent that classifies new PSA tickets by priority, advances them to In Progress, and posts a summary