Function: claude-code-ide--start-session

claude-code-ide--start-session is a natively compiled function defined in claude-code-ide.el.

Signature

(claude-code-ide--start-session &optional CONTINUE RESUME)

Documentation

Start a new Claude Code instance for the current project.

If CONTINUE is non-nil, start Claude with the -c (continue) flag. If RESUME is non-nil, start Claude with the -r (resume) flag.

Always creates a new instance; a project may run any number of them concurrently. When the project already has instances (or with a prefix argument), prompts for an optional instance name.

This function handles:
- CLI availability checking
- Dead session cleanup
- New session creation with a per-instance MCP server
- Process and buffer lifecycle management

Source Code

;; Defined in /nix/store/yjvbhwl7p6zrbw9xlnni7y4hra8sa3pl-emacs-packages-deps/share/emacs/site-lisp/claude-code-ide.el
(defun claude-code-ide--start-session (&optional continue resume)
  "Start a new Claude Code instance for the current project.
If CONTINUE is non-nil, start Claude with the -c (continue) flag.
If RESUME is non-nil, start Claude with the -r (resume) flag.

Always creates a new instance; a project may run any number of them
concurrently.  When the project already has instances (or with a
prefix argument), prompts for an optional instance name.

This function handles:
- CLI availability checking
- Dead session cleanup
- New session creation with a per-instance MCP server
- Process and buffer lifecycle management"
  (unless (claude-code-ide--ensure-cli)
    (user-error "Claude Code CLI not available.  Please install it and ensure it's in PATH"))

  ;; Clean up any dead sessions first
  (claude-code-ide--cleanup-dead-sessions)

  ;; Ensure the selected terminal backend is available before starting MCP
  (claude-code-ide--terminal-ensure-backend)

  (let* ((working-dir (claude-code-ide--get-working-directory))
         ;; Additional instances get an optional name; a prefix argument
         ;; offers the prompt for the first instance too
         (instance-name (when (or (claude-code-ide-mcp--sessions-for-project working-dir)
                                  current-prefix-arg)
                          (claude-code-ide--read-instance-name working-dir)))
         ;; A live instance may already own the base name — e.g. two
         ;; projects sharing a basename both render as *claude-code[proj]*.
         ;; Uniquify instead of clobbering or refusing.
         (buffer-name (let* ((base (claude-code-ide--instance-buffer-name working-dir instance-name))
                             (existing (get-buffer base)))
                        (if (and existing (claude-code-ide--buffer-session existing))
                            (generate-new-buffer-name base)
                          base)))
         (session-id (claude-code-ide--generate-session-id working-dir))
         (session nil)
         (registered nil))
    (condition-case err
        (progn
          ;; Start this instance's MCP server
          (setq session (claude-code-ide-mcp-create-session working-dir session-id instance-name))
          (setf (claude-code-ide-mcp-session-window-slot session)
                (claude-code-ide--assign-window-slot working-dir))
          ;; Register with the MCP tools server BEFORE spawning the CLI so
          ;; an early /mcp/<session-id> request finds its context
          (claude-code-ide-mcp-server-session-started session-id working-dir nil)
          (setq registered t)
          (let* ((port (claude-code-ide-mcp-session-port session))
                 (buffer-and-process (claude-code-ide--create-terminal-session
                                      buffer-name working-dir port continue resume session-id))
                 (buffer (car buffer-and-process))
                 (process (cdr buffer-and-process)))
            (setf (claude-code-ide-mcp-session-buffer session) buffer
                  (claude-code-ide-mcp-session-process session) process)
            (claude-code-ide-mcp-server-update-session-buffer session-id buffer)
            (with-current-buffer buffer
              (setq-local claude-code-ide--session session))
            ;; Install global terminal advice for the first live instance
            (claude-code-ide--maybe-install-global-advice)
            ;; Set up process sentinel to clean up when Claude exits.
            ;; The ghostel backend stashes its native sentinel on the
            ;; process so we can chain it here — otherwise ghostel's
            ;; buffer-local timers and focus-change hook never tear down.
            (let ((prev-sentinel (process-get process 'claude-code-ide--ghostel-sentinel)))
              (set-process-sentinel process
                                    (lambda (proc event)
                                      (when prev-sentinel
                                        (ignore-errors (funcall prev-sentinel proc event)))
                                      ;; Check for abnormal exit with error code
                                      (when (string-match "exited abnormally with code \\([0-9]+\\)" event)
                                        (let ((exit-code (match-string 1 event)))
                                          (claude-code-ide-debug "Claude process exited with code %s, event: %s"
                                                                 exit-code event)
                                          (message "Claude exited with error code %s" exit-code)))
                                      (when (or (string-match "finished" event)
                                                (string-match "exited" event)
                                                (string-match "killed" event)
                                                (string-match "terminated" event))
                                        (claude-code-ide--cleanup-session session)))))
            ;; Also add buffer kill hook as a backup.  The buffer-dying
            ;; flag stops cleanup from nested-killing the buffer while
            ;; the backend's own kill hooks still have to run on it.
            (with-current-buffer buffer
              (add-hook 'kill-buffer-hook
                        (lambda ()
                          (claude-code-ide--cleanup-session session 'buffer-dying))
                        nil t)
              ;; Set up terminal keybindings
              (claude-code-ide--setup-terminal-keybindings)
              ;; Add terminal-specific exit hooks
              (cond
               ((eq claude-code-ide-terminal-backend 'vterm)
                ;; Add vterm exit hook to ensure buffer is killed when process exits
                ;; vterm runs Claude directly, no shell involved
                (add-hook 'vterm-exit-functions
                          (lambda (&rest _)
                            (when (buffer-live-p buffer)
                              (kill-buffer buffer)))
                          nil t))
               ((eq claude-code-ide-terminal-backend 'eat)
                ;; eat uses kill-buffer-on-exit variable
                (setq-local eat-kill-buffer-on-exit t))))
            ;; Stabilization period for terminal layout initialization
            (sleep-for claude-code-ide-terminal-initialization-delay)
            ;; The CLI can die within the stabilization delay (e.g. it
            ;; failed to exec in the terminal backend's environment), in
            ;; which case the exit sentinel has already killed the buffer.
            ;; Displaying the dead buffer would surface only as a cryptic
            ;; wrong-type-argument, so fail with a real explanation.
            (unless (and (buffer-live-p buffer) (process-live-p process))
              (error "Claude Code exited immediately after startup.  Verify that `claude-code-ide-cli-path' (%s) is executable in the %s backend's environment"
                     claude-code-ide-cli-path claude-code-ide-terminal-backend))
            ;; Display the buffer in a side window
            (claude-code-ide--display-buffer-in-side-window buffer)
            (claude-code-ide-log "Claude Code %sstarted in %s with MCP on port %d%s"
                                 (cond (continue "continued and ")
                                       (resume "resumed and ")
                                       (t ""))
                                 (claude-code-ide--session-display-name session)
                                 port
                                 (if claude-code-ide-cli-debug " (debug mode enabled)" ""))
            ;; Delayed so the startup message above stays readable first
            (run-with-timer 2 nil #'claude-code-ide--maybe-recommend-ghostel)))
      ((error quit)
       ;; Session creation failed (or was quit) - tear down only THIS
       ;; instance; a directory-wide stop would kill sibling instances'
       ;; servers.  Once a terminal buffer exists, the full per-session
       ;; cleanup also kills it and its process — leaving it around would
       ;; orphan a running CLI nothing tracks anymore.
       (unless (and session (claude-code-ide-mcp-session-cleanup-done session))
         (if (and session (claude-code-ide-mcp-session-buffer session))
             (claude-code-ide--cleanup-session session)
           (when registered
             (claude-code-ide-mcp-server-session-ended session-id))
           (when session
             (claude-code-ide-mcp--stop-session session))))
       ;; Re-signal the error with improved message
       (signal (car err) (cdr err))))))