Conversation
Enhancement Analysis - Issue #977
Status: Complete Enhancement AnalysisQuestions for Reporter
Problem Summary iloom currently invokes the Claude CLI in full mode for lightweight tasks like generating branch names and commit messages. These invocations pay the full startup cost (hooks, LSP, plugin sync, CLAUDE.md discovery, etc.) even though they only need simple text generation. The User Impact All iloom users experience unnecessary latency during Enhancement Goal Add the Next Steps
Complete Context and Details (click to expand)Background from Issue Description The issue author notes this is "a long shot due to OAUTH issues," indicating awareness that the
Key Auth Considerations
Affected Features
Both are short-lived, single-prompt invocations that produce a few words or sentences of output. They do not need code analysis tools, LSP integration, plugins, or CLAUDE.md context. Additional Context
|
Analysis Phase
Executive SummaryThis issue adds Questions and Key Decisions
HIGH/CRITICAL Risks
Impact Summary
Complete Technical Reference (click to expand for implementation details)Problem Space ResearchProblem UnderstandingBranch naming ( Architectural ContextBoth invocations flow through a single function:
Historical Context
Edge Cases Identified
Codebase Research FindingsAffected Area: Branch Name GenerationEntry Point:
Affected Area: Commit Message GenerationEntry Point:
Affected Area: launchClaude() Core FunctionEntry Point: Similar Patterns Found
Affected FilesCore Changes
Test Changes
Architectural Flow AnalysisData Flow:
|
Implementation Plan for Issue #977SummaryAdd Questions and Key Decisions
High-Level Execution Phases
Quick Stats
Potential RisksNone beyond what was already identified in the analysis (OAuth auth breakage is mitigated by the env var check gating). Complete Implementation Guide (click to expand for step-by-step details)Automated Test Cases to CreateTest File:
|
Implementation CompleteSummaryAdded Changes Made
Validation Results
Detailed Changes by File (click to expand)src/utils/claude.tsChanges: Core --bare flag infrastructure
src/lib/CommitManager.tsChanges: Bare mode integration for commit messages
src/utils/claude.test.tsChanges: Test coverage for bare flag
src/lib/CommitManager.test.tsChanges: Test coverage for CommitManager bare mode
|
Auto-apply --bare mode in launchClaude() for headless utility operations (branch naming, commit messages) when ANTHROPIC_API_KEY is available. This skips hooks, LSP, plugins, and CLAUDE.md auto-discovery for faster startup. Falls back to normal mode when only OAuth/keychain auth is available, avoiding the regression from 308e55c. Fixes #977
603e7e5 to
61c9740
Compare
Analysis:
|
Analysis:
|
| Question | Answer |
|---|---|
| Should apiKeyHelper be a shell script on disk or can we use an inline command? | --settings accepts inline JSON: --settings '{"apiKeyHelper": "echo TOKEN"}'. Inline is simpler - no temp file needed. The value is a shell command whose stdout is used as the API key. |
| Does Claude Code accept OAuth tokens (sk-ant-oat01-...) via apiKeyHelper? | Yes - the docs state apiKeyHelper output is used for X-Api-Key and Authorization: Bearer headers. OAuth tokens with the sk-ant-oat01- prefix work as API keys for the Anthropic API. |
| Should we attempt token refresh if expired? | No. If the token is expired, the extraction will still return it, but the API call will fail. The correct behavior is to fall back to non-bare mode, where Claude Code handles its own OAuth flow including refresh. |
| Should the keychain-reading logic live in shouldUseBareMode or separately? | Separately. shouldUseBareMode should remain a fast synchronous check. A new async function (e.g., getBareModeSettings) should handle token extraction and settings JSON generation. |
HIGH/CRITICAL Risks
- Token expiry causes silent failures: If the extracted OAuth token has expired,
--barewill fail with an auth error. The implementation MUST catch this and fall back to non-bare mode, otherwise branch naming and commit message generation will fail entirely. - Keychain access may be blocked: On macOS, reading the keychain via
security find-generic-passwordcan fail silently (locked keychain in SSH sessions, no GUI available). This is analogous to the exact issue that caused commit 308e55c -CLAUDE_CODE_SIMPLEbroke OAuth because it skipped keychain reads. The apiKeyHelper approach must handle this gracefully.
Impact Summary
- 1 primary file to modify:
src/utils/claude.ts(shouldUseBareMode, launchClaude, new token extraction function) - 1 interface to update:
ClaudeCliOptionsinsrc/utils/claude.ts(addsettingsfield) - 1 test file:
src/utils/claude.test.ts(shouldUseBareMode tests, new bare+OAuth tests) - 8 call sites auto-benefit (no changes needed): all callers using
headless: true+noSessionPersistence: true - Cross-platform credential extraction needed: macOS (Keychain) + Linux (.credentials.json)
Complete Technical Reference (click to expand for implementation details)
Problem Space Research
Problem Understanding
The --bare flag makes headless Claude CLI calls faster by skipping startup overhead (hooks, LSP, plugins, CLAUDE.md walks). These utility calls (branch naming, commit messages, PR bodies) are performance-sensitive since users wait for them inline. Currently, only API key users get this benefit. Since most users authenticate via OAuth (Claude Max subscription), the feature is effectively unused.
Architectural Context
The shouldUseBareMode() function at src/utils/claude.ts:622 is the single gate. It's called from launchClaude() at line 163 as an auto-apply mechanism when headless && noSessionPersistence and bare isn't explicitly set. The --bare flag description confirms: "Anthropic auth is strictly ANTHROPIC_API_KEY or apiKeyHelper via --settings".
Historical Context: Commit 308e55c
The previous attempt to optimize utility calls used CLAUDE_CODE_SIMPLE=1 env var (which --bare now also sets internally). This was removed in commit 308e55c because CLAUDE_CODE_SIMPLE=1 disables OAuth credential lookup entirely, causing "Not logged in" errors for OAuth-only users. The key insight: --bare has the same OAuth-disabling behavior, but provides a recovery path via apiKeyHelper that CLAUDE_CODE_SIMPLE alone did not.
Edge Cases
- Token expiry: OAuth tokens have finite lifetimes (expiresAt is a Unix ms timestamp). Claude Code refreshes tokens internally, but an extracted token is a snapshot.
- Multiple keychain accounts: macOS keychain can have multiple
Claude Code-credentialsentries (observed:account=unknownfor MCP OAuth,account=$USERfor main credentials). - No credentials available: First-time users or fresh installs may have no cached OAuth token.
- Keychain locked/inaccessible: SSH sessions, cron jobs, or headless Linux environments without keychain daemon.
- Inline JSON escaping: The OAuth token may contain characters that need shell escaping when passed via
--settings.
Third-Party Research Findings
Claude Code CLI --bare flag
Source: WebSearch + CLI help text
Key Findings:
--baresetsCLAUDE_CODE_SIMPLE=1internally- Auth is strictly
ANTHROPIC_API_KEYenv var ORapiKeyHelpervia--settings - OAuth and keychain are never read in bare mode
--settings <file-or-json>accepts either a file path or inline JSON stringapiKeyHelpervalue is a shell command that outputs the API key to stdout- apiKeyHelper is called after 5 minutes or on HTTP 401 (for refresh)
Claude Code Credential Storage
Source: WebSearch + local filesystem investigation
Key Findings:
- macOS: Stored in macOS Keychain, service=
Claude Code-credentials, account=$USER- Readable via:
security find-generic-password -s "Claude Code-credentials" -a "$USER" -w - Returns JSON:
{"claudeAiOauth":{"accessToken":"sk-ant-oat01-...","refreshToken":"...","expiresAt":1774887933084,"scopes":[...],"subscriptionType":"max"},"mcpOAuth":{...}}
- Readable via:
- Linux: Stored in
~/.claude/.credentials.jsonwith mode 0600- Same JSON structure as macOS keychain value
- Windows: Stored in
~/.claude/.credentials.jsoninheriting user profile ACLs - Env var override:
CLAUDE_CODE_OAUTH_TOKENenv var can be used as alternative
Codebase Research Findings
Affected Area: Claude CLI utility layer
Entry Point: src/utils/claude.ts:622 - shouldUseBareMode() function
Dependencies:
- Uses:
process.env.ANTHROPIC_API_KEY - Used By:
launchClaude()at line 163 (auto-apply logic)
Entry Point: src/utils/claude.ts:152-555 - launchClaude() function
Dependencies:
- Uses:
shouldUseBareMode(),execa,ClaudeCliOptions - Used By: All headless utility operations across the codebase
Call Sites That Auto-Trigger Bare Mode
These call sites pass headless: true + noSessionPersistence: true, which triggers the shouldUseBareMode() check:
src/utils/claude.ts:665-668-generateBranchName()- branch name generationsrc/lib/CommitManager.ts:341-346-generateClaudeCommitMessage()- commit messagessrc/lib/PRManager.ts:72-76- PR body generationsrc/lib/IssueEnhancementService.ts:114-118- Issue enhancement (single)src/lib/IssueEnhancementService.ts:254-258- Issue enhancement (batch)src/lib/SessionSummaryService.ts:138-142- Session summary generationsrc/lib/SessionSummaryService.ts:342-346- Session summary (alternate path)src/lib/ValidationRunner.ts:414-419- Validation (conditional headless)src/lib/MergeManager.ts:510-516- Merge conflict resolution (conditional headless)
ClaudeCliOptions Interface
src/utils/claude.ts:56-84 - Currently lacks settings field. The interface needs a new optional field for --settings.
Current Bare Mode Logic
src/utils/claude.ts:162-167
const effectiveBare = bare ?? (headless && noSessionPersistence ? shouldUseBareMode() : false)
if (effectiveBare) {
args.push('--bare')
}
The auto-apply only adds --bare to args. It does not add --settings. For OAuth token flow, when shouldUseBareMode() returns true due to OAuth token availability, the --settings JSON with apiKeyHelper must also be added.
Platform-Specific Code Patterns
The codebase already handles platform differences (e.g., src/commands/shell.ts:252 checks process.platform === 'win32'). The credential extraction will need similar branching.
Affected Files
src/utils/claude.ts:56-84-ClaudeCliOptionsinterface - Addsettingsfieldsrc/utils/claude.ts:152-167-launchClaude()- Add--settingsarg building + bare mode OAuth logicsrc/utils/claude.ts:617-624-shouldUseBareMode()- Expand to check for OAuth token availability (or create new async function)src/utils/claude.test.ts:2295-2329- Existing shouldUseBareMode tests - Update for new OAuth pathsrc/utils/claude.test.ts:2175-2258- Existing bare mode tests - Add OAuth variant tests
Architectural Flow Analysis
Data Flow: OAuth token to --bare --settings
Entry Point: OS credential store (macOS Keychain / Linux ~/.claude/.credentials.json)
Flow Path:
- New function (e.g.,
getOAuthTokenForBareMode()) extracts token from platform-specific store shouldUseBareMode()(or new async variant) returns true when token is availablelaunchClaude()at line 162-167 detects bare mode should be active- New logic generates
--settings '{"apiKeyHelper": "echo <token>"}'arg - Claude CLI receives
--bare --settings ...and uses apiKeyHelper for auth - On auth failure (expired token, etc.), catch block at lines 441-553 handles the error
Affected Interfaces (ALL must be updated):
ClaudeCliOptionsatsrc/utils/claude.ts:56-84- Add optionalsettings?: string | Record<string, unknown>
Critical Implementation Note: The shouldUseBareMode() function is currently synchronous. Reading from Keychain requires spawning a subprocess (security command on macOS), which is async. Either: (a) make it async, (b) create a separate async function that the sync function delegates to at launchClaude callsite, or (c) read credentials at startup and cache.
Integration Points
launchClaude()is the single point where--bareand--settingsargs are built - no other files need modification for the core flow- All 9 call sites automatically benefit because they don't set
bareexplicitly - they rely on the auto-apply logic at line 163 - Error handling at lines 441-553 already catches Claude CLI errors via stderr - auth failures from expired tokens will be caught here
Medium Severity Risks
- Shell escaping of OAuth token in apiKeyHelper: The token is base64-ish and may contain characters that need escaping in
echo "TOKEN"command passed inline. Using single quotes around the token in the echo command should be sufficient, but tokens with single quotes would break. - Performance of credential extraction: Reading from macOS Keychain (
securityCLI) or filesystem adds latency to every utility call. Could be mitigated by caching the token in memory for the process lifetime. CLAUDE_CODE_OAUTH_TOKENenv var: If this env var is set, it could be used directly instead of reading from Keychain, providing a simpler path. Worth checking if callers might set this.
Implementation Plan for Issue #977 -- OAuth via apiKeyHelper for --bare modeSummaryExtend the existing Questions and Key Decisions
High-Level Execution Phases
Quick Stats
Potential Risks (HIGH/CRITICAL only)
Complete Implementation Guide (click to expand for step-by-step details)Automated Test Cases to CreateTest File:
|
Implementation Complete - Issue #977SummaryExtended bare mode auto-apply logic to work for OAuth-authenticated users. When Changes Made
Validation Results
Detailed Changes by File (click to expand)Files Modified
|
Combined Analysis & Plan - Issue #977Status: In Progress
|
Combined Analysis & Plan - Issue #977 (Prompt Too Long Retry)
Executive SummaryWhen Implementation OverviewHigh-Level Execution Phases
Quick Stats
Complete Analysis & Implementation Details (click to expand)Research FindingsProblem Space
Codebase Research
Affected Files
Integration Points
Implementation PlanAutomated Test Cases to CreateTest File: Click to expand complete test structure (30 lines)describe('prompt too long retry with opus[1m]', () => {
// Test in generateAndPostSummary context
it('should retry with opus[1m] when launchClaude throws "Prompt is too long" error', async () => {
// First call rejects with "Prompt is too long", second call succeeds with valid summary
// Verify launchClaude called twice: first with 'sonnet', second with 'opus[1m]'
// Verify comment was posted successfully
})
it('should retry with opus[1m] when launchClaude returns "Prompt is too long" as result text', async () => {
// First call resolves with string containing "Prompt is too long", second call succeeds
// Verify launchClaude called twice: first with 'sonnet', second with 'opus[1m]'
})
it('should not retry when launchClaude fails with a different error', async () => {
// Rejects with "Claude API error" -- should NOT retry, should be non-blocking
// Verify launchClaude called only once
})
// Test in generateSummary context
it('should retry with opus[1m] in generateSummary when prompt is too long', async () => {
// First call rejects with "Prompt is too long", second succeeds
// Verify launchClaude called twice
// Verify returned summary is from the retry call
})
it('should throw when retry also fails in generateSummary', async () => {
// Both calls reject -- should throw (generateSummary is NOT non-blocking)
// Verify launchClaude called twice
})
})Files to Modify1.
|
…long When session transcript exceeds Sonnet's 200K context window, SessionSummaryService now detects the "Prompt is too long" error and automatically retries with opus[1m] (1M context). This handles long sessions that would previously fail silently. Fixes #977
- Fetch staged diff upfront instead of relying on Claude directory access - Remove addDir option to eliminate unnecessary worktree context - Add effort: 'low' to generate messages faster with lighter weight - Truncate diffs exceeding 50KB to prevent token limit issues - Embed diff as structured XML section in commit prompt Fixes #977
iloom Session SummaryKey Themes:
Session Details (click to expand)Key Insights
Decisions Made
Challenges Resolved
Lessons Learned
Generated with 🤖❤️ by iloom.ai |
Fixes #977
Implment --bare flag on branch naming and commit message generation claude cli invocations
Issue details
This one is a long shot due to OAUTH issues. If env.ANTHROPIC_API_KEY is undefined, we will have to use the --settings flag to configure apiKeyHelper to return the Oauth token, and if it fails, just fall back to non --bare mode.
From docs:
--bare Minimal mode: skip hooks, LSP, plugin sync, attribution, auto-memory, background prefetches, keychain reads, and CLAUDE.md auto-discovery. Sets CLAUDE_CODE_SIMPLE=1. Anthropic auth is strictly ANTHROPIC_API_KEY or apiKeyHelper via --settings (OAuth and keychain are never read). 3P providers (Bedrock/Vertex/Foundry) use their own credentials. Skills still resolve via /skill-name. Explicitly provide context via: --system-prompt[-file], --append-system-prompt[-file], --add-dir (CLAUDE.md dirs), --mcp-config, --settings, --agents, --plugin-dir.
This PR was created automatically by iloom.