원클릭으로
new-tool
Scaffold a new tool page in dev.tools following the established pattern
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Scaffold a new tool page in dev.tools following the established pattern
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Add or update an app in the dev.tools software installer catalog
Add a prompt or skill to the dev.tools prompts collection (TypeScript catalog workflow)
Add a new tool page to dev.tools — covers ToolView, Editor, and Custom patterns
Internal dev.tools project conventions — state, styling, contexts, typing, and code style rules
Run the complete dev.tools pre-commit verification pipeline
Extend the LLM VRAM calculator — add quant families, update formulas, add test anchors
| name | new-tool |
| description | Scaffold a new tool page in dev.tools following the established pattern |
Use this skill whenever adding a new tool page to dev.tools.
src/common/<name>-utils.tsCreate a file with pure, testable functions. No React, no side effects.
export function myTransform(input: string): string {
return input; // implement
}
src/common/utils-factory.tsAdd two exports at the bottom of the file:
export function create<Name>Utils(): IStringUtil[] {
return [
{
toolId: '<name>-<action>',
textToDisplay: 'Human Readable Label',
toolFunction: (input: string) => myTransform(input),
},
];
}
export function create<Name>UtilList(): UtilList[] {
return [
{
toolGroupId: '<name>-group',
displayName: 'Group Display Name',
utils: create<Name>Utils(),
},
];
}
Import your new functions at the top of utils-factory.ts.
src/pages/<name>/index.tsxFollow this exact pattern (copy from src/pages/string-utils/index.tsx):
'use client';
import { create<Name>UtilList } from '@/common/utils-factory';
import { usePage } from '@/contexts/PageContext';
import ToolAbout from '@/controls/ToolAbout';
import React, { useEffect, useMemo } from 'react';
import ToolView, { ToolViewFunctionGroups, ToolViewGroup } from '../../components/elements/column/ToolView';
const IndexPage = (): React.JSX.Element => {
const { setPageTitle } = usePage();
useEffect(() => {
setPageTitle('<Page Title>');
}, [setPageTitle]);
const toolsGroups = useMemo(() => {
const groupsMap: ToolViewFunctionGroups = new Map();
create<Name>UtilList().forEach((tool) => {
const toolGroup: ToolViewGroup = {
funcGroupId: tool.toolGroupId,
funcGroupName: tool.displayName,
functions: tool.utils.map((func) => ({
funcId: func.toolId,
funcName: func.textToDisplay,
funcDescription: func.description,
func: (text, onSuccess, onFailure): void => {
try {
const result = func.toolFunction(text);
onSuccess(result);
} catch (e: unknown) {
onFailure(e);
}
},
})),
};
groupsMap.set(tool.toolGroupId, toolGroup);
});
return groupsMap;
}, []);
return (
<div style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0 }}>
<ToolAbout routeKey="<name>">One-paragraph description of what this tool does.</ToolAbout>
<ToolView searchable showCharCount toolChoseHeader="Select Utils" toolViewFunctionGroups={toolsGroups} />
</div>
);
};
export default IndexPage;
For async tools (hashing), wrap func.toolFunction in a .then(onSuccess).catch(onFailure) instead of try/catch — see src/pages/hashing-tools/index.tsx.
src/components/app-layout/ApplicationSidebar.tsxAdd an entry to the appropriate group's items array in the navGroups constant:
{ itemName: '<Display Name>', itemLink: '/<name>', icon: '?' },
Pick a single Unicode character for icon that visually relates to the tool. See existing entries in src/components/app-layout/ApplicationSidebar.tsx for examples.
test/common/<name>-utils.test.tsWrite Jest tests for every function in src/common/<name>-utils.ts:
import { myTransform } from '../../src/common/<name>-utils';
describe('<Name>Utils', () => {
describe('myTransform', () => {
it('handles normal input', () => {
expect(myTransform('hello')).toBe('hello');
});
it('handles empty string', () => {
expect(myTransform('')).toBe('');
});
});
});
test/pages/<name>.test.tsximport { render } from '@testing-library/react';
import IndexPage from '../../src/pages/<name>/index';
jest.mock('next/router', () => ({ useRouter: () => ({ pathname: '/<name>' }) }));
describe('<Name> page', () => {
it('renders without crashing', () => {
render(<IndexPage />);
expect(document.body).toBeTruthy();
});
});
npm run verify # format → lint → tests
npm run build # static export
npm run validate:sw # service worker precache covers the new route
npm run verify:ui # interactive Chrome check — 375/768/1280, light+dark
All four must exit 0 before the tool is considered done.
toolId, toolGroupId) must be kebab-case strings, unique across the app.textToDisplay is the user-visible label — use human-readable casing.utils-factory.ts, not in the page component.@/common/* maps to src/common/*.