apply_hunt_criteria_list
ChatGPTPurpose: Bulk-add the entities on a saved criteria list (included/excluded companies or universities) into a hunt's matching criterion field. NOT for: Generic criteria writes (update_hunt_criteria). Only for the four list-backed fields below. Returns: { added: number, total_entities: number, field_slug, sync: { ok, error? } }. Like update_hunt_criteria, the route auto-syncs to AWS after a successful write — no separate sync_hunt_draft needed before get_hunt_candidate_count. When to use: "Use my standard 'top SaaS companies' list" — pair with list_personas / list browsing tools to surface saved lists.
apply_hunt_criteria_list
ChatGPTPurpose: Bulk-add the entities on a saved criteria list (included/excluded companies or universities) into a hunt's matching criterion field. NOT for: Generic criteria writes (update_hunt_criteria). Only for the four list-backed fields below. Returns: { added: number, total_entities: number, field_slug, sync: { ok, error? } }. Like update_hunt_criteria, the route auto-syncs to AWS after a successful write — no separate sync_hunt_draft needed before get_hunt_candidate_count. When to use: "Use my standard 'top SaaS companies' list" — pair with list_personas / list browsing tools to surface saved lists.
apply_hunt_criteria_list
ChatGPTPurpose: Bulk-add the entities on a saved criteria list (included/excluded companies or universities) into a hunt's matching criterion field. NOT for: Generic criteria writes (update_hunt_criteria). Only for the four list-backed fields below. Returns: { added: number, total_entities: number, field_slug, sync: { ok, error? } }. Like update_hunt_criteria, the route auto-syncs to AWS after a successful write — no separate sync_hunt_draft needed before get_hunt_candidate_count. When to use: "Use my standard 'top SaaS companies' list" — pair with list_personas / list browsing tools to surface saved lists.
duplicate_hunt
ChatGPTPurpose: Create a new DRAFT hunt by copying an existing one's criteria, scorecard, outreach configuration, sourcing settings, and language. The new hunt is owned by the caller and starts empty (no candidates / messages / notes). NOT for: Editing an existing hunt (configuration changes happen in the Umamy dashboard). Not for creating a hunt from scratch (use the dashboard's setup wizard). Candidates, messages, notes, the linked LinkedIn account, and ATS connection are NEVER copied — those are reassigned manually on the new hunt. Returns: The newly created hunt — { id, name, status, role_name, created_at, updated_at }. status is always "draft" regardless of the source hunt's status. When to use: - "Spin up a copy of the Senior Engineer hunt for the EU team" - "Duplicate hunt X but skip the outreach templates" - "Clone this hunt as a new draft so I can iterate on it" Workflow: list_organizations → list_hunts(org_id) → duplicate_hunt(org_id, source_hunt_id, name). Defaults: All copy_* flags default to true when omitted; pass false to skip a section. add_me_as_owner defaults to true and is a no-op if the caller is already an owner of the source hunt.
duplicate_hunt
ChatGPTPurpose: Create a new DRAFT hunt by copying an existing one's criteria, scorecard, outreach configuration, sourcing settings, and language. The new hunt is owned by the caller and starts empty (no candidates / messages / notes). NOT for: Editing an existing hunt (configuration changes happen in the Umamy dashboard). Not for creating a hunt from scratch (use the dashboard's setup wizard). Candidates, messages, notes, the linked LinkedIn account, and ATS connection are NEVER copied — those are reassigned manually on the new hunt. Returns: The newly created hunt — { id, name, status, role_name, created_at, updated_at }. status is always "draft" regardless of the source hunt's status. When to use: - "Spin up a copy of the Senior Engineer hunt for the EU team" - "Duplicate hunt X but skip the outreach templates" - "Clone this hunt as a new draft so I can iterate on it" Workflow: list_organizations → list_hunts(org_id) → duplicate_hunt(org_id, source_hunt_id, name). Defaults: All copy_* flags default to true when omitted; pass false to skip a section. add_me_as_owner defaults to true and is a no-op if the caller is already an owner of the source hunt.
duplicate_hunt
ChatGPTPurpose: Create a new DRAFT hunt by copying an existing one's criteria, scorecard, outreach configuration, sourcing settings, and language. The new hunt is owned by the caller and starts empty (no candidates / messages / notes). NOT for: Editing an existing hunt (configuration changes happen in the Umamy dashboard). Not for creating a hunt from scratch (use the dashboard's setup wizard). Candidates, messages, notes, the linked LinkedIn account, and ATS connection are NEVER copied — those are reassigned manually on the new hunt. Returns: The newly created hunt — { id, name, status, role_name, created_at, updated_at }. status is always "draft" regardless of the source hunt's status. When to use: - "Spin up a copy of the Senior Engineer hunt for the EU team" - "Duplicate hunt X but skip the outreach templates" - "Clone this hunt as a new draft so I can iterate on it" Workflow: list_organizations → list_hunts(org_id) → duplicate_hunt(org_id, source_hunt_id, name). Defaults: All copy_* flags default to true when omitted; pass false to skip a section. add_me_as_owner defaults to true and is a no-op if the caller is already an owner of the source hunt.
generate_scorecard_criterion
ChatGPTPurpose: Propose 2–3 wordings for one new scorecard criterion that the user can pick from. NOT for: Replacing the whole scorecard (regenerate_hunt_scorecard). Not for persisting — it returns suggestions; call update_hunt_scorecard to commit a chosen one. Returns: A small array of candidate criterion drafts. Workflow: Server-side already follows get_authoring_guide("scorecard_criterion") rules. If the user is asking you to draft the wording before committing, fetch the guide first for the same rules. When to use: "Add a criterion about X" — gather options, let the user choose, then call update_hunt_scorecard with the chosen wording + a sensible rank.
generate_scorecard_criterion
ChatGPTPurpose: Propose 2–3 wordings for one new scorecard criterion that the user can pick from. NOT for: Replacing the whole scorecard (regenerate_hunt_scorecard). Not for persisting — it returns suggestions; call update_hunt_scorecard to commit a chosen one. Returns: A small array of candidate criterion drafts. Workflow: Server-side already follows get_authoring_guide("scorecard_criterion") rules. If the user is asking you to draft the wording before committing, fetch the guide first for the same rules. When to use: "Add a criterion about X" — gather options, let the user choose, then call update_hunt_scorecard with the chosen wording + a sensible rank.
generate_scorecard_criterion
ChatGPTPurpose: Propose 2–3 wordings for one new scorecard criterion that the user can pick from. NOT for: Replacing the whole scorecard (regenerate_hunt_scorecard). Not for persisting — it returns suggestions; call update_hunt_scorecard to commit a chosen one. Returns: A small array of candidate criterion drafts. Workflow: Server-side already follows get_authoring_guide("scorecard_criterion") rules. If the user is asking you to draft the wording before committing, fetch the guide first for the same rules. When to use: "Add a criterion about X" — gather options, let the user choose, then call update_hunt_scorecard with the chosen wording + a sensible rank.
get_authoring_guide
ChatGPTPurpose: Fetch the in-house authoring rules + canonical variable list for one kind of artifact you're about to write (outreach message, connection note, scorecard criterion, requirements filter, sourcing setup). The same rules drive Umamy's built-in AI generators — calling this keeps your output consistent with what the user already sees elsewhere in the product. NOT for: Reading the hunt's values (use get_hunt_criteria / get_hunt_scorecard / get_hunt_configuration). This tool returns editorial guidance, not data. Returns: { kind, guide: string } — a markdown blob to follow when drafting. For message-template kinds the markdown includes a table of the only allowed {{ placeholders }}; using anything else will be rejected by the write tool. When to use: Before any of these writes, especially the first time per conversation. Cheap to call. - Before set_hunt_message_sequence (intro / follow-ups / approve / reject) → kind: "outreach_message". - Before set_hunt_message_sequence with connection_note_template → kind: "connection_note" (smaller placeholder set, 200-char limit). - Before update_hunt_scorecard / generate_scorecard_criterion / regenerate_hunt_scorecard → kind: "scorecard_criterion". - Before update_hunt_criteria / apply_hunt_criteria_list → kind: "filters". - Before set_hunt_sourcing → kind: "sourcing".
get_authoring_guide
ChatGPTPurpose: Fetch the in-house authoring rules + canonical variable list for one kind of artifact you're about to write (outreach message, connection note, scorecard criterion, requirements filter, sourcing setup). The same rules drive Umamy's built-in AI generators — calling this keeps your output consistent with what the user already sees elsewhere in the product. NOT for: Reading the hunt's values (use get_hunt_criteria / get_hunt_scorecard / get_hunt_configuration). This tool returns editorial guidance, not data. Returns: { kind, guide: string } — a markdown blob to follow when drafting. For message-template kinds the markdown includes a table of the only allowed {{ placeholders }}; using anything else will be rejected by the write tool. When to use: Before any of these writes, especially the first time per conversation. Cheap to call. - Before set_hunt_message_sequence (intro / follow-ups / approve / reject) → kind: "outreach_message". - Before set_hunt_message_sequence with connection_note_template → kind: "connection_note" (smaller placeholder set, 200-char limit). - Before update_hunt_scorecard / generate_scorecard_criterion / regenerate_hunt_scorecard → kind: "scorecard_criterion". - Before update_hunt_criteria / apply_hunt_criteria_list → kind: "filters". - Before set_hunt_sourcing → kind: "sourcing".
get_authoring_guide
ChatGPTPurpose: Fetch the in-house authoring rules + canonical variable list for one kind of artifact you're about to write (outreach message, connection note, scorecard criterion, requirements filter, sourcing setup). The same rules drive Umamy's built-in AI generators — calling this keeps your output consistent with what the user already sees elsewhere in the product. NOT for: Reading the hunt's values (use get_hunt_criteria / get_hunt_scorecard / get_hunt_configuration). This tool returns editorial guidance, not data. Returns: { kind, guide: string } — a markdown blob to follow when drafting. For message-template kinds the markdown includes a table of the only allowed {{ placeholders }}; using anything else will be rejected by the write tool. When to use: Before any of these writes, especially the first time per conversation. Cheap to call. - Before set_hunt_message_sequence (intro / follow-ups / approve / reject) → kind: "outreach_message". - Before set_hunt_message_sequence with connection_note_template → kind: "connection_note" (smaller placeholder set, 200-char limit). - Before update_hunt_scorecard / generate_scorecard_criterion / regenerate_hunt_scorecard → kind: "scorecard_criterion". - Before update_hunt_criteria / apply_hunt_criteria_list → kind: "filters". - Before set_hunt_sourcing → kind: "sourcing".
get_candidate
ChatGPTPurpose: Full record for one candidate — profile (name, headline, experience, education), connection status, scorecard answers, score, and the entire message thread. NOT for: Just the messages (use get_candidate_messages — same data, leaner payload). Not for notes (use get_candidate_notes). Returns: A single candidate object including messages array. Use this when you want everything in one go. When to use: User asks "tell me about candidate X", "show me [name]'s profile", "what does the team know about this candidate?". Required: Both organization_id AND hunt_id — candidates are keyed by (candidate_id, hunt_id) on the backend; the same person may appear in multiple hunts as separate records. Get hunt_id from list_candidates (each candidate is tagged with the hunt it belongs to). Workflow: list_organizations → list_candidates(org_id) → get_candidate(org_id, hunt_id, candidate_id)
get_candidate
ChatGPTPurpose: Full record for one candidate — profile (name, headline, experience, education), connection status, scorecard answers, score, and the entire message thread. NOT for: Just the messages (use get_candidate_messages — same data, leaner payload). Not for notes (use get_candidate_notes). Returns: A single candidate object including messages array. Use this when you want everything in one go. When to use: User asks "tell me about candidate X", "show me [name]'s profile", "what does the team know about this candidate?". Required: Both organization_id AND hunt_id — candidates are keyed by (candidate_id, hunt_id) on the backend; the same person may appear in multiple hunts as separate records. Get hunt_id from list_candidates (each candidate is tagged with the hunt it belongs to). Workflow: list_organizations → list_candidates(org_id) → get_candidate(org_id, hunt_id, candidate_id)
get_candidate
ChatGPTPurpose: Full record for one candidate — profile (name, headline, experience, education), connection status, scorecard answers, score, and the entire message thread. NOT for: Just the messages (use get_candidate_messages — same data, leaner payload). Not for notes (use get_candidate_notes). Returns: A single candidate object including messages array. Use this when you want everything in one go. When to use: User asks "tell me about candidate X", "show me [name]'s profile", "what does the team know about this candidate?". Required: Both organization_id AND hunt_id — candidates are keyed by (candidate_id, hunt_id) on the backend; the same person may appear in multiple hunts as separate records. Get hunt_id from list_candidates (each candidate is tagged with the hunt it belongs to). Workflow: list_organizations → list_candidates(org_id) → get_candidate(org_id, hunt_id, candidate_id)
get_candidate_messages
ChatGPTPurpose: The full LinkedIn message thread with one candidate — every message sent and received, with sender, body, timestamp, and delivery status. NOT for: Internal team notes about the candidate (use get_candidate_notes). Not for the profile / scorecard (use get_candidate). Returns: Array of messages. Outdated/superseded messages (status MESSAGE_OUTDATED) are filtered out. When to use: User asks "what did we say to candidate X?", "did [name] reply?", "show me the conversation with this person". Required: organization_id AND hunt_id. If the user just gives you a candidate name, find them with list_candidates first to grab the hunt_id tag. Workflow: list_organizations → list_candidates(org_id) → get_candidate_messages(org_id, hunt_id, candidate_id)
get_candidate_messages
ChatGPTPurpose: The full LinkedIn message thread with one candidate — every message sent and received, with sender, body, timestamp, and delivery status. NOT for: Internal team notes about the candidate (use get_candidate_notes). Not for the profile / scorecard (use get_candidate). Returns: Array of messages. Outdated/superseded messages (status MESSAGE_OUTDATED) are filtered out. When to use: User asks "what did we say to candidate X?", "did [name] reply?", "show me the conversation with this person". Required: organization_id AND hunt_id. If the user just gives you a candidate name, find them with list_candidates first to grab the hunt_id tag. Workflow: list_organizations → list_candidates(org_id) → get_candidate_messages(org_id, hunt_id, candidate_id)
get_candidate_messages
ChatGPTPurpose: The full LinkedIn message thread with one candidate — every message sent and received, with sender, body, timestamp, and delivery status. NOT for: Internal team notes about the candidate (use get_candidate_notes). Not for the profile / scorecard (use get_candidate). Returns: Array of messages. Outdated/superseded messages (status MESSAGE_OUTDATED) are filtered out. When to use: User asks "what did we say to candidate X?", "did [name] reply?", "show me the conversation with this person". Required: organization_id AND hunt_id. If the user just gives you a candidate name, find them with list_candidates first to grab the hunt_id tag. Workflow: list_organizations → list_candidates(org_id) → get_candidate_messages(org_id, hunt_id, candidate_id)
get_candidate_notes
ChatGPTPurpose: Internal notes left by team members on a candidate (free-text, ordered chronologically). Notes are NOT visible to the candidate — they're private commentary among the hiring team. NOT for: LinkedIn messages with the candidate (use get_candidate_messages). Notes and messages are completely separate systems. Returns: Array of { id, hunt_id, candidate_id, content, author_id, created_at }, oldest first. When to use: User asks "what notes have we left on X?", "what did the team think of this candidate?", "any feedback on [name]?". Note on hunt_id: Optional. If the same person is in multiple hunts, omitting hunt_id returns notes across all of them within the org; pass hunt_id to scope to one. Org-wide authorization is always enforced. Workflow: list_organizations → list_candidates(org_id) → get_candidate_notes(org_id, candidate_id, [hunt_id])
get_candidate_notes
ChatGPTPurpose: Internal notes left by team members on a candidate (free-text, ordered chronologically). Notes are NOT visible to the candidate — they're private commentary among the hiring team. NOT for: LinkedIn messages with the candidate (use get_candidate_messages). Notes and messages are completely separate systems. Returns: Array of { id, hunt_id, candidate_id, content, author_id, created_at }, oldest first. When to use: User asks "what notes have we left on X?", "what did the team think of this candidate?", "any feedback on [name]?". Note on hunt_id: Optional. If the same person is in multiple hunts, omitting hunt_id returns notes across all of them within the org; pass hunt_id to scope to one. Org-wide authorization is always enforced. Workflow: list_organizations → list_candidates(org_id) → get_candidate_notes(org_id, candidate_id, [hunt_id])
get_candidate_notes
ChatGPTPurpose: Internal notes left by team members on a candidate (free-text, ordered chronologically). Notes are NOT visible to the candidate — they're private commentary among the hiring team. NOT for: LinkedIn messages with the candidate (use get_candidate_messages). Notes and messages are completely separate systems. Returns: Array of { id, hunt_id, candidate_id, content, author_id, created_at }, oldest first. When to use: User asks "what notes have we left on X?", "what did the team think of this candidate?", "any feedback on [name]?". Note on hunt_id: Optional. If the same person is in multiple hunts, omitting hunt_id returns notes across all of them within the org; pass hunt_id to scope to one. Org-wide authorization is always enforced. Workflow: list_organizations → list_candidates(org_id) → get_candidate_notes(org_id, candidate_id, [hunt_id])
get_hunt
ChatGPTPurpose: Full record for one hunt — name, status, criteria, owner, timestamps, high-level config flags. NOT for: Pipeline funnel numbers (use get_hunt_metrics_distribution with metric=pipeline_status). Not for the scorecard / outreach config (use get_hunt_configuration). Not for candidates (use list_candidates with hunt_id). Returns: A single hunt object. When to use: User asks "tell me about hunt X", "what's the status of the Senior Engineer role?". Or you have a hunt_id from list_hunts and need its details. Workflow: list_organizations → list_hunts(org_id) → get_hunt(org_id, hunt_id)
get_hunt
ChatGPTPurpose: Full record for one hunt — name, status, criteria, owner, timestamps, high-level config flags. NOT for: Pipeline funnel numbers (use get_hunt_metrics_distribution with metric=pipeline_status). Not for the scorecard / outreach config (use get_hunt_configuration). Not for candidates (use list_candidates with hunt_id). Returns: A single hunt object. When to use: User asks "tell me about hunt X", "what's the status of the Senior Engineer role?". Or you have a hunt_id from list_hunts and need its details. Workflow: list_organizations → list_hunts(org_id) → get_hunt(org_id, hunt_id)
get_hunt
ChatGPTPurpose: Full record for one hunt — name, status, criteria, owner, timestamps, high-level config flags. NOT for: Pipeline funnel numbers (use get_hunt_metrics_distribution with metric=pipeline_status). Not for the scorecard / outreach config (use get_hunt_configuration). Not for candidates (use list_candidates with hunt_id). Returns: A single hunt object. When to use: User asks "tell me about hunt X", "what's the status of the Senior Engineer role?". Or you have a hunt_id from list_hunts and need its details. Workflow: list_organizations → list_hunts(org_id) → get_hunt(org_id, hunt_id)
get_hunt_candidate_count
ChatGPTPurpose: Get the estimated candidate pool size for the hunt's current criteria — the feedback signal used to suggest loosening (count = 0) or tightening (count in the thousands) filters. NOT for: Actually listing those candidates (use preview_hunt_candidates for a sample, or list_candidates after launch). Returns: { count: number } — a quick estimate from the search backend. Requires the hunt to have a backend_job_id; if you get a "must sync first" error, call sync_hunt_draft and retry. When to use: After every meaningful criteria edit during requirements setup, so the user sees the pool changing in real time. Workflow: update_hunt_criteria → sync_hunt_draft (if not synced) → get_hunt_candidate_count.
get_hunt_candidate_count
ChatGPTPurpose: Get the estimated candidate pool size for the hunt's current criteria — the feedback signal used to suggest loosening (count = 0) or tightening (count in the thousands) filters. NOT for: Actually listing those candidates (use preview_hunt_candidates for a sample, or list_candidates after launch). Returns: { count: number } — a quick estimate from the search backend. Requires the hunt to have a backend_job_id; if you get a "must sync first" error, call sync_hunt_draft and retry. When to use: After every meaningful criteria edit during requirements setup, so the user sees the pool changing in real time. Workflow: update_hunt_criteria → sync_hunt_draft (if not synced) → get_hunt_candidate_count.
get_hunt_candidate_count
ChatGPTPurpose: Get the estimated candidate pool size for the hunt's current criteria — the feedback signal used to suggest loosening (count = 0) or tightening (count in the thousands) filters. NOT for: Actually listing those candidates (use preview_hunt_candidates for a sample, or list_candidates after launch). Returns: { count: number } — a quick estimate from the search backend. Requires the hunt to have a backend_job_id; if you get a "must sync first" error, call sync_hunt_draft and retry. When to use: After every meaningful criteria edit during requirements setup, so the user sees the pool changing in real time. Workflow: update_hunt_criteria → sync_hunt_draft (if not synced) → get_hunt_candidate_count.
get_hunt_configuration
ChatGPTPurpose: Inspect how a hunt is configured — the scoring rubric (scorecard), outreach message templates, and automation rules. NOT for: Pipeline numbers (use get_hunt_metrics_distribution with metric=pipeline_status). Not for the candidate list. Not for editing — this is read-only; configuration changes happen in the Umamy dashboard. Returns: Nested object with scorecard (criteria + weights), outreach (message templates / sequences), and automation (auto-actions on connection events). When to use: User asks "how is hunt X scoring candidates?", "what messages are being sent on the Senior Engineer hunt?", "show me the outreach setup", or wants to debug why candidates are scored a certain way. Workflow: list_organizations → list_hunts(org_id) → get_hunt_configuration(org_id, hunt_id)
get_hunt_configuration
ChatGPTPurpose: Inspect how a hunt is configured — the scoring rubric (scorecard), outreach message templates, and automation rules. NOT for: Pipeline numbers (use get_hunt_metrics_distribution with metric=pipeline_status). Not for the candidate list. Not for editing — this is read-only; configuration changes happen in the Umamy dashboard. Returns: Nested object with scorecard (criteria + weights), outreach (message templates / sequences), and automation (auto-actions on connection events). When to use: User asks "how is hunt X scoring candidates?", "what messages are being sent on the Senior Engineer hunt?", "show me the outreach setup", or wants to debug why candidates are scored a certain way. Workflow: list_organizations → list_hunts(org_id) → get_hunt_configuration(org_id, hunt_id)
get_hunt_configuration
ChatGPTPurpose: Inspect how a hunt is configured — the scoring rubric (scorecard), outreach message templates, and automation rules. NOT for: Pipeline numbers (use get_hunt_metrics_distribution with metric=pipeline_status). Not for the candidate list. Not for editing — this is read-only; configuration changes happen in the Umamy dashboard. Returns: Nested object with scorecard (criteria + weights), outreach (message templates / sequences), and automation (auto-actions on connection events). When to use: User asks "how is hunt X scoring candidates?", "what messages are being sent on the Senior Engineer hunt?", "show me the outreach setup", or wants to debug why candidates are scored a certain way. Workflow: list_organizations → list_hunts(org_id) → get_hunt_configuration(org_id, hunt_id)
get_hunt_criteria
ChatGPTPurpose: Read all candidate-filter fields on a hunt — the rows on hunt_criteria joined with their field templates so you know the slug, the human name, the type (text / select / multiselect / tags / entity-search / location / structured_object), whether it's required, current value, and option set for select fields. NOT for: The scoring rubric (use get_hunt_scorecard). Not for the outreach config or sourcing settings (use get_hunt_configuration). Not for resolving raw text into entity IDs — use search_hunt_entities for that. Returns: { criteria: [{ field_slug, field_name, field_type, is_required, field_value?, field_value_string_array?, field_value_search_criteria_array?, field_value_location?, helper_text, theme, display_order, entity_search_type }] } — ordered by display_order. Reading the right value column for the field's type is your job (text→field_value, select/multiselect/tags→field_value_string_array, entity-search→field_value_search_criteria_array, location→field_value_location, structured_object→field_value as JSON string). When to use: - Starting a hunt-setup conversation — first call after getting the hunt id. - "What's left to fill in?" — work the is_required-and-empty rows first. - Before writing values via update_hunt_criteria — to know which columns + slug to send. Workflow: get_hunt → get_hunt_criteria → update_hunt_criteria (loop with search_hunt_entities / search_hunt_locations for entity/location fields).
get_hunt_criteria
ChatGPTPurpose: Read all candidate-filter fields on a hunt — the rows on hunt_criteria joined with their field templates so you know the slug, the human name, the type (text / select / multiselect / tags / entity-search / location / structured_object), whether it's required, current value, and option set for select fields. NOT for: The scoring rubric (use get_hunt_scorecard). Not for the outreach config or sourcing settings (use get_hunt_configuration). Not for resolving raw text into entity IDs — use search_hunt_entities for that. Returns: { criteria: [{ field_slug, field_name, field_type, is_required, field_value?, field_value_string_array?, field_value_search_criteria_array?, field_value_location?, helper_text, theme, display_order, entity_search_type }] } — ordered by display_order. Reading the right value column for the field's type is your job (text→field_value, select/multiselect/tags→field_value_string_array, entity-search→field_value_search_criteria_array, location→field_value_location, structured_object→field_value as JSON string). When to use: - Starting a hunt-setup conversation — first call after getting the hunt id. - "What's left to fill in?" — work the is_required-and-empty rows first. - Before writing values via update_hunt_criteria — to know which columns + slug to send. Workflow: get_hunt → get_hunt_criteria → update_hunt_criteria (loop with search_hunt_entities / search_hunt_locations for entity/location fields).
get_hunt_criteria
ChatGPTPurpose: Read all candidate-filter fields on a hunt — the rows on hunt_criteria joined with their field templates so you know the slug, the human name, the type (text / select / multiselect / tags / entity-search / location / structured_object), whether it's required, current value, and option set for select fields. NOT for: The scoring rubric (use get_hunt_scorecard). Not for the outreach config or sourcing settings (use get_hunt_configuration). Not for resolving raw text into entity IDs — use search_hunt_entities for that. Returns: { criteria: [{ field_slug, field_name, field_type, is_required, field_value?, field_value_string_array?, field_value_search_criteria_array?, field_value_location?, helper_text, theme, display_order, entity_search_type }] } — ordered by display_order. Reading the right value column for the field's type is your job (text→field_value, select/multiselect/tags→field_value_string_array, entity-search→field_value_search_criteria_array, location→field_value_location, structured_object→field_value as JSON string). When to use: - Starting a hunt-setup conversation — first call after getting the hunt id. - "What's left to fill in?" — work the is_required-and-empty rows first. - Before writing values via update_hunt_criteria — to know which columns + slug to send. Workflow: get_hunt → get_hunt_criteria → update_hunt_criteria (loop with search_hunt_entities / search_hunt_locations for entity/location fields).
get_hunt_metrics_distribution
ChatGPTPurpose: Bucket distribution for one hunt-analytics metric. Powers histograms (score, years-of-experience), pie charts (sentiment, tags), and the kanban-style pipeline funnel. Forwards to AWS gateway /metrics_distribution. NOT for: "Over time" trends (use get_hunt_metrics_timeseries). Not for fetching individual candidates (use list_candidates). Returns: { ok, metric, date_range, buckets: [{ range, total, per_job }], jobs, meta: { total_candidates, total_jobs, returned_jobs } }. Each bucket is a category; per_job breaks the count down by hunt. Available metrics: - pipeline_status — candidate funnel (INGESTION → CONNECTION_SENT → CONNECTED → CANDIDATE_APPROVED → REJECTED_MERGED…). Use this for "candidates by status" / "what's the funnel" questions. - score — fit-score distribution in 10 buckets (0-10, 11-20, …, 91-100) - yoe — years-of-experience distribution (<1y, 1-2y, 3-5y, 6-10y, 10+y) - sentiment — POSITIVE / NEGATIVE / NEUTRAL counts of candidate replies - tags — tag counts (sorted descending; respects top_n) When to use: - "What's the funnel on hunt X?", "score distribution across my org", "sentiment of replies on the Senior Engineer hunt", "top tags on candidates" Workflow: - Org-wide distribution: list_organizations → get_hunt_metrics_distribution(org_id, metric) - Per-hunt funnel: list_organizations → list_hunts(org_id) → get_hunt_metrics_distribution(org_id, "pipeline_status", hunt_id) - Cross-org: list_organizations → loop through every id, calling this tool per org → combine yourself `top_n`: Only meaningful for tags and across-hunt distributions where there are many jobs — caps the per_job breakdown and merges the rest into _other.
get_hunt_metrics_distribution
ChatGPTPurpose: Bucket distribution for one hunt-analytics metric. Powers histograms (score, years-of-experience), pie charts (sentiment, tags), and the kanban-style pipeline funnel. Forwards to AWS gateway /metrics_distribution. NOT for: "Over time" trends (use get_hunt_metrics_timeseries). Not for fetching individual candidates (use list_candidates). Returns: { ok, metric, date_range, buckets: [{ range, total, per_job }], jobs, meta: { total_candidates, total_jobs, returned_jobs } }. Each bucket is a category; per_job breaks the count down by hunt. Available metrics: - pipeline_status — candidate funnel (INGESTION → CONNECTION_SENT → CONNECTED → CANDIDATE_APPROVED → REJECTED_MERGED…). Use this for "candidates by status" / "what's the funnel" questions. - score — fit-score distribution in 10 buckets (0-10, 11-20, …, 91-100) - yoe — years-of-experience distribution (<1y, 1-2y, 3-5y, 6-10y, 10+y) - sentiment — POSITIVE / NEGATIVE / NEUTRAL counts of candidate replies - tags — tag counts (sorted descending; respects top_n) When to use: - "What's the funnel on hunt X?", "score distribution across my org", "sentiment of replies on the Senior Engineer hunt", "top tags on candidates" Workflow: - Org-wide distribution: list_organizations → get_hunt_metrics_distribution(org_id, metric) - Per-hunt funnel: list_organizations → list_hunts(org_id) → get_hunt_metrics_distribution(org_id, "pipeline_status", hunt_id) - Cross-org: list_organizations → loop through every id, calling this tool per org → combine yourself `top_n`: Only meaningful for tags and across-hunt distributions where there are many jobs — caps the per_job breakdown and merges the rest into _other.
get_hunt_metrics_distribution
ChatGPTPurpose: Bucket distribution for one hunt-analytics metric. Powers histograms (score, years-of-experience), pie charts (sentiment, tags), and the kanban-style pipeline funnel. Forwards to AWS gateway /metrics_distribution. NOT for: "Over time" trends (use get_hunt_metrics_timeseries). Not for fetching individual candidates (use list_candidates). Returns: { ok, metric, date_range, buckets: [{ range, total, per_job }], jobs, meta: { total_candidates, total_jobs, returned_jobs } }. Each bucket is a category; per_job breaks the count down by hunt. Available metrics: - pipeline_status — candidate funnel (INGESTION → CONNECTION_SENT → CONNECTED → CANDIDATE_APPROVED → REJECTED_MERGED…). Use this for "candidates by status" / "what's the funnel" questions. - score — fit-score distribution in 10 buckets (0-10, 11-20, …, 91-100) - yoe — years-of-experience distribution (<1y, 1-2y, 3-5y, 6-10y, 10+y) - sentiment — POSITIVE / NEGATIVE / NEUTRAL counts of candidate replies - tags — tag counts (sorted descending; respects top_n) When to use: - "What's the funnel on hunt X?", "score distribution across my org", "sentiment of replies on the Senior Engineer hunt", "top tags on candidates" Workflow: - Org-wide distribution: list_organizations → get_hunt_metrics_distribution(org_id, metric) - Per-hunt funnel: list_organizations → list_hunts(org_id) → get_hunt_metrics_distribution(org_id, "pipeline_status", hunt_id) - Cross-org: list_organizations → loop through every id, calling this tool per org → combine yourself `top_n`: Only meaningful for tags and across-hunt distributions where there are many jobs — caps the per_job breakdown and merges the rest into _other.
get_hunt_metrics_timeseries
ChatGPTPurpose: Time-series counter for one hunt-analytics metric over time. Powers trend charts ("messages sent per week", "connections accepted over the last 30 days"). Forwards to AWS gateway /metrics_timeseries. NOT for: Bucket distributions like score histograms or pipeline funnels (use get_hunt_metrics_distribution). Not for organization-level metrics like team members or billing. Returns: { ok, metric, date_range: { from, to }, interval, total, series: [{ period, total, ...per_job }], series_keys }. Each series entry is a time bucket; per_job keys break the count down by hunt. Available metrics: - candidates_sourced — new candidates added to the funnel (INSERT events) - candidates_enriched — candidates that passed enrichment - connections_sent — LinkedIn connection requests sent - connections_accepted — connection requests accepted by the candidate - messages_sent — outbound messages sent to candidates - messages_received — inbound replies from candidates - positive_responses — replies with POSITIVE sentiment - negative_responses — replies with NEGATIVE sentiment - neutral_responses — replies with NEUTRAL sentiment - candidates_shortlisted — candidates moved to CANDIDATE_APPROVED - candidates_rejected — CONNECTION_REJECTED_, CANDIDATE_REJECTED - `candidates_not_interested` — CANDIDATE_NOT_INTERESTED When to use: - "How many connections were sent this week?", "trend of replies over the last month", "show messages sent per day on hunt X" - Any "over time" question Workflow: - Org-wide trend: list_organizations → get_hunt_metrics_timeseries(org_id, metric) - Per-hunt trend: list_organizations → list_hunts(org_id) → get_hunt_metrics_timeseries(org_id, metric, hunt_id) - Cross-org trend: list_organizations → loop through every id, calling this tool per org → combine yourself (note: response shapes don't merge cleanly; per-org summaries are usually what users want) Date filters: date_from / date_to accept ISO 8601 (2026-04-01) or relative (-30d, -1y). interval is day | week | month and defaults sensibly based on range. Computed rates: Rates like "connection acceptance rate" are not stored — derive them by calling two timeseries (connections_accepted and connections_sent) and dividing.
get_hunt_metrics_timeseries
ChatGPTPurpose: Time-series counter for one hunt-analytics metric over time. Powers trend charts ("messages sent per week", "connections accepted over the last 30 days"). Forwards to AWS gateway /metrics_timeseries. NOT for: Bucket distributions like score histograms or pipeline funnels (use get_hunt_metrics_distribution). Not for organization-level metrics like team members or billing. Returns: { ok, metric, date_range: { from, to }, interval, total, series: [{ period, total, ...per_job }], series_keys }. Each series entry is a time bucket; per_job keys break the count down by hunt. Available metrics: - candidates_sourced — new candidates added to the funnel (INSERT events) - candidates_enriched — candidates that passed enrichment - connections_sent — LinkedIn connection requests sent - connections_accepted — connection requests accepted by the candidate - messages_sent — outbound messages sent to candidates - messages_received — inbound replies from candidates - positive_responses — replies with POSITIVE sentiment - negative_responses — replies with NEGATIVE sentiment - neutral_responses — replies with NEUTRAL sentiment - candidates_shortlisted — candidates moved to CANDIDATE_APPROVED - candidates_rejected — CONNECTION_REJECTED_, CANDIDATE_REJECTED - `candidates_not_interested` — CANDIDATE_NOT_INTERESTED When to use: - "How many connections were sent this week?", "trend of replies over the last month", "show messages sent per day on hunt X" - Any "over time" question Workflow: - Org-wide trend: list_organizations → get_hunt_metrics_timeseries(org_id, metric) - Per-hunt trend: list_organizations → list_hunts(org_id) → get_hunt_metrics_timeseries(org_id, metric, hunt_id) - Cross-org trend: list_organizations → loop through every id, calling this tool per org → combine yourself (note: response shapes don't merge cleanly; per-org summaries are usually what users want) Date filters: date_from / date_to accept ISO 8601 (2026-04-01) or relative (-30d, -1y). interval is day | week | month and defaults sensibly based on range. Computed rates: Rates like "connection acceptance rate" are not stored — derive them by calling two timeseries (connections_accepted and connections_sent) and dividing.
get_hunt_metrics_timeseries
ChatGPTPurpose: Time-series counter for one hunt-analytics metric over time. Powers trend charts ("messages sent per week", "connections accepted over the last 30 days"). Forwards to AWS gateway /metrics_timeseries. NOT for: Bucket distributions like score histograms or pipeline funnels (use get_hunt_metrics_distribution). Not for organization-level metrics like team members or billing. Returns: { ok, metric, date_range: { from, to }, interval, total, series: [{ period, total, ...per_job }], series_keys }. Each series entry is a time bucket; per_job keys break the count down by hunt. Available metrics: - candidates_sourced — new candidates added to the funnel (INSERT events) - candidates_enriched — candidates that passed enrichment - connections_sent — LinkedIn connection requests sent - connections_accepted — connection requests accepted by the candidate - messages_sent — outbound messages sent to candidates - messages_received — inbound replies from candidates - positive_responses — replies with POSITIVE sentiment - negative_responses — replies with NEGATIVE sentiment - neutral_responses — replies with NEUTRAL sentiment - candidates_shortlisted — candidates moved to CANDIDATE_APPROVED - candidates_rejected — CONNECTION_REJECTED_, CANDIDATE_REJECTED - `candidates_not_interested` — CANDIDATE_NOT_INTERESTED When to use: - "How many connections were sent this week?", "trend of replies over the last month", "show messages sent per day on hunt X" - Any "over time" question Workflow: - Org-wide trend: list_organizations → get_hunt_metrics_timeseries(org_id, metric) - Per-hunt trend: list_organizations → list_hunts(org_id) → get_hunt_metrics_timeseries(org_id, metric, hunt_id) - Cross-org trend: list_organizations → loop through every id, calling this tool per org → combine yourself (note: response shapes don't merge cleanly; per-org summaries are usually what users want) Date filters: date_from / date_to accept ISO 8601 (2026-04-01) or relative (-30d, -1y). interval is day | week | month and defaults sensibly based on range. Computed rates: Rates like "connection acceptance rate" are not stored — derive them by calling two timeseries (connections_accepted and connections_sent) and dividing.
get_hunt_scorecard
ChatGPTPurpose: Read the evaluation scorecard for a hunt — the list of { id, text, is_mandatory, rank } items each candidate will be scored against. NOT for: Candidate-filter criteria (get_hunt_criteria). Not for individual candidate scores (use the candidate tools). Returns: { criteria: [{ id, text, is_mandatory, rank }] } — empty list if no scorecard has been built yet. When to use: Before update_hunt_scorecard (read-modify-write), or to check whether the scorecard meets the "≥3 items" bar before treating the scorecard step as done. Workflow: get_hunt_criteria (hiring brief) → get_hunt_scorecard → update_hunt_scorecard (or regenerate_hunt_scorecard / generate_scorecard_criterion for AI-assisted drafting).
get_hunt_scorecard
ChatGPTPurpose: Read the evaluation scorecard for a hunt — the list of { id, text, is_mandatory, rank } items each candidate will be scored against. NOT for: Candidate-filter criteria (get_hunt_criteria). Not for individual candidate scores (use the candidate tools). Returns: { criteria: [{ id, text, is_mandatory, rank }] } — empty list if no scorecard has been built yet. When to use: Before update_hunt_scorecard (read-modify-write), or to check whether the scorecard meets the "≥3 items" bar before treating the scorecard step as done. Workflow: get_hunt_criteria (hiring brief) → get_hunt_scorecard → update_hunt_scorecard (or regenerate_hunt_scorecard / generate_scorecard_criterion for AI-assisted drafting).
get_hunt_scorecard
ChatGPTPurpose: Read the evaluation scorecard for a hunt — the list of { id, text, is_mandatory, rank } items each candidate will be scored against. NOT for: Candidate-filter criteria (get_hunt_criteria). Not for individual candidate scores (use the candidate tools). Returns: { criteria: [{ id, text, is_mandatory, rank }] } — empty list if no scorecard has been built yet. When to use: Before update_hunt_scorecard (read-modify-write), or to check whether the scorecard meets the "≥3 items" bar before treating the scorecard step as done. Workflow: get_hunt_criteria (hiring brief) → get_hunt_scorecard → update_hunt_scorecard (or regenerate_hunt_scorecard / generate_scorecard_criterion for AI-assisted drafting).
get_hunt_setup_checklist
ChatGPTPurpose: Backend-computed "what's left to set up" checklist for one hunt. Mirrors the hunt-edit stepper and returns only the items that are relevant (LinkedIn / message-sequence items appear only for outbound hunts; the ATS item appears only when the org has an active ATS connection). Each item is server-evaluated as complete from the authoritative state (Supabase hunt_criteria / hunts.persona_id + AWS Job sourcing / scorecard / outreach / ATS). NOT for: How the hunt is configured today (use get_hunt_configuration — that returns the actual scorecard rubric, outreach templates, automation rules). Not for editing — this is read-only; the matching write tools (set_hunt_sourcing, update_hunt_criteria, update_hunt_scorecard, set_hunt_persona, set_hunt_message_sequence, set_hunt_ats_routing) live in the hunt-setup toolset. Not for pipeline funnel numbers (use get_hunt_metrics_distribution). Returns: { items: [{ key, step: "sourcing"|"requirements"|"scorecard"|"outreach", order, description, instructions, complete }], finished }. key is the stable item identifier (setup_sourcing, clarify_key_requirements, establish_scorecard, connect_linkedin_account, setup_message_sequence, connect_ats) — clients use it to localize description. order is contiguous after irrelevant items are filtered out. instructions is server-owned English guidance for the AI on how to complete that item (it points at the matching get_authoring_guide(kind) + the write tool to use); translate when you speak to the user, per the "match the user's language" rule. finished is true only when every returned item is complete. When to use: - User asks "what's left to set up hunt X?", "is hunt X ready to launch?", "why can't I launch?", "what's the next step on the SDR hunt?" - Start of a hunt-setup conversation, to plan the walkthrough - Before claiming a hunt is ready to launch — never say it's ready unless finished === true Workflow: get_hunt_setup_checklist(org_id, hunt_id) → for each complete: false item in order, follow its instructions (which calls out get_authoring_guide(kind) + the right write tool) → re-call get_hunt_setup_checklist after meaningful writes to surface progress.
get_hunt_setup_checklist
ChatGPTPurpose: Backend-computed "what's left to set up" checklist for one hunt. Mirrors the hunt-edit stepper and returns only the items that are relevant (LinkedIn / message-sequence items appear only for outbound hunts; the ATS item appears only when the org has an active ATS connection). Each item is server-evaluated as complete from the authoritative state (Supabase hunt_criteria / hunts.persona_id + AWS Job sourcing / scorecard / outreach / ATS). NOT for: How the hunt is configured today (use get_hunt_configuration — that returns the actual scorecard rubric, outreach templates, automation rules). Not for editing — this is read-only; the matching write tools (set_hunt_sourcing, update_hunt_criteria, update_hunt_scorecard, set_hunt_persona, set_hunt_message_sequence, set_hunt_ats_routing) live in the hunt-setup toolset. Not for pipeline funnel numbers (use get_hunt_metrics_distribution). Returns: { items: [{ key, step: "sourcing"|"requirements"|"scorecard"|"outreach", order, description, instructions, complete }], finished }. key is the stable item identifier (setup_sourcing, clarify_key_requirements, establish_scorecard, connect_linkedin_account, setup_message_sequence, connect_ats) — clients use it to localize description. order is contiguous after irrelevant items are filtered out. instructions is server-owned English guidance for the AI on how to complete that item (it points at the matching get_authoring_guide(kind) + the write tool to use); translate when you speak to the user, per the "match the user's language" rule. finished is true only when every returned item is complete. When to use: - User asks "what's left to set up hunt X?", "is hunt X ready to launch?", "why can't I launch?", "what's the next step on the SDR hunt?" - Start of a hunt-setup conversation, to plan the walkthrough - Before claiming a hunt is ready to launch — never say it's ready unless finished === true Workflow: get_hunt_setup_checklist(org_id, hunt_id) → for each complete: false item in order, follow its instructions (which calls out get_authoring_guide(kind) + the right write tool) → re-call get_hunt_setup_checklist after meaningful writes to surface progress.
get_hunt_setup_checklist
ChatGPTPurpose: Backend-computed "what's left to set up" checklist for one hunt. Mirrors the hunt-edit stepper and returns only the items that are relevant (LinkedIn / message-sequence items appear only for outbound hunts; the ATS item appears only when the org has an active ATS connection). Each item is server-evaluated as complete from the authoritative state (Supabase hunt_criteria / hunts.persona_id + AWS Job sourcing / scorecard / outreach / ATS). NOT for: How the hunt is configured today (use get_hunt_configuration — that returns the actual scorecard rubric, outreach templates, automation rules). Not for editing — this is read-only; the matching write tools (set_hunt_sourcing, update_hunt_criteria, update_hunt_scorecard, set_hunt_persona, set_hunt_message_sequence, set_hunt_ats_routing) live in the hunt-setup toolset. Not for pipeline funnel numbers (use get_hunt_metrics_distribution). Returns: { items: [{ key, step: "sourcing"|"requirements"|"scorecard"|"outreach", order, description, instructions, complete }], finished }. key is the stable item identifier (setup_sourcing, clarify_key_requirements, establish_scorecard, connect_linkedin_account, setup_message_sequence, connect_ats) — clients use it to localize description. order is contiguous after irrelevant items are filtered out. instructions is server-owned English guidance for the AI on how to complete that item (it points at the matching get_authoring_guide(kind) + the write tool to use); translate when you speak to the user, per the "match the user's language" rule. finished is true only when every returned item is complete. When to use: - User asks "what's left to set up hunt X?", "is hunt X ready to launch?", "why can't I launch?", "what's the next step on the SDR hunt?" - Start of a hunt-setup conversation, to plan the walkthrough - Before claiming a hunt is ready to launch — never say it's ready unless finished === true Workflow: get_hunt_setup_checklist(org_id, hunt_id) → for each complete: false item in order, follow its instructions (which calls out get_authoring_guide(kind) + the right write tool) → re-call get_hunt_setup_checklist after meaningful writes to surface progress.
get_organization_metrics
ChatGPTPurpose: Hunt totals by lifecycle status — { total_hunts, live_hunts, draft_hunts, paused_hunts, completed_hunts }. Counts hunts themselves, not candidates inside them. NOT for: Per-hunt candidate funnel numbers (use get_hunt_metrics_distribution with metric=pipeline_status). Not for activity analytics like connections_sent or messages_received (use get_hunt_metrics_timeseries). Returns: { total_hunts, live_hunts, draft_hunts, paused_hunts, completed_hunts } for one org. When to use: User asks "how many hunts do I have?", "how many active campaigns?", "give me an overview of my workspace". Workflow: list_organizations → get_organization_metrics(org_id) Cross-org: Always returns counts for one org. To answer "how many hunts across all my orgs?", loop: list_organizations → for each id, get_organization_metrics(id) → sum yourself.
get_organization_metrics
ChatGPTPurpose: Hunt totals by lifecycle status — { total_hunts, live_hunts, draft_hunts, paused_hunts, completed_hunts }. Counts hunts themselves, not candidates inside them. NOT for: Per-hunt candidate funnel numbers (use get_hunt_metrics_distribution with metric=pipeline_status). Not for activity analytics like connections_sent or messages_received (use get_hunt_metrics_timeseries). Returns: { total_hunts, live_hunts, draft_hunts, paused_hunts, completed_hunts } for one org. When to use: User asks "how many hunts do I have?", "how many active campaigns?", "give me an overview of my workspace". Workflow: list_organizations → get_organization_metrics(org_id) Cross-org: Always returns counts for one org. To answer "how many hunts across all my orgs?", loop: list_organizations → for each id, get_organization_metrics(id) → sum yourself.
get_organization_metrics
ChatGPTPurpose: Hunt totals by lifecycle status — { total_hunts, live_hunts, draft_hunts, paused_hunts, completed_hunts }. Counts hunts themselves, not candidates inside them. NOT for: Per-hunt candidate funnel numbers (use get_hunt_metrics_distribution with metric=pipeline_status). Not for activity analytics like connections_sent or messages_received (use get_hunt_metrics_timeseries). Returns: { total_hunts, live_hunts, draft_hunts, paused_hunts, completed_hunts } for one org. When to use: User asks "how many hunts do I have?", "how many active campaigns?", "give me an overview of my workspace". Workflow: list_organizations → get_organization_metrics(org_id) Cross-org: Always returns counts for one org. To answer "how many hunts across all my orgs?", loop: list_organizations → for each id, get_organization_metrics(id) → sum yourself.
list_ats_connections
ChatGPTPurpose: List the org's active ATS connections (Workable, Greenhouse, Lever, Ashby, …). Use this to decide whether the "Connect ATS" item on the setup checklist is relevant and which connection to map to the hunt. NOT for: Connecting a new ATS — that's a browser OAuth flow handled by the in-app AtsConnectionModal (surfaced via the local "Connect ATS" chat button). Returns: { ats_connections: [...] } — pick ats_connection_pk to then call list_ats_jobs, then map via update_hunt_configuration. When to use: Anywhere ATS is in scope — before mapping the hunt to an ATS job, before suggesting the user connect a new ATS.
list_ats_connections
ChatGPTPurpose: List the org's active ATS connections (Workable, Greenhouse, Lever, Ashby, …). Use this to decide whether the "Connect ATS" item on the setup checklist is relevant and which connection to map to the hunt. NOT for: Connecting a new ATS — that's a browser OAuth flow handled by the in-app AtsConnectionModal (surfaced via the local "Connect ATS" chat button). Returns: { ats_connections: [...] } — pick ats_connection_pk to then call list_ats_jobs, then map via update_hunt_configuration. When to use: Anywhere ATS is in scope — before mapping the hunt to an ATS job, before suggesting the user connect a new ATS.
list_ats_connections
ChatGPTPurpose: List the org's active ATS connections (Workable, Greenhouse, Lever, Ashby, …). Use this to decide whether the "Connect ATS" item on the setup checklist is relevant and which connection to map to the hunt. NOT for: Connecting a new ATS — that's a browser OAuth flow handled by the in-app AtsConnectionModal (surfaced via the local "Connect ATS" chat button). Returns: { ats_connections: [...] } — pick ats_connection_pk to then call list_ats_jobs, then map via update_hunt_configuration. When to use: Anywhere ATS is in scope — before mapping the hunt to an ATS job, before suggesting the user connect a new ATS.
list_ats_jobs
ChatGPTPurpose: List jobs available on one ATS connection so the assistant can pick the right ats_job_id to map to the hunt. NOT for: Listing connections (list_ats_connections first). Not for writing the mapping — pair with update_hunt_configuration (ats_connection_pk + ats_job_id). Returns: { ats_jobs: [...] }. When to use: Right before update_hunt_configuration in inbound-with-ATS or send-approved-to-ATS flows.
list_ats_jobs
ChatGPTPurpose: List jobs available on one ATS connection so the assistant can pick the right ats_job_id to map to the hunt. NOT for: Listing connections (list_ats_connections first). Not for writing the mapping — pair with update_hunt_configuration (ats_connection_pk + ats_job_id). Returns: { ats_jobs: [...] }. When to use: Right before update_hunt_configuration in inbound-with-ATS or send-approved-to-ATS flows.
list_ats_jobs
ChatGPTPurpose: List jobs available on one ATS connection so the assistant can pick the right ats_job_id to map to the hunt. NOT for: Listing connections (list_ats_connections first). Not for writing the mapping — pair with update_hunt_configuration (ats_connection_pk + ats_job_id). Returns: { ats_jobs: [...] }. When to use: Right before update_hunt_configuration in inbound-with-ATS or send-approved-to-ATS flows.
list_candidates
ChatGPTPurpose: List candidates (profiles surfaced into a hunt's pipeline) for one organization. Each candidate has a profile, connection status, score, and message thread. NOT for: Listing hunts (use list_hunts). Not for a single candidate's full record (use get_candidate). Not for messages or notes (use list_messages / list_notes or the candidate-scoped variants). Returns: Array of candidate objects with profile fields, connection_status, score, scorecard answers, message thread, and a hunt_id tag (so you can resolve back to the hunt for follow-up calls). When to use: - User asks "show me candidates", "who's connected on hunt X?", "list everyone who replied" - Need to find a candidate_id before drilling into get_candidate / get_candidate_messages / get_candidate_notes Workflow: list_organizations → list_candidates(org_id, [hunt_id], [status]) → get_candidate(org_id, hunt_id, candidate_id) / get_candidate_messages(...) / get_candidate_notes(...) Filters: - hunt_id — scope to a single hunt's pipeline - status — filter by connection status (e.g. CONNECTED, PENDING, REPLIED, REJECTED) Pagination: Set limit (and pass cursor from a previous response's next_cursor) to page through one hunt's candidates — only works when hunt_id is set. Without hunt_id the v1 endpoint fans out across every hunt in the org and returns a single merged page; use limit to cap. Cross-org: Always returns candidates for one org. To search across orgs, loop: list_organizations → for each id, list_candidates(id) → combine yourself.
list_candidates
ChatGPTPurpose: List candidates (profiles surfaced into a hunt's pipeline) for one organization. Each candidate has a profile, connection status, score, and message thread. NOT for: Listing hunts (use list_hunts). Not for a single candidate's full record (use get_candidate). Not for messages or notes (use list_messages / list_notes or the candidate-scoped variants). Returns: Array of candidate objects with profile fields, connection_status, score, scorecard answers, message thread, and a hunt_id tag (so you can resolve back to the hunt for follow-up calls). When to use: - User asks "show me candidates", "who's connected on hunt X?", "list everyone who replied" - Need to find a candidate_id before drilling into get_candidate / get_candidate_messages / get_candidate_notes Workflow: list_organizations → list_candidates(org_id, [hunt_id], [status]) → get_candidate(org_id, hunt_id, candidate_id) / get_candidate_messages(...) / get_candidate_notes(...) Filters: - hunt_id — scope to a single hunt's pipeline - status — filter by connection status (e.g. CONNECTED, PENDING, REPLIED, REJECTED) Pagination: Set limit (and pass cursor from a previous response's next_cursor) to page through one hunt's candidates — only works when hunt_id is set. Without hunt_id the v1 endpoint fans out across every hunt in the org and returns a single merged page; use limit to cap. Cross-org: Always returns candidates for one org. To search across orgs, loop: list_organizations → for each id, list_candidates(id) → combine yourself.
list_candidates
ChatGPTPurpose: List candidates (profiles surfaced into a hunt's pipeline) for one organization. Each candidate has a profile, connection status, score, and message thread. NOT for: Listing hunts (use list_hunts). Not for a single candidate's full record (use get_candidate). Not for messages or notes (use list_messages / list_notes or the candidate-scoped variants). Returns: Array of candidate objects with profile fields, connection_status, score, scorecard answers, message thread, and a hunt_id tag (so you can resolve back to the hunt for follow-up calls). When to use: - User asks "show me candidates", "who's connected on hunt X?", "list everyone who replied" - Need to find a candidate_id before drilling into get_candidate / get_candidate_messages / get_candidate_notes Workflow: list_organizations → list_candidates(org_id, [hunt_id], [status]) → get_candidate(org_id, hunt_id, candidate_id) / get_candidate_messages(...) / get_candidate_notes(...) Filters: - hunt_id — scope to a single hunt's pipeline - status — filter by connection status (e.g. CONNECTED, PENDING, REPLIED, REJECTED) Pagination: Set limit (and pass cursor from a previous response's next_cursor) to page through one hunt's candidates — only works when hunt_id is set. Without hunt_id the v1 endpoint fans out across every hunt in the org and returns a single merged page; use limit to cap. Cross-org: Always returns candidates for one org. To search across orgs, loop: list_organizations → for each id, list_candidates(id) → combine yourself.
list_hunts
ChatGPTPurpose: List hunts (recruitment campaigns) for one organization. A hunt is a single open role being filled — it has a name, target candidate criteria, an outreach configuration, and a candidate pipeline. NOT for: Listing candidates (use list_candidates). Not for hunt analytics like funnel counts or activity over time (use get_hunt_metrics_distribution / get_hunt_metrics_timeseries). Returns: Array of hunts with id, name, status (DRAFT/LIVE/PAUSED/COMPLETED), creation timestamps. Use id with the per-hunt tools below. When to use: - User asks "show my hunts", "what roles am I hunting for?", "list active campaigns" - Need a hunt id before drilling into candidates or analytics for a specific role Workflow: list_organizations → list_hunts(org_id) → get_hunt / get_hunt_configuration / list_candidates(hunt_id) / get_hunt_metrics_ Cross-org:* Always returns hunts for one org. To list across all orgs, loop: list_organizations → for each id, call list_hunts(id) in parallel → merge yourself.
list_hunts
ChatGPTPurpose: List hunts (recruitment campaigns) for one organization. A hunt is a single open role being filled — it has a name, target candidate criteria, an outreach configuration, and a candidate pipeline. NOT for: Listing candidates (use list_candidates). Not for hunt analytics like funnel counts or activity over time (use get_hunt_metrics_distribution / get_hunt_metrics_timeseries). Returns: Array of hunts with id, name, status (DRAFT/LIVE/PAUSED/COMPLETED), creation timestamps. Use id with the per-hunt tools below. When to use: - User asks "show my hunts", "what roles am I hunting for?", "list active campaigns" - Need a hunt id before drilling into candidates or analytics for a specific role Workflow: list_organizations → list_hunts(org_id) → get_hunt / get_hunt_configuration / list_candidates(hunt_id) / get_hunt_metrics_ Cross-org:* Always returns hunts for one org. To list across all orgs, loop: list_organizations → for each id, call list_hunts(id) in parallel → merge yourself.
list_hunts
ChatGPTPurpose: List hunts (recruitment campaigns) for one organization. A hunt is a single open role being filled — it has a name, target candidate criteria, an outreach configuration, and a candidate pipeline. NOT for: Listing candidates (use list_candidates). Not for hunt analytics like funnel counts or activity over time (use get_hunt_metrics_distribution / get_hunt_metrics_timeseries). Returns: Array of hunts with id, name, status (DRAFT/LIVE/PAUSED/COMPLETED), creation timestamps. Use id with the per-hunt tools below. When to use: - User asks "show my hunts", "what roles am I hunting for?", "list active campaigns" - Need a hunt id before drilling into candidates or analytics for a specific role Workflow: list_organizations → list_hunts(org_id) → get_hunt / get_hunt_configuration / list_candidates(hunt_id) / get_hunt_metrics_ Cross-org:* Always returns hunts for one org. To list across all orgs, loop: list_organizations → for each id, call list_hunts(id) in parallel → merge yourself.
list_messages
ChatGPTPurpose: Flat list of LinkedIn messages across one organization — useful for activity reports, "what got sent today?", or recent reply scans without pulling full candidate objects. NOT for: A single candidate's thread (use get_candidate_messages — same data, indexed under one person). Not for internal notes (use list_notes). Returns: Flat array of messages, each tagged with its hunt_id (so you can resolve back to the hunt). Outdated messages are filtered out. When to use: User asks "how many messages went out this week?", "show me recent replies", "list outbound messages on hunt X". Workflow: list_organizations → list_messages(org_id, [hunt_id], [candidate_id], [status]) Filters: - hunt_id — scope to one hunt - candidate_id — scope to one candidate (REQUIRES hunt_id) - status — e.g. MESSAGE_SENT, MESSAGE_RECEIVED Cross-org: Always returns messages for one org. To scan across orgs, loop: list_organizations → for each id, list_messages(id) → combine yourself.
list_messages
ChatGPTPurpose: Flat list of LinkedIn messages across one organization — useful for activity reports, "what got sent today?", or recent reply scans without pulling full candidate objects. NOT for: A single candidate's thread (use get_candidate_messages — same data, indexed under one person). Not for internal notes (use list_notes). Returns: Flat array of messages, each tagged with its hunt_id (so you can resolve back to the hunt). Outdated messages are filtered out. When to use: User asks "how many messages went out this week?", "show me recent replies", "list outbound messages on hunt X". Workflow: list_organizations → list_messages(org_id, [hunt_id], [candidate_id], [status]) Filters: - hunt_id — scope to one hunt - candidate_id — scope to one candidate (REQUIRES hunt_id) - status — e.g. MESSAGE_SENT, MESSAGE_RECEIVED Cross-org: Always returns messages for one org. To scan across orgs, loop: list_organizations → for each id, list_messages(id) → combine yourself.
list_messages
ChatGPTPurpose: Flat list of LinkedIn messages across one organization — useful for activity reports, "what got sent today?", or recent reply scans without pulling full candidate objects. NOT for: A single candidate's thread (use get_candidate_messages — same data, indexed under one person). Not for internal notes (use list_notes). Returns: Flat array of messages, each tagged with its hunt_id (so you can resolve back to the hunt). Outdated messages are filtered out. When to use: User asks "how many messages went out this week?", "show me recent replies", "list outbound messages on hunt X". Workflow: list_organizations → list_messages(org_id, [hunt_id], [candidate_id], [status]) Filters: - hunt_id — scope to one hunt - candidate_id — scope to one candidate (REQUIRES hunt_id) - status — e.g. MESSAGE_SENT, MESSAGE_RECEIVED Cross-org: Always returns messages for one org. To scan across orgs, loop: list_organizations → for each id, list_messages(id) → combine yourself.
list_notes
ChatGPTPurpose: Flat list of internal team notes across one organization. Useful for activity scans like "what did the team comment on this week?". NOT for: Notes on a single candidate (use get_candidate_notes — same data, scoped). Not for LinkedIn messages (use list_messages). Returns: Flat array of notes ordered most-recent first, each with hunt_id, candidate_id, content, author_id, created_at. When to use: User asks "show me recent team notes", "what comments has the team left on this hunt?", "list notes across my org". Workflow: list_organizations → list_notes(org_id, [hunt_id], [candidate_id]) Filters: hunt_id and/or candidate_id to scope. Cross-org: Always returns notes for one org. To scan across orgs, loop: list_organizations → for each id, list_notes(id) → combine yourself.
list_notes
ChatGPTPurpose: Flat list of internal team notes across one organization. Useful for activity scans like "what did the team comment on this week?". NOT for: Notes on a single candidate (use get_candidate_notes — same data, scoped). Not for LinkedIn messages (use list_messages). Returns: Flat array of notes ordered most-recent first, each with hunt_id, candidate_id, content, author_id, created_at. When to use: User asks "show me recent team notes", "what comments has the team left on this hunt?", "list notes across my org". Workflow: list_organizations → list_notes(org_id, [hunt_id], [candidate_id]) Filters: hunt_id and/or candidate_id to scope. Cross-org: Always returns notes for one org. To scan across orgs, loop: list_organizations → for each id, list_notes(id) → combine yourself.
list_notes
ChatGPTPurpose: Flat list of internal team notes across one organization. Useful for activity scans like "what did the team comment on this week?". NOT for: Notes on a single candidate (use get_candidate_notes — same data, scoped). Not for LinkedIn messages (use list_messages). Returns: Flat array of notes ordered most-recent first, each with hunt_id, candidate_id, content, author_id, created_at. When to use: User asks "show me recent team notes", "what comments has the team left on this hunt?", "list notes across my org". Workflow: list_organizations → list_notes(org_id, [hunt_id], [candidate_id]) Filters: hunt_id and/or candidate_id to scope. Cross-org: Always returns notes for one org. To scan across orgs, loop: list_organizations → for each id, list_notes(id) → combine yourself.
list_organizations
ChatGPTPurpose: List every Umamy organization (workspace) the signed-in user is a member of. This is your entry point — almost every other tool needs an organization_id, and this is how you discover them. NOT for: Listing hunts inside an org (use list_hunts). Not for fetching teammates, billing, or org settings. Returns: Array of { id, name, role }. Pass the id as organization_id to other tools. When to use: - First call in almost any conversation that touches Umamy data — you can't address most resources without an org id - User asks "what organizations / companies do I have access to?" - Disambiguating which org owns a hunt or candidate before drilling deeper Workflow patterns: - Single-org: list_organizations → pick one id → call list_hunts / list_candidates / get_hunt_metrics_ with that id - Cross-org analysis: list_organizations → loop through every id, calling tools per org in parallel, combine results yourself - Drill into a hunt: list_organizations → list_hunts(org_id) → get_hunt(org_id, hunt_id) - Drill into a candidate: list_organizations → list_candidates(org_id) → get_candidate(org_id, candidate's hunt_id, candidate_id) Why no automatic fan-out:* Different tools have different response shapes; cross-org merging is the model's job, not the server's. Looping is explicit, parallelisable, and shows your work.
list_organizations
ChatGPTPurpose: List every Umamy organization (workspace) the signed-in user is a member of. This is your entry point — almost every other tool needs an organization_id, and this is how you discover them. NOT for: Listing hunts inside an org (use list_hunts). Not for fetching teammates, billing, or org settings. Returns: Array of { id, name, role }. Pass the id as organization_id to other tools. When to use: - First call in almost any conversation that touches Umamy data — you can't address most resources without an org id - User asks "what organizations / companies do I have access to?" - Disambiguating which org owns a hunt or candidate before drilling deeper Workflow patterns: - Single-org: list_organizations → pick one id → call list_hunts / list_candidates / get_hunt_metrics_ with that id - Cross-org analysis: list_organizations → loop through every id, calling tools per org in parallel, combine results yourself - Drill into a hunt: list_organizations → list_hunts(org_id) → get_hunt(org_id, hunt_id) - Drill into a candidate: list_organizations → list_candidates(org_id) → get_candidate(org_id, candidate's hunt_id, candidate_id) Why no automatic fan-out:* Different tools have different response shapes; cross-org merging is the model's job, not the server's. Looping is explicit, parallelisable, and shows your work.
list_organizations
ChatGPTPurpose: List every Umamy organization (workspace) the signed-in user is a member of. This is your entry point — almost every other tool needs an organization_id, and this is how you discover them. NOT for: Listing hunts inside an org (use list_hunts). Not for fetching teammates, billing, or org settings. Returns: Array of { id, name, role }. Pass the id as organization_id to other tools. When to use: - First call in almost any conversation that touches Umamy data — you can't address most resources without an org id - User asks "what organizations / companies do I have access to?" - Disambiguating which org owns a hunt or candidate before drilling deeper Workflow patterns: - Single-org: list_organizations → pick one id → call list_hunts / list_candidates / get_hunt_metrics_ with that id - Cross-org analysis: list_organizations → loop through every id, calling tools per org in parallel, combine results yourself - Drill into a hunt: list_organizations → list_hunts(org_id) → get_hunt(org_id, hunt_id) - Drill into a candidate: list_organizations → list_candidates(org_id) → get_candidate(org_id, candidate's hunt_id, candidate_id) Why no automatic fan-out:* Different tools have different response shapes; cross-org merging is the model's job, not the server's. Looping is explicit, parallelisable, and shows your work.
list_personas
ChatGPTPurpose: List the organization's outreach personas — each ties a connected LinkedIn account to a tone-of-voice config that hunts can reuse for outbound messaging. NOT for: Connecting a new LinkedIn account — that's a browser OAuth flow handled by the in-app LinkedInConnectionDialog (the chat surfaces a "Connect LinkedIn" button locally; no MCP tool drives it). Returns: { personas: [...] } — pick a persona_id to associate with the hunt's outreach via the outreach UI (the assistant can navigate the user to the outreach step and recommend one of these). When to use: "Which LinkedIn accounts can this hunt send from?" / before suggesting the user assign a persona during outreach setup.
list_personas
ChatGPTPurpose: List the organization's outreach personas — each ties a connected LinkedIn account to a tone-of-voice config that hunts can reuse for outbound messaging. NOT for: Connecting a new LinkedIn account — that's a browser OAuth flow handled by the in-app LinkedInConnectionDialog (the chat surfaces a "Connect LinkedIn" button locally; no MCP tool drives it). Returns: { personas: [...] } — pick a persona_id to associate with the hunt's outreach via the outreach UI (the assistant can navigate the user to the outreach step and recommend one of these). When to use: "Which LinkedIn accounts can this hunt send from?" / before suggesting the user assign a persona during outreach setup.
list_personas
ChatGPTPurpose: List the organization's outreach personas — each ties a connected LinkedIn account to a tone-of-voice config that hunts can reuse for outbound messaging. NOT for: Connecting a new LinkedIn account — that's a browser OAuth flow handled by the in-app LinkedInConnectionDialog (the chat surfaces a "Connect LinkedIn" button locally; no MCP tool drives it). Returns: { personas: [...] } — pick a persona_id to associate with the hunt's outreach via the outreach UI (the assistant can navigate the user to the outreach step and recommend one of these). When to use: "Which LinkedIn accounts can this hunt send from?" / before suggesting the user assign a persona during outreach setup.
preview_hunt_candidates
ChatGPTPurpose: Fetch a small sample of candidates that match the hunt's current criteria, to sanity-check the filters before launching. Read-only — these are not yet in the hunt's pipeline. NOT for: Hard counts (use get_hunt_candidate_count). Not for the live candidate pipeline (list_candidates). Returns: { candidates: [...] } — a handful of profiles the search backend would surface today. When to use: "Show me what you'd find with these filters" / "are these the right kind of people?" — typically right before transitioning from requirements to scorecard. Workflow: Requires a backend_job_id like get_hunt_candidate_count — call sync_hunt_draft first if you've never synced.
preview_hunt_candidates
ChatGPTPurpose: Fetch a small sample of candidates that match the hunt's current criteria, to sanity-check the filters before launching. Read-only — these are not yet in the hunt's pipeline. NOT for: Hard counts (use get_hunt_candidate_count). Not for the live candidate pipeline (list_candidates). Returns: { candidates: [...] } — a handful of profiles the search backend would surface today. When to use: "Show me what you'd find with these filters" / "are these the right kind of people?" — typically right before transitioning from requirements to scorecard. Workflow: Requires a backend_job_id like get_hunt_candidate_count — call sync_hunt_draft first if you've never synced.
preview_hunt_candidates
ChatGPTPurpose: Fetch a small sample of candidates that match the hunt's current criteria, to sanity-check the filters before launching. Read-only — these are not yet in the hunt's pipeline. NOT for: Hard counts (use get_hunt_candidate_count). Not for the live candidate pipeline (list_candidates). Returns: { candidates: [...] } — a handful of profiles the search backend would surface today. When to use: "Show me what you'd find with these filters" / "are these the right kind of people?" — typically right before transitioning from requirements to scorecard. Workflow: Requires a backend_job_id like get_hunt_candidate_count — call sync_hunt_draft first if you've never synced.
regenerate_hunt_scorecard
ChatGPTPurpose: Replace the entire scorecard with an AI-generated set grounded in the hunt's hiring brief. NOT for: Tweaking one criterion (generate_scorecard_criterion). Not for committing manual edits (update_hunt_scorecard). Returns: { data: { criteria: [...] } } — the new persisted scorecard. Workflow: The server-side generator already follows get_authoring_guide("scorecard_criterion") rules — no need to fetch the guide before this tool. Fetch it only if you're planning to manually edit the result via update_hunt_scorecard afterwards. When to use: First-time scorecard creation, or when the brief changed materially.
regenerate_hunt_scorecard
ChatGPTPurpose: Replace the entire scorecard with an AI-generated set grounded in the hunt's hiring brief. NOT for: Tweaking one criterion (generate_scorecard_criterion). Not for committing manual edits (update_hunt_scorecard). Returns: { data: { criteria: [...] } } — the new persisted scorecard. Workflow: The server-side generator already follows get_authoring_guide("scorecard_criterion") rules — no need to fetch the guide before this tool. Fetch it only if you're planning to manually edit the result via update_hunt_scorecard afterwards. When to use: First-time scorecard creation, or when the brief changed materially.
regenerate_hunt_scorecard
ChatGPTPurpose: Replace the entire scorecard with an AI-generated set grounded in the hunt's hiring brief. NOT for: Tweaking one criterion (generate_scorecard_criterion). Not for committing manual edits (update_hunt_scorecard). Returns: { data: { criteria: [...] } } — the new persisted scorecard. Workflow: The server-side generator already follows get_authoring_guide("scorecard_criterion") rules — no need to fetch the guide before this tool. Fetch it only if you're planning to manually edit the result via update_hunt_scorecard afterwards. When to use: First-time scorecard creation, or when the brief changed materially.
search_hunt_entities
ChatGPTPurpose: Resolve a free-text query into the structured LinkedIn entities required by hunt filters — companies, schools, locations, job titles, job functions, industries. Returns real entity records with the IDs the criteria fields need; never invent these IDs yourself. NOT for: Reading a hunt's current values (get_hunt_criteria). Not for writing filters — pair this with update_hunt_criteria to apply the chosen results. Returns: { results: [{ id, name, logo? }] } (companies/schools/job-functions/industries) or { results: [{ country, region?, city? }] } (locations) — depending on type. Always present the names to the user and let them confirm before writing. When to use: - Whenever the user mentions a company / university / city / industry to include or exclude. - Building include/exclude company lists from a brand ("competitors of Salesforce" → multiple parallel searches). Workflow: search_hunt_entities → confirm with user via suggest_actions (in the in-app chat) → update_hunt_criteria with the returned IDs.
search_hunt_entities
ChatGPTPurpose: Resolve a free-text query into the structured LinkedIn entities required by hunt filters — companies, schools, locations, job titles, job functions, industries. Returns real entity records with the IDs the criteria fields need; never invent these IDs yourself. NOT for: Reading a hunt's current values (get_hunt_criteria). Not for writing filters — pair this with update_hunt_criteria to apply the chosen results. Returns: { results: [{ id, name, logo? }] } (companies/schools/job-functions/industries) or { results: [{ country, region?, city? }] } (locations) — depending on type. Always present the names to the user and let them confirm before writing. When to use: - Whenever the user mentions a company / university / city / industry to include or exclude. - Building include/exclude company lists from a brand ("competitors of Salesforce" → multiple parallel searches). Workflow: search_hunt_entities → confirm with user via suggest_actions (in the in-app chat) → update_hunt_criteria with the returned IDs.
search_hunt_entities
ChatGPTPurpose: Resolve a free-text query into the structured LinkedIn entities required by hunt filters — companies, schools, locations, job titles, job functions, industries. Returns real entity records with the IDs the criteria fields need; never invent these IDs yourself. NOT for: Reading a hunt's current values (get_hunt_criteria). Not for writing filters — pair this with update_hunt_criteria to apply the chosen results. Returns: { results: [{ id, name, logo? }] } (companies/schools/job-functions/industries) or { results: [{ country, region?, city? }] } (locations) — depending on type. Always present the names to the user and let them confirm before writing. When to use: - Whenever the user mentions a company / university / city / industry to include or exclude. - Building include/exclude company lists from a brand ("competitors of Salesforce" → multiple parallel searches). Workflow: search_hunt_entities → confirm with user via suggest_actions (in the in-app chat) → update_hunt_criteria with the returned IDs.
set_hunt_ats_routing
ChatGPTPurpose: Write the "ATS Sync" card on the Outreach step — what happens to candidates we approve once an ATS is connected. Whether to push them to the ATS at all, which stage they land in, which existing applicant stages we should ignore (don't message them), and whether we should skip anyone already in the recruiter's pipeline. NOT for: Mapping the hunt to a specific ATS job — that's an inbound-sourcing concern (set_hunt_sourcing(ats_connection_pk, ats_job_id)). Not for outreach messages or automation flags. Returns: { success: true, data: <full config> }. When to use: Only relevant when the org has an active ATS connection AND the hunt is mapped to a job in it (list_ats_connections non-empty, get_hunt_configuration.ats_connection_pk set). Otherwise direct the user to connect/map first.
set_hunt_ats_routing
ChatGPTPurpose: Write the "ATS Sync" card on the Outreach step — what happens to candidates we approve once an ATS is connected. Whether to push them to the ATS at all, which stage they land in, which existing applicant stages we should ignore (don't message them), and whether we should skip anyone already in the recruiter's pipeline. NOT for: Mapping the hunt to a specific ATS job — that's an inbound-sourcing concern (set_hunt_sourcing(ats_connection_pk, ats_job_id)). Not for outreach messages or automation flags. Returns: { success: true, data: <full config> }. When to use: Only relevant when the org has an active ATS connection AND the hunt is mapped to a job in it (list_ats_connections non-empty, get_hunt_configuration.ats_connection_pk set). Otherwise direct the user to connect/map first.
set_hunt_ats_routing
ChatGPTPurpose: Write the "ATS Sync" card on the Outreach step — what happens to candidates we approve once an ATS is connected. Whether to push them to the ATS at all, which stage they land in, which existing applicant stages we should ignore (don't message them), and whether we should skip anyone already in the recruiter's pipeline. NOT for: Mapping the hunt to a specific ATS job — that's an inbound-sourcing concern (set_hunt_sourcing(ats_connection_pk, ats_job_id)). Not for outreach messages or automation flags. Returns: { success: true, data: <full config> }. When to use: Only relevant when the org has an active ATS connection AND the hunt is mapped to a job in it (list_ats_connections non-empty, get_hunt_configuration.ats_connection_pk set). Otherwise direct the user to connect/map first.
set_hunt_message_automation
ChatGPTPurpose: Write the "Message Automation" card on the Outreach step — how aggressively Umamy sends without a human in the loop: connection-request approval mode, auto-send-on-accept, auto-send-everything, and the score threshold for auto-approval. NOT for: The actual message templates (set_hunt_message_sequence). Not for sender identity (set_hunt_sender_identity). Not for ATS routing (set_hunt_ats_routing). Returns: { success: true, data: <full config> }. Field notes: - automation_type — gates how connection requests get approved: - VALIDATE_ALL_CONNECTIONS — every request needs a human OK. - AUTO_APPROVE_ALL_CONNECTIONS — send all of them automatically. - AUTO_APPROVE_UMAMY_ANALYSIS — Umamy decides per-candidate based on the scorecard. - auto_send_first_message_on_accept — once the connection is accepted, fire the intro automatically. - auto_send_all_messages — full hands-off mode for the whole sequence. - auto_approve_threshold — fit-score cutoff (0–100) above which candidates are auto-approved when automation_type = AUTO_APPROVE_UMAMY_ANALYSIS. Higher = stricter. When to use: "Run this on autopilot", "lower the auto-approve bar to 70", "I want to validate every connection myself".
set_hunt_message_automation
ChatGPTPurpose: Write the "Message Automation" card on the Outreach step — how aggressively Umamy sends without a human in the loop: connection-request approval mode, auto-send-on-accept, auto-send-everything, and the score threshold for auto-approval. NOT for: The actual message templates (set_hunt_message_sequence). Not for sender identity (set_hunt_sender_identity). Not for ATS routing (set_hunt_ats_routing). Returns: { success: true, data: <full config> }. Field notes: - automation_type — gates how connection requests get approved: - VALIDATE_ALL_CONNECTIONS — every request needs a human OK. - AUTO_APPROVE_ALL_CONNECTIONS — send all of them automatically. - AUTO_APPROVE_UMAMY_ANALYSIS — Umamy decides per-candidate based on the scorecard. - auto_send_first_message_on_accept — once the connection is accepted, fire the intro automatically. - auto_send_all_messages — full hands-off mode for the whole sequence. - auto_approve_threshold — fit-score cutoff (0–100) above which candidates are auto-approved when automation_type = AUTO_APPROVE_UMAMY_ANALYSIS. Higher = stricter. When to use: "Run this on autopilot", "lower the auto-approve bar to 70", "I want to validate every connection myself".
set_hunt_message_automation
ChatGPTPurpose: Write the "Message Automation" card on the Outreach step — how aggressively Umamy sends without a human in the loop: connection-request approval mode, auto-send-on-accept, auto-send-everything, and the score threshold for auto-approval. NOT for: The actual message templates (set_hunt_message_sequence). Not for sender identity (set_hunt_sender_identity). Not for ATS routing (set_hunt_ats_routing). Returns: { success: true, data: <full config> }. Field notes: - automation_type — gates how connection requests get approved: - VALIDATE_ALL_CONNECTIONS — every request needs a human OK. - AUTO_APPROVE_ALL_CONNECTIONS — send all of them automatically. - AUTO_APPROVE_UMAMY_ANALYSIS — Umamy decides per-candidate based on the scorecard. - auto_send_first_message_on_accept — once the connection is accepted, fire the intro automatically. - auto_send_all_messages — full hands-off mode for the whole sequence. - auto_approve_threshold — fit-score cutoff (0–100) above which candidates are auto-approved when automation_type = AUTO_APPROVE_UMAMY_ANALYSIS. Higher = stricter. When to use: "Run this on autopilot", "lower the auto-approve bar to 70", "I want to validate every connection myself".
set_hunt_message_sequence
ChatGPTPurpose: Write the actual messages in the outreach flow — connection request note, intro message, follow-ups, and the approve/reject reply templates. Mirrors the "Message Sequence" cards in the Outreach step. NOT for: The automation behaviour around these messages (use set_hunt_message_automation for automation_type / auto-send flags / auto-approve threshold). Not for sender identity (set_hunt_sender_identity). Not for ATS routing (set_hunt_ats_routing). Returns: { success: true, data: <full config> }. Field notes: - initial_message_template — the intro. Putting [ ] placeholders in it opts into LLM personalisation at send time (the backend routes it to *_with_llm automatically). - reminder_outreach_templates_with_llm — array of follow-ups, in order. Replaces the existing list (pass the full set you want, not a delta). - min_days_before_follow_up — cadence between messages in business days. - connection_note_template — short text on the connection request itself (≤ 200 chars on standard accounts, ≤ 300 on premium). - approve_candidate_template_with_llm / reject_candidate_template_with_llm — reply sent when the recruiter approves / rejects a candidate. Validation: Every template field is checked against the canonical placeholder list — any {{ ... }} not in the allowed set rejects the whole write with a hint. Bracket form [ ... ] is unrestricted (those are LLM-personalised at send time). Workflow: Call get_authoring_guide("outreach_message") (and, when writing the connection note, get_authoring_guide("connection_note")) before drafting — it lists the allowed placeholders and tone rules. Then set_hunt_message_sequence(...). When to use: Anything that's "rewrite the intro", "set the follow-ups", "shorten the connection note", "change the reject message".
set_hunt_message_sequence
ChatGPTPurpose: Write the actual messages in the outreach flow — connection request note, intro message, follow-ups, and the approve/reject reply templates. Mirrors the "Message Sequence" cards in the Outreach step. NOT for: The automation behaviour around these messages (use set_hunt_message_automation for automation_type / auto-send flags / auto-approve threshold). Not for sender identity (set_hunt_sender_identity). Not for ATS routing (set_hunt_ats_routing). Returns: { success: true, data: <full config> }. Field notes: - initial_message_template — the intro. Putting [ ] placeholders in it opts into LLM personalisation at send time (the backend routes it to *_with_llm automatically). - reminder_outreach_templates_with_llm — array of follow-ups, in order. Replaces the existing list (pass the full set you want, not a delta). - min_days_before_follow_up — cadence between messages in business days. - connection_note_template — short text on the connection request itself (≤ 200 chars on standard accounts, ≤ 300 on premium). - approve_candidate_template_with_llm / reject_candidate_template_with_llm — reply sent when the recruiter approves / rejects a candidate. Validation: Every template field is checked against the canonical placeholder list — any {{ ... }} not in the allowed set rejects the whole write with a hint. Bracket form [ ... ] is unrestricted (those are LLM-personalised at send time). Workflow: Call get_authoring_guide("outreach_message") (and, when writing the connection note, get_authoring_guide("connection_note")) before drafting — it lists the allowed placeholders and tone rules. Then set_hunt_message_sequence(...). When to use: Anything that's "rewrite the intro", "set the follow-ups", "shorten the connection note", "change the reject message".
set_hunt_message_sequence
ChatGPTPurpose: Write the actual messages in the outreach flow — connection request note, intro message, follow-ups, and the approve/reject reply templates. Mirrors the "Message Sequence" cards in the Outreach step. NOT for: The automation behaviour around these messages (use set_hunt_message_automation for automation_type / auto-send flags / auto-approve threshold). Not for sender identity (set_hunt_sender_identity). Not for ATS routing (set_hunt_ats_routing). Returns: { success: true, data: <full config> }. Field notes: - initial_message_template — the intro. Putting [ ] placeholders in it opts into LLM personalisation at send time (the backend routes it to *_with_llm automatically). - reminder_outreach_templates_with_llm — array of follow-ups, in order. Replaces the existing list (pass the full set you want, not a delta). - min_days_before_follow_up — cadence between messages in business days. - connection_note_template — short text on the connection request itself (≤ 200 chars on standard accounts, ≤ 300 on premium). - approve_candidate_template_with_llm / reject_candidate_template_with_llm — reply sent when the recruiter approves / rejects a candidate. Validation: Every template field is checked against the canonical placeholder list — any {{ ... }} not in the allowed set rejects the whole write with a hint. Bracket form [ ... ] is unrestricted (those are LLM-personalised at send time). Workflow: Call get_authoring_guide("outreach_message") (and, when writing the connection note, get_authoring_guide("connection_note")) before drafting — it lists the allowed placeholders and tone rules. Then set_hunt_message_sequence(...). When to use: Anything that's "rewrite the intro", "set the follow-ups", "shorten the connection note", "change the reject message".
set_hunt_persona
ChatGPTPurpose: Assign (or clear) the outbound LinkedIn persona on a hunt — the LinkedIn account the engine will send connection requests / messages from. Writes hunts.persona_id AND triggers an AWS-side hunt sync so the engine picks up the new sender identity in one call. NOT for: Creating a new persona or connecting a new LinkedIn account — that's a UI-only OAuth flow (surface request_linkedin_connect in the in-app chat to start it). Not for the outreach language / booking_link (use set_hunt_sender_identity). Not for the inbound-only configuration's inbound_persona_id on the configuration object (that's set by set_hunt_sourcing). Returns: { success: true, hunt: { id, persona_id }, sync: { ok, error? } }. sync.ok: false is non-fatal — the supabase write succeeded but the engine doesn't see the change yet (usually because the hunt has no backend_job_id yet, i.e. the user has never synced). Tell the user and retry sync_hunt_draft after the first sync lands. When to use: - "Use [Jean] for this hunt" (after list_personas returned at least one). - "Switch this hunt to send from my hiring manager's account." - "Clear the persona on this hunt — I'm flipping it to inbound-only." (Pass persona_id: null.) Workflow: list_personas (to fetch the org's available personas + their LinkedIn account state) → confirm the user's pick via suggest_actions in the in-app chat → set_hunt_persona → navigate_to_step("outreach") so the user can see the picker reflect the change.
set_hunt_persona
ChatGPTPurpose: Assign (or clear) the outbound LinkedIn persona on a hunt — the LinkedIn account the engine will send connection requests / messages from. Writes hunts.persona_id AND triggers an AWS-side hunt sync so the engine picks up the new sender identity in one call. NOT for: Creating a new persona or connecting a new LinkedIn account — that's a UI-only OAuth flow (surface request_linkedin_connect in the in-app chat to start it). Not for the outreach language / booking_link (use set_hunt_sender_identity). Not for the inbound-only configuration's inbound_persona_id on the configuration object (that's set by set_hunt_sourcing). Returns: { success: true, hunt: { id, persona_id }, sync: { ok, error? } }. sync.ok: false is non-fatal — the supabase write succeeded but the engine doesn't see the change yet (usually because the hunt has no backend_job_id yet, i.e. the user has never synced). Tell the user and retry sync_hunt_draft after the first sync lands. When to use: - "Use [Jean] for this hunt" (after list_personas returned at least one). - "Switch this hunt to send from my hiring manager's account." - "Clear the persona on this hunt — I'm flipping it to inbound-only." (Pass persona_id: null.) Workflow: list_personas (to fetch the org's available personas + their LinkedIn account state) → confirm the user's pick via suggest_actions in the in-app chat → set_hunt_persona → navigate_to_step("outreach") so the user can see the picker reflect the change.
set_hunt_persona
ChatGPTPurpose: Assign (or clear) the outbound LinkedIn persona on a hunt — the LinkedIn account the engine will send connection requests / messages from. Writes hunts.persona_id AND triggers an AWS-side hunt sync so the engine picks up the new sender identity in one call. NOT for: Creating a new persona or connecting a new LinkedIn account — that's a UI-only OAuth flow (surface request_linkedin_connect in the in-app chat to start it). Not for the outreach language / booking_link (use set_hunt_sender_identity). Not for the inbound-only configuration's inbound_persona_id on the configuration object (that's set by set_hunt_sourcing). Returns: { success: true, hunt: { id, persona_id }, sync: { ok, error? } }. sync.ok: false is non-fatal — the supabase write succeeded but the engine doesn't see the change yet (usually because the hunt has no backend_job_id yet, i.e. the user has never synced). Tell the user and retry sync_hunt_draft after the first sync lands. When to use: - "Use [Jean] for this hunt" (after list_personas returned at least one). - "Switch this hunt to send from my hiring manager's account." - "Clear the persona on this hunt — I'm flipping it to inbound-only." (Pass persona_id: null.) Workflow: list_personas (to fetch the org's available personas + their LinkedIn account state) → confirm the user's pick via suggest_actions in the in-app chat → set_hunt_persona → navigate_to_step("outreach") so the user can see the picker reflect the change.
set_hunt_sender_identity
ChatGPTPurpose: Set the "Sender Identity" card values on the Outreach step — the outreach language (en or fr) and the default booking_link (Calendly / Cal.com / etc.) the assistant should weave into messages. NOT for: Assigning the outbound LinkedIn persona / account — use set_hunt_persona for that (it writes hunts.persona_id and re-syncs the engine in one shot). If no persona exists yet for the org, surface request_linkedin_connect first. Also not for the message templates themselves (use set_hunt_message_sequence). Returns: { success: true, data: <full config> }. When to use: - "We're sending in French" → flip language. - "Use this Calendly link for all hunts on this role" → set booking_link.
set_hunt_sender_identity
ChatGPTPurpose: Set the "Sender Identity" card values on the Outreach step — the outreach language (en or fr) and the default booking_link (Calendly / Cal.com / etc.) the assistant should weave into messages. NOT for: Assigning the outbound LinkedIn persona / account — use set_hunt_persona for that (it writes hunts.persona_id and re-syncs the engine in one shot). If no persona exists yet for the org, surface request_linkedin_connect first. Also not for the message templates themselves (use set_hunt_message_sequence). Returns: { success: true, data: <full config> }. When to use: - "We're sending in French" → flip language. - "Use this Calendly link for all hunts on this role" → set booking_link.
set_hunt_sender_identity
ChatGPTPurpose: Set the "Sender Identity" card values on the Outreach step — the outreach language (en or fr) and the default booking_link (Calendly / Cal.com / etc.) the assistant should weave into messages. NOT for: Assigning the outbound LinkedIn persona / account — use set_hunt_persona for that (it writes hunts.persona_id and re-syncs the engine in one shot). If no persona exists yet for the org, surface request_linkedin_connect first. Also not for the message templates themselves (use set_hunt_message_sequence). Returns: { success: true, data: <full config> }. When to use: - "We're sending in French" → flip language. - "Use this Calendly link for all hunts on this role" → set booking_link.
set_hunt_sourcing
ChatGPTPurpose: Flip the hunt's sourcing mode (inbound / outbound / both) and, for inbound, point it at the right source — an ATS connection + job, a LinkedIn job posting, or a LinkedIn Recruiter hiring project. Partial: only the fields you pass are written. NOT for: Outreach content / automation / ATS routing settings (use the set_hunt_message_* / set_hunt_ats_routing tools). Not for connecting a brand-new ATS or LinkedIn account — those are OAuth flows handled in-app; the chat surfaces the connect buttons via the local request_*_connect tools. Returns: { success: true, data: <full config> } — the persisted snapshot after the update. When to use: - "Make this hunt outbound only" / "switch to inbound + outbound". - "Hook the inbound pipeline up to my Greenhouse 'Senior Engineer' job". - "Use my LinkedIn job posting / hiring project for inbound". Workflow: get_authoring_guide("sourcing") (mode-picking + inbound-source rules) → get_hunt_configuration (see current state) → set_hunt_sourcing(...) → navigate_to_step("sourcing") (so the user sees the picker reflect the change) → sync_hunt_draft (so counts/previews pick up the new settings). Pairings to keep in mind: - sourcing_settings.inbound_enabled = true ⇒ also set one of the inbound sources below. - linkedin_job_posting_id and linkedin_hiring_project_id are mutually exclusive — passing one clears the other on the route. - ats_connection_pk + ats_job_id go together; you can list them via list_ats_connections / list_ats_jobs first.
set_hunt_sourcing
ChatGPTPurpose: Flip the hunt's sourcing mode (inbound / outbound / both) and, for inbound, point it at the right source — an ATS connection + job, a LinkedIn job posting, or a LinkedIn Recruiter hiring project. Partial: only the fields you pass are written. NOT for: Outreach content / automation / ATS routing settings (use the set_hunt_message_* / set_hunt_ats_routing tools). Not for connecting a brand-new ATS or LinkedIn account — those are OAuth flows handled in-app; the chat surfaces the connect buttons via the local request_*_connect tools. Returns: { success: true, data: <full config> } — the persisted snapshot after the update. When to use: - "Make this hunt outbound only" / "switch to inbound + outbound". - "Hook the inbound pipeline up to my Greenhouse 'Senior Engineer' job". - "Use my LinkedIn job posting / hiring project for inbound". Workflow: get_authoring_guide("sourcing") (mode-picking + inbound-source rules) → get_hunt_configuration (see current state) → set_hunt_sourcing(...) → navigate_to_step("sourcing") (so the user sees the picker reflect the change) → sync_hunt_draft (so counts/previews pick up the new settings). Pairings to keep in mind: - sourcing_settings.inbound_enabled = true ⇒ also set one of the inbound sources below. - linkedin_job_posting_id and linkedin_hiring_project_id are mutually exclusive — passing one clears the other on the route. - ats_connection_pk + ats_job_id go together; you can list them via list_ats_connections / list_ats_jobs first.
set_hunt_sourcing
ChatGPTPurpose: Flip the hunt's sourcing mode (inbound / outbound / both) and, for inbound, point it at the right source — an ATS connection + job, a LinkedIn job posting, or a LinkedIn Recruiter hiring project. Partial: only the fields you pass are written. NOT for: Outreach content / automation / ATS routing settings (use the set_hunt_message_* / set_hunt_ats_routing tools). Not for connecting a brand-new ATS or LinkedIn account — those are OAuth flows handled in-app; the chat surfaces the connect buttons via the local request_*_connect tools. Returns: { success: true, data: <full config> } — the persisted snapshot after the update. When to use: - "Make this hunt outbound only" / "switch to inbound + outbound". - "Hook the inbound pipeline up to my Greenhouse 'Senior Engineer' job". - "Use my LinkedIn job posting / hiring project for inbound". Workflow: get_authoring_guide("sourcing") (mode-picking + inbound-source rules) → get_hunt_configuration (see current state) → set_hunt_sourcing(...) → navigate_to_step("sourcing") (so the user sees the picker reflect the change) → sync_hunt_draft (so counts/previews pick up the new settings). Pairings to keep in mind: - sourcing_settings.inbound_enabled = true ⇒ also set one of the inbound sources below. - linkedin_job_posting_id and linkedin_hiring_project_id are mutually exclusive — passing one clears the other on the route. - ats_connection_pk + ats_job_id go together; you can list them via list_ats_connections / list_ats_jobs first.
sync_hunt_draft
ChatGPTPurpose: Push the hunt's current criteria + config to the AWS engine so candidate-count / preview tools work, and so the configuration changes take effect — WITHOUT launching the hunt. Always sends status: "draft"; the route refuses any other status from this tool. NOT for: Launching the hunt live — that stays a deliberate human action in-app (POST /hunts/:id/sync with status: "live" is intentionally not exposed). Not for changing criteria values (update_hunt_criteria) — sync ships whatever's already on the row. Returns: The hunt's updated record, including a freshly-populated backend_job_id if this is the first sync. When to use: - First time after the user has provided enough criteria to query — unlocks get_hunt_candidate_count / preview_hunt_candidates. - After non-trivial criteria or config edits, before re-running counts. Side effects: Idempotent; safe to call repeatedly.
sync_hunt_draft
ChatGPTPurpose: Push the hunt's current criteria + config to the AWS engine so candidate-count / preview tools work, and so the configuration changes take effect — WITHOUT launching the hunt. Always sends status: "draft"; the route refuses any other status from this tool. NOT for: Launching the hunt live — that stays a deliberate human action in-app (POST /hunts/:id/sync with status: "live" is intentionally not exposed). Not for changing criteria values (update_hunt_criteria) — sync ships whatever's already on the row. Returns: The hunt's updated record, including a freshly-populated backend_job_id if this is the first sync. When to use: - First time after the user has provided enough criteria to query — unlocks get_hunt_candidate_count / preview_hunt_candidates. - After non-trivial criteria or config edits, before re-running counts. Side effects: Idempotent; safe to call repeatedly.
sync_hunt_draft
ChatGPTPurpose: Push the hunt's current criteria + config to the AWS engine so candidate-count / preview tools work, and so the configuration changes take effect — WITHOUT launching the hunt. Always sends status: "draft"; the route refuses any other status from this tool. NOT for: Launching the hunt live — that stays a deliberate human action in-app (POST /hunts/:id/sync with status: "live" is intentionally not exposed). Not for changing criteria values (update_hunt_criteria) — sync ships whatever's already on the row. Returns: The hunt's updated record, including a freshly-populated backend_job_id if this is the first sync. When to use: - First time after the user has provided enough criteria to query — unlocks get_hunt_candidate_count / preview_hunt_candidates. - After non-trivial criteria or config edits, before re-running counts. Side effects: Idempotent; safe to call repeatedly.
update_hunt_criteria
ChatGPTPurpose: Set values on one or more existing hunt_criteria rows by field_slug. Each update names ONE slug and AT MOST ONE value column appropriate to that field's type. Partial: untouched columns are left alone. NOT for: Adding/removing criterion templates (those are seeded at hunt creation). Not for writing the scorecard (update_hunt_scorecard). Not for the outreach / sourcing config (update_hunt_configuration). Not for entity-search values you haven't resolved — call search_hunt_entities first to get real IDs. Returns: { updated: [field_slug, …], skipped: [{ field_slug, reason }, …], sync: { ok, error? } }. The route auto-syncs to AWS after a successful write, so get_hunt_candidate_count works immediately afterwards — no need to call sync_hunt_draft separately for criteria edits. Validation against criteria_field_templates happens at sync time: a bad value surfaces as sync.ok: false with the engine's error message. Which column to send for which field type (read these off get_hunt_criteria first): - text → field_value (string) - select / multiselect / tags → field_value_string_array (array of option values) - entity-search (companies, schools, …) → field_value_search_criteria_array ([{ id, name, logo? }]) - location → field_value_location ([{ country, region?, city? }]) - structured_object (degree-timing-filter, …) → field_value as a JSON string When to use: Every time the user gives a piece of the hiring brief that maps to a known criterion slug. Workflow: get_authoring_guide("filters") (editorial rules — order, loosen/tighten levers, what not to filter on) → get_hunt_criteria (slugs + types) → search_hunt_entities if needed → update_hunt_criteria (auto-syncs) → get_hunt_candidate_count.
update_hunt_criteria
ChatGPTPurpose: Set values on one or more existing hunt_criteria rows by field_slug. Each update names ONE slug and AT MOST ONE value column appropriate to that field's type. Partial: untouched columns are left alone. NOT for: Adding/removing criterion templates (those are seeded at hunt creation). Not for writing the scorecard (update_hunt_scorecard). Not for the outreach / sourcing config (update_hunt_configuration). Not for entity-search values you haven't resolved — call search_hunt_entities first to get real IDs. Returns: { updated: [field_slug, …], skipped: [{ field_slug, reason }, …], sync: { ok, error? } }. The route auto-syncs to AWS after a successful write, so get_hunt_candidate_count works immediately afterwards — no need to call sync_hunt_draft separately for criteria edits. Validation against criteria_field_templates happens at sync time: a bad value surfaces as sync.ok: false with the engine's error message. Which column to send for which field type (read these off get_hunt_criteria first): - text → field_value (string) - select / multiselect / tags → field_value_string_array (array of option values) - entity-search (companies, schools, …) → field_value_search_criteria_array ([{ id, name, logo? }]) - location → field_value_location ([{ country, region?, city? }]) - structured_object (degree-timing-filter, …) → field_value as a JSON string When to use: Every time the user gives a piece of the hiring brief that maps to a known criterion slug. Workflow: get_authoring_guide("filters") (editorial rules — order, loosen/tighten levers, what not to filter on) → get_hunt_criteria (slugs + types) → search_hunt_entities if needed → update_hunt_criteria (auto-syncs) → get_hunt_candidate_count.
update_hunt_criteria
ChatGPTPurpose: Set values on one or more existing hunt_criteria rows by field_slug. Each update names ONE slug and AT MOST ONE value column appropriate to that field's type. Partial: untouched columns are left alone. NOT for: Adding/removing criterion templates (those are seeded at hunt creation). Not for writing the scorecard (update_hunt_scorecard). Not for the outreach / sourcing config (update_hunt_configuration). Not for entity-search values you haven't resolved — call search_hunt_entities first to get real IDs. Returns: { updated: [field_slug, …], skipped: [{ field_slug, reason }, …], sync: { ok, error? } }. The route auto-syncs to AWS after a successful write, so get_hunt_candidate_count works immediately afterwards — no need to call sync_hunt_draft separately for criteria edits. Validation against criteria_field_templates happens at sync time: a bad value surfaces as sync.ok: false with the engine's error message. Which column to send for which field type (read these off get_hunt_criteria first): - text → field_value (string) - select / multiselect / tags → field_value_string_array (array of option values) - entity-search (companies, schools, …) → field_value_search_criteria_array ([{ id, name, logo? }]) - location → field_value_location ([{ country, region?, city? }]) - structured_object (degree-timing-filter, …) → field_value as a JSON string When to use: Every time the user gives a piece of the hiring brief that maps to a known criterion slug. Workflow: get_authoring_guide("filters") (editorial rules — order, loosen/tighten levers, what not to filter on) → get_hunt_criteria (slugs + types) → search_hunt_entities if needed → update_hunt_criteria (auto-syncs) → get_hunt_candidate_count.
update_hunt_scorecard
ChatGPTPurpose: Replace the hunt's scorecard with a new set of criteria — each { id, text, is_mandatory, rank }. This is a full replace, so include every criterion you want to keep (read first via get_hunt_scorecard). NOT for: Drafting from scratch — use regenerate_hunt_scorecard (whole thing) or generate_scorecard_criterion (one at a time). Not for evaluating candidates against the scorecard. Returns: { data: { criteria: [...] } } — the persisted set. When to use: After the user confirms a draft, or to apply ranking / pinning edits. Workflow: get_authoring_guide("scorecard_criterion") (signal-based phrasing rules, char limits, examples) → get_hunt_scorecard → modify → update_hunt_scorecard. Aim for ≥ 3 criteria grounded in the hiring brief.
update_hunt_scorecard
ChatGPTPurpose: Replace the hunt's scorecard with a new set of criteria — each { id, text, is_mandatory, rank }. This is a full replace, so include every criterion you want to keep (read first via get_hunt_scorecard). NOT for: Drafting from scratch — use regenerate_hunt_scorecard (whole thing) or generate_scorecard_criterion (one at a time). Not for evaluating candidates against the scorecard. Returns: { data: { criteria: [...] } } — the persisted set. When to use: After the user confirms a draft, or to apply ranking / pinning edits. Workflow: get_authoring_guide("scorecard_criterion") (signal-based phrasing rules, char limits, examples) → get_hunt_scorecard → modify → update_hunt_scorecard. Aim for ≥ 3 criteria grounded in the hiring brief.
update_hunt_scorecard
ChatGPTPurpose: Replace the hunt's scorecard with a new set of criteria — each { id, text, is_mandatory, rank }. This is a full replace, so include every criterion you want to keep (read first via get_hunt_scorecard). NOT for: Drafting from scratch — use regenerate_hunt_scorecard (whole thing) or generate_scorecard_criterion (one at a time). Not for evaluating candidates against the scorecard. Returns: { data: { criteria: [...] } } — the persisted set. When to use: After the user confirms a draft, or to apply ranking / pinning edits. Workflow: get_authoring_guide("scorecard_criterion") (signal-based phrasing rules, char limits, examples) → get_hunt_scorecard → modify → update_hunt_scorecard. Aim for ≥ 3 criteria grounded in the hiring brief.