Skip to content

feat(workspace, cli): Add per-session parallel conversation tracking#493

Open
JeanMertz wants to merge 6 commits intomainfrom
prr60
Open

feat(workspace, cli): Add per-session parallel conversation tracking#493
JeanMertz wants to merge 6 commits intomainfrom
prr60

Conversation

@JeanMertz
Copy link
Copy Markdown
Collaborator

@JeanMertz JeanMertz commented Mar 31, 2026

See: https://jp.computer/rfd/020-parallel-conversations

Each terminal session now independently tracks its active conversation. Two tabs in the same workspace can run queries simultaneously without interfering with each other.

Session identity is resolved automatically: getsid(0) on Unix, GetConsoleWindow() on Windows, terminal env vars ($TMUX_PANE, $WEZTERM_PANE, etc.) as fallback, with $JP_SESSION for explicit override. Mappings are stored in user-local data so each session's state persists across invocations.

Conversations are protected by OS-level advisory locks (flock on Unix, LockFileEx on Windows) for the duration of a jp query. When a lock is contended, the command polls up to 30 seconds (overridable via $JP_LOCK_DURATION) then shows an interactive prompt:

  • Continue waiting
  • Start a new conversation
  • Fork this conversation
  • Cancel

The global "active conversation" concept is removed entirely. All conversation targeting is now session-scoped.

New targeting keywords are available across all conversation commands:

jp query --id last      # most recently activated conversation
jp query --id prev      # session's previous conversation
jp query --id <id>      # specific conversation
jp query --id           # interactive picker
jp query --fork         # fork the session's active conversation
jp query --fork=2       # fork keeping last 2 turns

A conversation.default_id config field controls the fallback when no session mapping exists yet (default: ask — picker or error).

The terminal title is updated via OSC 2 when a conversation is resolved and again when the title generator task completes, so each tab shows which conversation it is working on.

Internally, the workspace API is rebuilt around ConversationHandle (proof of existence) and ConversationLock / ConversationMut (guard-scoped persistence, per RFD 069). Conversation data persists automatically on ConversationMut drop while the cross-process lock is held. jp_tombmap is removed in favor of HashMap + OnceLock + Arc<RwLock>. Config loading is refactored into a two-phase ConfigPipeline: static sources (files + env + --cfg) are resolved once, then optionally merged with per-conversation config, this allows the pre-startup phase to read the conversation.default_id config.

Closes: #198

Each terminal session now independently tracks its active conversation.
Two tabs in the same workspace can run queries simultaneously without
interfering with each other.

Session identity is resolved automatically: `getsid(0)` on Unix,
`GetConsoleWindow()` on Windows, terminal env vars (`$TMUX_PANE`,
`$WEZTERM_PANE`, etc.) as fallback, with `$JP_SESSION` for explicit
override. Mappings are stored in user-local data so each session's state
persists across invocations.

Conversations are protected by OS-level advisory locks (`flock` on Unix,
`LockFileEx` on Windows) for the duration of a `jp query`. When a lock
is contended, the command polls up to 30 seconds (overridable via
`$JP_LOCK_DURATION`) then shows an interactive prompt:

  - Continue waiting
  - Start a new conversation
  - Fork this conversation
  - Cancel

The global "active conversation" concept is removed entirely. All
conversation targeting is now session-scoped.

New targeting keywords are available across all conversation commands:

  jp query --id last      # most recently activated conversation
  jp query --id prev      # session's previous conversation
  jp query --id <id>      # specific conversation
  jp query --id           # interactive picker
  jp query --fork         # fork the session's active conversation
  jp query --fork=2       # fork keeping last 2 turns

A `conversation.default_id` config field controls the fallback when no
session mapping exists yet (default: `ask` — picker or error).

The terminal title is updated via OSC 2 when a conversation is resolved
and again when the title generator task completes, so each tab shows
which conversation it is working on.

Internally, the workspace API is rebuilt around `ConversationHandle`
(proof of existence) and `ConversationLock` / `ConversationMut`
(guard-scoped persistence, per RFD 069). Conversation data persists
automatically on `ConversationMut` drop while the cross-process lock is
held. `jp_tombmap` is removed in favor of `HashMap` + `OnceLock` +
`Arc<RwLock>`. Config loading is refactored into a two-phase
`ConfigPipeline`: static sources (files + env + `--cfg`) are resolved
once, then optionally merged with per-conversation config, this allows
the pre-startup phase to read the `conversation.default_id` config.

Closes: #198
Signed-off-by: Jean Mertz <git@jeanmertz.com>
…acking

Signed-off-by: Jean Mertz <git@jeanmertz.com>
…acking

Signed-off-by: Jean Mertz <git@jeanmertz.com>
…acking

Signed-off-by: Jean Mertz <git@jeanmertz.com>
…acking

Signed-off-by: Jean Mertz <git@jeanmertz.com>
…acking

Signed-off-by: Jean Mertz <git@jeanmertz.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support multiple concurrent conversations in different sessions

1 participant