Potato 2.9: Import from brat, doccano, Prodigy, CoNLL and QDA Tools
Potato 2.9 imports projects from brat, doccano, Prodigy, CoNLL and REFI-QDA, transcribes and diarizes audio locally, and records whether an image shape came from a person, a model or an import. Read the upgrade notes first.
Potato 2.9 imports existing projects from brat, doccano, Prodigy, CoNLL-2003, CoNLL-U and REFI-QDA .qdpx, transcribes and diarizes audio on your own machine, and records, for each image shape, whether a person drew it, a model proposed it or it was imported, and which room a vote was cast in. Most of the release is bug fixes, and several of them change what a working 2.8.2 config does, so read the upgrade notes below before you install.
pip install --upgrade potato-annotationBefore you upgrade
Run potato validate --strict on each config first. These are the changes most likely to stop a running study or change its data:
- Duplicate scheme names in one phase are refused, including two different types sharing a name. They used to share a single stored answer. The same name in different phases is still allowed.
min_annotators_per_instanceis now an alias for the per-item cap. Set on its own, items retire at that number. Set alongside a differentnum_annotators_per_itemormax_annotations_per_item, the config is refused.require_fully_annotated: trueis enforced. It was ignored before.- A save the server refuses now returns an HTTP error instead of 200.
/updateinstancereturns 400 when no key in the payload can be read. - A phase that fails to load aborts the boot instead of being dropped.
- CLI defaults no longer overwrite YAML, so
persist_sessions,customjsand the verbosity settings in your config now take effect. - Span offsets are Unicode code points, not UTF-16 units. This matters only for text with emoji or other characters outside the Basic Multilingual Plane.
- Agreement values for set-valued, order-valued, matrix and labelled ordinal schemes change and should be recomputed.
- Registrations are stored, salted and hashed, and sessions expire after 8 idle hours.
The full upgrade list also covers the configs that are now refused, the checks --strict adds, and the defaults that changed.
Bring an existing project in
Potato already read 15 computer-vision formats. 2.9 adds brat, doccano, Prodigy, CoNLL-2003/CoNLL-U and REFI-QDA, which is the interchange format NVivo, ATLAS.ti, MAXQDA, Quirkos and QDA Miner all read and write. One command turns an export into a project with a data file, a config and a README:
potato import -i ./my-brat-corpus/ -o my-projectImported annotations arrive as pre-annotations. Every annotator sees them as a starting point, and they are stored only once someone saves, so an item nobody opens exports as empty rather than as agreement nobody gave.
Some things do not come across yet, and the import says so in its warnings. brat relations and events are reported rather than imported, and a .qdpx brings in its text sources but not its picture, PDF, audio or video sources. Importing a project has the per-tool details.
Potato also writes .qdpx, so a coded project can go back to a QDA tool. REFI-QDA defines a selection's end position as inclusive, which is the opposite of Potato's convention, and the exporter follows the spec. ATLAS.ti keeps only one level of subcode, so exporting with --option flatten_subcodes=true re-parents deeper codes to the top level and names them Parent > Child.
Transcribe and diarize on your own machine
pip install 'potato-annotation[transcribe]'
potato transcripts ./interviews --transcribe --diarize --num-speakers 2 -o data/interviews.jsonTranscription runs faster-whisper and diarization runs sherpa-onnx. Neither needs PyTorch or a Hugging Face token. Voice-activity detection is on by default, and it can drop quiet speech; --asr-no-vad turns it off.
Audio and video items can also carry per-segment questions now. segment_schemes renders any annotation type inside a segment. Before 2.9 it was accepted and ignored.
Where a shape or vote came from
- Image shapes record whether a person drew them or a model proposed them, with
source,ai_model,confidence,edited,carried_overandimport_format. - Votes cast in a multiplayer room carry the room, the voter's role, their initial vote, whether it changed after the reveal, and the voter count.
AI assistance and spend
ai_support now records final_annotation, what the annotator actually saved, and pre_annotation_seeds, what the model answered first, so acceptance rates can be measured from your own data.
ai_budget.cap_usd sets a spend cap that refuses to start a run it cannot afford, instead of stopping halfway through. ai_budget.prices sets per-model rates in the config, so a new model can be priced without waiting for a release.
The built-in price table was checked against vendor pages on 2026-09-05. Opus had been priced three times too high, gpt-4.1-nano at twenty times its rate, and the Anthropic and Gemini default models had no price at all, so cap_usd did not bind them.
Fixes that affect results
The release notes list every fix. These are the ones that could have changed numbers you reported:
/admin/api/agreementnever produced a number, and it compared stored values rather than label names, so every categorical schema showed perfect agreement.- Set- and order-valued types reported agreement of 1.0 whatever was chosen, and ordinal measures ranked word labels alphabetically, so a labelled likert's ordinal alpha was really nominal.
- The second annotator on a two-per-item study was sent to the done page, and every answer they then gave was lost.
- AI suggestions were about the wrong item under every assignment strategy except
fixed_order. - A
selectpreselected its first label, so walking past an item stored an answer. - Uncertainty sampling, BADGE, BALD and hybrid threw on every run and scored everything 0.5.
min_response_timetrusted the time the client reported. It is now measured on the server.
Security fixes include sign-ups that were never saved under the default in-memory config, so after a restart anyone could claim an existing username with any password. document fields ran raw HTML from the corpus, and a room's export revealed other members' votes during the blind phase. All three are fixed.
Also in 2.9
- Reverse-proxy and path-prefix support on every page, including login, admin, dashboards and session review. See Reverse Proxy.
card_sortworks without a mouse, and moves are announced to screen readers.- Agreement over time, joined against codebook revisions, with a re-calibration trigger on
/admin/iaa. - A model-output review mode that includes the empty-prediction slice, so recall can be computed.
- When there is no work to give an annotator, the page they see names the cause and tells them what to report.
potato --versionreports the source and installed versions separately and flags a directory shadowing the package.
Thanks
Aldo Costa (@Eyecatch3r) sent #168, which lets Potato run below a path prefix behind a reverse proxy, and #171, which fixed the dynamic-labels example. @ruthenian8 reported #170, traced it to an item's labels field colliding with Item.labels, and proposed the fix.
Get it
pip install --upgrade potato-annotation
potato validate --strict config.yamlThe release notes list every change. If you set tasks up with a coding agent, potato-skill designs and builds the study for you, and the README now points Claude Code, Codex and Cursor users at it.