@laith-wallace/crisp 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.
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # CRISP — Design Intelligence for AI Agents
2
+
3
+ Five skills that give your AI agent a senior product designer's eye. Drop them into Claude, Cursor, Copilot, or Gemini and get structured design reviews, feature specs, and developer handoffs grounded in the CRISP framework.
4
+
5
+ **CRISP** = Contextual · Responsive · Intelligent · Seamless · Powerful
6
+
7
+ ---
8
+
9
+ ## Skills
10
+
11
+ | Command | What it does |
12
+ |---------|-------------|
13
+ | `/crisp-teach` | Onboards the AI to your product — users, design system, benchmarks. Writes `.crisp.md` which all other commands read automatically. Run once per project. |
14
+ | `/crisp-review` | 30-second scan. Returns a grade A–F and your top 3 issues with specific fixes. Use during rapid iteration. |
15
+ | `/crisp-audit` | Full CRISP evaluation. Scores all five dimensions, rates violations P0–P3, and benchmarks against Stripe, Linear, Notion, Asana, and Slack. |
16
+ | `/feature-design` | Designs a new feature from scratch using CRISP principles — user flows, component decisions, compliance checks, and open questions. |
17
+ | `/handoff` | Converts a reviewed design into a developer-ready spec — states, tokens, interactions, edge cases, accessibility, and exact copy. |
18
+
19
+ ---
20
+
21
+ ## Install
22
+
23
+ ### Claude Code
24
+ ```bash
25
+ npx skills add laith-wallace/crisp
26
+ ```
27
+
28
+ ### Cursor
29
+ Copy the contents of `.cursor/rules/` into your project's `.cursor/rules/` folder.
30
+
31
+ ### Other agents
32
+ - **GitHub Copilot / Antigravity** — copy from `.agents/skills/`
33
+ - **Gemini** — copy from `.gemini/skills/`
34
+ - **Manual** — copy any `.md` file from `files/` and add it to your agent's context
35
+
36
+ ---
37
+
38
+ ## How it works
39
+
40
+ Run `/crisp-teach` first. The AI interviews you about your product, users, and design system, then writes a `.crisp.md` file to your project root. Every subsequent CRISP command reads that file automatically — so reviews and specs are grounded in your specific context, not generic advice.
41
+
42
+ ```
43
+ /crisp-teach → writes .crisp.md
44
+ /crisp-review → reads .crisp.md, returns grade + top 3 issues
45
+ /crisp-audit → reads .crisp.md, full scored evaluation
46
+ /feature-design → reads .crisp.md, produces user flow + spec
47
+ /handoff → reads .crisp.md, produces dev-ready spec
48
+ ```
49
+
50
+ ---
51
+
52
+ ## The CRISP Framework
53
+
54
+ | Dimension | The test |
55
+ |-----------|----------|
56
+ | **C**ontextual | Can the user tell where they are and what this page does within 5 seconds? |
57
+ | **R**esponsive | Does the UI update immediately on every interaction? |
58
+ | **I**ntelligent | Are we showing insight, not raw data? |
59
+ | **S**eamless | Are we fitting into their day — not forcing them into ours? |
60
+ | **P**owerful | Is complexity hidden appropriately for each user type? |
61
+
62
+ ---
63
+
64
+ ## License
65
+
66
+ MIT
package/bin/crisp.mjs ADDED
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+ import * as p from '@clack/prompts';
3
+ import chalk from 'chalk';
4
+ import figlet from 'figlet';
5
+ import { existsSync, mkdirSync, copyFileSync } from 'node:fs';
6
+ import { join, dirname } from 'node:path';
7
+ import { homedir } from 'node:os';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ const LIME = '#c8ff3c';
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const PKG_ROOT = join(__dirname, '..');
13
+
14
+ const SKILLS = [
15
+ { value: 'crisp-teach', label: '/crisp-teach', hint: 'Onboard your AI to your product — writes .crisp.md' },
16
+ { value: 'crisp-review', label: '/crisp-review', hint: '30-second design scan, A–F grade, top 3 issues' },
17
+ { value: 'crisp-audit', label: '/crisp-audit', hint: 'Full CRISP evaluation across 5 dimensions' },
18
+ { value: 'feature-design', label: '/feature-design', hint: 'Design new features using CRISP principles' },
19
+ { value: 'handoff', label: '/handoff', hint: 'Convert designs to developer-ready specs' },
20
+ ];
21
+
22
+ const AGENTS = [
23
+ {
24
+ value: 'claude',
25
+ label: 'Claude Code',
26
+ hint: '~/.claude/skills/',
27
+ src: join(PKG_ROOT, '.claude', 'skills'),
28
+ dest: () => join(homedir(), '.claude', 'skills'),
29
+ detect: () => existsSync(join(homedir(), '.claude')),
30
+ },
31
+ {
32
+ value: 'cursor',
33
+ label: 'Cursor',
34
+ hint: '.cursor/rules/ (current project)',
35
+ src: join(PKG_ROOT, '.cursor', 'rules'),
36
+ dest: () => join(process.cwd(), '.cursor', 'rules'),
37
+ detect: () => existsSync(join(process.cwd(), '.cursor')) || existsSync(join(homedir(), '.cursor')),
38
+ },
39
+ {
40
+ value: 'antigravity',
41
+ label: 'Antigravity',
42
+ hint: '~/.agents/skills/',
43
+ src: join(PKG_ROOT, '.agents', 'skills'),
44
+ dest: () => join(homedir(), '.agents', 'skills'),
45
+ detect: () => existsSync(join(homedir(), '.agents')),
46
+ },
47
+ {
48
+ value: 'gemini',
49
+ label: 'Gemini CLI',
50
+ hint: '~/.gemini/skills/',
51
+ src: join(PKG_ROOT, '.gemini', 'skills'),
52
+ dest: () => join(homedir(), '.gemini', 'skills'),
53
+ detect: () => existsSync(join(homedir(), '.gemini')),
54
+ },
55
+ {
56
+ value: 'manual',
57
+ label: 'Manual copy',
58
+ hint: 'Show file paths — copy yourself',
59
+ src: join(PKG_ROOT, 'files'),
60
+ dest: () => null,
61
+ detect: () => false,
62
+ },
63
+ ];
64
+
65
+ function logo() {
66
+ const art = figlet.textSync('CRISP', { font: 'ANSI Shadow' });
67
+ return chalk.hex(LIME)(art);
68
+ }
69
+
70
+ function cancelIfNeeded(value) {
71
+ if (p.isCancel(value)) {
72
+ p.cancel('Installation cancelled.');
73
+ process.exit(0);
74
+ }
75
+ return value;
76
+ }
77
+
78
+ async function main() {
79
+ console.log('\n' + logo());
80
+ console.log(chalk.hex(LIME).dim(' Design Intelligence for AI Agents\n'));
81
+
82
+ p.intro(chalk.hex(LIME)('CRISP Installer'));
83
+
84
+ // Skill selection
85
+ const selectedSkills = cancelIfNeeded(
86
+ await p.multiselect({
87
+ message: 'Which skills do you want to install?',
88
+ options: SKILLS.map(s => ({ ...s, initialChecked: true })),
89
+ initialValues: SKILLS.map(s => s.value),
90
+ required: true,
91
+ })
92
+ );
93
+
94
+ // Agent selection — pre-select detected agents
95
+ const detectedValues = AGENTS.filter(a => a.detect()).map(a => a.value);
96
+
97
+ const selectedAgentValues = cancelIfNeeded(
98
+ await p.multiselect({
99
+ message: 'Install to which agents?',
100
+ options: AGENTS.map(a => ({
101
+ value: a.value,
102
+ label: a.label,
103
+ hint: a.detect()
104
+ ? chalk.hex(LIME)('✓ detected') + chalk.dim(' ' + a.hint)
105
+ : chalk.dim(a.hint),
106
+ })),
107
+ initialValues: detectedValues.length > 0 ? detectedValues : ['manual'],
108
+ required: true,
109
+ })
110
+ );
111
+
112
+ const selectedAgents = AGENTS.filter(a => selectedAgentValues.includes(a.value));
113
+ const results = {};
114
+
115
+ const spinner = p.spinner();
116
+ spinner.start('Installing skills…');
117
+
118
+ for (const agent of selectedAgents) {
119
+ results[agent.value] = { agent, files: [] };
120
+
121
+ if (agent.value === 'manual') continue;
122
+
123
+ const dest = agent.dest();
124
+ try {
125
+ mkdirSync(dest, { recursive: true });
126
+ } catch (e) {
127
+ results[agent.value].error = `Could not create ${dest}: ${e.message}`;
128
+ continue;
129
+ }
130
+
131
+ for (const skill of selectedSkills) {
132
+ const src = join(agent.src, skill + '.md');
133
+ const dst = join(dest, skill + '.md');
134
+ try {
135
+ copyFileSync(src, dst);
136
+ results[agent.value].files.push({ skill, path: dst, ok: true });
137
+ } catch (e) {
138
+ results[agent.value].files.push({ skill, path: dst, ok: false, error: e.message });
139
+ }
140
+ }
141
+ }
142
+
143
+ spinner.stop(chalk.hex(LIME)('Skills installed'));
144
+
145
+ // Summary
146
+ for (const [, { agent, files, error }] of Object.entries(results)) {
147
+ if (agent.value === 'manual') {
148
+ console.log('\n' + chalk.dim(' ── Manual copy ──'));
149
+ for (const skill of selectedSkills) {
150
+ const src = join(agent.src, skill + '.md');
151
+ console.log(' ' + chalk.dim(src));
152
+ }
153
+ continue;
154
+ }
155
+
156
+ if (error) {
157
+ console.log('\n' + chalk.red(` ✗ ${agent.label}: ${error}`));
158
+ continue;
159
+ }
160
+
161
+ console.log('\n' + chalk.dim(` ── ${agent.label} ──`));
162
+ for (const f of files) {
163
+ if (f.ok) {
164
+ console.log(' ' + chalk.hex(LIME)('✓') + ' ' + chalk.dim(f.path));
165
+ } else {
166
+ console.log(' ' + chalk.red('✗') + ' ' + f.skill + chalk.red(` — ${f.error}`));
167
+ }
168
+ }
169
+ }
170
+
171
+ p.outro(
172
+ chalk.hex(LIME)('Done.') +
173
+ chalk.dim(' Run ') +
174
+ chalk.hex(LIME)('/crisp-teach') +
175
+ chalk.dim(' in your agent to get started.')
176
+ );
177
+ }
178
+
179
+ main().catch(e => {
180
+ console.error(chalk.red('Error: ' + e.message));
181
+ process.exit(1);
182
+ });
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@laith-wallace/crisp",
3
+ "version": "1.0.0",
4
+ "description": "CRISP design intelligence skills for AI agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "crisp": "./bin/crisp.mjs"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ ".claude/skills/",
12
+ ".cursor/rules/",
13
+ ".agents/skills/",
14
+ ".gemini/skills/"
15
+ ],
16
+ "engines": {
17
+ "node": ">=18.0.0"
18
+ },
19
+ "dependencies": {
20
+ "@clack/prompts": "^0.9.0",
21
+ "chalk": "^5.3.0",
22
+ "figlet": "^1.7.0"
23
+ },
24
+ "keywords": ["design", "ux", "ai", "skills", "claude", "cursor", "crisp"],
25
+ "author": "Laith Wallace",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/laith-wallace/crisp"
30
+ }
31
+ }