luckiest-co 1.0.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.
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "luckiest",
3
+ "description": "Plan, go, finish. Guided planning, progress dashboards, and your luckiest.co tribe inside Claude Code.",
4
+ "version": "0.1.0",
5
+ "author": { "name": "Luckiest" }
6
+ }
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # Luckiest for Claude Code
2
+
3
+ Luckiest brings your planning flow, tribe, and skill dashboard into Claude Code. Plan your work inside your editor, track progress, and collaborate with your tribe without leaving the CLI.
4
+
5
+ Luckiest connects to your luckiest.co account, showing live skill bookmarks, tribe leaderboards, and guided planning workflows. All commands respect DRAFT, DOING, and DONE states tracked on luckiest.co.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npx luckiest-co
11
+ ```
12
+
13
+ Or add the plugin manually:
14
+ ```bash
15
+ npx claude plugin add luckiest-co
16
+ ```
17
+
18
+ ## Commands
19
+
20
+ | Command | What it does |
21
+ |---------|------------|
22
+ | `/luckiest start` | Begin a new skill or goal |
23
+ | `/luckiest plan` | Guided planning for a skill or project |
24
+ | `/luckiest go` | Move a bookmark to DOING |
25
+ | `/luckiest finish` | Mark work done and close |
26
+ | `/luckiest status` | Show current work state: DRAFT, DOING, or DONE |
27
+ | `/luckiest skills` | List all your bookmarked skills |
28
+ | `/luckiest home` | Jump to your luckiest.co home dashboard |
29
+ | `/luckiest leaderboard` | See your tribe's weekly activity and progress |
30
+ | `/luckiest helpers` | Find and request help from tribe members |
31
+ | `/luckiest wishes` | See what your tribe is working toward |
32
+ | `/luckiest charms` | View and use your skill boosters |
33
+
34
+ ## Requirements
35
+
36
+ - Claude Code (CLI)
37
+ - Active luckiest.co account
38
+ - Account API key (set via `claude config`)
package/bin/install.js ADDED
@@ -0,0 +1,413 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Forked from PAUL Framework's installer (bin/install.js), MIT licensed.
4
+ // Rebranded for Luckiest, extended with a connection-key prompt and
5
+ // owned-skill sync from luckiest.co. See ../LICENSE-THIRD-PARTY.md.
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const os = require('os');
10
+ const readline = require('readline');
11
+ const { execFileSync } = require('child_process');
12
+
13
+ // Colors
14
+ const cyan = '\x1b[36m';
15
+ const green = '\x1b[32m';
16
+ const yellow = '\x1b[33m';
17
+ const red = '\x1b[31m';
18
+ const dim = '\x1b[2m';
19
+ const reset = '\x1b[0m';
20
+
21
+ // Get version from package.json
22
+ const pkg = require('../package.json');
23
+
24
+ const banner = `
25
+ ${cyan} ██╗ ██╗ ██╗ ██████╗██╗ ██╗██╗███████╗███████╗████████╗
26
+ ██║ ██║ ██║██╔════╝██║ ██╔╝██║██╔════╝██╔════╝╚══██╔══╝
27
+ ██║ ██║ ██║██║ █████╔╝ ██║█████╗ ███████╗ ██║
28
+ ██║ ██║ ██║██║ ██╔═██╗ ██║██╔══╝ ╚════██║ ██║
29
+ ███████╗╚██████╔╝╚██████╗██║ ██╗██║███████╗███████║ ██║
30
+ ╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝ ╚═╝${reset}
31
+
32
+ Luckiest ${dim}v${pkg.version}${reset}
33
+ Plan, go, finish. Your luckiest.co skills and tribe, inside Claude.
34
+ `;
35
+
36
+ // Parse args
37
+ const args = process.argv.slice(2);
38
+ const hasGlobal = args.includes('--global') || args.includes('-g');
39
+ const hasLocal = args.includes('--local') || args.includes('-l');
40
+ const syncOnly = args.includes('--sync-only');
41
+
42
+ // Parse --config-dir argument
43
+ function parseConfigDirArg() {
44
+ const configDirIndex = args.findIndex(arg => arg === '--config-dir' || arg === '-c');
45
+ if (configDirIndex !== -1) {
46
+ const nextArg = args[configDirIndex + 1];
47
+ if (!nextArg || nextArg.startsWith('-')) {
48
+ console.error(` ${yellow}--config-dir requires a path argument${reset}`);
49
+ process.exit(1);
50
+ }
51
+ return nextArg;
52
+ }
53
+ const configDirArg = args.find(arg => arg.startsWith('--config-dir=') || arg.startsWith('-c='));
54
+ if (configDirArg) {
55
+ return configDirArg.split('=')[1];
56
+ }
57
+ return null;
58
+ }
59
+ const explicitConfigDir = parseConfigDirArg();
60
+ const hasHelp = args.includes('--help') || args.includes('-h');
61
+
62
+ console.log(banner);
63
+
64
+ // Show help if requested
65
+ if (hasHelp) {
66
+ console.log(` ${yellow}Usage:${reset} npx luckiest-co [options]
67
+
68
+ ${yellow}Options:${reset}
69
+ ${cyan}-g, --global${reset} Install globally (to Claude config directory)
70
+ ${cyan}-l, --local${reset} Install locally (to ./.claude in current directory)
71
+ ${cyan}-c, --config-dir <path>${reset} Specify custom Claude config directory
72
+ ${cyan}--sync-only${reset} Skip install, only sync owned skills from luckiest.co
73
+ ${cyan}-h, --help${reset} Show this help message
74
+
75
+ ${yellow}Examples:${reset}
76
+ ${dim}# Install to default ~/.claude directory${reset}
77
+ npx luckiest-co --global
78
+
79
+ ${dim}# Install to current project only${reset}
80
+ npx luckiest-co --local
81
+
82
+ ${dim}# Re-sync owned skills only (used by /luckiest skills)${reset}
83
+ npx luckiest-co --sync-only
84
+
85
+ ${yellow}What gets installed:${reset}
86
+ commands/luckiest/ - Slash commands (/luckiest:plan, /luckiest:go, etc.)
87
+ references/ - Vocabulary and chart-renderer references
88
+ templates/ - Brief templates
89
+ .claude-plugin/ - Plugin manifest
90
+
91
+ Owned skills purchased on luckiest.co are synced to ${dim}~/.claude/skills/<name>/${reset}.
92
+ `);
93
+ process.exit(0);
94
+ }
95
+
96
+ /**
97
+ * Expand ~ to home directory
98
+ */
99
+ function expandTilde(filePath) {
100
+ if (filePath && filePath.startsWith('~/')) {
101
+ return path.join(os.homedir(), filePath.slice(2));
102
+ }
103
+ return filePath;
104
+ }
105
+
106
+ /**
107
+ * Recursively copy directory, replacing paths in .md files
108
+ */
109
+ function copyWithPathReplacement(srcDir, destDir, pathPrefix) {
110
+ fs.mkdirSync(destDir, { recursive: true });
111
+
112
+ const entries = fs.readdirSync(srcDir, { withFileTypes: true });
113
+
114
+ for (const entry of entries) {
115
+ const srcPath = path.join(srcDir, entry.name);
116
+ const destPath = path.join(destDir, entry.name);
117
+
118
+ if (entry.isDirectory()) {
119
+ copyWithPathReplacement(srcPath, destPath, pathPrefix);
120
+ } else if (entry.name.endsWith('.md')) {
121
+ // Replace ~/.claude/ with the appropriate prefix in markdown files
122
+ let content = fs.readFileSync(srcPath, 'utf8');
123
+ content = content.replace(/~\/\.claude\//g, pathPrefix);
124
+ fs.writeFileSync(destPath, content);
125
+ } else {
126
+ fs.copyFileSync(srcPath, destPath);
127
+ }
128
+ }
129
+ }
130
+
131
+ /**
132
+ * ~/.luckiest/key helpers. The key is NEVER echoed to stdout/logs and is
133
+ * only ever written to this one file, at mode 0600.
134
+ */
135
+ function keyFilePath() {
136
+ return path.join(os.homedir(), '.luckiest', 'key');
137
+ }
138
+
139
+ function readSavedKey() {
140
+ try {
141
+ const raw = fs.readFileSync(keyFilePath(), 'utf8').trim();
142
+ return raw.length ? raw : null;
143
+ } catch {
144
+ return null;
145
+ }
146
+ }
147
+
148
+ function saveKey(key) {
149
+ const dir = path.join(os.homedir(), '.luckiest');
150
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
151
+ const file = keyFilePath();
152
+ fs.writeFileSync(file, `${key}\n`, { mode: 0o600 });
153
+ try {
154
+ fs.chmodSync(file, 0o600);
155
+ } catch {
156
+ // best effort on platforms without chmod semantics
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Prompt for the connection key. Input is not masked (no new dependency
162
+ * for that), but the value is never printed back and never logged.
163
+ */
164
+ function promptKey() {
165
+ return new Promise((resolve) => {
166
+ const rl = readline.createInterface({
167
+ input: process.stdin,
168
+ output: process.stdout
169
+ });
170
+ rl.question(
171
+ ` Paste your luckiest.co connection key (starts with lk_mcp_), or press Enter to skip: `,
172
+ (answer) => {
173
+ rl.close();
174
+ resolve(answer.trim());
175
+ }
176
+ );
177
+ });
178
+ }
179
+
180
+ function apiBaseUrl() {
181
+ return (process.env.LUCKIEST_API_URL || 'https://luckiest.co').replace(/\/$/, '');
182
+ }
183
+
184
+ function hasUnzip() {
185
+ try {
186
+ execFileSync('unzip', ['-v'], { stdio: 'ignore' });
187
+ return true;
188
+ } catch {
189
+ return false;
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Sync owned skills from luckiest.co into ~/.claude/skills/<name>/.
195
+ * Never logs the key or the Authorization header.
196
+ */
197
+ async function syncSkills() {
198
+ const key = readSavedKey();
199
+ if (!key) {
200
+ console.log(` ${dim}No luckiest.co connection key saved yet. Run ${cyan}npx luckiest-co${dim} and paste one to sync your owned skills.${reset}`);
201
+ return;
202
+ }
203
+
204
+ const base = apiBaseUrl();
205
+ console.log(` Syncing owned skills from ${cyan}${base}${reset}...\n`);
206
+
207
+ let skills;
208
+ try {
209
+ const res = await fetch(`${base}/api/skills/owned`, {
210
+ headers: { Authorization: `Bearer ${key}` }
211
+ });
212
+ if (!res.ok) {
213
+ console.log(` ${yellow}Could not fetch owned skills (HTTP ${res.status}). Skipping sync.${reset}`);
214
+ return;
215
+ }
216
+ const body = await res.json();
217
+ skills = Array.isArray(body) ? body : body.skills;
218
+ } catch (err) {
219
+ console.log(` ${yellow}Could not reach luckiest.co to sync skills: ${err.message}${reset}`);
220
+ return;
221
+ }
222
+
223
+ if (!skills || skills.length === 0) {
224
+ console.log(` ${dim}No owned skills found for this key.${reset}`);
225
+ return;
226
+ }
227
+
228
+ const skillsRoot = path.join(os.homedir(), '.claude', 'skills');
229
+ fs.mkdirSync(skillsRoot, { recursive: true });
230
+ const unzipAvailable = hasUnzip();
231
+
232
+ const results = [];
233
+
234
+ for (const skill of skills) {
235
+ const { name, version, downloadUrl } = skill || {};
236
+ if (!name || !downloadUrl) {
237
+ console.log(` ${yellow}Skipping a skill entry with missing name or downloadUrl.${reset}`);
238
+ continue;
239
+ }
240
+
241
+ // Sanitize skill name to prevent path traversal attacks
242
+ const safeName = path.basename(String(name || ''));
243
+ if (!safeName || safeName === '.' || safeName === '..' || safeName !== name) {
244
+ console.warn(` ${yellow}Skipping skill with unsafe name: ${name}${reset}`);
245
+ continue;
246
+ }
247
+
248
+ try {
249
+ const zipRes = await fetch(downloadUrl);
250
+ if (!zipRes.ok) {
251
+ throw new Error(`download failed (HTTP ${zipRes.status})`);
252
+ }
253
+ const buf = Buffer.from(await zipRes.arrayBuffer());
254
+
255
+ if (unzipAvailable) {
256
+ const dest = path.join(skillsRoot, safeName);
257
+ fs.mkdirSync(dest, { recursive: true });
258
+ const tmpZip = path.join(os.tmpdir(), `luckiest-skill-${safeName}-${Date.now()}.zip`);
259
+ fs.writeFileSync(tmpZip, buf);
260
+ try {
261
+ execFileSync('unzip', ['-q', '-o', tmpZip, '-d', dest]);
262
+ results.push({ name, version: version || 'unknown', path: dest });
263
+ } finally {
264
+ fs.unlinkSync(tmpZip);
265
+ }
266
+ } else {
267
+ const zipPath = path.join(skillsRoot, `${safeName}.zip`);
268
+ fs.writeFileSync(zipPath, buf);
269
+ results.push({ name, version: version || 'unknown', path: `${zipPath} (unzip manually, unzip not found on PATH)` });
270
+ }
271
+ } catch (err) {
272
+ console.log(` ${yellow}Warning: failed to install skill "${name}": ${err.message}${reset}`);
273
+ }
274
+ }
275
+
276
+ if (results.length === 0) {
277
+ console.log(` ${yellow}No skills were installed.${reset}`);
278
+ return;
279
+ }
280
+
281
+ console.log(`\n ${green}Skill sync summary:${reset}`);
282
+ const nameWidth = Math.max(4, ...results.map(r => r.name.length));
283
+ const versionWidth = Math.max(7, ...results.map(r => r.version.length));
284
+ console.log(` ${'Name'.padEnd(nameWidth)} ${'Version'.padEnd(versionWidth)} Path`);
285
+ for (const r of results) {
286
+ console.log(` ${r.name.padEnd(nameWidth)} ${r.version.padEnd(versionWidth)} ${r.path}`);
287
+ }
288
+ console.log('');
289
+ }
290
+
291
+ /**
292
+ * Install to the specified directory
293
+ */
294
+ function install(isGlobal) {
295
+ const src = path.join(__dirname, '..');
296
+ const configDir = expandTilde(explicitConfigDir) || expandTilde(process.env.CLAUDE_CONFIG_DIR);
297
+ const defaultGlobalDir = configDir || path.join(os.homedir(), '.claude');
298
+ const claudeDir = isGlobal
299
+ ? defaultGlobalDir
300
+ : path.join(process.cwd(), '.claude');
301
+
302
+ const locationLabel = isGlobal
303
+ ? claudeDir.replace(os.homedir(), '~')
304
+ : claudeDir.replace(process.cwd(), '.');
305
+
306
+ // Path prefix for file references
307
+ const pathPrefix = isGlobal
308
+ ? (configDir ? `${claudeDir}/` : '~/.claude/')
309
+ : './.claude/';
310
+
311
+ console.log(` Installing to ${cyan}${locationLabel}${reset}\n`);
312
+
313
+ // Copy commands/luckiest into commands/luckiest
314
+ const commandsDir = path.join(claudeDir, 'commands');
315
+ fs.mkdirSync(commandsDir, { recursive: true });
316
+
317
+ const commandsSrc = path.join(src, 'commands', 'luckiest');
318
+ const commandsDest = path.join(commandsDir, 'luckiest');
319
+ if (fs.existsSync(commandsSrc)) {
320
+ copyWithPathReplacement(commandsSrc, commandsDest, pathPrefix);
321
+ console.log(` ${green}✓${reset} Installed commands/luckiest`);
322
+ }
323
+
324
+ // Copy references/, templates/, .claude-plugin/ into the target root
325
+ const topLevelDirs = ['references', 'templates', '.claude-plugin'];
326
+ for (const dir of topLevelDirs) {
327
+ const dirSrc = path.join(src, dir);
328
+ const dirDest = path.join(claudeDir, dir);
329
+ if (fs.existsSync(dirSrc)) {
330
+ copyWithPathReplacement(dirSrc, dirDest, pathPrefix);
331
+ console.log(` ${green}✓${reset} Installed ${dir}`);
332
+ }
333
+ }
334
+
335
+ console.log(`
336
+ ${green}Done!${reset} Launch Claude Code and run ${cyan}/luckiest:plan${reset}.
337
+ `);
338
+ }
339
+
340
+ /**
341
+ * Prompt for install location
342
+ */
343
+ function promptLocation() {
344
+ return new Promise((resolve) => {
345
+ const rl = readline.createInterface({
346
+ input: process.stdin,
347
+ output: process.stdout
348
+ });
349
+
350
+ const configDir = expandTilde(explicitConfigDir) || expandTilde(process.env.CLAUDE_CONFIG_DIR);
351
+ const globalPath = configDir || path.join(os.homedir(), '.claude');
352
+ const globalLabel = globalPath.replace(os.homedir(), '~');
353
+
354
+ console.log(` ${yellow}Where would you like to install?${reset}
355
+
356
+ ${cyan}1${reset}) Global ${dim}(${globalLabel})${reset}, available in all projects
357
+ ${cyan}2${reset}) Local ${dim}(./.claude)${reset}, this project only
358
+ `);
359
+
360
+ rl.question(` Choice ${dim}[1]${reset}: `, (answer) => {
361
+ rl.close();
362
+ const choice = answer.trim() || '1';
363
+ resolve(choice !== '2');
364
+ });
365
+ });
366
+ }
367
+
368
+ async function main() {
369
+ if (syncOnly) {
370
+ await syncSkills();
371
+ return;
372
+ }
373
+
374
+ if (hasGlobal && hasLocal) {
375
+ console.error(` ${yellow}Cannot specify both --global and --local${reset}`);
376
+ process.exit(1);
377
+ }
378
+
379
+ let isGlobal;
380
+ if (explicitConfigDir && hasLocal) {
381
+ console.error(` ${yellow}Cannot use --config-dir with --local${reset}`);
382
+ process.exit(1);
383
+ } else if (hasGlobal) {
384
+ isGlobal = true;
385
+ } else if (hasLocal) {
386
+ isGlobal = false;
387
+ } else {
388
+ isGlobal = await promptLocation();
389
+ }
390
+
391
+ install(isGlobal);
392
+
393
+ const alreadyHasKey = !!readSavedKey();
394
+ if (!alreadyHasKey) {
395
+ const key = await promptKey();
396
+ if (key) {
397
+ if (!key.startsWith('lk_mcp_')) {
398
+ console.log(` ${yellow}That doesn't look like a luckiest.co key (expected lk_mcp_...), but saving it anyway.${reset}`);
399
+ }
400
+ saveKey(key);
401
+ console.log(` ${green}✓${reset} Key saved to ${dim}~/.luckiest/key${reset}\n`);
402
+ } else {
403
+ console.log(` ${dim}Skipped. Run ${cyan}npx luckiest-co --sync-only${dim} later once you have a key.${reset}\n`);
404
+ }
405
+ }
406
+
407
+ await syncSkills();
408
+ }
409
+
410
+ main().catch((err) => {
411
+ console.error(` ${red}Install failed: ${err.message}${reset}`);
412
+ process.exit(1);
413
+ });
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: Your charms balance and recent related activity.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` and `references/chart-renderer.md` first and follow them for all output in this command.
6
+
7
+ ## Step 1: Get the data
8
+
9
+ Call the `overview` tool from the luckiest MCP server. Use the `charms` balance and scan `tribePulse` for any entries whose `event` text relates to charms (earning or spending).
10
+
11
+ ## Step 2: Render the dashboard
12
+
13
+ Render one fenced code block following the chart-renderer grammar:
14
+
15
+ 1. Title line: `Charms`
16
+ 2. Balance line: `balance X` where X is the `charms` value from `overview`, right-aligned if paired with other numbers.
17
+ 3. If any charm-related entries exist in `tribePulse`, list them plainly, one per line, using the raw `event` text exactly as returned. Do not invent a friendlier phrasing.
18
+ 4. If there is no daily earn/spend history available (there is no history endpoint in this version), add this exact line: `History view coming soon.` Do not invent daily numbers, trends, or a chart of activity over time. Only render a bar chart of actual daily values if such data is actually returned by a tool; since none is available here, skip the bar chart and show the line above instead.
19
+ 5. Footer: `→ /luckiest charms`
20
+
21
+ Example:
22
+
23
+ ```
24
+ Charms
25
+ balance 130
26
+ History view coming soon.
27
+ → /luckiest charms
28
+ ```
29
+
30
+ Use only user-facing vocabulary from `references/vocabulary.md`. Never surface PLAN, APPLY, UNIFY, DRAFT, DOING, DONE, HANDOFF, or any internal term.
31
+
32
+ ## Step 3: Recommend next action
33
+
34
+ End your response with exactly one line, nothing after it:
35
+
36
+ Next: /luckiest home
@@ -0,0 +1,40 @@
1
+ ---
2
+ description: Wrap up, what shipped, what changed, what's next.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` first and follow it for all output in this command: plain language, no em dashes, no internal terms, one next-step recommendation at the end.
6
+
7
+ ## Step 1: Check that everything is done
8
+
9
+ Call the `status` tool from the luckiest MCP server.
10
+
11
+ If any task is still open (not complete), list those tasks for the user and stop here. Do not proceed to the rest of this command. End your response with exactly one line, nothing after it:
12
+
13
+ Next: /luckiest go
14
+
15
+ ## Step 2: Compose the recap
16
+
17
+ If every task is complete, write a short recap in chat with these sections:
18
+
19
+ - **Shipped**: what got built or changed, in plain terms.
20
+ - **Decisions**: any notable choices made along the way and why.
21
+ - **Key files**: the main files touched, so the user knows where to look.
22
+ - **Deferred**: anything explicitly pushed off, if applicable. Say "none" if there's nothing deferred.
23
+
24
+ ## Step 3: Close it out
25
+
26
+ Call the `finish` tool from the luckiest MCP server with:
27
+
28
+ ```
29
+ { decisions, keyFiles, deferred }
30
+ ```
31
+
32
+ using the same lists from your recap. This awards Charms and archives the history automatically.
33
+
34
+ Report the Charms earned in friendly, plain terms, for example: "You earned 3 charms."
35
+
36
+ ## Step 4: Wrap up
37
+
38
+ End your response with exactly one line, nothing after it:
39
+
40
+ Next: /luckiest plan for the next piece, or /luckiest home to see where you stand.
@@ -0,0 +1,45 @@
1
+ ---
2
+ description: Run your plan, one task at a time, checked as it goes.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` first and follow it for all output in this command: plain language, no em dashes, no internal terms, one next-step recommendation at the end.
6
+
7
+ ## Step 1: Load the plan
8
+
9
+ Call the `status` tool from the luckiest MCP server. This is a zero-context resume, treat its result as the full picture of where things stand: don't assume anything about prior state beyond what it returns.
10
+
11
+ ## Step 2: Execute in-session
12
+
13
+ Do all task work yourself, in this session, message by message.
14
+
15
+ - Forbidden: spawning subagents to execute tasks. Never hand off the actual work of a ready task to a subagent.
16
+ - Allowed: spawning subagents for research only (for example, looking something up, exploring the codebase for context). The work itself, writing code, making changes, running commands, stays in this session.
17
+
18
+ ## Step 3: Work through ready tasks, one at a time
19
+
20
+ Take the ready tasks one at a time, in order. For each one:
21
+
22
+ 1. Do the work using the task's suggested skill. If that skill is installed, invoke it via the Skill tool. If it isn't installed, do the work directly without it.
23
+ 2. Check your result against the task's "done means..." line. Don't move on until it's actually met.
24
+ 3. If the result is something the user can try themselves (a page, a feature, a flow), ask exactly this: "Try it yourself, does it work? yes / needs fixes." Wait for their answer.
25
+ 4. On a pass, call the `apply` tool with `{ taskId }` for that task, then call the `verify` tool with `{ results: [{ taskId, pass: true }] }`.
26
+ 5. On a fail, fix the problem before moving on to the next task. Only call `verify` with `pass: false` for that task if the user explicitly chooses to defer the fix instead of having you fix it now.
27
+
28
+ Only move to the next ready task once the current one is applied and verified (or deferred).
29
+
30
+ ## Step 4: Stop conditions
31
+
32
+ Pause and ask the user before doing any of the following, even if it seems like the obvious next step:
33
+
34
+ - Any destructive action (deleting data, dropping tables, force-pushing, overwriting files with no way back).
35
+ - Adding a new dependency.
36
+ - Any schema change.
37
+
38
+ If the session has to end before the plan is done, call the `pause` tool with `{ reason }`, a one-line reason describing where things were left.
39
+
40
+ ## Step 5: Wrap up
41
+
42
+ End your response with exactly one line, nothing after it.
43
+
44
+ - If all tasks are done: `Next: /luckiest finish to wrap up.`
45
+ - Otherwise: `Next: <the next task title>.`
@@ -0,0 +1,64 @@
1
+ ---
2
+ description: See who needs a hand right now, and claim a request to help.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` and `references/chart-renderer.md` first and follow them for all output in this command.
6
+
7
+ ## Step 1: Get the data
8
+
9
+ Call the `overview` tool from the luckiest MCP server to get the `openAssists` count. If an assist listing tool is available that returns the actual open requests (title, poster, wish reward, and id for each), use it and prefer that list over the raw count. In v1 a per-request listing may not be available through the MCP server: in that case, do not invent requests. Show the count and point the user to the full board, as described in Step 2.
10
+
11
+ ## Step 2: Render the open requests
12
+
13
+ If the count is zero and no requests come back, output nothing except:
14
+
15
+ ```
16
+ No open requests right now.
17
+ ```
18
+
19
+ Then end with:
20
+
21
+ ```
22
+ Next: /luckiest home
23
+ ```
24
+
25
+ Do not proceed further.
26
+
27
+ If you have the count but no per-request details (no listing tool available), render one fenced block with the count and an honest pointer, then stop:
28
+
29
+ ```
30
+ Needs Help
31
+ open requests 3
32
+ Full board and claiming at luckiest.co/dashboard
33
+ → /luckiest home
34
+ ```
35
+
36
+ and end with `Next: open luckiest.co to claim a request`.
37
+
38
+ If there are open requests with details, render one fenced code block following the chart-renderer grammar:
39
+
40
+ 1. Title line: `Needs Help (X open)` where X is the number of requests actually listed.
41
+ 2. One entry per request, each showing:
42
+ - Title of the request
43
+ - Poster name
44
+ - Wish reward, right-aligned, e.g. `reward 8 wishes`
45
+ - A claim line directly under it: `→ tell me "claim <id>" and I'll pick it up with respond_to_assist`
46
+
47
+ Example:
48
+
49
+ ```
50
+ Needs Help (2 open)
51
+ Fix the onboarding copy posted by Priya reward 8 wishes
52
+ → tell me "claim a12" and I'll pick it up with respond_to_assist
53
+
54
+ Review the pricing page posted by Marcus reward 5 wishes
55
+ → tell me "claim a13" and I'll pick it up with respond_to_assist
56
+ ```
57
+
58
+ Use only user-facing vocabulary from `references/vocabulary.md`. Never surface PLAN, APPLY, UNIFY, DRAFT, DOING, DONE, HANDOFF, or any internal term. Do not fabricate requests, posters, or rewards beyond what the tools return.
59
+
60
+ ## Step 3: Recommend next action
61
+
62
+ End your response with exactly one line, nothing after it:
63
+
64
+ Next: tell me "claim <id>" for the request you want to help with
@@ -0,0 +1,43 @@
1
+ ---
2
+ description: The community dashboard. Wishes and charms, plan progress, tribe pulse, and who needs help.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` and `references/chart-renderer.md` first and follow them for all output in this command.
6
+
7
+ ## Step 1: Get the data
8
+
9
+ Call the `overview` tool from the luckiest MCP server. It returns `{ wishes, charms, loop, openAssists, tribePulse }`.
10
+
11
+ ## Step 2: Render the dashboard
12
+
13
+ Render one fenced code block following the chart-renderer grammar, with four boxes in this order. Separate boxes with a blank line.
14
+
15
+ 1. **Wishes + Charms box**
16
+ - Title line: `Wishes & Charms`
17
+ - One line showing the two balances, aligned columns, thousands separators, for example `wishes 42 charms 130`
18
+ - Footer: `→ /luckiest wishes`
19
+
20
+ 2. **Active plan progress box**
21
+ - Title line: `Plan Progress`
22
+ - If `loop` is null, one line: `No plan yet.`
23
+ - If `loop` is present, one progress bar line using `█` (filled) and `░` (empty), exactly 20 chars total, with `done/total` right-aligned, for example `██████░░░░░░░░░░░░ 3/5`, plus the phase name if present.
24
+ - Footer: if `loop` is present, `→ /luckiest go`; if `loop` is null, `→ /luckiest status`
25
+
26
+ 3. **Tribe pulse box**
27
+ - Title line: `Tribe Pulse`
28
+ - One line per entry in `tribePulse`, showing the member name and the raw `event` string exactly as returned. Do not rewrite, embellish, or invent a friendlier phrasing for the event text. If `tribePulse` is empty, one line: `No recent activity.`
29
+ - Footer: `→ /luckiest leaderboard`
30
+
31
+ 4. **Needs help box**
32
+ - Title line: `Needs Help`
33
+ - One line: `open requests X` where X is `openAssists`.
34
+ - Footer: `→ /luckiest helpers`
35
+
36
+ Use only user-facing vocabulary from `references/vocabulary.md`. Never surface PLAN, APPLY, UNIFY, DRAFT, DOING, DONE, HANDOFF, or any internal term.
37
+
38
+ ## Step 3: Recommend next action
39
+
40
+ End your response with exactly one line, nothing after it, based on whether a plan is active:
41
+
42
+ - If `loop` is present (active plan): `Next: /luckiest go`
43
+ - If `loop` is null (no active plan): `Next: /luckiest plan`
@@ -0,0 +1,37 @@
1
+ ---
2
+ description: See how the tribe ranks. Top scores, one bar chart.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` and `references/chart-renderer.md` first and follow them for all output in this command.
6
+
7
+ ## Step 1: Get the data
8
+
9
+ Call the `tribe_leaderboard` tool from the luckiest MCP server. If the tool accepts a range argument and the user specified one (e.g. `/luckiest leaderboard 30d`), pass it through. Otherwise call it with no range argument.
10
+
11
+ ## Step 2: Render the leaderboard
12
+
13
+ Render one fenced code block following the chart-renderer grammar.
14
+
15
+ 1. **Range header**: only include a `[ 7 Days ] 30 Days All`-style range header if the tool's response indicates it supports ranges (e.g. it echoes back a range or accepts one). If there is no evidence the tool supports ranges, omit the header entirely. Do not invent range options.
16
+
17
+ 2. **Ranked bar chart**: one line per member, in rank order, with columns for rank, name, and a horizontal bar representing score. Use `█` for filled, `░` for empty, width 20 chars, value right-aligned. For example:
18
+
19
+ ```
20
+ Tribe Leaderboard
21
+ 1 Priya ████████████████░░░░ 820
22
+ 2 Sam ██████████████░░░░░░ 710
23
+ 3 Marcus ████████░░░░░░░░░░░░ 405
24
+ → /luckiest leaderboard
25
+ ```
26
+
27
+ 3. **Movement arrows**: only add a movement indicator (e.g. `▲2`, `▼1`, `=`) next to a member's name if the tool response includes prior-rank data for that member. If no prior-rank data is present anywhere in the response, omit movement indicators entirely for all members. Do not fabricate or estimate movement.
28
+
29
+ 4. **Footer**: last line in the block is `→ /luckiest leaderboard` (or the range-qualified form if a range was passed, e.g. `→ /luckiest leaderboard 30d`).
30
+
31
+ Use only user-facing vocabulary from `references/vocabulary.md`. Never surface PLAN, APPLY, UNIFY, DRAFT, DOING, DONE, HANDOFF, or any internal term.
32
+
33
+ ## Step 3: Recommend next action
34
+
35
+ End your response with exactly one line, nothing after it:
36
+
37
+ Next: /luckiest helpers
@@ -0,0 +1,38 @@
1
+ ---
2
+ description: Merge two overlapping skills into one, after you review the diff.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` first and follow it for all output in this command: plain language, no em dashes, no internal terms, one next-step recommendation at the end.
6
+
7
+ ## Step 1: Get the two skill ids
8
+
9
+ If the user named both skills (e.g. `/luckiest merge luckiest-copywriting their-copy-skill`), use those as `ourSkillId` and `theirSkillId`. Otherwise ask which two skills to merge, or point them to `/luckiest overlaps` to find a pair first.
10
+
11
+ ## Step 2: Draft the merge
12
+
13
+ Call the `draft_merge` tool from the luckiest MCP server with `{ ourSkillId, theirSkillId }`.
14
+
15
+ This does not install or archive anything yet. Show the user the returned diff plainly, as a fenced code block. Do not summarize it away, they need to see exactly what changes.
16
+
17
+ Ask exactly one approval question:
18
+
19
+ "Use this merged version? yes / no"
20
+
21
+ Wait for the answer.
22
+
23
+ - If no, stop here. End with the wrap-up line in Step 4.
24
+ - If yes, continue to Step 3.
25
+
26
+ ## Step 3: Apply the merge
27
+
28
+ Call the `apply_merge` tool from the luckiest MCP server with `{ ourSkillId, theirSkillId, mergedName, mergedContent }`, using the merged name and content from the draft in Step 2.
29
+
30
+ Tell the user plainly what happened: the two original skill directories were archived (moved to `~/.claude/luckiest-archive/`, never deleted) and the merged skill was installed under `mergedName`.
31
+
32
+ ## Step 4: Wrap up
33
+
34
+ End your response with exactly one line, nothing after it:
35
+
36
+ ```
37
+ Next: /luckiest skills
38
+ ```
@@ -0,0 +1,50 @@
1
+ ---
2
+ description: Find installed skills that overlap with your own, and resolve them.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` first and follow it for all output in this command: plain language, no em dashes, no internal terms, one next-step recommendation at the end.
6
+
7
+ ## Step 1: Pick a skill to check
8
+
9
+ If the user named a skill (e.g. `/luckiest overlaps luckiest-copywriting`), use that as `skillId`. Otherwise, list the installed `luckiest-*` skills (same discovery as `/luckiest skills`, directories under `~/.claude/skills/`) and ask which one to check.
10
+
11
+ ## Step 2: Scan
12
+
13
+ Call the `scan_overlaps` tool from the luckiest MCP server with `{ skillId }`.
14
+
15
+ If it returns no overlapping pairs, output exactly:
16
+
17
+ ```
18
+ No overlaps found for <skillId>.
19
+ ```
20
+
21
+ Then skip to Step 4.
22
+
23
+ ## Step 3: Show what overlaps and offer a resolution
24
+
25
+ List each overlapping pair plainly, one per entry, showing the other skill's id and its tag-overlap score (and description-similarity score if the tool returned one). Do not invent a score if none was returned.
26
+
27
+ ```
28
+ Overlaps with <skillId>:
29
+ • <theirSkillId> tag overlap 0.82
30
+ ```
31
+
32
+ For each pair, tell the user their three options in plain terms and how to pick one:
33
+
34
+ - "keep both" — leave both installed, the router picks the best fit per task.
35
+ - "shadow" — yours stays authoritative, theirs becomes a fallback.
36
+ - "merge" — draft a combined skill for review (nothing installs yet).
37
+
38
+ Tell them to reply with one of those words plus which pair, e.g. `"merge with <theirSkillId>"`.
39
+
40
+ If the user picks "keep both" or "shadow", call `resolve_overlap` with `{ ourSkillId, theirSkillId, resolution }` using their choice, then confirm what happened in one line.
41
+
42
+ If the user picks "merge", do not call `resolve_overlap` here. Instead tell them to run `/luckiest merge <skillId> <theirSkillId>` to draft and review it.
43
+
44
+ ## Step 4: Wrap up
45
+
46
+ End your response with exactly one line, nothing after it:
47
+
48
+ ```
49
+ Next: /luckiest skills
50
+ ```
@@ -0,0 +1,55 @@
1
+ ---
2
+ description: Plan your next piece of work. Guided questions, then a plan Claude can run.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` first and follow it for all output in this command: plain language, no em dashes, no internal terms, one next-step recommendation at the end.
6
+
7
+ ## Step 1: Gather context
8
+
9
+ Check whether `.luckiest/BRIEF.md` exists in the current project. If it exists, read it and use it as context for the interview below (what they're building, who it's for, what winning looks like). If it does not exist, continue without it.
10
+
11
+ ## Step 2: Check for active work
12
+
13
+ Call the `status` tool from the luckiest MCP server.
14
+
15
+ - If the returned state's position is active (already in progress), stop here. Tell the user a plan is already active and offer `/luckiest go` to resume it instead. Do not stage a new plan over an active one unless the user explicitly confirms they want to replace it. If they confirm, continue to Step 3.
16
+ - Otherwise, continue to Step 3.
17
+
18
+ ## Step 3: Run the interview
19
+
20
+ Ask ONE question at a time, waiting for the answer before asking the next:
21
+
22
+ 1. What outcome do you want this week?
23
+
24
+ Use the answer (plus the brief, if present) to shape a draft task list of 3 to 7 tasks. Each task title must be a single clean line under 200 characters, describing one piece of work. Do not append "done means" text or any acceptance-criteria text to the title.
25
+
26
+ For each draft task, call the `skill_router` tool from the luckiest MCP server to suggest a matching owned skill for that task. Attach the suggested skill(s) to the task.
27
+
28
+ For each task, state a one-line "done means..." in chat (not in the title, not stored anywhere) so the user sees what complete looks like for that task.
29
+
30
+ ## Step 4: Present the plan
31
+
32
+ Show the full draft plan: each task's title, its suggested skill(s), and its "done means..." line. Then ask exactly one approval question, nothing else:
33
+
34
+ "Here's your plan, good to go?"
35
+
36
+ Wait for the answer.
37
+
38
+ - If the user wants changes, revise the plan and ask the same approval question again.
39
+ - If the user says yes, continue to Step 5.
40
+
41
+ ## Step 5: Stage the plan
42
+
43
+ Call the `plan` tool from the luckiest MCP server with:
44
+
45
+ ```
46
+ { phase: <short phase name if any>, tasks: [{ title, skills }] }
47
+ ```
48
+
49
+ Include at most 25 tasks. Each title must stay under 200 characters. Do not include acceptance criteria or "done means" text in any task field.
50
+
51
+ ## Step 6: Wrap up
52
+
53
+ End your response with exactly one line, nothing after it:
54
+
55
+ Next: /luckiest go to start.
@@ -0,0 +1,53 @@
1
+ ---
2
+ description: Your skills, list what's installed, pull new purchases.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` first and follow it for all output in this command. Never delete skills.
6
+
7
+ ## Step 1: List installed luckiest skills
8
+
9
+ First, identify all directories in `~/.claude/skills/` that match the pattern `luckiest-*`. For each one:
10
+
11
+ 1. Read its `SKILL.md` file
12
+ 2. Extract the one-line `description:` value from the YAML frontmatter
13
+ 3. Display the skill name and description as a clean list
14
+
15
+ Format each line as:
16
+ ```
17
+ • <skill-name>: <one-line description>
18
+ ```
19
+
20
+ If no luckiest skills are installed, output:
21
+ ```
22
+ No luckiest skills installed yet. Use /luckiest skills sync to pull your purchases from luckiest.co.
23
+ ```
24
+
25
+ Then jump to Step 3.
26
+
27
+ ## Step 2: Offer sync
28
+
29
+ After the list, add a blank line, then this prompt:
30
+
31
+ ```
32
+ You can pull newly purchased skills by replying "sync" below.
33
+ ```
34
+
35
+ ## Step 3: Handle sync request
36
+
37
+ If the user replies "sync" or similar intent:
38
+
39
+ 1. Run this command via Bash: `npx luckiest-co --sync-only`
40
+ 2. Report what was added (skill names and versions) from the command output
41
+ 3. If no new skills were synced, acknowledge that the installation is already up to date
42
+
43
+ If the user does not request sync, skip this step.
44
+
45
+ ## Step 4: Next line
46
+
47
+ End your response with exactly one line, nothing after it:
48
+
49
+ ```
50
+ Next: /luckiest plan
51
+ ```
52
+
53
+ Never modify or delete any installed skills. This command is read-only except for the sync operation.
@@ -0,0 +1,45 @@
1
+ ---
2
+ description: Tell me about your project, a short interview that writes your Brand Brief.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` first and follow it for all output in this command: plain language, no em dashes, no internal terms, one next-step recommendation at the end.
6
+
7
+ ## Step 1: Check for an existing brief
8
+
9
+ Check whether `.luckiest/BRIEF.md` exists in the current project.
10
+
11
+ - If it exists, read it and show the user a short summary (what they're building, who it's for, what winning looks like). Then ask: "Keep this brief as is, or update it?" Wait for their answer.
12
+ - If they choose to keep it, skip straight to the sync step below and end the command.
13
+ - If they choose to update it, continue to the interview below, but only ask about the sections they want to change.
14
+ - If it does not exist, continue to the interview below.
15
+
16
+ Never overwrite `.luckiest/BRIEF.md` silently. The user always gets to see what's there first and decide.
17
+
18
+ ## Step 2: Run the interview
19
+
20
+ Ask the following questions ONE at a time, in order, waiting for the answer before asking the next. There are at most 6 questions. Tell the user up front that any question can be skipped by answering "skip."
21
+
22
+ 1. What are you building?
23
+ 2. Who is it for?
24
+ 3. What does winning look like in 30 days?
25
+ 4. What tone or voice should this have?
26
+ 5. Is there anything that must not change?
27
+ 6. Any links to share (designs, docs, prior work)?
28
+
29
+ Keep the tone conversational, not a form. Ask one question, read the reply, then move to the next. Don't dump all six at once.
30
+
31
+ ## Step 3: Write the brief
32
+
33
+ Read `templates/BRIEF.md` (in this plugin) for the section structure. Each section carries an HTML-comment prompt like `<!-- filled from the /luckiest start interview -->`. Fill each section in using the interview answers, in the user's own words where possible. If the user skipped a question, leave that section's `<!-- ... -->` comment in place rather than inventing content.
34
+
35
+ Write the result to `.luckiest/BRIEF.md` in the current project (create the `.luckiest/` directory if it doesn't exist).
36
+
37
+ ## Step 4: Sync
38
+
39
+ Call the `pause` tool from the luckiest MCP server with a reason like: `Brief created: <one-line summary of what they're building>`. This notes in the session bookmark that the brief now exists.
40
+
41
+ ## Step 5: Wrap up
42
+
43
+ End your response with exactly one line, nothing after it:
44
+
45
+ Next: /luckiest plan to plan your first work.
@@ -0,0 +1,55 @@
1
+ ---
2
+ description: Where you are. Progress, tasks, and your one next step.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` and `references/chart-renderer.md` first and follow them for all output in this command.
6
+
7
+ ## Step 1: Check for a plan
8
+
9
+ Call the `status` tool from the luckiest MCP server.
10
+
11
+ If the returned state is null (no active plan), output nothing except these two lines, in order:
12
+
13
+ ```
14
+ No plan yet. Start with /luckiest plan.
15
+ ```
16
+
17
+ Then end with:
18
+
19
+ ```
20
+ Next: /luckiest plan
21
+ ```
22
+
23
+ Do not proceed further.
24
+
25
+ ## Step 2: Render the status dashboard
26
+
27
+ If a plan exists, render one fenced code block following the chart-renderer grammar. The block MUST include:
28
+
29
+ 1. **Plan phase and header**: First line shows the plan's phase name (if present) or a generic title like "Your Work".
30
+ 2. **Progress bar**: One line with format `█` (filled) and `░` (empty) chars, exactly 20 chars total, with the count `done/total` right-aligned. Example: `██████░░░░░░░░░░░░ 3/5`
31
+ 3. **Task lines**: One line per task in the plan's task list. Each line shows:
32
+ - Task title (truncate to fit on line)
33
+ - Status glyph: `✓` for done, `▸` for doing, `·` for ready, `?` for assist
34
+ 4. **Pass rate (if any)**: If the state includes any verified task results, add a line showing pass rate in the format `pass rate: X/Y` where X is completed verifications and Y is total tasks.
35
+ 5. **Bookmark line (if paused)**: If the state includes a bookmark (pause), add a line showing the bookmark message.
36
+ 6. **Footer**: Last line in the block ends with the command to check status again (e.g. `→ /luckiest status`).
37
+
38
+ Use only the user-facing vocabulary from `references/vocabulary.md`. Never surface PLAN, APPLY, UNIFY, DRAFT, DOING, DONE, HANDOFF, or any internal term.
39
+
40
+ Map each task's status to a glyph (these are the task status values, not the plan position):
41
+ - "done" -> `✓`
42
+ - "doing" -> `▸`
43
+ - "ready" -> `·`
44
+ - "assist" -> `?`
45
+ - "blocked" -> `✗`
46
+
47
+ ## Step 3: Recommend next action
48
+
49
+ End your response with exactly one line, nothing after it, derived from the MCP `nextAction` field:
50
+
51
+ ```
52
+ Next: <nextAction>
53
+ ```
54
+
55
+ If nextAction is null or empty, default to the most logical next step based on the current state (e.g., `Next: /luckiest go` if tasks are ready).
@@ -0,0 +1,47 @@
1
+ ---
2
+ description: Check for updates to your installed luckiest skills and plugin.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` first and follow it for all output in this command: plain language, no em dashes, no internal terms, one next-step recommendation at the end.
6
+
7
+ ## Step 1: Check for updates
8
+
9
+ Call the `check_updates` tool from the luckiest MCP server.
10
+
11
+ ## Step 2: Report what's available
12
+
13
+ If no updates are available, output exactly:
14
+
15
+ ```
16
+ Everything is up to date.
17
+ ```
18
+
19
+ Then skip to Step 3.
20
+
21
+ If updates are available, list each one plainly, one per line, using only what the tool returns (skill or plugin name, current version, available version). Do not invent version numbers or changelog details that weren't returned. For example:
22
+
23
+ ```
24
+ Updates available:
25
+ • luckiest-copywriting 1.2.0 → 1.3.0
26
+ • luckiest-cro 2.0.1 → 2.1.0
27
+ ```
28
+
29
+ If any update includes a changelog or summary field in the tool response, show it as a short indented line under that entry. Do not fabricate one if it's missing.
30
+
31
+ ## Step 3: Offer to sync
32
+
33
+ If updates were found, add a blank line, then:
34
+
35
+ ```
36
+ You can pull these by replying "sync" below.
37
+ ```
38
+
39
+ If the user replies "sync" or similar intent, run this command via Bash: `npx luckiest-co --sync-only`, then report what was actually updated from the command output.
40
+
41
+ ## Step 4: Wrap up
42
+
43
+ End your response with exactly one line, nothing after it:
44
+
45
+ ```
46
+ Next: /luckiest skills
47
+ ```
@@ -0,0 +1,33 @@
1
+ ---
2
+ description: Request or approve a warm intro to someone outside your tribe.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` first and follow it for all output in this command: plain language, no em dashes, no internal terms, one next-step recommendation at the end.
6
+
7
+ ## Step 1: Figure out the intent
8
+
9
+ - If the user is asking for an intro to someone (e.g. `/luckiest vouch <targetId>`, or "I need a warm intro to X"), go to Step 2.
10
+ - If the user is approving a vouch someone asked them for (e.g. "approve vouch <vouchId>", or they were told about a pending vouch elsewhere), go to Step 3.
11
+ - If neither is clear, ask which one they mean.
12
+
13
+ ## Step 2: Request a warm intro
14
+
15
+ Call the `request_vouch` tool from the luckiest MCP server with `{ targetId }`. If this request is tied to an open assist request, include `assistRequestId` too.
16
+
17
+ This asks a shared 1st-degree tribe member (someone in your direct tribe who also knows the target) to vouch for you before you can reach a 3rd-degree person directly.
18
+
19
+ Report plainly that the request was sent and who needs to approve it, if the tool response says.
20
+
21
+ ## Step 3: Approve a vouch
22
+
23
+ Call the `approve_vouch` tool from the luckiest MCP server with `{ vouchId }`.
24
+
25
+ Confirm plainly that the vouch was approved and the intro can proceed.
26
+
27
+ ## Step 4: Wrap up
28
+
29
+ End your response with exactly one line, nothing after it:
30
+
31
+ ```
32
+ Next: /luckiest helpers
33
+ ```
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: Your wishes balance and recent related activity.
3
+ ---
4
+
5
+ Read `references/vocabulary.md` and `references/chart-renderer.md` first and follow them for all output in this command.
6
+
7
+ ## Step 1: Get the data
8
+
9
+ Call the `overview` tool from the luckiest MCP server. Use the `wishes` balance and scan `tribePulse` for any entries whose `event` text relates to wishes (earning or spending).
10
+
11
+ ## Step 2: Render the dashboard
12
+
13
+ Render one fenced code block following the chart-renderer grammar:
14
+
15
+ 1. Title line: `Wishes`
16
+ 2. Balance line: `balance X` where X is the `wishes` value from `overview`, right-aligned if paired with other numbers.
17
+ 3. If any wish-related entries exist in `tribePulse`, list them plainly, one per line, using the raw `event` text exactly as returned. Do not invent a friendlier phrasing.
18
+ 4. If there is no daily earn/spend history available (there is no history endpoint in this version), add this exact line: `History view coming soon.` Do not invent daily numbers, trends, or a chart of activity over time. Only render a bar chart of actual daily values if such data is actually returned by a tool; since none is available here, skip the bar chart and show the line above instead.
19
+ 5. Footer: `→ /luckiest wishes`
20
+
21
+ Example:
22
+
23
+ ```
24
+ Wishes
25
+ balance 42
26
+ History view coming soon.
27
+ → /luckiest wishes
28
+ ```
29
+
30
+ Use only user-facing vocabulary from `references/vocabulary.md`. Never surface PLAN, APPLY, UNIFY, DRAFT, DOING, DONE, HANDOFF, or any internal term.
31
+
32
+ ## Step 3: Recommend next action
33
+
34
+ End your response with exactly one line, nothing after it:
35
+
36
+ Next: /luckiest charms
package/package.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "luckiest-co",
3
+ "version": "1.0.0",
4
+ "description": "Luckiest for Claude Code: plan, go, finish. Your luckiest.co skills and tribe, inside Claude.",
5
+ "bin": { "luckiest-co": "./bin/install.js" },
6
+ "files": ["bin", "commands", "references", "templates", ".claude-plugin"],
7
+ "license": "MIT",
8
+ "engines": { "node": ">=18" }
9
+ }
@@ -0,0 +1,31 @@
1
+ # Chart Renderer: Shared Visual Grammar
2
+
3
+ All dashboard commands use this grammar for rendering data visualizations.
4
+
5
+ ## Grammar Rules
6
+
7
+ Render dashboards as fenced code blocks using this grammar:
8
+ - Section box: title line, then content, no borders needed beyond blank lines.
9
+ - Horizontal bar: `█` for filled, `░` for empty, width 20 chars, value right-aligned.
10
+ - Numbers: aligned columns, thousands separators.
11
+ - Range header when applicable: `[ 7 Days ] 30 Days All` with the active range bracketed.
12
+ - Footer line naming the drill-down command, e.g. `→ /luckiest wishes 30d`.
13
+
14
+ ## Example
15
+
16
+ ```
17
+ Wishes [ 7 Days ]
18
+ balance 42 earned 12 spent 5
19
+ 06-28 ████████░░░░░░░░░░░░ 4
20
+ 06-29 ██████████████░░░░░░ 7
21
+ 07-01 ██░░░░░░░░░░░░░░░░░░ 1
22
+ → /luckiest wishes 30d
23
+ ```
24
+
25
+ ## Implementation Notes
26
+
27
+ - Each bar is exactly 20 filled/empty blocks.
28
+ - Values are right-aligned after the bar.
29
+ - Column headers are spaced evenly with at least 2 spaces between.
30
+ - The footer command should match the context (e.g., `/luckiest wishes 30d` for a wishes dashboard).
31
+ - Use single-space line breaks between sections for clarity.
@@ -0,0 +1,35 @@
1
+ # Vocabulary: User-Facing Terms
2
+
3
+ Every command file MUST read this file and follow it in all output.
4
+
5
+ ## Internal Term -> User-Facing Term Mapping
6
+
7
+ | Internal | User-Facing |
8
+ |----------|-------------|
9
+ | PLAN | plan |
10
+ | APPLY | go |
11
+ | UNIFY | finish |
12
+ | skill_loop status | status |
13
+ | DRAFT | in progress |
14
+ | DOING | active |
15
+ | DONE | complete |
16
+ | UAT | testing |
17
+ | AC | requirements |
18
+ | HANDOFF | ready for review |
19
+
20
+ ## Hard Rules
21
+
22
+ 1. **Never show internal terms to the user.** All output must use user-facing vocabulary only. Never surface PLAN, APPLY, UNIFY, skill_loop, UAT, AC, HANDOFF, DRAFT, DOING, or any internal database term in user-visible output.
23
+
24
+ 2. **Exactly one suggested next action per response.** Every command output ends with a single next-step recommendation in the format: `Next: <one action>`
25
+
26
+ 3. **Plain language, no jargon, no em dashes.** Use direct, accessible language. No em dashes. No filler phrases. No marketing speak.
27
+
28
+ ## Interpretation Guide
29
+
30
+ - **"done means"**: A feature is complete when it's tested, documented, and ready for users. Not partial or draft.
31
+ - **"bookmark"**: Save progress state (current plan, step count, completion %) so users can resume later.
32
+ - **plan**: The complete feature spec and acceptance criteria.
33
+ - **go**: Execute the next step of the plan.
34
+ - **finish**: Mark the feature complete and document results.
35
+ - **status**: Check where you are in the feature work.
@@ -0,0 +1,23 @@
1
+ # Brand Brief
2
+
3
+ <!-- filled from the /luckiest start interview -->
4
+
5
+ ## What you're building
6
+
7
+ <!-- One sentence: the feature or product in user terms -->
8
+
9
+ ## Who it's for
10
+
11
+ <!-- The person or role this is built for -->
12
+
13
+ ## What winning looks like
14
+
15
+ <!-- 2-3 bullet points: specific outcomes or behaviors that prove success -->
16
+
17
+ ## Voice & constraints
18
+
19
+ <!-- How should this communicate? Any brand voice, tone, or technical limits -->
20
+
21
+ ## Links & assets
22
+
23
+ <!-- Design files, research docs, previous similar work, reference links -->