- Changed references from './scratchpad' to '.scratchpad/' in graph.json and plan.md for consistency. - Expanded Phase 6 follow-up section in plan.md to clarify changes made to the pat detection logic: - Updated `find_cafe_sparkle()` to utilize multiple template scales for improved detection. - Modified `_pat_room` to allow polling for maximum clicks instead of breaking on the first miss. - Added mouse movement after each pat to prevent cursor occlusion of sparkles. - Verified that room entry and modal state checks function correctly, but end-to-end pat success remains untested due to lack of available interactions.
15 KiB
CLAUDE.md
This file provides guidance to Claude Code when working with code in this repository.
What this project is
This repository is a personal Blue Archive JP daily-automation project.
It controls the real Blue Archive PC/Steam/Proton client running on a Linux machine named nik-gpu. The development machine is a MacBook named nik-macbookair.
The automation backend is local desktop control:
xdotoolfor mouse/keyboard/window controlscrotfor screenshots- Python/OpenCV for image matching and color/template detection
- OCR later, when needed
- no Android emulator control
- no ADB
- no uiautomator2
The reference project is located at:
~/repo/baas-reference/
That repository contains the full Blue Archive Auto Script implementation. It should be treated as the behavioral reference for this project.
Core architecture decision
This project must be Python-first.
Do not implement new Blue Archive automation logic in ba_dailies.sh.
ba_dailies.sh is only a thin runtime/deployment launcher for convenience on nik-gpu.
All feature logic must live in Python.
The intended structure is:
ba-auto-daily/
├── ba_dailies.sh
├── ba_daily.py
├── ba_auto/
│ ├── __init__.py
│ ├── driver.py
│ ├── detector.py
│ ├── navigation.py
│ ├── config.py
│ ├── tasks/
│ │ ├── __init__.py
│ │ ├── mailbox.py
│ │ ├── cafe.py
│ │ ├── stamina.py
│ │ ├── group.py
│ │ └── ...
│ └── reference_notes/
│ └── mapping.md
├── assets/
├── screenshots/
├── scripts/
├── setup.sh
├── plan.md
└── CLAUDE.md
The exact layout can evolve, but the architectural rule should not change:
- Bash launches Python.
- Python owns automation logic.
- The reference repository guides feature behavior.
- Local driver primitives adapt that behavior to the PC/Steam/Proton setup.
Reference-first rule
Before implementing any new feature, inspect the matching reference implementation in:
~/repo/baas-reference/module/
Do not start by inventing a Bash click sequence.
For every feature, first identify:
- Which reference file implements it.
- Which class/function contains the main control flow.
- What the reference uses for state detection.
- What the reference uses for retries/failure handling.
- Which parts depend on Android/uiautomator2 and must be replaced.
- Which parts can be ported directly as Python control flow.
- Which local driver primitives are missing.
Then implement the feature in Python under:
ba_auto/tasks/
Reference repository usage
The reference repository is read-only.
Allowed
- read reference modules
- inspect control flow
- reuse architecture ideas
- reuse retry/state-machine structure
- reuse task decomposition ideas
- reuse constants/config concepts when appropriate
- write local notes describing how a reference module maps to this project
Not allowed
- edit files in
~/repo/baas-reference/ - reimplement a reference feature from scratch in Bash
- create a local solution that ignores the reference flow when a reference implementation already exists
Two-machine architecture
Development happens on: nik-macbookair
Runtime happens on: nik-gpu
The Blue Archive client and X display live on nik-gpu.
Assume: (DISPLAY=:0, GDM XAUTHORITY under /run/user/1000)
The game runs under Steam/Proton on the Linux desktop.
There is no reliable local execution path on macOS. Anything that interacts with the game must be deployed to nik-gpu.
Deployment model
During iteration, files are pushed from nik-macbookair to nik-gpu.
Typical paths on nik-gpu:
~/ba_dailies.sh
~/ba_daily.py
~/ba_auto/
~/ba_assets/
~/.venvs/ba-auto-daily/
The current setup may still contain older paths such as:
~/ba_scripts/detect_and_click.py
When refactoring, prefer consolidating Python code into ba_auto/.
setup.sh should bootstrap or update the runtime layout on nik-gpu.
For a fresh checkout on nik-gpu, run from the repo root:
./setup.sh
After initial setup, individual changes may be pushed with scp or rsync.
Runtime dependencies on nik-gpu
These are host-level dependencies. Confirm they exist before assuming a bug is in the project code.
Required now:
xdotoolscrotpython3
Required Python packages:
opencv-pythonoropencv-python-headlessnumpy
Expected venv:
~/.venvs/ba-auto-daily/bin/python3
Quick check:
ssh nik-gpu "which xdotool scrot && ~/.venvs/ba-auto-daily/bin/python3 -c 'import cv2, numpy; print(cv2.__version__)'"
Future dependency: OCR engine, likely Tesseract or PaddleOCR.
Do not introduce OCR casually. Add it only when implementing a feature that actually needs OCR.
Working conventions
Use .scratchpad/ (create if missing) in the project root for temporary/intermediate files — e.g. cropped calibration images from screenshots/cafe/sparkle/, one-off debug output. Never write to /tmp or /private/tmp.
Bash policy
ba_dailies.sh should be a thin launcher only.
Preferred shape:
#!/usr/bin/env bash
set -euo pipefail
VENV_PYTHON="${VENV_PYTHON:-$HOME/.venvs/ba-auto-daily/bin/python3}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec "$VENV_PYTHON" "$SCRIPT_DIR/ba_daily.py" "$@"
Acceptable Bash responsibilities:
- choose Python binary
- set environment variables
- call Python entry point
- provide compatibility with old command names
- fail early if the Python entry point is missing
Not acceptable in Bash:
- feature state machines
- long click sequences
- OpenCV logic
- OCR logic
- retry loops for game states
- feature-specific navigation
- shop/sweep/battle logic
- new
do_<feature>game automation functions
If an existing Bash function exists, migrate it to Python rather than extending it.
Python entry point
The intended Python CLI entry point is:
ba_daily.py
It should support commands such as:
./ba_dailies.sh
./ba_dailies.sh mailbox
./ba_dailies.sh cafe
./ba_dailies.sh stamina
./ba_dailies.sh group
No argument should run the default daily flow.
Example default flow:
- focus game
- mailbox
- cafe
- future daily tasks
The CLI should dispatch into task modules under ba_auto/tasks/.
Driver layer
Create and maintain a driver layer in:
ba_auto/driver.py
The driver layer should wrap the PC/Steam/Proton backend.
It should provide reusable primitives such as:
focus_game()
screenshot()
click(x, y)
double_click(x, y)
drag/swipe(start, end, duration)
keypress(key)
sleep/wait
wait_until(...)
color_at(...)
region_average_color(...)
template_match(...)
find_and_click_template(...)
Feature modules should not directly shell out to xdotool or scrot unless a driver primitive is missing and being added.
Prefer:
driver.click(x, y)
over:
subprocess.run(["xdotool", "click", ...])
This keeps the project close to the reference architecture while replacing only the backend-control layer.
Detector layer
Image matching and color matching should live in ba_auto/detector.py or in clearly named helper classes/functions.
The cafe sparkle-matching logic formerly in scripts/detect_and_click.py (now retired) has been migrated here as find_cafe_sparkle(), called in-process rather than as a per-click subprocess.
The detector should support:
- screenshot input
- template matching
- threshold tuning
- masked matching
- click-offset handling
- debug image output to
.scratchpad/
Avoid one Python cold start per click attempt where possible. Prefer long-running Python task logic that can take repeated screenshots and click repeatedly from one process.
Navigation layer
Common navigation should live in ba_auto/navigation.py.
Use this for shared flows such as:
- returning home
- opening main menu
- opening mailbox
- opening cafe
- opening shop
- opening lesson/schedule
- closing popups
- generic back/escape handling
Do not duplicate navigation click sequences inside every task if they can be shared.
Task modules
Each feature should have a task module: ba_auto/tasks/<feature>.py
Example:
ba_auto/tasks/mailbox.py
ba_auto/tasks/cafe.py
ba_auto/tasks/group.py
ba_auto/tasks/stamina.py
Each task module should expose a clear function such as:
run(driver, config)
or:
run_mailbox(driver, config)
Keep task files feature-focused.
Reference mapping notes
Maintain a mapping file at:
ba_auto/reference_notes/mapping.md
Before or during implementation of a feature, update the mapping.
Use this format:
| Local feature | Reference file | Reference functions/classes | Local file | Backend replacements | Status |
|---|---|---|---|---|---|
| Cafe | module/cafe.py or relevant file |
... |
ba_auto/tasks/cafe.py |
uiautomator2 tap -> xdotool click, screenshot -> scrot/OpenCV | In progress |
Working conventions
Use .scratchpad/ for temporary or intermediate files.
Examples:
- cropped calibration images
- debug screenshots
- annotated match results
- temporary investigation notes
Do not use /tmp or /private/tmp unless there is a strong reason.
screenshots/ contains human reference captures. They are useful for calibration and documentation, but they are not necessarily automated test fixtures.
assets/ contains local template images. These should be captured from the local game setup where possible.
Testing and checks
Because the game only runs on nik-gpu, local macOS testing is limited.
Before deploying, run static/syntax checks locally:
bash -n ba_dailies.sh
python3 -m py_compile ba_daily.py
python3 -m py_compile ba_auto/*.py
python3 -m py_compile ba_auto/tasks/*.py
On nik-gpu, run real integration tests against the live game.
Example:
ssh nik-gpu "~/ba_dailies.sh cafe"
When debugging image matching, write debug images to .scratchpad/.
Existing features
Current project state (mailbox and cafe both migrated; no Bash feature logic remains):
ba_dailies.shis a thin launcher that execsba_daily.pyba_daily.pydispatchesmailbox/cafe/default flow toba_auto/tasks/ba_auto/tasks/mailbox.pyandba_auto/tasks/cafe.pyare both real Python: they click withba_auto/driver.pyprimitives and verify state withdriver.color_at/ba_auto/navigation.py(ported frommodule/mail.pyandmodule/cafe_reward.py'srgb_in_range/co_detectpattern) before pressing further keys — no legacy bridge remainsba_auto/detector.pyhasfind_cafe_sparkle(), the sparkle template-match ported in-process from the now-deletedscripts/detect_and_click.pyscripts/ba_dailies_legacy.shandscripts/detect_and_click.pyhave been deleted — nothing references them anymoreba_auto/driver.pyprimitives (run_command,focus_game,click,keypress,screenshot,wait,color_at) are wired into both task modulesba_auto/navigation.pyhas two shared state probes used by both tasks:is_on_subscreen(any mailbox/cafe/shop-style panel vs. the home screen) andis_modal_open(a dimmed dialog overlay)- Live testing found both the mailbox-icon and cafe-icon fixed coordinates were flaky (missed the first click, worked on retry) and that neither task verified anything before proceeding, so a missed click cascaded into blind actions and could reach an unverified Escape press on the home screen — which triggers Blue Archive's own "exit the game?" confirmation. See
plan.mdPhases 5–6 for the full writeup. This is the concrete reason both tasks verify state before acting rather than trusting fixed coordinates blindly. - Not yet verified for cafe: rank-up popups mid-pat-loop, and whether camera zoom/pan can drift over a long unattended run (the reference project zooms out before detecting; ours does not, and testing didn't reproduce a failure from skipping it — see
plan.mdPhase 6 "Not verified" list)
Migration goal:
- preserve existing behavior
- move feature logic from Bash into Python
- keep
ba_dailies.shas launcher only - make detection logic reusable
- prepare for future features by copying the reference project's structure where appropriate
Known cafe gaps to verify during migration
When migrating cafe logic, verify these manually against the actual current behavior:
- whether student rotation popups are handled
- whether rank-up popups are handled
- whether the view is zoomed/centered before sparkle detection
- whether detection still works when text overlaps the student
- whether one Python process can handle repeated sparkle detection faster than repeated cold starts
- whether both cafe rooms are handled consistently
- whether cafe income claim is robust against popup timing
Do not assume the old Bash implementation handles these correctly.
Anti-patterns
Do not:
- add new
do_<feature>Bash functions - build a giant Bash automation script
- recreate reference logic as fixed coordinate Bash click chains
- skip reading the reference module before implementing a feature
- put OCR in Bash
- put OpenCV state machines in Bash
- make every feature shell out independently to
xdotool - duplicate common navigation in every task
- copy reference image assets blindly
- edit
~/repo/baas-reference/ - implement event-specific features before the generic reusable machinery exists
Feature implementation workflow
For every new feature:
- Read the relevant
~/repo/baas-reference/module/...file. - Summarize the upstream feature flow in notes or comments.
- Add/update the reference mapping table.
- Identify missing local driver primitives.
- Implement or improve those primitives in
ba_auto/driver.pyorba_auto/detector.py. - Implement the feature in
ba_auto/tasks/<feature>.py. - Add CLI dispatch in
ba_daily.py. - Keep
ba_dailies.shunchanged unless launcher behavior changes. - Run syntax checks.
- Deploy to
nik-gpu. - Test against the live game.
- Update
plan.mdstatus.
Priority when uncertain
When uncertain, prefer this order:
- Preserve existing working behavior.
- Follow the reference project's control flow.
- Keep logic in Python.
- Add reusable driver primitives instead of feature-specific hacks.
- Use local screenshots/assets only when backend differences require it.
- Avoid large rewrites that do not move the project closer to reference-driven Python architecture.
User preference
The user wants this project to be as close to the original Blue Archive Auto Script architecture as practical, without recreating logic that already exists.
The user specifically does not want Claude Code to keep converting feature work into Bash.
Respect that preference.