Sourced is a coding tool. You declare what you're listening for, run a corpus through it, and get back claims tied to quotes — plus optional per-dimension scores with coverage tags. Every number on the right-hand side traces back to a sentence on the left. The system does not invent evidence.
Sourced separates evidence, claims, and scores at every step. Each is a different kind of truth. You can stop at any layer and still have something defensible.
The exact words a participant said, with character offsets. The system never paraphrases evidence. If you can read it back to the participant unchanged, it's evidence.
Equivalent to the raw quote in qualitative coding.
A typed assertion the system makes about the participant, anchored to one or more pieces of evidence: dimension (what kind of thing), relation (how they relate to it — the frame's own vocabulary), confidence (0–1), value (what was said).
Equivalent to a code in thematic analysis or grounded theory.
A per-dimension number derived from claims: density × average confidence. Reported alongside a coverage tag (thin / moderate / strong) so a thin score can't be mistaken for a strong one.
Equivalent to a construct estimate in mixed-methods reporting.
Alongside Evidence → Claim → Score, Sourced now ships a stance stack for conversational reading: hedges, questions, negation, agreement, and gated claim-to-claim relations — with the person's confirmations outranking any model assessment. Topic matching stays in embeddings; posture does not.
Immutable messages and spans — hash, offsets, verbatim quote. The LLM never rewrites this layer.
Proposed assertions with structured producer provenance. Born contestable; born unassessed.
Model support is separate from person governance. Claim relations stay proposed until a person confirms or dismisses them.
Drafts only — portraits and reflections that cite claims and go stale when those claims are contested.
Lexical and syntax detectors recover surface stance (hedge, commitment, negation scope, questions). Agreement reads confirm / reject / partial replies. Small NLI runs only on topic-matched prior claims — never free-range — and every relation is born proposed.
Ambiguous privacy cues quarantine first; mechanical phrases and API memory-off controls gate before any semantic work.
Studio's VIA Lab previews character-strength evidence from a story without writing to memory. Local demos under examples/via_profile/ run the full SQLite loop with quotes, hashes, and governance.
A frame is rarely right on the first run. Sourced is built around the audit-and-sharpen loop most qualitative researchers already do — except the codebook lives in version control and the inter-rater comparison is run by command line.
A frame is a YAML file with the dimensions you're listening for, written examples of what each one looks like (matches), and counter-examples (non_matches). The frame is your codebook. It is versioned and exportable.
Send each participant text to /v1/observe. Each call produces a list of traces. Every trace carries the source quote, the dimension it matched, the posture, the confidence, and the method ID. This is your coded dataset.
Sample 20–50 traces. Mark each as core / secondary / incidental / wrong. Add the wrongs as anti-examples back into the frame and re-run. One round of sharpening typically moves accuracy 25–30 points. The audit loop is the work.
Pull traces and scores out as JSON, CSV, or as a single export bundle. Every score links back to its claims; every claim links back to its evidence. The audit trail is the data — not a separate artifact.
Every score ships with a coverage tag. A score with two traces under it is labelled thin. One with five or more is strong. A reviewer can decide whether to interpret a thin score; it's not hidden.
Every score links to its claims. Every claim links to its evidence. Every piece of evidence is a quote with character offsets. You can reconstruct any score in the report from the source text alone.
Frames are versioned. The same text against the same frame version produces the same traces. If you change the frame, the old run is preserved with its frame version stamped on it.
Export everything as a single JSON bundle: frame, traces, evidence, scores, audit history. Re-import into the next study or hand it to a co-author. The bundle is your data; we don't hold it back.
Sourced has not been published with a validity study. Inter-rater reliability against human coders, convergent validity against VIA-IS and Big Five, and discriminant validity against sentiment-only baselines are all open work. We label the tool honestly until those results exist.
Three commands. One participant. The shape of every study at any scale.
# 1. Declare your frame (your codebook)
cat > my_frame.yaml <<'EOF'
frame_id: study_alpha_v1
dimensions:
- id: agency
description: Statements about taking initiative or being acted upon
matches:
- "I decided to apply"
- "I had no say in it"
non_matches:
- "the weather was bad"
EOF
# 2. Observe a participant text
curl -X POST $SOURCED_API/v1/observe \
-H "Content-Type: application/json" \
-H "X-Sourced-App: $APP_ID" \
-H "Authorization: Bearer $APP_SECRET" \
-d '{
"person_id": "p_001",
"frame_id": "study_alpha_v1",
"source_id": "interview_1",
"text": "I had been waiting months. Then one morning I just decided."
}'
# 3. Pull the report
curl "$SOURCED_API/v1/frames/study_alpha_v1/report/p_001" \
-H "X-Sourced-App: $APP_ID" \
-H "Authorization: Bearer $APP_SECRET"The same four-step loop, run at corpus scale. The Erowid phenomenology study codes a public archive of psychedelic experience reports against phenomenology@1 — a frame of twelve dimensions (unity, ego dissolution, time distortion, noetic quality, ineffability…) detected from a corpus-grounded marker codebook, not hand-tuned keywords. It is the reference study for doing this yourself: the frame, the corpus config, and the run command all ship in the repo.
# The whole loop — corpus → signals → traces → review → stats — in one command.
# Frame + corpus config live in usecases/erowid_phenomenology.yaml.
sourced corpus usecases/erowid_phenomenology.yaml \
--sample 200 --where "exp_id IN (SELECT exp_id FROM meq_scores)" \
--meq-correlate --seed 7 --artifacts runs/erowid-pilot-200
# Artifacts (replayable, every score traces to a quote):
# signals.db traces.jsonl doc_stats.csv corpus_stats.csv
# review_sample.csv meq_correlations.csv run.json200 reports (sampled from the 568 with human MEQ scores) → 11,190 detection signals → 1,522 promoted traces, in 4.6 minutes on a local embedding model. Each trace carries the exact sentence it fired on, its dimension, its relation (reports / denies / questions), and a confidence. Nothing is asserted without a quote under it.
Corpus prevalence — fraction of the 200 reports with at least one trace on that dimension.
The pilot validates the data layer: the loop runs end to end, every trace is grounded in a span, and the artifacts are replayable. It does not yet claim construct validity. Against human MEQ subscales the local-embedding correlations are weak (best positive_mood r = +0.23 on prevalence) — consistent with prior work measuring this corpus (local AUC 0.476 vs OpenAI-direct 0.794). The honest read: the embedding space, not the method, is the current ceiling.
The pilot also surfaced its own next move — time_distortion over-fires at 30% of sentences because drug-narrative time-talk matches generic temporal markers. That is exactly the audit-and-sharpen step: the false positives become anti-examples in the frame, and the run repeats. The tool tells you where it's wrong.
Full write-up: docs/reports/2026-06-research-pilot.md. Frame and corpus config: usecases/erowid_phenomenology.yaml. Reproducible runbook: docs/RESEARCHER_GUIDE.md.
Sourced is a translation layer from human language to traceable construct estimates. It is not a black-box scoring engine. The provenance is the contribution.