@taskclan/achilleon 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -3
- package/dist/index.cjs +20 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.mjs +27 -1
- package/dist/prompts.json +193 -0
- package/dist/registry.json +193 -0
- package/package.json +5 -1
- package/prompts/classify.yml +32 -0
- package/prompts/extract.yml +36 -0
- package/prompts/judge.yml +44 -0
- package/prompts/refine.yml +37 -0
- package/prompts/summarize.yml +32 -0
- package/prompts/translate.yml +31 -0
- package/schema/prompt.schema.json +84 -0
package/README.md
CHANGED
|
@@ -10,9 +10,9 @@ Three kinds of entries live in this repo:
|
|
|
10
10
|
|
|
11
11
|
| Kind | What it is | Where it runs |
|
|
12
12
|
|---|---|---|
|
|
13
|
-
| **Skill** | A single slash command with a fixed system prompt and tier binding | Inside `@taskclan` on the [VS Code extension](https://marketplace.visualstudio.com/items?itemName=taskclan.taskclan-intelligence)
|
|
14
|
-
| **Agent** | A named chat participant with a locked personality (`@taskclan-reviewer`, `@taskclan-guru`, ...) | VS Code chat |
|
|
15
|
-
| **Prompt** | A parameterised
|
|
13
|
+
| **Skill** | A single slash command with a fixed system prompt and tier binding | Inside `@taskclan` on the [VS Code extension](https://marketplace.visualstudio.com/items?itemName=taskclan.taskclan-intelligence), Cursor / Continue / Claude Code (via `dist/*` bundles), or anywhere else you can paste a prompt |
|
|
14
|
+
| **Agent** | A named chat participant with a locked personality (`@taskclan-reviewer`, `@taskclan-guru`, ...) | VS Code chat via the extension; also exportable as Cursor / Continue slash commands |
|
|
15
|
+
| **Prompt** | A parameterised template with `{{variables}}` — you fill in values at call time | Any SDK consumer via `render()` from `@taskclan/achilleon`. Ships with helpers for `summarize`, `translate`, `extract`, `classify`, `judge`, `refine`. |
|
|
16
16
|
|
|
17
17
|
## Directory shape
|
|
18
18
|
|
|
@@ -110,6 +110,44 @@ Skills are also emitted as plain markdown you can paste into any system-prompt /
|
|
|
110
110
|
# Or grab one
|
|
111
111
|
curl -O https://raw.githubusercontent.com/taskclan/achilleon/main/dist/raw/debug.md
|
|
112
112
|
|
|
113
|
+
### npm — for SDK / tooling authors
|
|
114
|
+
|
|
115
|
+
If you are building your own tool and want the registry as typed data:
|
|
116
|
+
|
|
117
|
+
npm install @taskclan/achilleon
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { skills, agents, prompts, render, getSkill, byTier, categories } from '@taskclan/achilleon';
|
|
121
|
+
|
|
122
|
+
// Every skill and agent, typed.
|
|
123
|
+
for (const s of skills) {
|
|
124
|
+
console.log(s.id, s.tier, s.description);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// One entry by id.
|
|
128
|
+
const debug = getSkill('debug');
|
|
129
|
+
console.log(debug?.system);
|
|
130
|
+
|
|
131
|
+
// Group by tier.
|
|
132
|
+
const heavyReasoners = byTier('t1-max');
|
|
133
|
+
|
|
134
|
+
// Render a parameterised prompt template.
|
|
135
|
+
const filled = render('summarize', {
|
|
136
|
+
text: articleBody,
|
|
137
|
+
length: '5 bullets',
|
|
138
|
+
});
|
|
139
|
+
// filled is now a full prompt string — hand it to any LLM.
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
CJS also works: `const { skills } = require('@taskclan/achilleon')`.
|
|
143
|
+
|
|
144
|
+
Raw JSON is also directly importable:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
import registry from '@taskclan/achilleon/registry';
|
|
148
|
+
// { skills: AchilleonSkill[], agents: AchilleonAgent[] }
|
|
149
|
+
```
|
|
150
|
+
|
|
113
151
|
### Taskclan Intelligence VS Code extension (first-party)
|
|
114
152
|
|
|
115
153
|
If you install [`taskclan.taskclan-intelligence`](https://marketplace.visualstudio.com/items?itemName=taskclan.taskclan-intelligence) from the VS Code Marketplace, you get every skill wired as `@taskclan /<name>` with T1 routing baked in. The extension pulls Achilleon at build time so new entries land in the next release automatically.
|
package/dist/index.cjs
CHANGED
|
@@ -5,15 +5,35 @@ const registry = JSON.parse(readFileSync(join(__dirname, 'registry.json'), 'utf8
|
|
|
5
5
|
|
|
6
6
|
const skills = registry.skills;
|
|
7
7
|
const agents = registry.agents;
|
|
8
|
+
const prompts = registry.prompts;
|
|
8
9
|
const entries = [...registry.agents, ...registry.skills];
|
|
9
10
|
|
|
11
|
+
function _render(id, values, prompts) {
|
|
12
|
+
const p = prompts.find((x) => x.id === id);
|
|
13
|
+
if (!p) throw new Error('achilleon: prompt "' + id + '" not found');
|
|
14
|
+
const provided = values || {};
|
|
15
|
+
const used = new Set();
|
|
16
|
+
const output = p.template.replace(/\{\{\s*([a-z][a-z_0-9]{0,39})\s*\}\}/g, (_, name) => {
|
|
17
|
+
used.add(name);
|
|
18
|
+
if (provided[name] !== undefined && provided[name] !== null) return String(provided[name]);
|
|
19
|
+
const varDef = (p.variables || []).find((v) => v.name === name);
|
|
20
|
+
if (varDef && varDef.default !== undefined) return varDef.default;
|
|
21
|
+
if (varDef && varDef.required === false) return '';
|
|
22
|
+
throw new Error('achilleon: prompt "' + id + '" missing required variable "' + name + '"');
|
|
23
|
+
});
|
|
24
|
+
return output;
|
|
25
|
+
}
|
|
26
|
+
|
|
10
27
|
module.exports = {
|
|
11
28
|
skills,
|
|
12
29
|
agents,
|
|
30
|
+
prompts,
|
|
13
31
|
entries,
|
|
14
32
|
getSkill: (id) => skills.find((s) => s.id === id),
|
|
15
33
|
getAgent: (id) => agents.find((a) => a.id === id),
|
|
16
34
|
getEntry: (id) => entries.find((e) => e.id === id),
|
|
35
|
+
getPrompt: (id) => prompts.find((p) => p.id === id),
|
|
17
36
|
categories: () => [...new Set(skills.map((s) => s.category))].sort(),
|
|
18
37
|
byTier: (tier) => entries.filter((e) => e.tier === tier),
|
|
38
|
+
render: (id, values) => _render(id, values, prompts),
|
|
19
39
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -44,13 +44,44 @@ export interface AchilleonAgent {
|
|
|
44
44
|
|
|
45
45
|
export type AchilleonEntry = AchilleonSkill | AchilleonAgent;
|
|
46
46
|
|
|
47
|
+
export interface AchilleonPromptVariable {
|
|
48
|
+
name: string;
|
|
49
|
+
description: string;
|
|
50
|
+
required?: boolean;
|
|
51
|
+
default?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface AchilleonPrompt {
|
|
55
|
+
kind: 'prompt';
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
description: string;
|
|
59
|
+
template: string;
|
|
60
|
+
variables?: AchilleonPromptVariable[];
|
|
61
|
+
tier?: SkillTier;
|
|
62
|
+
author?: string;
|
|
63
|
+
version?: string;
|
|
64
|
+
tags?: string[];
|
|
65
|
+
}
|
|
66
|
+
|
|
47
67
|
export const skills: AchilleonSkill[];
|
|
48
68
|
export const agents: AchilleonAgent[];
|
|
69
|
+
export const prompts: AchilleonPrompt[];
|
|
49
70
|
/** Agents first, then skills, in the order they were loaded. */
|
|
50
71
|
export const entries: AchilleonEntry[];
|
|
51
72
|
|
|
52
73
|
export function getSkill(id: string): AchilleonSkill | undefined;
|
|
53
74
|
export function getAgent(id: string): AchilleonAgent | undefined;
|
|
54
75
|
export function getEntry(id: string): AchilleonEntry | undefined;
|
|
76
|
+
export function getPrompt(id: string): AchilleonPrompt | undefined;
|
|
55
77
|
export function categories(): SkillCategory[];
|
|
56
78
|
export function byTier(tier: SkillTier): AchilleonEntry[];
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Render a prompt template with values. Missing required variables throw;
|
|
82
|
+
* missing optional variables substitute the empty string.
|
|
83
|
+
*
|
|
84
|
+
* import { render } from '@taskclan/achilleon';
|
|
85
|
+
* const filled = render('summarize', { text: articleBody, length: '5 bullets' });
|
|
86
|
+
*/
|
|
87
|
+
export function render(id: string, values: Record<string, string | number | boolean>): string;
|
package/dist/index.mjs
CHANGED
|
@@ -4,11 +4,12 @@ import { dirname, join } from 'node:path';
|
|
|
4
4
|
|
|
5
5
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
6
6
|
|
|
7
|
-
/** @type {{ skills: any[], agents: any[] }} */
|
|
7
|
+
/** @type {{ skills: any[], agents: any[], prompts: any[] }} */
|
|
8
8
|
const registry = JSON.parse(readFileSync(join(HERE, 'registry.json'), 'utf8'));
|
|
9
9
|
|
|
10
10
|
export const skills = registry.skills;
|
|
11
11
|
export const agents = registry.agents;
|
|
12
|
+
export const prompts = registry.prompts;
|
|
12
13
|
export const entries = [...registry.agents, ...registry.skills];
|
|
13
14
|
|
|
14
15
|
export function getSkill(id) {
|
|
@@ -23,6 +24,10 @@ export function getEntry(id) {
|
|
|
23
24
|
return entries.find((e) => e.id === id);
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
export function getPrompt(id) {
|
|
28
|
+
return prompts.find((p) => p.id === id);
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
/** All skill categories, sorted, unique. */
|
|
27
32
|
export function categories() {
|
|
28
33
|
return [...new Set(skills.map((s) => s.category))].sort();
|
|
@@ -32,3 +37,24 @@ export function categories() {
|
|
|
32
37
|
export function byTier(tier) {
|
|
33
38
|
return entries.filter((e) => e.tier === tier);
|
|
34
39
|
}
|
|
40
|
+
|
|
41
|
+
function _render(id, values, prompts) {
|
|
42
|
+
const p = prompts.find((x) => x.id === id);
|
|
43
|
+
if (!p) throw new Error('achilleon: prompt "' + id + '" not found');
|
|
44
|
+
const provided = values || {};
|
|
45
|
+
const used = new Set();
|
|
46
|
+
const output = p.template.replace(/\{\{\s*([a-z][a-z_0-9]{0,39})\s*\}\}/g, (_, name) => {
|
|
47
|
+
used.add(name);
|
|
48
|
+
if (provided[name] !== undefined && provided[name] !== null) return String(provided[name]);
|
|
49
|
+
const varDef = (p.variables || []).find((v) => v.name === name);
|
|
50
|
+
if (varDef && varDef.default !== undefined) return varDef.default;
|
|
51
|
+
if (varDef && varDef.required === false) return '';
|
|
52
|
+
throw new Error('achilleon: prompt "' + id + '" missing required variable "' + name + '"');
|
|
53
|
+
});
|
|
54
|
+
return output;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Render a prompt template with values. Missing required vars throw. */
|
|
58
|
+
export function render(id, values) {
|
|
59
|
+
return _render(id, values, prompts);
|
|
60
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"kind": "prompt",
|
|
4
|
+
"id": "classify",
|
|
5
|
+
"name": "Classify into a fixed set",
|
|
6
|
+
"description": "Classify a piece of text into exactly one of a small set of labels. Returns just the label.",
|
|
7
|
+
"tier": "t1-core",
|
|
8
|
+
"author": "taskclan",
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"tags": [
|
|
11
|
+
"classification"
|
|
12
|
+
],
|
|
13
|
+
"variables": [
|
|
14
|
+
{
|
|
15
|
+
"name": "text",
|
|
16
|
+
"description": "The text to classify.",
|
|
17
|
+
"required": true
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "labels",
|
|
21
|
+
"description": "Comma-separated list of allowed labels. E.g. \"billing, technical, refund, general\".",
|
|
22
|
+
"required": true
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "unknown_label",
|
|
26
|
+
"description": "The label to return when no other label fits. E.g. \"other\" or \"unknown\".",
|
|
27
|
+
"required": false,
|
|
28
|
+
"default": "unknown"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"template": "Classify the text below into EXACTLY ONE of these labels:\n{{labels}}\n\nIf none fit, respond with: {{unknown_label}}\n\nRules:\n- Output the single label, lowercase, and NOTHING else.\n- No explanation, no punctuation, no code fences.\n\n--- TEXT ---\n{{text}}\n--- END ---\n"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"kind": "prompt",
|
|
35
|
+
"id": "extract",
|
|
36
|
+
"name": "Extract structured data",
|
|
37
|
+
"description": "Pull structured fields out of unstructured text into a JSON object matching the shape you describe.",
|
|
38
|
+
"tier": "t1-flow",
|
|
39
|
+
"author": "taskclan",
|
|
40
|
+
"version": "1.0.0",
|
|
41
|
+
"tags": [
|
|
42
|
+
"extraction",
|
|
43
|
+
"structured"
|
|
44
|
+
],
|
|
45
|
+
"variables": [
|
|
46
|
+
{
|
|
47
|
+
"name": "text",
|
|
48
|
+
"description": "Unstructured source text.",
|
|
49
|
+
"required": true
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "shape",
|
|
53
|
+
"description": "Description of the JSON shape you want out. For example a TypeScript-style type such as \"name: string; email: string; company: string or null\".\n",
|
|
54
|
+
"required": true
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "strict",
|
|
58
|
+
"description": "If \"true\", missing fields become null. If \"false\", the model may infer plausible values from context.",
|
|
59
|
+
"required": false,
|
|
60
|
+
"default": "true"
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"template": "Read the source text below and extract a JSON object matching this shape:\n\n {{shape}}\n\nRules:\n- Output ONLY the JSON object. No prose, no code fences, no commentary.\n- When strict={{strict}}: for missing fields, use null. Do not invent values.\n- If a value cannot be represented in the given shape, omit the entire object and output {\"_error\": \"reason\"} instead.\n\n--- SOURCE ---\n{{text}}\n--- END ---\n"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"kind": "prompt",
|
|
67
|
+
"id": "judge",
|
|
68
|
+
"name": "LLM as judge",
|
|
69
|
+
"description": "Evaluate an AI-generated answer against a question and a rubric. Returns a structured verdict.",
|
|
70
|
+
"tier": "t1-max",
|
|
71
|
+
"author": "taskclan",
|
|
72
|
+
"version": "1.0.0",
|
|
73
|
+
"tags": [
|
|
74
|
+
"eval",
|
|
75
|
+
"judge"
|
|
76
|
+
],
|
|
77
|
+
"variables": [
|
|
78
|
+
{
|
|
79
|
+
"name": "question",
|
|
80
|
+
"description": "The original question or prompt the AI was answering.",
|
|
81
|
+
"required": true
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "answer",
|
|
85
|
+
"description": "The AI-generated answer to evaluate.",
|
|
86
|
+
"required": true
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"name": "rubric",
|
|
90
|
+
"description": "Rubric describing what a good answer looks like. Can be a paragraph or a bulleted list.",
|
|
91
|
+
"required": true
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
"template": "You are evaluating an AI-generated answer as a strict but fair judge.\nScore the answer against the rubric. Never side with the answer by\ndefault; look for real failures.\n\n--- QUESTION ---\n{{question}}\n--- END QUESTION ---\n\n--- ANSWER ---\n{{answer}}\n--- END ANSWER ---\n\n--- RUBRIC ---\n{{rubric}}\n--- END RUBRIC ---\n\nRespond with a JSON object exactly matching this shape (no prose):\n\n {\n \"verdict\": \"pass\" | \"fail\" | \"partial\",\n \"score\": 0-10 integer,\n \"reasoning\": \"one short paragraph\",\n \"failures\": [\"specific issue 1\", \"specific issue 2\"]\n }\n"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"kind": "prompt",
|
|
98
|
+
"id": "refine",
|
|
99
|
+
"name": "Refine text with feedback",
|
|
100
|
+
"description": "Rewrite a draft in response to specific feedback, preserving intent and unaffected sections.",
|
|
101
|
+
"tier": "t1-flow",
|
|
102
|
+
"author": "taskclan",
|
|
103
|
+
"version": "1.0.0",
|
|
104
|
+
"tags": [
|
|
105
|
+
"refine",
|
|
106
|
+
"editing"
|
|
107
|
+
],
|
|
108
|
+
"variables": [
|
|
109
|
+
{
|
|
110
|
+
"name": "draft",
|
|
111
|
+
"description": "The current text to refine.",
|
|
112
|
+
"required": true
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "feedback",
|
|
116
|
+
"description": "The specific changes to apply. Can be a bulleted list or a paragraph.",
|
|
117
|
+
"required": true
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"name": "preserve",
|
|
121
|
+
"description": "What must NOT change. E.g. \"keep all code snippets exactly as-is\", \"keep the ending paragraph\".",
|
|
122
|
+
"required": false,
|
|
123
|
+
"default": "keep everything not explicitly targeted by the feedback"
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"template": "Refine the draft below by applying the feedback. Follow these rules:\n\n1. Apply every piece of feedback that is actionable. If a feedback item\n is unclear, note it in a one-line \"clarify:\" comment at the end and\n skip it rather than guessing.\n2. Preserve: {{preserve}}\n3. Do not editorialise about the feedback. Output only the refined\n version, followed by any clarify: comments.\n\n--- DRAFT ---\n{{draft}}\n--- END DRAFT ---\n\n--- FEEDBACK ---\n{{feedback}}\n--- END FEEDBACK ---\n"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"kind": "prompt",
|
|
130
|
+
"id": "summarize",
|
|
131
|
+
"name": "Summarize text",
|
|
132
|
+
"description": "Produce a tight, faithful summary of a body of text at a controllable length and altitude.",
|
|
133
|
+
"tier": "t1-flow",
|
|
134
|
+
"author": "taskclan",
|
|
135
|
+
"version": "1.0.0",
|
|
136
|
+
"tags": [
|
|
137
|
+
"summary",
|
|
138
|
+
"text"
|
|
139
|
+
],
|
|
140
|
+
"variables": [
|
|
141
|
+
{
|
|
142
|
+
"name": "text",
|
|
143
|
+
"description": "The source text to summarise.",
|
|
144
|
+
"required": true
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"name": "length",
|
|
148
|
+
"description": "Target length. One of \"one sentence\", \"one paragraph\", \"bulleted\", \"5 bullets\", \"detailed\".",
|
|
149
|
+
"required": false,
|
|
150
|
+
"default": "one paragraph"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"name": "audience",
|
|
154
|
+
"description": "Who the summary is for. Shapes altitude and jargon level. E.g. \"senior engineer\", \"non-technical exec\", \"10 year old\".",
|
|
155
|
+
"required": false,
|
|
156
|
+
"default": "general reader"
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
"template": "Summarise the text below at length \"{{length}}\" for the audience \"{{audience}}\".\n\nRules:\n- Faithful to the source. Do not add facts.\n- Skip generic hedges like \"in conclusion\" or \"overall\".\n- If the source is empty or too short to summarise, say so and stop.\n\n--- SOURCE TEXT ---\n{{text}}\n--- END ---\n"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"kind": "prompt",
|
|
163
|
+
"id": "translate",
|
|
164
|
+
"name": "Translate text",
|
|
165
|
+
"description": "Translate text into a target language, preserving tone, formatting, and code fences.",
|
|
166
|
+
"tier": "t1-flow",
|
|
167
|
+
"author": "taskclan",
|
|
168
|
+
"version": "1.0.0",
|
|
169
|
+
"tags": [
|
|
170
|
+
"translation",
|
|
171
|
+
"i18n"
|
|
172
|
+
],
|
|
173
|
+
"variables": [
|
|
174
|
+
{
|
|
175
|
+
"name": "text",
|
|
176
|
+
"description": "Source text.",
|
|
177
|
+
"required": true
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"name": "target_language",
|
|
181
|
+
"description": "The target language. E.g. \"French\", \"Japanese\", \"Yoruba\", \"es-MX\".",
|
|
182
|
+
"required": true
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"name": "tone",
|
|
186
|
+
"description": "Optional tone override. E.g. \"formal\", \"conversational\", \"technical documentation\".",
|
|
187
|
+
"required": false,
|
|
188
|
+
"default": "match the source tone"
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
"template": "Translate the text below into {{target_language}}. Preserve tone\n(\"{{tone}}\"), formatting, and any code fences exactly. Never translate\ncontent inside code fences.\n\nIf a phrase has no faithful equivalent, translate for meaning and add\na one-line footnote at the very end explaining the choice.\n\n--- SOURCE ---\n{{text}}\n--- END ---\n"
|
|
192
|
+
}
|
|
193
|
+
]
|
package/dist/registry.json
CHANGED
|
@@ -628,5 +628,198 @@
|
|
|
628
628
|
],
|
|
629
629
|
"system": "You are the Taskclan sensei — a patient teacher in the Socratic\ntradition. You never give the answer directly. Every reply is a\nquestion that leads the student one step closer. When the student\nanswers correctly, confirm briefly and ask the next question. When\nthey get stuck, offer a smaller hint, still as a question. Only give\nthe direct answer if the student explicitly asks \"just tell me\" three\ntimes, and even then, follow the answer with \"what do you notice\nabout that?\".\n"
|
|
630
630
|
}
|
|
631
|
+
],
|
|
632
|
+
"prompts": [
|
|
633
|
+
{
|
|
634
|
+
"kind": "prompt",
|
|
635
|
+
"id": "classify",
|
|
636
|
+
"name": "Classify into a fixed set",
|
|
637
|
+
"description": "Classify a piece of text into exactly one of a small set of labels. Returns just the label.",
|
|
638
|
+
"tier": "t1-core",
|
|
639
|
+
"author": "taskclan",
|
|
640
|
+
"version": "1.0.0",
|
|
641
|
+
"tags": [
|
|
642
|
+
"classification"
|
|
643
|
+
],
|
|
644
|
+
"variables": [
|
|
645
|
+
{
|
|
646
|
+
"name": "text",
|
|
647
|
+
"description": "The text to classify.",
|
|
648
|
+
"required": true
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
"name": "labels",
|
|
652
|
+
"description": "Comma-separated list of allowed labels. E.g. \"billing, technical, refund, general\".",
|
|
653
|
+
"required": true
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
"name": "unknown_label",
|
|
657
|
+
"description": "The label to return when no other label fits. E.g. \"other\" or \"unknown\".",
|
|
658
|
+
"required": false,
|
|
659
|
+
"default": "unknown"
|
|
660
|
+
}
|
|
661
|
+
],
|
|
662
|
+
"template": "Classify the text below into EXACTLY ONE of these labels:\n{{labels}}\n\nIf none fit, respond with: {{unknown_label}}\n\nRules:\n- Output the single label, lowercase, and NOTHING else.\n- No explanation, no punctuation, no code fences.\n\n--- TEXT ---\n{{text}}\n--- END ---\n"
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
"kind": "prompt",
|
|
666
|
+
"id": "extract",
|
|
667
|
+
"name": "Extract structured data",
|
|
668
|
+
"description": "Pull structured fields out of unstructured text into a JSON object matching the shape you describe.",
|
|
669
|
+
"tier": "t1-flow",
|
|
670
|
+
"author": "taskclan",
|
|
671
|
+
"version": "1.0.0",
|
|
672
|
+
"tags": [
|
|
673
|
+
"extraction",
|
|
674
|
+
"structured"
|
|
675
|
+
],
|
|
676
|
+
"variables": [
|
|
677
|
+
{
|
|
678
|
+
"name": "text",
|
|
679
|
+
"description": "Unstructured source text.",
|
|
680
|
+
"required": true
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
"name": "shape",
|
|
684
|
+
"description": "Description of the JSON shape you want out. For example a TypeScript-style type such as \"name: string; email: string; company: string or null\".\n",
|
|
685
|
+
"required": true
|
|
686
|
+
},
|
|
687
|
+
{
|
|
688
|
+
"name": "strict",
|
|
689
|
+
"description": "If \"true\", missing fields become null. If \"false\", the model may infer plausible values from context.",
|
|
690
|
+
"required": false,
|
|
691
|
+
"default": "true"
|
|
692
|
+
}
|
|
693
|
+
],
|
|
694
|
+
"template": "Read the source text below and extract a JSON object matching this shape:\n\n {{shape}}\n\nRules:\n- Output ONLY the JSON object. No prose, no code fences, no commentary.\n- When strict={{strict}}: for missing fields, use null. Do not invent values.\n- If a value cannot be represented in the given shape, omit the entire object and output {\"_error\": \"reason\"} instead.\n\n--- SOURCE ---\n{{text}}\n--- END ---\n"
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
"kind": "prompt",
|
|
698
|
+
"id": "judge",
|
|
699
|
+
"name": "LLM as judge",
|
|
700
|
+
"description": "Evaluate an AI-generated answer against a question and a rubric. Returns a structured verdict.",
|
|
701
|
+
"tier": "t1-max",
|
|
702
|
+
"author": "taskclan",
|
|
703
|
+
"version": "1.0.0",
|
|
704
|
+
"tags": [
|
|
705
|
+
"eval",
|
|
706
|
+
"judge"
|
|
707
|
+
],
|
|
708
|
+
"variables": [
|
|
709
|
+
{
|
|
710
|
+
"name": "question",
|
|
711
|
+
"description": "The original question or prompt the AI was answering.",
|
|
712
|
+
"required": true
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
"name": "answer",
|
|
716
|
+
"description": "The AI-generated answer to evaluate.",
|
|
717
|
+
"required": true
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
"name": "rubric",
|
|
721
|
+
"description": "Rubric describing what a good answer looks like. Can be a paragraph or a bulleted list.",
|
|
722
|
+
"required": true
|
|
723
|
+
}
|
|
724
|
+
],
|
|
725
|
+
"template": "You are evaluating an AI-generated answer as a strict but fair judge.\nScore the answer against the rubric. Never side with the answer by\ndefault; look for real failures.\n\n--- QUESTION ---\n{{question}}\n--- END QUESTION ---\n\n--- ANSWER ---\n{{answer}}\n--- END ANSWER ---\n\n--- RUBRIC ---\n{{rubric}}\n--- END RUBRIC ---\n\nRespond with a JSON object exactly matching this shape (no prose):\n\n {\n \"verdict\": \"pass\" | \"fail\" | \"partial\",\n \"score\": 0-10 integer,\n \"reasoning\": \"one short paragraph\",\n \"failures\": [\"specific issue 1\", \"specific issue 2\"]\n }\n"
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
"kind": "prompt",
|
|
729
|
+
"id": "refine",
|
|
730
|
+
"name": "Refine text with feedback",
|
|
731
|
+
"description": "Rewrite a draft in response to specific feedback, preserving intent and unaffected sections.",
|
|
732
|
+
"tier": "t1-flow",
|
|
733
|
+
"author": "taskclan",
|
|
734
|
+
"version": "1.0.0",
|
|
735
|
+
"tags": [
|
|
736
|
+
"refine",
|
|
737
|
+
"editing"
|
|
738
|
+
],
|
|
739
|
+
"variables": [
|
|
740
|
+
{
|
|
741
|
+
"name": "draft",
|
|
742
|
+
"description": "The current text to refine.",
|
|
743
|
+
"required": true
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
"name": "feedback",
|
|
747
|
+
"description": "The specific changes to apply. Can be a bulleted list or a paragraph.",
|
|
748
|
+
"required": true
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
"name": "preserve",
|
|
752
|
+
"description": "What must NOT change. E.g. \"keep all code snippets exactly as-is\", \"keep the ending paragraph\".",
|
|
753
|
+
"required": false,
|
|
754
|
+
"default": "keep everything not explicitly targeted by the feedback"
|
|
755
|
+
}
|
|
756
|
+
],
|
|
757
|
+
"template": "Refine the draft below by applying the feedback. Follow these rules:\n\n1. Apply every piece of feedback that is actionable. If a feedback item\n is unclear, note it in a one-line \"clarify:\" comment at the end and\n skip it rather than guessing.\n2. Preserve: {{preserve}}\n3. Do not editorialise about the feedback. Output only the refined\n version, followed by any clarify: comments.\n\n--- DRAFT ---\n{{draft}}\n--- END DRAFT ---\n\n--- FEEDBACK ---\n{{feedback}}\n--- END FEEDBACK ---\n"
|
|
758
|
+
},
|
|
759
|
+
{
|
|
760
|
+
"kind": "prompt",
|
|
761
|
+
"id": "summarize",
|
|
762
|
+
"name": "Summarize text",
|
|
763
|
+
"description": "Produce a tight, faithful summary of a body of text at a controllable length and altitude.",
|
|
764
|
+
"tier": "t1-flow",
|
|
765
|
+
"author": "taskclan",
|
|
766
|
+
"version": "1.0.0",
|
|
767
|
+
"tags": [
|
|
768
|
+
"summary",
|
|
769
|
+
"text"
|
|
770
|
+
],
|
|
771
|
+
"variables": [
|
|
772
|
+
{
|
|
773
|
+
"name": "text",
|
|
774
|
+
"description": "The source text to summarise.",
|
|
775
|
+
"required": true
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
"name": "length",
|
|
779
|
+
"description": "Target length. One of \"one sentence\", \"one paragraph\", \"bulleted\", \"5 bullets\", \"detailed\".",
|
|
780
|
+
"required": false,
|
|
781
|
+
"default": "one paragraph"
|
|
782
|
+
},
|
|
783
|
+
{
|
|
784
|
+
"name": "audience",
|
|
785
|
+
"description": "Who the summary is for. Shapes altitude and jargon level. E.g. \"senior engineer\", \"non-technical exec\", \"10 year old\".",
|
|
786
|
+
"required": false,
|
|
787
|
+
"default": "general reader"
|
|
788
|
+
}
|
|
789
|
+
],
|
|
790
|
+
"template": "Summarise the text below at length \"{{length}}\" for the audience \"{{audience}}\".\n\nRules:\n- Faithful to the source. Do not add facts.\n- Skip generic hedges like \"in conclusion\" or \"overall\".\n- If the source is empty or too short to summarise, say so and stop.\n\n--- SOURCE TEXT ---\n{{text}}\n--- END ---\n"
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
"kind": "prompt",
|
|
794
|
+
"id": "translate",
|
|
795
|
+
"name": "Translate text",
|
|
796
|
+
"description": "Translate text into a target language, preserving tone, formatting, and code fences.",
|
|
797
|
+
"tier": "t1-flow",
|
|
798
|
+
"author": "taskclan",
|
|
799
|
+
"version": "1.0.0",
|
|
800
|
+
"tags": [
|
|
801
|
+
"translation",
|
|
802
|
+
"i18n"
|
|
803
|
+
],
|
|
804
|
+
"variables": [
|
|
805
|
+
{
|
|
806
|
+
"name": "text",
|
|
807
|
+
"description": "Source text.",
|
|
808
|
+
"required": true
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
"name": "target_language",
|
|
812
|
+
"description": "The target language. E.g. \"French\", \"Japanese\", \"Yoruba\", \"es-MX\".",
|
|
813
|
+
"required": true
|
|
814
|
+
},
|
|
815
|
+
{
|
|
816
|
+
"name": "tone",
|
|
817
|
+
"description": "Optional tone override. E.g. \"formal\", \"conversational\", \"technical documentation\".",
|
|
818
|
+
"required": false,
|
|
819
|
+
"default": "match the source tone"
|
|
820
|
+
}
|
|
821
|
+
],
|
|
822
|
+
"template": "Translate the text below into {{target_language}}. Preserve tone\n(\"{{tone}}\"), formatting, and any code fences exactly. Never translate\ncontent inside code fences.\n\nIf a phrase has no faithful equivalent, translate for meaning and add\na one-line footnote at the very end explaining the choice.\n\n--- SOURCE ---\n{{text}}\n--- END ---\n"
|
|
823
|
+
}
|
|
631
824
|
]
|
|
632
825
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taskclan/achilleon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Open registry of skills, agents, and prompts loaded by Taskclan Intelligence — and installable in Cursor, Continue.dev, Claude Code, Windsurf, Cline, Zed, or anywhere else you can paste a prompt. Contribute a YAML file to add or improve an entry.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Taskclan Inc.",
|
|
@@ -43,6 +43,8 @@
|
|
|
43
43
|
"./skills.json": "./dist/skills.json",
|
|
44
44
|
"./agents": "./dist/agents.json",
|
|
45
45
|
"./agents.json": "./dist/agents.json",
|
|
46
|
+
"./prompts": "./dist/prompts.json",
|
|
47
|
+
"./prompts.json": "./dist/prompts.json",
|
|
46
48
|
"./package.json": "./package.json"
|
|
47
49
|
},
|
|
48
50
|
"files": [
|
|
@@ -52,8 +54,10 @@
|
|
|
52
54
|
"dist/registry.json",
|
|
53
55
|
"dist/skills.json",
|
|
54
56
|
"dist/agents.json",
|
|
57
|
+
"dist/prompts.json",
|
|
55
58
|
"skills",
|
|
56
59
|
"agents",
|
|
60
|
+
"prompts",
|
|
57
61
|
"schema",
|
|
58
62
|
"README.md",
|
|
59
63
|
"LICENSE"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
id: classify
|
|
2
|
+
name: Classify into a fixed set
|
|
3
|
+
description: Classify a piece of text into exactly one of a small set of labels. Returns just the label.
|
|
4
|
+
tier: t1-core
|
|
5
|
+
author: taskclan
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
tags:
|
|
8
|
+
- classification
|
|
9
|
+
variables:
|
|
10
|
+
- name: text
|
|
11
|
+
description: The text to classify.
|
|
12
|
+
required: true
|
|
13
|
+
- name: labels
|
|
14
|
+
description: Comma-separated list of allowed labels. E.g. "billing, technical, refund, general".
|
|
15
|
+
required: true
|
|
16
|
+
- name: unknown_label
|
|
17
|
+
description: The label to return when no other label fits. E.g. "other" or "unknown".
|
|
18
|
+
required: false
|
|
19
|
+
default: unknown
|
|
20
|
+
template: |
|
|
21
|
+
Classify the text below into EXACTLY ONE of these labels:
|
|
22
|
+
{{labels}}
|
|
23
|
+
|
|
24
|
+
If none fit, respond with: {{unknown_label}}
|
|
25
|
+
|
|
26
|
+
Rules:
|
|
27
|
+
- Output the single label, lowercase, and NOTHING else.
|
|
28
|
+
- No explanation, no punctuation, no code fences.
|
|
29
|
+
|
|
30
|
+
--- TEXT ---
|
|
31
|
+
{{text}}
|
|
32
|
+
--- END ---
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
id: extract
|
|
2
|
+
name: Extract structured data
|
|
3
|
+
description: Pull structured fields out of unstructured text into a JSON object matching the shape you describe.
|
|
4
|
+
tier: t1-flow
|
|
5
|
+
author: taskclan
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
tags:
|
|
8
|
+
- extraction
|
|
9
|
+
- structured
|
|
10
|
+
variables:
|
|
11
|
+
- name: text
|
|
12
|
+
description: Unstructured source text.
|
|
13
|
+
required: true
|
|
14
|
+
- name: shape
|
|
15
|
+
description: >
|
|
16
|
+
Description of the JSON shape you want out.
|
|
17
|
+
For example a TypeScript-style type such as
|
|
18
|
+
"name: string; email: string; company: string or null".
|
|
19
|
+
required: true
|
|
20
|
+
- name: strict
|
|
21
|
+
description: If "true", missing fields become null. If "false", the model may infer plausible values from context.
|
|
22
|
+
required: false
|
|
23
|
+
default: "true"
|
|
24
|
+
template: |
|
|
25
|
+
Read the source text below and extract a JSON object matching this shape:
|
|
26
|
+
|
|
27
|
+
{{shape}}
|
|
28
|
+
|
|
29
|
+
Rules:
|
|
30
|
+
- Output ONLY the JSON object. No prose, no code fences, no commentary.
|
|
31
|
+
- When strict={{strict}}: for missing fields, use null. Do not invent values.
|
|
32
|
+
- If a value cannot be represented in the given shape, omit the entire object and output {"_error": "reason"} instead.
|
|
33
|
+
|
|
34
|
+
--- SOURCE ---
|
|
35
|
+
{{text}}
|
|
36
|
+
--- END ---
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
id: judge
|
|
2
|
+
name: LLM as judge
|
|
3
|
+
description: Evaluate an AI-generated answer against a question and a rubric. Returns a structured verdict.
|
|
4
|
+
tier: t1-max
|
|
5
|
+
author: taskclan
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
tags:
|
|
8
|
+
- eval
|
|
9
|
+
- judge
|
|
10
|
+
variables:
|
|
11
|
+
- name: question
|
|
12
|
+
description: The original question or prompt the AI was answering.
|
|
13
|
+
required: true
|
|
14
|
+
- name: answer
|
|
15
|
+
description: The AI-generated answer to evaluate.
|
|
16
|
+
required: true
|
|
17
|
+
- name: rubric
|
|
18
|
+
description: Rubric describing what a good answer looks like. Can be a paragraph or a bulleted list.
|
|
19
|
+
required: true
|
|
20
|
+
template: |
|
|
21
|
+
You are evaluating an AI-generated answer as a strict but fair judge.
|
|
22
|
+
Score the answer against the rubric. Never side with the answer by
|
|
23
|
+
default; look for real failures.
|
|
24
|
+
|
|
25
|
+
--- QUESTION ---
|
|
26
|
+
{{question}}
|
|
27
|
+
--- END QUESTION ---
|
|
28
|
+
|
|
29
|
+
--- ANSWER ---
|
|
30
|
+
{{answer}}
|
|
31
|
+
--- END ANSWER ---
|
|
32
|
+
|
|
33
|
+
--- RUBRIC ---
|
|
34
|
+
{{rubric}}
|
|
35
|
+
--- END RUBRIC ---
|
|
36
|
+
|
|
37
|
+
Respond with a JSON object exactly matching this shape (no prose):
|
|
38
|
+
|
|
39
|
+
{
|
|
40
|
+
"verdict": "pass" | "fail" | "partial",
|
|
41
|
+
"score": 0-10 integer,
|
|
42
|
+
"reasoning": "one short paragraph",
|
|
43
|
+
"failures": ["specific issue 1", "specific issue 2"]
|
|
44
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
id: refine
|
|
2
|
+
name: Refine text with feedback
|
|
3
|
+
description: Rewrite a draft in response to specific feedback, preserving intent and unaffected sections.
|
|
4
|
+
tier: t1-flow
|
|
5
|
+
author: taskclan
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
tags:
|
|
8
|
+
- refine
|
|
9
|
+
- editing
|
|
10
|
+
variables:
|
|
11
|
+
- name: draft
|
|
12
|
+
description: The current text to refine.
|
|
13
|
+
required: true
|
|
14
|
+
- name: feedback
|
|
15
|
+
description: The specific changes to apply. Can be a bulleted list or a paragraph.
|
|
16
|
+
required: true
|
|
17
|
+
- name: preserve
|
|
18
|
+
description: What must NOT change. E.g. "keep all code snippets exactly as-is", "keep the ending paragraph".
|
|
19
|
+
required: false
|
|
20
|
+
default: keep everything not explicitly targeted by the feedback
|
|
21
|
+
template: |
|
|
22
|
+
Refine the draft below by applying the feedback. Follow these rules:
|
|
23
|
+
|
|
24
|
+
1. Apply every piece of feedback that is actionable. If a feedback item
|
|
25
|
+
is unclear, note it in a one-line "clarify:" comment at the end and
|
|
26
|
+
skip it rather than guessing.
|
|
27
|
+
2. Preserve: {{preserve}}
|
|
28
|
+
3. Do not editorialise about the feedback. Output only the refined
|
|
29
|
+
version, followed by any clarify: comments.
|
|
30
|
+
|
|
31
|
+
--- DRAFT ---
|
|
32
|
+
{{draft}}
|
|
33
|
+
--- END DRAFT ---
|
|
34
|
+
|
|
35
|
+
--- FEEDBACK ---
|
|
36
|
+
{{feedback}}
|
|
37
|
+
--- END FEEDBACK ---
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
id: summarize
|
|
2
|
+
name: Summarize text
|
|
3
|
+
description: Produce a tight, faithful summary of a body of text at a controllable length and altitude.
|
|
4
|
+
tier: t1-flow
|
|
5
|
+
author: taskclan
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
tags:
|
|
8
|
+
- summary
|
|
9
|
+
- text
|
|
10
|
+
variables:
|
|
11
|
+
- name: text
|
|
12
|
+
description: The source text to summarise.
|
|
13
|
+
required: true
|
|
14
|
+
- name: length
|
|
15
|
+
description: Target length. One of "one sentence", "one paragraph", "bulleted", "5 bullets", "detailed".
|
|
16
|
+
required: false
|
|
17
|
+
default: one paragraph
|
|
18
|
+
- name: audience
|
|
19
|
+
description: Who the summary is for. Shapes altitude and jargon level. E.g. "senior engineer", "non-technical exec", "10 year old".
|
|
20
|
+
required: false
|
|
21
|
+
default: general reader
|
|
22
|
+
template: |
|
|
23
|
+
Summarise the text below at length "{{length}}" for the audience "{{audience}}".
|
|
24
|
+
|
|
25
|
+
Rules:
|
|
26
|
+
- Faithful to the source. Do not add facts.
|
|
27
|
+
- Skip generic hedges like "in conclusion" or "overall".
|
|
28
|
+
- If the source is empty or too short to summarise, say so and stop.
|
|
29
|
+
|
|
30
|
+
--- SOURCE TEXT ---
|
|
31
|
+
{{text}}
|
|
32
|
+
--- END ---
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
id: translate
|
|
2
|
+
name: Translate text
|
|
3
|
+
description: Translate text into a target language, preserving tone, formatting, and code fences.
|
|
4
|
+
tier: t1-flow
|
|
5
|
+
author: taskclan
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
tags:
|
|
8
|
+
- translation
|
|
9
|
+
- i18n
|
|
10
|
+
variables:
|
|
11
|
+
- name: text
|
|
12
|
+
description: Source text.
|
|
13
|
+
required: true
|
|
14
|
+
- name: target_language
|
|
15
|
+
description: The target language. E.g. "French", "Japanese", "Yoruba", "es-MX".
|
|
16
|
+
required: true
|
|
17
|
+
- name: tone
|
|
18
|
+
description: Optional tone override. E.g. "formal", "conversational", "technical documentation".
|
|
19
|
+
required: false
|
|
20
|
+
default: match the source tone
|
|
21
|
+
template: |
|
|
22
|
+
Translate the text below into {{target_language}}. Preserve tone
|
|
23
|
+
("{{tone}}"), formatting, and any code fences exactly. Never translate
|
|
24
|
+
content inside code fences.
|
|
25
|
+
|
|
26
|
+
If a phrase has no faithful equivalent, translate for meaning and add
|
|
27
|
+
a one-line footnote at the very end explaining the choice.
|
|
28
|
+
|
|
29
|
+
--- SOURCE ---
|
|
30
|
+
{{text}}
|
|
31
|
+
--- END ---
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://taskclan.com/achilleon/schema/prompt.schema.json",
|
|
4
|
+
"title": "Achilleon Prompt",
|
|
5
|
+
"description": "A parameterised prompt template loaded by SDK consumers. Different from a skill (fixed system prompt for a slash command) — prompts take user-supplied values and render a final prompt string at call time. Lives at prompts/{id}.yml.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["id", "name", "description", "template"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"id": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"pattern": "^[a-z][a-z0-9-]{1,39}$",
|
|
13
|
+
"description": "Lowercase, hyphen-separated. Must match the filename (without .yml). 2-40 characters."
|
|
14
|
+
},
|
|
15
|
+
"name": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"minLength": 2,
|
|
18
|
+
"maxLength": 60,
|
|
19
|
+
"description": "Human-readable name shown in docs and pickers."
|
|
20
|
+
},
|
|
21
|
+
"description": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"minLength": 8,
|
|
24
|
+
"maxLength": 200,
|
|
25
|
+
"description": "One-line description of what the prompt does."
|
|
26
|
+
},
|
|
27
|
+
"template": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"minLength": 20,
|
|
30
|
+
"maxLength": 8000,
|
|
31
|
+
"description": "The prompt body. Placeholders use {{variable}} syntax. Every placeholder must have a matching entry in `variables`; the validator enforces this."
|
|
32
|
+
},
|
|
33
|
+
"variables": {
|
|
34
|
+
"type": "array",
|
|
35
|
+
"maxItems": 20,
|
|
36
|
+
"items": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"required": ["name", "description"],
|
|
39
|
+
"additionalProperties": false,
|
|
40
|
+
"properties": {
|
|
41
|
+
"name": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"pattern": "^[a-z][a-z_0-9]{0,39}$",
|
|
44
|
+
"description": "Variable name as it appears in the template ({{name}}). snake_case."
|
|
45
|
+
},
|
|
46
|
+
"description": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"minLength": 4,
|
|
49
|
+
"maxLength": 200,
|
|
50
|
+
"description": "What the variable is for. Shown in docs + used by SDK tooling."
|
|
51
|
+
},
|
|
52
|
+
"required": {
|
|
53
|
+
"type": "boolean",
|
|
54
|
+
"default": true,
|
|
55
|
+
"description": "If false, the SDK renderer allows omission (empty string is substituted)."
|
|
56
|
+
},
|
|
57
|
+
"default": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"description": "Default value substituted when a required variable is missing but a default is provided."
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"tier": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"enum": ["t1-core", "t1-flow", "t1-max", "t1-auto"],
|
|
67
|
+
"description": "Recommended T1 tier this prompt runs well on. Consumers can override."
|
|
68
|
+
},
|
|
69
|
+
"author": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"pattern": "^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,38}[a-zA-Z0-9])?$"
|
|
72
|
+
},
|
|
73
|
+
"version": {
|
|
74
|
+
"type": "string",
|
|
75
|
+
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$"
|
|
76
|
+
},
|
|
77
|
+
"tags": {
|
|
78
|
+
"type": "array",
|
|
79
|
+
"items": { "type": "string", "minLength": 2, "maxLength": 30 },
|
|
80
|
+
"maxItems": 10,
|
|
81
|
+
"uniqueItems": true
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|