## Why It Matters

Describing a role out loud takes a minute. Writing the posting takes an hour. An AI assistant can do the writing: title, body, salary band, stages, credentials — created in your account as a **draft**, with an edit URL handed back. Nothing reaches your career page until a human presses Publish.

## Two Surfaces

| | In-app assistant | External MCP client |
|---|---|---|
| Setup | None — the chat is on every [Hiring](/hiring/job_postings) page | One-time connect: [Connecting AI Assistants](/docs/connecting-ai-assistants) |
| Clients | Kit's own agent | Claude Code, Claude Desktop, Codex CLI, OpenCode, your own |
| Permission | Hiring admin, active subscription | Same, plus `hiring_write` on the connection |
| Stages | Template only | Template **or** stages written for this one job |
| Editing a draft | Yes | Yes |

Both act **as you**. Neither can reach a posting you can't open, or do something the web form would refuse you.

## One Prompt, One Draft

```
Create a draft job posting: Senior Rails Engineer, remote in Poland, full-time.
Use our Software Engineer template for the stages. Pull a market salary band
before you write numbers. Context: Rails 8, Hotwire, Postgres; team of six;
this hire owns the billing domain and the Stripe migration.
```

What the assistant does with it:

| Step | Tool | Result |
|------|------|--------|
| 1 | `hiring_get_setup_guide` | Account state and what your role allows. On an account with no postings it also returns the stage-type schema |
| 2 | `hiring_list_templates` | Your account templates plus Kit's system ones, with stage counts |
| 3 | `compensation_get_salary_benchmark` | A band from real market listings Kit indexes — needs the Compensation Research module |
| 4 | `hiring_list_credentials` | The credential keys a posting may recommend |
| 5 | `hiring_create_job_posting` | Draft created. Returns the posting ID and its edit URL |

Skip step 3 and the model invents a salary from memory. Ask for the benchmark by name.

## Feed It Source Material

The assistant knows your stack and your team only if you tell it. What lifts a draft from generic to hireable:

- The last posting you were happy with — paste it, say "same voice, new role"
- Your notes from the kickoff call, unedited
- The team's actual constraints: time zone, on-call, salary ceiling, the thing the hire will own in month one

Two rules the body must follow, and the tools tell the model both:

- **Markdown**, not HTML.
- **No job title in the body.** Kit renders the title itself; start at "About the Role" or your first real section, or candidates read the title twice.

## Stages: Template or Inline

`process_template_id` and `stages` are mutually exclusive — passing both is an error.

**Template.** IDs come from `hiring_list_templates`. An assistant with no Kit account can browse Kit's public catalog first at `https://startupkit.app/mcp` (no auth, `list_catalog_templates`).

**Inline stages** — MCP clients only, for a process this one job needs:

```json
"stages": [
  {"name": "Application", "type": "application_form"},
  {"name": "Take-home", "type": "portfolio_upload",
   "config": {"payout": {"enabled": true, "amount": 500, "currency": "USD"}}},
  {"name": "Team review", "type": "team_review",
   "reviewers": [{"email": "ana@example.com", "role": "lead"}]},
  {"name": "Offer", "type": "offer"}
]
```

Ten types: `application_form`, `code_assignment`, `portfolio_upload`, `questionnaire`, `video`, `video_recording`, `team_review`, `live_interview`, `reference_check`, `offer`. Any of them takes a `payout` block. Reviewer emails must already be team members.

> [!NOTE]
> A template builds stages **at creation time only**. Changing the template later never reaches a posting already created — edit the stages instead.

## What AI Cannot Do

- **Publish.** No tool in Kit moves a posting out of draft. That is deliberate, not a gap.
- Assign the hiring team, or reviewers on an existing stage — web UI.
- Upload the social share image (`og_image`) — web UI.
- Re-apply a process template after creation.
- Clear a salary figure or a boolean. On the update tools `null` means "leave alone", so emptying a field is a web-UI job. (`recommended_credential_keys` is the exception: `[]` clears it.)

## Fixing the Draft

Both surfaces can edit what was created: `hiring_update_job_posting` for the posting, `hiring_update_stage` for one stage.

Creating a posting needs **Hiring admin** — the in-app chat doesn't even offer the tool to anyone else. Editing needs Hiring admin **or** hiring manager on that posting, so the manager who owns a role can iterate on it without holding admin.

Both tools are partial: keys you omit stay as they are, keys you pass overwrite. Two traps worth knowing before you let an agent loop on a draft:

- **`description` replaces the whole body.** There is no append. Have the assistant read the posting, rewrite it in full, then write it back.
- **Stage config sections replace wholesale, not deep-merge.** Passing `config.code_assignment` overwrites every key in that section, so send the keys you want to keep. (`reference_check` is the one section that merges.)

The update response truncates the description to 500 characters. To verify the full body, read it back with `hiring_get_job_posting`.

## Details That Bite

**Remote roles need a country.** With `remote: true`, Kit marks the listing as `TELECOMMUTE` in its structured data only if it can resolve a country — from `applicant_location_country` ("Poland", "United States"), or failing that from the location string. Resolve neither and Google Jobs never learns the role is remote.

**Recommended credentials are an invitation, nothing more.** Keys come from `hiring_list_credentials`. Every candidate who applies *after* you set them gets one email inviting them to share proof; earlier applicants are never emailed. Kit does not verify, score, rank, or filter anyone by what comes back.

**Salary period and currency default to year and USD.** Say the currency out loud in your prompt if the role is not US-based.

## Before You Publish

Read the draft. An assistant writing about your company is writing from what you gave it plus what it assumed.

> [!WARNING]
> The **stage description** is public — it renders on your career page for anyone browsing. The **brief** is private, readable only by a candidate who reached that stage. If an assistant wrote a take-home with a dataset link, confirm the link sits in the brief. See [Stage Description vs Brief](/docs/creating-a-job-posting#stage-description-vs-brief).

## Quick Checklist

- [ ] Hiring admin, active subscription — and `hiring_write` if you're using an external client
- [ ] Paste real source material: old posting, kickoff notes, constraints
- [ ] Ask for a salary benchmark explicitly, before the numbers are written
- [ ] Pick a template, or hand over inline stages with reviewers by email
- [ ] Check the body has no duplicated title and reads like your team
- [ ] Confirm task links live in the **brief**, not the stage description
- [ ] Set the hiring team in the web UI if the role is restricted
- [ ] Publish it yourself

## Next Steps

- [Creating a Job Posting](/docs/creating-a-job-posting) — every field, status, and stage setting in the web UI
- [AI Agent and MCP Tools](/docs/hiring-ai-agent-mcp) — the rest of the hiring toolset: triage, reviews, candidate replies
- [Connecting AI Assistants](/docs/connecting-ai-assistants) — MCP setup, OAuth, scopes
- [MCP Tools Reference](/docs/mcp-tools-reference) — parameters for every tool