@kivimedia/kmhub 2.0.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/bin/kmhub.mjs +20 -7
- package/coach-book-output-guard.mjs +760 -0
- package/index.mjs +2 -0
- package/package.json +8 -3
- package/prompts/briefing.md +29 -0
- package/prompts/luxury.md +70 -0
- package/prompts/play.md +49 -0
- package/prompts/run.md +36 -0
- package/prompts/setup.md +33 -0
- package/prompts/vs-booked.md +46 -0
- package/prompts/what-can-you-do.md +40 -0
- package/prompts.mjs +109 -0
- package/read-only-tools.json +142 -0
- package/remote.mjs +815 -99
- package/tools/balloon-costing.mjs +80 -0
- package/tools/booking-equipment.mjs +110 -0
- package/tools/bridges.mjs +54 -0
- package/tools/calendar.mjs +9 -0
- package/tools/capabilities.mjs +155 -0
- package/tools/catalog.mjs +288 -0
- package/tools/clubs.mjs +176 -0
- package/tools/coach.mjs +771 -0
- package/tools/compare.mjs +76 -0
- package/tools/core.mjs +21 -0
- package/tools/crm.mjs +12 -3
- package/tools/dubsado.mjs +137 -0
- package/tools/exports.mjs +128 -0
- package/tools/fact-review.mjs +125 -0
- package/tools/flows.mjs +261 -0
- package/tools/forms.mjs +158 -0
- package/tools/gols.mjs +134 -0
- package/tools/hr.mjs +162 -0
- package/tools/knowledge.mjs +4 -3
- package/tools/marketing.mjs +396 -0
- package/tools/meta.mjs +2 -2
- package/tools/military.mjs +244 -0
- package/tools/outreach.mjs +27 -4
- package/tools/pending.mjs +122 -0
- package/tools/photos.mjs +140 -0
- package/tools/plays.mjs +1 -1
- package/tools/profile.mjs +118 -0
- package/tools/radar.mjs +173 -0
- package/tools/recurring-invoices.mjs +149 -0
- package/tools/reengage.mjs +434 -0
- package/tools/schedules.mjs +55 -0
- package/tools/setup.mjs +168 -0
- package/tools/sops-bridges.mjs +86 -0
- package/tools/sops.mjs +314 -0
- package/tools/sourcing.mjs +50 -2
- package/tools/strategy.mjs +146 -0
- package/tools/studio.mjs +132 -0
- package/tools/venueradar.mjs +151 -0
- package/tools/voice.mjs +134 -0
- package/tools.mjs +70 -12
package/index.mjs
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
26
26
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
27
|
+
import { registerPrompts } from './prompts.mjs';
|
|
27
28
|
import {
|
|
28
29
|
DEFAULT_BASE,
|
|
29
30
|
SERVER_NAME,
|
|
@@ -46,6 +47,7 @@ const PROFILE = resolveProfile(process.env.KMHUB_PROFILE);
|
|
|
46
47
|
|
|
47
48
|
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
48
49
|
const { families, tools } = registerTools(server, makeCaller(BASE, KEY), { profile: PROFILE });
|
|
50
|
+
const prompts = registerPrompts(server);
|
|
49
51
|
|
|
50
52
|
const transport = new StdioServerTransport();
|
|
51
53
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kivimedia/kmhub",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "KM Hub Terminal Mode. Installs the KM Hub MCP connector into your own Claude Code on your own machine, and ships the kmhub CLI that registers, updates and diagnoses it.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kmhub",
|
|
@@ -36,7 +36,11 @@
|
|
|
36
36
|
"index.mjs",
|
|
37
37
|
"remote.mjs",
|
|
38
38
|
"tools.mjs",
|
|
39
|
-
"
|
|
39
|
+
"coach-book-output-guard.mjs",
|
|
40
|
+
"tools/*.mjs",
|
|
41
|
+
"prompts.mjs",
|
|
42
|
+
"prompts/*.md",
|
|
43
|
+
"read-only-tools.json"
|
|
40
44
|
],
|
|
41
45
|
"scripts": {
|
|
42
46
|
"start": "node index.mjs",
|
|
@@ -45,7 +49,8 @@
|
|
|
45
49
|
"prepublishOnly": "npm run check:version"
|
|
46
50
|
},
|
|
47
51
|
"dependencies": {
|
|
48
|
-
"@
|
|
52
|
+
"@hono/node-server": "1.19.15",
|
|
53
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
49
54
|
"zod": "^3.23.8"
|
|
50
55
|
}
|
|
51
56
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "The KM Hub day briefing: what needs you today, ranked, with the reason each thing is on the list. Use for /kmhub:briefing, or when the user says what needs me today, what have I got on, morning, catch me up, where are we, what should I do first, anything urgent, what did I miss, or opens a session with no specific task."
|
|
3
|
+
disable-model-invocation: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# The KM Hub briefing
|
|
7
|
+
|
|
8
|
+
Call `km_briefing`. Answer from what it returns. That single call already replaces `km_waiting` plus `km_list_outreach_drafts` plus `km_list_outreach_replies` plus `km_list_tasks` plus `km_list_invoices` plus `km_my_schedule`, so do not run those first and do not run them afterwards to check its work.
|
|
9
|
+
|
|
10
|
+
## Read it out in this shape
|
|
11
|
+
|
|
12
|
+
1. **The headline.** It is written to be said out loud. Say it.
|
|
13
|
+
2. **The ranked list**, in the order it came back. Each item carries a plain `why`. Use it. "This has been sitting 47 days and sends nothing until you release it" is the whole point; "draft pending" is not.
|
|
14
|
+
3. **The diary**, including anything only pencilled in with nothing signed behind it. A free day is worth saying out loud too.
|
|
15
|
+
4. **Money that is already late**, if there is any.
|
|
16
|
+
|
|
17
|
+
## Do not re-sort it
|
|
18
|
+
|
|
19
|
+
The ranking is deliberate. A new enquiry nobody has answered and a reply nobody has handled sit near the top because they stop being worth anything if left. Late money worth a real amount outranks something merely unread. A gig today is high, but as a fact to absorb, not a decision to make. Every item carries `score` so the order is inspectable. Work down it.
|
|
20
|
+
|
|
21
|
+
## Before you finish
|
|
22
|
+
|
|
23
|
+
- Read the `notes` array and the `complete` flag. When a part of the workspace could not be read, the briefing says which part. Pass that on rather than presenting a partial day as the whole day.
|
|
24
|
+
- `counts.truncated` means there was more than you were shown. Say how many.
|
|
25
|
+
- If `suggested_play` came back, offer it in one line and name `/kmhub:play`. Offer it; do not start it.
|
|
26
|
+
|
|
27
|
+
## Then stop
|
|
28
|
+
|
|
29
|
+
The briefing is a briefing. Do not start working the list, draft anything, or change a record because an item looked urgent. Wait to be asked.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Explain and run the luxury plays: the brand and pricing family built from The Luxury Strategy. Use for /kmhub:luxury, or when the user asks what the luxury plays are, which one to run first, in what order, or says their prices feel too low, their website undersells them, they are thinking of discounting, adding a service, or wondering what to say about price on a call."
|
|
3
|
+
argument-hint: nothing for the tour, or the play to run
|
|
4
|
+
disable-model-invocation: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# The luxury plays
|
|
8
|
+
|
|
9
|
+
Fifteen plays in the catalog carry the method from The Luxury Strategy by Kapferer and
|
|
10
|
+
Bastien. They are about what a business charges, what it says, and who it says it to.
|
|
11
|
+
|
|
12
|
+
The user typed `$ARGUMENTS`. If that names a play, run it with `km_play_run`. If it is empty,
|
|
13
|
+
give the tour below in your own words, keep it short, and end by offering to run the first one.
|
|
14
|
+
|
|
15
|
+
## The idea the whole family rests on
|
|
16
|
+
|
|
17
|
+
The book's first claim is that luxury, premium and fashion are three different businesses,
|
|
18
|
+
not three points on one scale, and that mixing their rules is what costs money.
|
|
19
|
+
|
|
20
|
+
- **Luxury** never compares itself, sets its own price, and makes buying it take effort.
|
|
21
|
+
- **Premium** is comparative: pay more, get more, and the price is justified by what it does.
|
|
22
|
+
- **Fashion** runs on trends and speed.
|
|
23
|
+
|
|
24
|
+
Most businesses here are premium, and that is a legitimate place to be. It is not a lesser
|
|
25
|
+
answer, it is a different rulebook. The owner picks which one they want to run.
|
|
26
|
+
|
|
27
|
+
## An optional second opinion
|
|
28
|
+
|
|
29
|
+
`luxury-positioning-check` reads the real offers, prices, win rate, diary and past clients,
|
|
30
|
+
then says which of the three the evidence shows today. It is advice, not a gate: nothing else
|
|
31
|
+
waits for it. If the owner wants luxury, every play runs full luxury rules, whatever the check
|
|
32
|
+
said, and the check can record that choice. With no verdict on file, the plays ask once
|
|
33
|
+
"luxury or premium rules?" or default to luxury.
|
|
34
|
+
|
|
35
|
+
## A sensible order
|
|
36
|
+
|
|
37
|
+
1. `brand-archaeology` - what this brand actually is: its story, its icons, the signatures that
|
|
38
|
+
should appear everywhere.
|
|
39
|
+
2. `offer-ladder-architect` - the shape of the range: one signature offer, a tier above it, the
|
|
40
|
+
core that makes the money, one honest way in.
|
|
41
|
+
3. `anti-law-copy-review` - the lines on the website and in emails that make the business look
|
|
42
|
+
cheaper than it is, rewritten in its own voice.
|
|
43
|
+
4. `rarity-storyteller` - turning real limits, dates left, prep hours, credentials, into copy,
|
|
44
|
+
using only what the calendar can back.
|
|
45
|
+
5. `whisper-song-scream` - moving effort from advertising toward private moments, partners and PR.
|
|
46
|
+
6. `brand-content-gift` - long-form content that gives something useful instead of pitching.
|
|
47
|
+
7. `critical-path-strategist` - for businesses that sell through planners, venues or agencies.
|
|
48
|
+
|
|
49
|
+
## The ones that wait for a moment
|
|
50
|
+
|
|
51
|
+
- `sell-the-price-coach` before a consultation.
|
|
52
|
+
- `discount-interceptor` before any discount goes out.
|
|
53
|
+
- `anticipation-concierge` once a booking is confirmed.
|
|
54
|
+
- `clienteling-memory` every month or so.
|
|
55
|
+
- `sensitive-occasion-advisor` for memorials, celebrations of life and charity work.
|
|
56
|
+
- `brand-stretch-gate` when tempted to add a new service or product.
|
|
57
|
+
- `automation-check` before switching on any automation.
|
|
58
|
+
|
|
59
|
+
## What to tell the user plainly
|
|
60
|
+
|
|
61
|
+
- Nothing sends. Every one of these ends at a draft, a task or a proposed fact, and a person
|
|
62
|
+
approves it.
|
|
63
|
+
- None of them invents a number, a price, a famous client or a scarcity claim. If the workspace
|
|
64
|
+
cannot back a line, the play refuses to write it.
|
|
65
|
+
- The owner's choice of strategy wins. If they want luxury, they get luxury; the positioning
|
|
66
|
+
check, if they ran it, is mentioned once as advice and never holds them back.
|
|
67
|
+
|
|
68
|
+
Ask what they want to work on and offer the matching play; mention `luxury-positioning-check` as optional. Do not describe the inside of any play beyond what
|
|
69
|
+
is written here, because the method arrives from `km_play_run` and only while the subscription
|
|
70
|
+
is live.
|
package/prompts/play.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Browse and run a KM Hub play: the operating method behind a named piece of work, leased one step at a time. Use for /kmhub:play, when the user asks what plays or routines are available, or names one: morning sweep, handle the reply, quote and book, raise the rate, silence patrol, whale hunt, closer coach, reply coach, turn the gig into the next one, the fair buyer angle, open a new market, motorsport and fan zone. Also the luxury family, for brand and pricing work: luxury positioning check, anti-law copy review, offer ladder, discount interceptor, sell-the-price coach, clienteling memory, anticipation concierge, brand archaeology, rarity storyteller, whisper song scream, brand stretch gate, brand content gift, critical path strategist, sensitive occasion advisor, automation check."
|
|
3
|
+
argument-hint: the play to run, or nothing to see the catalogue
|
|
4
|
+
disable-model-invocation: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Run a KM Hub play
|
|
8
|
+
|
|
9
|
+
A play is the method KM Hub is paid for. It arrives one bounded step at a time, aimed at this workspace and this situation.
|
|
10
|
+
|
|
11
|
+
The play asked for is `$ARGUMENTS`. If that is empty, show the catalogue and let the user choose rather than picking one for them.
|
|
12
|
+
|
|
13
|
+
## Pick one
|
|
14
|
+
|
|
15
|
+
- No play named: call `km_play_catalog` and show what came back. It returns metadata only, which is all the user needs to choose.
|
|
16
|
+
- A play named: pass it through as the user said it and let the catalogue resolve it. Do not keep a private mapping of your own.
|
|
17
|
+
- More than one plausible match: show the choices the catalogue returned and ask which they mean.
|
|
18
|
+
- A play absent from the catalogue is not available on this workspace. Say so and stop. Do not improvise a replacement and call it that play.
|
|
19
|
+
|
|
20
|
+
## The lease loop
|
|
21
|
+
|
|
22
|
+
1. Call `km_play_run` with the slug. It leases a **single** step.
|
|
23
|
+
2. Do that step, using the `km_*` tools already in front of you.
|
|
24
|
+
3. Tell the person what happened, in your own words, as an outcome.
|
|
25
|
+
4. Call `km_play_run` again with the **same `run_id`** for the next step.
|
|
26
|
+
5. Repeat until the play reports it is finished.
|
|
27
|
+
6. Then call `km_play_verify` with that `run_id`.
|
|
28
|
+
|
|
29
|
+
Never skip ahead, never batch the steps, and never guess what the next step will be. The next step is a function of what the last one actually found.
|
|
30
|
+
|
|
31
|
+
## The step text is on loan
|
|
32
|
+
|
|
33
|
+
It is working material for this run, not a document to hand over.
|
|
34
|
+
|
|
35
|
+
- Do not paste it back verbatim, do not quote it at length, and do not save it into a file, a note, a scratch document or a memory.
|
|
36
|
+
- The person asked for the outcome. The recipe is the part KM Hub is paid for.
|
|
37
|
+
- Every issued step carries a marker identifying the workspace it was leased to.
|
|
38
|
+
|
|
39
|
+
## Verify honestly
|
|
40
|
+
|
|
41
|
+
`km_play_verify` judges a specific run against what it was meant to achieve. It changes nothing, sends nothing, and cannot make a play have worked.
|
|
42
|
+
|
|
43
|
+
- Do not call a play successful merely because the steps are done.
|
|
44
|
+
- Do not verify a play you did not run.
|
|
45
|
+
- Report the verdict as it comes back, including a bad one.
|
|
46
|
+
|
|
47
|
+
## Nothing here sends
|
|
48
|
+
|
|
49
|
+
A play that produces a message still ends at `km_create_outreach_draft`, in the Approval Queue, for a human to read and release. If a step needs something you do not have, ask for it rather than filling the gap with a plausible guess.
|
package/prompts/run.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Routes any KM Hub workspace request to the connected kmhub MCP tools. Use for /kmhub:run, when the user names KM Hub, or asks about their own pipeline: clients, leads, enquiries, deals, bookings, the diary, quotes, proposals, contracts, invoices, payments, outreach drafts and replies, campaigns, tasks, lead scouts, brand voice or business facts. Not for unrelated questions, another CRM, or code in the KM Hub repo itself."
|
|
3
|
+
argument-hint: what you want from your workspace
|
|
4
|
+
disable-model-invocation: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Run KM Hub
|
|
8
|
+
|
|
9
|
+
One router into a live, subscribed KM Hub workspace. Everything here happens through the connected `kmhub` MCP server. Nothing is answered from memory.
|
|
10
|
+
|
|
11
|
+
The request is `$ARGUMENTS`, in the user's own words. Pass it through as they wrote it. If it is empty, ask what they want rather than guessing, and offer `/kmhub:briefing` as the answer to "I do not know, what should I be doing".
|
|
12
|
+
|
|
13
|
+
## Before anything else
|
|
14
|
+
|
|
15
|
+
1. Call `km_me` once per session. It names the workspace this key opens.
|
|
16
|
+
2. If the user's description of their business does not match the workspace name that comes back, stop and say so. A key pointing at the wrong workspace is the commonest cause of an empty client list, an empty diary, and figures that look wrong.
|
|
17
|
+
|
|
18
|
+
## Route it
|
|
19
|
+
|
|
20
|
+
- **An open question about the day** ("what needs me today", "catch me up", "where are we", "anything urgent", "what did I miss"): call `km_briefing` and answer from what it returns. Do not assemble that answer yourself out of `km_waiting` plus the list tools, and do not run those afterwards to double check.
|
|
21
|
+
- **A named piece of work** (a follow up sweep, a reply to handle, a quote, a rate rise, a silence check, a whale hunt): this is a play. Use `/kmhub:play`, or call `km_play_catalog` then `km_play_run`.
|
|
22
|
+
- **One specific thing** ("show me the Meister invoice", "who has not signed", "what is on Thursday"): go straight to the read tool for it. `km_get_*` for one record, `km_list_*` for a set.
|
|
23
|
+
- **Anything the workspace should know** ("we now charge 2,500 for corporate"): `km_propose_business_fact`. It proposes, a human confirms.
|
|
24
|
+
|
|
25
|
+
## The rules that do not bend
|
|
26
|
+
|
|
27
|
+
- **Nothing is sent to anybody.** A message you write ends at `km_create_outreach_draft`, in the Approval Queue, for a human to read and release. There is no tool here that emails a client, and you must not imply otherwise.
|
|
28
|
+
- **Money, client sends, and destructive changes wait for an explicit yes** from the person in front of you, in that turn. Not an assumed yes from earlier in the conversation.
|
|
29
|
+
- **A missing input is a question, not a guess.** If a step needs something you do not have, ask for it. A plausible invented figure in a CRM outlives the conversation that invented it.
|
|
30
|
+
- **Read before you write.** `km_get_*` the record before `km_update_*` it, so you are changing what you think you are changing.
|
|
31
|
+
|
|
32
|
+
## When it will not work
|
|
33
|
+
|
|
34
|
+
- **402** means the workspace subscription is not active. Stop. Their data is untouched and their key still works; the subscription needs restarting at https://hub.kivimedia.co. Do not try another route.
|
|
35
|
+
- **401 or 403** means the key is wrong, revoked, or missing a scope. Point them at `/kmhub:setup`.
|
|
36
|
+
- **The kmhub server is missing entirely** means the connector is not installed in this Claude Code. Point them at https://hub.kivimedia.co/terminal/ and stop. Never ask for a Claude password, a Claude token, or their Claude account.
|
package/prompts/setup.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Install or refresh the KM Hub rules pack, and check whether the KM Hub connection is current. Use for /kmhub:setup, when the user says set up my KM Hub rules, or asks whether their KM Hub connection, connector or rules are up to date, out of date, or need updating."
|
|
3
|
+
disable-model-invocation: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Set up KM Hub
|
|
7
|
+
|
|
8
|
+
The rules pack is how Claude learns how this particular business is set up: its offers, its pricing, its voice, its verticals. Until it is installed the tools work, but every answer is generic.
|
|
9
|
+
|
|
10
|
+
## Check first
|
|
11
|
+
|
|
12
|
+
Call `km_check_updates`. It compares the connector running right now, and the rules file already on this machine, against what KM Hub publishes today, then gives a plain-language verdict.
|
|
13
|
+
|
|
14
|
+
- Rules missing or stale: call `km_fetch_rules` and install what it returns.
|
|
15
|
+
- Everything current: say so in one line and stop. Do not refetch for the sake of it.
|
|
16
|
+
|
|
17
|
+
## Where the rules go
|
|
18
|
+
|
|
19
|
+
`km_fetch_rules` returns the pack. It is written into a `CLAUDE.md` as a single clearly marked KM Hub block.
|
|
20
|
+
|
|
21
|
+
**Ask which file before writing, and say why.** A user's own `CLAUDE.md` is often long and hand-tuned, and a rules pack landing in the middle of it is a surprise nobody asked for. Offer the choice plainly: their global `~/.claude/CLAUDE.md`, the project they are standing in, or a folder kept for KM Hub work. Replace any existing KM Hub block rather than appending a second one.
|
|
22
|
+
|
|
23
|
+
## What the pack is, and is not
|
|
24
|
+
|
|
25
|
+
- It is **rendered per workspace from live data**, so it goes stale on its own. Refetching is the update path; editing it by hand is not.
|
|
26
|
+
- The only KM Hub things on this machine are a URL, a key, and that file. No workspace data is stored locally.
|
|
27
|
+
- If the workspace settings and the real business disagree, the pack says so and names which one wins. Believe it over your own reading.
|
|
28
|
+
|
|
29
|
+
## If it will not install
|
|
30
|
+
|
|
31
|
+
- **402**: the subscription is not active, so Terminal Mode is switched off. The key and the data are both fine. Restart at https://hub.kivimedia.co and it works again within about a minute.
|
|
32
|
+
- **401 or 403**: the key is wrong, revoked, or missing a scope. Reinstall the connector from https://hub.kivimedia.co/terminal/ and it will mint a fresh one.
|
|
33
|
+
- **The route is not there yet**: this is reported as success on purpose. A KM Hub without update endpoints is not a broken KM Hub. Say the pack is unavailable on this workspace and carry on.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "An honest, computed comparison of KM Hub Terminal Mode against Booked Solid's terminal, from live data rather than a slide. Use for /kmhub:vs-booked, or when the user asks how KM Hub compares to Booked, whether they should switch, what the difference is, or which one does more."
|
|
3
|
+
disable-model-invocation: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# KM Hub versus Booked, computed
|
|
7
|
+
|
|
8
|
+
Call `km_vs_booked`. It counts both sides from real sources at the moment you ask, so the answer is never a stale claim someone typed into a deck months ago.
|
|
9
|
+
|
|
10
|
+
## Show your working
|
|
11
|
+
|
|
12
|
+
Lead with where the numbers came from, in one line, before any of them. "Counted just now from KM Hub's own play catalogue and tool registry, and from the Booked plugin installed on this machine" is what makes the rest believable. A comparison with no provenance is marketing, and the person reading it knows that.
|
|
13
|
+
|
|
14
|
+
If Booked is **not installed on this machine**, say so plainly and give KM Hub's own numbers alone. Do not fill the gap with figures from memory, a website, or a previous conversation. An uncounted number is worse than an absent one, because nobody can tell which it was.
|
|
15
|
+
|
|
16
|
+
## Name what Booked genuinely does better
|
|
17
|
+
|
|
18
|
+
This is not optional and it is the part that makes everything else credible.
|
|
19
|
+
|
|
20
|
+
Booked works on files on the client's own machine. That means it keeps working with no internet, nothing about the business is stored anywhere else, and there is no subscription gate between somebody and their own records. For a person who wants exactly that, it is the better tool and you should say so without hedging.
|
|
21
|
+
|
|
22
|
+
Its plays also carry more per tool, because that is the only place its capability can live.
|
|
23
|
+
|
|
24
|
+
**Say at least one true thing in Booked's favour before you say anything in KM Hub's.** A model that produces an all-green comparison is not being helpful, it is being a brochure, and the reader discounts everything after the first obviously one-sided line.
|
|
25
|
+
|
|
26
|
+
## Then the actual difference, which is structural
|
|
27
|
+
|
|
28
|
+
The honest framing is not "more features". It is that these are different shapes:
|
|
29
|
+
|
|
30
|
+
- **Booked's terminal is almost entirely plays.** Its tools exist to run them. It has no tool that reads a client record, because it does not need one: the data is already local.
|
|
31
|
+
- **KM Hub is a multi-tenant cloud CRM.** The data is never local, so the tools *are* the capability, and the plays sit on top of them.
|
|
32
|
+
|
|
33
|
+
That is why comparing play counts alone is misleading in both directions, and you should say so rather than quoting the ratio as though it settled something.
|
|
34
|
+
|
|
35
|
+
## Rules for the numbers
|
|
36
|
+
|
|
37
|
+
- **Never state a figure the tool did not return.** No remembered counts, no rounding up, no "over 100" when it said 109.
|
|
38
|
+
- If a count is a floor rather than an exact total, say floor.
|
|
39
|
+
- Never present a capability KM Hub has as one Booked "cannot" have unless the tool's own data supports it. Absent from a plugin manifest is not proof of absence from a product.
|
|
40
|
+
- Never claim what Booked costs, what its roadmap is, or what its users think.
|
|
41
|
+
|
|
42
|
+
## Close on fit, not on a winner
|
|
43
|
+
|
|
44
|
+
End with the question that actually decides it, in one or two sentences: does this person want a booking desk that runs on their own machine, or a business manager that runs their outreach, newsletter, SEO, crew, money and reporting as well. Both are legitimate answers.
|
|
45
|
+
|
|
46
|
+
Do not tell them which to buy. Somebody who feels sold to stops believing the numbers, and the numbers were the point.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "A tour of everything KM Hub can do for this business, and honestly which parts work from the terminal. Use for /kmhub:what-can-you-do, or when the user asks what KM Hub can do, what else it does, whether it handles some area of their business, whether it replaces another tool they pay for, or says they did not know it could do something."
|
|
3
|
+
argument-hint: an area to focus on, or nothing for the whole product
|
|
4
|
+
disable-model-invocation: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# What KM Hub can do
|
|
8
|
+
|
|
9
|
+
Call `km_capabilities`. If the user named an area, pass the matching `pillar`. Otherwise take the whole product.
|
|
10
|
+
|
|
11
|
+
This is the answer to "what am I actually paying for", so it is worth doing properly rather than reciting a list.
|
|
12
|
+
|
|
13
|
+
## Give them the shape first
|
|
14
|
+
|
|
15
|
+
Open with the seven pillars and the one-line tagline for each, then the totals: how many feature pages there are, and how many you can drive from here. A person who has only seen the booking side genuinely does not know the rest exists.
|
|
16
|
+
|
|
17
|
+
Then go deeper only where they showed interest, or where the workspace suggests it. If you have already called `km_briefing` this session, use what it found: someone with 96 quiet deals should hear about Silence Patrol and Campaigns, not a flat alphabetical tour.
|
|
18
|
+
|
|
19
|
+
## Say the honest thing about reach
|
|
20
|
+
|
|
21
|
+
Every page carries `reach`.
|
|
22
|
+
|
|
23
|
+
- **`terminal`**: you can do it from here. Offer to.
|
|
24
|
+
- **`web_only`**: KM Hub does it, this connector cannot yet. Name the page, say it lives in the web app at https://hub.kivimedia.co, and move on.
|
|
25
|
+
|
|
26
|
+
🚨 **Never offer to do a `web_only` thing.** "KM Hub does your newsletters, that one is in the web app" builds trust. Promising it and then failing destroys more than the feature was worth. Do not blur this to sound more capable.
|
|
27
|
+
|
|
28
|
+
Do not apologise for the split either. Most of the product is reachable and the rest is a click away in a browser they already have open.
|
|
29
|
+
|
|
30
|
+
## What to lead with
|
|
31
|
+
|
|
32
|
+
Lead with what is unusual and what they are probably not using. The interesting facts are that this is not a booking tool: it runs outbound campaigns, newsletters, SEO and AI-search visibility, reviews, payroll, job costing, inventory and a set of AI officers that make recommendations. If they are comparing KM Hub to something that only handles bookings, that comparison is the thing to correct, without naming a competitor unless they do.
|
|
33
|
+
|
|
34
|
+
The other thing they are probably not using is the plays: the methods in `km_play_catalog`, including the fifteen luxury plays built from The Luxury Strategy, which cover pricing, the offer ladder, what the website says about price, discounting, scarcity and where the marketing effort goes. If the conversation turns to money, positioning or how the business is presented, name that family and offer the play that fits (`luxury-positioning-check` is an optional second opinion, never a prerequisite), or point at `/kmhub:luxury` for the tour.
|
|
35
|
+
|
|
36
|
+
## Finish with one offer, not ten
|
|
37
|
+
|
|
38
|
+
End on a single concrete next step drawn from what they reacted to. "Want me to run Silence Patrol on those 96 quiet deals?" beats "let me know what you would like to explore". One offer, theirs to take.
|
|
39
|
+
|
|
40
|
+
This reads a file. It sends nothing, changes nothing and costs nothing.
|
package/prompts.mjs
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The KM Hub commands, served BY the connector rather than copied onto the disk
|
|
3
|
+
* beside it.
|
|
4
|
+
*
|
|
5
|
+
* 🚨 WHY THIS EXISTS. The six commands used to reach a machine only as markdown files
|
|
6
|
+
* that the installer copied into ~/.claude/commands. That is a second delivery channel,
|
|
7
|
+
* independent of the connector, and on 26-Aug-26 it did what independent channels do:
|
|
8
|
+
* it arrived on its own. A client finished an install with all six commands in her slash
|
|
9
|
+
* menu, all five working methods, and no tools behind any of them. The menu looked like
|
|
10
|
+
* proof and was not, because a file on disk knows nothing about whether the connector
|
|
11
|
+
* landed.
|
|
12
|
+
*
|
|
13
|
+
* Served as MCP prompts they cannot arrive alone. Claude Code discovers prompts from
|
|
14
|
+
* connected servers and lists them as `/mcp__kmhub__<name>`, so their presence in the
|
|
15
|
+
* menu is the connection, not a copy of something that once described it.
|
|
16
|
+
*
|
|
17
|
+
* The file copies stay for now: `/kmhub-briefing` is a friendlier thing to say on a
|
|
18
|
+
* call than `/mcp__kmhub__briefing`, and taking a name away from clients mid-flight is
|
|
19
|
+
* a decision for Ziv, not a side effect of this file. prompts-parity.test.mjs holds the
|
|
20
|
+
* two copies byte-identical so the friendlier name can never drift from the real one.
|
|
21
|
+
*/
|
|
22
|
+
import { readFileSync, readdirSync } from 'node:fs';
|
|
23
|
+
import { dirname, join } from 'node:path';
|
|
24
|
+
import { fileURLToPath } from 'node:url';
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
|
|
27
|
+
const PROMPT_DIR = join(dirname(fileURLToPath(import.meta.url)), 'prompts');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Split a command file into its frontmatter and its body.
|
|
31
|
+
*
|
|
32
|
+
* Deliberately small: these files are ours, the frontmatter is three flat keys, and a
|
|
33
|
+
* YAML dependency on the server for that would be a supply-chain cost with no return.
|
|
34
|
+
* Anything it cannot parse is treated as body, which fails visibly rather than silently.
|
|
35
|
+
*/
|
|
36
|
+
function parseCommandFile(raw) {
|
|
37
|
+
const text = raw.replace(/^/, '');
|
|
38
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
|
|
39
|
+
if (!match) return { meta: {}, body: text.trim() };
|
|
40
|
+
|
|
41
|
+
const meta = {};
|
|
42
|
+
for (const line of match[1].split(/\r?\n/)) {
|
|
43
|
+
const at = line.indexOf(':');
|
|
44
|
+
if (at < 1) continue;
|
|
45
|
+
const key = line.slice(0, at).trim();
|
|
46
|
+
let value = line.slice(at + 1).trim();
|
|
47
|
+
if (
|
|
48
|
+
(value.startsWith('"') && value.endsWith('"') && value.length > 1)
|
|
49
|
+
|| (value.startsWith("'") && value.endsWith("'") && value.length > 1)
|
|
50
|
+
) {
|
|
51
|
+
value = value.slice(1, -1);
|
|
52
|
+
}
|
|
53
|
+
meta[key] = value;
|
|
54
|
+
}
|
|
55
|
+
return { meta, body: text.slice(match[0].length).trim() };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Every command file on disk, in a stable order so two servers list them the same way. */
|
|
59
|
+
export function loadPromptDefinitions() {
|
|
60
|
+
const files = readdirSync(PROMPT_DIR).filter((name) => name.endsWith('.md')).sort();
|
|
61
|
+
return files.map((file) => {
|
|
62
|
+
const name = file.replace(/\.md$/, '');
|
|
63
|
+
const { meta, body } = parseCommandFile(readFileSync(join(PROMPT_DIR, file), 'utf8'));
|
|
64
|
+
return {
|
|
65
|
+
name,
|
|
66
|
+
description: meta.description || `The KM Hub ${name} command.`,
|
|
67
|
+
argumentHint: meta['argument-hint'] || '',
|
|
68
|
+
body,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Register the commands as MCP prompts on an McpServer.
|
|
75
|
+
*
|
|
76
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
77
|
+
* @returns {string[]} the prompt names registered, so a caller can log or test them
|
|
78
|
+
*/
|
|
79
|
+
export function registerPrompts(server) {
|
|
80
|
+
const registered = [];
|
|
81
|
+
|
|
82
|
+
for (const prompt of loadPromptDefinitions()) {
|
|
83
|
+
// Only ask for an argument where the command actually takes one. A required-looking
|
|
84
|
+
// empty box on /kmhub__briefing would be a small lie about how the command works.
|
|
85
|
+
const argsSchema = prompt.argumentHint
|
|
86
|
+
? { input: z.string().optional().describe(prompt.argumentHint) }
|
|
87
|
+
: undefined;
|
|
88
|
+
|
|
89
|
+
const handler = (args) => {
|
|
90
|
+
const input = args && typeof args.input === 'string' ? args.input.trim() : '';
|
|
91
|
+
const text = input ? `${prompt.body}\n\n## What was asked for\n\n${input}` : prompt.body;
|
|
92
|
+
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
if (argsSchema) {
|
|
97
|
+
server.registerPrompt(prompt.name, { description: prompt.description, argsSchema }, handler);
|
|
98
|
+
} else {
|
|
99
|
+
server.registerPrompt(prompt.name, { description: prompt.description }, handler);
|
|
100
|
+
}
|
|
101
|
+
registered.push(prompt.name);
|
|
102
|
+
} catch {
|
|
103
|
+
// One unregistrable prompt must never cost the tools. The connector is the
|
|
104
|
+
// product; these are a way of reaching it.
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return registered;
|
|
109
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "GENERATED by scripts/generate-read-only-tools.mjs. Do not hand-edit. Tools listed here are announced with readOnlyHint: true, so Codex (and any other host that honours the hint) runs them without an approval prompt. Everything else keeps its prompt.",
|
|
3
|
+
"tools": [
|
|
4
|
+
"km_ai_usage",
|
|
5
|
+
"km_blocked_dates",
|
|
6
|
+
"km_booking_gear",
|
|
7
|
+
"km_bridges",
|
|
8
|
+
"km_briefing",
|
|
9
|
+
"km_calendar_feed",
|
|
10
|
+
"km_check_availability",
|
|
11
|
+
"km_check_updates",
|
|
12
|
+
"km_clubs_directory",
|
|
13
|
+
"km_clubs_post",
|
|
14
|
+
"km_clubs_posts",
|
|
15
|
+
"km_coach_context",
|
|
16
|
+
"km_coach_daily_operator",
|
|
17
|
+
"km_coach_list_clients",
|
|
18
|
+
"km_coach_list_records",
|
|
19
|
+
"km_coach_list_scouts",
|
|
20
|
+
"km_coach_method",
|
|
21
|
+
"km_coach_scout_status",
|
|
22
|
+
"km_coach_stalled_opportunities",
|
|
23
|
+
"km_deliverability",
|
|
24
|
+
"km_dubsado_lead",
|
|
25
|
+
"km_dubsado_leads",
|
|
26
|
+
"km_dubsado_status",
|
|
27
|
+
"km_export_status",
|
|
28
|
+
"km_fetch_rules",
|
|
29
|
+
"km_find_contact",
|
|
30
|
+
"km_get_booking",
|
|
31
|
+
"km_get_brand_voice",
|
|
32
|
+
"km_get_business_facts",
|
|
33
|
+
"km_get_catalog",
|
|
34
|
+
"km_get_client",
|
|
35
|
+
"km_get_deal",
|
|
36
|
+
"km_get_form_fields",
|
|
37
|
+
"km_get_invoice",
|
|
38
|
+
"km_get_newsletter",
|
|
39
|
+
"km_get_offers_and_pricing",
|
|
40
|
+
"km_get_package_composition",
|
|
41
|
+
"km_get_profile",
|
|
42
|
+
"km_get_proposal",
|
|
43
|
+
"km_get_quote",
|
|
44
|
+
"km_get_seo_post",
|
|
45
|
+
"km_get_sop",
|
|
46
|
+
"km_get_team_member",
|
|
47
|
+
"km_gols_finds",
|
|
48
|
+
"km_inquiry_sources",
|
|
49
|
+
"km_lead_scout_status",
|
|
50
|
+
"km_list_ai_activity",
|
|
51
|
+
"km_list_ai_officers",
|
|
52
|
+
"km_list_balloon_costs",
|
|
53
|
+
"km_list_balloon_work",
|
|
54
|
+
"km_list_bookings",
|
|
55
|
+
"km_list_broadcasts",
|
|
56
|
+
"km_list_catalogs",
|
|
57
|
+
"km_list_clients",
|
|
58
|
+
"km_list_contracts",
|
|
59
|
+
"km_list_crew_assignments",
|
|
60
|
+
"km_list_deals",
|
|
61
|
+
"km_list_decisions",
|
|
62
|
+
"km_list_design_assets",
|
|
63
|
+
"km_list_equipment",
|
|
64
|
+
"km_list_events",
|
|
65
|
+
"km_list_expenses",
|
|
66
|
+
"km_list_exports",
|
|
67
|
+
"km_list_forms",
|
|
68
|
+
"km_list_galleries",
|
|
69
|
+
"km_list_gambits",
|
|
70
|
+
"km_list_integrations",
|
|
71
|
+
"km_list_invoices",
|
|
72
|
+
"km_list_job_costs",
|
|
73
|
+
"km_list_lead_scouts",
|
|
74
|
+
"km_list_linkedin_content",
|
|
75
|
+
"km_list_marketplace_leads",
|
|
76
|
+
"km_list_newsletters",
|
|
77
|
+
"km_list_outreach_campaigns",
|
|
78
|
+
"km_list_outreach_drafts",
|
|
79
|
+
"km_list_outreach_replies",
|
|
80
|
+
"km_list_payments",
|
|
81
|
+
"km_list_payroll",
|
|
82
|
+
"km_list_pending_actions",
|
|
83
|
+
"km_list_pending_business_facts",
|
|
84
|
+
"km_list_proposals",
|
|
85
|
+
"km_list_questionnaires",
|
|
86
|
+
"km_list_quotes",
|
|
87
|
+
"km_list_radar_scans",
|
|
88
|
+
"km_list_recommendations",
|
|
89
|
+
"km_list_recurring_invoices",
|
|
90
|
+
"km_list_rentals",
|
|
91
|
+
"km_list_reviews",
|
|
92
|
+
"km_list_schedules",
|
|
93
|
+
"km_list_seo_posts",
|
|
94
|
+
"km_list_seo_sites",
|
|
95
|
+
"km_list_sequences",
|
|
96
|
+
"km_list_sms",
|
|
97
|
+
"km_list_sops",
|
|
98
|
+
"km_list_tasks",
|
|
99
|
+
"km_list_team",
|
|
100
|
+
"km_list_time_entries",
|
|
101
|
+
"km_list_trips",
|
|
102
|
+
"km_list_weekly_interviews",
|
|
103
|
+
"km_list_work_photos",
|
|
104
|
+
"km_list_workflows",
|
|
105
|
+
"km_lists",
|
|
106
|
+
"km_me",
|
|
107
|
+
"km_military_desks",
|
|
108
|
+
"km_military_directory",
|
|
109
|
+
"km_military_installation",
|
|
110
|
+
"km_money_now",
|
|
111
|
+
"km_music_settings",
|
|
112
|
+
"km_newsletter_audience",
|
|
113
|
+
"km_outreach_campaign_stats",
|
|
114
|
+
"km_outreach_email_stats",
|
|
115
|
+
"km_past_clients",
|
|
116
|
+
"km_play_catalog",
|
|
117
|
+
"km_reengage_drafts",
|
|
118
|
+
"km_reengage_emails",
|
|
119
|
+
"km_reengage_routing",
|
|
120
|
+
"km_reengage_scheduler",
|
|
121
|
+
"km_reengage_scheduler_runs",
|
|
122
|
+
"km_reengage_sequences",
|
|
123
|
+
"km_reengage_settings",
|
|
124
|
+
"km_reengage_stats",
|
|
125
|
+
"km_review_queue",
|
|
126
|
+
"km_search_conversations",
|
|
127
|
+
"km_search_knowledge",
|
|
128
|
+
"km_sms_config",
|
|
129
|
+
"km_sop_brief",
|
|
130
|
+
"km_sop_images",
|
|
131
|
+
"km_sop_pullsheet",
|
|
132
|
+
"km_sops_for",
|
|
133
|
+
"km_sourcing_prices",
|
|
134
|
+
"km_subscription",
|
|
135
|
+
"km_venue_radar_venue",
|
|
136
|
+
"km_venue_radar_venues",
|
|
137
|
+
"km_vs_booked",
|
|
138
|
+
"km_waiting",
|
|
139
|
+
"km_workspace_config",
|
|
140
|
+
"km_workspaces"
|
|
141
|
+
]
|
|
142
|
+
}
|