Retag a Dataset with OpenRouter
Use an OpenRouter model to retag a CSV and audit its label changes.
Introduction
30 Second Summary
When a spreadsheet has hundreds of labels, a few questionable tags can make every summary built from it harder to trust. Checking each row by hand quickly turns into hours of repetitive work.
In this project, you will build a script in Python that sends each row to a decision model through OpenRouter. It saves the old tag beside the model's choice in a second CSV before calculating an agreement report.
What You'll Build
You will open a finished results file where every original tag sits beside the model's choice, ready for a focused review of the rows where they disagree.
By the end of this project, you'll have:
- A controlled classifier that chooses from your fixed list of allowed tags.
- A side-by-side results file that shows the old tag beside the model's choice for every row.
- A defensible agreement report showing the percentage of matched rows. The report records the change count. It also captures the result of your 30-row manual review.
- Secret Mission: An optional challenge to push your dataset review skills further.
Are there any prerequisites?
Basic Python familiarity on a laptop is enough for the coding. You also need an OpenRouter account with a key plus a CSV containing a few hundred to a few thousand rows.
Before We Start
A bulk retagging run needs enough context in every row for the model to make a useful choice. Each row also needs its current tag so you can measure disagreement.
This step prepares a local CSV for inspection. You will also create an OpenRouter API key stored in an environment variable.
In this step, get ready to:
- Prepare OpenRouter access with an API key stored outside your code.
- Export your items with their classification context and existing tags.
- Print the first ten rows in your terminal.
Create your OpenRouter key
Your API key authorizes future classification requests. Keeping it in an environment variable protects it from being copied into your script.
A new API key deserves careful handling. Keep the value out of screenshots and source files.
- Visit the OpenRouter API Keys page in your browser.
- Sign up for an OpenRouter account if prompted.
You should reach the page where your account manages API keys.
- Create a new API key.
- Name the key dataset-retagging.
OpenRouter displays the full key when it is created. This is the value your terminal needs.
- Copy the new API key to your clipboard.
macOS
- Replace sk-or-v1-YOUR-API-KEY in the command below with the key you copied.
- Store the key in OPENROUTER_API_KEY for this terminal session by running:
export OPENROUTER_API_KEY="sk-or-v1-YOUR-API-KEY"
What does this command do?
The export command makes the key available to programs launched from this terminal. Your future script can read OPENROUTER_API_KEY without storing the credential in a file.
- Check whether the environment variable is populated without printing its value by running:
if [ -n "${OPENROUTER_API_KEY:-}" ]; then echo "Set"; else echo "Not set"; fi
What should I see?
You should see Set in your terminal. This confirms that the current shell can access the key without revealing it.
Variable not set?
Check that you replaced the placeholder with your complete OpenRouter key. Keep the quotation marks around the value.
If you opened a new terminal after setting the key, run the export command again in that terminal session.
Help me check why my OpenRouter environment variable is empty.
Windows
- Replace sk-or-v1-YOUR-API-KEY in the command below with the key you copied.
- Store the key in OPENROUTER_API_KEY for this PowerShell session by running:
$env:OPENROUTER_API_KEY="sk-or-v1-YOUR-API-KEY"
What does this command do?
The $env: prefix stores the key in the current PowerShell environment. Programs launched from this terminal can read OPENROUTER_API_KEY without placing the credential in your script.
- Check whether the environment variable is populated without printing its value by running:
if ([string]::IsNullOrEmpty($env:OPENROUTER_API_KEY)) { "Not set" } else { "Set" }
What should I see?
You should see Set in PowerShell. This confirms that the current session can access the key without displaying it.
Variable not set?
Check that you replaced the placeholder with your complete OpenRouter key. Keep the quotation marks around the value.
If you opened a new PowerShell window after setting the key, run the environment variable command again in that window.
Help me check why my OpenRouter environment variable is empty.
Your OpenRouter credential is now available to the terminal while staying outside your source code. That removes the riskiest part of the setup.
Export your source CSV
The model needs a compact description of each item plus its existing tag. One row per item keeps the later comparison tied to the correct source record.
- Start an export from the tool that currently holds your items.
- Choose CSV as the export format.
You should see CSV selected as the export format before choosing the fields.
- Include the item content or metadata fields used for classification.
- Include the column containing each item's existing tag.
Your export preview should now show classification context beside the existing tag column.
- Save the exported file to your Desktop as source.csv.
You should see source.csv on your Desktop. This file is the local input for the retagging run.
Missing fields in the export?
Return to the export field selector if the file lacks item context or the existing tag column. Include only the fields needed to identify each item and classify it.
Help me choose the required columns for my source CSV.
Inspect the first ten rows
A small terminal sample catches missing columns and empty values before any requests cost money. It also shows whether long text makes the dataset difficult to inspect.
Before you print the sample, do you expect every item to show useful classification context plus an existing tag?
macOS
- Print the header plus the first ten data lines from source.csv by running:
head -n 11 ~/Desktop/source.csv
What should I see?
The head command prints the first 11 lines. You should see the column names followed by ten data lines.
File not found?
Confirm that the exported file is named source.csv on your Desktop. Check the file extension because spreadsheet tools can hide it.
Help me find why the terminal cannot read my source CSV.
Windows
- Print the first ten items from source.csv as a table by running:
Import-Csv -Path "$HOME\Desktop\source.csv" | Select-Object -First 10 | Format-Table
What should I see?
- The Import-Csv command reads the column names. It converts each row into an object.
- The Select-Object command limits the output to the first ten items.
- The Format-Table command displays those items under their column names.
File not found?
Confirm that the exported file is named source.csv on your Desktop. Check the file extension because spreadsheet tools can hide it.
Help me find why PowerShell cannot import my source CSV.
You should now see ten sample items beneath their column names. Check that each sample has enough context for classification plus an existing tag.
✔️ My setup is ready
Your credential and source data are ready for the first small classification run.
ⓧ I'd like to double check the setup
Confirm that your setup matches these two project artifacts:
- OpenRouter API key: Created in the OpenRouter dashboard and stored in a shell environment variable.
- Source CSV: Exported locally with one row per item, including item content or metadata for classification and an existing tag column.
Your key is protected and your source rows are visible. Next, you will send a small batch of twenty rows through the model and compare its tags with the old ones.
Inspect Your Dataset
The first ten rows of your CSV are already visible in your terminal. They show the raw material your retagging run must understand.
A classifier needs precise input columns. Otherwise, it may judge the wrong part of each row.
It also needs a closed set of valid outputs. This step turns your sample into that map.
In this step, get ready to:
- Identify the item content columns.
- Identify the current-tag column.
- Define the fixed list of allowed tags.
Map the classification columns
CSV headers define the role of each column. The model later reads the item content.
Your report compares the model's choice with the existing tag. A clear column map keeps that comparison traceable.
- Switch back to the terminal output from earlier.
- Find the header row above the first ten records.
- Choose every column that contains the item content or metadata needed for classification.
- Record the item content column names here: your item content column names.
- Identify the column that holds each row's existing tag.
- Record the current-tag column here: your current tag column name.
Your column map now separates classification evidence from the old decision. Every later comparison can point back to the right fields.
Define the allowed tag list
A taxonomy is the set of labels your dataset is meant to use. A fixed list keeps every model choice inside that set.
- Review the intended taxonomy for this dataset.
- List each valid tag once.
- Match each tag's spelling to the intended taxonomy.
- Match each tag's capitalization to the intended taxonomy.
- Record the final list here: your allowed tags separated by commas.
Why use a fixed list?
A fixed list gives the model one closed set of valid outcomes. This prevents new spellings from becoming accidental labels.
The intended taxonomy remains the source of truth. Historical tags can contain retired labels or spelling drift.
Verify the dataset mapping
The sample provides a quick check that your chosen fields work together. Each row should have enough evidence for classification plus an old tag for comparison.
Before you check the sample, do you expect every old tag to appear in your allowed list?
- Select one row from the first ten records.
- Read its classification evidence from your item content column names.
- Locate its old label under your current tag column name.
- Compare that old label with your allowed tags separated by commas.
- Repeat this trace for the remaining nine rows.
You should be able to trace each sample row from its evidence to its old tag. Any old label outside the fixed list becomes a clear candidate for retagging.
Your recorded mapping now names the item content columns plus the current-tag column. Your recorded taxonomy contains the complete allowed list.
You have cleared the ambiguity that makes bulk retagging risky. Next, you'll test this mapping on a small batch before touching the full file.
Test Twenty Model Decisions
Your source CSV is ready. You also know which columns contain the item text and its current tag.
Twenty rows give you a controlled test before the full dataset reaches the OpenRouter API. Each request constrains the decision model to your fixed taxonomy so every returned tag is usable.
In this step, get ready to:
- Configure the retagging script with your CSV columns and allowed tags.
- Send twenty rows to a low-cost decision model through OpenRouter.
- Print every old tag beside the model's new tag.
Configure the test data
The script needs four dataset-specific values before it can read your rows. These values connect the generic retagging logic to the CSV you inspected earlier.
- Return to the terminal from earlier.
- Record the path to your source CSV here: path/to/source.csv.
- Record the item column you identified earlier here: your item column.
- Record the current-tag column you identified earlier here: your current-tag column.
- Enter your fixed tag values as a comma-separated list here: comma-separated allowed tags.
- Use your text editor to create retag.py in the same folder as your source CSV.
- Configure retag.py to load the dataset by pasting this code:
import csv
import json
import os
import urllib.request
# Connect the script to the dataset and its fixed taxonomy
SOURCE_CSV = "[[SOURCE_CSV="path/to/source.csv"]]"
ITEM_COLUMN = "[[ITEM_COLUMN="your item column"]]"
TAG_COLUMN = "[[TAG_COLUMN="your current-tag column"]]"
ALLOWED_TAGS = [
tag.strip()
for tag in "[[ALLOWED_TAGS="comma-separated allowed tags"]]".split(",")
]
MODEL = "~typesafe/jev-latest"
API_URL = "https://openrouter.ai/api/alpha/decisions"
TEST_LIMIT = 20
API_KEY = os.environ["OPENROUTER_API_KEY"]
# Load the source rows so the test can use a small slice
with open(SOURCE_CSV, newline="", encoding="utf-8") as source_file:
rows = list(csv.DictReader(source_file))
print(f"Loaded {len(rows)} rows. Testing the first {min(TEST_LIMIT, len(rows))}.")
What does this code do?
- The dataset settings tell the script where to find each item and its existing tag.
- The allowed-tag value becomes a Python list after the script splits it at each comma.
- The test limit keeps this run to the first twenty rows.
- The API key comes from OPENROUTER_API_KEY in your environment. The key never appears in the source file.
- Save retag.py.
- Check the dataset configuration by running:
python retag.py
What does this command do?
Python runs retag.py with your saved configuration. This first run confirms that the environment variable and source CSV are available before any API requests are made.
You should see the total number of loaded rows. The message should also say that the script is testing the first 20 rows.
Dataset not loading?
- Check that your source CSV path points to the exported file from the previous step.
- Check that your terminal still has the OpenRouter API key environment variable from earlier.
- Confirm that every allowed tag is separated by a comma.
Ask for help with the values you entered without sharing your API key: Help me debug why my Python script cannot load its CSV or environment variable.
Send each row for one decision
A choice question gives the model a closed set of valid answers. The item becomes the decision state while your allowed tags become the available criteria.
- Add the following loop below the existing code in retag.py:
for index, row in enumerate(rows[:TEST_LIMIT], start=1):
# Ask for one decision from the fixed set of allowed tags
payload = {
"model": MODEL,
"state": row[ITEM_COLUMN],
"questions": {
"tag": {
"type": "choice",
"instructions": "Choose exactly one tag for this item.",
"criteria": {tag: tag for tag in ALLOWED_TAGS},
}
},
}
request = urllib.request.Request(
API_URL,
data=json.dumps(payload).encode("utf-8"),
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(request) as response:
result = json.load(response)
old_tag = row[TAG_COLUMN]
new_tag = result["answers"]["tag"]["choice"]
print(f"{index:02d} | old: {old_tag} | new: {new_tag}")
How are the decisions constrained?
- The state field contains the item that the model classifies.
- The choice question limits the answer to the keys inside criteria.
- The authorization header uses the environment value stored in API_KEY.
- The response supplies one selected tag through choice.
- The final line prints the existing tag beside the model's decision for direct comparison.
- Save retag.py.
✔️ Awesome, I've got everything!
Your script now loads the CSV and requests one allowed tag for each of the first twenty rows. Make sure retag.py is saved before testing it.
ⓧ I'd like to double check the full code
Compare your saved retag.py with the complete test script below:
import csv
import json
import os
import urllib.request
# Connect the script to the dataset and its fixed taxonomy
SOURCE_CSV = "[[SOURCE_CSV="path/to/source.csv"]]"
ITEM_COLUMN = "[[ITEM_COLUMN="your item column"]]"
TAG_COLUMN = "[[TAG_COLUMN="your current-tag column"]]"
ALLOWED_TAGS = [
tag.strip()
for tag in "[[ALLOWED_TAGS="comma-separated allowed tags"]]".split(",")
]
MODEL = "~typesafe/jev-latest"
API_URL = "https://openrouter.ai/api/alpha/decisions"
TEST_LIMIT = 20
API_KEY = os.environ["OPENROUTER_API_KEY"]
# Load the source rows so the test can use a small slice
with open(SOURCE_CSV, newline="", encoding="utf-8") as source_file:
rows = list(csv.DictReader(source_file))
print(f"Loaded {len(rows)} rows. Testing the first {min(TEST_LIMIT, len(rows))}.")
for index, row in enumerate(rows[:TEST_LIMIT], start=1):
# Ask for one decision from the fixed set of allowed tags
payload = {
"model": MODEL,
"state": row[ITEM_COLUMN],
"questions": {
"tag": {
"type": "choice",
"instructions": "Choose exactly one tag for this item.",
"criteria": {tag: tag for tag in ALLOWED_TAGS},
}
},
}
request = urllib.request.Request(
API_URL,
data=json.dumps(payload).encode("utf-8"),
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(request) as response:
result = json.load(response)
old_tag = row[TAG_COLUMN]
new_tag = result["answers"]["tag"]["choice"]
print(f"{index:02d} | old: {old_tag} | new: {new_tag}")
Run the twenty-row test
The first complete run proves that the API connection and taxonomy work together. It also gives you a readable sample of agreements and disagreements before you process the full file.
Before you run the test, do you expect the new tags to match every old tag?
- Start the twenty-row decision test by running:
python retag.py
What does this command test?
This run reads only the first twenty source rows. It sends each item to the selected decision model and prints the returned tag beside the old one.
You should see twenty numbered comparisons from 01 through 20. Every new: value should appear in your fixed allowed-tag list.
That is the test working. Your script can now produce constrained model decisions while preserving the original tags for comparison.
Decisions not printing?
- Confirm that the item column and current-tag column match the CSV header exactly.
- Check that the OpenRouter account linked to your key can make model requests.
- Inspect your comma-separated tag list for blank values or misspelled labels.
Share the error text without sharing your API key: Help me debug my twenty-row OpenRouter decision test.
Your twenty-row test is complete. Next, you can run the same decision process across the full CSV and save every comparison to a new file.
Retag the Full Dataset
Your twenty-row test proved that the retagging path can choose from the fixed tag list. The next challenge is preserving every decision in a CSV you can inspect.
A full run sends every source row through OpenRouter. Its activity record shows the run's token usage plus cost.
In this step, get ready to:
- Save the model decisions to a separate results CSV.
- Process every source row into the complete results CSV.
- Review the full run on the OpenRouter activity page.
Add the complete results export
Terminal output lets you watch decisions as they happen. A separate results file preserves both tag versions for later review.
The twenty-row limit stays in place for one short export check. This keeps the first saved file small enough to inspect quickly.
- In the retagging script from earlier, add a results export that writes every processed item with both tag versions in separate columns.
- Save the retagging script.
Before you rerun the script, do you expect the results CSV to contain twenty data rows or every source row?
- Rerun the script with the same terminal command from your twenty-row test.
You'll see twenty old-tag-versus-new-tag pairs in the terminal. The script also saves a separate results CSV containing those twenty items.
- Inspect the first ten rows of the results CSV with the same terminal method you used for the source CSV.
You should see the original tag in one column. You should see the model-selected tag in another column.
What does this export check prove?
The short run proves that each model decision stays attached to its source item. It also catches missing tag columns before the larger paid run.
Missing a tag column?
- Check that each exported record includes the original tag from its source row.
- Check that the model-selected tag is stored in a separate field on the same record.
- Check that the CSV export runs after all twenty result records have been collected.
Help me fix my results CSV export.
Run the full retagging job
The export shape now works on the tested path. Removing the processing limit scales the same classification rules to the full source file.
This run creates paid requests for every remaining row. Your short export check has already caught the most visible output problems.
- In the retagging script, remove the processing limit that stops after twenty rows.
- Save the retagging script.
✔️ My script matches the checkpoint
Your script is ready when the test limit is gone. The export must still preserve both tag versions for every processed item.
ⓧ I'd like to double check the full code
Compare your complete script against this cumulative behavior checklist:
- Confirm that the script reads every row from the full source CSV.
- Confirm that the script reads the OpenRouter API key from the shell environment.
- Confirm that the selected model must choose exactly one value from the fixed allowed-tag list.
- Confirm that the script prints both tag versions side by side.
- Confirm that the script writes every processed item to the complete results CSV.
The source run covered about 2,300 papers in 83 seconds. Treat that as a reference point because your file size may differ.
Before you start the full run, do you expect the results CSV row count to match the source CSV row count?
- Start the full run with the same terminal command from your twenty-row test.
You'll see each source row's old tag beside its new tag as processing continues. The terminal may pause while individual model requests complete.
When the final row finishes, the separate results CSV should contain every processed item. Both tag versions should remain in separate columns.
- Compare the number of data rows in the results CSV with the number in the source CSV.
The counts should match. This confirms that the full source file reached the results export.
What does matching the row count prove?
A matching count proves that every source item has a corresponding exported result. The separate tag columns preserve the evidence needed for the disagreement review.
Seeing fewer result rows?
- Check that no twenty-row processing limit remains in the script.
- Check the final terminal output for the source row where processing stopped.
- Check that every successful model response is added to the exported results collection.
Help me find why the full run stopped early.
Review the OpenRouter activity record
The saved CSV proves that the script produced results. The OpenRouter activity record gives you independent evidence of the usage behind that run.
Before you check the activity page, do you expect the full run to show more usage than the twenty-row test?
- Return to your OpenRouter account from earlier.
- Open the activity page.
- Find the activity record created when you ran the full dataset.
- Review the token usage recorded for the run.
- Review the cost recorded for the run.
You should see the full retagging run represented in the activity page. Its record should show the token usage plus the amount charged.
Can't find the full run?
- Check that the activity page includes the time when you ran the script.
- Check that the record uses the model configured in your retagging script.
- Check that you returned to the same OpenRouter account used by your API key.
Help me locate my retagging activity record.
That's the full batch done. Next, you'll isolate the rows where the two tags disagree for a focused manual review.
Audit Changed Tags
Your full retagging run has produced a results CSV with every old tag beside its proposed replacement. The next goal is to test a sample of those changes before trusting them.
A mismatch from the decision model flags a row for inspection. Human review determines whether the replacement fits the item better.
In this step, get ready to:
- Isolate rows where the old tag differs from the new tag.
- Select exactly 30 changed rows at random.
- Mark every sampled change as accept or reject.
Filter the changed rows
The complete results CSV remains your record of the full run. A separate filtered view keeps the audit focused on disagreements.
- Switch back to the retagging script from earlier.
- Locate the section immediately after the complete results CSV is written.
- Add a local post-processing view that displays only rows whose old tag differs from the model-selected new tag.
- Save the retagging script.
Before you run the local post-processing path, do you expect any matching tag pairs to appear?
- Run the script's local post-processing path against the existing results CSV.
You should see only rows where the old tag differs from the new tag.
- Compare the complete results CSV row count with the source CSV row count.
You should see the same total in both files. This confirms that filtering created an audit view without removing rows from the complete results.
Select a random sample
A random sample prevents you from choosing only obvious changes. Thirty rows provide a manageable set for direct review.
- Update the local post-processing view to display the source content plus both tag choices for a random sample of exactly 30 changed rows.
- Save the retagging script.
Before you run the audit view, how many changed rows do you expect it to select?
- Run the script's local audit path against the existing results CSV.
You should see exactly 30 sampled rows. Each row should show its source content plus both tag choices.
Review each proposed change
Mark accept when the new tag fits the item better within your fixed taxonomy. Mark reject when the old tag remains the better choice.
- Add a one-at-a-time manual audit flow with a decision field restricted to accept or reject.
- Save the retagging script.
Before you start the audit, do you expect the model's proposed tag to be better for every changed row?
- Run the manual audit flow against the random sample.
- Review the source content shown for the first sampled row.
- Compare the model-selected tag with the old tag.
- Enter accept or reject for that row.
- Repeat the review for the remaining 29 rows.
- Save the completed manual audit sample from the script.
Before you inspect the finished sample, do you expect any blank decision fields to remain?
- Count the rows in your manual audit sample.
You should count exactly 30 rows.
- Scan the decision field for blank values.
Every sampled row should contain either accept or reject. That is the human check done: every proposed change in your sample now has a recorded decision.
Audit loop stopping early?
- Confirm that the manual audit flow iterates over the 30 sampled rows.
- Check that each decision is stored before the script advances to the next row.
- Verify that the decision field accepts only accept or reject.
Help me debug my manual audit flow.
Your thirty decisions turn model disagreement into evidence you can inspect. Next, you'll summarize how often the tags matched plus how many sampled changes earned your approval.
Print the Agreement Report
Your OpenRouter run is complete. The results CSV now puts every old tag beside the model-selected tag.
Your thirty-row audit captures which changed tags you trust. The row-by-row evidence still needs a compact summary you can share.
In this step, get ready to:
- Calculate the percentage of processed rows where both tags match.
- Count rows whose model-selected tag differs from the old tag.
- Count accepted changes in the thirty-row audit.
Summarize the full results
Agreement summarizes how closely the model-selected tags follow the old tags across the full dataset. The changed-row count shows the size of the proposed update.
How the full-file metrics work
- The agreement percentage uses all processed rows as its denominator.
- A matching row has identical values in its two tag columns.
- The changed-row count covers every row with different values in those columns.
- Switch back to the retagging script from earlier.
- Find the existing section that records the thirty manual audit decisions.
- Add a report section after that code that calculates the agreement percentage plus changed-row count from the saved results CSV.
- Save the retagging script.
The classification run is already complete. This check reads the saved results CSV, so it avoids another batch of model requests.
Before you run the summary, do you expect the agreement percentage or changed-row count to reveal more about the scale of the retagging?
- Run the new report section against the saved results CSV with the local script workflow you used earlier.
You should see an agreement percentage based on the full dataset. You should also see the total number of changed rows.
Report totals look wrong?
- Check that the agreement calculation uses every row in the saved results CSV as its denominator.
- Check that the changed-row calculation compares both tag values from the same row.
Ask for help checking the report calculations.
Add the audit verdict
The full-file figures measure consistency across every row. The manual audit adds human judgment to a sample of the model's proposed changes.
What the accepted count means
The accepted-sample count covers decisions marked accept among the thirty audited disagreements. Accuracy requires trusted ground truth across the dataset, so this sample provides a focused quality check.
- Extend the terminal report with the count of manual audit decisions marked accept.
- Save the retagging script.
Before you run the final report, how do you expect the accepted count to compare with the thirty audited changes?
- Run the agreement report against the saved results CSV plus the recorded audit decisions.
What should I see?
- You should see the percentage of model-selected tags that match the old tags.
- You should see the total number of rows whose tag changed.
- You should see the number of accepted changes from the thirty-row manual sample.
Accepted count missing?
- Confirm that every sampled disagreement has an accept or reject decision.
- Confirm that the accepted count only uses decisions from the thirty-row manual sample.
Ask for help tracing the manual audit count.
Strong finish. Your report now separates dataset-wide agreement from human-reviewed evidence.
Secret mission
Create a Retagging Approval Policy
Your agreement report shows how often the new tags match the old ones. Turn your thirty manual decisions into an acceptance rate and a clear policy for applying model-selected changes.
Clean Up Your Resources
Clean Up Your Resources
Choose whether to preserve your local work, pause it for later, or delete it. The completed run has no always-on process, so keeping local artifacts creates no further OpenRouter usage or project cost.
Resources you used:
- Local source CSV containing the original tags.
- Local results CSV containing the old tags beside the model-selected tags.
- Local retagging script containing the fixed allowed-tag list.
- Local manual audit sample containing thirty accept or reject decisions.
- Terminal session containing the printed agreement report.
- Shell environment variable containing the OpenRouter API key.
Keep everything running
The retagging script and agreement report are the reusable pieces. The source CSV plus the results CSV preserve the evidence behind your decisions.
- Save a copy of the agreement report from the terminal in your own notes.
- Keep an untouched copy of the source CSV as a rollback point.
- Apply the accepted changes from the manual audit sample back to your original source.
- Retain the results CSV beside the manual audit sample for future review.
- Retain the retagging script for future classification batches.
- Remove every shell history entry containing the raw OpenRouter API key after you finish this session.
Pause - I'll come back to this later
Pause by ending the terminal work while leaving the local artifacts untouched. The script sends no more rows while it is stopped.
- Save a copy of the agreement report from the terminal in your own notes.
- Stop the retagging script with your terminal's interrupt control if it is still running.
- Remove the OpenRouter API key from the shell environment variable you used earlier.
- Search your shell history for the raw OpenRouter API key value.
- Delete every matching history entry using your shell's history controls.
- Close the terminal session after clearing the key.
- Leave the source CSV, results CSV, retagging script, and manual audit sample in their current local folder.
Delete - I don't want to use this again
Remove the local artifacts when you want a clean slate. Deleting these copies is final once your system clears them.
- Apply the accepted changes from the manual audit sample back to your original source.
- Confirm that your original source contains those accepted changes.
- Remove the OpenRouter API key from the shell environment variable you used earlier.
- Search your shell history for the raw OpenRouter API key value.
- Delete every matching history entry using your shell's history controls.
- Close the terminal session after clearing the key.
macOS
- Use the macOS file browser to locate the local source CSV from earlier.
- Repeat the search for the results CSV, retagging script, and manual audit sample.
- Move those local artifacts to your system's deleted-items area.
- Clear the deleted-items area to complete the removal.
Windows
- Use the Windows file browser to locate the local source CSV from earlier.
- Repeat the search for the results CSV, retagging script, and manual audit sample.
- Move those local artifacts to your system's deleted-items area.
- Clear the deleted-items area to complete the removal.
Nice Work!
Nice Work!
You did it! You built a bulk retagging workflow that uses OpenRouter to challenge inherited labels against a fixed tag list.
What you learned:
- Built a working retagging script that sends each row to OpenRouter with a fixed list of allowed tags.
- Produced a results CSV that keeps every old tag beside the model-selected new tag.
- Tested the model's changes with a 30-row manual audit. Printed an agreement report with the match percentage. The report includes the changed-row count. It also includes the accepted-sample count.
- Secret Mission: Completed the optional Secret Mission to extend your dataset review workflow.
Ready to quiz yourself?