Open work only, one item per line. Closed items move to docs_ai/BACKLOG_DONE.md.
What the tool does today: ../commands.md (generated). How it is built:
ARCHITECTURE.md. What the owner ruled: docs_ai/DECISIONS.md.
- An id is permanent and never reused. Take one with
bin/next-id <PREFIX>: one counter for every worktree on the machine, under a lock, and never below the highest number on any branch. Searching the text instead gave outCLI-26three times andMAX-16andMAX-23twice on 2026-09-24. - Prefixes:
RESresearch and measurement ·OPSrepository, tooling, CI, release ·COREcli-core·SPECprotocol spec and generator ·MAXdomain, client, transport, session ·CLIcommands and output ·DOChandwritten docs ·PROTOprotocol unknowns ·RISKrisks. - One item: the task as a title, then where the work starts (
path:lineor a REQUIREMENTS §). Analysis goes to a plan indocs_ai/plans/, a ruling toDECISIONS.md. - Priority: P1 blocks work or breaks something real · P2 this cycle · P3 someday.
- Mark: none — not started · 🚧
<branch>— taken · 🟡 — half done, the rest named · ⏸️ — deferred by the owner · 🚩 — waits on an owner decision. - Claim before code: put
🚧 <branch>on the line in the first push of the branch. Two agents built the same command on 2026-09-23 because an open PR was the only signal. - Close in the PR that ships the work: delete the line here in that PR, and append it to
docs_ai/BACKLOG_DONE.md(local, not in git). Users read what shipped inCHANGELOG.md.
- CLI-58 · P2 · 🟡
mcp --http: ChatGPT and Claude in the browser reach the CLI without a third-party proxy. Done: Streamable HTTP on127.0.0.1behind the owner's tunnel, a one-owner OAuth login (one-time terminal code, PKCE S256, 1 h access / 30-day rotating refresh, hashes only), every write through the form (NEED-593),--revoke— cli-messaging #527/#528/#543 (0.146.0), tg-cli #266, max-cli #398,docs/remote.mdin both. Left: the live check with Claude.ai and ChatGPT through Tailscale Funnel (owner; tg-clibin/tg-remote) — it also answers whether the apps show MCP forms at all, without which--httponly reads. MAX0.28.0 and TG0.27.0 are published with core0.17.0 and cli-messaging0.147.0; the reviewed search/history/service diagnostics work is included. - CLI-68 · P3 ·
mcp --httpas a background service:server installfor it (systemd/launchd), so the browser apps reach a machine without an open terminal. Follows CLI-58's live check (NEED-595 A: foreground first).
From the PyMax comparison (2026-09-24, NEED-175). Each is what PyMax's source declares
(MaxApiTeam/PyMax, src/pymax/api/, commit 53103f0) — a claim until measured. Every writing
operation is measured first in Saved messages (chat 0), as replies and reactions were (NEED-150),
and needs the owner's yes before it ships. Deleting messages was ruled out (NEED-32) until the owner asked for it on 2026-09-24 (MAX-47); marking
read only on an explicit flag (CLI-33, REQUIREMENTS §19).
-
MAX-48 · P3 · Send a round video note ("кружок"): opcode 82
{type: 1, uploaderType: 1},thumbhashfrom the upload answer,_type: "VIDEO"withvideoType: 1. MAX refuses a file that is not 480×480,yuv420p, limited range, bt709, baseline, AAC 48 kHz mono (PyMax #94).thumbhashis bytes — aUint8Arrayin a payload goes out as MessagePack bin sinceMAX-40. -
MAX-49 · P3 · Two-step password: log in when MAX asks for it (
passwordChallengein the login answer, thenAUTH_LOGIN_CHECK_PASSWORD115{trackId, password}), and set or remove one (112 → 107 → 111). PyMax 2.4.1, code; a user logged in with it on the mobile client (PyMax #106). The password is typed at a prompt, never an argument. Correction 2026-09-28: logging in with a password shipped withsession start(PR #66,src/session/login.ts:51). Left: setting and removing one (112 → 107 → 111). -
MAX-34 · 🟡 P3 · Live events: a long-running
max listenthat prints new messages, edits, reactions and typing as they arrive (PyMax'son_message,on_message_edit,on_reaction_update…). Conflicts with one-shot commands (CLAUDE.mdconstraint 4), so it needs a ruling first. What is new since the last check is alreadymax inbox(CLI-23). Correction 2026-09-25: the long-running part exists.max serveholds the connection andmax watchprints new messages as they arrive (src/server/server.ts,#pushed). What is left is edits, reactions and typing. The server receives them but passes on only new messages (opcode 128).Done 2026-09-25 from the third tab recording:
max watch --eventsprints edits (128 withstatus: EDITED), deletions (128 withstatus: REMOVED) and reactions (155); the plain stream is unchanged. Left: typing — MAX pushes 129 only after75 {chatId, subscribe: true}, which the tab sends for the chat it has open and repeats every 60 s;max servesubscribes to nothing. -
MAX-4 · 🟡 P3 · Chat addressing. Done: an id, or a title matched exactly then as a fragment, an ambiguous one refused (
resolve,src/client.ts:325;pickChat,src/resolve.ts:13). Left:@username, a phone number, a chat the account is not in. -
CLI-36 · P3 · The local copy made optional: a setting under which
maxwrites no chats or messages to disk and answers everything from MAX (--offlineandmessages searchthen refuse). Owner, 2026-09-24: «я бы сделал хранение опциональным в P3». Correction 2026-10-03 (T6): the per-profile cache is removed; this option would now need to control shared adapter recording and the login record (src/record.ts). -
CLI-5 · P3 ·
max raw <operation>— a debug escape hatch, validated against the spec, never arbitrary frames (REQUIREMENTS §22). -
MAX-52 · 🟡 P2 · The requests a real tab sends right after LOGIN: 21 on a fresh start (
48 48 272 35 32 302 163 208 27×4 209 28 22 48 28 35 53 209 35) and 9 after a re-login.maxsends none, which shows on every login — a stronger difference than telemetry. Decide per request: the read-only ones (272 folders, 302 banners, 163 call history, 27) could be copied; 22 subscribes to push and changes state. Captured 2026-09-25,docs/dev/capture/2026-09-25-web-tab.md. Names by PyMax (53103f0): 22CONFIG, 27ASSETS_UPDATE, 28ASSETS_GET_BY_IDS, 32CONTACT_INFO, 35CONTACT_PRESENCE, 48CHAT_INFO, 53CHATS_LIST, 208/209 stories, 272FOLDERS_GET, 302BANNERS_GET; 163 is not in its list. Onlymax servewill send them. 2026-09-25: the recording kept 27'stypeonly as"string", and no answer bodies, so what 27 asks for and which sync value each re-login sends back are unknown. The recorder now keeps both; the code waits on the next recording (withMAX-51).Done 2026-09-25 from the second recording (
docs_ai/captures/2026-09-25-web-tab-2.jsonl):max servesends 272, 302, 163 and 27 ×4 (STICKER,FAVORITE_STICKER,REACTION,ANIMOJI_SET) after every login, each re-login with the sync its previous answer returned (src/client.ts,live.readLikeTab). Left: 48{chatIds}, 32 and 35{contactIds}, 28, and the stories 208/209. Never: 22, which subscribes to push. -
RES-5 · 🟡 P2 · Does
LOGINmove presence or read state? Reading history does not (noCHAT_MARK, tested). Partly answered by the capture of 2026-09-25: the tab's own LOGIN sendsinteractive: falsetoo;truegoes only in pings, while its window has focus. Left: whether opening a chat with unread messages marks it read without opcode 50 — seeRES-10. Correction 2026-09-25 (RES-10, captured): the tab marks a chat read with an explicit opcode 50 after opening it, not with 49; and 49 withoutinteractivemoves nothing (measured,RES-11). Left: whether LOGIN itself moves presence — needs a second device watching. -
RES-7 · P3 · What a real client sends as opcode 36's payload.
{},{marker}are refused and{marker, count}closes the connection (pnpm probe:contacts), so only a capture answers it. It is the only route to contacts who share no chat. ClosesPROTO-1. -
PROTO-1 · 🟡 P3 · What opcode 36 returns: other clients call it
CONTACT_LIST, the protocol notes call itGET_BLOCKED. Waits onRES-7. -
PROTO-2 · P2 · How long MAX remembers a
cid. The send retry rests on deduplication measured seconds apart; minutes apart is unproven (ARCHITECTURE.md§6). -
PROTO-3 · P3 · The upper bound on
chatsCountinLOGIN: 100 works, 200 is refused. The spec caps it at 100 (src/spec/operations/session.ts:109). -
PROTO-6 · P3 · What the
messagesobject in theLOGINanswer holds. Nothing reads it (src/spec/operations/session.ts:156);pnpm probe:idsprints its type and key count. -
SPEC-3 · 🟡 P3 · Sanitized protocol fixtures, synthetic values only (REQUIREMENTS §24). Done: the web client's frames, headers and payload structure without values (
src/testing/fixtures/web-capture-2026-09-25.json,MAX-40), and the recorder for more (scripts/capture/web-recorder.js). Left: fixtures of MAX's answers to our own operations — response shapes are still tested with made-up payloads insrc/spec/. -
SPEC-4 · P3 · A generated list of implemented operations (§8, §30). Deferred: listing what MAX has and we lack means maintaining MAX's whole surface (§10).
Group moderation on the personal account (NEED-306…NEED-314, plan
docs_ai/plans/2026-09-27-group-moderation.md). review --unanswered shipped as CLI-43, chats events as CLI-44, chats members list as CLI-45, chats rules and chats check as CLI-46, MCP max_chats_check as CLI-47.
-
CLI-48 · P3 · Roles in
chats members listcome from the chat as the login carried it, which lags: right afteradmins addthe bot still showed asmember, whilebot admins listalready had it. Refresh the chat (opcode 48,CHAT_INFO) before reading roles, or say the roles may be old. -
MAX-62 · P3 · Lifting a bot's ban.
max <bot> bot members remove --block(andbot chats check) ban a person from rejoining by the invite link (measured 2026-09-27). The Bot API has no unblock, and the owner found no ban list in the MAX app. Re-adding the person by an admin works, but whether it lifts the ban is unknown — after leaving, the link may still refuse them. Find where MAX keeps the ban (a capture of the web client's group settings, orCHAT_MEMBERS59 with anothertype), then offermax chats members unban.
-
CLI-60 · P1 · 🟡 Personal-account commands onto cli-messaging's shared commands, deleting max's copy as each moves (T6). Done: delete, reactions, pin, mark-read, send/edit/forward, polls, chats and contacts reads,
messages list|show|context|search|links(#282), thestoregroup (#307),conversations(#308), transcripts into the shared store (item 5 step 2),inbox/review(step 3), MCP reads (step 4), shared completion and store diagnostics in doctor (step 5), record-backed client/callers/serve (#340–#343), removal of the cache command and storage code (steps 6–7), and contact writes (add|remove|block|unblock|rename|import), thechats foldersgroup, andaccount update/account sessions list|end, and group administration (create|join|leave|update, members/admin writes, invite links), and group reads (members list,events,inspect), and shared moderation/rules with legacy checkpoint migration. Left: a live check ofmessages list --transcribe. MAX permission levels, config migration and MCP filtering are complete. Correction 2026-10-03:models textis shared since #322;models audio, its catalogue and installer now use the shared package too. Plan and handoff:docs_ai/plans/2026-10-02-t6-item5-cache-off.md,docs_ai/plans/2026-10-02-t6-item5-handoff.md. Shared runner and operational diagnostics: done (#347/#352). Correction 2026-10-03: search read-only MCP bridge is merged (#357), as is the shared package-upgrade workflow (#358). The permission-model move is complete. Canonical permissions now govern CLI/native reads, server writes/reads and MCP;config migratepreserves legacy levels and group checkpoints. -
CORE-10 · P3 · Plugins from npm, only from an allow-list kept in the CLI itself — package names with pinned versions and integrity hashes — never an arbitrary package: a plugin runs inside a program holding the token of a personal account. oclif's
plugin-pluginsis the model. -
CORE-11 · P3 · Installers and standalone archives per platform (oclif's
pack), after a single-file build (G4 §3.9: Bun only). Lowest priority. -
RES-12 · P3 · Word search at 1M messages misses the speed targets of storage phase 2 §6 (accepted for phase 2 by the owner, 2026-10-02): every word with no chat or sender filter up to 124 ms (45), any word over all chats up to 232 ms (130), filling the index 53 s (20) with a 1.2 s vocabulary batch (500 ms). Every target holds at 100k. Starts at cli-messaging
src/store/sqlite/words.ts(matchWords, the ranked-first path) andsrc/store/sqlite/search-index.ts(fillSearchIndex); measure withbench/search/store-chain.ts(cli-messagingbench/search/results.md, "Phase 2 item 8").
Added by the owner on 2026-09-24. Each one goes against REQUIREMENTS §3 or §18, and the line says which; the plan for it starts by saying so.
- CLI-27 · P3 · Hooks for workflows:
maxruns a configured command when a check finds something new. Asked by the owner 2026-09-24 (NEED-172). Two things to settle in the plan: the message text reaches that command, so it must go as data on stdin and never into the command line; andmax watch --jsonl | <command>on a runningmax serve(MAX-35) already does this for live messages, asmax inbox --newon a schedule does for batches — say what a hook adds over those two pipes. Correction 2026-09-24: written beforemax serveexisted.
-
Completed 2026-10-04: release documentation describes canonical P7 defaults, resource-specific restrictions, explicit deletion confirmation and current permission recipes. Publication is separate.
-
Completed 2026-10-03: repository parity-audit skill runs the shared detailed auditor (#365; shared #470–#474). No account access.
-
Completed 2026-10-03: shared sends-list factory honors configured limit and shared skill factory exposes named link-conversations instructions (#368).
-
Completed 2026-10-03: message downloads, scheduled reads and evidence now use shared factories (#370); MAX retains safe transport and compatibility --output. Session-end mutation metadata is explicit.
-
Completed 2026-10-03: shared account-show factory retains MAX profile fields; contact-lookup argv refusal never repeats a number (#371). Permission runtime remains with T6/P7.
-
Completed 2026-10-03: response MIME preserves shared download fallback extensions (SDK0.136); streams remain lazy and bounded, without eager unused attachment requests.
-
Completed 2026-10-03: chats-show member counts explain possible self omission or partial lists without claiming incomplete loading (SDK0.137, CLI-62). Online and offline consumer regressions retain JSON counts and members.
-
Completed 2026-10-03: MAX poll.already.voted refusal explains explicit retract before a new vote when the poll permits changing votes (CLI-61). Provider error identity and one attempted write are preserved; wire refusal regressions cover other errors and an explicit retract refusal.
-
Completed 2026-10-04: coordinated MAX0.27.0/TG0.26.0 published, provenance and installed CLI versions verified; core0.17/shared0.140.
-
MCP parity · ✅ canonical personal tool catalogue and strict shared input schemas mounted on MAX’s held session; missing supported bindings and local-write permission checks implemented. Telegram forum tools remain unavailable; legacy moderation/rules names and native preview/transcript behavior retained. Shared prerequisite 0.144.0; final synthetic audit is kept in the private implementation plan. Consumer publication is separate.