Skip to content

Instantly share code, notes, and snippets.

@sharno
Created March 6, 2026 03:24
Show Gist options
  • Select an option

  • Save sharno/dbd3cc89242c566e552bdf87f6da9c67 to your computer and use it in GitHub Desktop.

Select an option

Save sharno/dbd3cc89242c566e552bdf87f6da9c67 to your computer and use it in GitHub Desktop.
freetaxusa filing taxes with an agent

Taxbot Agent Notes

Shell and tooling

  • Use fish as the source-of-truth shell.
  • Run terminal commands as fish -lc '<command>'.
  • Use uv for Python.
  • Use js_repl for persistent browser control when working interactively in FreeTaxUSA.

FreeTaxUSA workflow that works

Use a separate real Chrome instance with remote debugging enabled, then attach to it from js_repl with Playwright over CDP.

This is the workflow that worked reliably for interactive FreeTaxUSA filing.

One-time repo setup

Run from this repo:

fish -lc 'npm init -y'
fish -lc 'npm install playwright'

Launch the browser to control

Use a dedicated profile inside this repo:

fish -lc 'mkdir -p .chrome-debug-profile'
fish -lc "google-chrome-stable \
  --remote-debugging-port=9222 \
  --user-data-dir=/home/sharno/src/taxbot/.chrome-debug-profile \
  --no-first-run \
  --no-default-browser-check"

Notes:

  • Keep this Chrome process running while working.
  • The user signs in manually in this Chrome window.
  • Reuse the same .chrome-debug-profile across turns.

Attach from js_repl

Bootstrap:

var chromium;
({ chromium } = await import("playwright"));

Attach handles:

var cdpBrowser;
var cdpContext;
var cdpPage;

cdpBrowser = await chromium.connectOverCDP("http://127.0.0.1:9222");
cdpContext = cdpBrowser.contexts()[0];
cdpPage = cdpContext.pages()[0] ?? await cdpContext.newPage();
await cdpPage.goto("https://www.freetaxusa.com/", { waitUntil: "domcontentloaded" });

After attachment, keep using cdpPage.

Interaction pattern

  • Let the user handle authentication manually.
  • Read visible page text before acting:
console.log("URL:", cdpPage.url());
console.log("Title:", await cdpPage.title());
console.log(await cdpPage.evaluate(() => document.body.innerText.slice(0, 4000)));
  • Use direct Playwright actions for buttons/radios when the page is simple:
await cdpPage.getByRole("button", { name: /^Continue$/i }).click();
await cdpPage.getByRole("button", { name: /^Edit$/i }).click();
await cdpPage.getByRole("radio", { name: /^No$/i }).click();
  • After each action:
await cdpPage.waitForLoadState("domcontentloaded");
await cdpPage.waitForTimeout(2500);

Long-form tax entry pattern

For large FreeTaxUSA forms, prefer direct DOM field assignment using name/id inside page.evaluate(...) rather than long chains of Playwright label locators.

This is faster and avoids js_repl timeouts on large forms.

Example pattern:

await cdpPage.evaluate(() => {
  const setValue = (name, value) => {
    const el = document.querySelector(`[name="${name}"]`);
    if (!el) return;
    el.value = value;
    el.dispatchEvent(new Event("input", { bubbles: true }));
    el.dispatchEvent(new Event("change", { bubbles: true }));
  };

  setValue("fed_tax-CURRENCY", "35860.56");
});

Then verify values immediately:

console.log(await cdpPage.evaluate(() => ({
  fed: document.querySelector('[name="fed_tax-CURRENCY"]')?.value
})));

If FreeTaxUSA reformats a money field unexpectedly, re-check the rendered value before saving.

W-2 document workflow

  • Read files from /home/sharno/Downloads/Tax 2025.
  • Use shell tools first:
fish -lc 'ls -la "/home/sharno/Downloads/Tax 2025"'
fish -lc 'pdftotext -layout "/path/to/w2.pdf" -'
fish -lc 'pdftoppm -png "/path/to/w2.pdf" /tmp/taxbot-w2/page'
  • Use rendered PNG pages to visually confirm ambiguous W-2 labels.
  • Treat clearly labeled fields as safe to enter.
  • If a label-to-tax-field mapping is not explicit, state the uncertainty before deciding.

Progress tracking

Keep progress.md current at all times.

Record:

  • current page / stop point
  • exact question waiting on the user
  • values observed on-screen
  • files used
  • any judgment calls or uncertainty

Update progress.md whenever:

  • the stop point changes
  • the user answers a question
  • a document is read and used
  • a meaningful tax form section is completed

Current resume model

  • Source of truth for resume state: progress.md
  • Browser to use for resume: Chrome launched with .chrome-debug-profile
  • Control surface: js_repl attached over CDP to http://127.0.0.1:9222
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment