From a3454bcb572ed0da3b969fc0ab5e0d2dc9693bd0 Mon Sep 17 00:00:00 2001 From: Chaim Date: Wed, 27 May 2026 10:15:27 +0000 Subject: [PATCH] fix(training): bundle reference content + use docker bridge gateway MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Style Studio's curator-prompt + chat features read reference docs from disk at runtime. Two issues from the initial production run: 1. Dockerfile + .dockerignore excluded .claude/, docs/, and most of skills/. Now COPY the four specific files the new endpoints need: - .claude/agents/hermes-curator.md - skills/decision/SKILL.md - docs/legal-decision-lessons.md - docs/corpus-analysis.md .dockerignore opens whitelists for just those files. 2. Coolify's custom_docker_run_options=--add-host=host.docker.internal:host-gateway is not honored on dockerimage build_pack apps (ExtraHosts stayed []). Switch chat_proxy.py default to http://10.0.1.1:8770 — the docker0 bridge gateway, same pattern Paperclip uses for 3100. Bind the host pm2 service to 0.0.0.0:8770 so the container can reach it via the bridge IP. Oracle Cloud's security list keeps the port unreachable from the public internet. Co-Authored-By: Claude Opus 4.7 --- .dockerignore | 6 ++++++ Dockerfile | 12 ++++++++++++ scripts/legal-chat-service.config.cjs | 8 +++++++- web/chat_proxy.py | 17 ++++++++++++----- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/.dockerignore b/.dockerignore index 2020edc..c680482 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,7 @@ data/ .claude/ +!.claude/agents/ +!.claude/agents/hermes-curator.md mcp-server/.venv/ **/__pycache__/ *.pyc @@ -11,7 +13,11 @@ scripts/ skills/ !skills/docx/ !skills/docx/decision_template.docx +!skills/decision/ +!skills/decision/SKILL.md docs/ +!docs/legal-decision-lessons.md +!docs/corpus-analysis.md legacy/ node_modules/ .next/ diff --git a/Dockerfile b/Dockerfile index d34af39..66725d8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,6 +61,18 @@ COPY mcp-server/src/ ./mcp-server/src/ # (Path(__file__).resolve().parents[4] / "skills/docx/decision_template.docx") COPY skills/docx/decision_template.docx ./skills/docx/decision_template.docx +# Reference content the /training tab reads at runtime: +# - .claude/agents/hermes-curator.md → GET /api/training/curator/prompt +# - skills/decision/SKILL.md → system prompt for the chat +# - docs/legal-decision-lessons.md → system prompt for the chat +# - docs/corpus-analysis.md → system prompt for the chat +# +# These are read-only at runtime; chair edits go through git, not the container. +COPY .claude/agents/hermes-curator.md ./.claude/agents/hermes-curator.md +COPY skills/decision/SKILL.md ./skills/decision/SKILL.md +COPY docs/legal-decision-lessons.md ./docs/legal-decision-lessons.md +COPY docs/corpus-analysis.md ./docs/corpus-analysis.md + # Make mcp-server source available to web/app.py (it does sys.path.insert for legal_mcp) ENV PYTHONPATH=/app/mcp-server/src diff --git a/scripts/legal-chat-service.config.cjs b/scripts/legal-chat-service.config.cjs index c399d72..8330f44 100644 --- a/scripts/legal-chat-service.config.cjs +++ b/scripts/legal-chat-service.config.cjs @@ -31,7 +31,13 @@ module.exports = { // Run the in-package server via the venv interpreter so all // imports (claude_session, etc) resolve. script: "/home/chaim/legal-ai/mcp-server/.venv/bin/python", - args: "-m legal_mcp.chat_service.server --port 8770", + // Bind to 0.0.0.0 so the legal-ai container can reach the service + // via the docker bridge gateway (10.0.1.1:8770). Oracle Cloud's + // security list keeps port 8770 closed to the public internet; + // ufw is inactive but iptables INPUT default ACCEPT is fine here + // because the cloud-level firewall is the actual perimeter (same + // pattern paperclip uses for its 0.0.0.0:3100 binding). + args: "-m legal_mcp.chat_service.server --port 8770 --host 0.0.0.0", // claude CLI looks up credentials under HOME — make sure it // sees Daphna's session, not an empty container HOME. env: { diff --git a/web/chat_proxy.py b/web/chat_proxy.py index c52a8f0..58331ee 100644 --- a/web/chat_proxy.py +++ b/web/chat_proxy.py @@ -33,13 +33,20 @@ from web import chat_system_prompt logger = logging.getLogger(__name__) -# legal-chat-service lives on the host. In the container we reach it via -# host.docker.internal — which requires ``extra_hosts: host.docker.internal:host-gateway`` -# in the Coolify service definition. Set ``CHAT_SERVICE_URL`` to override -# (handy for local dev outside Docker). +# legal-chat-service lives on the host (pm2-managed, bound to 0.0.0.0:8770). +# From inside the container we reach it via the docker bridge gateway — +# 10.0.1.1 is the host on docker0 (the same address Paperclip uses for +# its 3100 bridge). Override with CHAT_SERVICE_URL if running outside +# Docker (local dev). +# +# Coolify's `custom_docker_run_options: --add-host=host.docker.internal:host-gateway` +# turned out NOT to apply to dockerimage-built apps as of Coolify 4.0.0, +# so the explicit IP is the reliable path. The cloud-level firewall +# (Oracle security list) keeps port 8770 unreachable from the public +# internet, matching the security posture of Paperclip's 3100. CHAT_SERVICE_URL = os.environ.get( "CHAT_SERVICE_URL", - "http://host.docker.internal:8770", + "http://10.0.1.1:8770", ) CHAT_SERVICE_TIMEOUT_S = float(os.environ.get("CHAT_SERVICE_TIMEOUT_S", "3600"))