Skip to content

Commit a1bafab

Browse files
committed
wrapper: fix --no-continue interactive mode, add clear-session command
1 parent 65a54c1 commit a1bafab

3 files changed

Lines changed: 88 additions & 63 deletions

File tree

README.md

Lines changed: 38 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ Four ways to unleash it:
1616
- [What's Inside?](#-whats-inside-full-image)
1717
- [Requirements](#-requirements)
1818
- [Quick Start](#%EF%B8%8F-quick-start)
19-
- [ENV Vars](#-env-vars)
2019
- [Usage](#-usage)
20+
- [Env vars](#env-vars)
2121
- [Interactive mode](#interactive-mode)
2222
- [Programmatic mode](#programmatic-mode)
2323
- [API mode](#api-mode)
@@ -147,47 +147,27 @@ docker pull psyb0t/claude-code:latest
147147
# 4. check install.sh for how the wrapper script works and wire it up yourself
148148
```
149149

150-
## 🔐 ENV Vars
150+
## 🧙 Usage
151151

152-
### Wrapper script vars
152+
### Env vars
153153

154-
Set these on your host (e.g. `~/.bashrc`). The wrapper forwards them to the container.
154+
Set these on your host (e.g. `~/.bashrc`). Apply to all modes — the wrapper forwards them to the container.
155155

156-
| Variable | What it does | Default |
157-
| ------------------------- | ------------------------------------------------------------------------------ | -------------------- |
158-
| `CLAUDE_GIT_NAME` | Git commit name inside the container | _(none)_ |
159-
| `CLAUDE_GIT_EMAIL` | Git commit email inside the container | _(none)_ |
160-
| `ANTHROPIC_API_KEY` | API key for authentication | _(none)_ |
161-
| `CLAUDE_CODE_OAUTH_TOKEN` | OAuth token for authentication | _(none)_ |
162-
| `CLAUDE_DATA_DIR` | Custom `.claude` data directory | `~/.claude` |
163-
| `CLAUDE_SSH_DIR` | Custom SSH key directory | `~/.ssh/claude-code` |
164-
| `CLAUDE_INSTALL_DIR` | Custom install path for the wrapper (install-time only) | `/usr/local/bin` |
165-
| `CLAUDE_BIN_NAME` | Custom binary name (install-time only) | `claude` |
156+
| Variable | What it does | Default |
157+
| ------------------------- | ------------------------------------------------------------------------------- | -------------------- |
158+
| `ANTHROPIC_API_KEY` | API key for authentication | _(none)_ |
159+
| `CLAUDE_CODE_OAUTH_TOKEN` | OAuth token for authentication | _(none)_ |
160+
| `CLAUDE_GIT_NAME` | Git commit name inside the container | _(none)_ |
161+
| `CLAUDE_GIT_EMAIL` | Git commit email inside the container | _(none)_ |
162+
| `CLAUDE_DATA_DIR` | Custom `.claude` data directory | `~/.claude` |
163+
| `CLAUDE_SSH_DIR` | Custom SSH key directory | `~/.ssh/claude-code` |
164+
| `CLAUDE_INSTALL_DIR` | Custom install path for the wrapper (install-time only) | `/usr/local/bin` |
165+
| `CLAUDE_BIN_NAME` | Custom binary name (install-time only) | `claude` |
166166
| `CLAUDE_ENV_*` | Forward custom env vars (prefix is stripped: `CLAUDE_ENV_FOO=bar``FOO=bar`) | _(none)_ |
167-
| `CLAUDE_MOUNT_*` | Mount extra volumes (path = same in container, or `src:dest`) | _(none)_ |
168-
| `DEBUG` | Enable debug logging with timestamps | _(none)_ |
169-
170-
### API mode vars
171-
172-
Set directly on the container (e.g. docker-compose).
173-
174-
| Variable | What it does | Default |
175-
| ----------------------- | ------------------------------------------------------------------------ | -------- |
176-
| `CLAUDE_MODE_API` | Set to `1` to run as HTTP API server instead of interactive/programmatic | _(none)_ |
177-
| `CLAUDE_MODE_API_PORT` | Port for the API server | `8080` |
178-
| `CLAUDE_MODE_API_TOKEN` | Bearer token for API auth (optional) | _(none)_ |
179-
180-
### Telegram mode vars
181-
182-
Set directly on the container (e.g. docker-compose).
183-
184-
| Variable | What it does | Default |
185-
| --------------------------- | --------------------------------------------------- | ----------------------------------- |
186-
| `CLAUDE_MODE_TELEGRAM` | Set to `1` to run as Telegram bot | _(none)_ |
187-
| `CLAUDE_TELEGRAM_BOT_TOKEN` | Bot token from [@BotFather](https://t.me/BotFather) | _(none)_ |
188-
| `CLAUDE_TELEGRAM_CONFIG` | Path to the YAML config file inside the container | `/home/claude/.claude/telegram.yml` |
167+
| `CLAUDE_MOUNT_*` | Mount extra volumes (path = same in container, or `src:dest`) | _(none)_ |
168+
| `DEBUG` | Enable debug logging with timestamps | _(none)_ |
189169

190-
### Authentication
170+
#### Authentication
191171

192172
Either log in interactively or set up a token:
193173

@@ -202,7 +182,7 @@ CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-xxx claude "do stuff"
202182
ANTHROPIC_API_KEY=sk-ant-api03-xxx claude "do stuff"
203183
```
204184

205-
### Forwarding env vars
185+
#### Forwarding env vars
206186

207187
The `CLAUDE_ENV_` prefix lets you inject arbitrary env vars into the container. The prefix gets stripped:
208188

@@ -211,7 +191,7 @@ The `CLAUDE_ENV_` prefix lets you inject arbitrary env vars into the container.
211191
CLAUDE_ENV_GITHUB_TOKEN=xxx CLAUDE_ENV_MY_VAR=hello claude "do stuff"
212192
```
213193

214-
### Extra volume mounts
194+
#### Extra volume mounts
215195

216196
The `CLAUDE_MOUNT_` prefix mounts additional directories:
217197

@@ -224,8 +204,6 @@ CLAUDE_MOUNT_RO=/data:/data:ro claude "read the data" # read-only
224204

225205
If the value contains `:`, it's used as-is (docker `-v` syntax). Otherwise, same path on both sides.
226206

227-
## 🧙 Usage
228-
229207
### Interactive mode
230208

231209
```bash
@@ -235,7 +213,8 @@ claude
235213
Just like the native CLI but in a container. The container persists between runs — `--continue` resumes your last conversation automatically.
236214

237215
```bash
238-
claude --update # opt in to auto-update on this run
216+
claude --update # opt in to auto-update on this run
217+
claude --no-continue # start fresh (skip auto-resume of last conversation)
239218
```
240219

241220
### Utility commands
@@ -249,6 +228,7 @@ claude doctor # health check
249228
claude auth # manage authentication
250229
claude setup-token # interactive OAuth token setup
251230
claude stop # stop the running interactive container for this workspace
231+
claude clear-session # delete session history for this workspace (next run starts fresh)
252232
```
253233

254234
### Programmatic mode
@@ -422,6 +402,14 @@ services:
422402
- /var/run/docker.sock:/var/run/docker.sock
423403
```
424404
405+
#### Env vars
406+
407+
| Variable | What it does | Default |
408+
| ----------------------- | ------------------------------------------------------------------------ | -------- |
409+
| `CLAUDE_MODE_API` | Set to `1` to run as HTTP API server instead of interactive/programmatic | _(none)_ |
410+
| `CLAUDE_MODE_API_PORT` | Port for the API server | `8080` |
411+
| `CLAUDE_MODE_API_TOKEN` | Bearer token for API auth (optional) | _(none)_ |
412+
425413
#### Endpoints
426414

427415
**`POST /run`** — send a prompt, get JSON back:
@@ -538,6 +526,14 @@ services:
538526
- /var/run/docker.sock:/var/run/docker.sock
539527
```
540528

529+
#### Env vars
530+
531+
| Variable | What it does | Default |
532+
| --------------------------- | --------------------------------------------------- | ----------------------------------- |
533+
| `CLAUDE_MODE_TELEGRAM` | Set to `1` to run as Telegram bot | _(none)_ |
534+
| `CLAUDE_TELEGRAM_BOT_TOKEN` | Bot token from [@BotFather](https://t.me/BotFather) | _(none)_ |
535+
| `CLAUDE_TELEGRAM_CONFIG` | Path to the YAML config file inside the container | `/home/claude/.claude/telegram.yml` |
536+
541537
#### Bot commands
542538

543539
| Command | What it does |

entrypoint.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,14 @@ else
329329
dbg "running claude update"
330330
CMD="$CMD && claude update"
331331
fi
332-
CMD="$CMD && (claude --dangerously-skip-permissions --continue $SYSTEM_HINT_FLAG || exec claude --dangerously-skip-permissions $SYSTEM_HINT_FLAG)"
332+
NO_CONTINUE_FILE="/home/claude/.claude/.${CLAUDE_CONTAINER_NAME}-no-continue"
333+
if [ -f "$NO_CONTINUE_FILE" ]; then
334+
rm -f "$NO_CONTINUE_FILE"
335+
dbg "no-continue flag set, skipping --continue"
336+
CMD="$CMD && exec claude --dangerously-skip-permissions $SYSTEM_HINT_FLAG"
337+
else
338+
CMD="$CMD && (claude --dangerously-skip-permissions --continue $SYSTEM_HINT_FLAG || exec claude --dangerously-skip-permissions $SYSTEM_HINT_FLAG)"
339+
fi
333340
fi
334341

335342

wrapper.sh

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,19 @@ if [ "${1:-}" = "stop" ]; then
9393
exit 0
9494
fi
9595

96+
# clear-session — remove project session files for current workspace
97+
if [ "${1:-}" = "clear-session" ]; then
98+
project_path=$(echo "$PWD" | sed 's|/|-|g')
99+
project_dir="$CLAUDE_DIR/projects/${project_path}"
100+
if [ -d "$project_dir" ]; then
101+
rm -rf "$project_dir"
102+
echo "cleared session for $PWD"
103+
else
104+
echo "no session found for $PWD (looked in $project_dir)"
105+
fi
106+
exit 0
107+
fi
108+
96109
# passthrough commands — run in throwaway container, bypass entrypoint
97110
case "${1:-}" in
98111
-v|--version|doctor|auth)
@@ -105,6 +118,8 @@ esac
105118
if [ $# -gt 0 ]; then
106119
NEEDS_VERBOSE=0
107120
HAS_OUTPUT_FORMAT=0
121+
HAS_PROMPT=0
122+
HAS_NO_CONTINUE=0
108123
PASS_ARGS=(-p)
109124
EXPECT_VALUE=""
110125
for arg in "$@"; do
@@ -130,6 +145,7 @@ if [ $# -gt 0 ]; then
130145
# already added, skip
131146
;;
132147
--no-continue)
148+
HAS_NO_CONTINUE=1
133149
PASS_ARGS+=("$arg")
134150
;;
135151
--output-format|--model|--system-prompt|--append-system-prompt|--json-schema|--effort|--resume)
@@ -154,6 +170,7 @@ if [ $# -gt 0 ]; then
154170
;;
155171
*)
156172
# positional arg = prompt
173+
HAS_PROMPT=1
157174
PASS_ARGS+=("$arg")
158175
;;
159176
esac
@@ -164,27 +181,32 @@ if [ $# -gt 0 ]; then
164181
exit 1
165182
fi
166183

167-
[ "$NEEDS_VERBOSE" = "1" ] && PASS_ARGS+=(--verbose)
168-
[ "$HAS_OUTPUT_FORMAT" = "0" ] && PASS_ARGS+=(--output-format text)
169-
170-
dbg "PASS_ARGS: ${PASS_ARGS[*]}"
171-
172-
# Programmatic mode — own container, no TTY
173-
prog_name="${container_name}_prog"
174-
dbg "prog container: $prog_name"
175-
if ! docker ps -a --format '{{.Names}}' | grep -q "^${prog_name}$"; then
176-
dbg "prog: container does not exist, creating with docker run"
177-
docker run --name "$prog_name" "${DOCKER_ARGS[@]}" -e CLAUDE_CONTAINER_NAME="$prog_name" $CLAUDE_IMAGE "${PASS_ARGS[@]}"
178-
dbg "prog: docker run exited with $?"
179-
else
180-
dbg "prog: container exists, writing args file and starting"
181-
printf '%q ' "${PASS_ARGS[@]}" > "$CLAUDE_DIR/.${prog_name}-args"
182-
trap 'rm -f "$CLAUDE_DIR/.${prog_name}-args"' EXIT
183-
dbg "prog: docker start -a $prog_name"
184-
docker start -a "$prog_name"
185-
dbg "prog: docker start exited with $?"
184+
if [ "$HAS_PROMPT" = "1" ]; then
185+
[ "$NEEDS_VERBOSE" = "1" ] && PASS_ARGS+=(--verbose)
186+
[ "$HAS_OUTPUT_FORMAT" = "0" ] && PASS_ARGS+=(--output-format text)
187+
188+
dbg "PASS_ARGS: ${PASS_ARGS[*]}"
189+
190+
# Programmatic mode — own container, no TTY
191+
prog_name="${container_name}_prog"
192+
dbg "prog container: $prog_name"
193+
if ! docker ps -a --format '{{.Names}}' | grep -q "^${prog_name}$"; then
194+
dbg "prog: container does not exist, creating with docker run"
195+
docker run --name "$prog_name" "${DOCKER_ARGS[@]}" -e CLAUDE_CONTAINER_NAME="$prog_name" $CLAUDE_IMAGE "${PASS_ARGS[@]}"
196+
dbg "prog: docker run exited with $?"
197+
else
198+
dbg "prog: container exists, writing args file and starting"
199+
printf '%q ' "${PASS_ARGS[@]}" > "$CLAUDE_DIR/.${prog_name}-args"
200+
trap 'rm -f "$CLAUDE_DIR/.${prog_name}-args"' EXIT
201+
dbg "prog: docker start -a $prog_name"
202+
docker start -a "$prog_name"
203+
dbg "prog: docker start exited with $?"
204+
fi
205+
exit 0
186206
fi
187-
exit 0
207+
208+
# flag-only args (no prompt): fall through to interactive mode
209+
[ "$HAS_NO_CONTINUE" = "1" ] && touch "$CLAUDE_DIR/.${container_name}-no-continue"
188210
fi
189211

190212
# signal update via file (env vars don't work with docker start)

0 commit comments

Comments
 (0)