Potato 2.9: Import from brat, doccano, Prodigy, CoNLL and QDA Tools
Potato 2.9 imports brat, doccano, Prodigy, CoNLL, and REFI-QDA projects, transcribes and diarizes audio locally, and records where each image shape came from.
Potato 2.9 imports existing projects from brat, doccano, Prodigy, CoNLL-2003, CoNLL-U, and REFI-QDA .qdpx, and it transcribes and diarizes audio on your own machine. It also records whether a person drew each image shape, a model proposed it, or it was imported, and which room each 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-annotationUpgrade notes
Run potato validate --strict on each config first. The following changes are the most likely to stop a running study or change its data:
- Duplicate scheme names in one phase are refused, even when the two schemes have different types. 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, it retires items at that number. Setting it alongside a differentnum_annotators_per_itemormax_annotations_per_itemmakes Potato refuse the config.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,customjs, and the verbosity settings in your config now take effect. - Span offsets are Unicode code points rather than UTF-16 units. The change matters only for text with emoji or other characters outside the Basic Multilingual Plane.
- Agreement values for set-valued, order-valued, matrix, and labeled 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.
Project import from annotation and QDA tools
Potato already read 15 computer-vision formats. Version 2.9 adds brat, doccano, Prodigy, CoNLL-2003/CoNLL-U, and REFI-QDA, the interchange format that 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 lists them 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.
Local transcription and diarization
Install the transcribe extra, then point potato transcripts at a folder of recordings:
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, and neither needs PyTorch or a Hugging Face token. Voice-activity detection is on by default and can drop quiet speech, so --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.
Provenance for image shapes and room votes
Version 2.9 records where two kinds of annotation came from:
- Image shapes record whether a person drew them or a model proposed them, with
source,ai_model,confidence,edited,carried_over, andimport_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 acceptance records and spend caps
ai_support now records final_annotation, what the annotator actually saved, and pre_annotation_seeds, what the model answered first, so you can measure acceptance rates 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 you can price a new model without waiting for a release.
We checked the built-in price table against vendor pages on 2026-09-05. Opus had been priced three times too high and gpt-4.1-nano at twenty times its rate. 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. The fixes below 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 labeled Likert scale'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.
The security fixes include the following three. Under the default in-memory config, sign-ups were never saved, 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.
Other changes in 2.9
The release also includes these changes:
- Reverse-proxy and path-prefix support covers every page, including login, admin, dashboards, and session review. See Reverse Proxy.
card_sortworks without a mouse, and moves are announced to screen readers./admin/iaashows agreement over time, joined against codebook revisions, with a re-calibration trigger.- A model-output review mode 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 to contributors
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.
Installing 2.9
Upgrade, then validate each config:
pip install --upgrade potato-annotation
potato validate --strict config.yamlIf 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. The release notes list every change.