Instructions to use jpanasuk/basecamp with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- HERMES
How to use jpanasuk/basecamp with HERMES:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
| set -e | |
| echo "================================================" | |
| echo " BASECAMP β AI Agent + Local Inference" | |
| echo " Portable. Auto-discovering. Stack-agnostic." | |
| echo " (Isolated: config lives only in basecamp state)" | |
| echo "================================================" | |
| echo "" | |
| # Start Ollama via supervisor in background | |
| supervisord -c /etc/supervisor/conf.d/supervisord.conf & | |
| # Wait for Ollama to be ready | |
| echo "Starting local Ollama..." | |
| for i in $(seq 1 60); do | |
| if curl -s http://127.0.0.1:11434/api/tags > /dev/null 2>&1; then | |
| echo "Local Ollama is up." | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| # First run: show connect screen. Everything written lives inside basecamp's | |
| # own state (the mounted volume) β never touches a host hermes install. | |
| CONFIG_FILE="/root/.hermes/basecamp_config.json" | |
| ENV_FILE="/opt/basecamp/basecamp.env" | |
| # FIX 2026-08-10: ALWAYS re-scan, even when a config exists. The old logic | |
| # skipped discovery when config was found ("Config found. Regenerating | |
| # tavern toolkit..."), so newly-added stack services stayed invisible until | |
| # the user manually ran `tavern rediscover`. The box must discover fresh | |
| # on every boot β that's the whole point of auto-discovery. | |
| echo "" | |
| echo "=== Scanning for AI services ===" | |
| echo "" | |
| if python3 /opt/basecamp/discover.py serve; then | |
| : | |
| else | |
| echo "" | |
| echo "Discovery failed. Falling back to basecamp's own Ollama." | |
| python3 /opt/basecamp/discover.py env || true | |
| # Install the secret-free static tavern so stack commands still work | |
| cp /opt/basecamp/tavern.sh /usr/local/bin/tavern 2>/dev/null || true | |
| chmod +x /usr/local/bin/tavern 2>/dev/null || true | |
| fi | |
| # Apply Hermes runtime config β process-scoped env vars, no config.yaml/.env writes | |
| if [ -f "$ENV_FILE" ]; then | |
| # shellcheck disable=SC1090 | |
| . "$ENV_FILE" | |
| fi | |
| # Best-effort: if Hermes has no model configured yet, set it via Hermes' own | |
| # Best-effort: if Hermes has no model configured yet, set it via Hermes' own | |
| # config CLI (schema-safe). This only ever writes inside basecamp's own HERMES_HOME. | |
| if [ -n "${HERMES_MODEL:-}" ] && ! hermes config get model > /dev/null 2>&1; then | |
| hermes config set model "$HERMES_MODEL" > /dev/null 2>&1 || true | |
| fi | |
| # CRITICAL (v0.20+): the stock config.yaml ships a default model+base_url | |
| # (openrouter), so the guard above never fires and env-only wiring | |
| # (OPENAI_BASE_URL / OPENAI_API_KEY) is IGNORED for non-authoritative hosts β | |
| # hermes's #28660 security gate blocks env keys for LAN/custom endpoints and | |
| # sends the "no-key-required" sentinel instead (auth 401). The sanctioned path | |
| # is a NAMED custom provider with an inline api_key. Configure it in | |
| # basecamp's OWN HERMES_HOME (never a host install). | |
| if [ -n "${OPENAI_BASE_URL:-}" ]; then | |
| hermes config set providers.basecamp.api "$OPENAI_BASE_URL" > /dev/null 2>&1 || true | |
| hermes config set providers.basecamp.default_model "$HERMES_MODEL" > /dev/null 2>&1 || true | |
| if [ -n "${OPENAI_API_KEY:-}" ]; then | |
| hermes config set providers.basecamp.api_key "$OPENAI_API_KEY" > /dev/null 2>&1 || true | |
| fi | |
| hermes config set providers.basecamp.context_length 131072 > /dev/null 2>&1 || true | |
| hermes config set model.provider basecamp > /dev/null 2>&1 || true | |
| hermes config set model.default "$HERMES_MODEL" > /dev/null 2>&1 || true | |
| # Drop the stock openrouter base_url so model.base_url doesn't lie about | |
| # where traffic actually goes (the named provider's api is authoritative). | |
| hermes config set model.base_url "" > /dev/null 2>&1 || true | |
| # Local engines (ollama/tabbyapi/vllm) generally don't support hermes's | |
| # reasoning-effort params β sending them yields "does not support thinking" | |
| # HTTP 400. Turn reasoning off for the basecamp provider. | |
| hermes config set agent.reasoning_effort off > /dev/null 2>&1 || true | |
| # Clear stale context probes so the live endpoint is re-queried. | |
| rm -f "${HERMES_HOME:-/root/.hermes}/context_length_cache.yaml" 2>/dev/null || true | |
| fi | |
| # Basecamp's own skin β install into basecamp's HERMES_HOME and activate it. | |
| # (Writes only inside the container's own state, never a host install.) | |
| if [ -d /opt/basecamp/skins ] && [ -f /opt/basecamp/skins/indigo.yaml ]; then | |
| mkdir -p "${HERMES_HOME:-/root/.hermes}/skins" | |
| cp /opt/basecamp/skins/indigo.yaml "${HERMES_HOME:-/root/.hermes}/skins/indigo.yaml" | |
| hermes config set display.skin indigo > /dev/null 2>&1 || true | |
| fi | |
| # ββ The tavern MCP server β exposes the connectivity toolkit as REAL | |
| # Hermes tools (mcp_tavern_status, mcp_tavern_self_check, mcp_tavern_wire, | |
| # mcp_tavern_rediscover, mcp_tavern_models, mcp_tavern_chat). The agent | |
| # sees them in its tool list and CALLS them β it can't invent commands | |
| # that don't exist. Writes only inside basecamp's own HERMES_HOME. | |
| # Injected DIRECTLY into config.yaml with yq (idempotent) β the | |
| # `hermes config set`/`hermes mcp add` paths get clobbered by hermes's | |
| # first-run config regeneration, but a yq write to the file survives. | |
| # Runs again just before exec hermes (below) so the injection happens | |
| # AFTER hermes's first-run config write, on every boot. | |
| inject_tavern_mcp() { | |
| if [ -f /opt/basecamp/tavern_mcp.py ]; then | |
| CFG="${HERMES_HOME:-/root/.hermes}/config.yaml" | |
| if [ -f "$CFG" ]; then | |
| yq -i '.mcp_servers.tavern.command = "python3" | | |
| .mcp_servers.tavern.args = ["/opt/basecamp/tavern_mcp.py"] | | |
| .mcp_servers.tavern.timeout = 120' "$CFG" 2>/dev/null || true | |
| fi | |
| fi | |
| } | |
| inject_tavern_mcp | |
| # Basecamp's own identity β install the SOUL.md that makes this Hermes | |
| # KNOW it must load the basecamp-stack skill for any stack question. | |
| # (Writes only inside the container's own state, never a host install.) | |
| if [ -f /opt/basecamp/SOUL.md ]; then | |
| cp /opt/basecamp/SOUL.md "${HERMES_HOME:-/root/.hermes}/SOUL.md" | |
| fi | |
| # Pull default model in background β AFTER discovery so the network scan | |
| # isn't competing with a multi-GB download (missed-service boot race). | |
| if [ -n "$BASECAMP_MODEL" ]; then | |
| if ! ollama list 2>/dev/null | grep -q "$BASECAMP_MODEL"; then | |
| echo "Pulling $BASECAMP_MODEL in background..." | |
| ollama pull "$BASECAMP_MODEL" > /dev/null 2>&1 & | |
| fi | |
| fi | |
| # Stack wiring audit β show every boot what's connected and what needs a fix. | |
| # (Read-only: audits and prints fixes; never edits other containers' configs.) | |
| if [ -x /opt/basecamp/discover.py ]; then | |
| echo "" | |
| echo "ββββββββββββββββββββββββββββββββββββββββββββ" | |
| echo " β Connected & wired β auditing your stack" | |
| echo "ββββββββββββββββββββββββββββββββββββββββββββ" | |
| python3 /opt/basecamp/discover.py wire 2>/dev/null || true | |
| fi | |
| echo "" | |
| echo "ββββββββββββββββββββββββββββββββββββββββββββ" | |
| echo " π Starting Basecamp Hermes..." | |
| echo " (this is the agent you'll talk to β loading" | |
| echo " its tools, skills, and memory. ~10-30s)" | |
| echo "ββββββββββββββββββββββββββββββββββββββββββββ" | |
| echo "" | |
| # Re-inject the tavern MCP server β config.yaml definitely exists now | |
| # (hermes's first-run write happened above), so the connectivity toolkit | |
| # is registered on EVERY boot, first boot included. | |
| inject_tavern_mcp | |
| # Handle arguments | |
| if [ $# -gt 0 ]; then | |
| case "$1" in | |
| tavern) | |
| shift | |
| exec tavern "$@" | |
| ;; | |
| ollama) | |
| shift | |
| exec ollama "$@" | |
| ;; | |
| bash|shell) | |
| shift | |
| exec bash "$@" | |
| ;; | |
| rediscover) | |
| rm -f "$CONFIG_FILE" | |
| exec python3 /opt/basecamp/discover.py serve | |
| ;; | |
| *) | |
| # Force-load the stack skill so hermes always has the discovered | |
| # services + fix recipes in context (description matching alone | |
| # isn't reliable with 67 skills competing). | |
| exec hermes -s basecamp-stack "$@" | |
| ;; | |
| esac | |
| else | |
| echo "Type 'tavern help' for stack commands." | |
| echo "Type 'tavern rediscover' to re-scan for services." | |
| echo "" | |
| exec hermes -s basecamp-stack | |
| fi | |