candidates_invite
ChatGPTEmail people a link to take a published challenge. Use it only for people the user named, with their addresses exactly as the user gave them. Each gets an email from Hunr now and a reminder after three days if they have not begun. Re-inviting someone works: if their invite to this challenge is still open and not begun, it is sent again with the new days to begin (resent); if it closed (expired, revoked, bounced, handed in, scored or decided) they get a new invite with its own attempt (invited). A bad address, a repeat, or someone taking the challenge right now is skipped and named in the answer. Each candidate who accepts uses one of the organisation's free screens; the answer says how many are left. Refused while the challenge is a draft. In Hunr's demo organisation the invites are made and listed but nobody is emailed, and the answer's note says so.
candidates_list
ChatGPTWhere each invited candidate is: invited, accepted (begun), submitted, scored, decided, expired, revoked (withdrawn) or bounced, with a count per status. Pass a challenge id for one challenge's candidates, or leave it out for the organisation's. It says where each candidate is, not their score.
challenge_get
ChatGPTThe current version of every part of a challenge and what is still missing. Use it to resume work on a challenge started in an earlier conversation. A challenge Hunr seeded (the demo's) also carries the chat that drafted it.
challenge_progress
ChatGPTThe challenge and the agent's latest steps on it, for Hunr's card to show while the agent works. Only the card calls it.
challenge_publish
ChatGPTPublish a finished challenge so candidates can be invited to it. Use it only when the user asks to publish this challenge. Publishing freezes it: every part is fixed at its current version and none can be changed afterwards, but the time box (challenge_update). Refused, with the parts named, while any required part is missing; refused as well if it is already published.
challenge_start
ChatGPTCall this first, the moment the user asks for a hiring or hackathon challenge, before asking anything or searching: a working title is enough, and the org is optional when the user has one. Everything after it (the research, the parts) is then the challenge's own, and Hunr's card shows the user your progress as you work. Answers with the challenge, its id, and missing: frame, sources, brief, rationale and judge, each with its shape. Take the role, level, stack and product from the request. Then always ask the user one thing, with your own question UI: the time box, how long candidates get, offering three or four lengths that fit the role, your pick first. Hunr has no default, never assume four hours, and a frame whose time box the user did not choose is refused. Ask nothing else. There is no starter and no candidate-facing data: the candidate reads the brief alone. Then research before writing: search finds the problem, the numbers and where held-back cases can come from in Hunr's corpus, whose sections can be quoted and checked; a page from outside the corpus can be cited once source_propose has added it. Then write each part with challenge_update, in the missing order.
challenge_update
ChatGPTStore one part of a challenge (frame, sources, brief, rationale, judge) in the shape its missing entry describes. Each write is a new version; an unknown field, a missing field or a value outside a closed vocabulary is refused with the field named, and nothing is stored. Parts decided together are written together: also takes the parts that follow this one, in order, in the same call (the judge after the brief, when the brief's numbers and the cases were settled together); the call stops at the first refused and says which were stored. Answers with the last part as stored, the version of every other part, and what is still missing; challenge_get reads the others. Once the challenge is published it takes one change: the frame with only time_box_minutes changed (or {time_box_minutes} alone), when the user asks for a different time box. Candidates who begin after it get the new time box, those already working keep theirs, and the brief's time line follows; any other change is refused.
challenges_list
ChatGPTThe organisation's challenges, most recently worked on first: each one's id, title, format, whether it is a draft, published, closed or archived, and which parts a draft still lacks. Archived challenges are left out unless include_archived is true. Use it to find a challenge the user names by title, before reading, publishing or inviting to it.
data_generate
ChatGPTGenerate the judge's held-back cases: describe each dataset and Hunr writes the rows, the same rows for the same spec and seed. Generated data serves the judge only: the records our side holds and serves through the fitted declaration, and the inputs we send the submission, when the judge's source is generated. It is never a candidate-facing kit: nothing generated ships to the candidate, and the brief describes none of it. Plan the data first from the judge's schema, then generate it in one call: every dataset the cases need (the entities before what refers to them), each with its fields and counts, in datasets, generated in order so a later one refs and looks up an earlier one. The records are clean, realistic and consistent, with nothing planted in them: each case category's inputs are clean records changed by that category's one operator. Use it for every piece of structured data the judge needs (records, traffic, events, logs as rows) instead of typing rows yourself; write only prose by hand. Each field sets one generator (seq, id, ref, int, float, enum, bool, time, fake, template, calc, text, after, lookup). An amount a reader can work out from a rate and a quantity on the record is calc over them, never drawn on its own, and numbers are numbers (10, never "10"): both are refused. Status words are shared across categories: no value of a served column found only on one category's rows. A ref draws from a dataset generated before, so generate the entities (players, accounts, builds) first, then what refers to them. Rows hang together by construction, never by generating again: what is fixed per entity (a build's branch, commit and start) goes on the entity's dataset and comes over with lookup; a time that follows another, in the row or in another dataset through a lookup (finished, received, completed after the scheduled pickup), is after it; a count within an entity (attempt, line number) is seq with per; a key that belongs to a parent is looked up, never drawn beside it (draw the user, look up its org; with no users dataset, the org is fixed_by the user); values that go together are enum by with choices (a status and its codes, a carrier and its services); a self-reference differs_from its pair (from and to accounts, a supplier and its customer); a status with a lifecycle is enum progress by its entity in time, a counter that only grows is int or float cumulative by its entity, and an entity's events follow its start with after over the looked-up start. Prose is yours to write, never faked: a text bank of eight or more templates in this system's words, with slots you write and the row's {fields}, never an enum of a few phrases the file repeats; the summary warns on prose that repeats or names a real firm. A digest is fake sha256. Firms' names are made up (fake company, carrier, law_firm…), never real firms. Real data recurs: users act many times, accounts pay many invoices, so an id that names such a thing takes a pool (or a ref to a dataset of them), and only the row's own key is new on every row. The answer has a summary of each column (check the skew is what you meant, and fix any column with a warning, a column that states a case's answer among them) and sample rows. No served field states the answer: no is_duplicate, prior_write or should_refuse, no true-or-false field true exactly on one category's rows, and nothing served that holds a value only on one category's rows; a case is found by reading the values a real record holds. Helper columns (an operator's part a template joins, a pick, a lookup of the category) take hidden: true: kept for gold and checks, never served through any capability or request; category, gold and gold_ fields are always hidden. A field only some rows hold (a completed_at when the status is complete, a refund_id when refunded) takes only_when, so it is null on the rest. With a generated source, the held-back cases are the last dataset, named cases, one jsonl row per case, 24 to 30 rows and at least 2 per category: id; category (enum by a seq n, its choices giving each row number its c…
data_query
ChatGPTCount what is in the challenge's datasets with read-only SQL (SQLite) instead of working it out yourself: each dataset is a table of its name with _row, its row number from 1. Use it for the judge's numbers: how many cases fall in each category, what a correct outcome comes to, how many calls a minimal handling of a case takes. Ask everything you need at once: up to ten named queries a call, each answered or refused on its own, at most 200 rows each.
doc_grep
ChatGPTUse this to find where a page states a number or a rule before fetching that section: lines of a document's live page matching a pattern (a case-insensitive regular expression, or the literal text), each with its section id and the lines around it.
doc_quote
ChatGPTChecks one citation against the live page: verified when the words are in the section, moved when they are elsewhere on the page, drifted when the page is readable but no longer says it, gone when the page cannot be read. Writing the sources part runs the same check on every quote and names any that is off, so use this only to test a passage before you rely on it.
fetch
ChatGPTUse this after search, before citing anything: reads a corpus section live from its page (id {document}#s{n} from search) as markdown with content_hash and fetched_at, which a citation carries. With a document id alone, the stored summary and outline: every section's id, heading and lead, no fetch. Cite only text this returned, and only from quotable sections; a quote is at most 300 characters.
me
ChatGPTThe signed-in Hunr user: their name, email, organisations and the permissions this connection holds. Use it when the user asks which account they are connected with.
orgs_list
ChatGPTThe Hunr organisations the signed-in user belongs to, each with its slug and the user's role. A challenge belongs to one organisation, named by its slug.
search
ChatGPTUse this when a challenge, a rubric or an answer key needs engineering evidence: search Hunr's curated corpus of engineering blogs and postmortems (operations), standards and reference docs (normative, reference), vendor changelogs (frontier). Its sections can be read live and quoted, and the challenge's sources part checks every quote against its page. Results are sections of pages, ranked; each has an id to fetch live. Ask for one thing per query in the words an engineer would use: a failure mode ("double spend under concurrent balance updates postgres"), a checkable fact ("postgres serializable isolation retry"), or a practice ("how payment teams reconcile ledger with processor"). quotable sections may be cited as fact; others are context. Pass format for a hiring or hackathon challenge and stack when the role names one.
source_propose
ChatGPTUse this when the challenge needs a page the corpus lacks, so it can be cited: an engineering blog post, a postmortem, a standard or a vendor's docs page you know or found that answers what search could not. Name the page's url and say in why what it holds, in the words search would use. Hunr reads it now (up to 25 seconds): passed means it is searchable for this organisation as of this call and the answer lists its sections to fetch; held means a person at Hunr decides; refused says why; pending means it is still being read. A host without a url only joins the review queue.
sources_list
ChatGPTUse this when a search finds nothing, to tell a gap in the corpus from a bad query: the hosts the corpus reads, with what each is evidence for (role, publication, formats, industries, stacks) and whether it may be cited as fact.