Vahtian

Qualitative analysis

Using GenAI in qualitative analysis without breaking your method

The model is a reading partner. You stay the analyst.

You paste your interviews into a chatbot, ask for a thematic analysis, and six tidy themes come back, each with participant quotes underneath. It looks like a week of work done in a minute. Then you open a transcript to find one of the quotes. Nobody said it.

The problemYou did not code badly. You asked for the wrong thing.

Many qualitative researchers have had this moment in the last two years, and it is part of why more than 400 of them, across more than thirty countries, signed an open letter rejecting generative AI in reflexive qualitative research. The themes came back as topic buckets. The quotes came back invented.

The chatbot was never built to do what you asked. Thematic analysis is roughly twenty small tasks in sequence: read everything, code a segment, hold that code in mind, meet a new idea in interview ten, go back and recode interview three. A chatbot has no memory of your dataset between prompts and no stable place to keep a code. Ask it to run the whole thing in one go and it does the only thing it can, which is to recognise the shape of a thematic-analysis report and write something with that shape. The fabricated quotes follow directly: a text predictor was asked to retrieve evidence it never stored.

That makes the failure structural. It also means the useful response is neither to swear off the tool nor to hand it the whole job.

The shiftInterlocutor, not coder

Coding was always a workaround for a human limit. You cannot hold twenty hours of interviews in your head at once, so you break the data into labelled pieces you can retrieve. A language model does not share that limit. It can hold the whole set in view and surface passages that speak to each other. Forcing it to imitate line-by-line human coding wastes the one thing it does well.

So the model works as a reading partner rather than a decider. It suggests candidate codes, groupings that might belong together, a contrasting reading you had not considered. You interrogate each suggestion against the transcript, keep what holds, drop what does not. The interpretation stays yours, because meaning in non-positivist work is made by a situated human.

Three moves make this work, whatever tool you use:

  • Divide the work. One small task per prompt, reviewed before the next. Never one prompt for the whole study.
  • Review every suggestion against the data. A code counts only after you have accepted or edited it. The model's confidence is a self-report, not evidence.
  • Keep themes as questions until you can sign them. "Could these codes describe how waiting reshapes daily life?" is a grouping. A theme exists when you can state it in one sentence, show what supports it, show what complicates it, and put your name on it.

Do this and you are still doing qualitative research. Be honest about which kind: this structured, reviewed approach fits framework, matrix, template and codebook thematic analysis best. It supports reflexive work through your own reading and memos, and it does not turn reflexive analysis into a button.

The toolWhat QualiVahti Local does for you

QualiVahti Local is an Obsidian vault plus open Python and R scripts that run this method on your own computer. The pipeline is one reviewable step at a time, and every step names its tool, so you can see exactly what the model touched.

  • Transcription. faster-whisper runs locally, large-v3 by default, so audio never leaves the machine. Drop a recording into 01_Audio/ and a watcher script transcribes it. Finnish, Swedish and around a hundred other languages are auto-detected, or forced with --language fi.
  • Code suggestions. A local model served by Ollama (qwen3:14b by default, qwen3:4b on an 8 GB laptop) suggests one to three first-cycle codes per excerpt, each with a rationale and its own marked uncertainty. Suggestions land in suggested_<id>.csv; your decisions live in a separate reviewed_<id>.csv, one review_status per row: accepted, edited, rejected or unclear. A code counts once you have marked it, and the model name and version id are written into every row.
  • A second opinion. build_vault_index.py vectorises your notes with a local embedding model (nomic-embed-text); chat_with_vault.py then answers questions over the whole vault with cited, clickable sources, using a different model (hermes3:8b) from the one that suggested your codes. It reports contradictions first and never decides meaning. Every chat session is logged under 11_Audit_Trail/chat_sessions/.
  • The reviewer paragraph, written from your records. Rscript _scripts/r/draft_ai_disclosure.R reads your reviewed coding and drafts the AI-use disclosure into 09_Methods_Draft/: your real accept, edit and reject counts, the coding model and version, the boundary sentence, and [MISSING:] tags for the facts only you can supply.
  • A pre-flight check. Rscript _scripts/r/preflight_check.R reports, before you export, whether the analysis loop hangs together: every row reviewed, every theme signed and grounded in a real quote with what complicates it, a saturation verdict logged as a three-way call (saturated, not saturated, or not resolvable at this n).

Everything is plain files you keep: Markdown notes, CSV coding, a .canvas evidence map where every node is a live note, and R tables and co-occurrence networks in 12_Exports/. Each run appends one line to 11_Audit_Trail/audit_log.md with the date, script, inputs, model and version, and outputs, so your AI use stays legible to a supervisor or journal. The only network address anywhere in the scripts is localhost, so the whole workflow runs with the internet switched off.

The scripts are open source under Apache-2.0 with a Zenodo DOI, which lets a reviewer inspect exactly what the model was allowed to do. The R side installs straight from an R session:

install.packages("qualivahti", repos = "https://heidihelena.r-universe.dev")

The criteriaHow this maps to a congruence framework

Nguyen-Trung and colleagues (2026) set out what methodologically congruent GenAI use looks like. QualiVahti is built to make each of their tenets the easy path.

  • A relational epistemology. The model offers candidate codes, groupings and a contrasting reading. It never names a theme or makes a decision. The second-opinion chat is an explicit dialogue partner, deliberately a different model from your coder, and the reflexivity memo has a section to declare that stance in your own words.
  • Ethical, responsible and rigorous use. Everything runs on your machine, since the only network address in the scripts is localhost, so no research data leaves it. Pseudonymisation happens in the cleaning step and the key stays outside the vault. Every run is logged with its model and version, and one command drafts the AI-use disclosure reviewers ask for.
  • The researcher leads, GenAI assists. The split is enforced in the files rather than the guidance: the model writes suggested_*.csv, you write reviewed_*.csv, and only rows you marked accepted or edited reach any table or figure. Scripts never overwrite a human-reviewed file.
  • From mechanical extraction to abductive discovery. Theme suggestions arrive as questions. A theme exists only when you can state it, show what supports it, show what complicates it, and sign it. The chat lets you interrogate a pattern and check a quote against the source, and the negative-case and saturation templates keep the back-and-forth honest.

Underneath all four sits the technical point: a chatbot has no memory of your dataset and cannot run twenty analytic steps in sequence. The vault sidesteps that by dividing the work into small, reviewed tasks with persistent files, so the model is only ever asked to do what it can do.

None of this makes a study congruent on its own. Congruence is the researcher's achievement, and no tool confers it. What the vault removes is the technical excuse: the reflexive memos, the audit trail, the human-first data contract and the disclosure paragraph are already in place, so what is left to supply is the interpretive work that was always yours.

Try it todayA prompt that keeps the model in its place

If you already work with a local model, this starting instruction keeps it in the interlocutor role. It mirrors the rules built into QualiVahti's own prompts.

System prompt · first-cycle coding

You are helping me with first-cycle qualitative coding.
You suggest; I decide.

Work only from the excerpt and codebook I give you, nothing else.
For each excerpt, offer one to three short candidate codes
(1 to 4 words, close to the participant's own words).
For each, quote the words that triggered it, and say plainly
what makes you unsure or what I need to judge.

Do not invent participant details or guess demographics.
Do not name themes; a theme is a claim only I can make.
If an excerpt contradicts an obvious pattern, say so.
End by stating what needs my judgement.

Give it one excerpt at a time, and review every suggestion against the transcript before you keep it.

Related guidesRead next

Further readingSources worth your time