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
92 changes: 92 additions & 0 deletions apps/hermes-obsidian-bridge/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"$schema": "../app-info-schema.json",
"name": "Hermes Obsidian Bridge",
"id": "hermes-obsidian-bridge",
"available": true,
"short_desc": "OpenAI-compatible proxy in front of Hermes api_server with session continuity and vault RAG",
"author": "cori",
"port": 9120,
"categories": [
"ai",
"utilities"
],
"description": "Thin OpenAI-compatible proxy in front of the Hermes api_server. Adds session continuity (X-Session-Id), vault RAG via the Obsidian Local REST API (X-Obsidian-Note-Path), and automatic cost routing between a cheap and strong model based on prompt length. Wire it into any OpenAI-compatible Obsidian plugin (Copilot for Obsidian, Text Generator, Local GPT) for in-note chat with the full Hermes agent. Image: forge.407.lol/cori/hermes-obsidian-bridge:sha-7139662d. Source: https://github.com/cori/hermes-obsidian-bridge.",
"tipi_version": 1,
"version": "sha-7139662d",
"source": "https://github.com/cori/hermes-obsidian-bridge",
"website": "https://github.com/cori/hermes-obsidian-bridge",
"exposable": true,
"supported_architectures": [
"arm64",
"amd64"
],
"created_at": 1757610000000,
"updated_at": 1757610000000,
"dynamic_config": true,
"form_fields": [
{
"type": "password",
"label": "Hermes API Server Key",
"hint": "Bearer token for the Hermes api_server. Must match the API_SERVER_KEY on the gateway host. Required.",
"required": true,
"env_variable": "API_SERVER_KEY",
"default": ""
},
{
"type": "text",
"label": "Hermes api_server URL",
"hint": "Base URL of the Hermes api_server (e.g. http://192.168.1.10:8642). Used by the bridge for chat and model listing. host.docker.internal works for Docker Desktop; on Linux Runtipi, use the host IP.",
"required": false,
"env_variable": "HERMES_BASE_URL",
"default": "http://host.docker.internal:8642/v1"
},
{
"type": "text",
"label": "Obsidian Local REST API URL",
"hint": "Base URL of the Obsidian Local REST API plugin. Default 27123. On Tailscale setups, use the Mac's Tailscale IP.",
"required": false,
"env_variable": "OBSIDIAN_REST_URL",
"default": "http://host.docker.internal:27123"
},
{
"type": "password",
"label": "Obsidian Local REST API Key",
"hint": "API key from the Obsidian Local REST API plugin (Settings → Local REST API → API Key). Leave empty if the plugin is configured for no auth on a trusted network.",
"required": false,
"env_variable": "OBSIDIAN_REST_KEY",
"default": ""
},
{
"type": "text",
"label": "Cheap Model",
"hint": "Model id to route short prompts to. Default uses umans-flash to burn expiring credits.",
"required": false,
"env_variable": "CHEAP_MODEL",
"default": "umans-flash"
},
{
"type": "text",
"label": "Strong Model",
"hint": "Model id to route longer prompts to.",
"required": false,
"env_variable": "STRONG_MODEL",
"default": "minimax-m3"
},
{
"type": "number",
"label": "Cheap Model Char Threshold",
"hint": "Prompts shorter than this (in characters) go to CHEAP_MODEL. Set to a large number to disable cheap-routing entirely.",
"required": false,
"env_variable": "CHEAP_MODEL_CHAR_THRESHOLD",
"default": 500
},
{
"type": "text",
"label": "Enable Vault RAG",
"hint": "Set to 'true' to pre-fetch the current note + today's daily + this week's review from Obsidian and prepend as context. Set to 'false' to disable.",
"required": false,
"env_variable": "RAG_ENABLED",
"default": "true"
}
]
}
33 changes: 33 additions & 0 deletions apps/hermes-obsidian-bridge/docker-compose.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"schemaVersion": 2,
"services": [
{
"name": "hermes-obsidian-bridge",
"image": "forge.407.lol/cori/hermes-obsidian-bridge:sha-7139662d",
"isMain": true,
"internalPort": 9120,
"command": "python -m bridge",
"environment": [
{ "key": "PORT", "value": "9120" },
{ "key": "API_SERVER_KEY", "value": "${API_SERVER_KEY}" },
{ "key": "HERMES_BASE_URL", "value": "${HERMES_BASE_URL}" },
{ "key": "OBSIDIAN_REST_URL", "value": "${OBSIDIAN_REST_URL}" },
{ "key": "OBSIDIAN_REST_KEY", "value": "${OBSIDIAN_REST_KEY}" },
{ "key": "CHEAP_MODEL", "value": "${CHEAP_MODEL}" },
{ "key": "STRONG_MODEL", "value": "${STRONG_MODEL}" },
{ "key": "CHEAP_MODEL_CHAR_THRESHOLD", "value": "${CHEAP_MODEL_CHAR_THRESHOLD}" },
{ "key": "RAG_ENABLED", "value": "${RAG_ENABLED}" },
{ "key": "LOG_LEVEL", "value": "info" }
],
"volumes": [
{ "hostPath": "${APP_DATA_DIR}/data", "containerPath": "/data" }
],
"healthCheck": {
"test": "python -c \"import urllib.request,sys; r=urllib.request.urlopen('http://127.0.0.1:9120/health', timeout=3); sys.exit(0 if r.status==200 else 1)\"",
"interval": "30s",
"timeout": "5s",
"retries": 3
}
}
]
}
29 changes: 29 additions & 0 deletions apps/hermes-obsidian-bridge/metadata/description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Hermes Obsidian Bridge

A thin OpenAI-compatible proxy in front of the Hermes `api_server`. Designed to be pointed
at from any client that speaks OpenAI chat-completions (Copilot for Obsidian, Text Generator,
Local GPT, Open WebUI, curl scripts).

## What it adds

- **Session continuity.** Pass `X-Session-Id` and the bridge forwards it; conversations resume
across separate HTTP calls instead of starting a fresh session every time.
- **Vault RAG.** Send `X-Obsidian-Note-Path` and the bridge reads the current note + today's
daily + this week's review from the Obsidian Local REST API and prepends them as context.
- **Cost routing.** Prompts shorter than `CHEAP_MODEL_CHAR_THRESHOLD` go to `CHEAP_MODEL`;
longer ones go to `STRONG_MODEL`. Explicit `model` in the request body is always respected.

## Install

Install via the Runtipi dashboard. Required field: `API_SERVER_KEY` (the bearer token for
the Hermes `api_server` — must match the value on the gateway host's `~/.hermes/.env`).

## Wire to Obsidian

Any OpenAI-compatible community plugin works. Recommended: **Copilot for Obsidian**, with
base URL `http://hermes-obsidian-bridge.407.lol/v1` and any string as the API key.

## Image source

Image is built and hosted at `forge.407.lol/cori/hermes-obsidian-bridge` (local Forgejo).
Source repo: https://github.com/cori/hermes-obsidian-bridge.
Binary file added apps/hermes-obsidian-bridge/metadata/logo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 69 additions & 0 deletions apps/inventree/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"$schema": "../app-info-schema.json",
"name": "InvenTree",
"id": "inventree",
"available": true,
"short_desc": "Open-source inventory management for parts, components, BOMs, and stock control",
"author": "InvenTree",
"port": 8000,
"categories": ["data", "utilities"],
"description": "InvenTree is an open-source inventory management system providing intuitive parts management, stock control, BOM management, and supplier tracking. Designed for makers, hobbyists, and small businesses. Features hierarchical categories, custom fields, build orders, REST API, mobile app with barcode scanning, and a plugin ecosystem.",
"tipi_version": 1,
"version": "1.5.5",
"source": "https://github.com/inventree/InvenTree",
"website": "https://inventree.org",
"exposable": true,
"supported_architectures": ["arm64", "amd64"],
"created_at": 1726700000000,
"updated_at": 1726700000000,
"dynamic_config": true,
"form_fields": [
{
"type": "random",
"label": "Database Password",
"hint": "Password for the PostgreSQL database (auto-generated)",
"required": true,
"env_variable": "INVENTREE_DB_PASSWORD",
"encoding": "hex"
},
{
"type": "random",
"label": "Secret Key",
"hint": "Django secret key for cryptographic signing (auto-generated)",
"required": true,
"env_variable": "INVENTREE_SECRET_KEY",
"encoding": "hex"
},
{
"type": "text",
"label": "Admin User",
"hint": "Username for the InvenTree superuser account",
"required": true,
"env_variable": "INVENTREE_ADMIN_USER",
"default": "admin"
},
{
"type": "password",
"label": "Admin Password",
"hint": "Password for the InvenTree superuser account",
"required": true,
"env_variable": "INVENTREE_ADMIN_PASSWORD"
},
{
"type": "text",
"label": "Admin Email",
"hint": "Email for the InvenTree superuser account",
"required": false,
"env_variable": "INVENTREE_ADMIN_EMAIL",
"default": "admin@localhost"
},
{
"type": "text",
"label": "Site URL",
"hint": "The external URL for this InvenTree instance (used for links, CSRF, etc.)",
"required": true,
"env_variable": "INVENTREE_SITE_URL",
"default": "https://inventree.407.lol"
}
]
}
130 changes: 130 additions & 0 deletions apps/inventree/docker-compose.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{
"$schema": "../dynamic-compose-schema.json",
"schemaVersion": 2,
"services": [
{
"name": "inventree-db",
"image": "postgres:17",
"environment": [
{ "key": "PGDATA", "value": "/var/lib/postgresql/data/pgdb" },
{ "key": "POSTGRES_USER", "value": "inventree" },
{ "key": "POSTGRES_PASSWORD", "value": "${INVENTREE_DB_PASSWORD}" },
{ "key": "POSTGRES_DB", "value": "inventree" }
],
"volumes": [
{ "hostPath": "${APP_DATA_DIR}/pgdb", "containerPath": "/var/lib/postgresql/data" }
],
"healthCheck": {
"test": "pg_isready -U inventree -d inventree",
"interval": "15s",
"timeout": "5s",
"retries": 10
}
},
{
"name": "inventree-cache",
"image": "redis:7-alpine",
"command": [
"redis-server",
"--save",
"",
"--appendonly",
"no"
],
"volumes": [
{ "hostPath": "${APP_DATA_DIR}/redis", "containerPath": "/data" }
],
"healthCheck": {
"test": "redis-cli ping",
"interval": "15s",
"timeout": "5s",
"retries": 10
}
},
{
"name": "inventree-server",
"image": "inventree/inventree:1.5.5",
"isMain": true,
"internalPort": "8000",
"dependsOn": [
"inventree-db",
"inventree-cache"
],
"environment": [
{ "key": "INVENTREE_DB_ENGINE", "value": "postgresql" },
{ "key": "INVENTREE_DB_NAME", "value": "inventree" },
{ "key": "INVENTREE_DB_HOST", "value": "inventree-db" },
{ "key": "INVENTREE_DB_PORT", "value": "5432" },
{ "key": "INVENTREE_DB_USER", "value": "inventree" },
{ "key": "INVENTREE_DB_PASSWORD", "value": "${INVENTREE_DB_PASSWORD}" },
{ "key": "INVENTREE_CACHE_ENABLED", "value": "True" },
{ "key": "INVENTREE_CACHE_HOST", "value": "inventree-cache" },
{ "key": "INVENTREE_CACHE_PORT", "value": "6379" },
{ "key": "INVENTREE_SECRET_KEY", "value": "${INVENTREE_SECRET_KEY}" },
{ "key": "INVENTREE_SITE_URL", "value": "${INVENTREE_SITE_URL}" },
{ "key": "INVENTREE_WEB_PORT", "value": "8000" },
{ "key": "INVENTREE_LOG_LEVEL", "value": "WARNING" },
{ "key": "INVENTREE_PLUGINS_ENABLED", "value": "True" },
{ "key": "INVENTREE_AUTO_UPDATE", "value": "True" },
{ "key": "INVENTREE_ADMIN_USER", "value": "${INVENTREE_ADMIN_USER}" },
{ "key": "INVENTREE_ADMIN_PASSWORD", "value": "${INVENTREE_ADMIN_PASSWORD}" },
{ "key": "INVENTREE_ADMIN_EMAIL", "value": "${INVENTREE_ADMIN_EMAIL}" },
{ "key": "INVENTREE_USE_X_FORWARDED_HOST", "value": "True" },
{ "key": "INVENTREE_USE_X_FORWARDED_PORT", "value": "True" },
{ "key": "INVENTREE_USE_X_FORWARDED_PROTO", "value": "True" },
{ "key": "INVENTREE_GUNICORN_TIMEOUT", "value": "90" },
{ "key": "TZ", "value": "${TZ}" }
],
"volumes": [
{ "hostPath": "${APP_DATA_DIR}/data", "containerPath": "/home/inventree/data" }
],
"healthCheck": {
"test": "invoke server-health --address http://localhost:8000",
"interval": "20s",
"timeout": "5s",
"retries": 10
}
},
{
"name": "inventree-worker",
"image": "inventree/inventree:1.5.5",
"command": [
"invoke",
"worker"
],
"dependsOn": [
"inventree-server"
],
"environment": [
{ "key": "INVENTREE_DB_ENGINE", "value": "postgresql" },
{ "key": "INVENTREE_DB_NAME", "value": "inventree" },
{ "key": "INVENTREE_DB_HOST", "value": "inventree-db" },
{ "key": "INVENTREE_DB_PORT", "value": "5432" },
{ "key": "INVENTREE_DB_USER", "value": "inventree" },
{ "key": "INVENTREE_DB_PASSWORD", "value": "${INVENTREE_DB_PASSWORD}" },
{ "key": "INVENTREE_CACHE_ENABLED", "value": "True" },
{ "key": "INVENTREE_CACHE_HOST", "value": "inventree-cache" },
{ "key": "INVENTREE_CACHE_PORT", "value": "6379" },
{ "key": "INVENTREE_SECRET_KEY", "value": "${INVENTREE_SECRET_KEY}" },
{ "key": "INVENTREE_SITE_URL", "value": "${INVENTREE_SITE_URL}" },
{ "key": "INVENTREE_WEB_PORT", "value": "8000" },
{ "key": "INVENTREE_LOG_LEVEL", "value": "WARNING" },
{ "key": "INVENTREE_PLUGINS_ENABLED", "value": "True" },
{ "key": "INVENTREE_AUTO_UPDATE", "value": "True" },
{ "key": "INVENTREE_USE_X_FORWARDED_HOST", "value": "True" },
{ "key": "INVENTREE_USE_X_FORWARDED_PORT", "value": "True" },
{ "key": "INVENTREE_USE_X_FORWARDED_PROTO", "value": "True" },
{ "key": "TZ", "value": "${TZ}" }
],
"volumes": [
{ "hostPath": "${APP_DATA_DIR}/data", "containerPath": "/home/inventree/data" }
],
"healthCheck": {
"test": "invoke worker-health",
"interval": "60s",
"timeout": "10s",
"retries": 3
}
}
]
}
22 changes: 22 additions & 0 deletions apps/inventree/metadata/description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# InvenTree

InvenTree is an open-source inventory management system for parts, components, and stock control. It provides hierarchical categories, BOM management, supplier tracking, build orders, custom fields, a REST API, and a mobile app with barcode scanning.

## Features

- **Parts Management**: Hierarchical categories, custom fields, part images, datasheet attachments
- **Stock Control**: Multi-location stock tracking, serialized items, stock history
- **BOM Management**: Multi-level BOMs with substitutions, BOM import/export
- **Build Orders**: Consume stock to build assemblies, track build progress
- **Supplier Management**: Multi-vendor pricing, supplier part URLs, purchase orders
- **REST API**: Full CRUD API for integration with external tools
- **Mobile App**: iOS/Android with barcode scanning
- **Plugin System**: 50+ community plugins for integrations and custom workflows

## Setup

On first launch, InvenTree runs database migrations and creates the admin account from the form fields. This can take 1-2 minutes. The server is ready when the health check passes.

## Usage

Ideal for tracking electronic components, CNC tooling, consumables, PCB materials, and any physical inventory that needs structured organization with supplier links and BOM support.
Binary file added apps/inventree/metadata/logo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading