ワンクリックで
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/*.