github.com/kuhyx/mtk-root
Unlike the app extractions, mtk_root could not travel alone: its four
libraries and three of its four test suites sat in scripts/lib/, one
directory up from the stages that source them. Taking only the directory
would have orphaned eight files here and left the new repo unable to
source anything, so all twelve moved in one filter-repo pass. The
mtk_root/ + lib/ sibling layout is preserved, so every
`source "$SCRIPT_DIR/../lib/..."` resolves with no call site edited.
Two things the new repo needed that the monorepo provided implicitly:
lib/tests/run_all.sh -- the copy here is shared with the non-mtk suite
and stays. Without a new one, shell-tests.yml's
glob over */lib/tests/run_all.sh would have
stopped covering these suites on a green build.
.shellcheckrc -- external-sources + source-path=SCRIPTDIR, which
is what lets shellcheck run with no severity
filter and still pass on the ../lib/ sources.
mtk_harness.sh stays here despite the name: test_common_datetime.sh
sources it. Removing it broke that suite outright, which running the
suite caught immediately. Its header now describes what it actually
serves; the misleading name is kept on purpose, since renaming would
churn its one consumer for nothing.
Verified: 84 tests pass in the new repo with shellcheck clean, 55 still
pass here, and check_shell_coverage.sh --all exits 0 with the four
mtk_root allowlist entries gone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
6.8 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.
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