Skip to content

Commit 94c8aa8

Browse files
committed
release: prepare v0.2.5
1 parent d156652 commit 94c8aa8

35 files changed

Lines changed: 1279 additions & 205 deletions

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
## Unreleased
44

5+
## v0.2.5 - 2026-05-06
6+
7+
- Added the Telegram notification contract: `New run` is configurable, `[Plan]` and `[Final]` notify, while live progress, direct responses, menus, callbacks, exports, and errors are sent silently.
8+
- Changed Final rendering to send a new `[Final]` message and best-effort delete transient live cards, preserving Details routing on the new Final Card.
9+
- Fixed tool-only runs so live current tools are not erased by stale polling snapshots and completed tool-only commands remain visible in Details and Tools file.
10+
- Added explicit Default Mode escape hatches through `/default` and `/reply --default` for threads that remain in App Server Plan Mode.
11+
- Added ADR-015, contract/regression documentation, release validation notes, Telegram transport tests for `disable_notification`, and live E2E coverage for notification and tool-only Details behavior.
12+
513
## v0.2.4 - 2026-05-05
614

715
- Changed `/newchat <prompt>` to create a real Codex UI Chat folder under `CTR_GO_CODEX_CHATS_ROOT` before starting the new thread.

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Codex Telegram bot and remote UI for local OpenAI Codex App Server, built in Go.
44

55
`codex-tg` turns a Telegram bot into a mobile control surface for local Codex threads: it watches Codex GUI/CLI activity, keeps thread identity visible, routes replies back to the right thread, and exposes high-signal controls such as Plan Mode prompts, Stop, Steer, Details, Tools file, and Get full log.
66

7-
Current release: `v0.2.4`.
7+
Current release: `v0.2.5`.
88

99
![codex-tg Telegram Plan Mode demo](docs/assets/telegram-plan-mode-demo.png)
1010

@@ -38,7 +38,8 @@ The demo flow is documented in [docs/demo/telegram-plan-mode-demo.md](docs/demo/
3838
- Telegram-origin live current tool rendering from App Server `item/*` events, while foreign GUI/CLI panels stay completed-tool only.
3939
- Stable visual identity per thread: emoji marker plus project/thread/run chips.
4040
- Explicit `New run -> [User] -> [commentary] -> [Tool] -> [Output] -> [Final]` chronology with status on the live commentary/final card.
41-
- Plan Mode starts from Telegram via `/plan` or `/reply --plan`, then renders `[Plan]` prompt-cards with reply-first routing and structured buttons when Codex provides choices.
41+
- Low-noise Telegram notifications: only `New run` (configurable), `[Plan]`, and `[Final]` are audible; live progress and exports are sent silently.
42+
- Plan Mode starts from Telegram via `/plan` or `/reply --plan`, and Default Mode can be forced with `/default` or `/reply --default` if a thread needs to leave Plan Mode; `[Plan]` prompt-cards keep reply-first routing and structured buttons when Codex provides choices.
4243
- Final Card with Details pagination and on-demand Tools file export.
4344
- On-demand full log archive from Codex session JSONL.
4445
- SQLite-backed durable state for bindings, routes, callbacks, observer target, panels, and delivery metadata.
@@ -47,7 +48,7 @@ The demo flow is documented in [docs/demo/telegram-plan-mode-demo.md](docs/demo/
4748
## Platform Status
4849

4950
- Windows: actively tested with the local Codex App Server, Telegram Bot API, observer flows, and live E2E demo.
50-
- macOS: `v0.2.4` is verified stable on macOS 26.3.1 arm64 with Go 1.26.2, LaunchAgent daemon startup, local build, Details binding validation, Telegram command-menu readback, real Chat folder creation, and live Telegram readback E2E.
51+
- macOS: `v0.2.5` is verified stable on macOS 26.3.1 arm64 with Go 1.26.2, LaunchAgent daemon startup, local build, Details binding validation, Telegram command-menu readback, real Chat folder creation, low-noise notification validation, and live Telegram readback E2E.
5152
- Linux: CI runs tests/builds on Ubuntu; full local daemon/runtime validation is still pending.
5253

5354
## Quickstart
@@ -79,7 +80,9 @@ In Telegram:
7980
/context
8081
```
8182

82-
Start or continue a Codex thread from Codex GUI/CLI. `codex-tg` should create a `New run` card, a `[User]` card, live progress cards, and then collapse the completed run into a final answer card with Details.
83+
Start or continue a Codex thread from Codex GUI/CLI. `codex-tg` should create a `New run` card, a `[User]` card, live progress cards, and then send a final answer card with Details while cleaning up transient live cards.
84+
85+
Set `CTR_GO_NOTIFY_NEW_RUN=off` to keep `New run` visible but silent. `[Plan]` prompts and `[Final]` cards still use normal Telegram notifications.
8386

8487
## Runtime Commands
8588

@@ -93,7 +96,7 @@ go run ./cmd/ctr-go daemon run
9396
Telegram commands:
9497

9598
- `/start`, `/help`
96-
- `/threads`, `/projects`, `/new`, `/newchat`, `/newthread`, `/show`, `/bind`, `/reply`, `/plan`
99+
- `/threads`, `/projects`, `/new`, `/newchat`, `/newthread`, `/show`, `/bind`, `/reply`, `/default`, `/plan`
97100
- `/settings`, `/model`, `/effort`
98101
- `/context`, `/whereami`
99102
- `/observe all`, `/observe off`
@@ -121,6 +124,7 @@ Primary environment variables:
121124
- `CTR_GO_ALLOWED_CHAT_IDS`
122125
- `CTR_GO_DEFAULT_CWD`
123126
- `CTR_GO_CODEX_CHATS_ROOT` (`~/Documents/Codex` by default)
127+
- `CTR_GO_NOTIFY_NEW_RUN` (`true` by default; set `false`/`off`/`0` to send `New run` silently)
124128
- `CTR_GO_LOG_ENABLED` (`true` by default; set `false`/`off`/`0` to discard daemon stdout logs)
125129
- `CTR_GO_DIAGNOSTIC_LOGS` (`true` by default; set `false`/`off`/`0` to keep normal bot logs but suppress structured `daemon_event` diagnostics)
126130
- `CTR_GO_OBSERVER_POLL_SECONDS`

docs/adr/ADR-004-final-card-details-ux.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,24 @@
22

33
- Status: accepted
44
- Decision: active runs keep trio live visibility, while completed runs collapse into one Final Card with a Details view.
5+
- Amended by: ADR-015 for Final Card notification delivery.
56

67
## Decisions
78

89
- An active run remains live-visible through the trio of Telegram surfaces used for current execution state, tool activity, and output activity.
9-
- After the final answer is available, the completed run collapses into one Final Card.
10+
- After the final answer is available, the completed run collapses into one newly sent Final Card.
1011
- `Details` is view-state of that one Telegram message, not a stream of new detail messages.
1112
- Details mode may page through final text, tool calls, and output without creating a replacement message stream.
1213
- Tool and output content remains available on demand in Details tool mode.
1314
- Full tool and output content is also available as a `.txt` file when message-sized rendering is not practical.
14-
- Deletion of old live tool/output messages after finalization is best-effort.
15+
- Deletion of old live commentary/tool/output messages after finalization is best-effort.
1516
- Details callbacks are bound to the completed run panel/card that created them. Missing, stale, or mismatched panel metadata must fail closed instead of falling back to the current panel for the thread.
1617

1718
## Consequences
1819

19-
- The completed-run operator surface is one stable message with Final and Details states.
20+
- The completed-run operator surface is one stable message with Final and Details states. That stable message is the new Final card, not the earlier live commentary message.
2021
- Callback handlers must edit the existing card whenever Telegram permits it instead of emitting a new stream of messages.
2122
- Pagination state belongs to the card view and must be recoverable from callback payloads or persisted card metadata.
2223
- Callback handlers must verify the panel, thread, turn, chat/topic, and message id before editing a Details/Final card or exporting Details tools.
2324
- Tool/output live messages must not be treated as durable final history; the final card and on-demand `.txt` export are the durable review surface.
24-
- Cleanup failures for old live tool/output messages must not fail final delivery.
25+
- Cleanup failures for old live commentary/tool/output messages must not fail final delivery.

docs/adr/ADR-006-plan-prompt-mode.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- A waiting Plan Mode prompt is rendered as a separate `[Plan]` prompt-card, not as a Final Card state and not as a passive tool/output message.
99
- Telegram-originated Plan Mode runs must be started with App Server `turn/start` `collaborationMode.mode = plan`; prompt wording alone is not treated as Plan Mode.
1010
- Telegram exposes Plan start commands through `/plan <text>`, `/plan_mode <text>`, `/plan <thread> <text>`, `/plan_mode <thread> <text>`, and `/reply --plan <thread> <text>`.
11+
- Telegram exposes Default Mode reset commands through `/default <text>`, `/default <thread> <text>`, and `/reply --default <thread> <text>`, which pass App Server `turn/start` `collaborationMode.mode = default`.
1112
- `/plan <text>` and `/plan_mode <text>` use normal routing precedence after the command: reply-to route, armed state, then bound thread.
1213
- `/plan <thread> <text>` and `/plan_mode <thread> <text>` are treated as explicit-thread commands only when the first token is a known thread id or UUID-like Codex thread id. Unknown plain words remain part of the prompt text for the implicit route.
1314
- `/reply --plan <thread> <text>` stays strict and requires an explicit thread id.

docs/adr/ADR-010-run-chronology-and-user-notice.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
- Status: accepted
44
- Supersedes: ADR-009
5+
- Amended by: ADR-015 for notification policy and Final Card delivery mechanics.
56

67
## Context
78

@@ -16,7 +17,7 @@ The Telegram observer is also a security surface: if a local GUI/CLI or another
1617
- `New run` is an orientation card with source metadata only. It does not own run status.
1718
- `[User]` is delivered once as request context. It does not show run status and is not updated for status-only changes.
1819
- The live `[commentary]` card owns run status while the run is active.
19-
- At terminal finalization, `New run`, `[Tool]`, and `[Output]` are deleted best-effort. `[User]` remains as historical request context, and `[commentary]` is edited into `[Final]`.
20+
- At terminal finalization, the bridge sends a new `[Final]` card, then deletes `New run`, `[commentary]`, `[Tool]`, and `[Output]` best-effort. `[User]` remains as historical request context.
2021
- `[Final]` shows final-answer text and status only; completed commentary/tool/output history is available through Details.
2122
- DB message routes and callback tokens remain the routing source of truth.
2223

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# ADR-015: Telegram Notification Contract
2+
3+
- Status: accepted
4+
- Supersedes: the terminal finalization message-edit detail in ADR-004 and ADR-010.
5+
6+
## Context
7+
8+
Telegram notification volume can become noisy when every observer card is sent as a normal message. The operator still needs audible attention for genuinely important events: a new run, a final answer, and a Plan Mode question that needs a choice or reply.
9+
10+
Telegram edits do not provide a reliable per-edit notification contract. Therefore a `[Final]` that is produced by editing the live `[commentary]` card cannot be made audible without also making the earlier commentary message audible.
11+
12+
## Decision
13+
14+
- New messages are silent by default through Telegram Bot API `disable_notification=true`.
15+
- Audible messages are limited to:
16+
- `New run`, controlled by `CTR_GO_NOTIFY_NEW_RUN` and enabled by default;
17+
- a newly sent `[Final]` card;
18+
- a routeable `[Plan]` prompt-card for user input or structured choices.
19+
- `[commentary]`, `[Tool]`, `[Output]`, `[User]`, command/menu responses, explicit exports, and fallback/error messages are silent.
20+
- Finalization sends a new `[Final]` card, records its message route, moves the panel summary message id to that new card, and then best-effort deletes the old `[commentary]`, `New run`, `[Tool]`, and `[Output]` messages.
21+
- `[User]` remains as historical request context.
22+
- Details and Back callbacks remain bound to the completed run panel/card. After finalization, the panel's summary message id is the new `[Final]` message id.
23+
24+
## Consequences
25+
26+
- The operator receives fewer notifications while preserving alerts for run start, required Plan input, and run completion.
27+
- The completed-run surface is still one stable Final/Details message, but it is no longer the same Telegram message that previously held live commentary.
28+
- Old routes for deleted live commentary messages may remain in SQLite, but active callback routing uses the new Final card message id.
29+
- Cleanup failures for old live messages must not fail Final delivery.
30+
31+
## Non-goals
32+
33+
- This does not add per-chat notification profiles.
34+
- This does not make Telegram edits audible.
35+
- This does not change App Server protocol or Plan Mode routing.

docs/release/v0.2.5.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# v0.2.5 Release Notes
2+
3+
## Highlights
4+
5+
- Telegram notification noise is reduced: only `New run` (configurable), `[Plan]`, and `[Final]` use normal Telegram notifications.
6+
- `[Final]` is delivered as a new message and transient live cards are cleaned up best-effort after finalization.
7+
- Tool-only runs, such as a single long shell command with empty output, keep their current tool visible while running and expose the completed command in Details and Tools file.
8+
- `/default` and `/reply --default` can force the next Telegram-origin turn into App Server Default Mode when a thread remains in Plan Mode.
9+
- ADR-015 records the notification contract.
10+
11+
## Validation
12+
13+
- `go test ./internal/appserver ./internal/daemon ./internal/telegram`
14+
- `go test ./internal/telegram ./internal/config ./internal/daemon ./internal/storage ./tests`
15+
- `go test ./...`
16+
- `go build -buildvcs=false ./...`
17+
- `git diff --check`
18+
- Python compile for the live E2E harness
19+
- targeted secret/local scan
20+
- macOS LaunchAgent rebuild/restart
21+
- checked-in live Telegram E2E cases: `tool_only_sleep_details` and `notification_contract`
22+
23+
## Notes
24+
25+
- No App Server protocol changes were required.
26+
- No database migration is required.
27+
- `CTR_GO_NOTIFY_NEW_RUN=false` keeps the `New run` card visible but silent.
28+
- `v0.2.5` is a patch release on top of `v0.2.4`.

docs/research/contract-matrix.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ This file now serves two purposes:
1515
- `/projects`
1616
- `/show <thread>`
1717
- `/bind <thread>`
18-
- `/reply [--plan] <thread> <text>`
18+
- `/reply [--plan|--default] <thread> <text>`
19+
- `/default <thread> <text>`
20+
- `/default <text>`
1921
- `/plan <thread> <text>`
2022
- `/plan <text>`
2123
- `/plan_mode <thread> <text>`
@@ -53,9 +55,11 @@ This file now serves two purposes:
5355
- The summary panel owns `Stop` and `Steer`.
5456
- Tool/output stream messages do not carry buttons.
5557
- Final answers are delivered separately and expose `Получить полный лог`.
58+
- Telegram sends normal notifications only for `New run` (configurable through `CTR_GO_NOTIFY_NEW_RUN`), `[Plan]` prompt-cards, and `[Final]`; other bot messages are silent.
5659
- Plan Mode / waiting-input states create a separate routeable `[Plan]` prompt-card.
5760
- `[Plan]` buttons are structured-only: they come from Codex `choices/options/suggestions/responses`, never from bridge heuristics.
5861
- Telegram-originated Plan Mode starts use App Server `turn/start` with `collaborationMode.mode = plan`; prompt wording alone is not Plan Mode.
62+
- Telegram-originated Default Mode starts through `/default` and `/reply --default` use App Server `turn/start` with `collaborationMode.mode = default`, which is the operator escape hatch when a thread remains in Plan Mode.
5963
- `/model` and `/effort` are button menus backed by SQLite daemon state for Telegram-started collaboration-mode model settings.
6064
- After a model or reasoning-effort selection, the edited settings message removes inline choice buttons.
6165
- `/projects` groups cached non-Chat projects by normalized `cwd`, sorts projects by latest cached thread activity, shows latest Codex UI Chat previews, opens full Chats pagination through `Open Chats`, and never accepts arbitrary filesystem paths from Telegram.
@@ -135,6 +139,7 @@ Additional route rules:
135139
- reply-to `[Plan]` routes before binding and carries `thread_id`, `turn_id`, and `request_id` when available
136140
- real `request_id` Plan answers use App Server server-request response; synthetic Plan answers use `turn/steer`
137141
- `/reply --plan`, `/plan`, and `/plan_mode` carry an explicit Plan Mode start intent when they create a new turn
142+
- `/reply --default` and `/default` carry an explicit Default Mode start intent when they create a new turn
138143

139144
## Observer targets
140145

@@ -163,6 +168,7 @@ Observer/UI v2 presentation contract:
163168
- appears before `[User]` and summary/tool/output for new runs
164169
- carries source markers, source mode, and route metadata, but not run status
165170
- is deleted best-effort after finalization
171+
- uses normal Telegram notification only when `CTR_GO_NOTIFY_NEW_RUN` is enabled
166172
- user notice:
167173
- appears after `New run` for GUI/CLI runs and before summary/tool/output
168174
- remains after finalization as the historical request marker
@@ -171,14 +177,18 @@ Observer/UI v2 presentation contract:
171177
- carries project/thread source markers
172178
- owns live run status while active
173179
- carries action buttons such as `Stop` and `Steer`
180+
- is sent silently and deleted best-effort after finalization
174181
- tool/output message:
175182
- carries source markers
176183
- carries no buttons
177184
- is deleted best-effort after finalization
178185
- final-answer message:
179186
- carries source markers
180187
- carries on-demand `Получить полный лог`
188+
- is sent as a new message with a normal Telegram notification
189+
- becomes the panel summary message id for Details/Back callbacks
181190
- contains final answer/status without replaying completed commentary/tool/output transcript
191+
- exposes completed tool-only turns through Details as `Tool activity`
182192

183193
Minimal event payload expected by the Telegram layer:
184194

0 commit comments

Comments
 (0)