mirror of
https://github.com/runyanjake/olomana.git
synced 2026-11-10 13:54:52 -08:00
Compare commits
6 Commits
020fd42208
...
5d3411c7e8
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d3411c7e8 | |||
| cb3a64aac4 | |||
| 61b5bbdd18 | |||
| 7f38fa2aed | |||
| b81d247ab4 | |||
| a619c3805f |
13
ai/llama_cpp/.env.example
Normal file
13
ai/llama_cpp/.env.example
Normal file
@ -0,0 +1,13 @@
|
||||
# Host directory path where GGUF models are stored
|
||||
MODELS_PATH=/pwspool/software/ai/llama_cpp
|
||||
|
||||
# Filename of the default model to load
|
||||
MODEL_FILE=Llama-3.1-8B-Instruct-Q4_K_M.gguf
|
||||
|
||||
# Optional API Key for securing endpoints (leave blank if internal-only, or set a secure token)
|
||||
API_KEY=your_super_secret_api_key_here
|
||||
|
||||
# Performance and hardware tuning
|
||||
GPU_LAYERS=999
|
||||
CTX_SIZE=4096
|
||||
THREADS=6
|
||||
1
ai/llama_cpp/.gitignore
vendored
Normal file
1
ai/llama_cpp/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.env
|
||||
18
ai/llama_cpp/README.md
Normal file
18
ai/llama_cpp/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Llama.cpp
|
||||
A general purpose llm server that projects can connect to.
|
||||
|
||||
## Network
|
||||
Create the `ai` docker network, applications can access the OpenAI spec server through `http://llm-server:8080/v1`.
|
||||
|
||||
## Setup
|
||||
1. Start service
|
||||
|
||||
```bash
|
||||
docker compose up
|
||||
```
|
||||
|
||||
2. Download model(s)
|
||||
```bash
|
||||
cd /pwspool/software/ai/llama_cpp
|
||||
sudo wget https://huggingface.co/bartowski/Meta-Llama-3.1-8B-Instruct-GGUF/resolve/main/Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf -O Llama-3.1-8B-Instruct-Q4_K_M.gguf
|
||||
```
|
||||
28
ai/llama_cpp/docker-compose.yml
Normal file
28
ai/llama_cpp/docker-compose.yml
Normal file
@ -0,0 +1,28 @@
|
||||
networks:
|
||||
ai:
|
||||
name: ai
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
llm-server:
|
||||
image: ghcr.io/ggml-org/llama.cpp:server-cuda
|
||||
container_name: llm-server
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- ai
|
||||
volumes:
|
||||
- ${MODELS_PATH:-/pwspool/software/ai/llama_cpp}:/models
|
||||
environment:
|
||||
- LLAMA_ARG_MODEL=/models/${MODEL_FILE:-Llama-3.1-8B-Instruct-Q4_K_M.gguf}
|
||||
- LLAMA_ARG_HOST=0.0.0.0
|
||||
- LLAMA_ARG_PORT=8080
|
||||
- LLAMA_ARG_N_GPU_LAYERS=${GPU_LAYERS:-999}
|
||||
- LLAMA_ARG_CTX_SIZE=${CTX_SIZE:-4096}
|
||||
- LLAMA_ARG_THREADS=${THREADS:-6}
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
@ -16,6 +16,8 @@ services:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /usr/bin/docker:/usr/local/bin/docker:ro
|
||||
- /usr/libexec/docker/cli-plugins/docker-compose:/usr/local/lib/docker/cli-plugins/docker-compose:ro
|
||||
- /usr/libexec/docker/cli-plugins:/usr/libexec/docker/cli-plugins:ro
|
||||
|
||||
labels:
|
||||
- traefik.http.routers.jenkins.rule=Host(`jenkins.whitney.rip`)
|
||||
- traefik.http.routers.jenkins.tls=true
|
||||
|
||||
49
software-development/project-management/multica/.env.example
Normal file
49
software-development/project-management/multica/.env.example
Normal file
@ -0,0 +1,49 @@
|
||||
# Public hostname (no scheme) and full origin. Everything (UI, /api, /ws) is served from this one host.
|
||||
FRONTEND_HOST=multica.example.com
|
||||
FRONTEND_ORIGIN=https://multica.example.com
|
||||
# Optional: public API URL used for webhook URLs and daemon setup commands. Same host works.
|
||||
MULTICA_PUBLIC_URL=https://multica.example.com
|
||||
|
||||
TRAEFIK_NETWORK=traefik
|
||||
# Host port (loopback only) for the local agent daemon: multica setup self-host --server-url http://localhost:<port>
|
||||
BACKEND_HOST_PORT=8090
|
||||
|
||||
# Required. Generate with `openssl rand -hex 32`
|
||||
JWT_SECRET=
|
||||
|
||||
# Database
|
||||
POSTGRES_USER=multica
|
||||
# Must be URL-safe (it's embedded in DATABASE_URL) — use `openssl rand -hex 24`, not base64
|
||||
POSTGRES_PASSWORD=
|
||||
POSTGRES_DATA_DIR=./data/postgres
|
||||
# Attachment storage (used when S3 is not configured)
|
||||
UPLOADS_DATA_DIR=./data/uploads
|
||||
|
||||
# Self-hosted Git integration (Forgejo/Gitea/GitLab). Generate with `openssl rand -base64 32`
|
||||
MULTICA_VCS_SECRET_KEY=
|
||||
|
||||
# Email for login codes — configure Resend OR SMTP (SMTP wins if SMTP_HOST is set).
|
||||
# Without either, login codes are only printed to the backend logs.
|
||||
RESEND_API_KEY=
|
||||
RESEND_FROM_EMAIL=noreply@example.com
|
||||
SMTP_HOST=
|
||||
SMTP_PORT=587
|
||||
SMTP_USERNAME=
|
||||
SMTP_PASSWORD=
|
||||
SMTP_FROM_EMAIL=
|
||||
# starttls (default) or implicit (port 465)
|
||||
SMTP_TLS=
|
||||
|
||||
# Optional Google login
|
||||
GOOGLE_CLIENT_ID=
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
|
||||
# Access control
|
||||
ALLOW_SIGNUP=true
|
||||
ALLOWED_EMAILS=
|
||||
ALLOWED_EMAIL_DOMAINS=
|
||||
# Set true after creating your workspace to force invite-only
|
||||
DISABLE_WORKSPACE_CREATION=false
|
||||
|
||||
# Set to 1 to disable the anonymous daily telemetry ping
|
||||
DO_NOT_TRACK=
|
||||
2
software-development/project-management/multica/.gitignore
vendored
Normal file
2
software-development/project-management/multica/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.env
|
||||
data/
|
||||
96
software-development/project-management/multica/README.md
Normal file
96
software-development/project-management/multica/README.md
Normal file
@ -0,0 +1,96 @@
|
||||
# Multica
|
||||
Open source project management with coding agents. Runs the official `ghcr.io/multica-ai/multica-backend` and `multica-web` images, plus Postgres (pgvector). Agents run on this host through the `multica` CLI daemon.
|
||||
|
||||
## Layout
|
||||
| Service | Networks | Exposed |
|
||||
| --- | --- | --- |
|
||||
| postgres | `internal` | — |
|
||||
| backend | `internal`, `traefik` | traefik: `/ws` on `FRONTEND_HOST`; host: `127.0.0.1:8090` (daemon) |
|
||||
| frontend | `internal`, `traefik` | traefik: everything else on `FRONTEND_HOST` |
|
||||
|
||||
- `internal` is a plain bridge for service-to-service traffic and outbound egress (email).
|
||||
- Single domain. Next.js proxies `/api`, `/auth`, `/uploads`, `/v1` to the backend. It does not proxy websockets, so traefik sends `/ws` to the backend directly.
|
||||
- No separate API domain. That layout requires `COOKIE_DOMAIN`, otherwise every write fails CSRF (403).
|
||||
- The backend entrypoint runs DB migrations on every start.
|
||||
|
||||
## Setup
|
||||
1. `cp .env.example .env` and fill it in.
|
||||
- `JWT_SECRET`: `openssl rand -hex 32`
|
||||
- `POSTGRES_PASSWORD`: `openssl rand -hex 24`. Must be URL-safe; base64 (`/`, `+`) breaks `DATABASE_URL` with "invalid port".
|
||||
- `MULTICA_VCS_SECRET_KEY`: `openssl rand -base64 32`
|
||||
2. Point DNS for `FRONTEND_HOST` at traefik.
|
||||
3. `docker compose up -d`
|
||||
4. Sign in with email. The code is sent via Resend/SMTP, or printed in `docker logs multica-backend-1` if email isn't working.
|
||||
5. After creating your workspace, optionally set `DISABLE_WORKSPACE_CREATION=true` and/or `ALLOW_SIGNUP=false`, then `docker compose up -d`.
|
||||
|
||||
## Versioning
|
||||
Server images and the CLI are released together and must run the same version. The tag is pinned in `docker-compose.yml` (currently `v0.6.5`), not in `.env`. Do not use `:latest`: a `docker compose pull` would move the server without the CLI.
|
||||
|
||||
## Local agent daemon
|
||||
Runs as the `multica` service user (system UID, home `/var/lib/multica`, no password, not in `docker`) under its systemd user unit. Connects to the backend on `127.0.0.1:${BACKEND_HOST_PORT}` (8090; 8080 belongs to traefik). The public domain does not resolve back to this host (hairpin NAT returns the router's self-signed cert), so use localhost.
|
||||
|
||||
The home directory is required: it holds `~/.multica` (config, token, logs), `~/.claude` (Claude Code login), `~/.config/systemd/user` (autostart unit), `~/multica_workspaces` (task checkouts) and `~/.local/bin` (CLIs).
|
||||
|
||||
Create the user:
|
||||
```bash
|
||||
sudo useradd --system --user-group --create-home --home-dir /var/lib/multica --shell /bin/bash multica
|
||||
sudo loginctl enable-linger multica # user systemd manager at boot, no login needed
|
||||
```
|
||||
|
||||
Shell as `multica` with a systemd user session (used by every command below and in Upgrade):
|
||||
```bash
|
||||
sudo -iu multica env XDG_RUNTIME_DIR=/run/user/$(id -u multica) \
|
||||
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u multica)/bus bash -l
|
||||
```
|
||||
|
||||
Inside that shell:
|
||||
```bash
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
# Claude Code (per-user install and login)
|
||||
curl -fsSL https://claude.ai/install.sh | bash
|
||||
claude # log in, then /exit
|
||||
|
||||
# multica CLI at the version pinned in docker-compose.yml
|
||||
VER=0.6.5
|
||||
cd "$(mktemp -d)"
|
||||
curl -fsSLO "https://github.com/multica-ai/multica/releases/download/v${VER}/multica-cli-${VER}-linux-amd64.tar.gz"
|
||||
curl -fsSLO "https://github.com/multica-ai/multica/releases/download/v${VER}/checksums.txt"
|
||||
sha256sum --check --ignore-missing checksums.txt
|
||||
tar -xzf "multica-cli-${VER}-linux-amd64.tar.gz" multica
|
||||
install -m 755 multica ~/.local/bin/multica
|
||||
cd ~
|
||||
|
||||
multica setup self-host --server-url http://localhost:8090 --app-url https://multica.whitney.rip
|
||||
multica login --token= # personal access token from Settings → Tokens in the web UI
|
||||
multica daemon start
|
||||
multica daemon status # expect: running, agent "claude", 1+ workspace
|
||||
multica daemon autostart enable # captures current PATH; ~/.local/bin must be on it
|
||||
```
|
||||
- Detects agent CLIs on `PATH` (`claude` here).
|
||||
- The autostart unit only inherits `PATH`. Daemon settings go in `multica config set`. Other env vars agents need (e.g. `GH_TOKEN`) go in `/var/lib/multica/.config/environment.d/*.conf`.
|
||||
- For agents that push code, give `multica` its own git identity and SSH key or token.
|
||||
- Status from `jr`: `sudo -u multica XDG_RUNTIME_DIR=/run/user/$(id -u multica) systemctl --user status multica-daemon`. Logs: `multica daemon logs` as `multica`.
|
||||
- Remove the user: `sudo loginctl disable-linger multica && sudo pkill -u multica && sudo userdel --remove multica`.
|
||||
- Sign out of the CLI: `multica auth logout`. This only deletes the local token; revoke it in the web UI too.
|
||||
|
||||
## Upgrade
|
||||
1. Change both image tags in `docker-compose.yml`.
|
||||
2. `docker compose pull && docker compose up -d && docker logs -f multica-backend-1`
|
||||
3. As `multica`, reinstall the CLI with the same `VER`, then `multica daemon stop && multica daemon start`.
|
||||
4. Check that `multica version` matches the image tag.
|
||||
|
||||
## Risks
|
||||
- **Agent access**: agents run as `multica`, which has no docker or sudo, but can still read anything world-readable on this host and reach localhost services (including the backend on 8090).
|
||||
- **`RESEND_API_KEY`**: the current value doesn't look like a Resend key (those start with `re_`). Until it's fixed, login codes only appear in the backend logs.
|
||||
- **No Redis**: auth endpoints have no rate limiting (logged at startup). Acceptable while signup is limited. Adding Redis also requires trusted-proxy settings (`RATE_LIMIT_TRUSTED_PROXIES`, `MULTICA_TRUSTED_PROXIES`) covering traefik and the frontend container, or all users share one rate-limit bucket.
|
||||
- **Uploads on local disk** (`UPLOADS_DATA_DIR`): back it up along with `POSTGRES_DATA_DIR`.
|
||||
- **Backend on the `traefik` network** (needed for `/ws`): other containers on that network can reach it directly.
|
||||
|
||||
## Possible extensions
|
||||
- **Email via SMTP** instead of Resend: set the `SMTP_*` vars.
|
||||
- **Google login**: `GOOGLE_CLIENT_ID`/`SECRET`. The redirect URI is `${FRONTEND_ORIGIN}/auth/callback`.
|
||||
- **GitHub App** (PR cards, repo picker): `GITHUB_APP_SLUG`, `GITHUB_WEBHOOK_SECRET`, `GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY`. Add them to compose. Needs `MULTICA_PUBLIC_URL` reachable from GitHub.
|
||||
- **Gitea/Forgejo integration**: already enabled (`MULTICA_VCS_*`). Connect it per workspace in Settings → Integrations.
|
||||
- **S3 storage, Slack/Lark/Telegram bots, server-side LLM (chat titles), plugins**: env vars are documented in upstream `.env.example` and `docker-compose.selfhost.yml`. Add the ones you need to the backend `environment:`.
|
||||
- **More agents**: install another supported CLI (`codex`, `opencode`, ...) on the host and restart the daemon.
|
||||
@ -0,0 +1,101 @@
|
||||
networks:
|
||||
# Service-to-service traffic (postgres <-> backend <-> frontend) and outbound egress.
|
||||
internal:
|
||||
driver: bridge
|
||||
traefik:
|
||||
external: true
|
||||
name: ${TRAEFIK_NETWORK:-traefik}
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: pgvector/pgvector:pg17
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: multica
|
||||
POSTGRES_USER: ${POSTGRES_USER:-multica}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}
|
||||
networks:
|
||||
- internal
|
||||
volumes:
|
||||
- ${POSTGRES_DATA_DIR:-./data/postgres}:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-multica} -d multica"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# Official image. Its entrypoint runs `migrate up` before starting the server.
|
||||
# Version is pinned to match the multica CLI on the host; see README "Versioning".
|
||||
backend:
|
||||
image: ghcr.io/multica-ai/multica-backend:v0.6.5
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
APP_ENV: production
|
||||
PORT: "8080"
|
||||
DATABASE_URL: postgres://${POSTGRES_USER:-multica}:${POSTGRES_PASSWORD}@postgres:5432/multica?sslmode=disable
|
||||
JWT_SECRET: ${JWT_SECRET:?JWT_SECRET must be set - openssl rand -hex 32}
|
||||
FRONTEND_ORIGIN: ${FRONTEND_ORIGIN:?FRONTEND_ORIGIN must be set}
|
||||
CORS_ALLOWED_ORIGINS: ${FRONTEND_ORIGIN}
|
||||
MULTICA_APP_URL: ${FRONTEND_ORIGIN}
|
||||
MULTICA_PUBLIC_URL: ${MULTICA_PUBLIC_URL:-}
|
||||
GOOGLE_REDIRECT_URI: ${FRONTEND_ORIGIN}/auth/callback
|
||||
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
|
||||
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}
|
||||
RESEND_API_KEY: ${RESEND_API_KEY:-}
|
||||
RESEND_FROM_EMAIL: ${RESEND_FROM_EMAIL:-noreply@multica.ai}
|
||||
SMTP_HOST: ${SMTP_HOST:-}
|
||||
SMTP_PORT: ${SMTP_PORT:-25}
|
||||
SMTP_USERNAME: ${SMTP_USERNAME:-}
|
||||
SMTP_PASSWORD: ${SMTP_PASSWORD:-}
|
||||
SMTP_FROM_EMAIL: ${SMTP_FROM_EMAIL:-}
|
||||
SMTP_TLS: ${SMTP_TLS:-}
|
||||
ALLOW_SIGNUP: ${ALLOW_SIGNUP:-true}
|
||||
ALLOWED_EMAILS: ${ALLOWED_EMAILS:-}
|
||||
ALLOWED_EMAIL_DOMAINS: ${ALLOWED_EMAIL_DOMAINS:-}
|
||||
DISABLE_WORKSPACE_CREATION: ${DISABLE_WORKSPACE_CREATION:-false}
|
||||
MULTICA_VCS_INTEGRATION_ENABLED: "true"
|
||||
MULTICA_VCS_SECRET_KEY: ${MULTICA_VCS_SECRET_KEY:-}
|
||||
DO_NOT_TRACK: ${DO_NOT_TRACK:-}
|
||||
networks:
|
||||
- internal
|
||||
- traefik
|
||||
volumes:
|
||||
- ${UPLOADS_DATA_DIR:-./data/uploads}:/app/data/uploads
|
||||
# Loopback only, for the multica agent daemon on this host.
|
||||
ports:
|
||||
- "127.0.0.1:${BACKEND_HOST_PORT:-8080}:8080"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK:-traefik}"
|
||||
- "traefik.http.services.multica-backend.loadbalancer.server.port=8080"
|
||||
# On the traefik network only so traefik can reach /ws; everything else
|
||||
# goes through the frontend.
|
||||
# Next.js rewrites proxy /api, /auth, /uploads to the backend, but not
|
||||
# websockets, so /ws on the main host must go straight to the backend.
|
||||
- "traefik.http.routers.multica-ws.rule=Host(`${FRONTEND_HOST}`) && (Path(`/ws`) || PathPrefix(`/ws/`))"
|
||||
- "traefik.http.routers.multica-ws.entrypoints=websecure"
|
||||
- "traefik.http.routers.multica-ws.tls.certresolver=let-sencrypt"
|
||||
- "traefik.http.routers.multica-ws.service=multica-backend"
|
||||
|
||||
# Official image. Proxies API calls to REMOTE_API_URL at runtime.
|
||||
frontend:
|
||||
image: ghcr.io/multica-ai/multica-web:v0.6.5
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
HOSTNAME: "0.0.0.0"
|
||||
REMOTE_API_URL: http://backend:8080
|
||||
networks:
|
||||
- internal
|
||||
- traefik
|
||||
depends_on:
|
||||
- backend
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=${TRAEFIK_NETWORK:-traefik}"
|
||||
- "traefik.http.routers.multica-web.rule=Host(`${FRONTEND_HOST}`)"
|
||||
- "traefik.http.routers.multica-web.entrypoints=websecure"
|
||||
- "traefik.http.routers.multica-web.tls.certresolver=lets-encrypt"
|
||||
- "traefik.http.services.multica-web.loadbalancer.server.port=3000"
|
||||
Loading…
x
Reference in New Issue
Block a user