github.com/kuhyx/android-guardian, cloned to ~/android-guardian
periodic_background/utils/ held two unrelated things: the Magisk module
and heavy_job_lock.sh. Only the module was a unit, so the directory is
split rather than moved.
heavy_job_lock.sh goes to digital_wellbeing/, NOT to ~/utils. Measured
rather than assumed: of its consumers only install_pacman_wrapper.sh
reads the repo copy, while pacman_wrapper.sh, makepkg_capped.sh and
meta/scripts/run_with_heavy_lock.sh all read the installed
/usr/local/bin copy. A library belongs with whoever installs it, and
exporting it would have added a cross-repo edge for one caller.
Fixed a bug that predates the extraction: update_android_hosts.sh set
GUARDIAN_MODULE_DIR to "$SCRIPT_DIR/android_guardian", a sibling that
never existed at that path -- packaging could not have worked from this
checkout at all. It now reads ${ANDROID_GUARDIAN_DIR:-~/android-guardian}
and require_guardian_module() gates build_module(), the single funnel
every packaging path goes through, so a missing checkout names the clone
command instead of failing inside a cp four helpers deep.
Verified both directions: with no checkout the guard fires with
instructions; with one, the module builds -- 182331 blocked domains, a
1.1 MB zip. The subsequent adb push failed on device-side storage, which
this commit does not touch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
7.0 KiB
testsAndMisc
Mixed-language monorepo: Python packages, Bash automation, and several apps.
Repository Layout
| Path | Description |
|---|---|
python_pkg/ |
Python packages — every .py in the repo belongs here or in an allowlisted dir |
meta/ |
Repo-wide tooling: pyproject.toml, requirements.txt, run.sh, lint_python.sh, .fvmrc, scripts/ |
linux_configuration/ |
Arch setup, i3 config, system maintenance, and the tracked git hooks |
phone_focus_mode/ |
GPS-based Android focus enforcer (Bash, ADB, Magisk) |
billsplit/ |
Receipt bill-splitting Flutter app (Dart) |
bottles/ |
Small standalone project |
docs/ |
Reference docs; docs/superpowers/ holds AI workflow artifacts |
third_party/ |
Vendored upstream skills/agents |
Root pyproject.toml, requirements.txt, run.sh, lint_python.sh and
.fvmrc are symlinks into meta/ — edit the files in meta/, not the
symlinks.
Extracted to their own repos: steam-backlog-enforcer,
screen-locker,
diet-guard,
wake-alarm,
dufs-cloud,
build-your-x (lives at ~/build_your_x),
reverse-survivors,
kcd2-dice-solver (lives at ~/kcd2-dice-solver),
focus-owner,
mtk-root,
system-maintenance (lives at
~/system-maintenance),
android-guardian (lives at
~/android-guardian).
Archived work: testsAndMisc-archive.
Adding a Flutter app
billsplit/ is currently the only one, and the only place binaries are
committed. To add another, repeat both halves or the icons fail silently:
- Add the icon globs to
.binary-allowlist. - Add matching
!overrides at the end of.gitignore— an ignored file fails silently ongit addrather than erroring.
Icons come from the shared generator in python_pkg/app_icons/. Dart style is
gated by CI only (.github/workflows/billsplit-ci.yml), not by a local hook.
Keep app dirs free of Python: the check-python-location hook requires every
.py to sit under python_pkg/ (or linux_configuration/, phone_focus_mode/,
meta/scripts/). billsplit/'s coverage gate therefore lives at
python_pkg/billsplit_coverage/.
Git Workflow
Work directly on main; commit and push straight there.
core.hooksPath points at the tracked linux_configuration/.githooks/, so
hooks travel with the repo. .git/hooks/ is unused — never run
pre-commit install.
- pre-commit: shfmt + shellcheck + jscpd (fails above 2% duplication),
then
pre-commit run --hook-stage pre-commit. - pre-push:
pre-commit run --hook-stage pre-push—prettierandci-mirror.ci-mirrorruns a clean-venv install,pre-commit runover all files, and pytest for changed packages.
Bootstrap a clone or new machine:
./meta/scripts/install_hooks.sh # wire hooks + install missing tools
./meta/scripts/install_hooks.sh --check # verify only; exit 1 if incomplete
Both hooks fail closed: every external binary is verified each run and
auto-installed via pacman where possible. A missing tool aborts the commit —
it never means "skip the check". Extend REQUIRED_TOOLS in
linux_configuration/.githooks/lib/common.sh when adding a language: system
hook. common.sh also warns when local shellcheck/prettier/shfmt/zsh drift
from the versions pinned in .github/workflows/pre-commit.yml.
Development Workflow
- Do NOT run tests unless instructed, or before committing.
- If tests fail on the same issue twice in a row, STOP and ask.
- Confirm a change works by running the program and inspecting output — not by running tests. Then ask the user to confirm the behaviour.
- Fix coverage gaps; do not ignore them.
AI evidence (enforced)
Every commit touching code needs an evidence artifact:
- Copy
docs/superpowers/evidence/template.json→docs/superpowers/evidence/<task-slug>-<date>.json. - Fill in intent, scope, changes, verification, risks, rollback.
- Stage it with the code.
validate_evidence.py rejects empty verification[] and the phrases
"should work", "probably fine", "seems right".
Staging ≥4 code files additionally requires a fresh
docs/superpowers/contracts/*.json in the same commit.
Deletions in docs/superpowers/sessions/* abort the commit (append-only).
Code Conventions
Anything already enforced by a hook is omitted here — run
pre-commit run --all-files and read .pre-commit-config.yaml for the
complete list. What follows is what a linter cannot check.
Python
from __future__ import annotationsfor forward references.- Prefix private functions/modules with
_(_smart_plug.py,_process_game_event). - Mock external calls in tests; never hit real APIs or the filesystem.
- For branch coverage: prefer an explicit
while Truewithtry/except StopIterationoverforwhen iterator exhaustion needs covering, and mock threads/subprocesses to keep tests fast.
Full linting/coverage configuration lives in meta/pyproject.toml
(ruff select = ["ALL"], mypy, pylint enable = "all", coverage
fail_under = 100 with branch coverage). Note the mypy hook disables a
number of error codes, so it is weaker than the strict = true in the config.
Shell
set -euo pipefailin every script.- Prefer
/proc,/sysand bash builtins over$(...)in hot paths — see theefficient-polling-scriptsskill. Theno-polling-antipatternshook only inspects functions named*_loop,*_daemonorpoll*, so a fork storm elsewhere passes clean. - Use
jq/yqfor JSON/YAML, notgrep/awk.
Key Files
meta/pyproject.toml— all Python tool configs.pre-commit-config.yaml— hook definitionslinux_configuration/.githooks/— the tracked git hooksmeta/requirements.txt— runtime + dev dependenciesdocs/superpowers/evidence/template.json— evidence template.github/workflows/—pre-commit,python-tests,shell-tests, and one CI workflow per app