Skip to content

Commit d58743b

Browse files
londondavilaclaude
andauthored
Doctor skill: track schema_version 3, quote the gh issue title, list ~/.grok (#262)
doctor still described `schema_version` 1 and 2 + bailed above 2, but CLI emitted 3 since 0.22.0 and skill pins `@tiny-fish/cli@latest`. as shipped it degraded to `--pretty` on every run. The feedback skill also passed an unquoted, user-derived title to `gh issue create`. three fixes landed in tinyfish-web-agent-integrations#29; this keeps the two copies of the plugin textually identical - `doctor`: schema 3 — `cli_version`, `ok_harnesses`/`ok_cli`, `checks[].scope`, `repairs[].action`, and the exit code coming from the harness scope alone, so `ok_cli: false` beside exit `0` is a real state. Drops the `registered, API key present but unverified` string the CLI no longer emits; `--fix` examples run through `npx` like step 1. - `feedback`: `--title "$title" --body-file "$body_file"`, injection warning widened to the title, and `eval` / constructed command strings prohibited. - `plugins/tinyfish/README.md`: adds `~/.grok` to the config dirs doctor reads, per the CLI's `CONFIG_DIRS`. The rest of that list matches. - 1.2.3 → 1.2.4 in `plugin.json` and the marketplace entry — `validate-skills.mjs` fails if they diverge --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent e03714c commit d58743b

10 files changed

Lines changed: 145 additions & 100 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"name": "tinyfish",
1515
"source": "./plugins/tinyfish",
1616
"description": "The complete web toolkit for your agent. Search the web, fetch clean content from URLs, automate browsers with natural language, and spin up headless browsers for full programmatic control.",
17-
"version": "1.2.3",
17+
"version": "1.2.4",
1818
"author": {
1919
"name": "TinyFish",
2020
"url": "https://tinyfish.ai"

plugins/tinyfish/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tinyfish",
3-
"version": "1.2.3",
3+
"version": "1.2.4",
44
"description": "The complete web toolkit for your agent. Search the web and get answers in milliseconds. Fetch any URL and get clean markdown content back. Send a browser agent to navigate sites, fill forms, and extract structured data. Spin up a headless browser for full programmatic control when you need it.",
55
"author": {
66
"name": "TinyFish",

plugins/tinyfish/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## 1.2.4 (2026-08-18)
4+
5+
### Fixed
6+
- Skill: `/tinyfish:doctor` describes `schema_version` `3` (CLI 0.22+). It still said `1` and `2` and bailed above `2`, so with `@latest` pinned it degraded every run to `--pretty`. Adds the two verdicts (`ok_harnesses`, `ok_cli`), `checks[].scope`, `repairs[].action`, and the exit code coming from the harness scope alone — `ok_cli: false` beside exit `0` is a real state. Drops the `registered, API key present but unverified` string the CLI no longer emits, and runs the `--fix` examples through `npx` like step 1.
7+
- Skill: `/tinyfish:feedback` quotes the title as well as the body: `--title "$title" --body-file "$body_file"`. The summary is derived from the user's free-form text too, so backticks or `$(…)` in it were evaluated by the filing shell. Also prohibits `eval` and constructed command strings.
8+
- Plugin README lists `~/.grok` among the config directories doctor reads; the CLI added a grok harness.
9+
- Skill: `/tinyfish:doctor` scopes the Cursor `unattended_safe` caveat to `2` and `3`; the CLI still gates `connect cursor` on its own authenticated call.
10+
- Skill: `/tinyfish:doctor` reads reach off `proves_harness_reach` rather than off `auth_mode`. A harness whose own client reports a live connection is wire evidence — Claude Code on OAuth included — and the skill was telling the agent to report it as unverified presence.
11+
- Skill: `/tinyfish:doctor` says to prefix `repairs[].command`; the CLI emits bare `tinyfish …`, which is not on PATH on the npx-only installs the skill is written for.
12+
- Skill: `/tinyfish:feedback` writes the title to a file like the body. A `title=…` assignment evaluates backticks and `$(…)` exactly as the command line does, so quoting the expansion alone moved the injection upstream rather than closing it.
13+
- Plugin README: `doctor` reports every run to TinyFish, not only when a repair runs, and diagnosis makes authenticated calls rather than only reading config.
14+
315
## 1.2.3 (2026-08-17)
416

517
### Changed

plugins/tinyfish/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ TinyFish's privacy policy: https://www.tinyfish.ai/privacy-policy
2929

3030
The two setup skills do touch your machine:
3131

32-
- **`/tinyfish:doctor`** runs the TinyFish CLI, which reads your agent config directories (`~/.claude`, `~/.codex`, `~/.cursor`, `~/.hermes`, `~/.openclaw`, `~/.config/opencode`) and the CLI credential store (`~/.tinyfish/config.json`) to find where TinyFish is registered. Diagnosis only reads; the repair step rewrites those registrations, and only commands the CLI itself proposes. `doctor` sends no analytics, though a repair re-runs `tinyfish connect`, which does — set `TINYFISH_NO_TELEMETRY` to suppress it.
32+
- **`/tinyfish:doctor`** runs the TinyFish CLI, which reads your agent config directories (`~/.claude`, `~/.codex`, `~/.cursor`, `~/.grok`, `~/.hermes`, `~/.openclaw`, `~/.config/opencode`) and the CLI credential store (`~/.tinyfish/config.json`) to find where TinyFish is registered. Diagnosis reads those files and makes authenticated calls to TinyFish to test what it found; the repair step rewrites the registrations, and only commands the CLI itself proposes. `doctor` reports its own run to TinyFish — set `TINYFISH_NO_TELEMETRY` to suppress that and the `tinyfish connect` a repair re-runs.
3333
- **`/tinyfish:feedback`** shells out to `gh issue create` against a public repo, after showing you the exact issue text and waiting for your approval.

plugins/tinyfish/skills/doctor/SKILL.md

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Diagnose and repair your TinyFish setup — MCP registration, auth,
55

66
# TinyFish Doctor
77

8-
`tinyfish doctor` (CLI 0.18+) owns the diagnosis. Your job is to run it, do the one
8+
`tinyfish doctor` (CLI 0.22+) owns the diagnosis. Your job is to run it, do the one
99
check it structurally cannot do, and act on what comes back. Never hand-edit config
1010
files — every repair goes through the CLI, which carries backup and merge rigor.
1111

@@ -17,40 +17,46 @@ the command from step 1 to run themselves.
1717

1818
## 1. Run doctor
1919

20-
```
20+
```sh
2121
npx -y @tiny-fish/cli@latest doctor --harness claude-code
2222
```
2323

24-
JSON on stdout: `schema_version`, `checks[]`, `harnesses[]`, `repairs[]`.
24+
JSON on stdout: `schema_version`, `cli_version`, `ok_harnesses`, `ok_cli`, `checks[]`,
25+
`harnesses[]`, `repairs[]`.
2526

26-
Read `schema_version` before the fields. This skill describes `1` and `2`. The command pins
27-
`@latest`, so a newer CLI can hand you a shape you do not know: above `2`, stop reading
28-
fields, show the user `--pretty` output instead, and rely on step 2 for the verdict.
27+
Read `schema_version` before the fields. This skill describes `3` (CLI 0.22+). The command
28+
pins `@latest`, so a newer CLI can hand you a shape you do not know: above `3`, stop reading
29+
fields, show the user `--pretty` output instead, and rely on step 2 for the verdict. Below
30+
`3` a single `ok` replaces the two verdicts and `checks[]` carry no `scope`, so read only
31+
`checks[]` and the exit code there.
2932

30-
The difference between the two is what a keyed registration proves. `2` tests an API-key
31-
registration on the wire, so a stale key header fails outright and earns a `connect` repair.
32-
`1` passes it on config presence alone, and step 2 is the only thing that catches it.
33+
**Two verdicts, not one.** `ok_harnesses` answers whether the user's agents can reach
34+
TinyFish; `ok_cli` answers whether the CLI's own credential works. `checks[].scope`
35+
(`harness`, `cli`, `info`) says which one a check counts toward, and only the harness scope
36+
moves the exit code — `ok_cli: false` beside exit `0` is a real state, not a contradiction.
37+
Report it as the CLI's own credential, not as a broken harness.
3338

3439
| Exit | Meaning |
3540
|---|---|
36-
| `0` | every check passed |
37-
| `1` | a check failed — read `checks[]` |
41+
| `0` | no harness check failed — `ok_cli` can still be `false` |
42+
| `1` | a harness check failed — read `checks[]` |
3843
| `2` | doctor could not run; **stdout is empty**, the reason is on stderr |
3944

4045
A `warn` is not a failure and does not move the exit code: doctor is saying it could not
41-
check something, not that it is broken. On `2`, `registered, API key present but unverified`
42-
means the key exists but doctor cannot read its value to test it, which is every Codex
43-
install and any harness whose config redacts the header. Never repair on a warn, prove it
44-
in step 2.
46+
check something, not that it is broken. A registration warn whose detail says the key was
47+
not readable, or was not verified, means the key exists but doctor could not test its value
48+
— every Codex install, and any harness whose config redacts the header. Never repair on a
49+
warn, prove it in step 2.
4550

4651
`--pretty` only when showing a human the list. Never put `--debug` output in a report —
4752
it is the one channel carrying raw stacks and absolute paths.
4853

4954
## 2. Prove the harness reach — the part doctor cannot do
5055

5156
`harnesses[].proves_harness_reach` is `false` whenever doctor could not prove that *this*
52-
harness authenticates. For OAuth harnesses it is always false, because the CLI cannot borrow
53-
the harness's token. You are the only one who can close that gap.
57+
harness authenticates. It is `true` only where the harness's own client reports a live
58+
connection, or where a key doctor could read verified on the wire — the CLI cannot borrow an
59+
OAuth token, so every harness that reports no connection state leaves the gap to you.
5460

5561
`--harness claude-code` narrows `harnesses[]` to exactly one entry, so there is no ambiguity about which harness it describes.
5662

@@ -68,25 +74,28 @@ namespace names it.
6874
| Auth error, but doctor says `registered: yes` | Registration exists; the credential behind it is broken |
6975
| TinyFish tools absent entirely | Server not loaded in this session — the user must restart the agent |
7076

71-
What a `registration: pass` proves depends on `schema_version`. On `2` an API-key
77+
What a `registration: pass` proves depends on `schema_version`. On `2` and `3` an API-key
7278
registration was tested on the wire, so a stale key header is already a `fail` with a
73-
`connect` repair beside it. On `1`, and on every OAuth or `auth_mode: unknown` registration
74-
at either version, pass is presence only: doctor read config, not the wire, and a stale key
75-
still passes while every call 401s. Neither version says anything about siblings, and a
79+
`connect` repair beside it. A pass carrying `proves_harness_reach: true` is the harness's own
80+
client reporting a live connection — wire evidence at any version, whatever `auth_mode` says.
81+
Every other pass is presence only: doctor read config, not the wire, and a stale key still
82+
passes while every call 401s. No version says anything about siblings, and a
7683
healthy sibling will answer cheerfully while the broken one stays broken.
7784

7885
## 3. Repair
7986

80-
Run only commands that appear in `repairs[]`, and show `command` before running it. Keep
81-
the order they arrive in: `auth login` comes before `connect` because `connect` writes
82-
whichever key is stored, so a dead one has to be replaced first.
87+
Run only commands that appear in `repairs[]`, and show `command` before running it. They
88+
arrive as bare `tinyfish …`, which is not on PATH under `npx` — swap that leading word for
89+
`npx -y @tiny-fish/cli@latest` when there is no global install. Keep
90+
the order they arrive in: `action: auth-login` comes before `action: connect` because
91+
`connect` writes whichever key is stored, so a dead one has to be replaced first.
8392

84-
- Terminal with the user present → `doctor --fix --harness claude-code`
85-
- Non-interactive → `doctor --fix --yes`; only `unattended_safe: true` repairs run and the
93+
- Terminal with the user present → `npx -y @tiny-fish/cli@latest doctor --fix --harness claude-code`
94+
- Non-interactive → `npx -y @tiny-fish/cli@latest doctor --fix --yes`; only `unattended_safe: true` repairs run and the
8695
rest return as skipped. Never report a skipped repair as a fix.
8796
- `unattended_safe: false` → hand it to the user, do not run it. Expect most repairs to be
8897
false: `auth login` always is, and `connect <harness>` is unsafe for every harness except
89-
Cursor — and on `2` Cursor only while the CLI's own authenticated call passes, since a
98+
Cursor — and on `2` and `3` Cursor only while the CLI's own authenticated call passes, since a
9099
revoked key still resolves as a credential. Read the field, do not infer it.
91100
- OAuth credential failures have no CLI repair: tell the user to run `/mcp`, pick tinyfish, and sign in.
92101

plugins/tinyfish/skills/feedback/SKILL.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ doctor produced no JSON — say so instead of attaching an empty report.
2020

2121
## Structure
2222

23-
```
23+
```markdown
2424
### What I was doing
2525
2626
### What happened
@@ -40,12 +40,14 @@ filing. Any edit they request happens before filing.
4040

4141
## File
4242

43-
- Preferred: write the body to a file, then
44-
`gh issue create --repo tinyfish-io/tinyfish-cookbook --title "<short
45-
summary>" --body-file <path>` (only if `gh` is installed and
46-
authenticated). Never interpolate the body into the command — it carries
47-
the user's free-form text and doctor's JSON, and backticks or `$(…)` in
48-
either would be evaluated by your shell.
43+
- Preferred: write the body and the title to files, then `gh issue create
44+
--repo tinyfish-io/tinyfish-cookbook --title "$(cat "$title_file")"
45+
--body-file "$body_file"` (only if `gh` is installed and authenticated).
46+
Both values come from the user's free-form text (the body also carries
47+
doctor's JSON), so neither may reach the shell as literal text — including
48+
in a `title=…` assignment, where backticks or `$(…)` are evaluated just the
49+
same. `cat`'s output is not re-parsed. Never build the command as a string
50+
or run it through `eval`.
4951
- Fallback: open a prefilled issue URL
5052
(`https://github.com/tinyfish-io/tinyfish-cookbook/issues/new?title=…&body=…`).
5153
Percent-encode both values — an unencoded `#` truncates the body and `&`

scripts/generate-harness-skills.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const GENERIC_REAUTH = `re-authenticate in the harness itself.
1717
| Codex, Hermes | no login command — auth runs on first tool use; trigger a TinyFish tool and finish the browser sign-in |
1818
| OpenCode | \`opencode mcp auth tinyfish\` |
1919
| Claude Code | \`/mcp\` in-app, or \`claude mcp login tinyfish\` |
20+
| Grok | no login command — in Grok Build, \`/mcps\`, select \`tinyfish\`, press \`i\`. A keyed registration instead reads \`TINYFISH_API_KEY\` from Grok's environment and has no OAuth fallback: re-run \`tinyfish connect grok --api-key <key>\` and start Grok from a new terminal |
2021
| OpenClaw, Cursor | key-based — \`tinyfish auth login\`, then \`tinyfish connect <harness>\` to rewrite the header |`;
2122

2223
const TARGETS = {
@@ -34,7 +35,7 @@ const TARGETS = {
3435
vars: {
3536
HARNESS_FLAG: "",
3637
HARNESS_ENTRY:
37-
"Run without `--harness`, so `harnesses[]` carries one entry per harness doctor knows — installed or not. Read the entry whose `harness` matches the agent you are running in, never the first one, and check its `detected` first: an absent harness reports `detected: false`, `registered: \"no\"`, `auth_mode: \"unknown\"`, which is not a fault to repair. doctor only knows `claude-code`, `codex`, `cursor`, `hermes`, `openclaw`, `opencode`; if you are none of those, no entry describes you and step 2 is your only evidence.",
38+
"Run without `--harness`, so `harnesses[]` carries one entry per harness doctor knows — installed or not. Read the entry whose `harness` matches the agent you are running in, never the first one, and check its `detected` first: an absent harness reports `detected: false`, `registered: \"no\"`, `auth_mode: \"unknown\"`, which is not a fault to repair. doctor only knows `claude-code`, `codex`, `cursor`, `grok`, `hermes`, `openclaw`, `opencode`; if you are none of those, no entry describes you and step 2 is your only evidence.",
3839
REAUTH: GENERIC_REAUTH,
3940
FEEDBACK: "file it at https://github.com/tinyfish-io/tinyfish-cookbook/issues",
4041
},

0 commit comments

Comments
 (0)