CLAUDE LABJP
2.1.273 — A round of connection work landed together: five opt-in headers for LLM gateways, and a notice when Claude Code stops trying to reconnect an MCP server09/29 — The date beside claude-sonnet-4-5 is 12 days out, but it is an earliest-possible estimate. The model is still Active, and public retirements get at least 60 days noticeMCP — People keep asking to reconnect a dropped server without ending the session. The disconnect is now announced, but reattaching is still something you do by handNEW — A scheduled task ran some days and not others. The cause was that only one folder had been bound to itWINDOWS — When Cowork fails on its very first task, check developer mode and the setup state before going looking for a causeHANDOFF — Before a long draft gets too heavy for one chat, decide on the three things the summary must carry into the next one2.1.273 — A round of connection work landed together: five opt-in headers for LLM gateways, and a notice when Claude Code stops trying to reconnect an MCP server09/29 — The date beside claude-sonnet-4-5 is 12 days out, but it is an earliest-possible estimate. The model is still Active, and public retirements get at least 60 days noticeMCP — People keep asking to reconnect a dropped server without ending the session. The disconnect is now announced, but reattaching is still something you do by handNEW — A scheduled task ran some days and not others. The cause was that only one folder had been bound to itWINDOWS — When Cowork fails on its very first task, check developer mode and the setup state before going looking for a causeHANDOFF — Before a long draft gets too heavy for one chat, decide on the three things the summary must carry into the next one
Articles/Cowork
Cowork/2026-07-17Advanced

It Worked on My Machine, but Nobody Could Trigger It — Four Assumptions I Stripped Out of a Cowork Plugin

I bundled four working automation skills into a plugin and shared it. Only one of them ever fired. Here is how I measured skill trigger rate, and the four assumptions — vocabulary, paths, connections, and naming — I had to strip out before it was portable.

cowork15plugin3skill2mcp20automation110distribution2

Premium Article

Working as an indie developer, I had accumulated four automation skills over six months, written a piece at a time between other work. All of them ran beautifully on my machine. So I packaged them into a plugin and handed it to a friend doing similar work.

His reply, a few days later, was short. "Installed it. Nothing happens."

Works here. Doesn't work there. An old story — but peeling the layers off one at a time showed me exactly what I had been quietly assuming. This is that record.

Break "it doesn't work" into stages

"It doesn't work" covers at least three different failures.

StageSymptomHow you spot it
Never firesClaude answers normally, skill is never invokedNo Skill tool call appears in the log
Fires, then diesInvoked, then stops on an errorPath, token, or permission errors surface
Finishes, wrong outputRuns to completion, result is offEvery step logs success; only the artifact is wrong

What was happening on his machine was the first one. If you skip past that and start debugging the body of the skill, you will dig in the wrong place for a long time.

I did exactly that. I suspected the connectors, then the permissions, and burned about an hour. The skill had never been called once, so nothing inside it mattered. When you are the only tester on your own tools, getting the order of suspicion wrong costs you the whole afternoon.

Turn trigger rate into a number

Arguing from intuition goes nowhere. "The description is probably bad" gives you no way to tell whether you fixed it.

So I wrote a small harness: replay a list of plausible utterances, record which skill gets picked. It runs claude -p headless and pulls the skill name out of the tool calls.

Test cases go in a JSONL file, one per line.

{"utterance": "pull together last week's sales into a report", "expect": "weekly-report"}
{"utterance": "generate the weekly report", "expect": "weekly-report"}
{"utterance": "can I get a summary for this week", "expect": "weekly-report"}
{"utterance": "sort through the issues that piled up", "expect": "issue-triage"}
{"utterance": "label the new issues that came in", "expect": "issue-triage"}
{"utterance": "draft the release notes", "expect": "release-notes"}
{"utterance": "check today's billing", "expect": "billing-check"}

expect is the skill you want chosen for that phrasing. Mix in the same intent said several different ways, not just the way you happen to say it. That matters more than it looks.

Here is the runner.

#!/usr/bin/env bash
# skill-trigger-check.sh — record which skill gets picked for each sample utterance
# usage: ./skill-trigger-check.sh cases.jsonl trigger-report.tsv
set -euo pipefail
 
CASES="${1:?usage: skill-trigger-check.sh <cases.jsonl> [out.tsv]}"
OUT="${2:-trigger-report.tsv}"
 
: > "$OUT"
 
while IFS= read -r line; do
  [ -z "$line" ] && continue
  utterance=$(jq -r '.utterance' <<<"$line")
  expected=$(jq -r '.expect'     <<<"$line")
 
  # One turn only. We want to know whether it fires, not to let it
  # actually relabel a real issue every time we test.
  actual=$(claude -p "$utterance" \
             --output-format stream-json --verbose --max-turns 1 2>/dev/null \
           | jq -rs '[ .[]
                       | select(.type == "assistant")
                       | .message.content[]?
                       | select(.type == "tool_use" and .name == "Skill")
                       | .input.skill ] | first // "none"')
 
  if [ "$actual" = "$expected" ]; then status="MATCH"; else status="MISS"; fi
  printf '%s\t%s\t%s\t%s\n' "$status" "$expected" "$actual" "$utterance" >> "$OUT"
done < "$CASES"
 
awk -F'\t' '
  { n++; if ($1 == "MATCH") m++ }
  END { printf "trigger rate: %d/%d (%.0f%%)\n", m, n, (n ? m*100/n : 0) }
' "$OUT"

--max-turns 1 keeps the test from doing real work. All I want to know is whether the skill gets picked, so I stop the moment it is. jq -rs collects the stream into an array, grabs the first Skill call, and falls back to none when there isn't one.

On my machine: 18 of 20 matched. 90%. No wonder it felt smooth.

On his machine, same cases: 5 of 20. 25%. Of four skills, exactly one was responding at all.

The moment there was a number, the conversation got concrete. Fifteen MISS rows tell you plainly what is going on.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A headless `claude -p` harness that replays 20 sample utterances and records which skill was picked — tracking the move from 25% to 85%
Three rules for rewriting a SKILL.md description from prose into routing input, with a concrete before and after
A bash preflight script, CI-ready as-is, that catches absolute paths, raw credentials, undocumented env vars, and collision-prone skill names
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

Related Articles

Cowork2026-08-23
Not Every Unreachable Connector Means the Same Thing in an Unattended Run
When an unattended task cannot reach a connector, the cause splits into three states: still connecting, unauthenticated, or genuinely absent. Each demands the opposite response. Here is the resolver that tells them apart.
Cowork2026-05-04
Why Cowork Scheduled Tasks Stop Mid-Run and How to Recover
Diagnose Cowork scheduled task failures using measured exit codes and real error output — why safe.directory delays failure instead of fixing it, how to pick a writable root before cloning, and how to structure logs with reason codes.
Cowork2026-04-29
Designing the One Page You Open Every Morning — Building Living Dashboards with Cowork Artifacts and MCP
Cowork Artifacts promote a chat answer into a re-openable page that fetches live MCP data. Here is how I design pages that replace recurring questions.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links