Ruin Everything
Connects to a shared local Google Chrome instance over CDP, preserving the browser profile and open application tabs so CLI or MCP clients can resume browser tasks, click controls, and keep sessions alive.
Automates Greenhouse job applications in a shared Chrome tab, including matching a fresh Outlook verification email to the application and filling in the email code to complete the verification step.
Reads the local macOS Messages database to find fresh domain-bound or sender-bound SMS one-time codes for signup and verification flows, then uses the matching code in browser forms.
Pick up a browser task where the last agent left it. Ruin connects to Chrome on your machine. A new CLI run or MCP client can find the same open application tab, finish a supported verification step, and check what the site actually confirmed.
Set up Chrome · Connect an MCP client · See what has been tested · Try your first MCP call · Contribute
In your browser | What Ruin can do |
A Greenhouse application asks for an email code | Match a fresh Outlook message to the application and fill the code. |
An Ashby tab closed after submission | |
A Workday tenant asks you to sign in | Use the local profile and follow a supported account activation back to the job. |
You have phone numbers from several countries |
Choose a starting point
For a new task, start the shared browser and open the target site. For an interrupted application, choose the site-specific watcher and pass the original job URL. Generic click tasks open a new tab.
Related MCP server: jobwatch
Use a shared local Chrome window
Install from the repository directory with Python 3.11+ and Google Chrome:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e .
ruin browserRun ruin browser to start or reconnect to the project browser. Every CLI task uses Python Playwright over CDP. The default endpoint is http://127.0.0.1:9222. The runner launches Chrome with a dedicated profile at ~/.ruin-everything/canvas-browser when this port is free. The CDP connection preserves the existing browser context settings, including its download behavior. Chrome stays open after the command exits. Other local clients can attach to the same endpoint and locate the job tab by its full URL. Give one client ownership of submission for each application.
Open Outlook Web in this profile and complete any required Microsoft sign-in before requesting a fresh email code. Closing the job tab, quitting Chrome or a site session expiring can still interrupt an application. A draft in a chat-specific browser must be recovered separately.
Run a browser click task
Install the optional dependencies with python -m pip install -e '.[agent]' and set OPENAI_API_KEY. Give the model an HTTPS starting page and a specific task:
ruin "Open the help page" --site https://example.org --channel chromeThe runner sends the task, page title and visible action labels to the selected model. It clicks the chosen control directly and observes the page again. A task can use one tab and up to 20 steps.
For example, if a visible button is labeled Open guide, the model can select its current ID. A changed URL or an ID missing from the snapshot stops that step. A blocked model decision leaves the page open for inspection.
Local credential filling
Add --autofill to use the system keyring and Chrome’s sign-in form. For a form with one visible password field that submits to the selected HTTPS origin, the runner clicks the empty field so Chrome can offer credentials saved in that browser profile. Complete sign-in in the open tab. The runner waits up to three minutes for the credential fields to disappear, then resumes the task. It leaves account selection and form submission to the login UI. A Chrome fixture verifies same-tab continuation with a restrictive script policy.
Local account registration
Run ruin identity to choose phone regions by name, save multiple numbers, select a default and reveal the password while editing. The offline editor uses the browser’s native select control and the phonenumbers library for dialing codes and international formatting. python-phonenumbers
For manual setup of a browser task with --site, create ~/.ruin/identity.json with owner-only permissions (chmod 600). Set auto_signup to true and supply string values for first_name, last_name, email, phone and default_password. This file stores the password in plain text. The local runner checks the selected HTTPS origin before each model decision until it submits a registration. It recognizes one visible Create Account, Create an Account, Register or Sign Up submit button on a same-origin POST form, fills recognized fields, and checks labeled Terms of Service, Terms of Use and Privacy Policy boxes. On an ordinary same-origin form it can also fill one empty, editable contact phone field. A visible matching signup field with a missing profile value leaves the tab open for completion.
For a subsequent single one-time-code field, the runner checks macOS Messages for up to 30 seconds for an incoming text received since the submission and ending in @hostname #code. Read access to the Messages database is required. MCP challenge and receipt results include a signup_policy field reporting the local setting. Chrome and SQLite fixtures exercise form submission, ordinary phone inputs, cross-origin actions, message age, direction and domain matching.
Workday accounts and signed-in sessions
On supported English Workday tenant forms, the CLI browser task tries the local email and password first. An explicit missing-account message opens registration. A generic sign-in failure leaves the original job open. After registration, Ruin checks the signed-in Outlook mailbox for a fresh activation message, follows a direct activation link on the exact tenant host, waits for visible confirmation and returns to the job URL. The adapter supports native POST forms and script-driven Workday dialogs with a recognized submit control. Local Chrome fixtures cover existing accounts, registration, activation and returning to the job. Production tenant layouts and wrapped email links can differ.
The adapter selects Sign In inside the open Workday dialog, even when the page header also offers Sign In. For a six-digit email challenge, it checks for one fresh Outlook message with a link to the same tenant and one labeled code, enters the code in the original tab, then waits for visible activation confirmation. The Jain Global dialog controls were inspected in shared Chrome. The six-digit activation path was verified with a simulated mailbox.
For a code sent to an existing tab, use the request time recorded when the site sent the SMS. Optionally add sms_senders to the local identity file, mapping an exact hostname to its dedicated sender string. Plain six-digit codes must come from that sender. Domain-bound messages work without a sender entry. Both paths require read access to the Mac Messages database.
ruin verify-sms --site "$VERIFICATION_URL" --requested-at "$REQUEST_UNIX_SECONDS"
ruin keep-alive --site "$STATUS_URL" --signed-in-text "Account overview" --interval 900 --timeout 86400Keep-alive opens a separate tab for the selected HTTPS status page. Use a read-only page with text unique to the signed-in view. The process checks that text after each visit, stops on redirects or missing text, and closes its own tab when finished. Run the command for the desired duration. Sites control their own session lifetimes. Simulated Chrome checks cover repeated GET requests and preservation of the original tab.
To provision credentials for local filling, use the entries below. The optional TOTP entry holds the site's Base32 seed.
keyring set ruin:https://example.org username
keyring set ruin:https://example.org password
keyring set ruin:https://example.org totpVerify a Greenhouse application with Outlook Web
On macOS or Linux, attach to a local debugging-enabled Chrome session that already has Outlook Web signed in and the original Greenhouse job tab open. Replace the example URL and employer with the exact job and the name used in its email. Start the watcher before the application requests a code. The existing application workflow still owns the initial submit.
ruin verify-email --cdp http://127.0.0.1:9222 \
--site https://job-boards.greenhouse.io/example/jobs/12345 \
--company "Example Employer" --timeout 180The watcher takes a snapshot of visible Outlook inbox rows and waits for a new or updated row whose timestamp follows the request window. It checks the employer, subject wording and Greenhouse sender, reads the code from the opened message, and submits it in the original job tab. A local lock serializes watcher processes. Keep other applications for the same employer idle during verification.
In the inbox diagram, a 09:59 message already exists when the watcher starts at 10:00. The watcher checks the 10:01 candidate against the employer and verification wording in the row, then checks the sender in the opened message. If two new candidates match, it stops before selecting either one. These times illustrate ordering; the watcher uses the recorded timestamps from the live run.
Recover an open challenge
If a challenge is already open at startup and offers a resend control, it requests a fresh code there. It makes at most one resend per run.
For a direct Greenhouse embed, pass the full quoted URL (including both for and token). If an existing challenge has no resend control, supply --requested-at UNIX_SECONDS from that job’s original request. For this recovery path the message body must also identify the job ID. A subject shared by two roles at the same employer cannot establish which form owns the code. A tab in another chat’s isolated browser must be handled there.
The prototype supports English, top-level Greenhouse forms and Outlook layouts exposing message identifiers, timestamps, sender addresses and a message body. Missing evidence or an ambiguous match stops verification. Only a visible receipt counts as success. A timeout can also happen after submission; check the original tab before retrying. Message contents and codes stay outside the model loop. The integration has been tested with browser fixtures; compatibility with a live employer form and Outlook tenant remains unverified.
Resume an authorized Ashby application
Use this workflow when a reviewed application has already reached verification. The original application driver owns the authorization for that job and completes the live challenge in the same tab. Start the receipt watcher alongside that driver, using the exact application URL:
ruin resume-ashby --cdp http://127.0.0.1:9222 \
--site 'https://jobs.ashbyhq.com/EMPLOYER/JOB-UUID/application' --timeout 300The CLI attaches to one matching tab and emits JSON state changes on standard error. On challenge_visible, the authorized driver uses the current widget. A driver using the Python API can supply its own approved handler directly:
receipt = await resume_ashby(context, application_url, timeout=300,
directory=receipt_directory, on_event=report_status,
on_challenge=complete_authorized_challenge)Import resume_ashby from ruin.agent.ashby. The handler receives the original Playwright page once per run. The standalone CLI observes the browser; it requires an application driver or person to interact with the widget. A completed challenge may automatically submit the form. Leave any existing submission in flight and watch for its result. An enabled Submit button by itself is insufficient evidence to send another request.
Receipt storage and retries
The watcher records success only when the same job displays Ashby's visible Success status with Your application was successfully submitted. It returns the receipt as JSON on standard output and stores one row per job in ~/.ruin-everything/ashby-receipts.sqlite3. A retry returns that stored receipt. A timeout, changed job or ambiguous tab produces an error without marking the job submitted. An external application tracker should import only a returned receipt.
For example, a challenge can disappear while the site is still processing the application. If the watcher times out then, check the original tab before taking another action. If that tab later displays the official receipt, rerun the watcher with the same URL to capture it.
The illustrated receipt is an example. The receipt pattern comes from a completed Baseten application. The reusable command was tested with simulated Ashby pages in Chrome, including a hidden receipt, a changed job, duplicate tabs and a retry after the tab closed.
Connect an agent over MCP
Tagged releases include the MCP server by default. A registry client can launch the package directly with uvx ruin-everything@0.2.0. GitHub releases
Give the client the exact job URL and describe what you see. If the question is whether an Ashby application went through, the client checks the receipt journal first. If the form is waiting for verification, the client inspects the open tab.
Tool | When to call it | Result |
| The selected registration or contact form is open at its exact HTTPS URL. | Local profile action and current signup policy. A submitted form can still require verification. |
| Greenhouse asks for an eight-character email code, a connector reports | The provider and visible state. A missing or duplicate tab gets its own result. The form stays open. |
| At handoff, even with Chrome closed | A saved receipt or |
| The original form is open and the outcome is uncertain | An existing receipt, or fresh evidence from the same job. A timeout is a tool error. The watcher leaves the form open. |
Install uv once. In an MCP client with JSON configuration, this example runs the latest PyPI release. The client must be able to find uvx on its PATH. An absolute path to uvx also works.
{
"mcpServers": {
"ruin-everything": {
"command": "uvx",
"args": [
"--isolated", "--refresh",
"--from", "ruin-everything[mcp]",
"ruin-mcp"
],
"env": { "RUIN_AUTO_UPDATE": "0" }
}
}
}To track the GitHub branch directly, set --from to ruin-everything[mcp] @ git+https://github.com/yuki4266/ruin-everything.git@main. Both configurations launch the actual ruin-mcp executable. A two-version smoke test verified refresh on both the Git and package paths. An existing editable installation can still launch it directly.
To register the server for your user account, run the command for your client. Open a new session to pick up the tool list.
codex mcp add ruin-everything --env RUIN_AUTO_UPDATE=0 -- uvx --isolated --refresh --from 'ruin-everything[mcp]' ruin-mcp
claude mcp add --scope user --transport stdio ruin-everything -e RUIN_AUTO_UPDATE=0 -- uvx --isolated --refresh --from 'ruin-everything[mcp]' ruin-mcpTry your first MCP call
After connecting your client, try this prompt with the fictional URL below. It works with Chrome closed and requires no job application or identity profile.
Call
get_ashby_receiptforhttps://jobs.ashbyhq.com/example/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/applicationand tell me its state.
On a fresh install, the expected state is unrecorded: the tool checked the local journal and found no receipt for this example. This read-only call was verified against the PyPI server.
The repository includes routing instructions for Codex and imports them from CLAUDE.md. To apply them in other workspaces, copy the application routing section into your user-level ~/.codex/AGENTS.md or ~/.claude/CLAUDE.md. Client permissions and site verification still apply to Duo, PayPal and other unsupported providers.
All four tools take site. The inspector checks once by default. Set wait_seconds to 1–300 to watch that same tab for a change from pending. From the CLI, use ruin watch --site "$JOB_URL" --timeout 30. The watch ends after detecting a supported state, losing the original tab, or reaching the time limit.
In a local Chrome simulation, a fresh Codex CLI session given only the Greenhouse URL and the eight-character-code symptom selected inspect_application_challenge as its first tool call and returned email_verification. The simulated form stayed empty.
The Ashby receipt watcher takes timeout_seconds (default 15, range 1–300). A returned receipt contains state, site, observed_at and the site's confirmation message. The application driver owns form interaction. After a timeout, check the same URL again before considering another submission.
The server uses the official Python MCP SDK over stdio. A browser automation client such as Playwright MCP can run alongside it by attaching to the same local Chrome with --cdp-endpoint http://127.0.0.1:9222. The integration test waits for Chrome to advertise its local debugging port, then connects two successive SDK clients to the simulated employer page. Python MCP SDK · Playwright MCP connection options
How updates reach your machine
What changes | When you get it |
MCP package via uvx | On the next server launch, uv resolves the latest version available from the configured source. A long-running server keeps its loaded code until restart. Initial installation and online refresh require network access. |
Direct installation | CLI and MCP startup schedule a quiet background check at most once every six hours per installation. A clean |
Site rules | Each new Greenhouse verification or live Ashby observation requests the project's selector file with a two-second network timeout. A workflow keeps its initial snapshot through completion. Offline or invalid updates fall back to the last valid cache at |
The rule file describes Ashby receipt elements, Greenhouse verification inputs and the email-code pattern, and Outlook rows and message bodies. The installed adapters enforce trusted origins, sender identity, job matching and receipt wording. A change to those checks requires a code release.
For maintainers, configure one PyPI Trusted Publisher for project ruin-everything, owner yuki4266, repository ruin-everything, workflow publish.yml and environment pypi. A push to main builds the version in pyproject.toml with the workflow run number as a fourth release component. For a tagged release, set the project version and push the matching tag (for example, 0.2.0 and v0.2.0). Both routes run the browser tests, build and check the wheel and source distribution, then publish using GitHub's OIDC identity. Release workflow · uv tool updates
Example: read courses after school sign-in
The Duke Canvas adapter demonstrates how a task resumes after an interactive login. Run the lookup in the shared profile:
ruin coursesThe result contains course names and links. Use --json for structured output:
To select an existing local debugging endpoint explicitly, run:
ruin courses --cdp http://127.0.0.1:9222 --jsonThe sign-in branch waits up to 180 seconds for the school to return the browser to Canvas. Set --timeout 300 for a longer wait. Duo approval takes place on the school sign-in path. Duke device recovery
Verification
Update tests cover overlapping startup checks, changes between rule snapshots, invalid downloads and offline fallback. Runtime checks verified a shared Chrome tab across independent CDP connections. For browser tests, install the Playwright Chromium build or use installed Chrome. Run python -m unittest discover -s tests -v. Install the agent extras to include the mocked model test. For installed Chrome, prefix the command with RUIN_TEST_CHANNEL=chrome.
A live Duke run returned course links after sign-in. A second run with the same profile also returned the list after visiting the school login route. The number of Duo prompts was not measured. The general click loop has been exercised with a simulated model response.
The hand-drawn diagrams are editable SVGs. They use Rough.js linework and Kalam lettering. Figure sources · Rough.js · Kalam font license
Development plan · Contribution and figure guidelines · MIT license
Contribute to Ruin Everything
Trying Ruin in a new MCP client? Share your setup and one tool result so someone else can repeat it. If setup stopped partway, ask in Q&A.
Report a bug · Suggest an idea · Contribute a translation, test or fix
Contributors
Thank you to everyone who tests a workflow, answers a question or sends a patch. GitHub commit contributors appear below.
Star History
Select the snapshot to explore the latest star history.
⭐ If Ruin helped you recover a browser task, give it a star on GitHub.
Available Tools
4 toolsget_ashby_receiptARead-only
Check the exact Ashby job first when asked whether it was submitted, including at handoff or after a lost tab. A stored receipt confirms success even with Chrome closed. Unrecorded means the outcome is unknown.
| Name | Required | Description | Default |
|---|---|---|---|
| site | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| site | Yes | |
| state | Yes | |
| message | No | |
| observed_at | No | |
| signup_policy | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint/openWorldHint annotations, the description adds genuinely useful interpretation rules: a stored receipt confirms success even with Chrome closed, and unrecorded means the outcome is unknown. It omits retention windows, latency, or auth requirements, but the result-semantics disclosure is the important part for a status-check tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with no filler, and the primary instruction ('check first when asked whether it was submitted') is front-loaded. The phrasing 'Check the exact Ashby job first' is slightly compressed/ambiguous but still readable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The output schema presumably covers return shape, and the description handles result interpretation well. However, for a tool with one required, undocumented parameter, an agent cannot confidently supply 'site', which is a meaningful completeness gap for an otherwise simple tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single required parameter 'site' has no schema description (0% coverage) and the description never explains what a 'site' is — a domain, an Ashby job slug, or an internal key. With low coverage the description should compensate, and it does not; 'the exact Ashby job' only hints that the value must be precise.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a concrete action (check the stored Ashby receipt) and the question it answers (was the job submitted?), which is more specific than the name alone. It does not name the sibling tools (e.g. watch_ashby_receipt) to sharpen the boundary, but the retrieval-vs-observation distinction is inferable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear triggering conditions: when asked whether a job was submitted, at handoff, or after a lost tab, and says to check this 'first'. The implied alternative (watching for a receipt) is never named, so the routing guidance stops short of explicit alternatives or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
inspect_application_challengeARead-onlyIdempotent
Inspect the original Greenhouse or Ashby application tab at its exact job URL. Use when Greenhouse asks for an 8-character email security code, including reports of '[one-time authentication code withheld]', or Ashby displays a reCAPTCHA image grid. On a lost tab, report whether the shared local browser still has it. Return the visible state only. Mailbox contents, CAPTCHA solving, Duo 2FA, PayPal Security Challenge and payment actions are outside this tool's scope. A positive wait watches just this job.
| Name | Required | Description | Default |
|---|---|---|---|
| site | Yes | ||
| wait_seconds | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| state | Yes | |
| provider | Yes | |
| signup_policy | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint true and destructiveHint false, so the safety profile is covered; the description adds real value beyond that by stating the tool only returns visible state, that it falls back to reporting shared-browser tab presence on a lost tab, and that a positive wait 'watches just this job.' It does not describe latency or polling cadence for the wait behavior, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is front-loaded with purpose, then trigger conditions, then exclusions, so the agent can stop reading early and still act. Every sentence contributes, though the bracketed code placeholder phrase is slightly awkward and the trailing wait sentence would read better next to the parameter discussion.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value explanation is unnecessary, and the annotations plus exclusions cover the safety and boundary story well. The unresolved gap is the meaning and accepted values of the required 'site' parameter, which matters given zero schema description coverage on a browser-tab tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden, yet neither parameter name is explained. 'A positive wait watches just this job' implicitly characterizes wait_seconds, and 'at its exact job URL' hints at site, but the agent must guess that site expects a job URL versus a site identifier such as 'greenhouse' or 'ashby'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a concrete verb and resource ('Inspect the original Greenhouse or Ashby application tab at its exact job URL') and clarifies the observable output ('Return the visible state only'). It is distinguishable from the siblings (ruin_auto_register, get_ashby_receipt, watch_ashby_receipt) through the explicit scope boundaries, though the noun 'challenge' in the name is never explicitly defined in prose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit triggers: 'Use when Greenhouse asks for an 8-character email security code ... or Ashby displays a reCAPTCHA image grid,' and it names when NOT to use it by excluding mailbox contents, CAPTCHA solving, Duo 2FA, PayPal Security Challenge, and payment actions. The lost-tab fallback ('report whether the shared local browser still has it') is also routed here rather than left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ruin_auto_registerB
Handle an open Workday Sign In or Create Account dialog at the exact job URL, or fill a supported signup form. Credentials come from the local profile.
| Name | Required | Description | Default |
|---|---|---|---|
| site | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| state | Yes | |
| sms_filled | No | |
| signup_policy | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=false and idempotentHint=false, and the description usefully adds that credentials are pulled from the local profile, so no credential parameters are needed. It does not disclose what happens on submission, whether an account is actually created on the external site, or how failures/unknown forms are reported – relevant for an action that registers accounts.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with no filler, and the operative condition (open dialog at the exact job URL) is stated first. Minor ambiguity comes from the 'or' between the two modes rather than wasted wording.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The output schema covers return values, but for a tool that drives registration/sign-in the description omits what 'Handle' entails (fill vs submit), which signup forms are 'supported', and what the caller should do on failure. Combined with an undocumented 'site' parameter, an agent cannot reliably invoke this without trial and error.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single required parameter 'site' has 0% schema description coverage, and the description never explains what its value should be (a full job URL? a hostname? 'workday'?). The phrase 'at the exact job URL' is at best an indirect hint that the parameter is URL-shaped, which is not enough to compensate for the schema gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a concrete target (an open Workday Sign In or Create Account dialog at the exact job URL) plus a second mode (fill a supported signup form), so an agent can tell this is a browser-driving registration/login tool rather than a read-only receipt tool like its siblings. The verb 'Handle' is the weak point – it never says whether the tool fills fields, submits, or only detects the dialog.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by state: call it when a Sign In/Create Account dialog is already open at the exact job URL. There are no explicit exclusions, no mention of the sibling tools (inspect_application_challenge, get_ashby_receipt, watch_ashby_receipt), and 'supported signup form' is never defined, leaving the agent to guess which sites qualify.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
watch_ashby_receiptBIdempotent
Watch the original Ashby form when a challenge clears or a submitted application has no receipt yet. Return saved evidence or record the official success message for this job. This never submits the form.
| Name | Required | Description | Default |
|---|---|---|---|
| site | Yes | ||
| timeout_seconds | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| site | Yes | |
| state | Yes | |
| message | Yes | |
| observed_at | Yes | |
| signup_policy | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations supply idempotentHint=true and destructiveHint=false, and the description usefully adds the safety constraint 'This never submits the form.' It also hints at side effects ('record the official success message for this job'), but never says whether the call blocks/polls, how retries work, or what state is written — notable gaps given no readOnlyHint is declared.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with no filler, and the non-submission guarantee is placed where it will be read. The phrasing is slightly awkward ('for this job', 'when a challenge clears') but nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and the safety constraint is covered. Still, for a tool with a timeout parameter that likely blocks or polls and may record state, the description omits operational behavior an agent needs before invoking it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for both parameters, so the description carries the full burden of explaining 'site' and 'timeout_seconds'. It does neither: the meaning of 'site', its accepted format, and the blocking/timeout behavior implied by timeout_seconds are all undocumented.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (the Ashby form / receipt) and a loose verb ('watch'), and adds a couple of condition clauses, but 'watch' is ambiguous between polling, blocking until timeout, and passively observing. It never distinguishes itself from the sibling get_ashby_receipt, so an agent cannot tell from the text alone which one to reach for.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It offers trigger context ('when a challenge clears or a submitted application has no receipt yet'), which is genuine when-to-use guidance. However, it gives no exclusions and no comparison to get_ashby_receipt or inspect_application_challenge, leaving the choice between siblings implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
get_ashby_receipt - First observed
inspect_application_challenge - First observed
ruin_auto_register - First observed
watch_ashby_receipt
TDQS
Scored across 4 tools
get_ashby_receipt and watch_ashby_receipt both concern Ashby submission receipts and could be confused at selection time, though one is an immediate lookup and the other a waiting watcher. inspect_application_challenge also partially overlaps with the receipt tools since it deals with Ashby challenge state, and coverage is split oddly across platforms.
All names are snake_case with a verb-first pattern (auto_register, inspect, get, watch), which is readable and consistent. The stray 'ruin_' prefix on only one tool is a minor deviation from the otherwise uniform convention.
Four tools is a tight, well-scoped set for a narrow challenge-handling workflow, with each tool earning a distinct role. It is slightly thin given the tool set references three platforms (Workday, Greenhouse, Ashby).
Challenge inspection and Workday dialog handling are covered, but receipt/status verification exists only for Ashby, leaving Workday and Greenhouse submissions without any outcome-checking tool. This is a notable gap in lifecycle coverage across the stated platforms.
Maintenance
Related MCP Connectors
Job applications done for you: check applications and interviews, get prep, apply to a job by URL.
Search open jobs across a directory of Greenhouse and Lever career sites, each result checked live
Connect AI agents to your own Chrome with scoped access, approvals, and verified task results.
Search remote tech jobs, inspect descriptions, compare roles, and retrieve application links.
Related MCP Servers
- FlicenseAqualityCmaintenanceEnables AI agents to automatically inspect and fill web application forms on job application sites through a logged-in Chrome, supporting text, select, radio, date, cascading dropdowns, and dynamic row operations.4-
- AlicenseAqualityBmaintenanceWatches company job boards (Greenhouse, Lever, Ashby, Workable, Workday and more) for new roles that match your filters, ranks them in a digest optionally fit-scored against your resume, and tracks every application with interview prep sheets. It never applies for you.31267 PyPIMIT
- AlicenseNot gradedqualityBmaintenanceEnables candidates to check where their job applications stand on employer careers portals straight from an AI client, retrieving applications, status history and deltas while keeping logins in the system keychain.1GPL 3.0
- FlicenseNot gradedqualityAmaintenanceEnables AI assistants to automate recruiter-side candidate sourcing and outreach by searching with multiple keywords, viewing and screenshotting resumes to extract share links, maintaining a persistent candidate database, filtering and scoring candidates, exporting Markdown reports, and sending greetings through a logged-in Chrome session.-