npx skillsauth add laststance/skills colorful-typeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
When running this skill in Codex, translate Claude Code-only primitives before acting: AskUserQuestion -> chat/request_user_input, TodoWrite -> update_plan, Task/TaskCreate/TeamCreate/SendMessage -> spawn_agent/send_input/wait_agent when available and allowed, and EnterPlanMode/ExitPlanMode -> a concise chat plan plus explicit approval.
Resolve Read/Write/Edit/Bash/WebSearch/WebFetch to Codex file/shell/web tools, and map ~/.claude/... paths to ~/.agents/... or ~/.codex/... unless the task explicitly targets Claude Code.
When running this skill in Cursor Agent, translate Claude Code-only primitives before acting: AskUserQuestion -> AskQuestion; TodoWrite -> Cursor TodoWrite or an equivalent checklist; Task/TaskCreate/TeamCreate/SendMessage/multi-agent flows -> Cursor Task (subagents), parallel Tasks, or run_in_background when allowed (TeamCreate/SendMessage may have no exact match); EnterPlanMode/ExitPlanMode -> Plan mode (SwitchMode / CreatePlan) plus explicit user approval.
Resolve Read/Write/Edit/StrReplace/Bash/web/search/MCP via Cursor Composer or Agent equivalents. MCP names written as mcp__server__tool typically map to call_mcp_tool with configured server identifiers. Map ~/.claude/... to ~/.cursor/skills/, .cursor/skills/, and .cursor/rules/ unless the task explicitly targets Claude Code.
Replace colorless primitives with domain-rich types. Every string answers: "string of WHAT?" Every number answers: "number of WHAT?"
TypeScript types are human-readable annotations. They communicate what domain concept a value represents, where it belongs (UI/logic/data/config), and what constraints apply.
string, number, boolean params that represent domain concepts (IDs, names, statuses, counts)ReturnType<typeof fn> or Parameters<typeof fn>[0] used where a named type should existidentity<T>, debounce, pipe) — these legitimately use primitives/generics| Target | Before (Colorless) | After (Colorful) | Priority |
|--------|-------------------|-------------------|----------|
| ID fields | id: string | id: UserId (branded) | HIGH |
| Status/enum | status: string | status: SymlinkStatus | HIGH |
| Domain strings | name: string | name: User['displayName'] | HIGH |
| Utility types | ReturnType<typeof getUser> | User | MEDIUM |
| Callbacks | (data: any) => void | (skill: Skill) => void | MEDIUM |
| Domain numbers | count: number | count: Agent['skillCount'] | MEDIUM |
| Booleans | isValid: boolean | isValid: Symlink['isValid'] | LOW |
i: number)<T>, <K extends string>)const sum: number = a + b)Launch 3 Explore subagents in parallel:
Agent A — Domain Type Inventory:
Find all type/interface definitions. List domain types with fields and JSDoc presence. Identify root entities vs derived types.
Agent B — Primitive Usage Map:
Search : string, : number, : boolean in function signatures, variable declarations, interface fields. EXCLUDE: type definition files themselves, generics, test files. Group by domain concept.
Agent C — Utility Type Audit:
Search ReturnType<, Parameters<, Awaited<, Partial<, Pick< and index access patterns. Identify which could be replaced with named types.
For each domain type definition:
// BEFORE
interface Skill {
name: string;
path: string;
version: number;
}
// AFTER
/**
* A reusable AI agent capability package containing a SKILL.md manifest.
* Symlinked into agent skill directories for cross-agent sharing.
* @example { name: "tdd-workflow", path: "~/.agents/skills/tdd-workflow", version: 2 }
*/
interface Skill {
/** Human-readable identifier matching the directory name. @example "tdd-workflow" */
name: string;
/** Absolute filesystem path to the skill directory. @example "~/.agents/skills/tdd-workflow" */
path: string;
/** Schema version of the SKILL.md manifest format (currently 1 or 2). */
version: number;
}
Every JSDoc includes: @description (domain meaning), @example (realistic value). Property-level JSDoc for each field.
// === Branded types — prevent mixing IDs across domains ===
type Brand<T, B extends string> = T & { readonly __brand: B };
type UserId = Brand<string, 'UserId'>;
type SkillId = Brand<string, 'SkillId'>;
type AgentId = Brand<string, 'AgentId'>;
type Timestamp = Brand<number, 'Timestamp'>;
// === Union types — finite domain values ===
type SymlinkStatus = 'valid' | 'broken' | 'missing';
type ThemeMode = 'light' | 'dark' | 'system';
// === Indexed access — "a field of a known entity" ===
type SkillName = Skill['name'];
type AgentDir = AgentConfig['dir'];
Decision rule:
UserId and SkillId)Replace all primitives in one pass, ordered by scope:
Rules:
UserId, SymlinkStatus)Skill['name'])as casts — fix the sourcepnpm typecheck # or tsc --noEmit — zero errors required
pnpm lint # no new warnings
Generate transformation report:
@description and @examplestring represents a domain concept (IDs, names, paths, statuses)number represents a domain quantity (counts, versions, timestamps)ReturnType<typeof fn> where a named type exists| Mistake | Fix |
|---------|-----|
| Replace ALL primitives including loop counters | Only replace at domain boundaries — leave generic computation alone |
| Create branded type for every single string field | Only brand when mixing is dangerous (IDs). Use index access for simple fields |
| Add as UserId casts everywhere | Create factory functions: const userId = (id: string): UserId => id as UserId |
| Modify runtime behavior while refactoring types | Type-only changes. If a test behavior changes, you went too far |
| Over-nest index access: Config['db']['host'] | Create named alias: type DbHost = Config['db']['host'] for readability |
| Skip JSDoc on "obvious" types | Domain meaning is never obvious to newcomers. Always document the WHY |
testing
Cited research briefs
development
Daily coding habit prompts JP
development
React core deep-dive JP
data-ai
Copy last agent reply