parent
cf4e9983c2
commit
fdb4c845bb
4 changed files with 172 additions and 34 deletions
118
bin/disinto
118
bin/disinto
|
|
@ -31,6 +31,9 @@ FACTORY_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
export USER="${USER:-$(id -un)}"
|
export USER="${USER:-$(id -un)}"
|
||||||
export HOME="${HOME:-$(eval echo "~${USER}")}"
|
export HOME="${HOME:-$(eval echo "~${USER}")}"
|
||||||
|
|
||||||
|
# Chat Claude identity directory — separate from factory agents (#707)
|
||||||
|
export CHAT_CLAUDE_DIR="${CHAT_CLAUDE_DIR:-${HOME}/.claude-chat}"
|
||||||
|
|
||||||
source "${FACTORY_ROOT}/lib/env.sh"
|
source "${FACTORY_ROOT}/lib/env.sh"
|
||||||
source "${FACTORY_ROOT}/lib/ops-setup.sh" # setup_ops_repo, migrate_ops_repo
|
source "${FACTORY_ROOT}/lib/ops-setup.sh" # setup_ops_repo, migrate_ops_repo
|
||||||
source "${FACTORY_ROOT}/lib/hire-agent.sh"
|
source "${FACTORY_ROOT}/lib/hire-agent.sh"
|
||||||
|
|
@ -634,6 +637,98 @@ prompt_admin_password() {
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── Chat identity prompt helper ───────────────────────────────────────────────
|
||||||
|
# Prompts for separate Claude identity for disinto-chat (#707).
|
||||||
|
# On yes, creates ~/.claude-chat/ and runs claude login in subshell.
|
||||||
|
# Returns 0 on success, 1 on failure/skip.
|
||||||
|
# Usage: prompt_chat_identity [<env_file>]
|
||||||
|
prompt_chat_identity() {
|
||||||
|
local env_file="${1:-${FACTORY_ROOT}/.env}"
|
||||||
|
local chat_claude_dir="${CHAT_CLAUDE_DIR:-${HOME}/.claude-chat}"
|
||||||
|
local config_dir="${chat_claude_dir}/config"
|
||||||
|
|
||||||
|
# Skip if ANTHROPIC_API_KEY is set (API key mode — no OAuth needed)
|
||||||
|
if grep -q '^ANTHROPIC_API_KEY=' "$env_file" 2>/dev/null; then
|
||||||
|
local api_key
|
||||||
|
api_key=$(grep '^ANTHROPIC_API_KEY=' "$env_file" | cut -d= -f2-)
|
||||||
|
if [ -n "$api_key" ]; then
|
||||||
|
echo "Chat: ANTHROPIC_API_KEY set — skipping OAuth identity setup"
|
||||||
|
echo "Chat: Chat will use API key authentication (no ~/.claude-chat mount)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if ~/.claude-chat already exists and has credentials
|
||||||
|
if [ -d "$chat_claude_dir" ]; then
|
||||||
|
if [ -d "${config_dir}/credentials" ] && [ -n "$(ls -A "${config_dir}/credentials" 2>/dev/null)" ]; then
|
||||||
|
echo "Chat: ~/.claude-chat already configured (resuming from existing identity)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Non-interactive mode without explicit yes
|
||||||
|
if [ "$auto_yes" = true ]; then
|
||||||
|
echo "Chat: --yes provided — creating ~/.claude-chat identity"
|
||||||
|
# Create directory structure
|
||||||
|
install -d -m 0700 -o "$USER" "$config_dir"
|
||||||
|
# Skip claude login in non-interactive mode — user must run manually
|
||||||
|
echo "Chat: Identity directory created at ${chat_claude_dir}"
|
||||||
|
echo "Chat: Run 'CLAUDE_CONFIG_DIR=${config_dir} claude login' to authenticate"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Interactive mode: prompt for separate identity
|
||||||
|
if [ -t 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "── Separate Claude identity for disinto-chat ──────────────────────"
|
||||||
|
echo "Create a separate Claude identity for disinto-chat to avoid OAuth"
|
||||||
|
echo "refresh races with factory agents sharing ~/.claude?"
|
||||||
|
echo ""
|
||||||
|
printf "Use separate identity for chat? [Y/n] "
|
||||||
|
|
||||||
|
local response
|
||||||
|
IFS= read -r response
|
||||||
|
response="${response:-Y}"
|
||||||
|
|
||||||
|
case "$response" in
|
||||||
|
[Nn][Ee]|[Nn])
|
||||||
|
echo "Chat: Skipping separate identity — chat will use shared ~/.claude"
|
||||||
|
echo "Chat: Note: OAuth refresh races may occur with concurrent agents"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# User said yes — create identity and run login
|
||||||
|
echo ""
|
||||||
|
echo "Chat: Creating identity directory at ${chat_claude_dir}"
|
||||||
|
install -d -m 0700 -o "$USER" "$config_dir"
|
||||||
|
|
||||||
|
# Run claude login in subshell with CLAUDE_CONFIG_DIR set
|
||||||
|
echo "Chat: Launching Claude login for chat identity..."
|
||||||
|
echo "Chat: (This will authenticate to a separate Anthropic account)"
|
||||||
|
echo ""
|
||||||
|
CLAUDE_CONFIG_DIR="$config_dir" claude login
|
||||||
|
local login_rc=$?
|
||||||
|
|
||||||
|
if [ $login_rc -eq 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Chat: Claude identity configured at ${chat_claude_dir}"
|
||||||
|
echo "Chat: Chat container will use: ${chat_claude_dir}:/home/chat/.claude-chat"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "Error: Claude login failed (exit code ${login_rc})" >&2
|
||||||
|
echo "Chat: Identity not configured"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Non-interactive, no TTY
|
||||||
|
echo "Warning: cannot prompt for chat identity (no TTY)" >&2
|
||||||
|
echo "Chat: Skipping identity setup — run manually if needed"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# ── init command ─────────────────────────────────────────────────────────────
|
# ── init command ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
disinto_init() {
|
disinto_init() {
|
||||||
|
|
@ -762,6 +857,9 @@ p.write_text(text)
|
||||||
# This ensures the password is set before Forgejo user creation
|
# This ensures the password is set before Forgejo user creation
|
||||||
prompt_admin_password "${FACTORY_ROOT}/.env"
|
prompt_admin_password "${FACTORY_ROOT}/.env"
|
||||||
|
|
||||||
|
# Prompt for separate chat identity (#707)
|
||||||
|
prompt_chat_identity "${FACTORY_ROOT}/.env"
|
||||||
|
|
||||||
# Set up local Forgejo instance (provision if needed, create users/tokens/repo)
|
# Set up local Forgejo instance (provision if needed, create users/tokens/repo)
|
||||||
if [ "$rotate_tokens" = true ]; then
|
if [ "$rotate_tokens" = true ]; then
|
||||||
echo "Note: Forcing token rotation (tokens/passwords will be regenerated)"
|
echo "Note: Forcing token rotation (tokens/passwords will be regenerated)"
|
||||||
|
|
@ -976,9 +1074,10 @@ p.write_text(text)
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Write CLAUDE_SHARED_DIR and CLAUDE_CONFIG_DIR to .env (idempotent)
|
# Write CLAUDE_SHARED_DIR, CLAUDE_CONFIG_DIR, and CHAT_CLAUDE_DIR to .env (idempotent)
|
||||||
_env_set_idempotent "CLAUDE_SHARED_DIR" "$CLAUDE_SHARED_DIR" "$env_file"
|
_env_set_idempotent "CLAUDE_SHARED_DIR" "$CLAUDE_SHARED_DIR" "$env_file"
|
||||||
_env_set_idempotent "CLAUDE_CONFIG_DIR" "$CLAUDE_CONFIG_DIR" "$env_file"
|
_env_set_idempotent "CLAUDE_CONFIG_DIR" "$CLAUDE_CONFIG_DIR" "$env_file"
|
||||||
|
_env_set_idempotent "CHAT_CLAUDE_DIR" "$CHAT_CLAUDE_DIR" "$env_file"
|
||||||
|
|
||||||
# Activate default agents (zero-cost when idle — they only invoke Claude
|
# Activate default agents (zero-cost when idle — they only invoke Claude
|
||||||
# when there is actual work, so an empty project burns no LLM tokens)
|
# when there is actual work, so an empty project burns no LLM tokens)
|
||||||
|
|
@ -1006,15 +1105,24 @@ p.write_text(text)
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
echo "── Claude authentication ──────────────────────────────"
|
echo "── Claude authentication ──────────────────────────────"
|
||||||
echo " OAuth (shared across containers):"
|
echo " Factory agents (shared OAuth):"
|
||||||
echo " Run 'claude auth login' on the host once."
|
echo " Run 'claude auth login' on the host once."
|
||||||
echo " Credentials in ${CLAUDE_CONFIG_DIR} are shared across containers."
|
echo " Credentials in ${CLAUDE_CONFIG_DIR} are shared across containers."
|
||||||
|
echo ""
|
||||||
|
echo " disinto-chat (separate identity #707):"
|
||||||
|
echo " Separate identity created at ${CHAT_CLAUDE_DIR:-${HOME}/.claude-chat}"
|
||||||
|
echo " Container mounts: ${CHAT_CLAUDE_DIR:-${HOME}/.claude-chat}:/home/chat/.claude-chat"
|
||||||
|
echo " CLAUDE_CONFIG_DIR=/home/chat/.claude-chat/config"
|
||||||
|
echo ""
|
||||||
echo " API key (alternative — metered billing, no rotation issues):"
|
echo " API key (alternative — metered billing, no rotation issues):"
|
||||||
echo " Set ANTHROPIC_API_KEY in .env to skip OAuth entirely."
|
echo " Set ANTHROPIC_API_KEY in .env to skip OAuth entirely."
|
||||||
|
echo " Chat container will not mount identity directory."
|
||||||
echo ""
|
echo ""
|
||||||
echo "── Claude config directory ────────────────────────────"
|
echo "── Claude config directories ───────────────────────────"
|
||||||
echo " CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}"
|
echo " Factory agents: CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}"
|
||||||
echo " Add this to your shell rc (~/.bashrc or ~/.zshrc):"
|
echo " Chat service: CLAUDE_CONFIG_DIR=/home/chat/.claude-chat/config"
|
||||||
|
echo ""
|
||||||
|
echo " Add factory agents CLAUDE_CONFIG_DIR to your shell rc:"
|
||||||
echo " export CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}"
|
echo " export CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}"
|
||||||
echo " This ensures interactive Claude Code sessions on this host"
|
echo " This ensures interactive Claude Code sessions on this host"
|
||||||
echo " share the same OAuth lock and token store as the factory."
|
echo " share the same OAuth lock and token store as the factory."
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
python3 \
|
python3 \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Non-root user — fixed UID 10001 for sandbox hardening (#706)
|
# Non-root user — fixed UID 10001 for sandbox hardening (#706, #707)
|
||||||
RUN useradd -m -u 10001 -s /bin/bash chat
|
RUN useradd -m -u 10001 -s /bin/bash chat
|
||||||
|
|
||||||
# Copy application files
|
# Copy application files
|
||||||
|
|
@ -25,9 +25,16 @@ COPY ui/ /var/chat/ui/
|
||||||
|
|
||||||
RUN chmod +x /entrypoint-chat.sh /usr/local/bin/server.py
|
RUN chmod +x /entrypoint-chat.sh /usr/local/bin/server.py
|
||||||
|
|
||||||
|
# Create and set ownership of chat identity directory for #707
|
||||||
|
RUN install -d -m 0700 /home/chat/.claude-chat/config/credentials \
|
||||||
|
&& chown -R chat:chat /home/chat/.claude-chat
|
||||||
|
|
||||||
USER chat
|
USER chat
|
||||||
WORKDIR /var/chat
|
WORKDIR /var/chat
|
||||||
|
|
||||||
|
# Declare volume for chat identity — mounted from host at runtime (#707)
|
||||||
|
VOLUME /home/chat/.claude-chat
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||||||
CMD python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/')" || exit 1
|
CMD python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/')" || exit 1
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# lib/claude-config.sh — Shared Claude config directory helpers (#641)
|
# lib/claude-config.sh — Shared Claude config directory helpers (#641, #707)
|
||||||
#
|
#
|
||||||
# Provides setup_claude_config_dir() for creating/migrating CLAUDE_CONFIG_DIR
|
# Provides:
|
||||||
# and _env_set_idempotent() for writing env vars to .env files.
|
# setup_claude_dir <dir> [<auto_yes>] — Create/migrate a Claude config directory
|
||||||
|
# setup_claude_config_dir [auto_yes] — Wrapper for default CLAUDE_CONFIG_DIR
|
||||||
|
# _env_set_idempotent() — Write env vars to .env files
|
||||||
#
|
#
|
||||||
# Requires: CLAUDE_CONFIG_DIR, CLAUDE_SHARED_DIR (set by lib/env.sh)
|
# Requires: CLAUDE_CONFIG_DIR, CLAUDE_SHARED_DIR (set by lib/env.sh)
|
||||||
|
|
||||||
|
|
@ -21,24 +23,33 @@ _env_set_idempotent() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create the shared CLAUDE_CONFIG_DIR, optionally migrating ~/.claude.
|
# Create a Claude config directory, optionally migrating ~/.claude.
|
||||||
# Usage: setup_claude_config_dir [auto_yes]
|
# This is the parameterized helper that handles any CLAUDE_CONFIG_DIR path.
|
||||||
setup_claude_config_dir() {
|
# Usage: setup_claude_dir <config_dir> [auto_yes]
|
||||||
local auto_yes="${1:-false}"
|
# setup_claude_dir /path/to/config [true]
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# $1 - Path to the Claude config directory to create
|
||||||
|
# $2 - Auto-confirm mode (true/false), defaults to false
|
||||||
|
#
|
||||||
|
# Returns: 0 on success, 1 on failure
|
||||||
|
setup_claude_dir() {
|
||||||
|
local config_dir="$1"
|
||||||
|
local auto_yes="${2:-false}"
|
||||||
local home_claude="${HOME}/.claude"
|
local home_claude="${HOME}/.claude"
|
||||||
|
|
||||||
# Create the shared config directory (idempotent)
|
# Create the config directory (idempotent)
|
||||||
install -d -m 0700 -o "$USER" "$CLAUDE_CONFIG_DIR"
|
install -d -m 0700 -o "$USER" "$config_dir"
|
||||||
echo "Claude: ${CLAUDE_CONFIG_DIR} (ready)"
|
echo "Claude: ${config_dir} (ready)"
|
||||||
|
|
||||||
# If ~/.claude is already a symlink to CLAUDE_CONFIG_DIR, nothing to do
|
# If ~/.claude is already a symlink to config_dir, nothing to do
|
||||||
if [ -L "$home_claude" ]; then
|
if [ -L "$home_claude" ]; then
|
||||||
local link_target
|
local link_target
|
||||||
link_target=$(readlink -f "$home_claude")
|
link_target=$(readlink -f "$home_claude")
|
||||||
local config_real
|
local config_real
|
||||||
config_real=$(readlink -f "$CLAUDE_CONFIG_DIR")
|
config_real=$(readlink -f "$config_dir")
|
||||||
if [ "$link_target" = "$config_real" ]; then
|
if [ "$link_target" = "$config_real" ]; then
|
||||||
echo "Claude: ${home_claude} -> ${CLAUDE_CONFIG_DIR} (symlink OK)"
|
echo "Claude: ${home_claude} -> ${config_dir} (symlink OK)"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
@ -54,25 +65,25 @@ setup_claude_config_dir() {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check CLAUDE_CONFIG_DIR contents
|
# Check config_dir contents
|
||||||
if [ -n "$(ls -A "$CLAUDE_CONFIG_DIR" 2>/dev/null)" ]; then
|
if [ -n "$(ls -A "$config_dir" 2>/dev/null)" ]; then
|
||||||
config_nonempty=true
|
config_nonempty=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Case: both non-empty — abort, operator must reconcile
|
# Case: both non-empty — abort, operator must reconcile
|
||||||
if [ "$home_nonempty" = true ] && [ "$config_nonempty" = true ]; then
|
if [ "$home_nonempty" = true ] && [ "$config_nonempty" = true ]; then
|
||||||
echo "ERROR: both ${home_claude} and ${CLAUDE_CONFIG_DIR} exist and are non-empty" >&2
|
echo "ERROR: both ${home_claude} and ${config_dir} exist and are non-empty" >&2
|
||||||
echo " Reconcile manually: merge or remove one, then re-run disinto init" >&2
|
echo " Reconcile manually: merge or remove one, then re-run disinto init" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Case: ~/.claude exists and CLAUDE_CONFIG_DIR is empty — offer migration
|
# Case: ~/.claude exists and config_dir is empty — offer migration
|
||||||
if [ "$home_nonempty" = true ] && [ "$config_nonempty" = false ]; then
|
if [ "$home_nonempty" = true ] && [ "$config_nonempty" = false ]; then
|
||||||
local do_migrate=false
|
local do_migrate=false
|
||||||
if [ "$auto_yes" = true ]; then
|
if [ "$auto_yes" = true ]; then
|
||||||
do_migrate=true
|
do_migrate=true
|
||||||
elif [ -t 0 ]; then
|
elif [ -t 0 ]; then
|
||||||
read -rp "Migrate ${home_claude} to ${CLAUDE_CONFIG_DIR}? [Y/n] " confirm
|
read -rp "Migrate ${home_claude} to ${config_dir}? [Y/n] " confirm
|
||||||
if [[ ! "$confirm" =~ ^[Nn] ]]; then
|
if [[ ! "$confirm" =~ ^[Nn] ]]; then
|
||||||
do_migrate=true
|
do_migrate=true
|
||||||
fi
|
fi
|
||||||
|
|
@ -83,11 +94,11 @@ setup_claude_config_dir() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$do_migrate" = true ]; then
|
if [ "$do_migrate" = true ]; then
|
||||||
# Move contents (not the dir itself) to preserve CLAUDE_CONFIG_DIR ownership
|
# Move contents (not the dir itself) to preserve config_dir ownership
|
||||||
cp -a "$home_claude/." "$CLAUDE_CONFIG_DIR/"
|
cp -a "$home_claude/." "$config_dir/"
|
||||||
rm -rf "$home_claude"
|
rm -rf "$home_claude"
|
||||||
ln -sfn "$CLAUDE_CONFIG_DIR" "$home_claude"
|
ln -sfn "$config_dir" "$home_claude"
|
||||||
echo "Claude: migrated ${home_claude} -> ${CLAUDE_CONFIG_DIR}"
|
echo "Claude: migrated ${home_claude} -> ${config_dir}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
@ -97,7 +108,15 @@ setup_claude_config_dir() {
|
||||||
rmdir "$home_claude" 2>/dev/null || true
|
rmdir "$home_claude" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
if [ ! -e "$home_claude" ]; then
|
if [ ! -e "$home_claude" ]; then
|
||||||
ln -sfn "$CLAUDE_CONFIG_DIR" "$home_claude"
|
ln -sfn "$config_dir" "$home_claude"
|
||||||
echo "Claude: ${home_claude} -> ${CLAUDE_CONFIG_DIR} (symlink created)"
|
echo "Claude: ${home_claude} -> ${config_dir} (symlink created)"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Create the shared CLAUDE_CONFIG_DIR, optionally migrating ~/.claude.
|
||||||
|
# Wrapper around setup_claude_dir for the default config directory.
|
||||||
|
# Usage: setup_claude_config_dir [auto_yes]
|
||||||
|
setup_claude_config_dir() {
|
||||||
|
local auto_yes="${1:-false}"
|
||||||
|
setup_claude_dir "$CLAUDE_CONFIG_DIR" "$auto_yes"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -473,9 +473,10 @@ services:
|
||||||
- disinto-net
|
- disinto-net
|
||||||
command: ["echo", "staging slot — replace with project image"]
|
command: ["echo", "staging slot — replace with project image"]
|
||||||
|
|
||||||
# Chat container — Claude chat UI backend (#705)
|
# Chat container — Claude chat UI backend (#705, #707)
|
||||||
# Internal service only; edge proxy routes to chat:8080
|
# Internal service only; edge proxy routes to chat:8080
|
||||||
# Sandbox hardened per #706 — no docker.sock, read-only rootfs, minimal caps
|
# Sandbox hardened per #706 — no docker.sock, read-only rootfs, minimal caps
|
||||||
|
# Separate identity mount (#707) to avoid OAuth refresh races with factory agents
|
||||||
chat:
|
chat:
|
||||||
build:
|
build:
|
||||||
context: ./docker/chat
|
context: ./docker/chat
|
||||||
|
|
@ -495,11 +496,15 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
# Mount claude binary from host (same as agents)
|
# Mount claude binary from host (same as agents)
|
||||||
- CLAUDE_BIN_PLACEHOLDER:/usr/local/bin/claude:ro
|
- CLAUDE_BIN_PLACEHOLDER:/usr/local/bin/claude:ro
|
||||||
# Throwaway named volume for chat config (isolated from host ~/.claude)
|
# Separate Claude identity mount for chat — isolated from factory agents (#707)
|
||||||
- chat-config:/var/chat/config
|
# Only mounted if ANTHROPIC_API_KEY is not set (API key mode skips OAuth)
|
||||||
|
- ${CHAT_CLAUDE_DIR:-${HOME}/.claude-chat}:/home/chat/.claude-chat
|
||||||
environment:
|
environment:
|
||||||
CHAT_HOST: "0.0.0.0"
|
CHAT_HOST: "0.0.0.0"
|
||||||
CHAT_PORT: "8080"
|
CHAT_PORT: "8080"
|
||||||
|
# Point Claude to separate identity directory
|
||||||
|
CLAUDE_CONFIG_DIR: /home/chat/.claude-chat/config
|
||||||
|
CLAUDE_CREDENTIALS_DIR: /home/chat/.claude-chat/config/credentials
|
||||||
networks:
|
networks:
|
||||||
- disinto-net
|
- disinto-net
|
||||||
|
|
||||||
|
|
@ -509,7 +514,6 @@ volumes:
|
||||||
agent-data:
|
agent-data:
|
||||||
project-repos:
|
project-repos:
|
||||||
caddy_data:
|
caddy_data:
|
||||||
chat-config:
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
disinto-net:
|
disinto-net:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue