Python oracle: ..\codex-telegram-remote
This file now serves two purposes:
- baseline behavior imported from the Python oracle
- target Telegram observer/UI v2 deltas that the Go runtime is expected to adopt
/start/help/threads/projects/show <thread>/bind <thread>/reply [--plan] <thread> <text>/plan <thread> <text>/plan <text>/plan_mode <thread> <text>/plan_mode <text>/settings/model/effort/new <project-key-or-number> <prompt>/newchat <prompt>/newthread <prompt>/context/whereami/observe all|off/status/repair/stop [thread]/approve <request_id>/deny <request_id>
/whereamiis an alias of/context/modelsis an alias of/model/reasoningand/reasoning_effortare aliases of/effort/codex_settingsis an alias of/settings/awayand/backexist in the Python product surface but are not part of the minimal Go cutover slice yet
ctr-go initcreates a private local config file at~/.codex-tg/config.envby default.ctr-go service installis the macOS service-first setup path; it can prompt interactively or receive all important values through flags.- macOS service lifecycle commands are
ctr-go service start|stop|restart|status|enable-login|disable-login|uninstall. CTR_GO_CONFIGpoints at an alternate config file.- Config precedence is explicit environment variables, then config file values, then built-in defaults.
- Config files use simple
.envstyleKEY=VALUEentries; comments and quoted values are supported, but shell expansion is not. - Runtime proxy env can be stored in the private config and applied after
startup; LaunchAgent plists still carry only
CTR_GO_CONFIG. status,doctor, daemon logs, init summaries, service summaries, LaunchAgent plists, and tray surfaces must not print Telegram bot tokens in full.- Official GitHub Release assets include
ctr-goarchives for macOS, Linux, and Windows, macOS.pkgartifacts, andSHA256SUMS.
- Global observer monitoring is default-on when an operator target can be resolved automatically.
/observe allmoves the single global observer target to the current chat/topic./observe offdisables global background monitoring.- The observer target model is no longer additive
main DM + extra feeds. - The observer surface is centered around a summary panel keyed by
(chat, project, thread). - The summary panel owns
StopandSteer. - Tool/output stream messages do not carry buttons.
- Final answers are delivered separately and expose
Получить полный лог. - Telegram sends normal notifications only for
New run(configurable throughCTR_GO_NOTIFY_NEW_RUN),[Plan]prompt-cards, and[Final]; other bot messages are silent. - Plan Mode / waiting-input states create a separate routeable
[Plan]prompt-card. [Plan]buttons are structured-only: they come from Codexchoices/options/suggestions/responses, never from bridge heuristics.- Telegram-originated Plan Mode starts use App Server
turn/startwithcollaborationMode.mode = plan; prompt wording alone is not Plan Mode. - If a thread remains in Plan Mode,
Turn off Planon the Plan Final Card and/stop <thread>set a one-shot local reset; the next ordinary Telegram-originatedturn/startfor that thread usescollaborationMode.mode = defaultand then clears the reset. /modeland/effortare button menus backed by SQLite daemon state for Telegram-started collaboration-mode model settings.- After a model or reasoning-effort selection, the edited settings message removes inline choice buttons.
/projectsgroups cached non-Chat projects by normalizedcwd, sorts projects by latest cached thread activity, shows latest Codex UI Chat previews, opens full Chats pagination throughOpen Chats, and never accepts arbitrary filesystem paths from Telegram./projectsbuttons show meaningful labels (N. Project name,Chat N. Thread name); internal project keys are not rendered in the menu, and project rows showlast thread:.- Cached threads under generic
Documents/Codexpaths or the configuredCTR_GO_CODEX_CHATS_ROOTare treated as single-threadChats; selecting a Chat opens and binds that thread and does not offer projectNew thread. New threadcreates a one-shot state; the next plain-text message starts a new App Server thread in the selected project cwd and uses that text as the first prompt./newchat <prompt>creates a dated Chat folder under the configured Chats root, calls App Serverthread/startwith that cwd, and uses the prompt as the first turn./newthread <prompt>starts a new App Server thread without a Telegram-selected cwd parameter and uses the prompt as the first turn. It must not create a Chat folder; App Server may still attach the daemon default cwd./plan <text>and/plan_mode <text>use reply route, armed state, or current binding when the first token is not a known or UUID-like thread id.- Synthetic polling prompts without
request_idare answered withturn/steer, thenturn/startif the turn is already unavailable. - Replies to active turns steer the active turn. If steering is rejected while the thread still looks genuinely active, the bridge must not create a parallel
turn/start; stale-active errors such asno active turn to steerare handled by ADR-012 and may fall back to a newturn/startafter re-read. - All observer/card messages carry a visual identity header:
emoji [Project] [Thread] [T:thread] [R:run] [Kind]. - Emoji markers are stable visual hints; route correctness remains based on DB message routes and callback tokens.
- Full
thread_idandturn_idare exposed through/contextand theGet thread idsummary/Final action; compactT:/R:chips are not routing authority. - Foreign GUI/CLI runs create separate
New runand[User]cards before the live trio. - If the prompt is not available when the run is discovered,
[User]starts as a placeholder and is edited into the real prompt later. - Telegram-originated runs create
New runand the live trio, but do not duplicate the user request as[User]. - Telegram-visible text must never render literal
"<nil>". Missing, null, empty, or nil-like App Server fields are treated as absent and must be cleaned before Markdown/entity conversion.
Navigation/edit-in-place callbacks:
nav_projectsnav_all_chatsnav_activenav_threads_pagenav_projects_pagenav_project_threads_pagepick_projectshow_threadshow_context
State-changing callbacks:
bind_herefollow_hereobserve_allreply_hintstop_turnapproveapprove_sessiondenycancel
Target v2 callback surface:
show_threadbind_herestop_turnsteer_turnget_full_loganswer_choiceobserve_allobserve_offsettings_overviewsettings_model_menusettings_reasoning_menusettings_model_setsettings_reasoning_setget_thread_idturn_off_plan
From Python tests and router behavior:
- explicit thread id from command
- reply-to Telegram message route
- current thread binding
Additional route rules:
/showand/bindwithout an explicit thread id must resolve reply-route first- route precedence stays unchanged even after the observer/UI v2 changes
- target v2 no longer assumes a dedicated read-only observer-only chat
- free-text routing still needs an unambiguous target even if the current chat also receives global observer panels
- reply-to
[Plan]routes before binding and carriesthread_id,turn_id, andrequest_idwhen available - real
request_idPlan answers use App Server server-request response; synthetic Plan answers useturn/steer /reply --plan,/plan, and/plan_modecarry an explicit Plan Mode start intent when they create a new turn- Hidden
/reply --defaultand/defaultfallback paths may still carry an explicit Default Mode start intent, but they are not advertised in the public command menu. Turn off Planand/stopcarry a one-shot Default Mode reset intent for the next ordinary turn, not for the current callback/stop action itself.
- Oracle baseline:
- implicit main DM when exactly one allowed user exists
- explicit observer targets from
/observe all - explicit observer targets do not replace the implicit main DM
- Target v2:
- one global observer target
- default-on when the target can be resolved automatically
/observe allmoves the target/observe offdisables monitoring
turn_startedtool_activitythread_updatedfinal_answerturn_completedturn_failed
Observer/UI v2 presentation contract:
- run notice:
- appears before
[User]and summary/tool/output for new runs - carries source markers, source mode, and route metadata, but not run status
- is deleted best-effort after finalization
- uses normal Telegram notification only when
CTR_GO_NOTIFY_NEW_RUNis enabled
- appears before
- user notice:
- appears after
New runfor GUI/CLI runs and before summary/tool/output - remains after finalization as the historical request marker
- may start as a placeholder and edit into the actual prompt
- appears after
- summary-panel update:
- carries project/thread source markers
- owns live run status while active
- carries action buttons such as
StopandSteer - is sent silently and deleted best-effort after finalization
- tool/output message:
- carries source markers
- carries no buttons
- is deleted best-effort after finalization
- final-answer message:
- carries source markers
- carries on-demand
Получить полный лог - is sent as a new message with a normal Telegram notification
- becomes the panel summary message id for Details/Back callbacks
- contains final answer/status without replaying completed commentary/tool/output transcript
- exposes completed tool-only turns through Details as
Tool activity
Minimal event payload expected by the Telegram layer:
event_idkindthread_idproject_namethread_titletext
Optional event payload fields:
statusturn_iditem_idrequest_idneeds_replyneeds_approval
Plan prompt payload fields:
prompt_idsourcethread_idturn_iditem_idrequest_idquestionoptionsfingerprint
- global observer is active by default when one operator target exists
/observe allmoves the observer target to the current chat/topic/observe offdisables global monitoring/statusmust show readiness, transport, queue, tracked thread count, and current routing/contextmust describe the active tuple of chat/project/thread or the lack of one- polling fallback must emit progress/final/completion for foreign threads
- stale live-only assumptions must not suppress polling fallback
- repair must recreate app-server sessions and resume tracked threads without manual route surgery
- observer delivery must remain durable across daemon restart
- summary panels must be stable per
(chat, project, thread)instead of spamming a new actionable message for every event - waiting Plan prompts must be visible as
[Plan]messages and answerable by Telegram Reply - Plan answer buttons must stay scoped to their Plan turn; a stale pending input from an older turn must not be attached to a newer
[commentary]card - late foreign
[User]prompts must edit the existing placeholder, not append below live trio messages - duplicate live+poll sync must not create multiple
[Plan]cards for the same prompt fingerprint