Skip to main content
Glama
satovarb16
by satovarb16

save_job_analysis

Save or update job analysis records by ID or URL to prevent duplicates and preserve omitted fields.

Instructions

Persist an analyzed job record. Upserts by id then by url (D10).

Resolution order:

  1. id given -> that row is the target; unknown id -> error="not_found".

  2. No id, url given and matching an existing row -> that row is the target (upsert by URL, unchanged semantics from the prior JSON store, including "omitted optional argument preserves the previous value").

  3. Otherwise -> a brand new row. title/company are NEVER used to match an existing record (R3) — a user editing a title for clarity must not silently create a duplicate under an update path, and title text is never treated as an update key either way.

url and custom_title follow the same "explicit argument overwrites, omission (None) preserves the previous value" rule as score/ recommendation/notes/jd_text — this is what lets a URL be supplied later without disturbing the custom_title, and vice versa (SC-04). On a brand new row, at least one of url/custom_title must resolve to a non-None value, or the record has no way for a human to find it again (R1, SC-03).

This tool NEVER raises — all failures are encoded in the return envelope.

Args: title: Job title (Claude-extracted). Always required, always overwrites — no omit-preserve semantics. company: Company name (Claude-extracted). Same as title. country: Free-text country (Claude-extracted). Same as title. id: Existing job id to update. None to create or upsert-by-url. url: Job posting URL. Nullable/unique attribute, not the identity (D1). Omitted (None) preserves the existing value on an update. custom_title: User-supplied handle when url is absent. Same omit-preserve rule as url. jd_text: Full pasted job description, stored in the job_descriptions side table. Omitted (None) leaves any existing captured JD untouched. score: 0-100 match score (Claude-supplied). Omit-preserve. recommendation: APPLY/CONSIDER/SKIP (Claude-supplied). Omit-preserve. notes: Free-text notes. Omit-preserve.

Returns: SaveJobResult with success=True, id, url, custom_title, updated flag on success; success=False with error/message on failure.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idNo
urlNo
notesNo
scoreNo
titleYes
companyYes
countryYes
jd_textNo
custom_titleNo
recommendationNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
idNo
urlNo
errorNo
messageNo
successYes
updatedNo
custom_titleNo
possible_duplicate_idNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Addedv0.3.1

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations at all, the description carries the full behavioral burden and does so thoroughly: 'This tool NEVER raises — all failures are encoded in the return envelope,' the omit-preserve rule, the 'title/company are NEVER used to match' safeguard against silent duplicates, the R1/SC-03 requirement that a new row resolve url or custom_title, and the unknown-id error='not_found' path. These are exactly the traits an agent cannot infer from the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well front-loaded (purpose, then resolution order, args, returns) and each sentence carries meaning. It loses a point for repetition of the omit-preserve rule across the body and per-arg list, and for unexplained internal codes (D10, R3, SC-04, R1, SC-03) that are noise to an agent with no key.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 10 params, 0% schema coverage, and a complex multi-key upsert, the description covers resolution logic, per-param semantics, the new-row constraint, and failure encoding. An output schema exists, so the brief Returns note is sufficient; nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must carry parameter meaning — and it documents all 10 args individually, distinguishing always-overwrite fields (title/company/country) from omit-preserve fields (url/custom_title/jd_text/score/recommendation/notes) and explaining id's create-vs-update role. This is a large value add over the bare schema types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Persist an analyzed job record') plus the core mechanism ('Upserts by id then by url'), which cleanly separates it from read siblings like get_job/list_jobs and from analyze_job. An agent can identify the tool's role without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The three-step 'Resolution order' gives explicit conditions for when an id targets an existing row, when a url upserts, and when a brand new row is created, which is strong invocation guidance. However, it never names an alternative sibling (e.g. use get_job to read, analyze_job to compute), so the tool-vs-tool routing remains implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.