Resolve Claude projects directory inside the lib (honor CLAUDE_CONFIG_DIR) #34

Open
opened 2026-04-08 13:02:47 +00:00 by mprihoda · 0 comments
mprihoda commented 2026-04-08 13:02:47 +00:00 (Migrated from github.com)

Problem

DirectConversationLogIndex requires callers to pass a fully-resolved projectDir: os.Path. That forces every consumer to reimplement two facts about Claude Code's on-disk layout:

  1. Base directory resolution~/.claude/projects/, but honoring CLAUDE_CONFIG_DIR when set.
  2. Project path encoding/home/mph/ops/kanon-home-mph-ops-kanon.

Neither concern is app logic; both are "how Claude Code stores sessions." The lib is the natural owner.

Real-world bite

In kanon's transcript-analyze command we hardcoded os.home / ".claude" / "projects". On a machine where CLAUDE_CONFIG_DIR=~/.claude-iw (iw-cli's isolated config), session discovery fails with "No sessions found for this project" even though claude --resume finds them fine — because the actual sessions live under ~/.claude-iw/projects/….

Every consumer will hit this eventually, and each will fix it independently (or not).

Proposed API

Something like:

object ClaudeProjects:
  /** Base projects dir, honoring CLAUDE_CONFIG_DIR (fallback: ~/.claude/projects). */
  def baseDir(): os.Path

  /** Encode a working directory to Claude's project-dir naming and join with baseDir. */
  def projectDirFor(cwd: os.Path): os.Path

And convenience overloads on DirectConversationLogIndex that take a cwd directly:

def listSessionsFor(cwd: os.Path): Seq[LogFileMetadata]
def forSessionAt(cwd: os.Path, sessionId: String): Option[LogFileMetadata]

Existing path-based methods stay for callers that already know the project dir.

Acceptance

  • CLAUDE_CONFIG_DIR is honored when resolving the base projects dir
  • Path encoding (/-, leading -) lives in the lib with tests
  • DirectConversationLogIndex has a cwd-based entry point so consumers don't touch paths
  • Existing API remains source-compatible

Context

Downstream bug report and discussion: kanon transcript-analyze on PROC-272. Stopgap in kanon will add CLAUDE_CONFIG_DIR handling locally until this lands.

## Problem `DirectConversationLogIndex` requires callers to pass a fully-resolved `projectDir: os.Path`. That forces every consumer to reimplement two facts about Claude Code's on-disk layout: 1. **Base directory resolution** — `~/.claude/projects/`, but honoring `CLAUDE_CONFIG_DIR` when set. 2. **Project path encoding** — `/home/mph/ops/kanon` → `-home-mph-ops-kanon`. Neither concern is app logic; both are "how Claude Code stores sessions." The lib is the natural owner. ## Real-world bite In `kanon`'s `transcript-analyze` command we hardcoded `os.home / ".claude" / "projects"`. On a machine where `CLAUDE_CONFIG_DIR=~/.claude-iw` (iw-cli's isolated config), session discovery fails with "No sessions found for this project" even though `claude --resume` finds them fine — because the actual sessions live under `~/.claude-iw/projects/…`. Every consumer will hit this eventually, and each will fix it independently (or not). ## Proposed API Something like: ```scala object ClaudeProjects: /** Base projects dir, honoring CLAUDE_CONFIG_DIR (fallback: ~/.claude/projects). */ def baseDir(): os.Path /** Encode a working directory to Claude's project-dir naming and join with baseDir. */ def projectDirFor(cwd: os.Path): os.Path ``` And convenience overloads on `DirectConversationLogIndex` that take a `cwd` directly: ```scala def listSessionsFor(cwd: os.Path): Seq[LogFileMetadata] def forSessionAt(cwd: os.Path, sessionId: String): Option[LogFileMetadata] ``` Existing path-based methods stay for callers that already know the project dir. ## Acceptance - [ ] `CLAUDE_CONFIG_DIR` is honored when resolving the base projects dir - [ ] Path encoding (`/` → `-`, leading `-`) lives in the lib with tests - [ ] `DirectConversationLogIndex` has a cwd-based entry point so consumers don't touch paths - [ ] Existing API remains source-compatible ## Context Downstream bug report and discussion: `kanon` transcript-analyze on PROC-272. Stopgap in kanon will add `CLAUDE_CONFIG_DIR` handling locally until this lands.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
iterative-works/claude-code-query#34
No description provided.