Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
125 changes: 125 additions & 0 deletions api/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/bin/sh
set -e

ROLE="${HONCHO_ROLE:-api}"
CONFIG_DIR="${HONCHO_CONFIG_DIR:-/config}"
ENV_FILE="${CONFIG_DIR}/.env"
CONFIG_TOML="${CONFIG_DIR}/config.toml"

echo "=== Honcho Dappnode — ${ROLE} ==="

# ── 1. Seed config.toml into shared volume if not present ─────
# On first boot, copy the baked-in honcho-self-hosted config.toml
# to the shared volume so the setup wizard can read/write it.
if [ ! -f "${CONFIG_TOML}" ]; then
mkdir -p "${CONFIG_DIR}"
if [ -f /app/config.toml ]; then
cp /app/config.toml "${CONFIG_TOML}"
echo "[Config] Seeded config.toml to shared volume"
fi
fi

# ── 2. Load env vars from shared .env file ────────────────────
# The setup wizard writes LLM_VLLM_API_KEY, LLM_VLLM_BASE_URL,
# LLM_MODEL, etc. to this file. Export them into the process
# environment so Honcho reads them at import time.
if [ -f "${ENV_FILE}" ]; then
echo "[Config] Loading env vars from ${ENV_FILE}"
while IFS= read -r line; do
# Skip comments and empty lines
case "$line" in
\#*|"") continue ;;
esac
# Export each KEY=VALUE pair
key=$(echo "$line" | cut -d= -f1)
val=$(echo "$line" | cut -d= -f2-)
export "$key"="$val"
done < "${ENV_FILE}"
fi

# ── 3. Rewrite config.toml for single-provider Dappnode mode ──
# The honcho-self-hosted config.toml has hardcoded model names for
# OpenRouter/xAI/Venice. Replace ALL model references + backup
# provider to use the single provider from the setup wizard.
if [ -f "${CONFIG_TOML}" ]; then
MODEL="${LLM_MODEL:-}"
BASE_URL="${LLM_VLLM_BASE_URL:-}"

if [ -n "${MODEL}" ]; then
sed -i "s|^MODEL = \".*\"|MODEL = \"${MODEL}\"|g" "${CONFIG_TOML}"
sed -i "s|^BACKUP_MODEL = \".*\"|BACKUP_MODEL = \"${MODEL}\"|g" "${CONFIG_TOML}"
sed -i "s|^DEDUCTION_MODEL = \".*\"|DEDUCTION_MODEL = \"${MODEL}\"|g" "${CONFIG_TOML}"
sed -i "s|^INDUCTION_MODEL = \".*\"|INDUCTION_MODEL = \"${MODEL}\"|g" "${CONFIG_TOML}"
echo "[Config] All model references set to: ${MODEL}"
fi

# Single provider mode: backup = same as primary
sed -i "s|^BACKUP_PROVIDER = \".*\"|BACKUP_PROVIDER = \"vllm\"|g" "${CONFIG_TOML}"

if [ -n "${BASE_URL}" ]; then
sed -i "s|^OPENAI_COMPATIBLE_BASE_URL = \".*\"|OPENAI_COMPATIBLE_BASE_URL = \"${BASE_URL}\"|g" "${CONFIG_TOML}"
fi

# Copy rewritten config.toml into /app where Honcho reads it
cp "${CONFIG_TOML}" /app/config.toml

echo "[Config] config.toml applied to /app/config.toml"
fi

# ── 3b. Set placeholder values if no provider configured yet ──
# On first boot before the wizard runs, LLM vars are empty.
# Set placeholders so clients.py can initialize without crashing.
# Actual LLM calls will fail, but the API server will start.
if [ -z "${LLM_VLLM_API_KEY}" ]; then
echo "[Config] WARNING: No LLM provider configured yet."
echo "[Config] Run the Setup Wizard at http://setup-wizard.honcho.dappnode:8080"
export LLM_VLLM_API_KEY="not-configured"
export LLM_VLLM_BASE_URL="https://localhost:9999"
export LLM_OPENAI_API_KEY="not-configured"
export LLM_OPENAI_COMPATIBLE_API_KEY="not-configured"
export LLM_EMBEDDING_API_KEY="not-configured"
fi

# ── 4. Ensure all Honcho env vars are exported ────────────────
# Even if the .env file was loaded above, make sure critical vars
# are set (they may come from docker-compose env or the wizard)
export AUTH_USE_AUTH=false
echo "[LLM] Base URL: ${LLM_VLLM_BASE_URL:-not set}"
echo "[LLM] Model: ${LLM_MODEL:-not set}"

# ── 5. Role-based startup ─────────────────────────────────────
if [ "${ROLE}" = "api" ]; then

echo "[DB] Waiting for PostgreSQL ..."
until pg_isready -h database -U honcho -q 2>/dev/null; do
sleep 2
done
echo "[DB] PostgreSQL is ready."

# On-demand backup dump for Dappnode backup button
pg_dump -h database -U honcho -d honcho --clean --if-exists \
-f /backup/honcho.sql 2>/dev/null || \
echo "[Backup] No existing data to dump (first boot)."

echo "[Migrations] Running ..."
cd /app
python -m alembic upgrade head 2>&1 || \
echo "[Migrations] Alembic failed — may already be up to date."
echo "[Migrations] Done."

echo "[Server] Starting Honcho API on :8000 ..."
exec uvicorn src.main:app \
--host 0.0.0.0 \
--port 8000 \
--workers 1

elif [ "${ROLE}" = "deriver" ]; then

sleep 5
echo "[Deriver] Starting background worker ..."
exec python -m src.deriver

else
echo "[ERROR] Unknown HONCHO_ROLE: ${ROLE}"
exit 1
fi
12 changes: 10 additions & 2 deletions dappnode_package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
{
"name": "honcho.dnp.dappnode.eth",
"version": "0.1.0",
"upstreamVersion": "v3.0.6",
"upstreamVersion": "v3.0.0",
"upstreamRepo": "chuygarcia92/honcho-self-hosted",
"upstreamArg": "UPSTREAM_VERSION",
"shortDescription": "Self-sovereign AI memory layer for Hermes and OpenClaw agents.",
"description": "Honcho is an open-source memory platform that gives your AI agents persistent, reasoning-backed memory across sessions. Based on the community-proven honcho-self-hosted project.\n\n**What Honcho does:**\n- Extracts observations from every message (Deriver)\n- Answers natural-language questions about users on demand (Dialectic)\n- Compresses long sessions into concise summaries (Summary)\n- Consolidates and refines stored memories periodically (Dream)\n\n**Endpoint:** `http://honcho.dappnode:8000`\n\n**LLM requirement:** Use the Setup Wizard to connect Honcho to your local Ollama package or any cloud API provider.",
"type": "service",
"mainService": "api",
"architectures": ["linux/amd64", "linux/arm64"],
"architectures": [
"linux/amd64",
"linux/arm64"
],
"requirements": {
"minimumDappnodeVersion": "0.2.30"
},
Expand All @@ -17,6 +20,11 @@
"name": "honcho-db-dump",
"path": "/backup/honcho.sql",
"service": "api"
},
{
"name": "honcho-llm-config",
"path": "/config/.env",
"service": "setup-wizard"
}
],
"changelog": "Initial release. Packages Honcho v3 using honcho-self-hosted config overlay with Dappnode Setup Wizard UI.",
Expand Down
59 changes: 59 additions & 0 deletions deriver/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
ARG UPSTREAM_VERSION

# ── Stage 1: Clone upstream Honcho source ─────────────────────
FROM python:3.12-slim AS source

ARG UPSTREAM_VERSION

RUN apt-get update && apt-get install -y --no-install-recommends git \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /src

# Clone upstream Honcho at pinned tag (fall back to main)
RUN git clone --depth 1 --branch ${UPSTREAM_VERSION} \
https://github.com/plastic-labs/honcho.git . \
|| git clone --depth 1 https://github.com/plastic-labs/honcho.git .

# Clone honcho-self-hosted config overlay
RUN git clone --depth 1 \
https://github.com/elkimek/honcho-self-hosted.git /overlay

# Overlay the proven config.toml from honcho-self-hosted
# This routes ALL workers through the "vllm" transport slot
# and prevents the "Missing client for Summary: google" error
RUN cp /overlay/config.toml /src/config.toml

# ── Stage 2: Build using upstream Honcho's own Dockerfile ─────
FROM python:3.12-slim

COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

RUN apt-get update && apt-get install -y --no-install-recommends \
git \
build-essential \
postgresql-client \
libpq5 \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY --from=source /src /app

# Install dependencies
ENV UV_LINK_MODE=copy
RUN uv sync --frozen --no-dev 2>/dev/null || uv sync --no-dev

# Activate venv via PATH (avoids broken shebang issues from multi-stage)
ENV PATH="/app/.venv/bin:$PATH"
ENV VIRTUAL_ENV="/app/.venv"

# Create backup output directory
RUN mkdir -p /backup

COPY entrypoint.sh /app/dappnode-entrypoint.sh
RUN chmod +x /app/dappnode-entrypoint.sh

EXPOSE 8000

ENTRYPOINT ["sh", "/app/dappnode-entrypoint.sh"]
125 changes: 125 additions & 0 deletions deriver/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/bin/sh
set -e

ROLE="${HONCHO_ROLE:-api}"
CONFIG_DIR="${HONCHO_CONFIG_DIR:-/config}"
ENV_FILE="${CONFIG_DIR}/.env"
CONFIG_TOML="${CONFIG_DIR}/config.toml"

echo "=== Honcho Dappnode — ${ROLE} ==="

# ── 1. Seed config.toml into shared volume if not present ─────
# On first boot, copy the baked-in honcho-self-hosted config.toml
# to the shared volume so the setup wizard can read/write it.
if [ ! -f "${CONFIG_TOML}" ]; then
mkdir -p "${CONFIG_DIR}"
if [ -f /app/config.toml ]; then
cp /app/config.toml "${CONFIG_TOML}"
echo "[Config] Seeded config.toml to shared volume"
fi
fi

# ── 2. Load env vars from shared .env file ────────────────────
# The setup wizard writes LLM_VLLM_API_KEY, LLM_VLLM_BASE_URL,
# LLM_MODEL, etc. to this file. Export them into the process
# environment so Honcho reads them at import time.
if [ -f "${ENV_FILE}" ]; then
echo "[Config] Loading env vars from ${ENV_FILE}"
while IFS= read -r line; do
# Skip comments and empty lines
case "$line" in
\#*|"") continue ;;
esac
# Export each KEY=VALUE pair
key=$(echo "$line" | cut -d= -f1)
val=$(echo "$line" | cut -d= -f2-)
export "$key"="$val"
done < "${ENV_FILE}"
fi

# ── 3. Rewrite config.toml for single-provider Dappnode mode ──
# The honcho-self-hosted config.toml has hardcoded model names for
# OpenRouter/xAI/Venice. Replace ALL model references + backup
# provider to use the single provider from the setup wizard.
if [ -f "${CONFIG_TOML}" ]; then
MODEL="${LLM_MODEL:-}"
BASE_URL="${LLM_VLLM_BASE_URL:-}"

if [ -n "${MODEL}" ]; then
sed -i "s|^MODEL = \".*\"|MODEL = \"${MODEL}\"|g" "${CONFIG_TOML}"
sed -i "s|^BACKUP_MODEL = \".*\"|BACKUP_MODEL = \"${MODEL}\"|g" "${CONFIG_TOML}"
sed -i "s|^DEDUCTION_MODEL = \".*\"|DEDUCTION_MODEL = \"${MODEL}\"|g" "${CONFIG_TOML}"
sed -i "s|^INDUCTION_MODEL = \".*\"|INDUCTION_MODEL = \"${MODEL}\"|g" "${CONFIG_TOML}"
echo "[Config] All model references set to: ${MODEL}"
fi

# Single provider mode: backup = same as primary
sed -i "s|^BACKUP_PROVIDER = \".*\"|BACKUP_PROVIDER = \"vllm\"|g" "${CONFIG_TOML}"

if [ -n "${BASE_URL}" ]; then
sed -i "s|^OPENAI_COMPATIBLE_BASE_URL = \".*\"|OPENAI_COMPATIBLE_BASE_URL = \"${BASE_URL}\"|g" "${CONFIG_TOML}"
fi

# Copy rewritten config.toml into /app where Honcho reads it
cp "${CONFIG_TOML}" /app/config.toml

echo "[Config] config.toml applied to /app/config.toml"
fi

# ── 3b. Set placeholder values if no provider configured yet ──
# On first boot before the wizard runs, LLM vars are empty.
# Set placeholders so clients.py can initialize without crashing.
# Actual LLM calls will fail, but the API server will start.
if [ -z "${LLM_VLLM_API_KEY}" ]; then
echo "[Config] WARNING: No LLM provider configured yet."
echo "[Config] Run the Setup Wizard at http://setup-wizard.honcho.dappnode:8080"
export LLM_VLLM_API_KEY="not-configured"
export LLM_VLLM_BASE_URL="https://localhost:9999"
export LLM_OPENAI_API_KEY="not-configured"
export LLM_OPENAI_COMPATIBLE_API_KEY="not-configured"
export LLM_EMBEDDING_API_KEY="not-configured"
fi

# ── 4. Ensure all Honcho env vars are exported ────────────────
# Even if the .env file was loaded above, make sure critical vars
# are set (they may come from docker-compose env or the wizard)
export AUTH_USE_AUTH=false
echo "[LLM] Base URL: ${LLM_VLLM_BASE_URL:-not set}"
echo "[LLM] Model: ${LLM_MODEL:-not set}"

# ── 5. Role-based startup ─────────────────────────────────────
if [ "${ROLE}" = "api" ]; then

echo "[DB] Waiting for PostgreSQL ..."
until pg_isready -h database -U honcho -q 2>/dev/null; do
sleep 2
done
echo "[DB] PostgreSQL is ready."

# On-demand backup dump for Dappnode backup button
pg_dump -h database -U honcho -d honcho --clean --if-exists \
-f /backup/honcho.sql 2>/dev/null || \
echo "[Backup] No existing data to dump (first boot)."

echo "[Migrations] Running ..."
cd /app
python -m alembic upgrade head 2>&1 || \
echo "[Migrations] Alembic failed — may already be up to date."
echo "[Migrations] Done."

echo "[Server] Starting Honcho API on :8000 ..."
exec uvicorn src.main:app \
--host 0.0.0.0 \
--port 8000 \
--workers 1

elif [ "${ROLE}" = "deriver" ]; then

sleep 5
echo "[Deriver] Starting background worker ..."
exec python -m src.deriver

else
echo "[ERROR] Unknown HONCHO_ROLE: ${ROLE}"
exit 1
fi
Loading
Loading