Skip to content

Releases: mmr710/nightmux

nightmux 1.3.0

Choose a tag to compare

@mmr710 mmr710 released this 08 Oct 13:13
48df028

Added

  • !qa HH:MM [url]|now|off (nightly browser QA pass that files issues), !leaderboard [post] (opt-in counts on a public board), a GitHub Pages site (landing, live office demo, leaderboard), a Docker image on ghcr.io, a cloud-init for fresh VPSes, an installer that works with curl | sh, and a new README top.

  • !saved counts what nightmux did for you (context not re-read, night turns, limit resumes, green checks); !wrapped [days] draws a shareable card with a tweet button; the night reel is signed and gets one too; !public on|expose|off serves a read-only office (states only) at /public/.

  • !race [claude,codex] <task>: several agents do the same task, each in its own git worktree; one card compares changes and !goal results, a 🏆 tap stages the winner. Voice notes are transcribed with your own transcribe_cmd (e.g. whisper.cpp) and shown back as 🎙.

  • Built-in agents: !cursor (Cursor CLI), !amp, !goose, !qwen (Qwen Code) — start, resume, !update and their own look in the office.

  • Dashboard-only mode: with no bot token nightmux runs on the dashboard and its chat view alone — --setup offers it at the token prompt, + project numbers topics locally, --doctor accepts it.

  • nightmux --demo [port]: serves the office with a made-up night across three projects — working, asking, hitting limits — no Telegram bot, config or API keys needed.

  • The office has a lounge: idle agents walk to the coffee machine, TV or toilet and back; an agent on a usage limit goes to bed until the window resets. Demo GIF re-recorded.

  • Token savings and a prompt coach: auto-compact on by default (200k), !fresh (memory → /clear → re-read after a green !goal), !lint (holds vague prompts; ✨ improve rewrites them from your first-try prompts), correction detection feeding !route stats and learned routing, !coach, and !ladder (haiku/sonnet/opus by task class, stepping up when the agent struggles).

  • !briefing HH:MM|now|off: one message each morning — done overnight, waiting for you (questions, open PRs with GitHub's merge verdict, production errors), usage windows with their forecast, and what is queued, held or stopped — with night reel and stats buttons.

  • Dashboard: 💬 on each topic opens it as a live chat — messages both ways, working menu buttons, a composer, a working indicator, in-page notifications — at /chat?t=<topic>, peers included; the dashboard is installable as an app (manifest, service worker, icon).

  • !deps: known vulnerabilities (npm audit, pip-audit, govulncheck) worst first and packages a major version behind, with an upgrade with agent button; !deps nightly HH:MM checks every night and reports only findings.

  • Limit forecast: usage windows are sampled every minute; when one will fill before it resets (within 90 min) at the last hour's pace, topics working on that agent get one ⏳ warning with a switch button; !forecast, and the dashboard limit cards show the projected time.

  • Project memory: .nightmux/memory.md per project (what it is, how to run/test, decisions, gotchas, in progress), rewritten by the live agent after 6 turns and 15 quiet minutes and read first by every session nightmux starts or switches to; !memory [update|on|off].

  • Office: a server strip with status dots, ⚙ dashboard / + project / + server links (deep-linking to the form and the add-server steps), and a banner when a server is not answering. Topics on a peer that is down no longer vanish from the office and dashboard: they show, marked, with where to fix it.

  • Dashboard: + add server gives the steps and a one-use, 30-minute nightmux.py --join <code> command; the new machine fetches the bot settings and a peer secret over the tailnet, configures itself as a peer and installs the service, and appears in the new servers section (status, agents, topics, remove). A setup panel lists what is missing on this machine with the fix — the same checks as --doctor, which gained bot topic rights, agents, projects folder, tailnet dashboard, gh and Chromium.

  • Deploy previews: !watch posts the preview URL a host attaches to the PR's commit (GitHub deployment, deploy-preview status, or a bot comment) with open/screenshot buttons; bot comments are no longer fed to the agent as reviews. !errors: a per-topic webhook for Sentry (or any JSON) — new errors become 🛠 fix buttons or, on auto, prompts; !errors expose publishes only /hook on :8443 via Tailscale Funnel.

  • !desktop: a virtual screen (Xvfb + openbox) with a password-protected noVNC link over the tailnet; !tools add desktop gives the agent nightmux's own computer-use MCP server (screenshot, click, type, key, scroll, open); !desktop open|shot|off.

  • Android: !apk builds the project's debug APK (Gradle wrapper at the root or under android/, or Flutter) and sends it to the topic; !apk install puts it on your phone over wireless debugging (!android pair|connect <ip:port>); !shot android sends the phone's screen, and a photo after it is a bug report with the activity on screen and recent logcat errors. A failed build offers "send to agent".

  • !issues / !issue <n>: open issues as buttons; the agent gets the issue, a branch and the PR recipe, nightmux finds the branch's PR and watches it (CI failures, reviews, merge button). !issues auto [label] takes labelled issues one at a time while the topic is quiet.

  • !tools add browser [all]: registers Playwright's MCP server with the topic's agent(s) via each CLI's own mcp add (Claude Code at local scope), tells the agent to verify UI changes with it, and offers a restart to load it; !tools rm browser, !tools restart.

  • Dashboard: + new project creates the Telegram topic, folder and session (optionally with an idea brief and check loop, on a peer if chosen); topic cards gain agent chips (tap to make live), + agent and close (stops agents, unbinds, closes the Telegram topic, keeps files).

  • !route auto|off: a prompt that starts a new task is classed light/normal/heavy and the topic switches to the best live bench agent for that class; mid-task prompts never move; !goal green/stuck results adjust per-class scores.

  • Point and fix: a photo sent within two hours of !preview/!shot reaches the agent with the page URL, that page's console errors and its rendered DOM (as a file), and an instruction to fix what is marked and recheck.

  • !reel [hours] / !reel daily HH:MM: the office's desks are recorded once a minute; the busiest room is replayed as a GIF (the office page draws each moment in headless Chromium, a stdlib PNG/GIF encoder stitches them) with captions and per-project commit stats.

  • !pair <agent> [rounds]: after every turn that changed the tree, a second agent on the bench reviews git diff <since> in the same folder; real findings go back to the coder (2 rounds by default, then to you), LGTM is a quiet 👍.

  • Loop guard: two independent signs of an agent circling (same error 3×, one file churned while the diff stays flat, repeated apologies, !goal failing the same way) ping the topic with step back / hand to another agent / pause buttons; !loopguard auto|ping|off.

  • !idea [@agent] <what to build> in a fresh topic: a new folder under
    projects_root (never reusing one), git init, the agent started with a
    spec → MVP → ./check.sh prompt queued, and !goal sh ./check.sh on.

  • !p: saved prompts as tap-to-send buttons — built-ins review,
    fix-tests, spec, explain, tidy, ship; !p save <name> <text>
    with {{args}} for what follows the name; config overrides and hides
    built-ins.

  • !watch pr [n]: polls the topic's pull request; a failed check's log and
    new review comments (inline too) are queued to the agent once each, the gh
    account's own comments skipped; green pings once per commit with a merge
    button (!watch merge); a merged or closed PR ends the watch.

  • !preview: finds what the session's own processes serve over HTTP (by
    process tree, agents' own sockets excluded) and sends tap-to-open links on
    the tailnet — tailscale serve for loopback-only dev servers, never public.
    !shot [:port][/path|url] sends a phone-size screenshot (headless Chromium).

  • !goal [rounds] <check>: after every finished turn the check (tests, build,
    lint) runs in the project dir; a failure's tail goes back to the agent as
    its next prompt until it passes. Reports green once; stops and pings on the
    same failure three times or when out of rounds; your next message resumes.

  • Two (or more) servers behind one bot: the primary forwards a topic's
    updates to the peer that runs it (!server <peer> / !server local), the
    peer ("poll_telegram": false) replies to Telegram directly. Peers talk on a
    secret-gated /peer/ listener; the dashboard and office aggregate every
    machine's topics, metrics and limits.

  • Dashboard (/ on the webhook port): server metrics (CPU, memory, disk,
    load, uptime, tmux sessions) and limits per agent — sessions live/busy/held
    plus the usage windows Claude Code and Codex report themselves.

  • Chat analysis — !stats [days] (also /tmstats) and the dashboard's
    analyze button read Claude Code, Codex, opencode and agy transcripts on
    this machine and report prompts, model calls, tokens, cache hit rate,
    context size, nudge prompts and model mix, with concrete tips on what to
    change. Counts only; no prompt text leaves the function.

Fixed

  • A hand-broken ~/.nightmux.json now stops the daemon with one line naming the line/column and the usual cause, instead of a traceback; --join keeps an unreadable config as .broken rather than replacing it silently. install.sh clones/updates ~/nightmux from GitHub instead of installing the (lagging) PyPI release.

  • !apk: a build that runs past apk_timeout (default 60 min, was a fixed 30) now stops entirely — the Gradle client no longer keeps running after the wrapper shell i...

Read more

nightmux 1.2.0

Choose a tag to compare

@mmr710 mmr710 released this 02 Sep 10:29

Three weeks of work that had been sitting on a branch. If you installed from PyPI
in August, this is a substantially different program: nightmux.py gained 2,580
lines and lost 148.

One topic, several agents

A bare !<agent> in a bound topic now switches that topic between claude, agy,
codex, opencode and anything in agents — same directory, a tmux session per
agent, and the one you left still running. !agents lists the bench and marks
the live one. Switching back lands in the conversation you left, not a fresh one.

Fixes worth knowing about

  • A tmux call that timed out was read as "no sessions are running." run()
    reports a timeout by returning text, which parsed as an empty pane list — so
    every bound topic was told its session had died, then rebaselined, which drops
    the transcript offset and silently skips whatever arrived during the gap. One
    box logged 209 timeouts and 72 false deaths in three days.
  • A session whose name matched a window name elsewhere was reported gone by
    every command typed at it.
    Every Claude Code pane runs in a window called
    claude, so a session named claude resolved to whichever session held one.
  • The status-line snapshot of a parked session was swept after a day, taking
    its context figure and transcript path with it — so the sessions that lost
    their context reporting were exactly the parked ones idle_hint exists for.
  • Two topics could bind one tmux session, sharing a scrape cursor, so one of
    them silently got no output. !bind refuses it; !status flags existing pairs.
  • The context warning fired after the compaction it warns about, and a
    /compact that never landed was never retried.

Also

  • !spendcap 500k / 2M caps what turns cost, not how many there were. A bare
    number is still turns, so existing configs are unchanged.
  • !agents and the context warning now say when a session reports no context
    figure at all — on agy, codex or opencode that whole layer is off, and it used
    to be off silently.
  • !ctx no longer re-reads the whole transcript every time it is typed.

Full detail in CHANGELOG.md.

nightmux 1.1.0

Choose a tag to compare

@mmr710 mmr710 released this 12 Aug 07:28

Run Claude Code — or Codex, Gemini, aider, anything with a prompt — from a Telegram topic, with a real tmux session behind it on your own machine.

pipx install git+https://github.com/mmr79/nightmux
nightmux --setup

Added

  • Any terminal agent, not just Claude Code. !claude, !codex, !gemini, !aider, !agy start a session; cfg["agents"] adds your own as [command, resume-flags] with no code change.
  • !resume remembers which agent a topic was started with, so a codex session is no longer resumed with claude's flag.

Changed

  • The project is nightmux. It was tgctl, then briefly telemux — which turned out to be another project's name on PyPI and six other repositories' on GitHub. Both older names are migrated automatically on first run: config, offsets and any held prompts come along.
  • The hook scripts are nightmux_stop.py, nightmux_notify.py and nightmux_state.py. Hyphens are not legal in a module name, and that was the only thing between this tree and a pip install. Upgrading from an older clone: re-run --setup to repoint Claude Code at them.

Fixed

  • A rate-limit hold that expired with an empty queue was never cleared: the session stayed flagged as limited across restarts, and the topic never heard the resume it was promised.
  • The 5-hour and 7-day usage figures could report a window that had already reset — a stale 92% beside a reset time in the past.

Python 3.8+, stdlib only, no dependencies, no relay server. Full notes in CHANGELOG.md.