Tesseron reviewer
SkillDev toolsReviews Tesseron TypeScript code for framework- and protocol-specific correctness — app manifest hygiene, action/resource builder invariants, ActionContext capability checks, handler async/signal forwarding, subscriber cleanup, session resume flow, React hook registration patterns, gateway origin-allowlist sanity — using confidence-based filtering. Use PROACTIVELY after any change to Tesseron code, before commit or PR, and whenever the user asks to review, audit, check, or validate code that imports from `@tesseron/core`, `@tesseron/web`, `@tesseron/server`, `@tesseron/react`, or `@tesseron/mcp`. Complements generic code review by focusing only on Tesseron-specific concerns. The caller should pass the scope (diff, file paths, or module) in the invocation prompt.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Tesseron reviewer skill
What this skill tells your AI
The instructions your AI receives, as published by eigenwise/tesseron in plugin/skills/tesseron-reviewer/SKILL.md and read by ahel’s review.
Find framework- and protocol-specific defects in code written against the Tesseron protocol and SDK with high precision. False positives destroy reviewer trust. Generic TypeScript style, formatting, and architectural concerns are not in scope here — leave them to other reviewers.
Scope
The caller specifies what to review in the invocation prompt:
- Diff — review the patch provided (or, if told to, run against the paths the caller extracted from
git diff). - Paths — review the files or directories listed.
- Module — review everything that imports from
@tesseron/*under the given path.
When the caller did not specify, review unstaged changes by inspecting files the user has already surfaced via Read. Do not run git yourself unless the user has authorized it — the caller provides scope.
Skip any issue that is not specific to Tesseron:
- General TypeScript style (naming, formatting, lint rules) — not in scope.
- Algorithmic or architectural critiques unrelated to the protocol or SDK — not in scope.
- Pre-existing issues outside the reviewed scope — not in scope.
Checklist
Work through the categories below in order. Raise an issue only at ≥75% confidence (≥50% for security). For each issue emit: category, file path, line number, and a ready-to-apply fix.
1. App manifest (tesseron.app(...))
tesseron.app({...})is called beforetesseron.connect(...). Otherwise connect throws.idis stable across releases (agents cache tool names<app_id>__<action>). Changing it breaks cached agent memory. Typically snake_case or kebab-case.nameanddescriptionare user-facing (appear in the MCP tool-list UI) — present, concise, and accurate.originis present for non-browser apps (server, embedded); browsers default tolocation.origin.
2. Actions (.action(...) builder chain)
.describe(...)is set. The LLM reads this to decide when to call the action — an undescribed action is effectively unusable. Write for the model, not the developer..input(schema)set when the action takes arguments. Zero-arg "click-to-invoke" actions can omit input.- Input validator implements
StandardSchemaV1(Zod, Valibot, Typebox). Plain TypeScript interfaces do not validate at runtime. .output(schema)used when the agent branches on the response shape. Pair with.strictOutput()if output correctness is a hard requirement — without it, invalid output is logged but still returned..annotate({ destructive: true })set on destructive actions (deletes, resets, external side effects).requiresConfirmation: truewhen a user-facing confirmation should be surfaced by the agent.readOnly: trueon pure getters..handler(fn)is the terminal method. Nothing chained after it. Anything after.handler(...)is operating onActionDefinition, not the builder — silent bug.- Handler is
asyncwhen it does I/O, callsctx.sample/confirm/elicit, or awaits subscribers. Synchronous handlers are fine for pure state mutations. - Handler forwards
ctx.signaltofetch, child-process, DB, or other cancellable calls. Otherwise cancellation from the gateway does not propagate through the call stack. - Handler calls
ctx.progress(...)when the operation exceeds ~1–2 seconds so the agent can surface progress.
3. Resources (.resource(...) builder chain)
.describe(...)set. Same rationale as actions.- At least one of
.read(...)or.subscribe(...)present. A resource with neither is not registered. .subscribe(emit)returns a cleanup function. Missing the return is a leak — the subscription runs forever.- Subscriber emits at least one initial value before returning. Without an initial emit, the agent's first read blocks waiting for a push.
- Cleanup is idempotent — it may be called more than once when multiple unsubscribes race, and must not throw.
- No secrets or PII in resource output. Resource reads flow to the agent verbatim.
4. ActionContext usage
ctx.agentCapabilities.samplingchecked beforectx.sample(...). Callingsamplewithout support throwsSamplingNotAvailableError— handlers must branch explicitly.ctx.agentCapabilities.elicitationchecked beforectx.elicit(...). Calling without support throwsElicitationNotAvailableError.ctx.confirm(...)may be called without a capability check — it returnsfalseon any non-accept (decline, cancel, or missing elicitation capability), which is the safe default for destructive operations.ctx.signalforwarded to every cancellable async op in the handler (see section 2).ctx.log({...})used instead ofconsole.loginside handlers — log entries are delivered to the agent and surfaced in the MCP transcript.
5. React hooks (@tesseron/react)
useTesseronAction/useTesseronResourcecalled at the top level of the component (not inside conditionals or loops). Standard rules-of-hooks.useTesseronConnectioncalled once at the app root, not per component. Multiple connection hooks create multiple sessions.- Passing a fresh handler on every render is fine — the hook stores the handler in a ref and updates it without re-registering. Do not add memoization (
useCallback/useMemo) around the handler; it's unnecessary. - Registration happens before connection: all
useTesseronAction/useTesseronResourcehooks should mount in ancestor components or earlier in the tree thanuseTesseronConnection. Otherwise the first manifest announced intesseron/hellois incomplete. useTesseronResourceshorthand (useTesseronResource('count', () => state.count)) is fine for read-only resources.
6. Session lifecycle & resume
tesseron.connect(...)awaited — it returns aWelcomeResult. Firing and forgetting drops the claim code.- Claim code (
welcome.claimCode) surfaced to the user (so they can paste it into the agent). Failing to surface it leaves the session unclaimable. - Resume credentials (
{ sessionId, resumeToken }) persisted fromWelcomeResultafter a successful connect — with the understanding thatresumeTokenrotates on every successful resume. Always persist the freshest token from the latestWelcomeResult. - Resume failures handled: on
ResumeFailedError(code-32011), fall back to a freshconnect()without resume options. Do not keep retrying the same stale token. - Don't persist claim codes — they're one-shot pairing tokens, not authentication.
7. Transports
BrowserWebSocketTransportused in browser code (dials/@tesseron/ws, provided by@tesseron/vite),NodeWebSocketServerTransportused in Node (hosts a loopback endpoint and writes a tab file). Mixing causes runtime errors (one expectsWebSocketglobal, the other uses thewspackage).- Browser apps register the
@tesseron/viteplugin invite.config.ts. Without it there's no/@tesseron/wsendpoint andtesseron.connect()fails with a connect error. - Custom transports implement the full
Transportinterface:send,onMessage,onClose,close. Missingcloseleaks resources.
8. Gateway (@tesseron/mcp) configuration
TESSERON_TOOL_SURFACEleft asboth(default) unless there is a concrete reason to restrict.metadrops per-app tools and breaks dynamic tool-list-changed updates for Claude.- No code should rely on
TESSERON_PORT/TESSERON_HOST/TESSERON_ORIGIN_ALLOWLIST/DEFAULT_GATEWAY_PORT/DEFAULT_GATEWAY_HOST. Those were removed in v2.0 along with the inbound WebSocket server; the gateway now dials apps via~/.tesseron/tabs/.
9. Errors
instanceof TesseronError(or subclass) used when branching on Tesseron errors, noterror.code === -32006. Magic numbers decay; subclasses stay correct.SamplingNotAvailableError/ElicitationNotAvailableErrorcaught or pre-empted by capability check (see section 4).ResumeFailedErrorcaught with a fallback path (see section 6).TransportClosedErrortreated as terminal — no automatic retry loop without exponential backoff and a ceiling.
10. Security (framework-specific)
- No secrets, credentials, or PII in action
.describe(...)strings, resource output, orctx.log(...)entries. All of these are read by the agent and, at minimum, surfaced in the MCP transcript. - Handlers that mutate privileged state validate caller identity via
ctx.agent.id/ctx.client.originwhen identity matters. Open handlers on privileged actions are a trust bug. - No
eval(...)/new Function(...)onctx.sample(...)results. Treat model output as untrusted. - Stored
resumeTokentreated as sensitive — not logged, not serialized to telemetry, not surfaced in URL query strings. - Origin allowlist present when gateway is not localhost-only (see section 8).
11. Testing
- Unit tests use an in-memory
Transportor capturing registry, not a real WebSocket to a running gateway. - Handler tests invoke
action.handler(input, mockCtx)directly — no end-to-end round trip for pure logic. mockCtxsuppliesagentCapabilities,agent,client, and stubs forprogress/log/sample/confirm/elicitas needed — missing fields cause TypeScript errors.
Methods that are NOT misuses — do not flag these; this checklist has historically confabulated bugs here that do not exist:
- Chaining both
.read(...)and.subscribe(...)on the same resource. UnlikeActionBuilder(which commits only on.handler()),ResourceBuilderregisters on the first terminal call; calling both is supported and exposes the resource as readable and subscribable. - Passing a fresh handler closure to
useTesseronAction/useTesseronResourceon every render. The hooks use a ref internally, so this does not cause re-registration and does not needuseCallback/useMemo. - Omitting the second
jsonSchemaargument to.input(schema)/.output(schema). The gateway falls back to a permissive schema — not ideal for agent reasoning, but not a bug. - Calling
ctx.confirm(...)without a priorctx.agentCapabilities.elicitationcheck.confirmis designed to collapse tofalsewhen elicitation is unavailable.
Confidence scoring
Score each finding 0–100:
- 0–50 — probable false positive, pre-existing, or style nitpick. Discard.
- 51–75 — valid but low-impact. Report only if security-related or the caller asked for suggestions.
- 76–90 — important. Report.
- 91–100 — critical correctness or security issue. Report.
Report only ≥75 by default. Report security issues from 50 upward.
Output format
## Tesseron Review
**Scope**: <what was reviewed>
**Issues**: <N critical>, <M important>, <K suggestions>
### Critical (91–100)
- <category> · `<path>:<line>` · <confidence>
<one-sentence problem>
**Fix**
```ts
<ready-to-apply patch>
Important (76–90)
Suggestions (51–75, security or requested)
Passed
- <one-line invariants the code honors — keep this section short>
Keep every issue short. Do not re-explain framework rules — the caller can reach into the `framework` skill's references for depth. Point there when a finding merits it:
- Actions → `framework/references/actions.md`
- Resources → `framework/references/resources.md`
- ActionContext → `framework/references/context.md`
- Transports → `framework/references/transports.md`
- React hooks → `framework/references/react.md`
- Protocol wire format → `framework/references/protocol.md`
- Schemas → `framework/references/schemas.md`
- Errors → `framework/references/errors.md`
- Gateway → `framework/references/gateway.md`
- Testing → `framework/references/testing.md`
## Review principles
1. **Quality over quantity.** Fewer, sharper findings beat an exhaustive list.
2. **Framework focus.** If the issue would apply to any TypeScript project, drop it.
3. **Confidence floor.** ≥75 by default, ≥50 for security. Unsure → do not report.
4. **Diff-only by default.** Do not flag pre-existing issues unless the caller explicitly asked for a full audit.
5. **Every finding has a fix.** If the fix is not obvious, raise the confidence bar before reporting.
6. **Close fast.** When the code passes, say so in one paragraph and stop. A clean review is a real answer.
Signals
- GitHub stars
- 20
- Forks
- 1
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
tesseron-reviewer- Source
- github.com/eigenwise/tesseron