Autonomous AI agent to daily solve Duolingo lessons using computer-use tools. Provides 7 primitive browser-control tools for the LLM to control a Playwright browser and complete Duolingo exercises without hardcoded logic.
LazyLingo defines 18 tools for Duolingo automation via Playwright. Most tools have descriptions (good), but schemas are incomplete: many lack proper type constraints, enums, and parameter descriptions. Tool names are action-oriented (scroll, screenshot, click_by_id) but several are overly specific to Duolingo's UI (click_word_tile, open_chest) rather than generalizable patterns. Error handling is minimal, tools return strings without structured error classification or recovery guidance. No tool annotations (readOnlyHint/destructiveHint) despite clear risk levels. Output schemas are undocumented; LLMs cannot predict return structure. Composition is reasonable (tools chain via page_state IDs), but parameter validation rules are not stated in descriptions.
Place ALL word tiles in order AND submit in ONE call. Use for BOTH "Scrivi" (translate) and "Riempi" (fill-blank) exercises. For fill-blank: pass ALL available tiles in the correct grammatical order. For translate: pass only the tiles needed for the correct translation.
Remove all placed tiles and return them to the bank. Recovery tool.
Left-click at pixel coordinates (x, y).
Click element by ID from the last page_state(). Use for ALL button/UI clicks.
Click the first visible element whose text contains this string.
DEPRECATED. Only use as a last resort if answer_tile_exercise fails.
Call ONLY once back on /learn after completing the full lesson.
No tool annotations (readOnlyHint/destructiveHint/idempotentHint) despite clear risk levels. Tools marked READ_ONLY vs WRITE in metadata but not in schema.
Output schemas undocumented. Tools return strings (e.g. 'started', 'found', base64 PNG) but LLMs cannot predict structure or downstream field availability.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 50 | 2026-07-28+ | v2 |
Open a treasure chest reward and handle the full animation sequence.
Return the current URL and all visible buttons/inputs with integer IDs, text, and (x,y) coordinates. Each element has an [ID] usable with click_by_id(). Call first on any new screen.
Send a keyboard key: "Enter", "Space", "1"/"2"/"3", "Escape".
Capture the full browser screen and return it as a base64-encoded PNG. Call this whenever you need to see the visual state: word tiles, images, question layouts, or anything not covered by page_state().
Scroll the page. direction: 'down' | 'up'
Skip a listening exercise (clicks the accessibility skip link).
Skip a microphone/speaking exercise.
Start the next available (non-completed) lesson on the /learn page. Use this INSTEAD of manually clicking lesson bubbles with click(x, y). It handles all cases automatically: 1. If Duolingo already shows an INIZIA/START popup next to a lesson, clicks it. 2. Otherwise scans all skill-path buttons, skips completed ones (checkmark icon), skips locked ones (greyed/low-opacity), and clicks the first available node. Returns "started" on success, or an error description if nothing was found.
Click CONTROLLA/CHECK. Use ONLY after type_text() — NOT after tiles.
Clear the active text input and type this text. Use ONLY when there is a real text <input> box visible (no tile bank present).
Check if text appears in the DOM. Use after submitting to confirm the UI updated (e.g. verify("CONTINUA")). Returns 'found'/'not found'.
Error handling returns unstructured strings without recovery guidance. No distinction between retryable, user-fixable, or fatal errors. E.g. 'nothing was found' gives LLM no next step.
Parameter descriptions lack validation rules. E.g. 'direction' in scroll accepts 'down'|'up' but description does not state enum constraint; 'pixels' has no min/max bounds.
click_word_tile marked DEPRECATED but still exposed. Deprecated tools should be removed or wrapped with clear migration guidance to answer_tile_exercise.