Auric Artisan Plugins Developer Reference
Overview
Source-level reference for maintaining the Auric Artisan plugins suite. It covers the platform folders, manifests, host APIs, UI panels, parser and color math contracts, bot security, social publishing, build outputs and validation steps required before shipping plugin changes.
1. Architecture
+The plugins suite is not a monorepo package with one shared runtime. Each host has its own entry point and packaging model. The design goal is behavior parity rather than build-system centralization: every surface exposes WCAG and APCA contrast, practical color parsing, accessible palette support or vision simulation in the way its host expects.
| Family | Runtime | Primary host boundary |
|---|---|---|
| Design tools | Figma, Penpot, Sketch | Host document selection, fills, text layers, UI panel or native dialogs |
| Code editor | VS Code | Language activation, hover provider, document color provider, diagnostics |
| Launchers | Alfred, Raycast | Typed color arguments and copyable results |
| Chat and social | Cloudflare Workers | Signed HTTP requests, cron, webhooks and social APIs |
Prefer small, host-native changes. If a feature must span multiple plugins, update the shared parser and color math ports consistently and document any platform-specific deviations.
2. File map
+| Path | Role |
|---|---|
plugins/alfred/ |
Alfred workflow package, plist, Node script filter and CommonJS color helpers. |
plugins/bots/ |
Cloudflare Worker for Slack, Discord, health routes and Color of the Day social posting. |
plugins/figma/ |
Figma manifest, sandbox code, iframe UI, CSS and local UI color libraries. |
plugins/penpot/ |
Penpot manifest, plugin host script, iframe UI, CSS and local UI color libraries. |
plugins/raycast/ |
Raycast TypeScript command with local color parser and math ports. |
plugins/sketch/ |
Sketch plugin bundle, manifest, commands, shared helpers and pack scripts. |
plugins/vscode/ |
VS Code extension: extension.js, the engine in lib/, the
auric-artisan CLI in bin/, the split build in build/
and apps/, and tests in test/. |
4. Figma and Penpot
+
Figma and Penpot share the same user-facing panel structure: Audit, Palette, Fix and Vision.
Their host scripts differ because Figma uses figma.* APIs and Penpot uses
penpot.* APIs.
| Contract | Figma | Penpot |
|---|---|---|
| Manifest | plugins/figma/manifest.json |
plugins/penpot/manifest.json |
| Host entry | code.js |
plugin.js |
| UI entry | ui.html with event.data.pluginMessage |
ui.html with raw event.data |
| Panel size | 360 x 560 |
360 x 560 |
| Network | allowedDomains: ["none"] |
Local plugin UI and host APIs |
| Permissions | Figma editor type only | content:write, user:read |
Both hosts compute effective backgrounds by walking ancestors. Figma audits text plus selected fill/stroke UI pairs, while Penpot v1 focuses on text contrast and palette/fix operations for selected shapes.
5. Design panel message protocol
+| Message | Direction | Purpose |
|---|---|---|
init |
Host to UI | Initializes the panel and active tab. |
selectionchange |
Host to UI | Updates the selected node or shape count. |
audit |
UI to host | Runs the active selection audit. |
audit:result |
Host to UI | Returns issues and scanned counts. |
audit:outline |
UI to host | Draws temporary red dashed outlines for issue ids. |
audit:clearOutlines |
UI to host | Removes outline layers or shapes. |
audit:select |
UI to host | Selects the failing node or shape in the host editor. |
fix:one, fix:all |
UI to host | Nudges failing fills to the requested contrast target. |
palette:seedFromSelection |
UI to host | Returns the first selected fill as a seed color. |
palette:apply |
UI to host | Applies generated palette swatches to the current selection. |
vision:run |
UI to host | Collects unique fills and returns simulated swatches. |
close |
UI to host | Closes the plugin panel. |
Preserve message names when refactoring UI code. Existing handlers are direct string switches, so a renamed message silently breaks a panel action.
6. Sketch plugin
+
The Sketch bundle lives under
plugins/sketch/Auric Artisan.sketchplugin/Contents/Sketch/. The manifest declares
identifier com.auricartisan.sketch, version 0.1.0, compatible
version 94 and four menu commands.
| File | Responsibility |
|---|---|
audit.js |
Scans visible text layers, computes effective background and selects failures. |
fix.js |
Nudges failing text colors along Lab lightness until the target passes. |
palette.js |
Prompts for seed, background, harmony and target, then creates a swatch group. |
vision.js |
Duplicates selection to the right and applies CVD transforms to copied colors. |
shared.js |
Color math, Sketch layer helpers, background resolution and CVD transforms. |
Sketch commands are native-dialog oriented. Avoid introducing web UI assumptions into this bundle unless the host packaging and review flow are updated.
7. VS Code extension
+
plugins/vscode/package.json declares auric-artisan version
0.13.2, “Auric Artisan — Color, Accessibility & Code Health”, for
VS Code ^1.74.0. The extension is plain CommonJS with extension.js as its
entry and runs without a build step. It activates on the auricArtisanIssues view and on
CSS-family files plus JS, TS, React, HTML, Vue, Svelte, Astro, PHP, JSON, JSONC, Markdown and XML.
| File | Role |
|---|---|
extension.js |
Activation, hover and color providers, diagnostics, commands, the Studio, Overview and picker webviews, and the Issues tree. |
lib/color-core.js |
Color parsing, conversions, WCAG and APCA contrast, and color-vision simulation. |
lib/scanner.js |
Workspace scanning and extractPairs(), which reads color and background pairs
from each style scope. |
lib/a11y.js |
The WCAG rules (RULES: 62 rules across 28 success criteria), the profiles in
WCAG_PROFILES, scoring and the auric-disable comment parser. |
lib/codehealth.js |
The Code Health checks: secrets, security, risk, debug, TODO, merge conflicts and size. |
lib/health-report.js |
health.json, SARIF 2.1.0 and the trend history. |
lib/ai-remediation.js, lib/workspace-store.js |
The local remediation plan and the .auric-artisan data folder. |
bin/auric-artisan.js |
The headless CLI, auric-artisan scan [dir]. |
packages/data |
ARIA and WCAG reference data vendored from extension/packages/data;
npm run a11y:sync at the repository root regenerates it. |
build/build.mjs, apps/*/app.config.mjs |
The split build described below. |
hoverProviderparses the color token under the cursor and returns aMarkdownStringwith a data-URI swatch, values, nearest name and contrast tables.colorProvidersupplies VS Code's native color picker for non-CSS languages that lack VS Code's built-in color picker, whencolorPicker.modeisdecoratorsor the native hover picker is on.extractPairs()inlib/scanner.jsscans each style scope forcolor,background-colorand an opaque, non-gradientbackground.analyzeDocument()writes diagnostics under collectionauric-artisanwith codelow-contrast. Documents overMAX_DOC_BYTES = 1024 * 1024are skipped.- The activity bar container
auricArtisanholds three views: Overview (webviewauricArtisanHome), Accessibility Issues (treeauricArtisanIssues) and Color Picker (webviewauricArtisanPickerView, collapsed). - Keybindings:
Ctrl+Alt+C/Cmd+Alt+CrunsauricArtisan.pickColorandCtrl+Alt+A/Cmd+Alt+ArunsauricArtisan.inspectAccessibility, both when the editor has focus. - Workspace data goes to
.auric-artisan/(auricArtisan.data.folderName):scan-cache.json,settings.json, the health record and the remediation plan.
The 23 commands:
| Command | Title (category Auric Artisan) |
|---|---|
auricArtisan.openStudio |
Open Color & Accessibility Studio |
auricArtisan.scanProject |
Scan Project for Accessibility (Use Cache) |
auricArtisan.rescanProject |
Force Rescan Project and Refresh Cache |
auricArtisan.generateAiPlan |
Generate Agent-Ready Remediation Plan |
auricArtisan.projectHealthReport |
Generate Project Health Report (Color, A11y & Code Health) |
auricArtisan.writeHealthReport |
Write Health Record (health.json + SARIF) |
auricArtisan.clearScanCache |
Clear Workspace Scan Cache |
auricArtisan.openDataFolder |
Open Workspace Data Folder |
auricArtisan.searchIssues |
Search Accessibility Issues |
auricArtisan.groupIssues |
Group Accessibility Issues (Type / File / Severity) |
auricArtisan.openIssueDocs |
Open WCAG Documentation |
auricArtisan.openIssueInStudio |
Open Issue in Contrast Studio |
auricArtisan.clearIssueSearch |
Clear Accessibility Issue Search |
auricArtisan.generatePalette |
Generate Accessible Palette |
auricArtisan.checkContrast |
Check Contrast of Selection |
auricArtisan.fixAllContrast |
Fix All Contrast Issues in File |
auricArtisan.pickColor |
Pick / edit color |
auricArtisan.chooseColorPickerMode |
Choose Color Picker Mode |
auricArtisan.disableNativeColorPicker |
Disable native color picker (use Auric Artisan) |
auricArtisan.restoreNativeColorPicker |
Restore native color picker (use VS Code's) |
auricArtisan.refreshDiagnostics |
Refresh Contrast Diagnostics |
auricArtisan.chooseAccent |
Change Accent Color (Theme the Studio) |
auricArtisan.inspectAccessibility |
Inspect Accessibility of Element |
The 46 settings:
| Setting | Type | Default |
|---|---|---|
auricArtisan.appearance.accent |
string | gold |
auricArtisan.hover.enabled |
boolean | true |
auricArtisan.inspect.enabled |
boolean | true |
auricArtisan.inspect.onHover |
boolean | true |
auricArtisan.colorPicker.mode |
string: auric, decorators |
auric |
auricArtisan.colorPicker.nativeHoverPicker |
boolean | false |
auricArtisan.colorPicker.swatches |
boolean | true |
auricArtisan.colorPicker.clickAction |
string: inlinePicker, fullEditor, off |
inlinePicker |
auricArtisan.colorPicker.autoOpen |
boolean | false |
auricArtisan.colorPicker.inlineSwatches |
boolean | false |
auricArtisan.contrast.enabled |
boolean | true |
auricArtisan.contrast.standard |
string: wcag2, apca, both |
wcag2 |
auricArtisan.contrast.apcaThreshold |
number | 60 |
auricArtisan.contrast.threshold |
number | 4.5 |
auricArtisan.contrast.severity |
string: error, warning, information, hint |
warning |
auricArtisan.contrast.flagCvdRisk |
boolean | true |
auricArtisan.contrast.checkPageBackground |
boolean | true |
auricArtisan.a11y.enabled |
boolean | true |
auricArtisan.a11y.profile |
string: 2.0, 2.1, 2.2, 3.0-draft |
2.2 |
auricArtisan.codeHealth.enabled |
boolean | true |
auricArtisan.codeHealth.diagnostics |
boolean | true |
auricArtisan.codeHealth.todo |
boolean | true |
auricArtisan.codeHealth.debug |
boolean | true |
auricArtisan.codeHealth.secret |
boolean | true |
auricArtisan.codeHealth.conflict |
boolean | true |
auricArtisan.codeHealth.risk |
boolean | true |
auricArtisan.codeHealth.security |
boolean | true |
auricArtisan.codeHealth.customSecretPatterns |
array | none |
auricArtisan.codeHealth.size |
boolean | true |
auricArtisan.health.enabled |
boolean | true |
auricArtisan.health.writeOnScan |
boolean | true |
auricArtisan.health.formats |
array | json, sarif, history |
auricArtisan.health.fileName |
string | health.json |
auricArtisan.health.maxIssues |
number | 5000 |
auricArtisan.health.historyLimit |
number | 200 |
auricArtisan.data.enabled |
boolean | true |
auricArtisan.data.folderName |
string | .auric-artisan |
auricArtisan.scan.cache.enabled |
boolean | true |
auricArtisan.scan.cache.maxAgeMinutes |
number | 1440 |
auricArtisan.scan.live |
boolean | true |
auricArtisan.scan.liveDelayMs |
number | 700 |
auricArtisan.scan.autoScan |
boolean | false |
auricArtisan.scan.autoScanOnStartup |
boolean | false |
auricArtisan.scan.autoScanDelayMs |
number | 1800 |
auricArtisan.scan.maxFiles |
number | 4000 |
auricArtisan.scan.exclude |
string | **/{node_modules,dist,build,out,.git,vendor,coverage,.auric-artisan}/** |
Scripts in plugins/vscode/package.json: npm test runs
test/run-tests.js and test/build.test.js; npm run validate
runs test/validate.mjs; npm run verify runs both the validator and the
tests, as does vscode:prepublish; npm run package builds the VSIX with
vsce.
The CLI takes --json, --sarif, --baseline,
--write-baseline, --fail-on high|medium|low, --max-new,
--min-score, --profile, --threshold,
--no-code-health, --max-files (default 20000) and --quiet,
honours .auricignore, and exits 0 on a pass, 1 on a policy violation and 2 on a usage
error.
npm run build (or npm run vscode:build at the repository root) runs
build/build.mjs, which writes four extensions to dist/<app>/:
auric-color, auric-a11y, auric-codehealth and
auric-artisan, an Extension Pack that ships no code and installs the other three. Each
build rewrites the auricArtisan namespace into its own, for example
auricA11y.scanProject, because two installed extensions cannot own the same command
or setting id. The CHANGELOG lists this split as 1.0.0, unreleased; 0.13.2 ships as the single
extension above.
Keep diagnostic parsing deliberately conservative. False positives in source files become noisy very quickly, especially in generated CSS, theme files and documentation examples.
8. Alfred workflow
+
Alfred uses info.plist to wire the aa contrast script filter to
/usr/bin/env node contrast.js "$1". The script emits Alfred-shaped JSON
{ items } to stdout.
splitArgs()supports quoted segments and function-style colors with spaces.- Rows include ratio, APCA Lc, foreground HEX, background HEX and a full summary.
- Modifier metadata lets users copy a full summary from the ratio row.
pack.ps1andpack.shbuildAuric Artisan.alfredworkflow.
cd plugins/alfred
./pack.sh
9. Raycast extension
+
Raycast is a TypeScript React command package. package.json declares the
contrast command in view mode with required foreground and
background text arguments.
src/contrast.tsxrendersDetailwith markdown preview, metadata rows and copy actions.- Dependencies are
@raycast/apiand@raycast/utils. - Scripts include
ray develop,ray build -e dist,ray lintandray publish. - Color helper ports live under
src/lib/.
cd plugins/raycast
npm run dev
npm run build
npm run lint
10. Cloudflare worker bots
+
plugins/bots/src/index.js is the Worker entry. It routes Slack, Discord, social
preview, social publish, X account checks, robots.txt, security.txt and
health checks, and its scheduled handler runs the daily post.
| Route | Handler | Purpose |
|---|---|---|
POST /slack |
handleSlack |
Verifies Slack HMAC signature and returns Block Kit contrast output. |
POST /discord |
handleDiscord |
Verifies Discord Ed25519 signature, handles PING and slash commands. |
GET /social/color-of-day/preview |
handleColorOfTheDayPreview |
Returns post text and target list without publishing. |
POST /social/color-of-day |
handleColorOfTheDayPost |
Publishes to configured targets after secret validation. |
GET /social/x/verify |
handleXVerify |
Checks that the configured X credentials work and belong to
X_EXPECTED_USERNAME. Needs SOCIAL_POST_SECRET. |
POST /social/x/selftest |
handleXSelfTest |
Publishes a throwaway X post and deletes it; ?keep=1 keeps it. Needs
SOCIAL_POST_SECRET. |
GET /robots.txt |
Inline | Disallows all crawling of the Worker. |
GET /.well-known/security.txt, GET /security.txt |
Inline | Returns the security contact file. |
GET /, GET /health |
Inline health response | Returns a plain text OK response. |
Discord command registration is handled by register-discord-commands.js. It creates
command aa-contrast with one required string option named colors.
12. Environment variables
+| Variable | Used by |
|---|---|
SLACK_SIGNING_SECRET |
Slack request verification. |
DISCORD_PUBLIC_KEY |
Discord interaction signature verification. |
DISCORD_APPLICATION_ID, DISCORD_BOT_TOKEN |
Discord command registration. |
DISCORD_GUILD_ID |
Optional guild-scoped command registration for fast iteration. |
SOCIAL_POST_ENABLED |
Gate that must be enabled for non-dry-run social publishing. |
SOCIAL_POST_SECRET |
Manual publish authorization secret. |
SOCIAL_POST_DRY_RUN |
Forces social post preview behavior without publishing. |
COLOR_OF_DAY_SOURCE_URL, COLOR_OF_DAY_TIME_ZONE |
Daily color source and date selection. |
SOCIAL_SLACK_WEBHOOK_URL, SOCIAL_DISCORD_WEBHOOK_URL |
Webhook targets for social posting. |
MASTODON_INSTANCE_URL, MASTODON_ACCESS_TOKEN |
Mastodon social posting. |
SOCIAL_WEBHOOK_URL, SOCIAL_WEBHOOK_AUTHORIZATION |
Generic JSON webhook target. |
SLACK_WEBHOOK_URL, DISCORD_WEBHOOK_URL |
Used when the SOCIAL_ webhook variables are not set. |
MASTODON_VISIBILITY |
Mastodon post visibility; default public. |
SOCIAL_POST_HASHTAGS |
Hashtags added to each post. |
AURIC_BASE_URL |
Site base for the Color of the Day source and the explore link; default
https://auricartisan.com. |
X_CLIENT_ID, X_CLIENT_SECRET |
X OAuth 2.0 client. The secret can be empty for a native app. |
X_USER_ACCESS_TOKEN, X_REFRESH_TOKEN |
OAuth 2.0 user tokens written by npm run x:authorize. They seed the token
store on a first run; an access token alone works as a bearer token that cannot be
renewed. |
X_API_KEY, X_API_KEY_SECRET, X_ACCESS_TOKEN,
X_ACCESS_TOKEN_SECRET |
OAuth 1.0a user context, the alternative to OAuth 2.0. |
X_API_BASE_URL |
X API base; default https://api.x.com. |
X_EXPECTED_USERNAME |
The account the X checks expect; auricartisan in
wrangler.toml. |
X_TOKEN_KEY |
KV key for the stored OAuth 2.0 tokens; default x:oauth2:tokens. |
BOT_STATE (KV binding; X_TOKENS is accepted as a legacy
name) |
Keeps the rotating OAuth 2.0 tokens and the one-post-per-target-per-day log. Without it the Worker falls back to memory and loses a rotated token when the isolate recycles. |
wrangler.toml sets the non-secret values under [vars]:
SOCIAL_POST_ENABLED = "0", SOCIAL_POST_DRY_RUN = "1",
SOCIAL_POST_HASHTAGS, AURIC_BASE_URL,
COLOR_OF_DAY_SOURCE_URL, COLOR_OF_DAY_TIME_ZONE and
X_EXPECTED_USERNAME, so posting is off as committed. Everything else is a secret,
uploaded with wrangler secret put or npm run x:secrets.
13. Packaging
+| Platform | Command | Output |
|---|---|---|
| Alfred | plugins/alfred/pack.ps1 or pack.sh |
Auric Artisan.alfredworkflow |
| Sketch | plugins/sketch/pack.ps1 or pack.sh |
Auric Artisan.sketchplugin.zip |
| Raycast | npm run build |
dist Raycast build |
| VS Code | npm run package (vsce) |
auric-artisan-0.13.2.vsix |
| Bots | npm run deploy |
Cloudflare Worker deployment |
Figma and Penpot are source-folder plugins. Validate manifests and host loading directly before publishing or distributing store packages.
14. Security and privacy
+- Figma declares
networkAccess.allowedDomains = ["none"]; keep design-file work local unless product requirements change. - Penpot write permission is needed for outlines, fixes and palette application. Avoid widening permissions without release notes.
- Slack rejects unsigned or stale requests using HMAC-SHA256 verification and a five-minute replay window.
- Discord rejects unsigned interactions using Ed25519 verification over timestamp plus body.
- Social publishing requires
SOCIAL_POST_SECRETfor manual posts andSOCIAL_POST_ENABLED=1for non-dry-run publishing. - Generated design outlines should be removable and named with stable Auric Artisan prefixes.
- Do not add remote code execution paths to plugin UIs. Keep scripts local to the package.
15. Validation checklist
+- Parse every JSON manifest and package file in
plugins/. - Verify Figma menu commands:
audit,palette,fixandvision. - Verify Penpot permissions and UI script references.
- Verify Sketch manifest command identifiers and referenced scripts.
- Run Alfred contrast with HEX, RGB, HSL and named color inputs.
- Run Raycast build and lint when changing TypeScript or package metadata.
- Run VS Code hover, color provider and CSS-family diagnostics in representative files.
- Run bot tests and verify Slack and Discord signature paths with known test requests.
- Preview Color of the Day before enabling social publishing.
- Regenerate documentation discovery, feeds, sitemaps, PWA cache and search after docs changes.
node scripts/generate-discovery.mjs
node scripts/generate-pwa-cache-manifest.mjs
node search/client/build-index.js
npm test
For platform workflow instructions, see the Plugins User Guide.
11. Color Of The Day Social Publisher
+The social publisher reads
/js/components/color-of-the-day.js, extracts the public palette arrays, derives the mega palette, selects the daily color with date/time-zone logic and formats the social post.colorSourceUrl()defaults tohttps://auricartisan.complus the public color component path.getColorOfTheDayFromSource()parses source text and computes the daily color.buildColorOfTheDayPost()writes the public post body, RGB, HSL, explore URL and hashtags.collectTargets()supports Slack webhook, Discord webhook, Mastodon, X and generic JSON webhook targets.postColorOfTheDay()supports dry runs, enable gating, per-target posting and failure collection.The cron expression in
wrangler.tomlis30 3 * * *. Cloudflare runs cron in UTC, so this corresponds to 09:00 in Asia/Kolkata.