clef-mcp 0.1.1 → 0.1.3
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 +29 -1
- package/dist/cli.js +21 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +21 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/skills/clef-decisions/SKILL.md +96 -0
package/README.md
CHANGED
|
@@ -63,6 +63,18 @@ args = []
|
|
|
63
63
|
}
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
**ZCode** — `~/.zcode/cli/config.json` (user scope; servers auto-connect in new sessions):
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"mcp": {
|
|
71
|
+
"servers": {
|
|
72
|
+
"clef-mcp": { "command": "clef-mcp", "args": [], "type": "stdio" }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
66
78
|
**Generic MCP client** — any client that speaks MCP over stdio: run `clef-mcp` as the server command.
|
|
67
79
|
|
|
68
80
|
Ready-made snippets live in [`examples/`](examples/).
|
|
@@ -104,7 +116,7 @@ Ready-made snippets live in [`examples/`](examples/).
|
|
|
104
116
|
|
|
105
117
|
| Type | Criteria | Meaning |
|
|
106
118
|
|------|----------|---------|
|
|
107
|
-
| `choice` | map of `option id → description
|
|
119
|
+
| `choice` | map of `option id → description`, or a plain list of options (ids = the strings) | Pick among named options |
|
|
108
120
|
| `score` | ordered list of descriptions | Ordered scale (index = score) |
|
|
109
121
|
| `noul` | optional `{"true": "...", "false": "..."}` | Yes/no question |
|
|
110
122
|
|
|
@@ -131,6 +143,22 @@ Strictly structured — the server never turns the result into prose:
|
|
|
131
143
|
|
|
132
144
|
`state` is treated strictly as **data**: it is never interpreted as instructions for the MCP server itself (see [Security](#security--data-handling)).
|
|
133
145
|
|
|
146
|
+
## Teach your agent (skill)
|
|
147
|
+
|
|
148
|
+
The tool schema tells the client *what* `clef_decide` accepts; agents also need to know *when* to reach for it and *how* to frame decisions. The bundled skill covers that: decision patterns (next action / routing / classification / noul / score), batching up to 64 questions into one forward pass, writing mutually exclusive criteria, interpreting distributions (argmax vs flat), thresholds for safety-adjacent calls, and error recovery.
|
|
149
|
+
|
|
150
|
+
Install it for your agent(s):
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# from this repo
|
|
154
|
+
cp -r skills/clef-decisions ~/.agents/skills/
|
|
155
|
+
|
|
156
|
+
# or from the npm package
|
|
157
|
+
cp -r "$(npm root -g)/clef-mcp/skills/clef-decisions" ~/.agents/skills/
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`~/.agents/skills/` is the shared location for ZCode / Claude Code / Codex-style agents.
|
|
161
|
+
|
|
134
162
|
## CLI
|
|
135
163
|
|
|
136
164
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -74,7 +74,9 @@ function toSystemOneRequest(input, defaultModel) {
|
|
|
74
74
|
const questions = {};
|
|
75
75
|
for (const [qid, q] of Object.entries(input.questions)) {
|
|
76
76
|
const question = { type: q.type, instructions: q.instructions };
|
|
77
|
-
if (q.criteria !== void 0)
|
|
77
|
+
if (q.criteria !== void 0) {
|
|
78
|
+
question.criteria = q.type === "choice" && Array.isArray(q.criteria) ? Object.fromEntries(q.criteria.map((c) => [c, c])) : q.criteria;
|
|
79
|
+
}
|
|
78
80
|
questions[qid] = question;
|
|
79
81
|
}
|
|
80
82
|
return {
|
|
@@ -804,14 +806,23 @@ import { z } from "zod";
|
|
|
804
806
|
function criteriaDescription(limits) {
|
|
805
807
|
return z.string().min(1).max(limits.maxCriteriaDescChars);
|
|
806
808
|
}
|
|
809
|
+
function countIssues(count, limits) {
|
|
810
|
+
if (count === 0) return "criteria must not be empty";
|
|
811
|
+
if (count > limits.maxCriteriaPerQuestion) return `too many criteria (max ${limits.maxCriteriaPerQuestion})`;
|
|
812
|
+
return void 0;
|
|
813
|
+
}
|
|
807
814
|
function choiceCriteria(limits) {
|
|
808
|
-
return z.
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
ctx.issues.push({ code: "custom", message:
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
+
return z.union([
|
|
816
|
+
// Plain list: option ids equal to the strings themselves.
|
|
817
|
+
z.array(criteriaDescription(limits)).check((ctx) => {
|
|
818
|
+
const problem = countIssues(ctx.value.length, limits);
|
|
819
|
+
if (problem) ctx.issues.push({ code: "custom", message: problem, input: ctx.value });
|
|
820
|
+
}),
|
|
821
|
+
z.record(z.string().min(1).max(limits.maxCriteriaDescChars), criteriaDescription(limits)).check((ctx) => {
|
|
822
|
+
const problem = countIssues(Object.keys(ctx.value).length, limits);
|
|
823
|
+
if (problem) ctx.issues.push({ code: "custom", message: problem, input: ctx.value });
|
|
824
|
+
})
|
|
825
|
+
]);
|
|
815
826
|
}
|
|
816
827
|
function scoreCriteria(limits) {
|
|
817
828
|
return z.array(criteriaDescription(limits)).check((ctx) => {
|
|
@@ -832,7 +843,7 @@ function questionSchema(limits) {
|
|
|
832
843
|
if (!parsed.success) {
|
|
833
844
|
ctx.addIssue({
|
|
834
845
|
code: "custom",
|
|
835
|
-
message: `"choice" questions require non-empty criteria as a map of option id -> description (${parsed.error.issues[0]?.message ?? "invalid criteria"})`
|
|
846
|
+
message: `"choice" questions require non-empty criteria as a map of option id -> description, or a plain list of options (${parsed.error.issues[0]?.message ?? "invalid criteria"})`
|
|
836
847
|
});
|
|
837
848
|
}
|
|
838
849
|
} else if (q.type === "score") {
|
|
@@ -1736,7 +1747,7 @@ async function confirm(question, yes) {
|
|
|
1736
1747
|
}
|
|
1737
1748
|
|
|
1738
1749
|
// src/version.ts
|
|
1739
|
-
var VERSION = "0.1.
|
|
1750
|
+
var VERSION = "0.1.3";
|
|
1740
1751
|
|
|
1741
1752
|
// src/cli/install.ts
|
|
1742
1753
|
var OS_NAMES = {
|