noui-generalize
- Repo stars 0
- Author updated Live
- Author repo skills-registry
- Domain
- AI
- Compatible agents
-
- Claude Code
- Cursor
- Cline
- Codex
- Windsurf
- Gemini CLI
- +20
- Trust score
- 88 / 100 · community maintained
- Author / version / license
- @tomevault-io · no license declared
- Token usage
- Heavy
- Setup complexity
- Manual integration
- External API key
- Required · Vendor-specific
- Operating systems
- Docker
- Runtime requirements
- Python · Docker
- Permissions
-
- Read-only
- Write / modify
- Shell exec
- Network behavior
- External requests
- Install commands
- 26 variants
Profile is derived at build time from SKILL.md and install vectors. Subject to drift from author intent.
Heads up: 未限定 allowed-tools,默认拥有全部工具权限。
---
name: noui-generalize
description: Use this skill when the user wants to generalize a recorded MCP workflow, rename tools to readab…
category: ai
runtime: Python / Docker
---
# noui-generalize output preview
## PART A: Task fit
- Use case: Use this skill when the user wants to generalize a recorded MCP workflow, rename tools to readable names, replace raw API params with natural-language parameters, fix bot detection issues (Akamai, Cloudflare, PerimeterX), rewrite operations to use CDP browser execution, or make a generated MCP server usable by Claude Code. Triggers on "generalize a recorded workflow", "rename MCP tools", "replace raw API params with readable names", "make the MCP usable by Claude Code", "generalize tool signatures", "I can't use the MCP tools", "Akamai is blocking", "429 with valid cookies", "TLS fingerprinting", "CDP fetch", "execute from inside the browser", "anti-bot workaround", "tabby credentials are empty", or "browser is authenticated but API calls fail"..
- Inputs: target material, constraints, expected output, and acceptance criteria.
- Evidence boundary: follow “Works for both MCP and Skill outputs / Critical Rules (Never Violate) / Phase 0 — Diagnose Execution Strategy” and do not present inference as author intent.
## PART B: Execution result
- **01** The card summarizes the use case; runtime output centers on “Use this skill when the user wants to generalize a recorded MCP workflow, rename tools to readable names, replace raw API params with natural-language parameters, fix bot detection issues (Akamai, Cloudflare, PerimeterX), rewrite operations to use CDP browser execution, or make a generated MCP server usable by Claude Code. Triggers on "generalize a recorded workflow", "rename MCP tools", "replace raw API params with readable names", "make the MCP usable by Claude Code", "generalize tool signatures", "I can't use the MCP tools", "Akamai is blocking", "429 with valid cookies", "TLS fingerprinting", "CDP fetch", "execute from inside the browser", "anti-bot workaround", "tabby credentials are empty", or "browser is authenticated but API calls fail".”.
- **02** When the source has headings, the agent prioritizes “Works for both MCP and Skill outputs / Critical Rules (Never Violate) / Phase 0 — Diagnose Execution Strategy” so the result follows the author’s structure.
- **03** Typical output includes task judgment, concrete steps, required commands or file edits, validation, and follow-up options.
- **04** Risk context follows the fingerprint: read files, write/modify files, run shell commands; may access external network resources; requires Vendor-specific API keys.
## Running Rules
- read files, write/modify files, run shell commands; may access external network resources; requires Vendor-specific API keys.
- Validate with a small sample before expanding scope.
- Return the result, validation criteria, and next iteration options. The source mentions slash commands such as `/noui-record-workflow`, `/noui-record-login`, `/noui-generate-skill`, `/noui-generate-mcp`, `/credentials`; use them first when your agent supports command triggers.
Name target files or source material, expected output, forbidden changes, and whether network or shell access is allowed. Permission fingerprint: read files, write/modify files, run shell commands.
Start with a small task and check whether the result follows “Works for both MCP and Skill outputs / Critical Rules (Never Violate) / Phase 0 — Diagnose Execution Strategy”. Inspect diffs, logs, previews, or tests before expanding scope.
Confirm the final output includes a concrete result, evidence, and next action. If it stays generic, tighten inputs, boundaries, and acceptance criteria.
---
name: noui-generalize
description: Use this skill when the user wants to generalize a recorded MCP workflow, rename tools to readab…
category: ai
source: tomevault-io/skills-registry
---
# noui-generalize
## When to use
- Use this skill when the user wants to generalize a recorded MCP workflow, rename tools to readable names, replace raw…
- Use it when the task has clear inputs, repeatable steps, and validation criteria.
## What to provide
- Target material, scope, expected result, and forbidden changes.
- Whether network, commands, file writes, or external services are allowed.
## Execution rules
- Organize steps around “Works for both MCP and Skill outputs / Critical Rules (Never Violate) / Phase 0 — Diagnose Execution Strategy” and keep inference separate from source facts.
- read files, write/modify files, run shell commands; may access external network resources; requires Vendor-specific API keys.
- Validate with a small sample before expanding the task.
## Output requirements
- Return the deliverable, key evidence, validation method, and next action.
- Mark missing information as unknown; do not invent commands, platforms, or dependencies. The author source anchors workflow facts; repository files anchor sources and commands; Fluxly only adds fit, limitations, and quality judgment.
skill "noui-generalize" {
input -> user goal + target files + boundaries + acceptance criteria
context -> Works for both MCP and Skill outputs / Critical Rules (Never Violate) / Phase 0 — Diagnose Execution Strategy
rules -> SKILL.md triggers / order / output contract
runtime -> Python / Docker | read files, write/modify files, run shell commands | may access external network resources
guardrails -> requires Vendor-specific API keys + small-sample validation + diff/log review
output -> copyable result + checklist + next iteration
} NoUI Generalize
Take a generated FastMCP server (or Skill) and make it work and usable:
- Execution strategy — generated servers execute inside the Tabby browser via CDP by default (see
/noui-record-workflow→ How Execution Works). This skill handles the edge cases: SPA content that needs navigation + DOM scraping, sites requiring HITL login, profiles that need credential-type fixes, or rare cases where the--execution-mode httpfallback is the right call. - Interface cleanup — replace raw internal API parameters (
f_sid,bl,reqid) with natural-language names (origin,destination,departure_date) so Claude Code can invoke tools without domain knowledge.
Prerequisite: /noui-record-workflow must be complete and the MCP server must exist under workbench/mcp_servers/. For authenticated sites, /noui-record-login must also be complete with a running Tabby session.
Works for both MCP and Skill outputs
The generalization logic is identical for either output format:
- MCP output: edit
workbench/mcp_servers/<app>/<server>/operations/<tool>.py— the body ofasync def execute(...). The FastMCP tool signature inserver.pymirrors the execute() signature, so renaming params also requires updating theserver.pydecorator args. - Skill output: edit
workbench/skills/<app>/operations/<tool>.py— the body ofasync def execute(...)and the_build_parser()argparse registrations, because the skill operation is a standalone CLI script. TheSKILL.mdbody's command examples also reference the flag names, so update them too (or regenerate SKILL.md by re-runningworkflow export --as skill --description-override "...").
The Phase 0 execution diagnosis (bot detection, empty credentials, profile promotion) applies to both outputs unchanged — both runtimes share the same noui_runtime/auth.py and the same Tabby credential flow.
After generalizing a skill, use /noui-generate-skill (not /noui-generate-mcp) for install / test.
Critical Rules (Never Violate)
- NEVER rewrite all tools at once — propose the new name and parameter list for each tool and get user approval before editing any files
- ALWAYS preserve existing execution mechanics (URL, method, headers, CDP vs. httpx) unless deliberately switching modes — only the Python function interface changes
- ALWAYS hardcode values that were static in the recording (session routing params, build labels,
bl,f_sid,reqid,soc_app, etc.) — do not expose infrastructure params to the caller - NEVER ask questions that can be answered by reading the code or URL
httpxonly appears in generated operations when--execution-mode httpwas used explicitly. Default generated operations usenoui_runtime.cdp.cdp_fetch. If you seehttpxin a default-mode server, something is wrong.- ALWAYS connect to the direct CDP port (
localhost:9222) forRuntime.evaluate— the Tabby relay (localhost:9223) only allows screencast and input events. - ALWAYS use
credentials: 'include'in browser-sidefetch()calls — the generatedcdp_fetchhelper already does this; preserve it when hand-editing. - NEVER assume "Login successful" in worker logs means login actually worked — CloakBrowser reports success when the DSL finishes, not when auth cookies appear. Always verify by checking cookies.
- After rewriting, always remind the user to restart Claude Code to reload the updated tools
Phase 0 — Diagnose Execution Strategy
Before touching tool names or params, check whether the tools actually work.
0a. Find and test the server
ls -lt workbench/mcp_servers/
Run a quick end-to-end test:
.venv/bin/python -c "
import asyncio, json, sys
sys.path.insert(0, 'workbench/mcp_servers/<app_slug>/<server_id>')
from operations.<tool_name> import execute
async def test():
result = await execute(...) # fill in sample params
print(json.dumps(result, indent=2)[:2000])
asyncio.run(test())
"
0b. Classify the result
| Result | Diagnosis | Next step |
|---|---|---|
| 200 with real data | Tool works — skip to Phase 2 (interface cleanup) | |
No Tabby page matching '<domain>' |
No tab open on the target site | Open the site in the Tabby browser, or tabby session ensure --profile <id> |
| Connection refused on 9222 | Tabby session not running | tabby session ensure --profile <id> |
CORS error / credentials include not allowed |
Cross-origin fetch blocked | Re-export with --execution-mode http |
| 429 / "Too Many Requests" from CDP | Very rare — Akamai flagging in-browser too | Phase 1 — verify the account, consider HITL re-login |
Server was generated with --execution-mode http and returns 429 |
httpx blocked by TLS fingerprinting | Re-export without --execution-mode http to land on the CDP default |
Empty credentials / name: "" (http mode only) |
Tabby credential_types format bug | Phase 1, Fix A |
No active profile found (http mode only) |
Profile still STAGING | Phase 1, Fix B |
0c. Confirm bot detection (if 429)
Verify the browser itself can make the call:
# Execute fetch from INSIDE the browser via CDP
import asyncio, json, websockets, httpx
async def test():
resp = await httpx.AsyncClient().get("http://localhost:9222/json", timeout=5)
targets = resp.json()
ws_url = [t["webSocketDebuggerUrl"] for t in targets if t["type"] == "page"][0]
js = """
fetch('/api/endpoint/test', { credentials: 'include' })
.then(r => r.text().then(t => JSON.stringify({status: r.status, body: t.substring(0, 200)})))
"""
async with websockets.connect(ws_url) as ws:
await ws.send(json.dumps({
"id": 1, "method": "Runtime.evaluate",
"params": {"expression": js, "awaitPromise": True, "returnByValue": True}
}))
resp = json.loads(await ws.recv())
print(resp["result"]["result"]["value"])
asyncio.run(test())
If 200 from browser but 429 from httpx → confirmed TLS fingerprinting. Proceed to Phase 1.
Phase 1 — Fix Execution Strategy
Fix A — credential_types format bug
After a fresh login register, the service_profiles table stores credential_types.cookies as a string array (["cookie_a", "cookie_b"]), but credentials.service.ts expects object arrays with .name. Every cookie comes back with empty name and value.
-- Run from tabby/ directory:
-- docker compose exec -T postgres psql -U browser_hitl -d browser_hitl
-- Check current format:
SELECT credential_types FROM service_profiles WHERE profile_id = '<profile>';
-- Fix: convert each string to {name, volatility} object:
UPDATE service_profiles SET credential_types = '{
"cookies": [
{"name": "EG_SESSIONTOKEN", "volatility": "STABLE"},
{"name": "bm_sz", "volatility": "VOLATILE"},
{"name": "ak_bmsc", "volatility": "VOLATILE"},
{"name": "user", "volatility": "STABLE"}
],
"headers": []
}'
WHERE profile_id = '<profile>';
Mark cookies that rotate frequently (Akamai tokens: bm_sz, ak_bmsc, bm_so, bm_s, _abck) as VOLATILE. Everything else is STABLE.
Fix B — Promote profile to ACTIVE
The credentials API (POST /credentials/request) only resolves ACTIVE profiles. Fresh registrations start as STAGING.
UPDATE service_profiles SET version_state = 'ACTIVE' WHERE profile_id = '<profile>';
Fix C — Set refresh_interval_seconds
The keepalive runner defaults to 3600s between artifact re-exports. Set lower for faster credential refresh:
UPDATE applications
SET export_policy = export_policy || '{"refresh_interval_seconds": 60}'::jsonb
WHERE name ILIKE '%<app_name>%';
Fix D — HITL login (when CloakBrowser fails)
If the automated login DSL can't complete (Akamai blocks form interactions), log in manually:
- Open Chrome →
chrome://inspect - Click "Configure..." → add
localhost:9222 - Click inspect on the page target
- In DevTools Console:
window.location = 'https://example.com/login' - Complete login manually via the screencast panel
- Force re-export:
UPDATE sessions SET artifacts_last_exported_at = NULL WHERE id = '<session_id>';
Port 9222 vs 9223: Port 9222 is the direct CDP endpoint (full access). Port 9223 is Tabby's relay that only allows
Page.screencast*andInput.dispatch*Event. Use 9222 for all workaround steps.
Fix E — CDP execution is the default (no rewrite needed)
CDP-based execution is now the default generated output. A recently exported
server already has operations that call find_page and cdp_fetch from
noui_runtime/cdp.py. If you are hand-editing or need to reason about the
pattern, the primitives are:
from noui_runtime.cdp import find_page, cdp_fetch
ws_url = await find_page("api.example.com") # match the recorded domain
result = await cdp_fetch( # fetch inside the browser
ws_url,
"https://api.example.com/v1/items",
method="POST",
headers={"Accept": "application/json"},
body={"name": "x"}, # JSON-encoded automatically
)
cdp_fetch always sets credentials: 'include'. The full specification lives
in compiler/runtime/cdp_adapter.py.
When you still need to re-generate or hand-edit:
- The server was generated with
--execution-mode httpand keeps getting 429. → Re-export without the flag to land on the CDP default. - You need SPA content that isn't exposed as a JSON API. → see DOM-scrape generalization below.
- The API truly cannot be reached from the browser origin (CORS, or
server-to-server endpoint). → keep
--execution-mode httpand fix the underlying auth / credential issue instead.
For the rationale (TLS fingerprinting, why 9222, why credentials: 'include'),
see /noui-record-workflow → How Execution Works.
DOM-scrape generalization (SPA-rendered content)
When data is rendered by client-side JS and not available as a JSON API, the
generated cdp_fetch path won't work — you need to navigate and scrape the
rendered DOM. This is a hand-written generalization on top of the CDP default:
import asyncio, json
import websockets
async def _navigate_and_scrape(ws_url: str, url: str, extract_js: str, wait_seconds: int = 7) -> dict:
"""Navigate to a URL, wait for SPA render, then extract data via JS."""
async with websockets.connect(ws_url) as ws:
await ws.send(json.dumps({
"id": 1, "method": "Page.navigate", "params": {"url": url}
}))
await ws.recv()
await asyncio.sleep(wait_seconds)
# Reuse the CDP runtime's eval helper — same session, same cookies
from noui_runtime.cdp import cdp_eval
return await cdp_eval(ws_url, extract_js)
To find the right DOM selectors, inspect data-stid or similar attributes:
# Discovery: list all data-stid values on the page
js = """
JSON.stringify([...new Set(
[...document.querySelectorAll('[data-stid]')]
.map(e => e.getAttribute('data-stid'))
)].sort())
"""
What to change when adding DOM-scrape to an operation:
- Keep
from noui_runtime.cdp import find_page, cdp_eval(the default module already exposes both). - Add
import asyncio, json, websocketsforPage.navigate. - Replace the
cdp_fetch(...)call with_navigate_and_scrape(ws_url, target_url, extract_js). - Extract the shape you need via a JS expression that returns
JSON.stringify(...).
Single browser instance caveat: Tabby runs one CloakBrowser per session. CDP navigation changes the page — if keepalive actions need the homepage, coordinate or set keepalive to
dom_checkonbodyonly.
Phase 2 — Understand the Server
Read
tools.json— note all tool names and their raw parameter names.Read each
operations/<name>.py— understand the call: URL, method, request body structure, which params are infrastructure vs. business inputs.Ask the user:
"What workflow did you record? Describe in plain language what you were doing — for example: 'I searched for flights from Fortaleza to Seattle on June 1 for 1 adult'."
Use the answer to anchor the business meaning of each tool.
Phase 3 — Close Gaps Per Tool
For each tool, ask only the questions needed to understand which parameters carry business input:
- "Which parameter in this tool controls [the thing you described]? Do you know what value you used during recording?"
- "This tool posts to
[endpoint]— is this the main [action]? What inputs does it need from the user?" - For opaque bodies: "The request body appears to be binary-encoded. Based on what you described (origin, destination, date), which of these raw params do you think carries each value?"
Skip questions that are answerable from the URL path, parameter names, or values visible in the code.
Phase 4 — Rewrite Tools One at a Time
For each tool, follow this sequence:
4a. Propose
Show the user the proposed new interface before touching any files:
Tool: create_data_batchexecute
New name: search_flights
New parameters:
- origin: str # IATA code or city name (e.g. "FOR", "Fortaleza")
- destination: str # IATA code or city name (e.g. "SEA", "Seattle")
- departure_date: str # Date in YYYY-MM-DD format
- passengers: int = 1 # Number of passengers
Hardcoded (from recording):
- f_sid: "<value from recording>"
- bl: "<value>"
- reqid: <value>
- soc_app: <value>
Execution: CDP fetch / httpx (state which)
Approve this? (yes / adjust: ...)
4b. Edit on approval
Once approved, make four edits:
operations/<old_name>.py— rewrite the function signature and body:- New function name matches the approved tool name
- New parameters are natural-language (
origin,destination, etc.) - Infrastructure params are hardcoded as local variables
- Build the raw request from the natural params (string formatting, encoding)
- Use CDP fetch if Phase 1 flagged bot detection; otherwise preserve the existing HTTP call
tools.json— update the entry:name→ new tool namedescription→ plain-English description of what it doesparameters→ updated list with natural-language names, types, descriptions
server.py— update the import and tool registration to use the new function name (if the function was renamed)API.md— refresh the documentation:
.venv/bin/python cli/main.py mcp docs <server_id>
This overwrites API.md from the current tools.json. Run it after every tool edit, not just at the end.
4c. Move to next tool
Repeat Phase 4 for each tool. Do not batch edits.
Phase 5 — Iterate After Testing
After all tools are rewritten, do a final docs refresh:
.venv/bin/python cli/main.py mcp docs <server_id>
Then tell the user:
"Done.
API.mdis up to date. Please restart Claude Code (close and reopen, or run/reconnect) to reload the updated tools. Then try invoking the workflow — for example: 'search for flights from Fortaleza to Seattle on June 1'."
When the user reports results, fix any issues:
| Problem | Fix |
|---|---|
| Wrong parameter mapping | Re-read the operation, ask clarifying question, re-propose |
| Missing required parameter | Add it to signature and body |
| Tool call fails with HTTP error | Read the error body, compare to original recording values |
| Body encoding wrong | Check if original body was URL-encoded, JSON, or protobuf — reconstruct accordingly |
| 429 from tool call on a CDP-default server | Verify Tabby has an authenticated tab open; if yes, the account may be flagged — redo HITL login (Phase 1, Fix D) |
429 from tool call on --execution-mode http server |
Re-export without the flag to use the CDP default |
| CDP connection refused | Tabby session not running — tabby session ensure --profile <id> |
fetch() returns 403 inside browser |
Session expired — redo HITL login (Phase 1, Fix D) |
Keep iterating until the user can successfully invoke the workflow using natural language.
What to Hardcode vs. Expose as Parameters
| Hardcode | Expose as parameter |
|---|---|
f_sid, bl, reqid, soc_app |
Origin, destination, dates |
| Build labels, session routing tokens | Search inputs (keywords, quantities) |
| CSRF tokens captured during recording | Filters (cabin class, stops) |
| App version identifiers | User preferences the tool is supposed to accept |
Infrastructure headers (x-goog-ext-*) |
Any value that changes meaningfully per call |
When in doubt: if the value was the same every time during recording and doesn't carry user intent, hardcode it.
Dynamic-Header-Injection Sites (JS-injected auth)
Some SPAs acquire a short-lived bearer token in-memory (fetch from /auth/init or similar on page load), then wrap window.fetch / XMLHttpRequest with an interceptor that sets Authorization: Bearer <jwt> right before every XHR. The cookie jar is empty of auth material, localStorage / sessionStorage don't hold the bearer either, yet every real API call carries it. Calling the API from cdp_fetch with credentials: 'include' alone will get you a 401 or 403.
Detect
- HAR contains an
Authorization: Bearer eyJ...header whose JWTjti(orsub,exp) rotates between recordings of the same flow. document.cookieat runtime does not include the bearer substring.localStorageandsessionStoragedumps don't contain the bearer either.- The recorded API host is on a different subdomain from
www.*(e.g.api-prod-*,api.*).
Workaround — CDP Network-event sniffing
Enable CDP's Network domain, reload the page, listen for Network.requestWillBeSent, and grab the Authorization off the first request that matches your target host. Cache in /tmp with a TTL, invalidate on 401/403, retry once.
Reference implementation (10-line core):
await ws.send({"id": 1, "method": "Network.enable"})
await ws.send({"id": 2, "method": "Page.reload"})
deadline = loop.time() + 20
while loop.time() < deadline:
msg = json.loads(await ws.recv())
if msg.get("method") != "Network.requestWillBeSent":
continue
url = msg["params"]["request"].get("url", "")
if TARGET_HOST not in url:
continue
authz = {k.lower(): v for k, v in msg["params"]["request"].get("headers", {}).items()}.get("authorization", "")
if authz.startswith("eyJ"):
return authz
See .claude/skills/indigo-flight-search/noui_runtime/indigo_auth.py for the full cache + retry wrapper around this core. The IndiGo skill is the canonical example of this pattern in this repo.
Forward pointer: When the retro-C1 generic
sniff_headers()helper lands innoui_runtime, delete the hand-written module and replace the import. Seeplans/noui/noui-agent-friction-retro-plan.mdSection C1.
Per-host static client IDs
Sites of this shape often pair the dynamic JWT with a stable user_key / x-api-key / x-client-id header that is per-host but constant across sessions (look for the same value across every request to that host in the HAR). Hardcode those — they're infrastructure, not user input.
Known Anti-Bot Sites
| Site | Bot Detection | CloakBrowser Login | Workaround |
|---|---|---|---|
| Expedia | Akamai Bot Manager | Form blocked silently; reaches homepage but can't submit | HITL login + CDP fetch + DOM scrape |
| Generic SPA with JS-injected auth | Token not in cookies/localStorage; Authorization is set by a fetch interceptor in the page's JS bundle |
n/a (site may be anonymous) | Sniff the Authorization via CDP Network.requestWillBeSent on page reload; cache per session. See Dynamic-Header-Injection Sites above. |
IndiGo (api-prod-*-skyplus6e.goindigo.in) |
Anonymous session; per-host user_key + rotating JWT; Akamai cookies |
n/a | Hardcode per-host user_keys; sniff JWT at runtime. Reference: indigo-flight-search skill. |
Architecture Notes
- Why cookies alone fail: Akamai fingerprints the TLS ClientHello, HTTP/2 settings frame, header order, and other transport-layer signals.
httpx/curlhave distinctly different fingerprints from Chrome, even with identical cookies. - Why CDP works:
Runtime.evaluate+fetch()executes inside the real Chrome process. The HTTP request goes through Chrome's network stack with its native TLS implementation and fingerprint. - Port 9222 vs 9223: Port 9222 is the direct CDP endpoint (full access). Port 9223 is Tabby's relay proxy that only allows
Page.startScreencast,Page.stopScreencast,Page.screencastFrameAck, andInput.dispatch*Event. Use 9222 for this workaround. - Single browser instance: Tabby runs one CloakBrowser per session. CDP navigation changes the page for that session — if keepalive needs the homepage, set keepalive health checks to
dom_checkonbodyrather than URL-based checks.
Decision Flow
Start
│
Phase 0: Test the tool as-is
│
├─ Works (200 with data)?
│ └─ Skip to Phase 2 (interface cleanup)
│
├─ "No Tabby page matching <domain>"?
│ └─ Open the site in Tabby, or `tabby session ensure --profile <id>`
│
├─ CORS / cross-origin error?
│ └─ Re-export with `--execution-mode http`
│
├─ 429 on a default-mode server?
│ └─ Phase 1: Fix D (HITL re-login) — the session or account is flagged
│
├─ 429 on an `--execution-mode http` server?
│ └─ Re-export without the flag to land on the CDP default
│
├─ Empty credentials / name: "" (http mode)?
│ └─ Phase 1: Fix A (credential_types format)
│
├─ "No active profile" (http mode)?
│ └─ Phase 1: Fix B (promote to ACTIVE)
│
├─ Login didn't actually work?
│ └─ Phase 1: Fix D (HITL login)
│
├─ 401/403 on default CDP server, cookies appear correct?
│ └─ Check HAR: is `Authorization` present and does its JWT `jti` rotate across recordings?
│ └─ Yes → Dynamic-header-injection pattern; see *Dynamic-Header-Injection Sites* section
│
Phase 2: Read tools.json + operations + ask user about workflow
│
Phase 3: Close gaps per tool (targeted questions only)
│
Phase 4: Rewrite tools one at a time (propose → approve → edit)
│
Phase 5: Test, iterate, remind user to restart Claude Code
Related Skills
/noui-record-login— Record login and register with Tabby (run first for authenticated sites)/noui-record-workflow— Record and export the workflow (run first to generate the server)/noui-generate-mcp— Server lifecycle after generalization (start/stop/connect to Claude Code)
Source: adoptai/noui — distributed by TomeVault.
Decide Fit First
Design Intent
How To Use It
Boundaries And Review