Files
SellPL a43a8e8231
CI / ci (push) Has been cancelled
CI / android (push) Has been cancelled
docs: record the measured storage cost and the new crate boundary
Updates the ADR log, architecture, limitations, perf table and README to match
what now exists, rather than what was expected.

**The perf number was wrong and is now honest.** The M0 figure of 0.279 MB
excluded SQLite entirely — the placeholder binary never referenced the crate, so
dead-code elimination dropped it. With the daemon actually opening a database it
is **1.364 MB**, of which bundled SQLite is ~1.1 MB. That is 1.1 MB of the 5 MB
budget spoken for, leaving 3.8 MB for D-Bus, X11 and a UI toolkit.

This is the first number that makes the section 5 budget feel like a budget
rather than a formality, and it turns ADR-4's bundled-vs-system-linked choice
into a real trade-off with a measured price on both sides.

- ADR-4 marked accepted and implemented, with that trade-off left open.
- ARCHITECTURE.md documents why `blocker-storage` is a sibling crate and not a
  submodule: the dependency direction is what keeps the zero-dependency purity
  proof automatic rather than a grep someone can route around.
- LIMITATIONS.md drops the stale "storage has no I/O" shortfall and records the
  bundled-vs-system question instead, plus the fact that `LockState` still always
  evaluates to Normal.
- README status table and layout updated.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-02 13:10:25 +00:00

124 lines
5.3 KiB
Markdown

# Blocker
A cross-platform app and website blocker for **Android, Windows and Linux**.
One shared Rust core owns every decision. Platform code observes the OS and
enforces what the core decides. That is what makes the same schedule behave
identically on all three, and it is testable rather than aspirational — the golden
decision tables in `tests/` are the parity contract, so a platform disagreeing
with the core fails the build instead of producing a bug report.
## Status
**M0 — repository bootstrap.** The core engine exists and is tested; nothing
enforces anything yet. No platform has a working build.
| Milestone | State |
|---|---|
| M0 repo bootstrap | in progress |
| M1 core engine | engine, lock timers and safety guarantees written and tested; SQLite persistence landed in `storage/` |
| M2-Linux | not started — daemon is a placeholder |
| M3-Android | not started |
| M4 conditions | not started |
| M5 websites | not started |
| M6 Strict Mode + friction | not started |
| M7 statistics, settings, releases | not started |
Milestone order is Linux-first rather than Android-first. See ADR-15.
## What it will do
- Schedules of apps, websites and keywords, with time windows, usage limits,
launch counts, Wi-Fi and location conditions
- Blocklist and allowlist modes, with strictest-wins when schedules overlap
- QuickBlock: block a chosen set for a chosen duration
- Strict Mode and a configurable friction ladder, so turning blocking off takes
deliberate effort in a weak moment while remaining always possible
- Local usage statistics
## What it will not do
This is a friction tool, not a wall. A user with root, ADB, safe mode, a factory
reset, or desktop admin rights can always remove it, and that is intended. Factory
reset, safe mode and OS recovery are never interfered with. The goal is to outlast
an impulse, not to defeat a determined decision.
There is also a hardcoded list of things that can never be blocked — the phone and
dialler, emergency calls and alerts, and on desktop the OS shell and the Settings
basics needed to keep the machine usable. There is no setting that changes it.
See [`docs/LIMITATIONS.md`](docs/LIMITATIONS.md) for all eight platform limits,
stated plainly, plus the shortfalls in the current code.
## Build and test
Requires a stable Rust toolchain. The toolchain is pinned in `rust-toolchain.toml`.
```sh
scripts/ci.sh # everything, stops at the first failure
scripts/ci.sh --keep-going # everything, summarises all failures
cargo test --workspace # tests only
cargo build --workspace # build only
scripts/size-check.sh # the 5 MB stripped daemon gate
```
Build artifacts go to `$HOME/.blocker-target`, outside the repository, so `target/`
never shows up in `git status` and can be deleted in one command. Override with
`CARGO_TARGET_DIR`.
Two checks skip on a machine without the relevant toolchain — Android without an
SDK, the secret scan without gitleaks. Both **skip loudly** and are listed in the
summary as not-passes. A skip is never reported as a pass.
## Layout
```
core/ the decision engine — pure, no OS calls, no dependencies
storage/ SQLite persistence (rusqlite, bundled), fail-open recovery
tests/ golden decision tables, and the engine purity check
desktop/daemon/ long-lived observer and enforcer (5 MB budget)
desktop/ui/ block-screen window, launched on demand
desktop/platform-linux/ ForegroundWatcher backends, enforcement
desktop/platform-windows/ same, Windows
android/ not started
docs/ architecture, ADRs, limitations, permissions, perf, testing
scripts/ ci.sh, size-check.sh
```
## Documentation
| Document | What it is for |
|---|---|
| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | The purity contract, `next_wakeup`, and why the engine has no dependencies |
| [`docs/DECISIONS.md`](docs/DECISIONS.md) | 17 ADRs, including the two still awaiting a decision |
| [`docs/LIMITATIONS.md`](docs/LIMITATIONS.md) | What the OS will not let us do, and what is not built yet |
| [`docs/PERMISSIONS.md`](docs/PERMISSIONS.md) | Every permission, and what degrades without it |
| [`docs/PERF.md`](docs/PERF.md) | Section 5 budgets, and the measurements taken so far |
| [`docs/TESTING.md`](docs/TESTING.md) | The golden-table contract and the manual checklists |
| [`CLAUDE.md`](CLAUDE.md) | The project specification. It governs. |
## Performance budgets
| Metric | Target |
|---|---|
| Idle CPU | ~0%, no wakeups without events |
| Idle RAM (daemon) | ≤ 15 MB RSS |
| Block latency | ≤ 150 ms |
| Daemon binary | ≤ 5 MB stripped |
| APK size | ≤ 10 MB |
Currently measured: **1.364 MB** stripped daemon, which includes bundled SQLite.
Of the 5 MB budget that leaves 3.8 MB for D-Bus, X11 and a UI toolkit — a real
margin rather than a comfortable one. Enforced in CI from the first commit by
`scripts/size-check.sh`.
## Licence
**Not yet chosen.** See ADR-17. Choosing a licence is the owner's decision, and it
interacts with the UI toolkit choice in ADR-6 (Slint is GPL-3.0 or commercial), so
it is not something to settle by accident.
## A note on origin
Blocker is a functional reimplementation of the behaviour of existing app blockers.
It reuses no third-party name, logo, icon, copy, or screenshot — only behaviour.