I wanted the 1Point3Acres daily check-in and quiz to happen without another browser login or a morning reminder.
The finished app starts with Windows and runs once during the 9:00 AM hour. I can also click Run Now at any time. It uses my normal signed-in Chrome, completes the check-in, answers the daily multiple-choice question, submits it, and prints each important result in the app window.
Starting the app does not start the local model. The model loads only when the site has an unanswered quiz.
flowchart TB
A["Windows app starts the run"] --> B["Local bridge sends one command"]
B --> C["Extension opens signed-in Chrome"]
C --> D["Check in and verify the page"]
D --> E{"Quiz already complete?"}
E -->|"Yes"| H["Show the result in the app"]
E -->|"No"| F["Load the local model and choose an answer"]
F --> G["Select, submit once, and reload"]
G --> H
Figure 1. Chrome keeps the login. The local model joins only when a quiz needs an answer.
The real problem was the browser login
My first idea was to launch the site with Playwright. That gave me a controllable browser, but not the Chrome session I already used every day.
Browser automation usually creates a separate profile. My normal Chrome was signed in; the automated browser was not. Making two running processes share one Chrome profile can also cause profile-locking problems.
I did not need another profile. I needed a narrow way to ask my existing Chrome session to perform one known workflow.
The solution was a small unpacked Chrome extension. It runs inside my normal profile, so the site sees the login that is already there. The Python app never reads, copies, or stores browser cookies.
Four parts keep the workflow simple
Each part owns one kind of work:
- The Windows app shows the clock, next run, current status, Run Now button, and live logs.
- The scheduler records the last scheduled date so restarting the app during the same hour does not create a second run.
- The local bridge moves small commands and results between Python and Chrome through
127.0.0.1. - The Chrome extension opens the daily pages, interacts with visible controls, and checks the outcome.
The scheduled run and Run Now use the same function. A manual test therefore exercises the same workflow that will run the next morning.
What happens during one run
The extension asks the local bridge for work about twice a minute. When a run is waiting, it opens a background tab and follows this sequence:
- Open the daily check-in page.
- Stop if login, CAPTCHA, or another security check needs a person.
- Skip the check-in if the page already says
今日已签到. - Otherwise select a mood, fill the required note, submit once, and reload the page to verify success.
- Open the daily quiz and skip it if it is already complete.
- Otherwise extract the question and choices, request one local-model answer, select the matching option, submit once, and verify the completed state.
The extension reports each meaningful transition to the app. A scheduled failure therefore leaves a readable message instead of disappearing inside a background process.
The LLM makes one decision, not the whole plan
The local model does not browse, click, schedule, or decide whether a submission worked. Normal code owns those predictable steps.
The model receives only the quiz question and its numbered choices. It returns four fields:
choice index
choice text
confidence
short reason
Python checks that the index exists and that its text matches the selected choice. Chrome then requires that text to match exactly one visible answer button. These checks prevent a plausible-looking model response from selecting the wrong control.
The model is also lazy-loaded. Windows startup creates only the app, scheduler, and local bridge. If Chrome later finds an unanswered quiz, the bridge receives /solve; only then does Python import the LM Studio code and load local-agent-vlm on 127.0.0.1:1234.
If the quiz is already complete, the model never starts. If another LM Studio model is active, the app stops with a visible error instead of unloading someone else’s work.
A real page test found the missing field
The first full run reached the check-in page and clicked Submit, but the page did not change.
I first suspected that the site rejected a JavaScript-generated click. I switched the extension to Chrome DevTools mouse input, but the real page still refused the submission.
The screenshot showed the actual problem: the note box had a red border and a message saying it was required. The website had changed its form.
The fix was straightforward:
- focus the existing note box;
- insert a short generic note;
- read the value back;
- submit once;
- reload the page and check its new state.
The next live run completed both the check-in and quiz. It also changed the most important rule in the implementation:
A click is an attempt. The page’s new state is the result.
When a run fails, the extension now leaves the tab open and brings it to the front. The visible page usually explains more than a generic click error.
How I checked the result
The focused test file passed 24 tests. The full WebContentAgent suite passed 98 tests.
The tests cover saved page fixtures, quiz parsing, model-answer validation, schedule persistence, duplicate-run prevention, and lazy model loading. One test starts a fresh Python process, imports the desktop app, and verifies that no lmstudio module appears.
Unit tests could not prove that today’s website accepted the workflow, so I also ran the complete process in the real signed-in Chrome session. That test found the required note field and later confirmed both completed states.
The automation stays inside a narrow boundary
The assistant visits two known daily-task pages. It does not export credentials, bypass verification, or keep clicking when the result is uncertain. It submits each observed incomplete task once and checks the page afterward.
The app and Chrome extension must remain available during the 9:00 AM hour. LM Studio must be installed, but the model does not need to be running beforehand.
Website markup and rules can change. Account automation should only be used when it agrees with the site’s terms and the account owner’s intent.
What made it work
The useful design choice was separating responsibilities:
The app owns time and logs.
Chrome owns the login.
The extension owns page interaction.
The bridge moves small local messages.
The model chooses one answer.
Normal code verifies the result.
Reusing the signed-in Chrome profile removed the extra-login problem. Loading the model only for an unanswered quiz kept Windows startup light. Reloading the page after submission made the website—not the click—the source of truth.
Comments