[FEATURE] Add session lock file
Preflight Checklist
- [x] I have searched existing feature requests and this hasn't been requested before
- [x] This is a single feature request (not multiple features)
---
Problem Statement
When building orchestration systems that manage multiple Claude Code sessions, there's no reliable way to detect which sessions are currently active or to coordinate between processes. External tools need to poll Claude Code's state or resort to process inspection, which is fragile and platform-dependent.
An orchestrator managing parallel Claude Code sessions needs to:
- Know which sessions are currently active
- Avoid conflicting with active sessions on the same project
- Clean up stale sessions after crashes
---
Proposed Solution
Claude Code should create a lock file at ~/.claude/projects/{project}/{session}.lock (or {session}.pid) when a session starts and remove it when the session ends gracefully.
Lock file contents:
{
"pid": 12345,
"startedAt": "2025-01-19T10:30:00Z",
"sessionId": "session-abc123",
"cwd": "/Users/user/myproject"
}
Orchestrator integration example:
import { readdir, readFile, stat } from 'fs/promises';
import { join } from 'path';
import { homedir } from 'os';
interface SessionLock {
pid: number;
startedAt: string;
sessionId: string;
cwd: string;
}
async function getActiveClaudeSessions(projectHash: string): Promise<SessionLock[]> {
const lockDir = join(homedir(), '.claude', 'projects', projectHash);
const files = await readdir(lockDir);
const lockFiles = files.filter(f => f.endsWith('.lock'));
const sessions: SessionLock[] = [];
for (const file of lockFiles) {
const content = await readFile(join(lockDir, file), 'utf-8');
const lock: SessionLock = JSON.parse(content);
// Verify process is still running
if (isProcessAlive(lock.pid)) {
sessions.push(lock);
}
}
return sessions;
}
function isProcessAlive(pid: number): boolean {
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
}
// Usage: Wait for exclusive project access
async function waitForProjectAvailable(projectHash: string): Promise<void> {
while ((await getActiveClaudeSessions(projectHash)).length > 0) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
Python orchestrator example:
import json
import os
from pathlib import Path
from dataclasses import dataclass
from datetime import datetime
@dataclass
class SessionLock:
pid: int
started_at: datetime
session_id: str
cwd: str
def get_active_sessions(project_hash: str) -> list[SessionLock]:
lock_dir = Path.home() / ".claude" / "projects" / project_hash
sessions = []
for lock_file in lock_dir.glob("*.lock"):
with open(lock_file) as f:
data = json.load(f)
# Check if process is still alive
try:
os.kill(data["pid"], 0)
sessions.append(SessionLock(
pid=data["pid"],
started_at=datetime.fromisoformat(data["startedAt"]),
session_id=data["sessionId"],
cwd=data["cwd"]
))
except ProcessLookupError:
# Stale lock file - process no longer exists
lock_file.unlink() # Clean up
return sessions
---
Priority
Medium - Enables new integration patterns but workarounds exist
---
Feature Category
Developer tools/SDK
---
Alternative Solutions
Current workarounds are fragile:
- Process inspection - Parse
ps aux | grep claudeoutput (platform-specific, unreliable) - File watching - Monitor
~/.claudefor changes (high overhead, race conditions) - Custom wrapper scripts - Maintain external state (duplicates what Claude Code should track)
---
Use Case Example
Scenario: CI system running parallel Claude Code agents
- CI job spawns 4 Claude Code instances for different tasks
- Orchestrator checks
~/.claude/projects/*/for{session}.lockfiles - If a task fails, orchestrator can identify the stuck session by PID
- Orchestrator waits for all locks to clear before marking job complete
- On crash recovery, orchestrator cleans up stale locks where PID no longer exists
---
Additional Context
This aligns with standard Unix conventions (e.g., /var/run/*.pid files) and would make Claude Code more composable in larger automation systems. The lock file approach is battle-tested in tools like npm, yarn, and many database systems.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗