The OpCode Bug Hunt

ChatGPT Image Oct 7, 2025, 12_24_27 PM

Introduction

I recently discovered OpCode, a desktop GUI for Claude Code built with Tauri v2 and React. As someone who works with various development tools, I was intrigued by the concept of having a visual interface for managing Claude Code sessions and projects. After downloading and running it locally, I immediately ran into an interesting bug that led to my first contribution to the project.

The Bug

When I launched OpCode, I noticed something odd in the project list. My project was being misidentified:

Actual location:
~/projects/flipside/data-discovery

Displayed as:
~/projects/flipside/data/discovery

The hyphen in data-discovery was being replaced with a slash, making it look like a nested directory structure that didn’t actually exist.

This wasn’t just a display issue—it fundamentally broke the project discovery mechanism for any project with hyphens in the directory name, which is quite common in modern development practices.

Investigation

The issue was in the Rust backend, specifically in the src-tauri/src/commands/claude.rs file. OpCode stores project metadata in ~/.claude/projects/, where each project directory is named using an encoded version of the project path (slashes replaced with hyphens).

The problematic code was in the get_project_path_from_sessions() function:

fn get_project_path_from_sessions(project_dir: &PathBuf) -> Result<String, String> {
    // ... code to read JSONL files
    if let Some(Ok(first_line)) = reader.lines().next() {
        if let Ok(json) = serde_json::from_str::<serde_json::Value>(&first_line) {
            if let Some(cwd) = json.get("cwd").and_then(|v| v.as_str()) {
                return Ok(cwd.to_string());
            }
        }
    }
}

The function only checked the first line of the JSONL session file for the current working directory (cwd). However, in my session file, the first line had "cwd": null, while the actual project path appeared on subsequent lines:

{"type":"system","cwd":null}
{"type":"system","cwd":"/Users/shah/projects/flipside/data-discovery"}

When the function failed to find a valid cwd, it fell back to the deprecated decode_project_path() function, which blindly replaced all hyphens with slashes—hence the bug.

The Fix

The solution was straightforward: instead of checking only the first line, scan the first 10 lines for a valid, non-empty cwd value. View the full diff on GitHub →

fn get_project_path_from_sessions(project_dir: &PathBuf) -> Result<String, String> {
    let entries = fs::read_dir(project_dir)
        .map_err(|e| format!("Failed to read project directory: {}", e))?;

    for entry in entries {
        if let Ok(entry) = entry {
            let path = entry.path();
            if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("jsonl") {
                if let Ok(file) = fs::File::open(&path) {
                    let reader = BufReader::new(file);
                    // Check first few lines instead of just the first line
                    for line in reader.lines().take(10) {
                        if let Ok(line_content) = line {
                            // Parse the JSON and extract cwd
                            if let Ok(json) = serde_json::from_str::<serde_json::Value>(&line_content) {
                                if let Some(cwd) = json.get("cwd").and_then(|v| v.as_str()) {
                                    if !cwd.is_empty() {
                                        return Ok(cwd.to_string());
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    Err("Could not determine project path from session files".to_string())
}

Testing

To ensure the fix worked correctly and prevent regressions, I added comprehensive unit tests covering various scenarios:

  • Normal case: cwd on the first line
  • Bug scenario: project paths with hyphens
  • Null cwd on first line, valid path on second line
  • Multiple lines before valid cwd appears
  • Edge cases: empty directories, no JSONL files, missing cwd fields

All 8 tests pass:

running 8 tests
test commands::claude::tests::test_get_project_path_from_sessions_empty_dir ... ok
test commands::claude::tests::test_get_project_path_from_sessions_with_hyphen ... ok
test commands::claude::tests::test_get_project_path_from_sessions_null_cwd_first_line ... ok
test commands::claude::tests::test_get_project_path_from_sessions_multiple_lines ... ok
test commands::claude::tests::test_get_project_path_from_sessions_normal_case ... ok
test commands::claude::tests::test_get_project_path_from_sessions_no_jsonl_files ... ok
test commands::claude::tests::test_get_project_path_from_sessions_no_cwd ... ok
test commands::claude::tests::test_get_project_path_from_sessions_multiple_sessions ... ok

test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured

The Pull Request

I submitted the fix as PR #382. The final changeset is clean and focused:

  • 2 files changed
  • 152 insertions, 7 deletions
  • Includes the bug fix, comprehensive tests, and a minor compilation fix

The PR follows the project’s contributing guidelines and includes a detailed commit message explaining the issue, root cause, and solution.

Lessons Learned

  1. Edge cases matter: The assumption that cwd would always be on the first line was reasonable but failed in practice.
  2. File format assumptions are fragile: JSONL files can have varying structures. Defensive parsing is essential.
  3. Tests are documentation: The unit tests not only validate the fix but also document the expected behavior and edge cases for future maintainers.
  4. Clean PRs get merged faster: Taking the time to create a focused, well-documented PR (without formatting noise) makes review easier.

Conclusion

Contributing to open source projects is rewarding, especially when you’re fixing a bug that directly affects your workflow. OpCode is an interesting project that bridges the gap between command-line tools and GUI interfaces, and I’m glad I could contribute to making it more robust.

If you’re interested in trying OpCode or contributing yourself, check out the GitHub repository.


This post documents my first contribution to OpCode. The bug fix was developed and tested using Claude Code itself—a nice meta moment for a tool designed to work with Claude Code.



Comments are closed.