taskplane 0.23.16 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -98,9 +98,9 @@ export const SECTIONS: SectionDef[] = [
98
98
  { configPath: "orchestrator.orchestrator.worktreeLocation", label: "Worktree Location", control: "toggle", layer: "L1", fieldType: "enum", values: ["sibling", "subdirectory"], description: "Where lane worktree directories are created" },
99
99
  { configPath: "orchestrator.orchestrator.worktreePrefix", label: "Worktree Prefix", control: "input", layer: "L1", fieldType: "string", description: "Prefix for worktree directory names" },
100
100
  { configPath: "orchestrator.orchestrator.batchIdFormat", label: "Batch ID Format", control: "toggle", layer: "L1", fieldType: "enum", values: ["timestamp", "sequential"], description: "Batch ID format for logs/branch naming" },
101
- // spawn_mode removed from Orchestrator section — /orch always requires tmux.
101
+ // spawn_mode removed from Orchestrator section — Runtime V2 is subprocess-only.
102
102
  // The user-facing spawn mode setting is under Worker (controls /task behavior).
103
- { configPath: "orchestrator.orchestrator.tmuxPrefix", label: "Tmux Prefix", control: "input", layer: "L1+L2", fieldType: "string", prefsKey: "tmuxPrefix", description: "Prefix for orchestrator tmux sessions" },
103
+ { configPath: "orchestrator.orchestrator.sessionPrefix", label: "Session Prefix", control: "input", layer: "L1+L2", fieldType: "string", prefsKey: "sessionPrefix", description: "Prefix for orchestrator session names" },
104
104
  { configPath: "orchestrator.orchestrator.operatorId", label: "Operator ID", control: "input", layer: "L1+L2", fieldType: "string", prefsKey: "operatorId", description: "Operator identifier (empty = auto-detect)" },
105
105
  { configPath: "orchestrator.orchestrator.integration", label: "Integration", control: "toggle", layer: "L1", fieldType: "enum", values: ["manual", "supervised", "auto"], description: "How completed batches are integrated. manual = user runs /orch-integrate. supervised = supervisor proposes plan, asks confirmation. auto = supervisor executes without asking." },
106
106
  ],
@@ -162,7 +162,7 @@ export const SECTIONS: SectionDef[] = [
162
162
  { configPath: "taskRunner.worker.model", label: "Worker Model", control: "input", layer: "L1+L2", fieldType: "string", prefsKey: "workerModel", description: "Worker model (empty = inherit session)" },
163
163
  { configPath: "taskRunner.worker.tools", label: "Worker Tools", control: "input", layer: "L1", fieldType: "string", description: "Worker tool allowlist" },
164
164
  { configPath: "taskRunner.worker.thinking", label: "Worker Thinking", control: "input", layer: "L1", fieldType: "string", description: "Worker thinking mode" },
165
- { configPath: "taskRunner.worker.spawnMode", label: "Spawn Mode", control: "toggle", layer: "L1", fieldType: "enum", values: ["subprocess", "tmux"], description: "How /task spawns workers and reviewers. subprocess = child process (simpler), tmux = named sessions (attachable for debugging)" },
165
+ { configPath: "taskRunner.worker.spawnMode", label: "Spawn Mode", control: "toggle", layer: "L1", fieldType: "enum", values: ["subprocess"], optional: true, description: "How /task spawns workers and reviewers. Runtime V2 supports subprocess only." },
166
166
  ],
167
167
  },
168
168
  {
@@ -625,7 +625,7 @@ export function detectFieldSource(
625
625
  } else if (field.fieldType === "enum") {
626
626
  // Enum rule: must be a valid enum value from the field's values array.
627
627
  // Matches extractAllowlistedPreferences which checks exact enum membership
628
- // (e.g., raw.spawnMode === "tmux" || raw.spawnMode === "subprocess").
628
+ // (e.g., raw.spawnMode === "subprocess").
629
629
  if (prefVal !== undefined && field.values && field.values.includes(String(prefVal))) return "user";
630
630
  } else if (field.fieldType === "number") {
631
631
  // Number rule: must be typeof number and finite → (user)
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Migration-only helpers for legacy TMUX-shaped persisted lane fields.
3
+ *
4
+ * Runtime V2 no longer accepts TMUX config/runtime contracts. The only
5
+ * compatibility retained here is one-release state ingress normalization for
6
+ * `lanes[].tmuxSessionName` → `lanes[].laneSessionId`.
7
+ */
8
+
9
+ export interface LaneSessionAliasTarget {
10
+ laneSessionId?: unknown;
11
+ tmuxSessionName?: unknown;
12
+ }
13
+
14
+ /**
15
+ * Read canonical + legacy lane session fields from a lane-like record.
16
+ */
17
+ export function readLaneSessionAliases(target: LaneSessionAliasTarget): {
18
+ laneSessionId: unknown;
19
+ tmuxSessionName: unknown;
20
+ } {
21
+ return {
22
+ laneSessionId: target.laneSessionId,
23
+ tmuxSessionName: target.tmuxSessionName,
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Normalize tmuxSessionName -> laneSessionId in place and remove legacy key.
29
+ */
30
+ export function normalizeLaneSessionAlias(target: LaneSessionAliasTarget): void {
31
+ if (typeof target.laneSessionId !== "string" && typeof target.tmuxSessionName === "string") {
32
+ target.laneSessionId = target.tmuxSessionName;
33
+ }
34
+ if ("tmuxSessionName" in target) {
35
+ delete target.tmuxSessionName;
36
+ }
37
+ }
@@ -14,8 +14,8 @@ export interface OrchestratorConfig {
14
14
  worktree_location: "sibling" | "subdirectory";
15
15
  worktree_prefix: string;
16
16
  batch_id_format: "timestamp" | "sequential";
17
- spawn_mode: "tmux" | "subprocess";
18
- tmux_prefix: string;
17
+ spawn_mode: "subprocess";
18
+ sessionPrefix: string;
19
19
  /** Optional operator identifier. Auto-detected from OS username if empty. */
20
20
  operator_id: string;
21
21
  /** How completed batches are integrated. manual = user runs /orch-integrate. supervised = supervisor proposes plan, asks confirmation. auto = supervisor executes without asking. */
@@ -260,7 +260,7 @@ export const DEFAULT_ORCHESTRATOR_CONFIG: OrchestratorConfig = {
260
260
  worktree_prefix: "taskplane-wt",
261
261
  batch_id_format: "timestamp",
262
262
  spawn_mode: "subprocess",
263
- tmux_prefix: "orch",
263
+ sessionPrefix: "orch",
264
264
  operator_id: "",
265
265
  integration: "manual",
266
266
  },
@@ -608,7 +608,7 @@ export interface AllocatedTask {
608
608
  /**
609
609
  * A fully-allocated lane ready for execution.
610
610
  *
611
- * Contains everything Steps 2-3 need to spawn TMUX sessions,
611
+ * Contains everything Steps 2-3 need to run lane sessions,
612
612
  * monitor progress, and identify the lane. This is the contract
613
613
  * between Step 1 (allocation) and Step 2 (execution).
614
614
  */
@@ -617,8 +617,8 @@ export interface AllocatedLane {
617
617
  laneNumber: number;
618
618
  /** Lane identifier for display and logging (e.g., "lane-1") */
619
619
  laneId: string;
620
- /** TMUX session naming seed (e.g., "orch-lane-1") — used by Step 2 */
621
- tmuxSessionName: string;
620
+ /** Lane session identifier (e.g., "orch-lane-1") — used by Step 2 */
621
+ laneSessionId: string;
622
622
  /** Absolute path to the lane's worktree directory */
623
623
  worktreePath: string;
624
624
  /** Git branch name checked out in the worktree */
@@ -690,7 +690,7 @@ export interface LaneTaskOutcome {
690
690
  endTime: number | null;
691
691
  /** Human-readable reason for the outcome */
692
692
  exitReason: string;
693
- /** TMUX session name used for this task (e.g., "orch-lane-1") */
693
+ /** Lane session name used for this task (e.g., "orch-lane-1") */
694
694
  sessionName: string;
695
695
  /** Whether .DONE file was found */
696
696
  doneFileFound: boolean;
@@ -758,7 +758,7 @@ export interface LaneExecutionResult {
758
758
  // ── Execution Constants ──────────────────────────────────────────────
759
759
 
760
760
  /**
761
- * Grace period (ms) after TMUX session exits before declaring failure.
761
+ * Grace period (ms) after a lane session exits before declaring failure.
762
762
  * Allows time for .DONE file to be flushed to disk on slow filesystems.
763
763
  */
764
764
  export const DONE_GRACE_MS = 5_000;
@@ -769,7 +769,7 @@ export const DONE_GRACE_MS = 5_000;
769
769
  export const EXECUTION_POLL_INTERVAL_MS = 2_000;
770
770
 
771
771
  /**
772
- * Maximum retries for TMUX session spawn failures.
772
+ * Maximum retries for legacy lane-session spawn failures.
773
773
  * Only transient failures (session name collision) are retried.
774
774
  */
775
775
  export const SESSION_SPAWN_RETRY_MAX = 2;
@@ -779,12 +779,12 @@ export const SESSION_SPAWN_RETRY_MAX = 2;
779
779
  /**
780
780
  * Error codes for lane execution failures.
781
781
  *
782
- * - EXEC_SPAWN_FAILED: TMUX session could not be created after retries
782
+ * - EXEC_SPAWN_FAILED: Lane session could not be created after retries
783
783
  * - EXEC_TASK_FAILED: task completed without .DONE (non-zero exit)
784
784
  * - EXEC_TASK_STALLED: STATUS.md unchanged for stall_timeout (handled by Step 3)
785
785
  * - EXEC_TASK_STAGE_FAILED: git add failed for task files
786
786
  * - EXEC_TASK_COMMIT_FAILED: git commit failed for staged task files
787
- * - EXEC_TMUX_NOT_AVAILABLE: tmux binary not found
787
+ * - EXEC_TMUX_NOT_AVAILABLE: Legacy `tmux` binary not found (compat path)
788
788
  * - EXEC_WORKTREE_MISSING: lane worktree path doesn't exist
789
789
  */
790
790
  export type ExecutionErrorCode =
@@ -819,7 +819,7 @@ export class ExecutionError extends Error {
819
819
  *
820
820
  * Produced by `resolveTaskMonitorState()` from combining:
821
821
  * - .DONE file presence
822
- * - TMUX session liveness
822
+ * - Lane-session liveness
823
823
  * - STATUS.md parse results
824
824
  * - STATUS.md mtime for stall detection
825
825
  */
@@ -838,7 +838,7 @@ export interface TaskMonitorSnapshot {
838
838
  totalChecked: number;
839
839
  /** Total checkbox count across all steps */
840
840
  totalItems: number;
841
- /** Whether the TMUX session is alive */
841
+ /** Whether the lane session is alive */
842
842
  sessionAlive: boolean;
843
843
  /** Whether the .DONE file was found */
844
844
  doneFileFound: boolean;
@@ -864,9 +864,9 @@ export interface LaneMonitorSnapshot {
864
864
  laneId: string;
865
865
  /** Lane number (1-indexed) */
866
866
  laneNumber: number;
867
- /** TMUX session name (e.g., "orch-lane-1") */
867
+ /** Lane session name (e.g., "orch-lane-1") */
868
868
  sessionName: string;
869
- /** Whether the TMUX session is alive right now */
869
+ /** Whether the lane session is alive right now */
870
870
  sessionAlive: boolean;
871
871
  /** Current task being executed (null if lane is idle/complete) */
872
872
  currentTaskId: string | null;
@@ -943,7 +943,7 @@ export interface MtimeTracker {
943
943
  * - monitorLanes() runs as sibling async loop, can kill stalled sessions
944
944
  * - executeWave() coordinates both and applies policy
945
945
  * - Monitor's stall-kill does NOT conflict with executeLane() because
946
- * executeLane() polls tmux session status and will see the killed session
946
+ * executeLane() polls session liveness and will see the killed session
947
947
  */
948
948
 
949
949
  /**
@@ -1089,7 +1089,7 @@ export interface OrchBatchRuntimeState {
1089
1089
  * Session registry entry for /orch-sessions command.
1090
1090
  */
1091
1091
  export interface OrchestratorSessionEntry {
1092
- /** TMUX session name (e.g., "orch-lane-1") */
1092
+ /** Lane session name (e.g., "orch-lane-1") */
1093
1093
  sessionName: string;
1094
1094
  /** Lane ID (e.g., "lane-1") */
1095
1095
  laneId: string;
@@ -1339,9 +1339,9 @@ export interface TransactionRecord {
1339
1339
  /**
1340
1340
  * Error codes for merge operations.
1341
1341
  *
1342
- * - MERGE_SPAWN_FAILED: Could not create TMUX session for merge agent
1342
+ * - MERGE_SPAWN_FAILED: Could not create merge-agent session
1343
1343
  * - MERGE_TIMEOUT: Merge agent did not produce result within timeout
1344
- * - MERGE_SESSION_DIED: TMUX session exited without writing result
1344
+ * - MERGE_SESSION_DIED: Merge-agent session exited without writing result
1345
1345
  * - MERGE_RESULT_INVALID: Result file exists but contains invalid JSON
1346
1346
  * - MERGE_RESULT_MISSING_FIELDS: Result JSON missing required fields
1347
1347
  * - MERGE_UNKNOWN_STATUS: Result has an unrecognized status value
@@ -1384,7 +1384,7 @@ export const MERGE_TIMEOUT_MS = 90 * 60 * 1000;
1384
1384
  export const MERGE_POLL_INTERVAL_MS = 2_000;
1385
1385
 
1386
1386
  /**
1387
- * Grace period after TMUX session exits before declaring failure (ms).
1387
+ * Grace period after a merge-agent session exits before declaring failure (ms).
1388
1388
  * Allows for slow disk flush of the result file.
1389
1389
  */
1390
1390
  export const MERGE_RESULT_GRACE_MS = 3_000;
@@ -1401,7 +1401,7 @@ export const MERGE_RESULT_READ_RETRIES = 3;
1401
1401
  export const MERGE_RESULT_READ_RETRY_DELAY_MS = 1_000;
1402
1402
 
1403
1403
  /**
1404
- * Maximum retries for TMUX session spawn during merge.
1404
+ * Maximum retries for merge-agent session spawn.
1405
1405
  */
1406
1406
  export const MERGE_SPAWN_RETRY_MAX = 2;
1407
1407
 
@@ -1442,7 +1442,7 @@ export const MERGE_HEALTH_WARNING_THRESHOLD_MS = 10 * 60 * 1000; // 10 minutes
1442
1442
  export const MERGE_HEALTH_STUCK_THRESHOLD_MS = 20 * 60 * 1000; // 20 minutes
1443
1443
 
1444
1444
  /**
1445
- * Number of lines to capture from the bottom of a tmux pane
1445
+ * Number of lines to capture from recent merge output snapshots
1446
1446
  * for activity detection via snapshot comparison.
1447
1447
  * @since TP-056
1448
1448
  */
@@ -1529,7 +1529,7 @@ export interface MergeSessionSnapshot {
1529
1529
  * @since TP-056
1530
1530
  */
1531
1531
  export interface MergeSessionHealthState {
1532
- /** TMUX session name */
1532
+ /** Merge session name */
1533
1533
  sessionName: string;
1534
1534
  /** Lane number this session belongs to */
1535
1535
  laneNumber: number;
@@ -1899,7 +1899,7 @@ export interface EngineEvent {
1899
1899
 
1900
1900
  // ── Merge health monitoring fields (TP-056) ──────────────────
1901
1901
 
1902
- /** TMUX session name (for merge_health_* events) */
1902
+ /** Merge session name (for merge_health_* events) */
1903
1903
  sessionName?: string;
1904
1904
  /** Merge health status classification (for merge_health_* events) */
1905
1905
  healthStatus?: MergeHealthStatus;
@@ -2223,7 +2223,7 @@ export interface OrchDashboardViewModel {
2223
2223
  elapsed: string; // e.g., "2m 14s"
2224
2224
  summary: OrchSummaryCounts;
2225
2225
  laneCards: OrchLaneCardData[];
2226
- attachHint: string; // e.g., "tmux attach -t orch-lane-1"
2226
+ attachHint: string; // e.g., "Attach via the current runtime session tool"
2227
2227
  errors: string[];
2228
2228
  failurePolicy: string | null; // e.g., "stop-wave" if stopped by policy
2229
2229
  }
@@ -2457,7 +2457,7 @@ export interface PersistedTaskRecord {
2457
2457
  taskId: string;
2458
2458
  /** Lane number the task was assigned to (1-indexed) */
2459
2459
  laneNumber: number;
2460
- /** TMUX session name used (e.g., "orch-lane-1") */
2460
+ /** Lane session name used (e.g., "orch-lane-1") */
2461
2461
  sessionName: string;
2462
2462
  /** Current task status */
2463
2463
  status: LaneTaskStatus;
@@ -2574,7 +2574,7 @@ export interface PersistedSegmentRecord {
2574
2574
  status: PersistedSegmentStatus;
2575
2575
  /** Lane ID the segment executed on (e.g., "lane-1"), empty if not yet assigned */
2576
2576
  laneId: string;
2577
- /** TMUX session name used for this segment */
2577
+ /** Lane session name used for this segment */
2578
2578
  sessionName: string;
2579
2579
  /** Absolute path to the worktree used for this segment */
2580
2580
  worktreePath: string;
@@ -2627,8 +2627,8 @@ export interface PersistedLaneRecord {
2627
2627
  laneNumber: number;
2628
2628
  /** Lane identifier (e.g., "lane-1") */
2629
2629
  laneId: string;
2630
- /** TMUX session name (e.g., "orch-lane-1") */
2631
- tmuxSessionName: string;
2630
+ /** Lane session identifier (e.g., "orch-lane-1") */
2631
+ laneSessionId: string;
2632
2632
  /** Absolute path to the lane's worktree directory */
2633
2633
  worktreePath: string;
2634
2634
  /** Git branch name checked out in the worktree */
@@ -2809,7 +2809,7 @@ export interface PersistedBatchState {
2809
2809
  * - RESUME_INVALID_STATE: State file exists but cannot be parsed/validated
2810
2810
  * - RESUME_SCHEMA_MISMATCH: State file has incompatible schema version
2811
2811
  * - RESUME_PHASE_NOT_RESUMABLE: Persisted phase does not allow resume
2812
- * - RESUME_TMUX_UNAVAILABLE: TMUX is not available for session reconnection
2812
+ * - RESUME_TMUX_UNAVAILABLE: Legacy session backend is unavailable for reconnection
2813
2813
  * - RESUME_EXECUTION_FAILED: Resume reconciliation succeeded but execution failed
2814
2814
  */
2815
2815
  export type ResumeErrorCode =
@@ -2834,7 +2834,7 @@ export class ResumeError extends Error {
2834
2834
  /**
2835
2835
  * Result of reconciling a single task's persisted state against live signals.
2836
2836
  *
2837
- * Combines persisted status, tmux session liveness, and .DONE file presence
2837
+ * Combines persisted status, lane-session liveness, and .DONE file presence
2838
2838
  * into a deterministic action for the resume engine.
2839
2839
  *
2840
2840
  * Reconciliation precedence (highest → lowest):
@@ -2850,7 +2850,7 @@ export interface ReconciledTaskState {
2850
2850
  persistedStatus: LaneTaskStatus;
2851
2851
  /** Reconciled live status after checking signals */
2852
2852
  liveStatus: LaneTaskStatus;
2853
- /** Whether the TMUX session is alive right now */
2853
+ /** Whether the lane session is alive right now */
2854
2854
  sessionAlive: boolean;
2855
2855
  /** Whether the .DONE file was found */
2856
2856
  doneFileFound: boolean;
@@ -2913,9 +2913,9 @@ export type AbortMode = "graceful" | "hard";
2913
2913
  /**
2914
2914
  * Error codes for abort operations.
2915
2915
  *
2916
- * - ABORT_TMUX_LIST_FAILED: Could not list TMUX sessions
2916
+ * - ABORT_TMUX_LIST_FAILED: Could not list legacy session records
2917
2917
  * - ABORT_WRAPUP_WRITE_FAILED: Failed to write wrap-up signal file(s)
2918
- * - ABORT_KILL_FAILED: Failed to kill one or more TMUX sessions
2918
+ * - ABORT_KILL_FAILED: Failed to kill one or more lane sessions
2919
2919
  * - ABORT_STATE_DELETE_FAILED: Failed to delete batch-state.json
2920
2920
  */
2921
2921
  export type AbortErrorCode =
@@ -2928,7 +2928,7 @@ export type AbortErrorCode =
2928
2928
  * Per-lane result from an abort operation.
2929
2929
  */
2930
2930
  export interface AbortLaneResult {
2931
- /** TMUX session name */
2931
+ /** Lane session name */
2932
2932
  sessionName: string;
2933
2933
  /** Lane ID (e.g., "lane-1") or "unknown" */
2934
2934
  laneId: string;
@@ -2983,7 +2983,7 @@ export type AbortActionStep =
2983
2983
  * Target session with enrichment from persisted state.
2984
2984
  */
2985
2985
  export interface AbortTargetSession {
2986
- /** TMUX session name */
2986
+ /** Lane session name */
2987
2987
  sessionName: string;
2988
2988
  /** Lane ID from persisted state or "unknown" */
2989
2989
  laneId: string;
@@ -3495,12 +3495,12 @@ export interface WriteMailboxMessageOpts {
3495
3495
 
3496
3496
  // ── Runtime V2 Contracts (TP-102) ────────────────────────────────────
3497
3497
  //
3498
- // These types define the foundational contracts for the no-TMUX Runtime V2
3498
+ // These types define the foundational contracts for backend-neutral Runtime V2
3499
3499
  // architecture. They are additive — existing runtime paths continue to work
3500
3500
  // while Runtime V2 is incrementally adopted.
3501
3501
  //
3502
3502
  // Design principles:
3503
- // 1. Agent identity is a stable runtime ID, not a TMUX session name.
3503
+ // 1. Agent identity is a stable runtime ID, not a legacy session name.
3504
3504
  // 2. Packet-path authority is explicit, never inferred from cwd.
3505
3505
  // 3. Process ownership uses a registry, not terminal session discovery.
3506
3506
  // 4. Normalized events flow directly from child to parent.
@@ -3546,13 +3546,13 @@ export const TERMINAL_AGENT_STATUSES: ReadonlySet<RuntimeAgentStatus> = new Set(
3546
3546
  /**
3547
3547
  * Stable agent identity for Runtime V2.
3548
3548
  *
3549
- * This replaces TMUX session names as the canonical identifier for a
3549
+ * This replaces legacy session names as the canonical identifier for a
3550
3550
  * spawned agent process. The string format is deliberately compatible
3551
3551
  * with existing naming conventions (e.g., "orch-henrylach-lane-1-worker")
3552
3552
  * to minimize churn in supervisor tools, dashboard, and mailbox addressing.
3553
3553
  *
3554
3554
  * The key semantic change: this is a **runtime process ID**, not a terminal
3555
- * session name. Code must not assume `tmuxHasSession(agentId)` is valid.
3555
+ * session label. Code must not assume terminal-session probes apply to RuntimeAgentId.
3556
3556
  *
3557
3557
  * @since TP-102
3558
3558
  */
@@ -3645,7 +3645,7 @@ export interface ExecutionUnit {
3645
3645
  * the agent is considered visible. Updated on status transitions and
3646
3646
  * cleaned up on batch completion.
3647
3647
  *
3648
- * Replaces TMUX session discovery as the source of truth for agent
3648
+ * Replaces legacy session discovery as the source of truth for agent
3649
3649
  * liveness, identity, and attribution.
3650
3650
  *
3651
3651
  * File location: `.pi/runtime/{batchId}/agents/{agentId}/manifest.json`
@@ -3684,7 +3684,7 @@ export interface RuntimeAgentManifest {
3684
3684
  *
3685
3685
  * Contains all active and recently-exited agents for one batch.
3686
3686
  * The authoritative source of truth for which agents exist, replacing
3687
- * TMUX session discovery.
3687
+ * legacy session discovery.
3688
3688
  *
3689
3689
  * File location: `.pi/runtime/{batchId}/registry.json`
3690
3690
  *
@@ -3918,7 +3918,7 @@ export function runtimeRegistryPath(stateRoot: string, batchId: string): string
3918
3918
  *
3919
3919
  * Produces IDs compatible with the existing naming convention
3920
3920
  * (e.g., "orch-henrylach-lane-1-worker") while semantically
3921
- * decoupling them from TMUX session names.
3921
+ * decoupling them from legacy session names.
3922
3922
  *
3923
3923
  * @param prefix - Operator/batch prefix (e.g., "orch-henrylach")
3924
3924
  * @param laneNumber - Lane number (null for merge agents)
@@ -488,7 +488,7 @@ export function generateLaneId(laneLocalNumber: number, repoId?: string): string
488
488
  }
489
489
 
490
490
  /**
491
- * Generate a TMUX session name for a lane.
491
+ * Generate a lane session identifier for a lane.
492
492
  *
493
493
  * Includes the operator identifier (`opId`) for collision resistance
494
494
  * across concurrent operators on the same machine.
@@ -496,20 +496,20 @@ export function generateLaneId(laneLocalNumber: number, repoId?: string): string
496
496
  * - Repo mode: `"{prefix}-{opId}-lane-{N}"` — operator-scoped
497
497
  * - Workspace mode: `"{prefix}-{opId}-{repoId}-lane-{N}"` — operator + repo scoped
498
498
  *
499
- * TMUX session names must not contain periods or colons. Both `opId`
499
+ * Session identifiers must not contain periods or colons. Both `opId`
500
500
  * and `repoId` are assumed to be sanitized identifiers (alphanumeric
501
501
  * + hyphens only).
502
502
  *
503
- * @param tmuxPrefix - TMUX prefix from config (e.g., "orch")
503
+ * @param sessionPrefix - Session prefix from config (e.g., "orch")
504
504
  * @param laneLocalNumber - Lane number within the repo group (1-indexed)
505
505
  * @param opId - Operator identifier (sanitized, e.g., "henrylach")
506
506
  * @param repoId - Repo identifier (undefined in repo mode)
507
507
  */
508
- export function generateTmuxSessionName(tmuxPrefix: string, laneLocalNumber: number, opId: string, repoId?: string): string {
508
+ export function generateLaneSessionId(sessionPrefix: string, laneLocalNumber: number, opId: string, repoId?: string): string {
509
509
  if (repoId) {
510
- return `${tmuxPrefix}-${opId}-${repoId}-lane-${laneLocalNumber}`;
510
+ return `${sessionPrefix}-${opId}-${repoId}-lane-${laneLocalNumber}`;
511
511
  }
512
- return `${tmuxPrefix}-${opId}-lane-${laneLocalNumber}`;
512
+ return `${sessionPrefix}-${opId}-lane-${laneLocalNumber}`;
513
513
  }
514
514
 
515
515
 
@@ -1069,8 +1069,9 @@ export function validateAllocationInputs(
1069
1069
  * newly-created lanes in this call are rolled back.
1070
1070
  *
1071
1071
  * 4. **Build AllocatedLane[]** — each lane gets repo-aware `laneId` and
1072
- * `tmuxSessionName`. In workspace mode: `"api/lane-1"`, `"orch-api-lane-1"`.
1073
- * In repo mode: `"lane-1"`, `"orch-lane-1"` (unchanged).
1072
+ * `laneSessionId`. In workspace mode: `"api/lane-1"`, `"orch-api-lane-1"`.
1073
+ * In repo mode: `"lane-1"`,
1074
+ * `"orch-lane-1"` (unchanged).
1074
1075
  *
1075
1076
  * **Determinism guarantee:** Given the same `waveTasks`, `pending`, and `config`,
1076
1077
  * this function always produces the same lane assignments and task ordering.
@@ -1279,7 +1280,7 @@ export function allocateLanes(
1279
1280
  }
1280
1281
 
1281
1282
  // ── Stage 4: Build AllocatedLane[] from assignments + worktrees ─
1282
- const tmuxPrefix = config.orchestrator.tmux_prefix || "orch";
1283
+ const sessionPrefix = config.orchestrator.sessionPrefix || "orch";
1283
1284
  const opId = resolveOperatorId(config);
1284
1285
  const strategy = config.assignment.strategy as AllocatedLane["strategy"];
1285
1286
  const sizeWeights = config.assignment.size_weights;
@@ -1328,10 +1329,11 @@ export function allocateLanes(
1328
1329
  0,
1329
1330
  );
1330
1331
 
1332
+ const laneSessionId = generateLaneSessionId(sessionPrefix, entry.localLane, opId, entry.repoId);
1331
1333
  allocatedLanes.push({
1332
1334
  laneNumber: entry.globalLane,
1333
1335
  laneId: generateLaneId(entry.localLane, entry.repoId),
1334
- tmuxSessionName: generateTmuxSessionName(tmuxPrefix, entry.localLane, opId, entry.repoId),
1336
+ laneSessionId,
1335
1337
  worktreePath: wt.path,
1336
1338
  branch: wt.branch,
1337
1339
  tasks: allocatedTasks,
@@ -1654,13 +1654,11 @@ export function meetsMinVersion(actual: [number, number], minimum: [number, numb
1654
1654
  * - git worktree support
1655
1655
  * - pi availability
1656
1656
  *
1657
- * Conditional checks (warn if spawn_mode is "subprocess", fail if "tmux"):
1658
- * - tmux version >= 2.6
1659
- * - tmux functional (can create/destroy sessions)
1657
+ * Compatibility checks:
1658
+ * - Runtime backend mode visibility (subprocess-only)
1660
1659
  */
1661
1660
  export function runPreflight(config: OrchestratorConfig, repoRoot?: string): PreflightResult {
1662
1661
  const checks: PreflightCheck[] = [];
1663
- const tmuxRequired = config.orchestrator.spawn_mode === "tmux";
1664
1662
 
1665
1663
  // ── Git version ──────────────────────────────────────────────
1666
1664
  const gitResult = execCheck("git --version");
@@ -1706,68 +1704,12 @@ export function runPreflight(config: OrchestratorConfig, repoRoot?: string): Pre
1706
1704
  : "Workspace root is not a git repo. Check workspace config repo paths.",
1707
1705
  });
1708
1706
 
1709
- // ── TMUX availability and version ────────────────────────────
1710
- const tmuxResult = execCheck("tmux -V");
1711
- if (tmuxResult.ok) {
1712
- const version = parseVersion(tmuxResult.stdout);
1713
- const versionStr = `${version[0]}.${version[1]}`;
1714
- if (meetsMinVersion(version, [2, 6])) {
1715
- checks.push({
1716
- name: "tmux",
1717
- status: "pass",
1718
- message: `TMUX ${versionStr} available`,
1719
- });
1720
- } else {
1721
- checks.push({
1722
- name: "tmux",
1723
- status: tmuxRequired ? "fail" : "warn",
1724
- message: `TMUX ${versionStr} found, but 2.6+ required`,
1725
- hint: "Upgrade TMUX: https://github.com/tmux/tmux/wiki/Installing",
1726
- });
1727
- }
1728
- } else {
1729
- checks.push({
1730
- name: "tmux",
1731
- status: tmuxRequired ? "fail" : "warn",
1732
- message: "TMUX not found",
1733
- hint: tmuxRequired
1734
- ? "Install TMUX (required for tmux spawn_mode):\n" +
1735
- " Linux: sudo apt install tmux\n" +
1736
- " macOS: brew install tmux\n" +
1737
- " Windows (MSYS2): pacman -S tmux\n" +
1738
- " Or set spawn_mode: subprocess in .pi/task-orchestrator.yaml"
1739
- : "TMUX not required for subprocess spawn_mode. Install for drill-down observability:\n" +
1740
- " Linux: sudo apt install tmux | macOS: brew install tmux",
1741
- });
1742
- }
1743
-
1744
- // ── TMUX functional (only if tmux was found) ─────────────────
1745
- if (tmuxResult.ok) {
1746
- const testSession = "orch-preflight-test";
1747
- const tmuxFunctional = execCheck(`tmux new-session -d -s ${testSession} "exit 0"`);
1748
- if (tmuxFunctional.ok) {
1749
- // Clean up test session
1750
- execCheck(`tmux kill-session -t ${testSession}`);
1751
- checks.push({
1752
- name: "tmux-functional",
1753
- status: "pass",
1754
- message: "TMUX can create sessions",
1755
- });
1756
- } else {
1757
- checks.push({
1758
- name: "tmux-functional",
1759
- status: tmuxRequired ? "fail" : "warn",
1760
- message: "TMUX installed but cannot create sessions",
1761
- hint: "Check TMUX server status. Try: tmux new-session -d -s test 'echo ok'",
1762
- });
1763
- }
1764
- } else {
1765
- checks.push({
1766
- name: "tmux-functional",
1767
- status: tmuxRequired ? "fail" : "warn",
1768
- message: "Skipped — TMUX not installed",
1769
- });
1770
- }
1707
+ // ── Runtime backend contract (Runtime V2) ─────────────────────
1708
+ checks.push({
1709
+ name: "runtime-backend",
1710
+ status: "pass",
1711
+ message: `Runtime V2 subprocess backend active (configured spawn_mode: ${config.orchestrator.spawn_mode})`,
1712
+ });
1771
1713
 
1772
1714
  // ── Pi availability ──────────────────────────────────────────
1773
1715
  const piResult = execCheck("pi --version");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.23.16",
3
+ "version": "0.24.0",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -27,12 +27,11 @@ orchestrator:
27
27
  # Batch ID format used in branch names and logs.
28
28
  batch_id_format: "timestamp"
29
29
 
30
- # "tmux" = named sessions you can attach to
31
- # "subprocess" = headless execution without tmux dependency
30
+ # Runtime V2 execution backend (subprocess-only)
32
31
  spawn_mode: "subprocess"
33
32
 
34
- # Prefix for TMUX session names when tmux mode is enabled.
35
- tmux_prefix: "orch"
33
+ # Prefix for orchestrator session names.
34
+ session_prefix: "orch"
36
35
 
37
36
  # Optional operator identifier for team-scale collision resistance.
38
37
  # Auto-detected from OS username if empty. Set explicitly in CI or