Drafting from pull requests
npx @shipdot/cli draft # writes draft entriesnpx @shipdot/cli draft --dry-run # prints them insteadshipdot draft reads pull requests merged into the base branch and writes one entry per user-facing change. It never publishes anything: drafts are files you review, edit and commit (or that the GitHub Action puts in a pull request for review).
Which pull requests
Section titled “Which pull requests”- Base branch:
--base, elsedraft.baseBranchin the config, else the repository default branch. - Since:
--since <date>, else the date of the most recent tag, else the date of your newest entry. - Skipped, with the reason printed for each:
- PRs labeled
skip-shipdot(configurable withdraft.ignoreLabels); - bot authors (any
[bot]account, plusdraft.excludeAuthors); - non-user Conventional Commit types:
chore,ci,test,docs,refactor,build,style,revert(configurable withdraft.excludeTypes); - PRs that already have an entry (entries written by
draftrecord the PR number inpr:); - shipdot’s own draft PRs;
- PRs whose
### shipdotsection saysskip.
- PRs labeled
Authentication: GITHUB_TOKEN or GH_TOKEN, falling back to gh auth token if the GitHub CLI is installed. The repository comes from --repo, GITHUB_REPOSITORY, or the origin remote.
Template mode (default)
Section titled “Template mode (default)”Offline and deterministic. For each PR:
- If the description has a
### shipdotsection, its content is the note. The first lines can settitle:,type:,target:andlink:. - Otherwise the title comes from the PR title without its conventional prefix (
feat(export): add excel export (#12)→ “Add excel export”), and the type from the prefix (feat→ new,fix→ fixed, anything else → improved).
## What changedRefactors the exporter and adds an XLSX writer.
### shipdottitle: Export to Exceltype: newtarget: "#btn-export"
You can now export any report to Excel with one click.The note ends at the next heading of the same or a higher level (like ## Checklist) or at a horizontal rule (---). Keep the section above anything appended to the end of the description, such as the footer some tools sign pull requests with, or it becomes part of the note.
Writing skip as the only content of the section opts the PR out. shipdot’s own pull request template includes this section; copy it into yours.
LLM mode (bring your own key)
Section titled “LLM mode (bring your own key)”Set these environment variables to let a model rewrite drafts in user language and translate them into every configured locale:
| Variable | Description |
|---|---|
SHIPDOT_LLM_PROVIDER |
anthropic or openai-compatible (also settable as llm.provider in the config) |
SHIPDOT_LLM_API_KEY |
Your API key. Only ever read from the environment. |
SHIPDOT_LLM_MODEL |
Model name. Defaults to claude-opus-5-5 for anthropic; required for openai-compatible. |
SHIPDOT_LLM_BASE_URL |
Base URL for openai-compatible providers (default https://api.openai.com/v1), for example a local Ollama or vLLM server. |
Requests use plain fetch, no SDKs. A PR with a ### shipdot section keeps its human-written note and is not sent to the model. Use --no-llm to force template mode.
What is sent, exactly
Section titled “What is sent, exactly”For each pull request without a ### shipdot section, one request containing:
- the PR title (up to 300 characters) and body (up to 6,000 characters);
- the instructions, the default locale, and the list of locales to translate into.
Nothing else: no diffs, code, file names, commits, comments, labels, author names or repository details.
Prompt-injection safeguards
Section titled “Prompt-injection safeguards”PR text is written by contributors and is treated as untrusted:
- It is wrapped in
<pull_request>tags, with<,>and&escaped so it can’t close them. - The system prompt says the content is data, not instructions, and must not change the output format.
- The reply must be a JSON object that passes validation: a known
type, a single-line plain-text title of at most 100 characters, a body of at most 1,500 characters, and translations only for configured locales. - Anything else (invalid JSON, schema violations, a refusal, an HTTP error) falls back to template mode for that PR, with a warning.
- Drafts are always reviewed by a human in a pull request, and the body is sanitized again by
shipdot build.
The API key is never logged, and in the Action it is masked with core.setSecret.