Expected Parrot · An evidence-first tutorial

Auditable qualitative coding

Move from raw interview transcripts to a traceable codebook, exact excerpts, analytic memos, and theory exports—without losing the path from a claim back to its source.

Tool: BewleyMethod: thematic and grounded-theory analysisLicense: MIT

Explore a finished example. Search and filter coded excerpts from twenty public-domain letters exchanged by John and Abigail Adams in the interactive HTML explorer generated by Bewley.

01 Orientation

Bewley is a local-first command-line workspace for coding interviews, field notes, open-ended responses, and other UTF-8 text. It is designed for analyses where interpretation matters, but so do provenance and recovery.

Evidence stays exact

Annotations point to a whole document, an inclusive line range, or an exact byte span.

History is append-only

Edits and undo operations become events. Earlier analytic decisions remain inspectable.

Codes can evolve

Rename, merge, split, nest, and link codes as distinctions sharpen.

Outputs stay portable

Export quotes, snippets, theory structures, narratives, or standalone HTML.

Import documents
Create codes
Annotate spans
Compare + memo
Export evidence
The workflow is iterative: findings from comparison often send you back to revise codes and recode evidence.

02 The local data model

ObjectRoleWhy it matters
DocumentA versioned UTF-8 sourcePreserves the material being interpreted.
CodeA named analytic categoryMakes the codebook explicit and revisable.
AnnotationA code attached to evidenceConnects an interpretation to an exact passage.
MemoAn analytic noteRecords comparisons, hypotheses, and exceptions.
EventAn append-only state changeProvides history, audit, and non-destructive undo.
Source of truth. Events and immutable objects live under .bewley/. The SQLite index is derived state and can be rebuilt.

03 Installation

pip install "git+https://github.com/expectedparrot/bewley.git"
bewley --help
bewley docs list

For local development, clone the repository and install it in editable mode:

git clone https://github.com/expectedparrot/bewley.git
cd bewley
pip install -e .
pytest -q
Working-directory rule. Bewley has no --cwd option. Run every project command from the directory containing .bewley/.

04 Start a project

Keep a small pilot corpus inside the project so paths remain stable and the first codebook can be reviewed before scaling.

mkdir customer-interviews
cd customer-interviews
mkdir corpus
cp /path/to/interviews/*.txt corpus/

bewley init
bewley add corpus/interview-01.txt
bewley add corpus/interview-02.txt
bewley list documents
bewley status

Read the pilot set before formal coding. Note recurring language, surprising cases, the unit of analysis, and the research question the codes must help answer.

Optional agent-run open coding

Bewley packages current document revisions as EDSL Jobs; the ep CLI executes them, and Bewley audits the Results before producing candidates for review.

Configure EDSL once per workspace

Use the EDSL CLI to authenticate and check connectivity. Login stores the Expected Parrot key for the working directory; keep the resulting .env private and out of version control.

ep auth login
ep auth status
ep check

# Optional: inspect or manage named environments
ep profiles list
ep profiles current
ep profiles --help

See EDSL’s Managing Keys guide for Expected Parrot and model-provider keys.

bewley open-coding jobs --output jobs.ep --pilot 5
ep run jobs.ep --model <model-name> --output results.ep
bewley open-coding ingest results.ep --jobs jobs.ep
Review remains explicit. Ingestion writes qualitative-analysis/candidate_codes.csv; it does not create codes or annotations.

05 Code exact evidence

Create a compact starter codebook, with descriptions that distinguish neighboring concepts. Then attach each code at the narrowest useful scope.

bewley code create onboarding_friction \
  --description "Difficulty reaching an initial successful outcome"

# Lines are 1-based and inclusive.
bewley annotate apply onboarding_friction corpus/interview-01.txt \
  --lines 18:24

# Bytes are 0-based with an exclusive end.
bewley annotate apply onboarding_friction corpus/interview-02.txt \
  --bytes 412:603

bewley show snippets --code onboarding_friction
Annotation scope is mandatory. Every annotation needs exactly one of --document, --lines S:E, or --bytes S:E. Prefer spans for claims that will later need direct quotations.

06 Refine the codebook

Qualitative coding is not a one-pass labeling exercise. Review excerpts together and revise categories when a distinction repeatedly matters.

bewley code rename setup_problems onboarding_friction \
  --description "Difficulty reaching an initial successful outcome"

bewley code create unclear_guidance
bewley code set-parent unclear_guidance onboarding_friction

bewley code link onboarding_friction early_churn causes \
  --memo "Repeated in four interviews"

bewley code list --tree
bewley code links onboarding_friction

Use merge for synonyms, split for a code that hides meaningful variation, hierarchy for “is a kind of,” and links for analytic relationships such as causes, enables, or contradicts.

07 Constant comparison and memos

Retrieve coded evidence across the corpus, compare positive and deviant cases, and write down why the comparison changes your interpretation.

bewley query 'onboarding_friction & early_churn'
bewley query 'onboarding_friction & !early_churn'

bewley memo add --code onboarding_friction \
  "Friction predicts churn mainly when no human recovery occurs."

bewley memo add --document corpus/interview-07.txt \
  "Deviant case: severe setup friction, but strong support restored trust."

Quote boolean expressions because &, |, !, and parentheses also have meaning to a shell.

08 Export evidence and theory

bewley export quotes --all --format jsonl --human > quotes.jsonl
bewley export html --output coded-corpus.html
bewley export theory --format json --output theory.json
bewley export theory --format mermaid --output theory.mmd
bewley export plots --output-dir plots
bewley export narrative --output narrative.md

See the result of bewley export html in the interactive Adams letters explorer.

Descriptive plots, not findings

Plots help audit the shape of the coding work: which codes dominate, which documents received disproportionate attention, and which codes appear in the same documents. They are diagnostics for returning to the evidence—not statistical tests.

Horizontal bars comparing annotation and document counts for seven codes in the Adams letters example.
Code prevalence. Dark bars count annotations; the thin light bars count distinct documents. A large gap can reveal repeated coding within a small number of sources.
Horizontal bars showing annotation and distinct-code counts by Adams letter.
Coding density. Uneven density is a prompt to check sampling, document length, and analyst attention—not evidence that one document is intrinsically more important.
Matrix showing the number of Adams letters in which each pair of codes appears.
Code co-occurrence. Cells count documents containing both codes. Co-occurrence suggests comparisons to inspect; it does not establish a relationship or causal mechanism.

Before reporting a finding, inspect the export and confirm that its excerpts are non-empty, correctly scoped, and representative of the pattern. Treat a generated narrative as an inventory to interpret, not as a substitute for reading the evidence.

09 Integrity and recovery

bewley status
bewley history
bewley fsck
bewley rebuild-index

# Undo by appending a compensating event:
bewley undo <event_id>

Run fsck before handing artifacts downstream. If a source document changes, review any conflicted annotations and resolve them against the new revision rather than silently accepting shifted text.

10 Command map

NeedCommand family
Import or revise sourcesadd, update, list documents
Run agent-assisted open codingopen-coding jobs, ep run, open-coding ingest
Build the codebookcode create|rename|merge|split|set-parent|link
Attach and inspect evidenceannotate apply|show|remove|resolve, show snippets
Compare casesquery, code coverage
Record interpretationmemo add|list|show|edit
Publish artifactsexport quotes|html|plots|theory|narrative
Inspect methodologydocs show getting-started|workflow|commands|grounded-theory

11 Agent-facing JSON contract

Bewley is designed to be driven by agents. Every command emits exactly one versioned JSON envelope by default. Branch on ok; do not infer success from the shape of data.

{
  "schema_version": "1.0",
  "ok": true,
  "command": ["bewley", "status"],
  "data": {"documents": 20, "codes": 7},
  "warnings": [],
  "next_actions": []
}

Failures replace data with a structured error and exit nonzero. Suggested actions use argv arrays and declare whether they mutate state, require network access, or require user approval.

bewley capabilities
bewley agent status
bewley agent schema envelope
bewley agent schema action
Human output is opt-in. Use --human or -H only for terminal presentation. Agents should consume the default envelope.