skilldrop-cli 0.13.5 → 0.13.6
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 +3 -2
- package/catalogue.json +19 -1
- package/contracts/catalogue.schema.json +1 -0
- package/model-routing.json +8 -0
- package/package.json +1 -1
- package/packs/design/pack.json +22 -0
- package/packs/design/skills/brand-kit/SKILL.md +105 -0
- package/packs/design/skills/brand-kit/evals/eval_queries.json +30 -0
- package/packs/design/skills/brand-kit/evals/evals.json +18 -0
- package/packs/design/skills/brand-kit/examples/northwind-brand.md +48 -0
- package/packs/design/skills/brand-kit/manifest.json +44 -0
- package/packs/design/skills/brand-kit/scripts/check_brand.py +114 -0
- package/packs/design/skills/brand-kit/templates/brand.json +54 -0
- package/packs/{stakeholder-comms → design}/skills/deck-builder/SKILL.md +27 -9
- package/packs/{stakeholder-comms → design}/skills/deck-builder/manifest.json +2 -2
- package/packs/{stakeholder-comms → design}/skills/deck-builder/scripts/build_deck.py +105 -3
- package/packs/{stakeholder-comms → design}/skills/deck-builder/templates/deck-spec.json +4 -1
- package/packs/design/skills/marketing-flyer/SKILL.md +113 -0
- package/packs/design/skills/marketing-flyer/evals/eval_queries.json +30 -0
- package/packs/design/skills/marketing-flyer/evals/evals.json +18 -0
- package/packs/design/skills/marketing-flyer/examples/community-health-fair.md +68 -0
- package/packs/design/skills/marketing-flyer/manifest.json +39 -0
- package/packs/design/skills/marketing-flyer/reference.md +54 -0
- package/packs/design/skills/marketing-flyer/scripts/build_flyer.py +323 -0
- package/packs/design/skills/marketing-flyer/templates/flyer-spec.json +26 -0
- package/packs/stakeholder-comms/pack.json +1 -1
- package/profiles.json +1 -1
- /package/packs/{stakeholder-comms → design}/skills/deck-builder/evals/eval_queries.json +0 -0
- /package/packs/{stakeholder-comms → design}/skills/deck-builder/evals/evals.json +0 -0
- /package/packs/{stakeholder-comms → design}/skills/deck-builder/examples/exec-board-update.md +0 -0
- /package/packs/{stakeholder-comms → design}/skills/deck-builder/examples/templated-brand-deck.md +0 -0
- /package/packs/{stakeholder-comms → design}/skills/deck-builder/reference.md +0 -0
- /package/packs/{stakeholder-comms → design}/skills/deck-builder/requirements.txt +0 -0
- /package/packs/{stakeholder-comms → design}/skills/deck-builder/templates/palettes.json +0 -0
- /package/packs/{stakeholder-comms → design}/skills/slide-outliner/SKILL.md +0 -0
- /package/packs/{stakeholder-comms → design}/skills/slide-outliner/evals/eval_queries.json +0 -0
- /package/packs/{stakeholder-comms → design}/skills/slide-outliner/evals/evals.json +0 -0
- /package/packs/{stakeholder-comms → design}/skills/slide-outliner/manifest.json +0 -0
- /package/packs/{stakeholder-comms → design}/skills/slide-outliner/templates/deck-outline.md +0 -0
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/skilldrop-cli)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
|
|
6
|
-
**
|
|
6
|
+
**Portable AI-agent skills for the deliverables knowledge workers actually ship:** ADRs, design docs, PRDs, runbooks, threat models, decks, postmortems and adversarial reviews. Each one is a folder you copy into Claude Code, Cursor, Kiro, Codex or Copilot.
|
|
7
7
|
|
|
8
8
|
```text
|
|
9
9
|
messy input → a skill with a quality bar → a gate that can say no → your decision
|
|
@@ -19,7 +19,8 @@ Install one pack. Every role pack also brings `core` (intake, critique, review c
|
|
|
19
19
|
- **Architects:** `solution-architect` — diagrams, ADRs, design docs, API and data contracts, threat models. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/solution-architect/)
|
|
20
20
|
- **Software teams:** `dev-team` — story splitting, implementation with adversarial review, merge gates, launch readiness, release notes. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/dev-team/)
|
|
21
21
|
- **SRE and on-call:** `sre-oncall` — observability, runbooks, incident comms, postmortems, capacity. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/sre-oncall/)
|
|
22
|
-
- **Explaining things to decision-makers:** `stakeholder-comms` — audience profiles,
|
|
22
|
+
- **Explaining things to decision-makers:** `stakeholder-comms` — audience profiles, exec summaries, decision logs, guides. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/stakeholder-comms/)
|
|
23
|
+
- **On-brand decks and flyers:** `design` — capture your brand once, then build `.pptx` decks and print-ready flyers with your logo, colours and fonts. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/design/)
|
|
23
24
|
- **Adopting and building AI:** `ai-engineering` — readiness, use-case triage, policy, agent loops, budgets, agent threat models, evals. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/ai-engineering/)
|
|
24
25
|
- **Building on the Claude API:** `claude-api` — prompt caching, token budgets, eval generation, tool schemas. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/claude-api/)
|
|
25
26
|
- **Everyone:** `core` on its own. [Open pack](https://sananthanarayan.github.io/skilldrop/packs/core/)
|
package/catalogue.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "RFC-0034. The catalogue index: pack display order and the outcome browse axis (RFC-0026). Pack metadata lives in packs/<pack>/pack.json; membership is the folders — a skill is in a pack because it sits at packs/<pack>/skills/<name>/.",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
-
"packs": ["core", "solution-architect", "product-manager", "dev-team", "sre-oncall", "stakeholder-comms", "ai-engineering", "claude-api"],
|
|
4
|
+
"packs": ["core", "solution-architect", "product-manager", "dev-team", "sre-oncall", "stakeholder-comms", "design", "ai-engineering", "claude-api"],
|
|
5
5
|
"outcomes": {
|
|
6
6
|
"decide-what-to-build": {
|
|
7
|
+
"for": "Product managers · founders · strategists",
|
|
7
8
|
"description": "Turn a direction into a committed, measurable plan: press releases, strategy frameworks, OKRs, business cases, requirements, PRDs, and the metrics that will say whether it worked.",
|
|
8
9
|
"skills": [
|
|
9
10
|
"prfaq",
|
|
@@ -20,6 +21,7 @@
|
|
|
20
21
|
]
|
|
21
22
|
},
|
|
22
23
|
"design-the-system": {
|
|
24
|
+
"for": "Architects · tech leads",
|
|
23
25
|
"description": "Commit the shape before the code: decision records, design docs, diagrams, contracts, schemas, migration and threat models, and the design of any agentic parts.",
|
|
24
26
|
"skills": [
|
|
25
27
|
"adr-generator",
|
|
@@ -40,6 +42,7 @@
|
|
|
40
42
|
]
|
|
41
43
|
},
|
|
42
44
|
"build-and-review-software": {
|
|
45
|
+
"for": "Software teams · coding agents",
|
|
43
46
|
"description": "The loop around the code itself: supervised implementation, adversarial review panels, test plans, triage, accessibility and static-analysis passes, and the policy files agents read.",
|
|
44
47
|
"skills": [
|
|
45
48
|
"feature-implement-loop",
|
|
@@ -58,6 +61,7 @@
|
|
|
58
61
|
]
|
|
59
62
|
},
|
|
60
63
|
"build-on-the-claude-api": {
|
|
64
|
+
"for": "Teams building on the Anthropic API",
|
|
61
65
|
"description": "Skills for teams building directly on the Anthropic API — prompt caching strategy, token budgeting, eval generation, and tool-use schema writing.",
|
|
62
66
|
"skills": [
|
|
63
67
|
"prompt-caching-advisor",
|
|
@@ -67,6 +71,7 @@
|
|
|
67
71
|
]
|
|
68
72
|
},
|
|
69
73
|
"run-and-recover-the-service": {
|
|
74
|
+
"for": "SRE · on-call · platform teams",
|
|
70
75
|
"description": "Operate what shipped: runbooks, observability design, release notes, incident communication, and the postmortem that closes the loop.",
|
|
71
76
|
"skills": [
|
|
72
77
|
"runbook-generator",
|
|
@@ -78,6 +83,7 @@
|
|
|
78
83
|
]
|
|
79
84
|
},
|
|
80
85
|
"explain-it-to-decision-makers": {
|
|
86
|
+
"for": "Anyone presenting to leadership",
|
|
81
87
|
"description": "Get a non-technical audience to a decision: audience profiling, deck outlines and real decks, exec summaries, decision logs, and how-to guides.",
|
|
82
88
|
"skills": [
|
|
83
89
|
"audience-profile",
|
|
@@ -89,6 +95,7 @@
|
|
|
89
95
|
]
|
|
90
96
|
},
|
|
91
97
|
"govern-ai-use": {
|
|
98
|
+
"for": "AI enablement · engineering leaders · risk owners",
|
|
92
99
|
"description": "Adopt AI deliberately and prove what it is doing: readiness assessment, use-case triage, rollout plans, acceptable-use policy, adoption staging, and usage reporting.",
|
|
93
100
|
"skills": [
|
|
94
101
|
"ai-readiness-assessment",
|
|
@@ -99,7 +106,18 @@
|
|
|
99
106
|
"ai-usage-report"
|
|
100
107
|
]
|
|
101
108
|
},
|
|
109
|
+
"create-on-brand-collateral": {
|
|
110
|
+
"for": "Marketers · designers · anyone making a deck or flyer",
|
|
111
|
+
"description": "Make collateral that looks like it came from your team: capture the brand once, then build decks and print-ready flyers with your logo, colours and fonts.",
|
|
112
|
+
"skills": [
|
|
113
|
+
"brand-kit",
|
|
114
|
+
"deck-builder",
|
|
115
|
+
"marketing-flyer",
|
|
116
|
+
"slide-outliner"
|
|
117
|
+
]
|
|
118
|
+
},
|
|
102
119
|
"get-a-draft-ready-to-ship": {
|
|
120
|
+
"for": "Anyone shipping a document",
|
|
103
121
|
"description": "The passes either side of a generator: collect a messy input into a structured brief, critique the argument, and strip the machine artifacts before it leaves the building.",
|
|
104
122
|
"skills": [
|
|
105
123
|
"brief-intake",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"additionalProperties": false,
|
|
24
24
|
"required": ["description", "skills"],
|
|
25
25
|
"properties": {
|
|
26
|
+
"for": { "type": "string", "description": "Who this job belongs to, shown on the home page's outcome cards." },
|
|
26
27
|
"description": { "type": "string", "description": "The chip's tooltip on the catalogue site." },
|
|
27
28
|
"skills": { "type": "array", "items": { "type": "string" }, "minItems": 1 }
|
|
28
29
|
}
|
package/model-routing.json
CHANGED
|
@@ -150,6 +150,14 @@
|
|
|
150
150
|
"tier": "standard",
|
|
151
151
|
"rationale": "Checks evidence against a fixed checklist. Bounded synthesis, not adversarial review."
|
|
152
152
|
},
|
|
153
|
+
"brand-kit": {
|
|
154
|
+
"tier": "standard",
|
|
155
|
+
"rationale": "Extracts and normalises brand facts from files and pages, then runs a checker. Bounded synthesis."
|
|
156
|
+
},
|
|
157
|
+
"marketing-flyer": {
|
|
158
|
+
"tier": "standard",
|
|
159
|
+
"rationale": "Writes short copy to fit and fills a spec for a deterministic builder. Bounded generation."
|
|
160
|
+
},
|
|
153
161
|
"runbook-generator": {
|
|
154
162
|
"tier": "standard",
|
|
155
163
|
"rationale": "Operational doc from service facts. Bounded synthesis."
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skilldrop-cli",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.6",
|
|
4
4
|
"description": "Portable AI-agent skills for the deliverables knowledge workers ship \u2014 diagrams, ADRs, PRDs, runbooks, decks, reviews \u2014 installable into Claude Code, Cursor, Kiro, and any IDE that takes custom instructions. One command per skill or per role-based pack.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Sanjay Ananthanarayan",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "On-brand visual work: capture a brand once, then build real PowerPoint decks and print-ready marketing flyers in that brand, with logo, colours and fonts applied.",
|
|
3
|
+
"display_name": "Design",
|
|
4
|
+
"keywords": ["brand", "deck", "pptx", "flyer", "marketing", "logo"],
|
|
5
|
+
"links": {
|
|
6
|
+
"documentation": "https://sananthanarayan.github.io/skilldrop/packs/design/"
|
|
7
|
+
},
|
|
8
|
+
"maintainers": [
|
|
9
|
+
{
|
|
10
|
+
"name": "sananthanarayan"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"first-value": {
|
|
14
|
+
"audience-posture": "non-technical",
|
|
15
|
+
"prerequisites": ["Your logo as a PNG file, and your brand colours if you know them"],
|
|
16
|
+
"starter-task": "Capture your brand once, then make a flyer in it",
|
|
17
|
+
"starter-prompt": "Set up our brand kit from this logo (./brand/logo.png) and these colours: #0E5A46, #F2A541. Then make a Letter-size flyer for our community health fair on Saturday 14 November, 10am–2pm, at Riverside Park.",
|
|
18
|
+
"verification": "brand-kit writes brand.json and a one-page BRAND.md with contrast checked, and marketing-flyer writes flyer.html in your colours with your logo, one call to action, and only the facts you gave it.",
|
|
19
|
+
"recovery": "If the flyer comes out in default colours, check that marketing-flyer was given the brand.json path. If brand-kit does not activate, ask for it by name (\"use brand-kit\")."
|
|
20
|
+
},
|
|
21
|
+
"requires": ["core"]
|
|
22
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: brand-kit
|
|
3
|
+
description: Capture a brand once as a reusable brand.json — logo files (and an on-dark version), colour roles as hex codes, heading and body fonts, voice, imagery rules, a PowerPoint template, contact details and the legal footer — plus a one-page BRAND.md, with text contrast checked and every value traced to where it came from. Use when the user wants decks, flyers or documents in their branding, says "use our brand", "here's our logo and colours", "set up our brand kit", or hands over brand guidelines.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# brand-kit
|
|
7
|
+
|
|
8
|
+
You turn whatever the user has about their brand (logo files, a guidelines PDF, a website, a
|
|
9
|
+
few hex codes, "we use green") into one `brand.json` that other skills build from:
|
|
10
|
+
[`deck-builder`](../deck-builder/SKILL.md) for PowerPoint decks and
|
|
11
|
+
[`marketing-flyer`](../marketing-flyer/SKILL.md) for flyers. Capturing the brand once means
|
|
12
|
+
nobody answers the same questions for every deck, and the deck and the flyer match.
|
|
13
|
+
|
|
14
|
+
## How to respond
|
|
15
|
+
|
|
16
|
+
1. **Ask for everything in one message, and take what they already gave.** Never ask for
|
|
17
|
+
something the user already supplied.
|
|
18
|
+
|
|
19
|
+
> To set up your brand kit, send whatever you have. Anything you skip I'll either take from
|
|
20
|
+
> what you sent or leave for you to confirm:
|
|
21
|
+
> 1. **Brand name**, and a tagline if you use one
|
|
22
|
+
> 2. **Logo files.** The main logo, plus a white or light version for dark backgrounds if
|
|
23
|
+
> you have one. PNG is best; SVG works for flyers, but PowerPoint needs PNG.
|
|
24
|
+
> 3. **Colours** as hex codes (`#0E5A46`), or a guidelines PDF or website I can read them from
|
|
25
|
+
> 4. **Fonts** for headings and body text
|
|
26
|
+
> 5. **Voice:** how you sound, and words you always or never use
|
|
27
|
+
> 6. **Imagery:** the kind of photos or illustrations you use, and what to avoid
|
|
28
|
+
> 7. **A PowerPoint template** (`.potx` or `.pptx`) if your company has one
|
|
29
|
+
> 8. **Contact and legal:** website, email, phone, and any footer line such as "© 2026 …"
|
|
30
|
+
|
|
31
|
+
2. **Read the sources the user points to.** From a guidelines PDF or website, extract colour
|
|
32
|
+
hex codes, font names, logo usage rules and voice. Tag every value with where it came from
|
|
33
|
+
in `sources`: `[explicit]` when the source states it, `[inferred]` when you derived it (a
|
|
34
|
+
colour sampled from the logo, a tone read from the About page). Never present an inferred
|
|
35
|
+
value as the brand's own rule.
|
|
36
|
+
|
|
37
|
+
3. **Fill the five colour roles.** The roles are `primary` (main brand colour; slide title
|
|
38
|
+
bars, flyer bands), `secondary` (supporting), `accent` (highlights, calls to action),
|
|
39
|
+
`background` and `text`. If the user gave one or two colours, derive the rest and say which
|
|
40
|
+
roles you filled. Usually `background` is white or a near-white tint of the primary,
|
|
41
|
+
`text` is a near-black, and `secondary` is a lighter or darker step of the primary.
|
|
42
|
+
|
|
43
|
+
4. **Write the files** next to the logo files, so relative paths resolve:
|
|
44
|
+
- `brand.json`, in the shape of [`templates/brand.json`](templates/brand.json). Leave a
|
|
45
|
+
field out instead of guessing it.
|
|
46
|
+
- `BRAND.md`: one page with the name, colour swatches as a table (role, hex, use), fonts,
|
|
47
|
+
voice, imagery rules and logo rules, readable by a person who never opens the JSON.
|
|
48
|
+
|
|
49
|
+
5. **Check it.**
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Claude Code
|
|
53
|
+
python3 "${CLAUDE_SKILL_DIR}/scripts/check_brand.py" ./brand/brand.json
|
|
54
|
+
# Other IDEs (from the skill folder)
|
|
55
|
+
python3 scripts/check_brand.py ./brand/brand.json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
It fails on a malformed hex code, text-on-background contrast below 4.5:1, a missing logo
|
|
59
|
+
file or template. It warns when white text on the primary is hard to read, when the accent
|
|
60
|
+
is too light for text, when a logo is SVG or EPS, or when fonts aren't set. Fix the
|
|
61
|
+
failures. Report each warning with what it means for the deck or flyer.
|
|
62
|
+
|
|
63
|
+
6. **Hand off.** Tell the user the path to `brand.json` and that `deck-builder` and
|
|
64
|
+
`marketing-flyer` will use it: `build_deck.py --brand brand.json`, or the flyer spec's
|
|
65
|
+
`brand` field.
|
|
66
|
+
|
|
67
|
+
**Non-interactive runs** (subagent, CI, headless): never invent a brand colour, font or logo.
|
|
68
|
+
Use only what the input supplies, tag derived colours `[inferred]`, and list missing fields
|
|
69
|
+
at the top of the response. With no brand material at all, emit `BLOCKED: need at least a
|
|
70
|
+
brand name and either a logo file or one brand colour`.
|
|
71
|
+
|
|
72
|
+
## Useful references in this skill
|
|
73
|
+
|
|
74
|
+
- [`templates/brand.json`](templates/brand.json) — the full shape, with every field filled in for a sample brand
|
|
75
|
+
- [`scripts/check_brand.py`](scripts/check_brand.py) — the checker: hex format, contrast, logo files and formats, template
|
|
76
|
+
- [`examples/northwind-brand.md`](examples/northwind-brand.md) — worked example: a logo, two hex codes and a website become a brand kit
|
|
77
|
+
|
|
78
|
+
## Quality bar
|
|
79
|
+
|
|
80
|
+
- **Every colour is a hex code with a role.** "Our green" is not a brand colour; `#0E5A46` used for title bars is.
|
|
81
|
+
- **Text on background passes 4.5:1,** checked by the script rather than by eye.
|
|
82
|
+
- **Every value says where it came from,** and inferred values are marked as inferred.
|
|
83
|
+
- **Logo files are real paths that exist,** with a PNG for PowerPoint and an on-dark version when the brand has one.
|
|
84
|
+
- **Nothing is invented.** A field the user didn't supply and couldn't be read from their sources is left out and listed, not guessed.
|
|
85
|
+
- **BRAND.md fits on one page.** A person checks the brand from it without opening the JSON.
|
|
86
|
+
|
|
87
|
+
## When to use this skill
|
|
88
|
+
|
|
89
|
+
- ✅ Before the first branded deck or flyer, so both come out in the same brand
|
|
90
|
+
- ✅ The user hands over brand guidelines, a logo, or a website and asks for things "in our style"
|
|
91
|
+
- ✅ A brand has changed and the old `brand.json` needs updating
|
|
92
|
+
|
|
93
|
+
## When NOT to use this skill
|
|
94
|
+
|
|
95
|
+
- ❌ Designing a new brand from scratch: this captures a brand, it doesn't invent one
|
|
96
|
+
- ❌ Building the deck or flyer itself; use `deck-builder` or `marketing-flyer`
|
|
97
|
+
- ❌ A one-off document where the user only wants the default look
|
|
98
|
+
|
|
99
|
+
## Anti-patterns to avoid
|
|
100
|
+
|
|
101
|
+
- ❌ **Asking eight separate questions** instead of one message with everything.
|
|
102
|
+
- ❌ **Sampling a colour from a JPEG** and recording it as the official hex without the `[inferred]` tag.
|
|
103
|
+
- ❌ **Accepting an SVG logo for PowerPoint use** without saying a PNG is needed.
|
|
104
|
+
- ❌ **Picking a pale accent as the text colour** because it is "on brand". It fails contrast and nobody can read it.
|
|
105
|
+
- ❌ **Filling the voice section with adjectives** ("innovative, passionate"). Words to use and words to avoid are what a writer can act on.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"query": "Here's our logo and brand colours \u2014 set up a brand kit we can reuse",
|
|
4
|
+
"should_trigger": true
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"query": "Use our brand guidelines PDF so everything matches our style",
|
|
8
|
+
"should_trigger": true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"query": "Capture our fonts, colours and logo rules in one place",
|
|
12
|
+
"should_trigger": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"query": "Make our decks and flyers on-brand \u2014 start with the brand settings",
|
|
16
|
+
"should_trigger": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"query": "Build a PowerPoint deck for the board meeting",
|
|
20
|
+
"should_trigger": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"query": "Make a flyer for our open day",
|
|
24
|
+
"should_trigger": false
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"query": "Design a new logo for my startup",
|
|
28
|
+
"should_trigger": false
|
|
29
|
+
}
|
|
30
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "brand-kit",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "Set up our brand kit. Logo is ./brand/northwind-logo.png and there's a white version ./brand/northwind-logo-white.png. Our colours are #0E5A46 and #F2A541. We use Georgia for headings. Website is northwindhealth.example.",
|
|
7
|
+
"assertions": [
|
|
8
|
+
"Writes brand.json next to the logo files, with logo.primary and logo.on_dark set to the two supplied paths",
|
|
9
|
+
"colors.primary is #0E5A46 and colors.accent is #F2A541; secondary, background and text are filled and listed as derived",
|
|
10
|
+
"fonts.heading.family is Georgia; the body font is either asked for or marked as a default, not presented as the brand's",
|
|
11
|
+
"Every value has a source, with derived values tagged [inferred]",
|
|
12
|
+
"Runs check_brand.py and reports its contrast figures",
|
|
13
|
+
"Writes a one-page BRAND.md with a colour table (role, hex, use)",
|
|
14
|
+
"Invents no tagline, phone number, address or legal footer"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Worked example — a logo, two colours and a website become a brand kit
|
|
2
|
+
|
|
3
|
+
## Input given to the skill
|
|
4
|
+
|
|
5
|
+
> Set up our brand kit. Logo is `./brand/northwind-logo.png` and there's a white version
|
|
6
|
+
> `./brand/northwind-logo-white.png`. Our colours are `#0E5A46` and `#F2A541`. We use Georgia
|
|
7
|
+
> for headings. Website is northwindhealth.example.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
**Wrote** `./brand/brand.json` and `./brand/BRAND.md`.
|
|
12
|
+
|
|
13
|
+
**Filled for you, please confirm:** `secondary` `#3D7F6B` (a lighter step of your green),
|
|
14
|
+
`background` `#FFFFFF` and `text` `#1F2A28` (near-black with a green cast). Voice is read
|
|
15
|
+
from your About page and tagged `[inferred]`.
|
|
16
|
+
|
|
17
|
+
**Not set (nothing supplied):** body font, tagline, phone, address, legal footer, PowerPoint
|
|
18
|
+
template. Tell me your body font; until then decks and flyers use their defaults.
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
$ python3 scripts/check_brand.py ./brand/brand.json
|
|
22
|
+
text on background 14.79:1
|
|
23
|
+
white on primary 8.17:1
|
|
24
|
+
WARN accent on background is 2.05:1 — use the accent for shapes and rules, not text
|
|
25
|
+
WARN fonts.body is not set; generators fall back to their defaults
|
|
26
|
+
OK: brand.json — 0 failure(s), 2 warning(s)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### BRAND.md
|
|
30
|
+
|
|
31
|
+
| Role | Hex | Use |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| primary | `#0E5A46` | Slide title bars, flyer header band, buttons |
|
|
34
|
+
| secondary | `#3D7F6B` | Charts, secondary panels |
|
|
35
|
+
| accent | `#F2A541` | Call to action, highlights; shapes and rules, never body text |
|
|
36
|
+
| background | `#FFFFFF` | Page and slide background |
|
|
37
|
+
| text | `#1F2A28` | Body text |
|
|
38
|
+
|
|
39
|
+
- **Fonts:** headings Georgia (from you); body font not set yet
|
|
40
|
+
- **Logo:** full colour on white; the white version on the green. Never the full-colour logo on the green.
|
|
41
|
+
- **Voice** `[inferred]`: warm and plain, short sentences. Says "members", not "patients".
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
**Why this is a good output:** it uses every fact the user gave and invents none. It fills only
|
|
46
|
+
the colour roles a deck needs, says which ones it filled, and leaves the tagline and legal
|
|
47
|
+
footer empty rather than making them up. The checker's figures show white titles on the
|
|
48
|
+
green will read, and its accent warning is carried into BRAND.md as "never body text".
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "brand-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Capture a brand once as a reusable brand.json — logo files (and an on-dark version), colour roles as hex codes, heading and body fonts, voice, imagery rules, a PowerPoint template, contact details and the legal footer — plus a one-page BRAND.md, with text contrast checked and every value traced to where it came from. Use when the user wants decks, flyers or documents in their branding, says \"use our brand\", \"here's our logo and colours\", \"set up our brand kit\", or hands over brand guidelines.",
|
|
5
|
+
"entrypoint": "SKILL.md",
|
|
6
|
+
"deps": {
|
|
7
|
+
"npm": [],
|
|
8
|
+
"pip": []
|
|
9
|
+
},
|
|
10
|
+
"env": {
|
|
11
|
+
"required": [],
|
|
12
|
+
"optional": []
|
|
13
|
+
},
|
|
14
|
+
"related": [
|
|
15
|
+
"deck-builder",
|
|
16
|
+
"marketing-flyer"
|
|
17
|
+
],
|
|
18
|
+
"handoff": [
|
|
19
|
+
{
|
|
20
|
+
"to": "deck-builder",
|
|
21
|
+
"when": "the brand kit is written and the user wants a deck",
|
|
22
|
+
"purpose": "Build the PowerPoint deck in this brand: build_deck.py --brand brand.json.",
|
|
23
|
+
"fallback": "If deck-builder is absent, give the user the brand.json path and the five hex codes to paste into whatever deck tool they use."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"to": "marketing-flyer",
|
|
27
|
+
"when": "the brand kit is written and the user wants a flyer or one-page sheet",
|
|
28
|
+
"purpose": "Build a print-ready flyer in this brand from the flyer spec's brand field.",
|
|
29
|
+
"fallback": "If marketing-flyer is absent, give the user BRAND.md so a designer or tool can apply it by hand."
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"tags": [
|
|
33
|
+
"brand",
|
|
34
|
+
"logo",
|
|
35
|
+
"colours",
|
|
36
|
+
"fonts",
|
|
37
|
+
"design",
|
|
38
|
+
"style-guide"
|
|
39
|
+
],
|
|
40
|
+
"model": {
|
|
41
|
+
"tier": "standard",
|
|
42
|
+
"rationale": "Extracts and normalises brand facts from files and pages, then runs a checker. Bounded synthesis."
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Check a brand.json before anything is generated from it. Stdlib only.
|
|
3
|
+
|
|
4
|
+
Checks:
|
|
5
|
+
- every colour role is a 6-digit hex code
|
|
6
|
+
- text on background, and white on primary, reach WCAG AA contrast (4.5:1)
|
|
7
|
+
- each logo file exists, and is PNG or JPG (PowerPoint cannot place SVG or EPS)
|
|
8
|
+
- a referenced .pptx/.potx template exists
|
|
9
|
+
- heading and body fonts are named
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
python3 check_brand.py path/to/brand.json
|
|
13
|
+
Exit code 1 if any check fails; warnings alone exit 0.
|
|
14
|
+
"""
|
|
15
|
+
import json
|
|
16
|
+
import re
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
HEX = re.compile(r"^#[0-9A-Fa-f]{6}$")
|
|
21
|
+
ROLES = ("primary", "secondary", "accent", "background", "text")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def luminance(hex_str):
|
|
25
|
+
h = hex_str.lstrip("#")
|
|
26
|
+
def ch(v):
|
|
27
|
+
v = int(v, 16) / 255
|
|
28
|
+
return v / 12.92 if v <= 0.03928 else ((v + 0.055) / 1.055) ** 2.4
|
|
29
|
+
r, g, b = (ch(h[i:i + 2]) for i in (0, 2, 4))
|
|
30
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def contrast(a, b):
|
|
34
|
+
la, lb = sorted((luminance(a), luminance(b)), reverse=True)
|
|
35
|
+
return (la + 0.05) / (lb + 0.05)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def main(argv):
|
|
39
|
+
if len(argv) != 1:
|
|
40
|
+
print(__doc__)
|
|
41
|
+
return 2
|
|
42
|
+
path = Path(argv[0]).expanduser().resolve()
|
|
43
|
+
base = path.parent
|
|
44
|
+
try:
|
|
45
|
+
brand = json.loads(path.read_text())
|
|
46
|
+
except (OSError, json.JSONDecodeError) as e:
|
|
47
|
+
print(f"FAIL cannot read {path}: {e}")
|
|
48
|
+
return 1
|
|
49
|
+
fails, warns = [], []
|
|
50
|
+
|
|
51
|
+
colors = brand.get("colors") or {}
|
|
52
|
+
for role in ROLES:
|
|
53
|
+
v = colors.get(role)
|
|
54
|
+
if not v:
|
|
55
|
+
warns.append(f"colors.{role} is missing; the generators will derive it from the others")
|
|
56
|
+
elif not HEX.match(v):
|
|
57
|
+
fails.append(f"colors.{role} is {v!r}, not a 6-digit hex code like #1A2A6C")
|
|
58
|
+
for x in colors.get("extra") or []:
|
|
59
|
+
if not HEX.match(str(x.get("hex", ""))):
|
|
60
|
+
fails.append(f"colors.extra {x.get('name', '?')!r} has hex {x.get('hex')!r}")
|
|
61
|
+
if HEX.match(colors.get("text", "")) and HEX.match(colors.get("background", "")):
|
|
62
|
+
r = contrast(colors["text"], colors["background"])
|
|
63
|
+
if r < 4.5:
|
|
64
|
+
fails.append(f"text on background contrast is {r:.2f}:1, below 4.5:1")
|
|
65
|
+
print(f" text on background {r:5.2f}:1")
|
|
66
|
+
if HEX.match(colors.get("primary", "")):
|
|
67
|
+
r = contrast("#FFFFFF", colors["primary"])
|
|
68
|
+
msg = f"white text on primary is {r:.2f}:1"
|
|
69
|
+
if r < 4.5:
|
|
70
|
+
warns.append(msg + " — slide title bars and flyer bands will use dark text instead")
|
|
71
|
+
print(f" white on primary {r:5.2f}:1")
|
|
72
|
+
if HEX.match(colors.get("accent", "")) and HEX.match(colors.get("background", "")):
|
|
73
|
+
r = contrast(colors["accent"], colors["background"])
|
|
74
|
+
if r < 3:
|
|
75
|
+
warns.append(f"accent on background is {r:.2f}:1 — use the accent for shapes and rules, not text")
|
|
76
|
+
|
|
77
|
+
logo = brand.get("logo") or {}
|
|
78
|
+
if isinstance(logo, str):
|
|
79
|
+
logo = {"primary": logo}
|
|
80
|
+
if not logo.get("primary") and not logo.get("on_dark"):
|
|
81
|
+
warns.append("no logo file — decks and flyers will carry the brand name as text instead")
|
|
82
|
+
for field in ("primary", "on_dark", "mark"):
|
|
83
|
+
ref = logo.get(field)
|
|
84
|
+
if not ref:
|
|
85
|
+
continue
|
|
86
|
+
lp = (base / ref) if not Path(ref).is_absolute() else Path(ref)
|
|
87
|
+
if not lp.exists():
|
|
88
|
+
fails.append(f"logo.{field} {ref!r} does not exist (looked in {lp.parent})")
|
|
89
|
+
elif lp.suffix.lower() not in (".png", ".jpg", ".jpeg"):
|
|
90
|
+
warns.append(f"logo.{field} is {lp.suffix}: fine for the flyer, but PowerPoint needs PNG or JPG — export one")
|
|
91
|
+
|
|
92
|
+
tpl = (brand.get("templates") or {}).get("pptx")
|
|
93
|
+
if tpl:
|
|
94
|
+
tp = (base / tpl) if not Path(tpl).is_absolute() else Path(tpl)
|
|
95
|
+
if not tp.exists():
|
|
96
|
+
fails.append(f"templates.pptx {tpl!r} does not exist")
|
|
97
|
+
|
|
98
|
+
fonts = brand.get("fonts") or {}
|
|
99
|
+
for role in ("heading", "body"):
|
|
100
|
+
f = fonts.get(role)
|
|
101
|
+
fam = f.get("family") if isinstance(f, dict) else f
|
|
102
|
+
if not fam:
|
|
103
|
+
warns.append(f"fonts.{role} is not set; generators fall back to their defaults")
|
|
104
|
+
|
|
105
|
+
for w in warns:
|
|
106
|
+
print(f"WARN {w}")
|
|
107
|
+
for f in fails:
|
|
108
|
+
print(f"FAIL {f}")
|
|
109
|
+
print(f"{'FAILED' if fails else 'OK'}: {path.name} — {len(fails)} failure(s), {len(warns)} warning(s)")
|
|
110
|
+
return 1 if fails else 0
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if __name__ == "__main__":
|
|
114
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "brand-kit output. deck-builder and marketing-flyer read this file; any field left out is asked for or defaulted by them. Paths are relative to this file. Every value carries where it came from in `sources`.",
|
|
3
|
+
"name": "Northwind Health",
|
|
4
|
+
"tagline": "Care that comes to you",
|
|
5
|
+
"logo": {
|
|
6
|
+
"primary": "logo.png",
|
|
7
|
+
"on_dark": "logo-white.png",
|
|
8
|
+
"mark": "mark.png",
|
|
9
|
+
"notes": "Keep clear space equal to the height of the N on every side. Never place the full-colour logo on the green."
|
|
10
|
+
},
|
|
11
|
+
"colors": {
|
|
12
|
+
"primary": "#0E5A46",
|
|
13
|
+
"secondary": "#3D7F6B",
|
|
14
|
+
"accent": "#F2A541",
|
|
15
|
+
"background": "#FFFFFF",
|
|
16
|
+
"text": "#1F2A28",
|
|
17
|
+
"extra": [
|
|
18
|
+
{ "name": "Mist", "hex": "#E8F1EE", "use": "panel backgrounds" }
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"fonts": {
|
|
22
|
+
"heading": { "family": "Georgia", "fallback": "serif", "weight": 700 },
|
|
23
|
+
"body": { "family": "Arial", "fallback": "sans-serif", "weight": 400 }
|
|
24
|
+
},
|
|
25
|
+
"voice": {
|
|
26
|
+
"tone": "Warm, plain, confident. Short sentences.",
|
|
27
|
+
"use": ["members", "care team", "near you"],
|
|
28
|
+
"avoid": ["patients", "cutting-edge", "solutions"]
|
|
29
|
+
},
|
|
30
|
+
"imagery": {
|
|
31
|
+
"style": "Real people in daylight, community settings, no stock handshakes.",
|
|
32
|
+
"do": ["natural light", "diverse ages"],
|
|
33
|
+
"dont": ["clinical close-ups", "illustrated icons as hero images"]
|
|
34
|
+
},
|
|
35
|
+
"templates": {
|
|
36
|
+
"pptx": "northwind-master.potx"
|
|
37
|
+
},
|
|
38
|
+
"contact": {
|
|
39
|
+
"website": "northwindhealth.example",
|
|
40
|
+
"email": "hello@northwindhealth.example",
|
|
41
|
+
"phone": "",
|
|
42
|
+
"address": ""
|
|
43
|
+
},
|
|
44
|
+
"legal": {
|
|
45
|
+
"footer": "© 2026 Northwind Health",
|
|
46
|
+
"disclaimer": ""
|
|
47
|
+
},
|
|
48
|
+
"sources": {
|
|
49
|
+
"colors": "brand guidelines PDF, page 4 [explicit]",
|
|
50
|
+
"fonts": "brand guidelines PDF, page 6 [explicit]",
|
|
51
|
+
"voice": "website About page [inferred]",
|
|
52
|
+
"logo": "files supplied by the user [explicit]"
|
|
53
|
+
}
|
|
54
|
+
}
|