Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"name": "tinyfish",
"source": "./plugins/tinyfish",
"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.",
"version": "1.2.3",
"version": "1.2.4",
"author": {
"name": "TinyFish",
"url": "https://tinyfish.ai"
Expand Down
2 changes: 1 addition & 1 deletion plugins/tinyfish/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tinyfish",
"version": "1.2.3",
"version": "1.2.4",
"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.",
"author": {
"name": "TinyFish",
Expand Down
12 changes: 12 additions & 0 deletions plugins/tinyfish/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## 1.2.4 (2026-08-18)

### Fixed
- 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.
- 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.
- Plugin README lists `~/.grok` among the config directories doctor reads; the CLI added a grok harness.
- Skill: `/tinyfish:doctor` scopes the Cursor `unattended_safe` caveat to `2` and `3`; the CLI still gates `connect cursor` on its own authenticated call.
- 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.
- 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.
- 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.
- Plugin README: `doctor` reports every run to TinyFish, not only when a repair runs, and diagnosis makes authenticated calls rather than only reading config.

## 1.2.3 (2026-08-17)

### Changed
Expand Down
2 changes: 1 addition & 1 deletion plugins/tinyfish/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ TinyFish's privacy policy: https://www.tinyfish.ai/privacy-policy

The two setup skills do touch your machine:

- **`/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.
- **`/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.
- **`/tinyfish:feedback`** shells out to `gh issue create` against a public repo, after showing you the exact issue text and waiting for your approval.
63 changes: 36 additions & 27 deletions plugins/tinyfish/skills/doctor/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Diagnose and repair your TinyFish setup — MCP registration, auth,

# TinyFish Doctor

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

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

## 1. Run doctor

```
```sh
npx -y @tiny-fish/cli@latest doctor --harness claude-code
```

JSON on stdout: `schema_version`, `checks[]`, `harnesses[]`, `repairs[]`.
JSON on stdout: `schema_version`, `cli_version`, `ok_harnesses`, `ok_cli`, `checks[]`,
`harnesses[]`, `repairs[]`.

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

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

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

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

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

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

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

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

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

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

## 3. Repair

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

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

Expand Down
16 changes: 9 additions & 7 deletions plugins/tinyfish/skills/feedback/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ doctor produced no JSON — say so instead of attaching an empty report.

## Structure

```
```markdown
### What I was doing
### What happened
Expand All @@ -40,12 +40,14 @@ filing. Any edit they request happens before filing.

## File

- Preferred: write the body to a file, then
`gh issue create --repo tinyfish-io/tinyfish-cookbook --title "<short
summary>" --body-file <path>` (only if `gh` is installed and
authenticated). Never interpolate the body into the command — it carries
the user's free-form text and doctor's JSON, and backticks or `$(…)` in
either would be evaluated by your shell.
- Preferred: write the body and the title to files, then `gh issue create
--repo tinyfish-io/tinyfish-cookbook --title "$(cat "$title_file")"
--body-file "$body_file"` (only if `gh` is installed and authenticated).
Both values come from the user's free-form text (the body also carries
doctor's JSON), so neither may reach the shell as literal text — including
in a `title=…` assignment, where backticks or `$(…)` are evaluated just the
same. `cat`'s output is not re-parsed. Never build the command as a string
or run it through `eval`.
- Fallback: open a prefilled issue URL
(`https://github.com/tinyfish-io/tinyfish-cookbook/issues/new?title=…&body=…`).
Percent-encode both values — an unencoded `#` truncates the body and `&`
Expand Down
3 changes: 2 additions & 1 deletion scripts/generate-harness-skills.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const GENERIC_REAUTH = `re-authenticate in the harness itself.
| Codex, Hermes | no login command — auth runs on first tool use; trigger a TinyFish tool and finish the browser sign-in |
| OpenCode | \`opencode mcp auth tinyfish\` |
| Claude Code | \`/mcp\` in-app, or \`claude mcp login tinyfish\` |
| 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 |
| OpenClaw, Cursor | key-based — \`tinyfish auth login\`, then \`tinyfish connect <harness>\` to rewrite the header |`;

const TARGETS = {
Expand All @@ -34,7 +35,7 @@ const TARGETS = {
vars: {
HARNESS_FLAG: "",
HARNESS_ENTRY:
"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.",
"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.",
REAUTH: GENERIC_REAUTH,
FEEDBACK: "file it at https://github.com/tinyfish-io/tinyfish-cookbook/issues",
},
Expand Down
Loading
Loading