template-renderer について
template-renderer は、仕様書・計画書・タスクのテンプレートを値で埋めるスキルです。Markdown 文書を生成するワークフロー向けに、トークン、パス、スキーマを検証します。
主な機能
- 01仕様書・計画書・タスクテンプレートのレンダリング
- 02{{TOKEN}} プレースホルダーの置換
- 03トークンの許可リストとサニタイズ
- 04テンプレートと出力パスの検証
- 05仕様書スキーマの検査
- 06不足・未使用トークンの通知
活用シーン
- 01収集した要件から仕様書を生成
- 02トークン値を使ったプロジェクト計画の作成
- 03検証済みテンプレートデータによるタスク文書の作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ oimiragieo/ agent-studio --skill template-rendererインストール後、Claude Code で/template-rendererを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
commands/template-renderer.mdhooks/post-execute.cjspre-execute.cjsreferences/research-requirements.mdrules/template-renderer.mdschemas/input.schema.jsonoutput.schema.jsonscripts/main.cjstemplates/implementation-template.md詳細
テンプレートレンダラー
Template Renderer スキル - {{TOKEN}} プレースホルダーを実際の値に置き換えてテンプレートをレンダリングします。schema 検証とセキュリティ制御(SEC-SPEC-003、SEC-SPEC-004)により、specification-template.md、plan-template.md、tasks-template.md をサポートします。 - 3 種類すべてのテンプレートをレンダリング(仕様、計画、タスク) - {{TOKEN}} → 値の置換によるトークン置換 - セキュリティ:トークン値のサニタイズ(インジェクションを防止) - セキュリティ:トークンの許可リスト適用(事前定義されたトークンのみ許可) - セキュリティ:テンプレートパスの検証(PROJECT_ROOT のみ) - 仕様テンプレートのスキーマ検証 - 必須トークンが不足している場合のエラー処理 - 未使用トークンの警告システム - Markdown の書式と構造を保持ステップ 1:入力の検証(セキュリティ - 必須)
テンプレートパスの検証(SEC-SPEC-002):
- テンプレートファイルが PROJECT_ROOT 内に存在することを確認します
- パストラバーサルの試み(../)を拒否します
.claude/templates/内のテンプレートのみを許可します
トークン許可リストの検証(SEC-SPEC-003):
// Allowed tokens by template type
const SPEC_TOKENS = [
'FEATURE_NAME',
'VERSION',
'AUTHOR',
'DATE',
'STATUS',
'ACCEPTANCE_CRITERIA_1',
'ACCEPTANCE_CRITERIA_2',
'ACCEPTANCE_CRITERIA_3',
'TERM_1',
'TERM_2',
'TERM_3',
'HTTP_METHOD',
'ENDPOINT_PATH',
'PROJECT_NAME',
];
const PLAN_TOKENS = [
'PLAN_TITLE',
'DATE',
'FRAMEWORK_VERSION',
'STATUS',
'EXECUTIVE_SUMMARY',
'TOTAL_TASKS',
'FEATURES_COUNT',
'ESTIMATED_TIME',
'STRATEGY',
'KEY_DELIVERABLES_LIST',
'PHASE_N_NAME',
'PHASE_N_PURPOSE',
'PHASE_N_DURATION',
'DEPENDENCIES',
'PARALLEL_OK',
'VERIFICATION_COMMANDS',
];
const TASKS_TOKENS = [
'FEATURE_NAME',
'VERSION',
'AUTHOR',
'DATE',
'STATUS',
'PRIORITY',
'ESTIMATED_EFFORT',
'RELATED_SPECS',
'DEPENDENCIES',
'FEATURE_DISPLAY_NAME',
'FEATURE_DESCRIPTION',
'BUSINESS_VALUE',
'USER_IMPACT',
'EPIC_NAME',
'EPIC_GOAL',
'SUCCESS_CRITERIA',
];
トークン値のサニタイズ(SEC-SPEC-004):
function sanitizeTokenValue(value) {
return String(value)
.replace(/[<>]/g, '') // Prevent HTML injection
.replace(/\$\{/g, '') // Prevent template literal injection
.replace(/\{\{/g, '') // Prevent nested token injection
.trim();
}
ステップ 2:テンプレートの読み込み
Read または mcpfilesystemread_text_file を使用してテンプレートファイルを読み込みます:
.claude/templates/specification-template.md(46 個のトークン).claude/templates/plan-template.md(30 個以上のトークン).claude/templates/tasks-template.md(20 個以上のトークン)
ステップ 3:トークンの置換
すべての {{TOKEN}} プレースホルダーをサニタイズ済みの値に置き換えます:
function renderTemplate(templateContent, tokenMap) {
let rendered = templateContent;
// Replace each token
for (const [token, value] of Object.entries(tokenMap)) {
// Validate token is in whitelist
if (!isAllowedToken(token, templateType)) {
throw new Error(`Token not in whitelist: ${token}`);
}
// Sanitize value
const sanitizedValue = sanitizeTokenValue(value);
// Replace all occurrences
const regex = new RegExp(`\\{\\{${token}\\}\\}`, 'g');
rendered = rendered.replace(regex, sanitizedValue);
}
// Check for missing required tokens
const missingTokens = rendered.match(/\{\{[A-Z_0-9]+\}\}/g);
if (missingTokens) {
throw new Error(`Missing required tokens: ${missingTokens.join(', ')}`);
}
return rendered;
}
ステップ 4:スキーマ検証(仕様テンプレートのみ)
仕様テンプレートの場合、レンダリングされた出力を JSON Schema に照らして検証します:
// Extract YAML frontmatter
const yamlMatch = rendered.match(/^---\n([\s\S]*?)\n---/);
if (!yamlMatch) {
throw new Error('No YAML frontmatter found');
}
// Parse YAML
const yaml = require('js-yaml');
const frontmatter = yaml.load(yamlMatch[1]);
// Validate against schema
const schema = JSON.parse(
fs.readFileSync('.claude/schemas/specification-template.schema.json', 'utf8')
);
const Ajv = require('ajv');
const ajv = new Ajv();
const validate = ajv.compile(schema);
if (!validate(frontmatter)) {
throw new Error(`Schema validation failed: ${JSON.stringify(validate.errors)}`);
}
ステップ 5:出力の書き込み
Write または mcpfilesystemwrite_file を使用して、レンダリングされたテンプレートを出力パスに書き込みます:
- 出力パスが PROJECT_ROOT 内にあることを確認します
- 必要に応じて親ディレクトリを作成します
- UTF-8 エンコーディングでファイルを書き込みます
ステップ 6:検証
レンダリング後のチェックを実行します:
# Check no unresolved tokens remain
grep "{{" <output-file> && echo "ERROR: Unresolved tokens found!" || echo "✓ All tokens resolved"
# For specifications: Validate YAML frontmatter
head -50 <output-file> | grep -E "^---$" | wc -l # Should output: 2
# For specifications: Validate against schema (if ajv installed)
# ajv validate -s .claude/schemas/specification-template.schema.json -d <output-file>
</execution_process>
<best_practices>
- テンプレートパスは必ず検証する:読み込み前に PROJECT_ROOT 検証を使用します
- すべてのトークン値をサニタイズする:インジェクション攻撃を防止します(SEC-SPEC-004)
- トークンの許可リストを適用する:事前定義されたトークンのみを許可します(SEC-SPEC-003)
- トークン不足時はエラーにする:必須トークンの不足を黙って無視しないでください
- 未使用トークンを警告する:トークン名の誤入力に気づけるようにします
- Markdown の書式を保持する:インデント、箇条書き、コードブロックを変更しないでください
- 仕様のスキーマを検証する:仕様テンプレートに対して JSON Schema 検証を実行します
- すべての操作を記録する:テンプレート、使用したトークン、出力パスをメモリに記録します
</best_practices>
<error_handling>
必須トークンの不足:
ERROR: Missing required tokens in template:
- {{FEATURE_NAME}}
- {{ACCEPTANCE_CRITERIA_1}}
Provide these tokens in the token map.
無効なトークン(許可リストにない):
ERROR: Token not in whitelist: INVALID_TOKEN
Allowed tokens for specification-template: FEATURE_NAME, VERSION, AUTHOR, DATE, ...
テンプレートパスのトラバーサル:
ERROR: Template path outside PROJECT_ROOT
Path: ../../etc/passwd
Only templates from .claude/templates/ are allowed.
スキーマ検証の失敗(仕様テンプレート):
ERROR: Schema validation failed:
- /version: must match pattern "^\d+\.\d+\.\d+$"
- /acceptance_criteria: must have at least 1 item
未使用トークンの警告:
WARNING: Unused tokens provided:
- EXTRA_TOKEN_1
- EXTRA_TOKEN_2
These tokens are not in the template. Check for typos.
</error_handling>
**例 1:仕様テンプレートのレンダリング**// From another skill (e.g., spec-gathering)
Skill({
skill: 'template-renderer',
args: {
templateName: 'specification-template',
outputPath: '.claude/context/artifacts/specifications/my-feature-spec.md',
tokens: {
FEATURE_NAME: 'User Authentication',
VERSION: '1.0.0',
AUTHOR: 'Claude',
DATE: '2026-01-28',
STATUS: 'draft',
ACCEPTANCE_CRITERIA_1: 'User can log in with email and password',
ACCEPTANCE_CRITERIA_2: 'Password meets complexity requirements',
ACCEPTANCE_CRITERIA_3: 'Failed login attempts are logged',
},
},
});
例 2:計画テンプレートのレンダリング
Skill({
skill: 'template-renderer',
args: {
templateName: 'plan-template',
outputPath: '.claude/context/plans/my-feature-plan.md',
tokens: {
PLAN_TITLE: 'User Authentication Implementation Plan',
DATE: '2026-01-28',
FRAMEWORK_VERSION: 'Agent-Studio v3.1.0',
STATUS: 'Phase 0 - Research',
EXECUTIVE_SUMMARY: 'Implementation plan for JWT-based authentication...',
TOTAL_TASKS: '14 atomic tasks',
ESTIMATED_TIME: '2-3 weeks',
STRATEGY: 'Foundation-first (schema) → Core features',
},
},
});
例 3:タスクテンプレートのレンダリング
Skill({
skill: 'template-renderer',
args: {
templateName: 'tasks-template',
outputPath: '.claude/context/artifacts/tasks/auth-tasks.md',
tokens: {
FEATURE_NAME: 'user-authentication',
VERSION: '1.0.0',
AUTHOR: 'Engineering Team',
DATE: '2026-01-28',
FEATURE_DISPLAY_NAME: 'User Authentication',
FEATURE_DESCRIPTION: 'JWT-based authentication system',
BUSINESS_VALUE: 'Enables user account management',
USER_IMPACT: 'Users can securely access personalized features',
},
},
});
例 4:CLI の使用方法
# Using CLI wrapper (after implementation in main.cjs)
node .claude/skills/template-renderer/scripts/main.cjs \
--template specification-template \
--output ./my-spec.md \
--tokens '{"FEATURE_NAME":"My Feature","VERSION":"1.0.0","AUTHOR":"Claude","DATE":"2026-01-28"}'
# Or with JSON file
node .claude/skills/template-renderer/scripts/main.cjs \
--template plan-template \
--output ./my-plan.md \
--tokens-file ./tokens.json
例 5:spec-gathering との統合
// In spec-gathering skill (Task #16):
// After collecting requirements via progressive disclosure...
const tokens = {
FEATURE_NAME: gatheredRequirements.featureName,
VERSION: '1.0.0',
AUTHOR: 'Claude',
DATE: new Date().toISOString().split('T')[0],
ACCEPTANCE_CRITERIA_1: gatheredRequirements.criteria[0],
ACCEPTANCE_CRITERIA_2: gatheredRequirements.criteria[1],
ACCEPTANCE_CRITERIA_3: gatheredRequirements.criteria[2],
// ... more tokens
};
Skill({
skill: 'template-renderer',
args: {
templateName: 'specification-template',
outputPath: `.claude/context/artifacts/specifications/${featureName}-spec.md`,
tokens: tokens,
},
});
</usage_example>
メモリプロトコル(必須)
開始前:
cat .claude/context/memory/learnings.md
完了後:
- 新しいパターン ->
.claude/context/memory/learnings.md - 問題の発見 ->
.claude/context/memory/issues.md - 決定事項 ->
.claude/context/memory/decisions.md
中断を想定してください:コンテキストがリセットされる場合があります。メモリに記録されていなければ、実行されていないものとみなされます。