Skip to content

feat(daemon): send session-project path mapping to server#224

Merged
AnnatarHe merged 1 commit intomainfrom
feat/session-project-path-cache
Feb 12, 2026
Merged

feat(daemon): send session-project path mapping to server#224
AnnatarHe merged 1 commit intomainfrom
feat/session-project-path-cache

Conversation

@AnnatarHe
Copy link
Copy Markdown
Contributor

@AnnatarHe AnnatarHe commented Feb 11, 2026

Summary

  • Parse session_id and workspace fields from Claude Code statusline JSON input
  • Send session→project path mapping to daemon via unix socket (fire-and-forget, ~1ms)
  • Daemon forwards mapping to server via POST /api/v1/cc/session-project
  • Enables server-side pwd enrichment for OTEL events that report "/" instead of the actual project directory

Changes

  • model/cc_statusline_types.go: Add SessionID and Workspace fields to CCStatuslineInput
  • daemon/socket.go: Add session_project message type, struct, and handler case
  • daemon/client.go: Add SendSessionProject() fire-and-forget socket function
  • model/api_session_project.go (new): SendSessionProjectUpdate() HTTP API call
  • commands/cc_statusline.go: Wire up session-project send before daemon info query

Related

Test plan

  • Run cc statusline with fixture JSON containing session_id and workspace, verify daemon receives socket message
  • Verify daemon dispatches HTTP call to server endpoint
  • Verify statusline output is unaffected (no latency impact from fire-and-forget send)
  • go build ./... passes

🤖 Generated with Claude Code


Open with Devin

Parse session_id and workspace from Claude Code statusline input,
send the session→project mapping to the daemon via unix socket,
which forwards it to the server via POST /api/v1/cc/session-project.
This enables the server to fix incorrect pwd values during OTEL
ingestion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @AnnatarHe, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the Claude Code statusline integration by enabling the transmission of session and project directory information. This data is crucial for enriching telemetry events on the server, providing more accurate context for user activity, especially when project paths might otherwise be reported generically. The changes are designed to be efficient, utilizing a fire-and-forget mechanism for daemon communication to avoid performance bottlenecks.

Highlights

  • Session-Project Mapping: Introduced functionality to parse session_id and workspace fields from Claude Code statusline JSON input.
  • Daemon Communication: Implemented sending session-to-project path mappings to the daemon via a fire-and-forget Unix socket message, ensuring minimal latency impact.
  • Server-Side Enrichment: The daemon now forwards these mappings to the server via a new POST /api/v1/cc/session-project endpoint, enabling server-side enrichment for OTEL events.
  • New API Endpoint: Added a new API call SendSessionProjectUpdate() to handle the HTTP communication with the server for session-project mappings.
Changelog
  • commands/cc_statusline.go
    • Added logic to extract SessionID and Workspace information from the statusline input.
    • Implemented a call to daemon.SendSessionProject to dispatch the session-project mapping via a Unix socket.
  • daemon/client.go
    • Introduced SendSessionProject function to establish a non-blocking Unix socket connection and send session-project mapping messages.
  • daemon/socket.go
    • Added SocketMessageTypeSessionProject constant to define the new message type.
    • Defined SessionProjectRequest struct to encapsulate session ID and project path for socket communication.
    • Implemented a new case in handleConnection to process SocketMessageTypeSessionProject messages, parsing the payload and dispatching an asynchronous call to model.SendSessionProjectUpdate.
  • model/api_session_project.go
    • Created a new file to define the sessionProjectRequest and sessionProjectResponse structs for the HTTP API.
    • Implemented SendSessionProjectUpdate function to send the session-to-project path mapping to the server via a POST request.
  • model/cc_statusline_types.go
    • Added SessionID and Workspace fields to the CCStatuslineInput struct.
    • Defined CCStatuslineWorkspace struct to hold CurrentDir and ProjectDir information.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new feature to send a session-to-project-path mapping from the CLI to the server via the daemon. The changes look good and cover the client, daemon, and model layers appropriately. I've added a couple of comments to improve the robustness of the new daemon logic by adding better error handling and safer type assertions. Once these are addressed, the changes should be ready to merge.

Comment thread daemon/socket.go
Comment on lines +191 to +196
sessionID, _ := payload["sessionId"].(string)
projectPath, _ := payload["projectPath"].(string)
if sessionID != "" && projectPath != "" {
go model.SendSessionProjectUpdate(context.Background(), *p.config, sessionID, projectPath)
slog.Debug("session_project update dispatched", slog.String("sessionId", sessionID))
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This block has a couple of issues that should be addressed for robustness:

  1. The type assertions for sessionID and projectPath ignore the ok boolean return value. This is unsafe because if the payload is malformed (e.g., a field is missing or has the wrong type), this will fail silently.
  2. The error returned by model.SendSessionProjectUpdate inside the goroutine is ignored. Any error during the API call to the server will be lost, making debugging difficult.

The suggested change below addresses both points by checking the type assertion results and handling the error from the API call by logging it.

			sessionID, ok1 := payload["sessionId"].(string)
			projectPath, ok2 := payload["projectPath"].(string)
			if ok1 && ok2 && sessionID != "" && projectPath != "" {
				go func() {
					if err := model.SendSessionProjectUpdate(context.Background(), *p.config, sessionID, projectPath); err != nil {
						slog.Warn("Failed to send session-project update", slog.Any("err", err), slog.String("sessionId", sessionID))
					}
				}()
				slog.Debug("session_project update dispatched", slog.String("sessionId", sessionID))
			} else {
				slog.Warn("Received invalid or incomplete session_project payload", "payload", payload)
			}

Comment thread daemon/client.go
},
}

json.NewEncoder(conn).Encode(msg)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error returned by json.NewEncoder(conn).Encode(msg) is not handled. Even for a fire-and-forget function, it's good practice to log such errors for debugging purposes. You could use the slog package for this, which is used elsewhere in the daemon package (you would need to add the log/slog import).

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 6 additional findings in Devin Review.

Open in Devin Review

Comment thread daemon/client.go
Comment on lines +55 to +71
func SendSessionProject(socketPath string, sessionID, projectPath string) {
conn, err := net.DialTimeout("unix", socketPath, 10*time.Millisecond)
if err != nil {
return
}
defer conn.Close()

msg := SocketMessage{
Type: SocketMessageTypeSessionProject,
Payload: SessionProjectRequest{
SessionID: sessionID,
ProjectPath: projectPath,
},
}

json.NewEncoder(conn).Encode(msg)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Missing write deadline on socket connection in SendSessionProject can block the statusline indefinitely

SendSessionProject sets a 10ms dial timeout but never sets a write deadline on the connection. The json.NewEncoder(conn).Encode(msg) call at line 70 could block indefinitely if the daemon accepts the connection but is slow to read.

Root Cause and Impact

Compare with RequestCCInfo at daemon/client.go:82 which properly sets conn.SetDeadline(time.Now().Add(timeout)) before writing. SendSessionProject omits this safeguard.

This function is called synchronously in the statusline command (commands/cc_statusline.go:83) which has a hard 100ms timeout. If the daemon's read buffer is full or the daemon is busy, the write could block for much longer than the expected ~1ms, potentially consuming the entire 100ms budget and causing the statusline to time out. While Unix domain socket writes are typically fast due to kernel buffering, this is a missing safeguard that violates the "fire-and-forget, ~1ms" contract stated in the comment.

Impact: Under load or unusual daemon conditions, the statusline could hang or time out, degrading the user experience.

Suggested change
func SendSessionProject(socketPath string, sessionID, projectPath string) {
conn, err := net.DialTimeout("unix", socketPath, 10*time.Millisecond)
if err != nil {
return
}
defer conn.Close()
msg := SocketMessage{
Type: SocketMessageTypeSessionProject,
Payload: SessionProjectRequest{
SessionID: sessionID,
ProjectPath: projectPath,
},
}
json.NewEncoder(conn).Encode(msg)
}
func SendSessionProject(socketPath string, sessionID, projectPath string) {
conn, err := net.DialTimeout("unix", socketPath, 10*time.Millisecond)
if err != nil {
return
}
defer conn.Close()
conn.SetDeadline(time.Now().Add(10 * time.Millisecond))
msg := SocketMessage{
Type: SocketMessageTypeSessionProject,
Payload: SessionProjectRequest{
SessionID: sessionID,
ProjectPath: projectPath,
},
}
json.NewEncoder(conn).Encode(msg)
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@AnnatarHe AnnatarHe merged commit d594338 into main Feb 12, 2026
6 of 7 checks passed
@AnnatarHe AnnatarHe deleted the feat/session-project-path-cache branch February 12, 2026 16:54
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.

1 participant