Conversation
📝 WalkthroughWalkthroughAdds persistent host-side Claude long-lived OAuth token support with secure storage and auto-injection, a new Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI as vp CLI
participant Container as Claude Container
participant FS as File System (~/.config/vibepod/...)
User->>CLI: vp run claude setup-token
CLI->>Container: Launch container (interactive)
Container->>User: Display long-lived token
Container-->>CLI: Exit
CLI->>User: Prompt "Paste token:" (masked)
User->>CLI: Paste token
CLI->>FS: write oauth-token (0600)
FS-->>CLI: File created
CLI->>User: Confirm saved
sequenceDiagram
participant User
participant CLI as vp CLI
participant FS as File System (~/.config/vibepod/...)
participant Container as Claude Container
participant Env as Container Env
User->>CLI: vp run claude -p "say ok"
CLI->>FS: read oauth-token (if no host env)
FS-->>CLI: token or None
CLI->>CLI: Determine effective auth source (CLI env > agent config env > stored token > interactive creds)
alt Token available
CLI->>Env: set CLAUDE_CODE_OAUTH_TOKEN=token
else ANTHROPIC_API_KEY present
CLI->>Env: set ANTHROPIC_API_KEY=...
end
CLI->>Container: Launch with merged_env + passthrough args
Container->>Env: Read auth env
Container-->>User: Run command
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🤖 Augment PR SummarySummary: Adds a long-lived Claude Code OAuth token workflow (to bypass upstream refresh issues), plus diagnostics and CLI passthrough improvements. Changes:
Technical Notes: Uses Click/Typer extra-args support to preserve unknown flags for forwarding, and adds logic to avoid injecting stored tokens during 🤖 Was this summary useful? React with 👍 or 👎 |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/vibepod/commands/run.py (2)
3-29:⚠️ Potential issue | 🟡 MinorFix ruff I001 import ordering to unblock CI.
The CI pipeline flagged the import block as unsorted. Running
ruff check --fix(orruff format) locally should resolve it.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/vibepod/commands/run.py` around lines 3 - 29, The import block at the top (starting with "from __future__ import annotations" and including json, os, sys, time, datetime, pathlib.Path, typing.Annotated, typer, rich.prompt Confirm/Prompt and the vibepod.* imports) is unsorted and triggers ruff I001; reorder imports into standard-library, third-party, and local groups and alphabetize names within each group (preserve the future import first), or simply run "ruff check --fix" / "ruff format" to apply the correct ordering automatically so functions like agent_config_dir, DockerManager, SessionLogger, and console helpers remain available in the same scope.
539-579:⚠️ Potential issue | 🟡 Minor
setup-tokenprompt is skipped when--detachis used.If a user runs
vp run claude setup-token -d(or sets detach defaults elsewhere), the function returns at line 541 before reaching_capture_claude_setup_token, so the token is never captured. The interactiveclaude setup-tokenflow fundamentally needs a terminal — consider either rejecting--detachwithsetup-tokenup front, or warning the user that detach disables token capture.🛠️ Suggested guard
if detach: + if selected_agent == "claude" and "setup-token" in passthrough_args: + warning( + "`setup-token` needs an interactive terminal to capture the token; " + "ignoring --detach and attaching." + ) + else: success(f"Started {container.name}") return🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/vibepod/commands/run.py` around lines 539 - 579, The early return when detach is true skips the Claude setup-token flow; before returning on detach, check if selected_agent == "claude" and "setup-token" in passthrough_args and if so, refuse detach (or warn and force attach): replace the simple detach return with a guard that either raises/prints an error and exits (so users cannot run `--detach` with the interactive `claude setup-token`), or logs a warning and sets detach=False so the code continues to call _capture_claude_setup_token; adjust the block around variables detach, selected_agent, passthrough_args, container.name and the return to implement this guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/agents/index.md`:
- Around line 281-283: The fenced code block containing
"~/.config/vibepod/agents/claude/oauth-token (mode 0600)" is missing a
language tag; update the opening triple-backtick to include "text" (i.e., change
``` to ```text) so the block satisfies Markdownlint MD040 and renders correctly.
In `@src/vibepod/cli.py`:
- Around line 31-41: The alias handler _alias in _register_run_alias currently
has no parameters so Typer doesn't create option parsers; update _alias (or
extract a shared signature) to mirror the public parameters of run.run (e.g.,
workspace, pull, detach, env, name, network, paste_images, ikwid) using
typer.Option/Annotated signatures so Typer generates the same CLI flags, then
call run.run(...) with agent=agent_name and forward those parameters;
alternatively factor the parameter list into a shared helper used by both
run.run and _alias to avoid duplication.
In `@src/vibepod/commands/doctor.py`:
- Around line 11-16: Remove the unused imports to fix the ruff F401 CI failure:
delete Annotated from the typing import list and remove the unused symbol info
from the vibepod.utils.console import list so the import line becomes only the
actually used names (e.g., keep Any if used, and keep console, error, success,
warning). Update the import statements referencing typing and
vibepod.utils.console accordingly in the module where agent_config_dir and typer
are used (look for the top-level imports of Annotated and info).
In `@src/vibepod/commands/run.py`:
- Around line 51-56: The token file is created with default permissive mode by
Path.write_text before chmod; change _write_claude_stored_token to create and
write the file atomically with restricted permissions from the start: ensure the
parent directory exists (call
_claude_stored_token_path(config_dir).parent.mkdir(...)) then open the file
using os.open with flags os.O_WRONLY|os.O_CREAT|os.O_TRUNC and mode 0o600, wrap
the returned fd with os.fdopen and write token.strip() + "\n" using UTF-8, close
the file and return the Path; remove the separate os.chmod call since the file
is created with the correct mode.
In `@tests/test_doctor.py`:
- Around line 122-129: The test test_doctor_reports_host_env_mode should
explicitly isolate the environment so it exercises the CLAUDE_CODE_OAUTH_TOKEN
branch: in the test, after monkeypatching agent_config_dir (and before invoking
runner.invoke for app), remove or unset ANTHROPIC_API_KEY from the environment
(via monkeypatch.delenv or setting it to an empty value) and ensure
CLAUDE_CODE_OAUTH_TOKEN is set; this guarantees doctor.py's branch that checks
CLAUDE_CODE_OAUTH_TOKEN is executed rather than the ANTHROPIC_API_KEY branch.
---
Outside diff comments:
In `@src/vibepod/commands/run.py`:
- Around line 3-29: The import block at the top (starting with "from __future__
import annotations" and including json, os, sys, time, datetime, pathlib.Path,
typing.Annotated, typer, rich.prompt Confirm/Prompt and the vibepod.* imports)
is unsorted and triggers ruff I001; reorder imports into standard-library,
third-party, and local groups and alphabetize names within each group (preserve
the future import first), or simply run "ruff check --fix" / "ruff format" to
apply the correct ordering automatically so functions like agent_config_dir,
DockerManager, SessionLogger, and console helpers remain available in the same
scope.
- Around line 539-579: The early return when detach is true skips the Claude
setup-token flow; before returning on detach, check if selected_agent ==
"claude" and "setup-token" in passthrough_args and if so, refuse detach (or warn
and force attach): replace the simple detach return with a guard that either
raises/prints an error and exits (so users cannot run `--detach` with the
interactive `claude setup-token`), or logs a warning and sets detach=False so
the code continues to call _capture_claude_setup_token; adjust the block around
variables detach, selected_agent, passthrough_args, container.name and the
return to implement this guard.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d7acdb54-f564-4cca-94bd-441b3ffeecbc
📒 Files selected for processing (7)
docs/agents/index.mdsrc/vibepod/cli.pysrc/vibepod/commands/doctor.pysrc/vibepod/commands/run.pytests/test_claude_token.pytests/test_cli.pytests/test_doctor.py
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/vibepod/commands/doctor.py (2)
66-222: LGTM — diagnostic is thorough and exit-code semantics are well-defined.Path (
cfg_dir / "oauth-token") matches the constant used byrun.py(CLAUDE_TOKEN_FILENAME); precedence in the "Effective auth mode" section mirrors the actual auto-injection logic inrun.py(lines 345–354). The exit-code 2 gate correctly avoids false positives when a stored token or host env override would still authenticate the next run.One small consideration:
cfg_dir / "oauth-token"is duplicated here instead of importingCLAUDE_TOKEN_FILENAME/_claude_stored_token_pathfromrun.py. Minor drift risk if the filename ever changes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/vibepod/commands/doctor.py` around lines 66 - 222, The cfg_dir / "oauth-token" literal is duplicated instead of reusing the canonical constant/helper from run.py; replace the hard-coded filename with the shared symbol used by run.py (import CLAUDE_TOKEN_FILENAME or _claude_stored_token_path from run.py) and use that symbol when constructing stored_path and any related checks so the doctor command always matches run.py's CLAUDE token filename/logic.
39-54: Minor:EXPIRED Xm agois unfriendly for long-expired tokens.If a token expired several days ago, the output is "EXPIRED 4320m ago" rather than "3d ago". Consider reusing the same tiered formatter used in
_format_mtimefor consistency. Non-blocking.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/vibepod/commands/doctor.py` around lines 39 - 54, The expiry formatter _format_expiry currently shows long expirations as minutes (e.g., "EXPIRED 4320m ago"); update _format_expiry to reuse the same tiered human-friendly formatting used by _format_mtime (days/hours/minutes) so expired durations are rendered like "3d ago" or "2h 5m ago" instead of large minute counts; implement this by computing minutes = abs(delta_ms) // 60000 for negative deltas and using the same branch logic (minutes < 60, <1440, else) to build the "EXPIRED X" string, or factor the shared logic into a small helper that both _format_mtime and _format_expiry call.docs/agents/index.md (1)
308-312: Prefercatovernanoto inspect the token file.
nanoopens an editor and risks accidentally saving modifications (even a stray newline change) to a secret file.cat(orless) is safer for read-only inspection.📝 Proposed tweak
-ls -l ~/.config/vibepod/agents/claude/oauth-token -# or to view contents (treat as a secret — do not share): -nano ~/.config/vibepod/agents/claude/oauth-token +ls -l ~/.config/vibepod/agents/claude/oauth-token +# or to view contents (treat as a secret — do not share): +cat ~/.config/vibepod/agents/claude/oauth-token🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/agents/index.md` around lines 308 - 312, The markdown snippet shows using `nano` to view a secret token file which risks accidental edits; update the example code block so it recommends a read-only viewer like `cat` (or `less`) instead of `nano`, i.e., replace the `nano ~/.config/vibepod/agents/claude/oauth-token` line with a `cat` (or `less`) command and update the accompanying comment to emphasize read-only inspection.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@docs/agents/index.md`:
- Around line 308-312: The markdown snippet shows using `nano` to view a secret
token file which risks accidental edits; update the example code block so it
recommends a read-only viewer like `cat` (or `less`) instead of `nano`, i.e.,
replace the `nano ~/.config/vibepod/agents/claude/oauth-token` line with a `cat`
(or `less`) command and update the accompanying comment to emphasize read-only
inspection.
In `@src/vibepod/commands/doctor.py`:
- Around line 66-222: The cfg_dir / "oauth-token" literal is duplicated instead
of reusing the canonical constant/helper from run.py; replace the hard-coded
filename with the shared symbol used by run.py (import CLAUDE_TOKEN_FILENAME or
_claude_stored_token_path from run.py) and use that symbol when constructing
stored_path and any related checks so the doctor command always matches run.py's
CLAUDE token filename/logic.
- Around line 39-54: The expiry formatter _format_expiry currently shows long
expirations as minutes (e.g., "EXPIRED 4320m ago"); update _format_expiry to
reuse the same tiered human-friendly formatting used by _format_mtime
(days/hours/minutes) so expired durations are rendered like "3d ago" or "2h 5m
ago" instead of large minute counts; implement this by computing minutes =
abs(delta_ms) // 60000 for negative deltas and using the same branch logic
(minutes < 60, <1440, else) to build the "EXPIRED X" string, or factor the
shared logic into a small helper that both _format_mtime and _format_expiry
call.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c3e53fb5-fd8b-4a2a-8c08-a04be8fce271
📒 Files selected for processing (8)
docs/agents/index.mdsrc/vibepod/cli.pysrc/vibepod/commands/doctor.pysrc/vibepod/commands/run.pytests/test_claude_token.pytests/test_cli.pytests/test_config.pytests/test_doctor.py
✅ Files skipped from review due to trivial changes (1)
- tests/test_doctor.py
🚧 Files skipped from review as they are similar to previous changes (3)
- tests/test_cli.py
- tests/test_claude_token.py
- src/vibepod/commands/run.py
Introduces a robust workaround for Claude Code's OAuth token refresh bug by supporting long-lived tokens, adds a new diagnostic
doctorcommand for inspecting agent authentication state, and improves the CLI's flexibility and usability. The most significant changes are grouped below.Claude OAuth Long-lived Token Support:
oauth-tokenfile) asCLAUDE_CODE_OAUTH_TOKEN, bypassing the upstream refresh bug and reducing the need for frequent re-logins. [1] [2]CLI and Command Improvements:
doctorsubcommand to the CLI for inspecting agent authentication and config state, with detailed output for Claude credentials, stored tokens, environment overrides, and effective auth mode. [1] [2]vp runand its agent aliases to forward extra arguments, enabling flows likevp run claude setup-token. [1] [2] [3] [4]These changes make authentication with Claude more reliable.
Summary by CodeRabbit
New Features
vp doctorto inspect and report Claude authentication status.vp run claude setup-tokenone-time flow and automatic token injection on subsequent runs.Documentation
Tests