Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
3a9d25e
chore: default codex agents to mcp
jaromil Jan 31, 2026
afba8af
chore: codex mcp invariants
jaromil Jan 31, 2026
709e91a
docs: capture codex mcp transcript
jaromil Jan 31, 2026
02308b7
chore: choose mcp io adapter
jaromil Jan 31, 2026
c9a1169
chore: define mcp transcript rules
jaromil Jan 31, 2026
a6a389c
feat: add codex_mode to agents
jaromil Jan 31, 2026
aa9613b
feat: add stdio pty factory
jaromil Jan 31, 2026
08bb014
feat: add mcp pty adapter
jaromil Jan 31, 2026
9c02edb
feat: route codex mcp sessions
jaromil Jan 31, 2026
0a02e2d
feat: emit mcp notify signals
jaromil Jan 31, 2026
0ff9147
feat: make mcp prompt injection safe
jaromil Jan 31, 2026
5d3e457
test: cover mcp api paths
jaromil Jan 31, 2026
6b67183
docs: note codex mcp behavior
jaromil Jan 31, 2026
3be9d88
fix: normalize mcp input handling
jaromil Jan 31, 2026
7df4dd3
fix: normalize mcp output newlines
jaromil Jan 31, 2026
bf51070
feat: add text buffer module
jaromil Jan 31, 2026
658e32f
feat: add terminal text view
jaromil Jan 31, 2026
7092156
test: cover history hydration
jaromil Jan 31, 2026
0714413
feat: add prompt output segments
jaromil Jan 31, 2026
7a5da21
feat: decouple terminal socket
jaromil Jan 31, 2026
f470ec4
feat: remove xterm session view
jaromil Jan 31, 2026
5a1177e
feat: expose session ui config
jaromil Feb 1, 2026
4168baa
feat: handle carriage returns
jaromil Feb 1, 2026
8b86c73
test: add terminal text scroll test
jaromil Feb 1, 2026
80c781a
docs: update agent orientation
jaromil Feb 1, 2026
4fb92d6
feat: suppress prompt echo
jaromil Feb 1, 2026
5970108
feat: add session header controls
jaromil Feb 1, 2026
0e51e83
chore: move scroll control to header
jaromil Feb 1, 2026
a36b457
feat: add input resize handle
jaromil Feb 1, 2026
d014c82
chore: hide idle input scrollbar
jaromil Feb 1, 2026
c5af179
feat: add input font settings
jaromil Feb 1, 2026
ca2a517
feat: fit terminal view on mobile
jaromil Feb 1, 2026
70111dc
feat: route mcp notifications in read loop
jaromil Feb 1, 2026
fd9ffbc
feat: format mcp notifications in output
jaromil Feb 1, 2026
b4cfc7d
docs: clarify mcp notification envelope
jaromil Feb 1, 2026
c73dbbb
test: cover interleaved mcp notifications
jaromil Feb 1, 2026
9967e41
docs: mention mcp console output
jaromil Feb 1, 2026
30cbf2a
docs: refine mcp payload display plan
jaromil Feb 1, 2026
162eeea
feat: add log-codex-events setting
jaromil Feb 1, 2026
6c1e7dc
feat: log mcp events to file
jaromil Feb 1, 2026
7df6aed
chore: warn on missing mcp event log dir
jaromil Feb 1, 2026
2c3e799
docs: close mcp codex events plan
jaromil Feb 1, 2026
67282b2
fix: add shutdown coordinator ordering
jaromil Feb 1, 2026
3d6feca
fix: update shutdown signal handling
jaromil Feb 1, 2026
2c6ccc5
fix: add shutdown timeouts
jaromil Feb 1, 2026
8557921
fix: manage pty process groups
jaromil Feb 1, 2026
c89a05c
fix: close sessions on shutdown
jaromil Feb 1, 2026
97b7921
fix: add process registry
jaromil Feb 1, 2026
0db0831
test: assert shutdown phase order
jaromil Feb 1, 2026
4e73753
docs: add shutdown checklist
jaromil Feb 1, 2026
4beca5d
Isolate MCP stdio process group
jaromil Feb 3, 2026
d6f7a3a
Redirect MCP stdio stderr to stdout
jaromil Feb 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions .gestalt/plans/mcp-codex-events.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#+TITLE: MCP codex/event Notifications in Session Console
#+SUBTITLE: Display Codex MCP JSON-RPC event notifications in session output
#+DATE: 2026-02-01
#+KEYWORDS: mcp codex event json-rpc session console terminal

* DONE [#A] Store Codex MCP event notifications to file
Effort: M
Goal: Stop printing MCP notifications to the terminal and persist them to `.gestalt/sessions/Events-<session-name>-<date>`.
Notes: Logging must be opt-in via `session.log-codex-events` (default false).

** DONE [#A] Add config switch for codex event logging
Why: Logging should be configurable and default to off.
Change: Introduce `session.log-codex-events` in `config/gestalt.toml` (default false) and wire it through settings/options.
Tests: Extend settings/config tests to cover the new default.
Done when: Config key parses and defaults to false.

** DONE [#A] Write MCP notifications to file instead of terminal
Why: Users want events persisted without terminal noise.
Change: Add a session-scoped MCP event logger that writes NDJSON lines to `Events-<session-name>-<date>` in the session log dir. Update `mcpPty` notification handling to write to file when enabled and omit terminal output.
Tests: Add tests that notifications no longer surface in output, and that the event file receives the notification payload.
Done when: Events are quiet in the terminal and persisted when enabled.

** DONE [#B] Ensure cleanup and error handling for event logs
Why: Avoid file handle leaks and silent failures.
Change: Close the event logger on session/pty close and warn when logging is enabled but no session log dir is configured.
Tests: Add a close-path unit test if needed.
Done when: Event logging resources are cleaned up reliably.

* DONE [#A] Confirm scope + output UX for codex/event notifications
Effort: S
Goal: Lock output formatting, filtering, and any opt-in/opt-out behavior before implementation.
Notes: Keep basic functionality; no new dependencies; preserve existing session behavior.

** DONE [#A] Clarify formatting + filtering rules
Why: The console output is user-facing; we need a stable, minimal format that won’t flood or confuse.
Change: Use a consistent line prefix for all MCP notifications: `[mcp <method>]`. For `codex/event`, append best-effort `msg.type` and `msg.message` as `"[mcp codex/event] <type>: <message>"`. For other methods or missing fields, append a compact JSON string of params (truncated to a safe length) as `"[mcp <method>] <params>"`. Decision: show all MCP notifications in the console (not just codex/event). Meta fields (requestId/threadId) are omitted by default to reduce noise; include only if you want them surfaced later.\n\nProposed defaults (if you accept):\n- Example: `[mcp codex/event] task_started: generating response`\n- Example: `[mcp initialized] {\"capabilities\":{...}}`\n- Truncation: 512 chars after prefix, add `…` to indicate truncation.\n- No ANSI styling or colors.\nTests: N/A (decision).\nDone when: You confirm the proposed format or provide an alternative.

** DONE [#B] Confirm when events should appear
Why: Notifications can arrive while idle or during tool calls; current flow only surfaces events during awaits.
Change: Decide that codex/event notifications must be printed immediately upon receipt, even when no call is in flight.
Tests: N/A (decision).
Done when: We agree events must appear even when the session is idle.

* DONE [#A] Backend: route MCP notifications to session output
Effort: M
Goal: Ensure codex/event JSON-RPC notifications are surfaced in the session console reliably.
Notes: Keep implementation minimal; avoid over-engineering; reuse existing mcpPty output path.

** DONE [#A] Make readLoop handle notifications directly
Why: Notifications can arrive outside request/response waits; current flow only processes them when awaiting a response.
Change: In `internal/terminal/pty_mcp.go`, parse each NDJSON message and immediately call `handleNotification` when `Method` is set; only enqueue messages with `ID` to the response channel.
Tests: Add unit test that sends a codex/event notification without a pending request and verifies it is written to session output.
Done when: codex/event notifications show in session output even when no call is active.

** DONE [#A] Update handleNotification to always show notifications
Why: Current behavior only prints in debug mode, which hides notifications from users.
Change: Adjust `handleNotification` to always emit a line for all MCP notifications, using the format in the previous step. Keep existing parsing of `params.msg.type`/`params.msg.message` for codex/event as best-effort, and add a compact JSON fallback for other methods or missing fields. Truncate long params to a safe length.\nTests: Unit test that codex/event results in a readable line (format confirmed in Step 1), with best-effort parsing and a safe fallback; add a test for a non-codex notification line with truncation.\nDone when: MCP notifications are printed consistently regardless of debug settings and the output format matches the decision.

** DONE [#B] Define the notification contract used for formatting
Why: We need a minimal, documented expectation for event payload parsing to avoid brittle logic.
Change: Document (in code comments or docs) the expected `codex/event` params shape: `{ _meta: { requestId, threadId }, id, msg: { type, message } }`, and that parsing is best-effort.
Tests: N/A (documentation).
Done when: The expected event envelope and fallback behavior are captured.

* DONE [#B] Tests + validation
Effort: M
Goal: Prevent regressions and verify event visibility without impacting normal MCP responses.
Notes: Use existing MCP test helpers; keep tests small and deterministic.

** DONE [#B] Add notification output test for idle session
Why: Ensure notifications appear even when no tool call is pending.
Change: Extend `internal/terminal/pty_mcp_notify_test.go` (or add a new test) to inject a `codex/event` notification via the fake MCP server and assert the session output stream includes the formatted event line.
Tests: Unit test described above.
Done when: Test passes and fails without the new routing change.

** DONE [#B] Preserve response handling behavior
Why: Ensure requests still match responses and output remains stable.
Change: Add a small test (or extend existing ones) that interleaves a `codex/event` notification between request and response and verifies the response still completes and output includes both event line and assistant response.
Tests: Unit test in `internal/terminal/pty_mcp_test.go` or `internal/terminal/pty_mcp_notify_test.go`.
Done when: Both event output and normal response behavior are verified.

* DONE [#C] Rollout + docs (optional)
Effort: S
Goal: Ensure user expectations are captured without changing external APIs.
Notes: Optional unless you want explicit doc updates.

** DONE [#C] Update docs/notes if desired
Why: Make it discoverable that MCP event notifications appear in console output.
Change: Add a short note to `internal/codexmcp/README.md` or a relevant docs file about codex/event output formatting.
Tests: N/A.
Done when: Documentation reflects the new behavior.

* DONE [#A] Open questions
Effort: S
Goal: Resolve ambiguities before implementation.
Notes: These block final design.

** DONE [#A] Confirm display format and verbosity
Why: Avoid user confusion or log spam.
Change: Provide your preferred line format and whether to include meta (requestId/threadId), plus whether to show non-codex notifications.
Tests: N/A.
Done when: You confirm the final display rules.

** DONE [#B] Confirm whether events should also emit to notify/workflow bus
Why: You might want codex/event to feed workflows or logs, not just console output.
Change: Decision: console-only for now; do not emit MCP notifications to notify/workflow buses.
Tests: N/A.
Done when: Scope captured (console-only).
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Use this as the minimum context to start any plan task.
- `internal/skill`: skill metadata/loader, prompt XML.
- `internal/watcher`: fsnotify watcher, event bus helpers, git branch monitoring.
- `internal/logging`: structured logs + buffer.
- Frontend: `frontend/src/App.svelte` tabs; `frontend/src/views/Dashboard.svelte` agents/sessions; `frontend/src/lib/terminalStore.js` xterm + WS; `frontend/src/lib/eventStore.js` `/ws/events`.
- Frontend: `frontend/src/App.svelte` tabs; `frontend/src/views/Dashboard.svelte` agents/sessions; `frontend/src/lib/terminalStore.js` text stream + WS; `frontend/src/lib/eventStore.js` `/ws/events`.
- CLI: `cmd/gestalt-send` pipes stdin to agent sessions over REST.

## Runtime flow (high level)
Expand Down Expand Up @@ -64,7 +64,7 @@ Use this as the minimum context to start any plan task.
```
filesystem -> watcher_events -> /ws/events -> frontend eventStore -> UI
agent/session/workflow/config -> Manager/handlers -> /api/*/events -> frontend stores -> UI
terminal output -> Session output bus -> /ws/session/:id -> xterm
terminal output -> Session output bus -> /ws/session/:id -> frontend text view
```
- Testing: `internal/event/testing.go` helpers (`MockBus`, `EventCollector`, `ReceiveWithTimeout`, `MatchEvent`).

Expand Down Expand Up @@ -102,7 +102,7 @@ terminal output -> Session output bus -> /ws/session/:id -> xterm

## Frontend store simplification notes
- Dashboard orchestration (agent/config/git event handling, config extraction counts, git context) lives in `frontend/src/lib/dashboardStore.js`; Dashboard view now just binds store state.
- Terminal input helpers have direct tests in `frontend/src/lib/terminal/input.test.js`.
- Terminal text stream behavior is covered by `frontend/src/lib/terminal/segments.test.js` and `frontend/src/components/TerminalTextView.test.js`.

## Plan UI notes
- Plans are served via `/api/plans` (metadata + headings) from `.gestalt/plans/`; PlanView renders PlanCard details/summary and refreshes on file change events.
Expand Down
1 change: 1 addition & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Coverage targets:
## Test patterns in this repo

- Fake PTYs: `internal/api/rest_test.go`, `internal/terminal/manager_test.go`.
- MCP stdio fakes: `internal/api/mcp_test_helpers_test.go`, `internal/terminal/pty_mcp_test.go` (no Codex binary required).
- Table-driven tests: `internal/agent/agent_test.go`, `internal/terminal/shell_test.go`.
- Integration helpers: websocket harnesses in `internal/api/*_integration_test.go`.

Expand Down
Loading
Loading