This repository now contains a complete proof-of-concept research harness for studying how consumer chatbot LLMs respond to interpersonal/advice-seeking prompts when both the explicit question framing and the tone of the scenario narrative are varied. It includes:
- the active prompt-and-sample structure used for the experiment
- Bash scripts for generating queries, submitting them to multiple LLM providers, and collecting outputs
- second-pass and aggregate comparison prompts and scripts
- archived generated artifacts in
./results/for independent analysis and review - a manuscript draft and related research documentation
Archived generated artifacts are stored in ./results/. They are intentionally separated from the active harness directories so they do not impede using this repository to run your own tests.
Read in this order:
SCIENTIFIC_PAPER_DRAFT.mdoutput/analysis_all_CHATGPT.md,output/analysis_all_GEMINI.md,output/analysis_all_CLAUDE.mdoutput/analysis_001_*.md,output/analysis_003_*.md,output/analysis_008_*.mdANALYSIS_CODE_CHEATSHEET.mdresults/
Read in this order:
REPOSITORY_PROCESS_DOCUMENTATION.md- this
README.md prefixes/samples/build_queries.shsubmit_queries.shcombine_series.shbuild_result_queries.shsubmit_result_queries_prompt.mdsubmit_result_queries.shcompare_all_results_prompt.mdcompare_all_results.shenv.exampleresults/
Read in this order:
REPOSITORY_PROCESS_DOCUMENTATION.md- this
README.md samples/andprefixes/queries/output/combined_*.mdoutput/combined_query_*.mdANALYSIS_CODE_CHEATSHEET.mdoutput/analysis_*.mdoutput/analysis_all_*.mdresults/SCIENTIFIC_PAPER_DRAFT.md
The code in this repository has been significantly written or altered by an AI tool with human supervision. The instructions to the AI agents were detailed, step-by-step pseudocode with very specific limitations. Whenever possible, the code is also explicitly and extensively commented so that it may be audited to determine that it does what it says it does. Again, while the code in this repository works for me and I am using it, it should be considered a proof-of-concept for others to refine, fix, and build upon.
Used for converting the TSV output from the RSS feed into something useable.
Converts a TSV export into two root-level files:
converted_tsv.htmlconverted_tsv.md
The script expects the TSV path as its first argument. It assumes the TSV has a header row and three tab-separated columns:
titleurlcontents
The HTML output preserves the contents field as HTML and removes the trailing Reddit export footer starting at <!-- SC_ON -->. The Markdown output strips most HTML tags and converts common HTML entities into plain text.
Example:
./convert_tsv_to_html.sh 1_reference/selected-items.tsvCombines every Markdown file in prefixes/ with every Markdown file in samples/ and writes the results to queries/.
- Input:
prefixes/*.md,samples/*.md - Output:
queries/<sample_id>_<prefix_name>_<sample_suffix>.md - Format: prefix text, then a blank line, then sample text
Example:
./build_queries.shIf prefixes/negative-others.md and samples/008_unsympathetic.md exist, the script writes queries/008_negative-others_unsympathetic.md.
Submits every Markdown file in queries/ to one or more LLM APIs as a fresh single-turn user message and writes the returned assistant text to output/.
- Input:
queries/*.md - Output:
output/<query_name>_CHATGPT.md,output/<query_name>_GEMINI.md, and/oroutput/<query_name>_CLAUDE.md - Configuration: automatically loads
.envfrom the repo root if present - Provider selection:
--chatgptsubmits only to OpenAI--geminisubmits only to Gemini--claudesubmits only to Claude--allsubmits to all three- provider switches can be combined, for example
--chatgpt --claude - no switch defaults to
--chatgpt
- Logging and errors:
- stdout is written to
output/results.log - stderr is written to
output/results.err - existing output files are skipped instead of being regenerated
- selected providers are submitted in parallel for each query
- request failures are logged and the script continues with the remaining query/provider combinations
- the script exits non-zero at the end if any requests failed
- stdout is written to
- Query handling constraints:
- every request is sent as a single fresh user turn, to mirror typing a prompt into a blank web chat
- OpenAI requests set
store: false - Gemini requests set
store: false - Claude requests use the stateless Messages API with a single
usermessage - OpenAI requests include a unique
safety_identifierper query - Claude requests include a unique
metadata.user_idper query - Gemini's
generateContentendpoint does not expose a documented per-request user-ID field, so isolation there is enforced by sending each query as a standalone single-turn request with no prior history andstore: false
- API behavior:
- OpenAI uses
POST /v1/responses - Gemini uses
POST /v1beta/models/<model>:generateContent - Claude uses
POST /v1/messages - each query is sent as a standalone prompt with no prior conversation state
- OpenAI uses
Requirements:
- for
--chatgpt:OPENAI_API_KEY - for
--gemini:GEMINI_API_KEY - for
--claude:CLAUDE_API_KEYorANTHROPIC_API_KEY curlmust be installedjqmust be installed
Optional:
OPENAI_MODELoverrides the default model, which isgpt-5GEMINI_MODELoverrides the default model, which isgemini-3.6-flashCLAUDE_MODELoverrides the default model, which isclaude-sonnet-4-6ANTHROPIC_VERSIONoverrides the Claude API version header, which defaults to2023-06-01
Example:
./submit_queries.sh --chatgpt --claudeExample .env:
OPENAI_API_KEY=your_key_here
OPENAI_MODEL=gpt-5
GEMINI_API_KEY=your_key_here
GEMINI_MODEL=gemini-3.6-flash
CLAUDE_API_KEY=your_key_here
CLAUDE_MODEL=claude-sonnet-4-6
ANTHROPIC_VERSION=2023-06-01Recursively combines related Markdown files from a directory tree into one output file per numeric ID for each matching directory.
- Input: files named like
base_<id>.md,sym_<id>.md,not_<id>.md, andresult_*_<id>.md - Directory selection: any directory containing either
base_<id>.mdorresult_*_<id>.mdfiles is processed - Output:
combined_<id>.mdin each matching input directory by default, or in a mirrored directory tree under an optional output directory - Format:
- each source file starts with a Markdown header line containing its filename
- file contents are concatenated with a blank line between sections
The script orders inputs like this:
base_<id>.mdsym_<id>.mdnot_<id>.mdresult_neutral_<id>.md,result_neutral_sym_<id>.md,result_neutral_not_<id>.mdresult_positive_<id>.md,result_positive_sym_<id>.md,result_positive_not_<id>.mdresult_negative_<id>.md,result_negative_sym_<id>.md,result_negative_not_<id>.md
For additional result families such as result_negative_me_<id>.md, the script keeps the same order within that family: no suffix first, then _sym, then _not.
Example:
./combine_series.sh outputThat command processes output/ and every nested subdirectory beneath it.
To write the combined files somewhere else:
./combine_series.sh output combined_outputIf output/001/ contains matching files, the combined output is written to combined_output/001/.
Transforms each output/combined_<id>.md file into a compact query-oriented file for downstream comparative analysis.
- Input:
output/combined_<id>.md - Output:
output/combined_query_<id>.md - Skip behavior:
- ignores files such as
combined_query_<id>.md - skips rebuilding if the target
combined_query_<id>.mdalready exists
- ignores files such as
- Transformations:
- omits the first four sections from the combined file:
<id>_control.md<id>_neutral.md<id>_sympathetic.md<id>_unsympathetic.md
- keeps headers for the remaining sections
- rewrites those headers to a compact initials-based form
- removes the first body line immediately under each retained header when that line is the repeated filename/provider marker
- omits the first four sections from the combined file:
Header format:
- source header:
008_negative-me_control_CHATGPT.md - rewritten header:
008_n-m_c_CHATGPT
That means:
- the prompt family is reduced to initials split on hyphens
- the sample variant is reduced to its first letter:
control->cneutral->nsympathetic->sunsympathetic->u
- the provider suffix is preserved
Example:
./build_result_queries.shSubmits every output/combined_query_<id>.md file to one or more LLM APIs for comparative analysis and writes the returned text to output/.
- Input:
output/combined_query_*.md - Output:
output/analysis_<id>_CHATGPT.md,output/analysis_<id>_GEMINI.md, and/oroutput/analysis_<id>_CLAUDE.md - Configuration: automatically loads
.envfrom the repo root if present - Prompt source:
submit_result_queries_prompt.md - Provider selection:
--chatgptsubmits only to OpenAI--geminisubmits only to Gemini--claudesubmits only to Claude--allsubmits to all three- provider switches can be combined, for example
--chatgpt --claude - no switch defaults to
--chatgpt
- Logging and errors:
- stdout is written to
output/analysis.log - stderr is written to
output/analysis.err - existing output files are skipped instead of being regenerated
- selected providers are submitted in parallel for each combined query file
- request failures are logged and the script continues with the remaining query/provider combinations
- the script exits non-zero at the end if any requests failed
- stdout is written to
- Query handling constraints:
- every request is sent as a single fresh user turn, to mirror typing a prompt into a blank web chat
- OpenAI requests set
store: false - Gemini requests set
store: false - Claude requests use the stateless Messages API with a single
usermessage - OpenAI requests include a unique
safety_identifierper query - Claude requests include a unique
metadata.user_idper query - Gemini's
generateContentendpoint does not expose a documented per-request user-ID field, so isolation there is enforced by sending each query as a standalone single-turn request with no prior history andstore: false
- Prompt behavior:
- the script prepends a fixed analysis prompt to the inlined contents of each
combined_query_<id>.mdfile and submits that as one user message - the response is written verbatim to the corresponding
analysis_<id>_<PROVIDER>.mdfile
- the script prepends a fixed analysis prompt to the inlined contents of each
Example:## AI Usage
The code in this repository has been significantly written or altered by an AI tool with human supervision. The instructions to the AI agents were detailed, step-by-step pseudocode with very specific limitations. Whenever possible, the code is also explicitly and extensively commented so that it may be audited to determine that it does what it says it does. Again, while the code in this repository works for me and I am using it, it should be considered a proof-of-concept for others to refine, fix, and build upon.
./submit_result_queries.sh --allSubmits all output/combined_query_<id>.md files together to one or more LLM APIs for one aggregate comparison pass per provider.
- Input: every
output/combined_query_*.md - Output:
output/analysis_all_CHATGPT.md,output/analysis_all_GEMINI.md, and/oroutput/analysis_all_CLAUDE.md - Configuration: automatically loads
.envfrom the repo root if present - Prompt source:
compare_all_results_prompt.md - Provider selection:
--chatgptsubmits only to OpenAI--geminisubmits only to Gemini--claudesubmits only to Claude--allsubmits to all three- provider switches can be combined, for example
--chatgpt --claude - no switch defaults to
--chatgpt
- Logging and errors:
- stdout is written to
output/compare_all.log - stderr is written to
output/compare_all.err - existing output files are skipped instead of being regenerated
- selected providers are submitted in parallel
- request failures are logged and the script continues with the remaining providers
- the script exits non-zero at the end if any requests failed
- stdout is written to
- Query handling constraints:
- every request is sent as a single fresh user turn, to mirror typing into a blank web chat
- OpenAI requests set
store: false - Gemini requests set
store: false - Claude requests use the stateless Messages API with a single
usermessage - OpenAI requests include a unique
safety_identifierper query - Claude requests include a unique
metadata.user_idper query - Gemini's
generateContentendpoint does not expose a documented per-request user-ID field, so isolation there is enforced by sending each aggregate query as a standalone single-turn request with no prior history andstore: false
- Prompt behavior:
- the script prepends a fixed comparison prompt
- it then inlines every
combined_query_*.mdfile in one aggregate submission, separated by filename headers - the response is written verbatim to the corresponding
analysis_all_<PROVIDER>.mdfile
Example:
./compare_all_results.sh --allThe current compare_all_results.sh implementation submits all output/combined_query_*.md files as one inline text prompt per provider rather than uploading them as files.
As of July 30, 2026, the current aggregate input size in this repo is:
output/combined_query_001.md: 90,737 bytes, 14,839 wordsoutput/combined_query_003.md: 64,084 bytes, 10,487 wordsoutput/combined_query_008.md: 40,863 bytes, 6,382 words- total: 195,684 bytes, 31,708 words
A rough estimate puts that aggregate prompt around 50k-65k input tokens once prompt text and separators are included.
That is currently well below the documented limits of the default large-context models used here:
- Gemini 3.6 Flash:
1,048,576input tokens - Claude Sonnet 4.6: up to
1Mtokens
Practical caveats:
- the current corpus is unlikely to hit a hard context limit on Gemini or Claude
- output quality may still degrade before the hard limit is reached as more files are added
- transient provider capacity or timeout issues may appear before context exhaustion
- if the aggregate corpus grows several times larger,
compare_all_results.shis the script most likely to need chunking or batching first
Stores short commands and one-liners used in this project.
Right now it includes the SQLite command that exports selected RSSGuard items into a TSV file.
converted_tsv.htmlandconverted_tsv.mdare generated files and are ignored by Git.queries/is populated bybuild_queries.sh.output/is populated bysubmit_queries.sh.- combined review files can be generated from any directory with
combine_series.sh. results/stores archived generated artifacts for independent analysis and review. Those artifacts are intentionally not part of the activesamples/,queries/, oroutput/workflow so they do not interfere with using the harness for fresh testing.
The code in this repository has been significantly written or altered by an AI tool with human supervision. The instructions to the AI agents were detailed, step-by-step pseudocode with very specific limitations. Whenever possible, the code is also explicitly and extensively commented so that it may be audited to determine that it does what it says it does. Again, while the code in this repository works for me and I am using it, it should be considered a proof-of-concept for others to refine, fix, and build upon.
You are encouraged to fork and refine or rebuild this program or create something better that has the same functionality.
This is what most people would call "vibe coded".
