Skip to content

Monkey 1.2: daily-budget evolution stages, Telegram remote control, signed auto-updates, screensaver fixes, grace-period cap - #5

Merged
fcspcs merged 5 commits into
mainfrom
claude/monkey-image-budget-levels-1g7mx9
Aug 9, 2026
Merged

Monkey 1.2: daily-budget evolution stages, Telegram remote control, signed auto-updates, screensaver fixes, grace-period cap#5
fcspcs merged 5 commits into
mainfrom
claude/monkey-image-budget-levels-1g7mx9

Conversation

@fcspcs

@fcspcs fcspcs commented Aug 9, 2026

Copy link
Copy Markdown
Owner

What's in here

Monkey evolution now follows the daily allowance. The stage picture was tied to fifths of the balance cap, so days of genuine saving often changed nothing on screen. Now each stage is one saved daily allowance: one day's grant is the small monkey, two saved allowances the second picture, up to stage 5 at five. Manual top-ups still reset the savings — only time from daily grants grows the monkey.

Optional Telegram remote control — works even while the PC is off. Two bots, strictly separated: Monkey's bot answers /status; the friend's bot can also /add, /pause and /resume from anywhere, without the master password ever leaving the PC. The relay is a single Cloudflare Worker (cloud/worker.js) each user deploys into their own free account — the repository ships no credentials. The worker projects the balance exactly while the PC is off (daily accrual is deterministic) and queues the friend's commands until the next start. Every path is authenticated: sync secret (DPAPI-encrypted at rest) for the PC, per-bot webhook secrets for Telegram, one-time pairing codes (hashed, 5 tries, 10 minutes) for chats. Remote commands are limited to add/pause/resume, re-validated by the service, and deduplicated against replays. New General/Telegram tab switch in the control panel.

Self-update from signed releases — no password, no reinstall. The service checks the latest GitHub release every six hours and installs newer versions by itself. Safe without a password because it only moves one way: each release carries an update.json manifest signed with the project's ECDSA P-256 key (public half baked into the service), so not even a network-controlling admin can feed the guard a doctored build; downgrades are rejected. The installer gains a silent update mode that swaps binaries and restarts the service; balance, password and settings survive untouched, and a running agent restarts itself once it sees the new service version. Dormant until a maintainer runs tools/new-update-key.ps1, commits the public key and stores the private half as the UPDATE_SIGNING_KEY Actions secret — the release workflow then signs every release automatically.

Screensaver detection fixed. The clock kept running for manually launched screensavers (a .scr started via shortcut/hotkey never sets the system flag) and when modern Windows simply switches the display off instead of running a saver. Detection now has three layers (official query, Screen-saver desktop probe, foreground .scr process) plus display-off tracking via GUID_CONSOLE_DISPLAY_STATE power notifications, all under the existing pause setting.

Empty-balance grace periods capped. The 120-second emergency window after signing in with an empty balance could be milked by signing in repeatedly — and the ordinary 90-second grace had the same hole via lock/unlock. Every grace granted while the balance is empty is now counted (persisted immediately, so a hard reboot doesn't forget): three come in full length, from the fourth on it's 10 seconds to sign-out. Any top-up resets the counter, so the emergency window keeps serving its real purpose.

Version bumped to 1.2.0.

Notes for review

  • Built in a Linux container without a Windows/.NET toolchain, so this branch has not been compiled locally — the CI build is the compile check.
  • Auto-update and release signing stay dormant until the update key exists (see README "Automatic updates").
  • Worth a manual pass after the build: Telegram setup flow end-to-end, one silent update cycle on a test machine, hotkey-launched screensaver pausing the clock, and the 4th sign-in with an empty balance ejecting after 10 seconds.

🤖 Generated with Claude Code

https://claude.ai/code/session_012XNyzACDtEMNqWXFdeeHSE


Generated by Claude Code

claude added 5 commits August 9, 2026 07:59
Two bots, strictly separated: Monkey's bot can only ask /status, the
friend's bot can also top up time, pause and resume - from anywhere,
without the master password ever leaving the PC. The relay is a single
Cloudflare Worker (cloud/worker.js) each user deploys into their own
free account; the repository ships no credentials.

The service reports its state every 30 seconds (and on every change and
at shutdown) and picks up queued commands. Because the daily top-up is
fully predictable, the worker answers exactly even while the PC is off,
and the friend's commands wait in a queue until the next start.

Security: the PC authenticates to the worker with a generated sync
secret (stored DPAPI-encrypted on the PC, as a secret on the worker);
Telegram webhooks carry per-bot secret tokens; chats must pair once via
a one-time code (hashed at rest, 5 tries, 10 minutes). Bot tokens pass
through the PC once during setup and are kept only by the worker.
Remote commands are limited to add/pause/resume, are re-validated by
the service and deduplicated against replays. The control panel gains a
General/Telegram tab switch; everything stays off until configured.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XNyzACDtEMNqWXFdeeHSE
The service checks the project's latest release every six hours and
installs a newer version by itself. No master password is involved,
because the mechanism can only move one way: every release carries an
update.json manifest signed with the project's ECDSA P-256 update key,
and the matching public key is baked into the installed service. No
valid signature, no update - so not even someone who controls the
network (or plants a root certificate) can feed the guard a doctored
'new version', which would otherwise be the cheapest bypass of the
whole tool. Only strictly newer versions are accepted (no downgrade
replays), the installer is staged in the SYSTEM-only data folder and
checked against the signed hash before it runs.

The new installer gains a silent 'update' mode that just swaps the
program files: watchdog paused, service stopped, old binaries renamed
aside, new ones extracted, service restarted. Balance, password and
settings stay untouched. A still-running agent keeps working from the
renamed file and restarts itself once it sees the new service version
(guarded against restart loops by comparing with the file on disk).

Auto-update ships enabled and can be turned off in the settings.
Dormant until a maintainer generates a key (tools/new-update-key.ps1),
commits the public half and stores the private half as the GitHub
Actions secret UPDATE_SIGNING_KEY - the release workflow then signs
every release automatically. The repository itself stays free of any
secrets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XNyzACDtEMNqWXFdeeHSE
The clock only paused when Windows itself had started the screensaver -
SPI_GETSCREENSAVERRUNNING is the sole signal the agent checked. Two
real-world cases slipped through: a screensaver launched by hand
(shortcut or hotkey running a .scr directly) never sets that flag, and
modern Windows often runs no screensaver at all but simply switches the
display off. In both cases the timer kept eating the balance.

Detection now has three layers in the agent: the official query, the
'Screen-saver' desktop Windows creates for system-started savers (its
mere existence - even access-denied - means one is running), and the
foreground window's process image ending in .scr for manual launches.
On top of that the agent subscribes to GUID_CONSOLE_DISPLAY_STATE power
notifications and reports 'display off' in its heartbeat; the service
treats that like a running screensaver under the same setting, and the
agent syncs immediately on the on/off edge instead of waiting for the
next two-second tick.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XNyzACDtEMNqWXFdeeHSE
The emergency window after signing in with an empty balance (120 s by
default) could be milked: sign out, sign back in, collect another two
minutes, repeat forever. The ordinary 90-second grace had the same hole
via lock/unlock, since leaving the session resets the running grace and
returning started a fresh one.

The service now counts every grace it grants while the balance is
empty - persisted immediately, so a hard reboot doesn't forget it. The
first three come in full length; from the fourth on there are only ten
seconds before sign-out, enough to see it coming and nothing more. As
soon as the balance is positive again (daily allowance, master
password, or a friend's Telegram top-up) the counter drops back to
zero and the emergency window works normally again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XNyzACDtEMNqWXFdeeHSE
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XNyzACDtEMNqWXFdeeHSE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants