@matamt-dbg/dsh-studio 0.3.0 → 0.5.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.
@@ -0,0 +1,287 @@
1
+ # Pixie Gate guide
2
+
3
+ English | [한국어](pixie-gate.ko.md)
4
+
5
+ Pixie Gate lets the **Pixie model read, judge, and rework content** at a set moment in an agent's work, then sends the result to the agent or to you. Rules and external jobs belong to DSH command hooks (Claude Code and Codex hooks); Pixie Gate is the layer above them for work that needs a model's judgment. It works on the original text alone, without any hook.
6
+
7
+ - [Create a gate](#create-a-gate)
8
+ - [When, and how results apply](#when-and-how-results-apply)
9
+ - [Advanced options](#advanced-options)
10
+ - [Pixie hook scripts](#pixie-hook-scripts)
11
+ - [The pixie helper](#the-pixie-helper)
12
+ - [Decision engine](#decision-engine)
13
+ - [Example scripts](#example-scripts)
14
+ - [Agent skill](#agent-skill)
15
+ - [Chat notes and per-session switches](#chat-notes-and-per-session-switches)
16
+ - [Run records](#run-records)
17
+ - [Limits and troubleshooting](#limits-and-troubleshooting)
18
+
19
+ ## Create a gate
20
+
21
+ 1. In **Studio → Pixie → Settings → Model**, choose the Pixie model. Gate tasks and `pixie ask` use it; `pixie judge` follows the [decision engine](#decision-engine) setting.
22
+ 2. In **Gates → Gate composition**, press **New gate** and pick a template. Each point has one representative template (instruction format check, agent message protocol, block risky commands, digest long tool results, verify the final answer); the blank gate is last. The switch on each card turns the gate on or off everywhere.
23
+ 3. Set **When** and **What Pixie does**. Write the task in plain words: whether to pass or stop, what to replace or add, and what note to show only to you.
24
+ 4. Put a sample in **Try it** and run it. The configured Pixie model really answers; nothing is recorded or sent to a session.
25
+ 5. Press **Apply**, then **Save** at the top of the page. Only saved gates apply to runs.
26
+ 6. **Gates → Scope** sets the script folder at the top and then lists the presets made in Studio. Gates not yet added to a Studio preset are collected at the bottom. Use **Add gate** on a preset to attach a gate, and the row switch to turn it on or off **for that preset only**. A gate can be attached to several presets; one preset's switch never affects another. Save to apply. A gate runs only for agents using those presets.
27
+
28
+ Only one enabled gate per preset and **When** is allowed (the page warns, and saving is refused). Saved definitions live in `<profile>/studio-data/pixie-gate/definitions.json`.
29
+
30
+ ## When, and how results apply
31
+
32
+ Pixie answers with five fields, all optional. Without a verdict the gate passes.
33
+
34
+ | Field | Meaning |
35
+ | --- | --- |
36
+ | Verdict | `pass` or `stop` |
37
+ | Reason | Why it stopped; the correction to make |
38
+ | Replacement | Text that replaces the target |
39
+ | Addition | Text sent along with the target |
40
+ | Note | Shown only to you |
41
+
42
+ Each point applies them in a fixed way. Output a point cannot apply becomes a note, not an error.
43
+
44
+ | When | Stop + reason | Replacement | Addition | Note |
45
+ | --- | --- | --- | --- | --- |
46
+ | You send an instruction | Input rejected; the run record keeps a restore card | Message replaced (optional confirmation) | Sent along | Recorded |
47
+ | Agents message each other | Input rejected | Message replaced | Sent along | Recorded |
48
+ | Before a tool runs | Execution denied (the reason reaches the agent) | As a note | As a note | Recorded |
49
+ | A tool result arrives | Result blocked (the reason reaches the agent) | Result replaced (not for structured results carrying a value) | Sent along | Recorded |
50
+ | The agent finishes its answer | Asked to redo it with the reason (per-turn limit) | As a note | As a note | Recorded |
51
+
52
+ When the verdict is stop, the replacement and addition never reach the main model. At message points the replacement becomes the rejection's suggestion and the addition becomes a note. Input or tools another hook already rejected do not run the gate.
53
+
54
+ ## Advanced options
55
+
56
+ | Option | Default | Description |
57
+ | --- | --- | --- |
58
+ | Pixie hook script | None | A script run before the task. See [below](#pixie-hook-scripts) |
59
+ | Show the result in the chat | On | Shows the result right under what the gate checked. See [Chat notes](#chat-notes-and-per-session-switches) |
60
+ | Confirm before replacing | Off | Stops a real replacement and shows it as a suggestion (message points) |
61
+ | If Pixie fails | Continue as usual | Continue as usual or stop it on model or script errors and timeouts |
62
+ | Target agents | Main agent (Subagents for agent messages) | Main agent, Subagents, or All |
63
+ | Time limit (seconds) | 60 | Script, helper, and model calls together |
64
+ | Redo limit per turn | 1 | Corrections per turn at the answer-end point |
65
+
66
+ ## Pixie hook scripts
67
+
68
+ Build flows the two fields cannot express — only certain tools, translate → judge → retranslate loops, external measurements, concluding from a judgment alone — as a script. Studio does not build features one by one; it gives scripts the means.
69
+
70
+ - **Location:** the default is `<profile>/studio-data/pixie-gate/commands/`; change it under **Gates → Scope → Script folder** to another absolute or `~/…` path, and use **Open folder** to show it in Finder or Explorer (when DSH runs on your desktop). Leave it empty to restore the default; the folder is not created for you. Only executable files (`chmod +x`) in that folder can be chosen. Subfolders, links pointing outside the folder, and names containing `..` are excluded. Press **Refresh list** after adding a file.
71
+ - **Supported environments:** available only when DSH runs with a bash profile (macOS and Linux). Windows is not supported yet; where scripts are unsupported the gate does not run them and applies its error policy.
72
+ - **Working directory and sandbox:** scripts run in the session working directory through the DSH shell service, under the session's sandbox policy. A read-only session cannot write files.
73
+ - **Trials** do not run the script because no session policy is known. Check it in a real session.
74
+
75
+ ### Input, output, exit codes
76
+
77
+ | Item | Rule |
78
+ | --- | --- |
79
+ | stdin | The target text (instruction, message, tool arguments JSON, tool result, final answer) |
80
+ | stdout | Use it in the task as `{{hooks.<name>.text}}`; only boundary newlines are removed; up to 256 KB |
81
+ | stdout is a JSON object | `{{hooks.<name>.data}}` holds that JSON; otherwise it is empty |
82
+ | exit 0 | Continue: Pixie runs the task |
83
+ | exit 10 | Skip this gate: the original flow continues, no model call |
84
+ | exit 11 | Use stdout as the gate output: no Pixie call. See below |
85
+ | Other, or timeout | Error: the error policy applies |
86
+
87
+ `<name>` is the file name without its last extension (`measure-subtitle.sh` → `measure-subtitle`). A task using an undefined variable cannot be saved.
88
+
89
+ **Exit 11 — the script concludes.** stdout must be the same JSON object Pixie returns, with optional `verdict` (`pass` or `stop`), `reason`, `replace`, `append`, and `note`. The [point rules](#when-and-how-results-apply) apply unchanged, and the run record shows **Concluded by** `Hook script`. Non-JSON output or an unknown field follows the error policy.
90
+
91
+ ```bash
92
+ printf '{"verdict":"stop","reason":"The form has no title line."}'; exit 11
93
+ ```
94
+
95
+ If the script always ends with exit 10 or 11, the **task** can stay empty. A gate with an empty task fails when its script exits 0.
96
+
97
+ ### Environment
98
+
99
+ | Variable | Value |
100
+ | --- | --- |
101
+ | `PIXIE_POINT` | `user-message`, `agent-message`, `tool-before`, `tool-after`, `turn-end` |
102
+ | `PIXIE_TOOL_NAME`, `PIXIE_TOOL_ARGS` | Tool name and arguments JSON at tool points |
103
+ | `PIXIE_AGENT` | `root` or `child` |
104
+ | `PIXIE_SESSION_ID`, `PIXIE_TURN` | Session ID and turn number |
105
+ | `PIXIE_GATE_NAME` | Gate name |
106
+ | `PIXIE_URL`, `PIXIE_TOKEN` | For the `pixie` helper; issued per run and revoked when the script ends |
107
+
108
+ ## The pixie helper
109
+
110
+ Inside a script, the `pixie` command calls the Pixie model. It is first on the script's `PATH` and needs curl.
111
+
112
+ ```sh
113
+ pixie ask "<instruction>" [--input]
114
+ pixie judge [--type bool|select|score] --question "<question>" [type arguments] [--json] [--input]
115
+ ```
116
+
117
+ - With `--input` the helper reads its input from stdin; otherwise it uses the gate target.
118
+ - `ask` prints the answer and exits 0, using the Pixie model.
119
+ - `judge` judges with the [decision engine](#decision-engine); types and output follow the table there.
120
+ - Usage, token, limit, and model errors exit 2 with a message on stderr. A failed helper call never decides the gate; the script's exit code does.
121
+ - Limits: 20 calls and 256 KB per request for each run. Calls follow the gate time limit and cancellation; their usage is added to the gate and listed under **Helper calls** in the run record.
122
+ - A token reaches only that run's ask and judge. The helper uses a Studio route on the DSH web server, so it is unavailable without one (for example, headless).
123
+
124
+ ## Decision engine
125
+
126
+ `pixie judge` uses the engine chosen in **Studio → Pixie → Gates → Decision engine**. A judgment runs only when a script asks for one, and the script decides what to do with the result.
127
+
128
+ | Engine | Description |
129
+ | --- | --- |
130
+ | LLM (default) | The judge model (the Pixie model when unset) answers in the Jev format. The judge system prompt can be changed |
131
+ | Jev | [TypeSafe Jev](https://docs.typesafe.ai/api) answers through its API. The model defaults to `jev-latest`; once thresholds are tuned, pin a version such as `jev-1.13.0`. **Gate input is sent to TypeSafe** |
132
+
133
+ **Jev API key:** paste it on the decision engine page and press **Save key**. It is stored in DSH credentials as `TYPESAFE_API_KEY` and never shown again. A `TYPESAFE_API_KEY` from the environment or `.env` is used instead and cannot be changed on the page. Without a valid key, `pixie judge` fails with exit 2.
134
+
135
+ | `--type` | Arguments | stdout | exit |
136
+ | --- | --- | --- | --- |
137
+ | `bool` (default) | `--threshold` (default 0.5); optional `--true "<what yes means>"`, `--false "<what no means>"` | "yes" probability | 0 at or above the threshold, 1 below |
138
+ | `select` | Two or more `--option name="description"` | The chosen option name | 0 |
139
+ | `score` | 2–10 `--level "description"`, lowest first | The score (from 0, may be fractional) | 0 |
140
+
141
+ - `--json` prints one JSON line `{"type","label","answer","engine"}`. `label` is `yes`/`no` for bool, the option name for select, and the nearest level number for score; `answer` holds the probabilities and confidence.
142
+ - Write the full judgment in `--question`; question IDs are not sent to the model. When the input has several parts, wrap them in JSON and name them in the question, such as `` `source` ``.
143
+ - A judgment error stays an error: it never becomes "no" or a low score, and exits 2.
144
+ - The previous `pixie judge --question … --threshold …` still works (`--type bool`).
145
+
146
+ ### The `judge` agent tool
147
+
148
+ The same decision engine is also an agent tool, `judge`. It is in Studio Master, and you can pick it in the preset editor's tool list. The built-in Optimized preset does not include it.
149
+
150
+ - Input is the Jev request shape as is: `{ state, questions: { <id>: { type, instructions, criteria } } }`, with the bool (`noul`), select (`choice`), and score types above.
151
+ - Output is per-question `answers` (probabilities and confidence), the engine used (`llm` or `jev`), and usage.
152
+ - It judges and never rewrites text. Use it to rank, filter, or verify, and let the agent do the editing (for example: score locale strings, rewrite only the low ones, judge again).
153
+ - A failed judgment comes back as a tool error, including when no engine is set or the Jev key is missing.
154
+
155
+ ## Example scripts
156
+
157
+ **Tool filter** (`only-search-tools.sh`, when a tool result arrives): run the gate only for long search results.
158
+
159
+ ```bash
160
+ #!/bin/bash
161
+ case "$PIXIE_TOOL_NAME" in grep|glob|web_search) ;; *) exit 10 ;; esac
162
+ size=$(wc -c)
163
+ [ "$size" -gt 4000 ] || exit 10
164
+ echo "$size"
165
+ ```
166
+
167
+ **Subtitle measurement** (`measure-subtitle.sh`, when you send an instruction): pass the measurement as JSON.
168
+
169
+ ```bash
170
+ #!/bin/bash
171
+ text=$(cat)
172
+ lines=$(printf '%s' "$text" | grep -c -- '-->' || true)
173
+ printf '{"cues":%d,"bytes":%d}\n' "$lines" "${#text}"
174
+ ```
175
+
176
+ Task: `Measured: {{hooks.measure-subtitle.data}}` …
177
+
178
+ **Translation check** (`translate-check.sh`, when the agent finishes its answer): if the answer is already Korean, one judgment ends it (exit 10); otherwise Pixie translates it and the decision engine judges faithfulness against the source. No Pixie task is written; exit 11 leaves the note directly, and the note appears [under the answer in the chat](#chat-notes-and-per-session-switches). If neither attempt passes, the last translation is kept with a `not verified` label (`충실도 미확인`). Helper errors (exit 2) become exit 1 so the error policy applies. Requires `jq` (included with macOS).
179
+
180
+ ```bash
181
+ #!/bin/bash
182
+ source=$(cat)
183
+ printf '%s' "$source" | pixie judge --question "Is the prose of this text written in Korean? Ignore code blocks, file paths, identifiers and command output." --threshold 0.8 --input >/dev/null
184
+ status=$?
185
+ [ "$status" -eq 0 ] && exit 10
186
+ [ "$status" -eq 2 ] && exit 1
187
+ for _ in 1 2; do
188
+ draft=$(printf '%s' "$source" | pixie ask "Translate this agent answer into natural Korean. Keep code blocks, file paths, identifiers, commands and numbers unchanged. Keep the Markdown structure. Output only the translation." --input) || exit 1
189
+ if jq -n --arg s "$source" --arg t "$draft" '{source:$s, translation:$t}' \
190
+ | pixie judge --question "Does \`translation\` keep every condition, number, negation and code element of \`source\`?" --threshold 0.7 --input >/dev/null; then
191
+ jq -n --arg t "$draft" '{note: ("[한국어 번역]\n" + $t)}'; exit 11
192
+ else
193
+ status=$?
194
+ [ "$status" -eq 2 ] && exit 1
195
+ fi
196
+ done
197
+ jq -n --arg t "$draft" '{note: ("[한국어 번역 — 충실도 미확인]\n" + $t)}'
198
+ exit 11
199
+ ```
200
+
201
+ An answer that mixes Korean and English gets a middle Korean probability, so it is translated and may score low on faithfulness. Lower the first threshold (0.8) to skip mixed answers.
202
+
203
+ **Completion claim audit** (`claim-check.sh`, when the agent finishes its answer): judges with select whether the answer's test-pass claim matches the last recorded run. A contradiction asks for a redo, missing evidence leaves a note, and low confidence hands over to Pixie with exit 0. Adapt the run record file (`.last-test-run`) to your project.
204
+
205
+ ```bash
206
+ #!/bin/bash
207
+ answer=$(cat)
208
+ evidence=$(cat .last-test-run 2>/dev/null || echo "no recorded test run")
209
+ result=$(jq -n --arg a "$answer" --arg e "$evidence" '{answer:$a, evidence:$e}' | pixie judge --type select --json --input \
210
+ --question "Is the claim in \`answer\` that tests passed supported by \`evidence\`?" \
211
+ --option supported="evidence shows the claimed tests ran and passed, or answer makes no test claim" \
212
+ --option contradicted="evidence shows a failure or a different run" \
213
+ --option missing="answer claims tests passed but evidence has no run") || exit 1
214
+ case "$(jq -r .label <<<"$result")" in
215
+ supported) exit 10 ;;
216
+ contradicted) printf '{"verdict":"stop","reason":"The test results contradict the claim. Check the actual results and report again."}'; exit 11 ;;
217
+ missing) [ "$(jq '.answer.confidence < 0.6' <<<"$result")" = true ] && { printf '%s' "$result"; exit 0; }
218
+ printf '{"note":"No recorded test run."}'; exit 11 ;;
219
+ esac
220
+ ```
221
+
222
+ Task for a gate using this script (runs only on low confidence): `Read {{hooks.claim-check.data}}; stop with a reason if the test claim is unsupported.`
223
+
224
+ **Changed files** (`list-changed-files.sh`, when the agent finishes its answer): report git changes in the working directory.
225
+
226
+ ```bash
227
+ #!/bin/bash
228
+ git status --porcelain 2>/dev/null | head -50
229
+ ```
230
+
231
+ ## Agent skill
232
+
233
+ On start, Studio installs a skill with this guide and the hook rules into `<DSH home>/skills/studio-pixie-hook-guide/` (`~/.dsh/skills/` by default). Ask an agent something like "build a Pixie gate that checks translations" and it reads the skill to help you choose the point, write the script, use `pixie judge`, and follow the exit 0/10/11 rules.
234
+
235
+ - It holds `SKILL.md` (the rules) and `guide.md` (this guide).
236
+ - Updating Studio updates the skill. Files you edited are never overwritten; to get the Studio version back, delete that file and restart DSH.
237
+
238
+ ## Chat notes and per-session switches
239
+
240
+ **Chat notes:** a gate with **Show the result in the chat** on (Advanced; on by default) shows its result as a block right under what it checked, whether the script (exit 11) or Pixie concluded it. The setting decides; the output does not. The block is drawn from Studio's gate records and is never written to the session log.
241
+
242
+ | Point | Where the block appears |
243
+ | --- | --- |
244
+ | You send an instruction / agents message each other | Right under that message, outside the turn's folded steps. A subagent's message shows in the subagent's chat |
245
+ | Before a tool runs / a tool result arrives | Right under that tool call, inside the turn's steps (expand the turn to see it). Before and after results of one call show together |
246
+ | The agent finishes its answer | Right under that turn's answer |
247
+
248
+ A rejected instruction has no message in the chat, so its result stays in the Pixie tab only.
249
+
250
+ ![Gate results under the instruction, the Read and Bash calls, and the answer](../images/en/pixie-gate-chat-results.png)
251
+
252
+ When the turn is folded, the instruction and answer results stay visible; tool results fold with the steps.
253
+
254
+ ![The same turn folded](../images/en/pixie-gate-chat-results-folded.png)
255
+
256
+ Turn the setting off in the gate editor under **Advanced → Show the result in the chat**. The gate still runs and its record stays in the Pixie tab.
257
+
258
+ ![Show the result in the chat](../images/en/pixie-gate-show-in-chat.png)
259
+
260
+ - The block shows the note when there is one, for example a translation. Without a note it shows the verdict with its reason, and any replacement or addition in a collapsed section. A failed run shows one error line.
261
+ - If the note's first line starts with a bracketed label such as `[한국어 번역]`, the label becomes the block title. A label containing `not verified` (or `미확인`) gets a **not verified** badge.
262
+ - The body renders as Markdown. The block offers **Hide**, **Open in Pixie tab**, and **Turn off in this session**.
263
+ - It appears after the gate finishes; there is no progress indicator. Skipped turns (exit 10), cancelled runs, and runs whose gate had the setting off get no block. Each run keeps the setting it started with. If a gate ran more than once at the same place, only the last result shows.
264
+ - The result block does not change the checked message, tool call, or answer. **Hide** collapses only the gate result.
265
+
266
+ **Per-session switches:** at the top of **Pixie** tab → **Gates**, **Gates in this session** lists every gate that applies to this session's preset with a switch that turns it off for this session only. **Turn off in this session** on a chat block is the same switch.
267
+
268
+ - A gate switched off does not run at any point in this session: no script, Pixie, or decision engine call, and no record. It applies from the next message; no restart is needed.
269
+ - Gate definitions, preset attachments, and other sessions do not change. A new session starts with the preset's settings.
270
+ - The list shows gates that are switched on, attached to this preset, and not switched off for it.
271
+
272
+ ## Run records
273
+
274
+ The gate records in the session's right-side **Pixie** tab list each run. The detail shows the action actually applied (replaced, appended, rejected, blocked, steered, none), who concluded (Pixie, hook script, skipped by hook), the five output fields, token usage, original and final text, notes, and helper calls. Helper calls also show each `pixie judge` type, chosen value, engine, and confidence. When a script concluded the run, the output section is titled **Script output**. For a rejected input, **Edit and send** puts the suggestion (or the original) into the composer.
275
+
276
+ ## Limits and troubleshooting
277
+
278
+ - **A gate does not run.** Check that it is on, has a preset, and is saved; that the session runs that preset; that the target agents (root or child) match; and that it is not off in **Gates in this session**. Without a Pixie model the error policy applies.
279
+ - **`hook-script-unsupported`** means no bash executor is available.
280
+ - **`Session sandbox policy and cwd are required`** means the session policy is unknown.
281
+ - **`pixie: helper is not available`** means there is no web server, or the command ran outside a script run.
282
+ - **`pixie: HTTP 401`** means the run already ended or the token belongs to another run. **429** is the call limit; **413** is the request size limit.
283
+ - **`Jev API key is not configured`** means the decision engine is Jev and `TYPESAFE_API_KEY` is missing. **`Jev request failed: HTTP 401`** means a wrong key; **422** means a malformed question.
284
+ - **Saving the key reports an empty `refs:` line.** Change the bare `refs:` line in the DSH credentials file (`.credentials.yaml` in the DSH home) to `refs: {}` and save again. DSH cannot add a key under a `refs:` line with no value.
285
+ - **`Hook script exit 11 needs a gate output JSON`** means the stdout of an exit 11 is not gate output JSON.
286
+ - Sandboxes that block local network access can make helper calls fail.
287
+ - Background tasks (pre-compaction, file pre-indexing) are not supported yet.