SlopScore
00 crowd

capsules-harmonyos

Harmoniser: tiny apps you don't need to download.
Open repo on GitHubgithub.com/Akshaz7/capsules-harmonyos
C · ★ 1 · 0 forks · Apache-2.0 · paperwork by the Cap'mmostly ai (inferred)light human (inferred)works-on-my-machine (inferred)other
listed 1 hour ago by Akshaz7 · last checked 1 hour ago
The owner didn't write this. This repo never submitted itself. The Cap'm found it on a truffle trawl and wrote its paperwork from what GitHub already shows. Picked by hand by the Cap'm on 2026-10-10: Harmoniser: tiny apps you don't need to download.; its own README says "They were generated with Claude by seed". 1 stars; Apache-2.0 license. The owner did not submit this. Votes count; awards don't until the owner claims it.

I'm not calling your project slop! Geeze, it's a joke... Do you own this repo?

Log in with GitHub as Akshaz7. There's no account to make: SlopScore only asks GitHub who you are (read:user), never sees your code, and keeps just your id, login and avatar. Then you can:

  • Keep it, on your terms. Commit your own slopscore.md (spec) and press Refresh. Your paperwork replaces the Cap'm's, and you can submit it for Slop of the Day.
  • Take it down. One click on Remove. It stays gone; the trawl never brings it back.

Log in with GitHub

Can't log in as the owner? Request a takedown. No login needed, and a trawled listing comes down right away.

GitHub says
Harmoniser: tiny apps you don't need to download.
created
2026-10-03 · pushed 6 days ago · 366 commits · 3 contributors
release
v1.0-hackyeah · 2026-10-04
languages
C 86%Python 7%JavaScript 3%Shell 3%C++ 1%Makefile 0%
paperwork
licensereadme 42% health
dependencies
no dependency graph (no manifest, or disabled) · OSV.dev, checked 1 hour ago

Disclosures, inferred by the Cap'm

slopbucket
vibe-coded
category
other
ai_generated
mostly
human_touch
light
status
works-on-my-machine
language (detected)
ccmakecppjavascriptmakefilepythonshelltypescript
license (detected)
apache-2.0

The Cap'm's log

The Cap'm wrote this paperwork, not the owner. This repo never submitted itself to SlopScore. The Cap'm picked it by hand: Harmoniser: tiny apps you don't need to download.; its own README says "They were generated with Claude by seed". It carries the Apache-2.0 license. The disclosures above are his best guess from what GitHub shows.

Is this yours? Commit a real slopscore.md and press Refresh to replace this, or remove the listing in one click. There's no account to make: you log in with GitHub.

README — the repo's own words, folded up so the grading fits on one screen

Harmoniser

Tiny apps you don't need to download.

Describe a tiny app in one sentence and get it running natively on HarmonyOS. The app is plain JSON, checked against a strict schema, and can only use the device features you allow.

Built at HackYeah 2026. The project started from the HackYeah Hackathon Template, which gave the empty ArkTS project, AGENTS.md, AI_WORKFLOW.md and hackathon-resources/. Everything else was built during the hackathon; the commit history shows how. More docs: AI integration, compliance audit, demo script, pitch outline, third-party notes. Research notes (AI-assisted desk research, snapshots of their date, nothing run on a device): widget research, judges' feedback, HarmonyOS digest, skills vetting, research pack.

Related repositories

Repository What it is
Akshaz7/capsules-harmonyos (this one) The HarmonyOS app, plus the wrist-companion firmware in esp32-companion/
SimpsonLWH/harmoniser-web The web backend: the capsule marketplace API (harmoniser-web.vercel.app) and the device relay (harmoniser.keanuc.net)

Each app Harmoniser makes is a capsule: a small single-purpose app, such as a set of cooking timers, a squat counter or a medication checklist. It is described as JSON under the contract in SCHEMA.md. A capsule contains no code. Harmoniser reads it, rejects anything outside the schema, and draws it with native ArkUI components backed by real system services.

Status (2026-10-04, commit 260e558): English only: Harmoniser understands English requests; anything else gets "Harmoniser understands English for now. Try: 'timer 10 minutes'." without reaching any model. The app has four tabs: Create, Capsules, Marketplace and Settings. On Create you type or dictate a request (mic button) and tap Create; a build card shows each step while it is made. generateCapsule routes it: request cache, rules, built-in templates (plus a live marketplace search), then the on-device LLM (Cactus with LFM2-VL-450M) for simple requests, or the cloud first for requests that need logic. You choose where your requests go. Most requests are built on the phone (rules, templates, the on-device model). When one needs a cloud model, the app names the provider first, which may be outside the EU: Claude (Anthropic), with a live forecast or web search for live capsules. Switch to EU-only (turn off Allow non-EU providers) or On-device only at any time in Settings → AI mode; in On-device only, nothing leaves your phone. Every cloud provider gets a one-time notice before its first request, and only the request text (plus the forecast line for live capsules) is sent. On-device only mode never uses the cloud or the marketplace. "A task list and the weather for Kraków" (also starting with "make", "create" or "build") is built by a rule, with no model (PRs #14, #15). The gatekeeper sheet asks you to allow or deny each permission, and the capsule joins Your capsules with a badge showing how it was made. A capsule page has Change it…, Share, Add to home screen, its activity log and Remove capsule; capsules made by rules or on-device offer Make it smarter with . Schema v1 capsules (live state and computed values) and v1.2 device readings (motion counting, battery, weather) are built. A redesign is being switched on area by area (theme/Flags.ets); while it is on, the app is locked to light mode. Capsules that vibrate and the notification "Done" action are not built. See What's real and what's simulated.

Challenge themes

Theme How Harmoniser addresses it
Intelligent Experiences (lead) Plain-language requests become working mini-apps. An on-device rule parser handles common requests instantly. A small on-device LLM (LFM2-VL-450M on the Cactus engine) handles many simple ones without a network. Requests that need logic, such as a tennis scoreboard, a unit converter or a live bill split, are routed to a cloud LLM, which builds schema v1 capsules with live state and computed values. Every capsule, whatever produced it, is re-validated against the schema.
Human-Centric Technology: responsible tech Generated apps cannot run code. Each capsule must declare the permissions it needs; the validator rejects anything undeclared, and the gatekeeper blocks and logs anything the user denied. Every capsule shows whether it was made by rules, on-device, in the cloud or by someone else. Full control over where requests go: most requests are built on the phone; when one needs a cloud model, the app names the provider first (Claude, outside the EU), and On-device only keeps everything on the phone. Before a provider's first request, a notice names that provider, says whether it is outside the EU and that only the request text is sent, and lets you switch to On-device only. Consent is stored per provider. Requests for actions capsules can't do by design (sending SMS, calls, reading contacts, sending email, browsing websites, payments) are refused with a plain explanation, rather than turned into a weaker app. Imported capsules always go through the consent sheet, and nothing is saved until you run them. The on-device model runs locally, with Cactus's telemetry stubbed out so the engine makes no network calls. The cloud API key is never packed into the public .hap; a byte scan of the test-1 .hap found none (re-run it on the final release).

The third theme, Spatial Experiences, is not claimed.

Architecture

flowchart LR
    R["User request<br/>(English)"] --> C["Request cache<br/>200 recent results"]
    C -- "hit (re-validated)" --> V
    C -- "miss" --> P["Rule parser<br/>on-device, offline"]
    P -- "no rule" --> T["Template library<br/>108 templates + live<br/>marketplace search"]
    T -- "match" --> V
    T -- "no match; simple request" --> OD["On-device LLM<br/>Cactus + LFM2-VL-450M,<br/>slot-filling"]
    T -- "no match; needs logic<br/>(maths, scoring, converters…)" --> AI["Cloud LLM<br/>Claude (Anthropic), after<br/>the user OKs the notice;<br/>never in On-device only"]
    R -- "needs live info<br/>(weather, trip, look-up)" --> LV["Live capsules<br/>Claude + Open-Meteo forecast<br/>or web search; non-EU switch on"]
    LV -- "capsule JSON" --> V
    OD -- "rejected or not installed" --> AI
    P -- "capsule JSON" --> V["Validator<br/>strict SCHEMA.md v0, v1, v1.1, v1.2"]
    OD -- "capsule JSON" --> V
    AI -- "capsule JSON" --> V
    IM["Import<br/>file or QR code"] -.-> V
    MK["Marketplace<br/>install (or 108 shipped examples)"] -.-> V
    RN -.-> EX["Share<br/>system share panel"]
    V -- "invalid: errors fed back,<br/>1 retry" --> AI
    V -- "valid capsule" --> G["Gatekeeper<br/>per-permission allow/deny,<br/>block log"]
    G --> RN["Renderer + v1 interpreter<br/>ArkUI components"]
    RN --> CAL["Calendar Kit<br/>timer reminders"]
    RN --> N["Notifications<br/>timer finished"]
    RN --> DR["Device readings<br/>motion (accelerometer),<br/>battery, weather (Open-Meteo)"]
    RN --> VB["Vibration"]
    G --> W["Home-screen widget<br/>Form Kit, 1x2 / 2x2 / 2x4 / 4x4"]

    classDef built fill:#d8f5d0,stroke:#2e7d32,color:#1b1b1b
    classDef planned fill:#f2f2f2,stroke:#9e9e9e,stroke-dasharray:5 4,color:#555
    class C,P,T,OD,AI,V,G,RN,CAL,N,W,IM,MK,EX,DR,LV built
    class VB planned
Loading

Green boxes are built. The dashed grey box is planned and not yet in the code. Imported capsules go through the validator and the gatekeeper sheet like any other. The on-device and cloud models each get one corrective retry, and both outputs go through the validator. Permissions are checked twice. The validator rejects a capsule that uses a permission it doesn't declare. Then the gatekeeper's consent screen lets the user allow or deny each declared permission. Any component or action that needs a denied permission is drawn as blocked, refused when tapped, and logged.

Stage Source Notes
Types entry/src/main/ets/core/CapsuleTypes.ets The only definition of capsule types
Rule parser core/RuleParser.ets Timers, counters, dose schedules, goals, bill splits and checklists. pomodoro (25/5, or e.g. pomodoro 50/10) and any focus/work plus break/rest pair become timers that take turns: Start break stops focus, and Start focus stops the break. Goals (for progress units such as glasses, pages, steps or km, or an explicit goal) and bill splits come out as live v1 capsules, e.g. "{count} / 8 · {8 - count} to go". Requests that mention score, game, players, quiz, convert, calculate or streak are skipped and left for the cloud. A task list together with the weather (a task list and the weather for Kraków, weather in Warsaw and a to-do list) becomes one capsule with a checklist and a weather reading. A leading "make/create/build (me) a" is ignored before matching. Times of day in a request ("vitamins at 8am and 8pm", "at 19:30", up to 5) become daily time triggers that send a reminder; a bare "at 8" means 08:00 and says so. Returns null when no rule matches.
On-device LLM core/providers/CactusProvider.ets, cactus/ (HAR: prebuilt libcactus_engine.so for arm64-v8a, Node-API wrapper) The model only picks an intent and fills slots, and code builds the capsule. Slots must be grounded in the request: every word slot shares a word with it, and every number appears in it. Inference runs off the UI thread. If grounding catches a value copied from a prompt example, the retry drops that example. A scoreboard intent builds 2 or more named counters. The model weights are not in the .hap. It produces v0 capsules only.
Cloud LLM core/ModelProvider.ets (providers), core/CapsuleModel.ets (system prompt and the plan/capsule/check steps) Supports the Anthropic Messages API, Mistral (JSON output mode, OpenAI-compatible endpoint) or any OpenAI-compatible chat endpoint. Generation is two-step. The model first lists what the app must do (up to 8 points), then writes the capsule from that plan. The capsule is validated, with one retry that quotes the validator's exact errors. Then the model checks the capsule against every point and may revise it once. A revision is kept only if it also passes the validator, so a failed plan or check never loses a valid capsule. The plan step can refuse instead: {"error"} for requests that aren't an app (e.g. "asdf") and {"unsupported": [...]} for capabilities capsules don't have. These come back as ok: false with failure not-an-app or unsupported. Smart routing returns them as they are, with no on-device fallback, and sends requests that mention such capabilities to the cloud first. Output is capped at 8192 tokens (Claude used up 2048 on planning). The prompt teaches schema v0 and v1 with two v1 examples. The request is capped at 500 characters and treated only as a description, never as instructions.
Validator core/CapsuleValidator.ets Rejects unknown fields, component types, actions and permissions, dangling ids, and missing permissions. For v1 it also type-checks every expression, checks every name exists, rejects computed cycles, and enforces the limits (60 components, nesting depth 5, 30 state values, 30 computed values, 20 steps per button). {name} placeholders are allowed only in display templates; anywhere else they are rejected, so they never appear literally on screen.
Expressions and interpreter (v1) core/Expr.ets, core/CapsuleProgram.ets, core/V1Fixtures.ets Expressions are parsed by our own lexer and parser with static types and a step budget, never eval. The pure interpreter runs button steps all-or-nothing (applyActions), handles input binding (setInput) and {expr} templates. Tennis scoreboard and bill-split fixtures are included.
Pipeline core/CapsuleGenerator.ets, core/index.ets generateCapsule(request, { mode, allowNonEu }) first checks the request cache (model-made capsules per normalised request, re-validated; Make it smarter skips it), then runs the rules (a match returns at once), then the template library. needsLogic sends maths, scoring, converting, conditions, inputs, lists, quizzes and streaks to the cloud first. Everything else goes on-device, then to the cloud. Cloud builds use Claude (claude-sonnet-5-5 by default), after the user's OK. Requests that need live information (weather, opening hours, events, "look up", or a trip or packing list for a bundled city) skip the cache, templates, marketplace and on-device model and go to Claude when allowNonEu is on (see Live capsules). Mode on-device-only never calls the cloud. If the cloud hasn't been allowed yet, a logic request returns needsCloud so the app can ask. cloudOnly skips rules and on-device for Make it smarter, and still respects the mode and the non-EU setting. Only the system prompt and the request text are sent. Every capsule is validated again. Origins are rules, on-device, cloud-eu:mistral, cloud:anthropic, cloud:openai or (in the app) imported.
Renderer renderer/CapsuleRuntime.ets, renderer/CapsuleView.ets Draws the six v0 component types and the v1 ones (display, input, list, when, row), recursively. Rows of 1–2 children share the width equally; rows of 3 or more go two per line (2+1, 2+2). A v1 button press runs the interpreter, then the gatekeeper must allow every resulting v0 action before any state changes. enabledIf disables buttons. v1 state values are saved per capsule. Running timers have Pause/Resume and Stop. The schema actions pauseTimer, stopTimer and resetTimer (approved by Ash) also work in buttons, v1 steps and triggers. Pausing or stopping cancels the timer's calendar event.
Gatekeeper gatekeeper/Gatekeeper.ets, pages/ConsentView.ets, pages/LogView.ets A consent bottom sheet with an allow/deny switch per permission (including Other devices for the devices permission, schema sendToDevice), a block log (last 200 entries) and Remove. It also gates components nested inside when and row. Grants and the log persist in Preferences.
Main screen (Create tab) pages/Index.ets, pages/HomeHero.ets, pages/PromptBar.ets, pages/CreateText.ets, pages/CapsuleStore.ets, pages/CapsuleEntry.ets A "What do you need?" box with a typed "Try: …" placeholder, a mic for dictation, and Create; while it builds, a card shows each step (reading, templates, model…) with a skeleton capsule and Cancel, then the consent sheet. The AI status line sits under the input. The first request to each cloud provider shows a one-time notice naming it: "Use Mistral AI (EU)?" or "Use Claude (outside the EU)?". OK sends it, and On-device only switches mode. A refused request shows "Harmoniser can't do by design. Capsules can only use: …" without suggestion chips or a cloud notice. If a request can't be built, a failure card says why in one line, offers one alternative that builds on the phone ("Try instead") plus suggestion chips, and says where requests are built; when a cloud is set up but wasn't used, Try with cloud AI shows the provider notice first and retries only that request. The real error goes to hilog. A Recent row of live mini widgets and suggestion chips under the empty box are built but switched off (CREATE_RECENT, CREATE_SUGGESTIONS in theme/Flags.ets). The hidden requests demo tennis and demo bill split load the v1 fixtures.
Capsules tab and capsule page pages/Index.ets, pages/CapsuleFrame.ets, pages/ChangeCard.ets, widget/AddToHomeButton.ets Saved capsules with live state, an origin badge and Add to home screen; the Import icon is on this tab. An open capsule fills the page (back chevron; the tab bar stays and tapping a tab closes it). It has Change it… at the top, the capsule itself, then Share, Add to home screen and Activity log; a ⋯ menu in the title bar holds Share, Show as QR code, Publish/Remove from marketplace, Send to device and Remove capsule (which removes its permissions and calendar events). The route text reads "Simple enough for a widget" or "Widget shows the main values". Make it smarter with rebuilds a rules- or on-device-made capsule in the cloud (with the one-time notice if needed), shows the consent sheet again, and on Run replaces it. Back closes an open capsule.
Redesign (in progress) theme/ (Tokens, Flags, Breakpoint), components/ Switched on area by area in theme/Flags.ets: shell, Create, capsule frame, build progress, consent sheet, Capsules, Marketplace, Settings, the Gatekeeper log, Snap, Share/QR sheet and error cards are on; the app is locked to light mode while NEW_THEME is on. On screens at least 600 vp wide, an open capsule's extras move to a side panel and the Marketplace uses two columns (phones unchanged). Per-kind capsule layouts are on for the six that passed an emulator check (record list, versus, form, converter, goal ring, grouped checklist; FINISHED_PATTERNS); timer ring and quiz are built but stay on the classic layout until Ash approves them, and any other capsule uses the classic layout.
Tab bar pages/Index.ets (native Tabs, own floating bar), SettingsView, LogView, MarketplaceView in embedded mode A floating frosted pill with Create, Capsules, Marketplace and Settings; icons bounce on tap. Checked on the emulator: all four tabs respond to taps.
Settings pages/SettingsView.ets, pages/AppSettings.ets AI mode: Smart (default; its label names the provider it would really use: "On-device + Claude (outside the EU) when needed", or "On-device only: Claude is outside the EU" while non-EU providers are off) or On-device only ("Requests never leave the device"). Under Advanced, Allow non-EU providers is on by default (it lets live capsules use Claude); turning it off makes Smart mode EU-only. Motion: count shakes "While a capsule is open" (default) or anywhere in Harmoniser. All are saved in Preferences and enforced by core. The limits text ("Common apps are made on your phone. Unusual ones need cloud AI (Claude).") appears here too.
Timer adapter adapters/TimerAdapter.ets Adds each timer to the app's own local calendar as an event with a reminder
Notification adapter adapters/NotificationAdapter.ets Posts " is done" when a timer reaches zero (notificationManager). It is only active when reminders is allowed.
Widget router core/CapsuleRouter.ets Decides how a capsule appears on a widget. Every capsule fits except motion capsules and capsules with nothing a card can draw (only a battery/weather reading, or only an input); those show "Tap to open". Small capsules get the full card (up to 3 timers/counters/checklists, 3 text lines, 3 buttons; checklists of any length show the first unticked items and "+N more"; small v1 capsules up to 3 display lines, 3 buttons and 2 parts). Bigger ones get a condensed card: the top 3 display values and up to 3 buttons, with "Open for more", or "Open to edit values" when the capsule has inputs. v1 buttons run their steps on the widget itself (all-or-nothing, enabledIf respected, every action approved by the gatekeeper), and the app and widget share the same values.
Widget model core/WidgetModel.ets Pure logic: saved widget state, the card view, mapping taps to the capsule's declared actions, and choosing which capsule a new widget shows. Components whose permission isn't granted are hidden.
Widget widget/HarmoniserFormAbility.ets, widget/WidgetService.ets, widget/WidgetStore.ets, widget/pages/HarmoniserCard.ets Form Kit card in four sizes: 1x2 (compact: icon, name and one summary line such as a count, "3 / 8", "25:00" or "2 / 5 done"; a tap opens the app), 2x2 (default), 2x4 and 4x4 (wide layouts, up to 8 checklist items). A checklist card shows only unticked items, keeps "x / y done" in the header, and shows "All done" when everything is ticked. A new widget is blank ("Tap to choose a capsule") and opens a picker listing each capsule with its name, a preview and a colour; a widget shows a capsule only when the user picks one (a new capsule no longer fills a blank widget by itself), and a small coloured dot by its title keeps its colour. A capsule page offers Add to home screen (the only add-to-home control), and removing a capsule blanks its widget. It has live timer countdowns with start, counters with +, and tickable checklists. Taps are checked against the gatekeeper, and "Tap to open" opens that capsule in the app. The widget keeps its capsule across app updates, and its state (timers, counts, ticks) syncs both ways with the app.
Sharing sharing/ (CapsuleShare, ShareExport, ImportFlow, SharingBar) Export writes capsule-<id>.json and opens the system share panel (Share Kit). Import accepts a .json file (Document picker) or a QR code (Scan Kit). It enforces an 8 KB cap and validates before anything else. It replaces the sender's id and never carries over permission grants. An imported capsule shows the consent sheet with a "From someone else" badge, and is saved only when you run it.
Share target (receiving) entryability/EntryAbility.ets, pages/ShareLaunch.ets, module.json5 (ohos.want.action.sendData for text, links and images) Harmoniser appears in the system share panel. Shared text or a link becomes the request and goes through the normal create flow, with the cloud notice and consent sheet before anything is saved. Shared images go through the photo path (system OCR first, see Photo → capsule).
Shared text to capsule core/SharedText.ets, generateCapsuleFromSharedText Without a model: recipes become one timer per timed step, chats with amounts become a live v1 bill split, workouts become a checklist plus timers, and lists become a checklist. Other text goes to the cloud as a quoted request under the usual policy. Text over 2,000 characters is rejected.
Template library core/templates/ (TemplateLibrary, CoreTemplates, SlotFill, RequestCache), rawfile/templates/library.json, scripts/seed-capsules/ 108 English templates, each passing the validator, and every button pressed through the v1 interpreter. They were generated with Claude by seed.mjs and checked with the app's own validator. A keyword, tag and synonym matcher picks a template after the rules, and slots (numbers, names, items) are filled by rule. Unclear slots go to the on-device model, which keeps only grounded values. A match is made entirely on the phone: origin template, badge "Made on your phone · no internet". Matching was tuned on about 60 hand-written requests; generic words and nonsense fall through to the models. Some templates have fixed labels (e.g. card-game players).
Marketplace pages/MarketplaceView.ets (the Marketplace tab), adapters/MarketplaceClient.ets Search, category chips and cards with Install. Install only downloads the JSON into the normal import flow (8 KB cap, validator, fresh id), and the consent sheet says "From the marketplace". Capsule pages offer Publish to marketplace when marketplace.baseUrl is set, with a warning that the name and how it works become public (no values, request or permissions), and Remove from marketplace. It uses a separate anonymous owner token. The backend is Lewis's harmoniser-web. With no URL, no network or a 503, the screen shows the shipped examples with a calm note. Nine shipped templates are marked listed: false and are kept out of the marketplace listing (curation).

The timer adapter uses Calendar Kit rather than reminderAgentManager. On phones, agent reminders need an AppGallery Connect capability grant, and without it publishReminder fails with error 1700002.

Timers are saved as system Calendar events. On the emulator the calendar alert doesn't fire; on a real device, background alerts need the agent reminder capability (AppGallery approval). We'll test calendar alerts on the Pura 70.

On-device AI: the Cactus port

Cactus had no HarmonyOS build, so we ported it.

  • Cross-compile: Cactus v2.2.2 (commit 2cfcdb8) is built for arm64-v8a with the OHOS NDK toolchain, using 3 small patches (cactus/cactus-ohos.patch). A no-op telemetry stub replaces the libcurl-based telemetry, so the engine makes no network calls. Two emplace_back aggregate initialisations are rewritten for the SDK's Clang 15. The result is libcactus_engine.so: 3.5 MB, 2.5 MB stripped, with 182 exported cactus_* symbols. It needs only OHOS libc and libc++_shared.so.
  • Node-API wrapper: our own C++ (cactus/src/main/cpp/napi_init.cpp) exposes initModel, complete and freeModel to ArkTS as Promises. They run on the libuv worker pool, so inference never blocks the UI thread. The HAR adds about 3.8 MB to the .hap: the engine, libcactus_napi.so (75 KB) and libc++_shared.so (1.2 MB).
  • Model: LFM2-VL-450M in Cactus's 4-bit cq4 format, 383 MB zipped and about 480 MB on the device. It is pushed into the app's sandbox with hdc file send -b and never packed into the .hap.
  • Slot-filling instead of free generation: given the full schema, the 450M model copied prompt examples and printed placeholders. Only 3 of 10 capsules were correct, and gemma-4-E2B at 2-bit got 0/10. So the model now only picks an intent and fills grounded slots, and code builds the capsule.

Measured on the HarmonyOS emulator. It runs on the host's Apple M4 Pro cores, so a phone will be slower; we haven't measured one.

Metric Result
Model load (cactus_init) 256 ms in the spike, 310.7 ms in the app
Time to first token 267–386 ms for a 29-token prompt. A 350–600-token prompt raised it to 1.2–1.6 s, which is one reason the slot-filling prompt is kept short.
Decode / prefill 92–114 tokens/s / 75–108 tokens/s
Memory 335–388 MB RSS reported by Cactus; 245 MB process PSS, because the weights are memory-mapped
Capsule accuracy 9/15 correct on the eval requests with the app's provider code; 11/15 with the rule parser in front

AI evaluation

scripts/eval-providers.mjs runs requests through each configured cloud provider, using the app's own prompt, validator and v1 interpreter. It checks both that the capsule is valid and that it does the right thing. There are three sets:

  • Tuning (15 requests): used to develop the prompt.
  • Held-out (5): written after the first prompt was locked, and never used for tuning.
  • Refusal (2): nonsense, and a request for capabilities capsules don't have, which should be refused.

Current pipeline (two-step plan, capsule, self-check, with refusals). These are the final numbers, with network failures re-run:

Set Mistral ministral-14b-latest (EU; no longer used in the app) Anthropic claude-sonnet-5-5
Tuning (15) 14/15 14/15
Held-out (5) 4/5 5/5
Refusal (2) 2/2 2/2

The prompt has changed since the held-out set was written: the two-step pipeline was added, and the plan prompt was adjusted after the eval caught Claude running out of output tokens and plans over-building simple apps. The held-out requests still weren't used to tune it, but read 4/5 and 5/5 with that in mind.

Hard logic requests (tennis scoreboard, darts for 3 players, quiz on capitals, reading streak), measured on the earlier single-step prompt:

Mistral ministral-14b-latest (EU; no longer used in the app) Anthropic claude-sonnet-5-5
Hard logic (4) 2/4 4/4

Ministral built the tennis scoreboard and darts correctly. The quiz and the habit streak failed both attempts: the model used step types and functions the schema doesn't have. The validator rejected both, so no wrong capsule reached the user, but those requests fail. Claude was correct on all four, and faster on the tennis scoreboard (12 s against 22 s). This set hasn't been re-run on the current pipeline.

Mistral is no longer used in the app (its code is switched off); these numbers are kept as a record. The app's cloud model is Claude. These are small samples, and the numbers are indicative, not a benchmark.

Wrist companion (stretch goal)

esp32-companion/ is firmware for a Waveshare ESP32-S3-Touch-AMOLED-1.8 that shows one capsule on the wrist: a timer countdown, or a counter with a big + button. It has its own HTTP/JSON API, a Python mock server with the same API, and host-side tests: 1,646 C checks, 19 Python tests on the mock, 37 on the fake relay, and 72 API checks that pass against both the mock and the real board. The screen, touch and timer beep are confirmed on hardware by the owner. Rep counting with the accelerometer is experimental and off by default.

The app side is built but not yet tested against the live relay. adapters/DeviceRelay.ets and adapters/InstallToken.ets implement the relay contract (pairing codes, send, state, a random install token in the X-Harmoniser-Token header that is never logged) and are unit-tested. A Show on another device panel on timer and counter capsules can pair a device (scan its QR code or type its three words) and send the capsule. Sending needs the capsule's devices permission ("Other devices"): the first send asks once (Allow and send / Don't allow), and the gatekeeper logs every send and refusal. A capsule button can also send with the sendToDevice action. The panel is hidden unless config.local.json sets devices.relayBaseUrl, or the dev flag devices.simulate, which shows a labelled in-app simulation, so phones never show a fake device. It was checked on the emulator only with that simulation (pair by phrase, consent, logged send). After a send the panel shows the device's live state (e.g. "On Browser: Tea timer 2:54", counting down), also checked with the simulation. It has not been tested against the mock relay or the live relay. The phone sends capsules through a small cloud relay that the device pairs with by QR code. The relay is live (since 2026-10-03, about 21:50) in the backend repository harmoniser-web at https://harmoniser.keanuc.net: routes /api/devices/**, a /pair page and a /device page that turns any browser tab into a second device. The board side is verified against it: the firmware's relay client (registration, pairing by QR code or three-word phrase, receiving capsules and actions, state reports) passed test_relay.sh 106 of 106 against production and then polled it over HTTPS for 30 minutes with no reboot, no gap and no failed request. The app side is not: as far as this README knows, nobody has yet run the app against the live relay, so the phone-to-device path end to end is unproven. The board is not a Huawei device and does not run HarmonyOS; it stands in for a watch. All of the companion's code is in this repository under esp32-companion/; only its Wi-Fi credentials and build output are kept out. The app doesn't depend on it. Details, its own test status and its third-party list are in esp32-companion/README.md; its AI-assisted work is logged in esp32-companion/AI_WORKFLOW.md. Wi-Fi credentials stay in a git-ignored main/secrets.h.

Setup, build, install, launch

Read the rest on GitHub

Scan report · 2026-10-10
  • ✓ Prohibited terms or links
  • ✓ Repository eligibility
  • ✓ slopscore.md paperwork
  • ✓ Content policy
  • ✓ Risk review

From the balcony · 0 of 4 clapped

    Cap'm Slop, Princess, Crusoe and Schnitzel read it and passed. Their reasons are on the balcony, with every other verdict.

    Critics are accounts on this site with no GitHub account behind them. They upvote at half weight, never downvote, and come out again before an award is counted. Who they are.

    0 comments

    log in to comment.

    report this listing — log in to report