Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
directory: "/noc-dashboard/backend"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: ['python', 'javascript', 'typescript']
language: ['python', 'javascript']

steps:
- name: Checkout repository
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ build/
*.so
# Logs
*.log
# Pipeline reports
reports/
profiles/local/.env
213 changes: 213 additions & 0 deletions INTENT.md

Large diffs are not rendered by default.

47 changes: 22 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# StackDeploy
# AutoStack

**Version:** v2.0
**Status:** Production Ready
**Repository:** https://github.com/OneByJorah/StackDeploy
**Repository:** https://github.com/OneByJorah/AutoStack

---

Expand All @@ -29,7 +29,7 @@

## Overview

StackDeploy is a **unified, production-ready Docker Compose deployment** that consolidates self-hosted web search, long-term memory, browser automation, vector storage, and Obsidian note-taking under a single IP with centralized management. Designed to run on consumer hardware with Tailscale networking, exposing everything through direct ports.
AutoStack is a **unified, production-ready Docker Compose deployment** that consolidates self-hosted web search, long-term memory, browser automation, vector storage, and Obsidian note-taking under a single IP with centralized management. Designed to run on consumer hardware with Tailscale networking, exposing everything through direct ports.

**Core philosophy:** One stack, one IP, one admin panel, zero secrets in git.

Expand All @@ -55,7 +55,7 @@ StackDeploy is a **unified, production-ready Docker Compose deployment** that co
┌─────────────────────────────────────────────────────────────────┐
STACKDEPLOY
AUTOSTACK
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ SEARCH & BROWSER MEMORY & KNOWLEDGE │ │
│ │ SearXNG (8080) Honcho API (8081) │ │
Expand Down Expand Up @@ -86,7 +86,7 @@ StackDeploy is a **unified, production-ready Docker Compose deployment** that co
|-------|-------|
| Runtime | Linux (Ubuntu 22.04+), Docker Compose |
| Orchestration | Docker Compose v2, Bash bootstrap scripts |
| VCS | Git + GitHub (`github.com/OneByJorah/StackDeploy`) |
| VCS | Git + GitHub (`github.com/OneByJorah/AutoStack`) |
| Memory/Context | Honcho (pgvector + Redis), Qdrant |
| Search | SearXNG + Camofox (stealth browser) |
| Notes | Obsidian Remote (web UI) |
Expand Down Expand Up @@ -136,8 +136,8 @@ StackDeploy is a **unified, production-ready Docker Compose deployment** that co

```bash
# 1. Clone
git clone https://github.com/OneByJorah/StackDeploy.git
cd StackDeploy
git clone https://github.com/OneByJorah/AutoStack.git
cd AutoStack

# 2. Configure environment
cp .env.example .env
Expand Down Expand Up @@ -179,6 +179,7 @@ All secrets in `.env` (never committed). See `.env.example` for full list.

| Variable | Purpose | Required |
|----------|---------|----------|
| `SEARXNG_SECRET_KEY` | SearXNG secret key for session signing | Optional |
| `HONCHO_DB_PASSWORD` | PostgreSQL password for Honcho | Yes |
| `CAMOFOX_API_KEY` | Camofox auth key | Optional |
| `CAMOFOX_ADMIN_KEY` | Camofox admin key | Optional |
Expand Down Expand Up @@ -291,21 +292,13 @@ docker compose \

## CI/CD & Deployment

**GitHub Actions** (`.github/workflows/ci-cd.yml`):
**GitHub Actions** (`.github/workflows/codeql.yml`):

```yaml
# Triggers: push to main, PR to main
# Jobs:
# 1. lint - hadolint, shellcheck, yamllint
# 2. build - docker compose build (all services)
# 3. test - spin up stack, run healthcheck.sh
# 4. deploy - SSH to server, pull, restart (on main)
```
- Weekly CodeQL security scanning (Python, JavaScript)
- Triggers: push to main/master, PR to main/master

**Branch model:** `main` = stable; feature branches for WIP.

**Deploy:** `git push origin main` → auto-deploys to configured host via SSH.

---

## Security
Expand All @@ -322,7 +315,7 @@ docker compose \
## Project Structure

```
StackDeploy/
AutoStack/
├── docker-compose.yml # 9 services, validated
├── .env.example # Documented placeholders
├── .env # Local secrets (gitignored)
Expand Down Expand Up @@ -356,6 +349,9 @@ StackDeploy/

## Screenshots

Screenshots are planned but not yet captured. See the live deployment for visual reference.

<!--
All screenshots are live captures from the local dev instance (ollama host).

### Portainer Admin Panel (Port 9000)
Expand All @@ -377,24 +373,25 @@ All screenshots are live captures from the local dev instance (ollama host).
### Honcho Memory API (Port 8081)
![Honcho](docs/screenshots/honcho.png)
*Long-term memory for agents*
-->

---

## Hermes Integration

StackDeploy ships first-class Hermes Agent skills.
AutoStack ships first-class Hermes Agent skills.

### Local Install Path

```bash
~/.hermes/skills/devops/stackdeploy/SKILL.md
~/.hermes/skills/devops/autostack/SKILL.md
```

### Inline Commands

```bash
# Health check
cd /home/j1admin/StackDeploy && bash scripts/healthcheck.sh localhost
cd /home/j1admin/AutoStack && bash scripts/healthcheck.sh localhost

# JSON search via SearXNG
curl -s 'http://localhost:8080/search?format=json&q=<query>&language=en'
Expand All @@ -405,11 +402,11 @@ curl -X POST http://localhost:9377/api/v1/browse \
-d '{"url": "https://example.com", "action": "screenshot"}'

# CloakBrowser for protected sites
cd /home/j1admin/StackDeploy/browser-search && node scripts/cloak/cloak-fetch.mjs "https://example.com"
cd /home/j1admin/AutoStack/browser-search && node scripts/cloak/cloak-fetch.mjs "https://example.com"

# Honcho memory operations
curl -X POST http://localhost:8081/api/v1/memory \
-H "Authorization: Bearer $HONCHO_TOKEN" \
-H "Authorization: Bearer ***" \
-d '{"text": "Remember this..."}'
```

Expand All @@ -435,4 +432,4 @@ Built by **Jhonattan L. Jimenez** (J1admin).

- GitHub: [@OneByJorah](https://github.com/OneByJorah)
- Tailscale: `ollama` (ollama host)
- Primary GPU: RTX 3060 12GB
- Primary GPU: RTX 3060 12GB
4 changes: 2 additions & 2 deletions bootstrap.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
# StackDeploy one-shot deploy for Hermes
# AutoStack one-shot deploy for Hermes
# Fixes stale searxng container automatically
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$REPO_DIR"
Expand All @@ -14,4 +14,4 @@ if docker ps -a --format '{{.Names}}' | grep -x searxng >/dev/null 2>&1; then
fi
cd "$REPO_DIR/browser-search" && [ -d node_modules ] || npm install
bash "$REPO_DIR/tests/smoke.sh"
echo "StackDeploy ready at $REPO_DIR"
echo "AutoStack ready at $REPO_DIR"
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ services:
restart: unless-stopped
ports:
- "8080:8080"
environment:
- SEARXNG_SECRET_KEY=${SEARXNG_SECRET_KEY:-changeme}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/"]
interval: 30s
Expand Down
2 changes: 1 addition & 1 deletion docs/HEADROOM_SETUP.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Headroom / Aphrodite Setup

Headroom is integrated into StackDeploy as an optional service under `vendor/headroom`, using the upstream `headroomlabs-ai/headroom` codebase. It exposes a local proxy on port `8787` plus Qdrant/Neo4j backends for vector + graph memory. Aphrodite-specific config is handled through Headroom’s proxy and `headroom.toml` conventions.
Headroom is integrated into AutoStack as an optional service under `vendor/headroom`, using the upstream `headroomlabs-ai/headroom` codebase. It exposes a local proxy on port `8787` plus Qdrant/Neo4j backends for vector + graph memory. Aphrodite-specific config is handled through Headroom’s proxy and `headroom.toml` conventions.

## Prerequisites

Expand Down
4 changes: 2 additions & 2 deletions docs/HERMES_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

```bash
# 1. Clone the repository
git clone https://github.com/OneByJorah/StackDeploy.git
cd StackDeploy
git clone https://github.com/OneByJorah/AutoStack.git
cd AutoStack

# 2. Environment
cp .env.example .env
Expand Down
2 changes: 1 addition & 1 deletion docs/HONCHO_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Honcho provides long-term memory/workspace context for Hermes Agent.
git submodule update --init vendor/honcho
```

4. Start Honcho alongside StackDeploy:
4. Start Honcho alongside AutoStack:
```bash
docker compose -f docker-compose.yml -f docker-compose.honcho.yml up -d
```
Expand Down
5 changes: 3 additions & 2 deletions docs/MAINTENANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
docker compose restart
```

## Update model
## Update images

```bash
docker compose up -d llama-server
docker compose pull
docker compose up -d
```

## Backup Honcho memory
Expand Down
4 changes: 2 additions & 2 deletions docs/SERVER_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

```bash
# 1. Clone the repository
git clone https://github.com/OneByJorah/StackDeploy.git
cd StackDeploy
git clone https://github.com/OneByJorah/AutoStack.git
cd AutoStack

# 2. Environment
cp .env.example .env
Expand Down
4 changes: 2 additions & 2 deletions docs/SETUP_WIZARD.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Setup Wizard

arah supports four access modes. Choose one at install time, or switch later by updating `.env`.
AutoStack supports four access modes. Choose one at install time, or switch later by updating `.env`.

- `local` — no tunnels, no tailscale, no cloudflare; services reachable on localhost ports only.
- `tailscale` — services exposed over Tailscale only.
Expand All @@ -25,7 +25,7 @@ ENABLE_SETUP_API=1 docker compose -f docker-compose.yml -f noc-dashboard/docker-

Then open:
- `http://localhost:9500/setup`
- Or, if the Cloudflare tunnel is active: `https://arah.<your-domain>.com/setup`
- Or, if the Cloudflare tunnel is active: `https://autostack.<your-domain>.com/setup`

Select mode, enter tokens/tunnel info, and submit.

Expand Down
8 changes: 4 additions & 4 deletions docs/hermes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# StackDeploy + Hermes Agent
# AutoStack + Hermes Agent

This doc describes how the Hermes Agent uses the local StackDeploy services.
This doc describes how the Hermes Agent uses the local AutoStack services.

## Cluster Health
```bash
Expand All @@ -26,12 +26,12 @@ curl -s -o /dev/null -w 'qdrant=%{http_code}\n' http://localhost:6333/

## BrowserSearch CLI
```bash
cd /home/j1admin/StackDeploy/browser-search
cd /home/j1admin/AutoStack/browser-search
node scripts/cloak/cloak-fetch.mjs "https://example.com" --format markdown
```

## Smoke test
```bash
cd /home/j1admin/StackDeploy
cd /home/j1admin/AutoStack
bash tests/smoke.sh
```
6 changes: 3 additions & 3 deletions live-manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"updated_at": "2026-07-03T03:45:00Z",
"tailscale_ip": "[REDACTED]",
"github_repo": "OneByJorah/arah",
"repo_url": "https://github.com/OneByJorah/arah",
"tunnel_hostname": "arah.<your-domain>.com",
"github_repo": "OneByJorah/AutoStack",
"repo_url": "https://github.com/OneByJorah/AutoStack",
"tunnel_hostname": "autostack.<your-domain>.com",
"services": {
"honcho": {
"container": "honcho-self-hosted_redis_1",
Expand Down
6 changes: 3 additions & 3 deletions noc-dashboard/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# J1-NOC Dashboard

Read-only monitoring dashboard for StackDeploy. Polls every service's real health
Read-only monitoring dashboard for AutoStack. Polls every service's real health
endpoint (the same ones in `docker-compose.yml` / `scripts/healthcheck.sh`) over the
internal Docker network, plus optional Portainer container stats.

**This does not replace or proxy anything.** Every service still exposes its own
port/API exactly as before — this just gives you one screen to see all of them at once.

## Install into StackDeploy
## Install into AutoStack

1. Drop this whole `noc-dashboard/` folder into the root of your `StackDeploy` repo,
1. Drop this whole `noc-dashboard/` folder into the root of your `AutoStack` repo,
alongside `docker-compose.yml`.
2. Copy `docker-compose.dashboard.yml` to the repo root too (next to
`docker-compose.honcho.yml` / `docker-compose.headroom.yml`).
Expand Down
12 changes: 6 additions & 6 deletions noc-dashboard/backend/app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
J1-NOC Dashboard — StackDeploy monitoring backend.
J1-NOC Dashboard — AutoStack monitoring backend.

Polls every service in StackDeploy over the internal Docker network using
Polls every service in AutoStack over the internal Docker network using
the SAME health endpoints defined in docker-compose.yml / scripts/healthcheck.sh,
plus optional Portainer container stats if PORTAINER_URL is set.

Expand Down Expand Up @@ -190,7 +190,7 @@ async def lifespan(app: FastAPI):
task.cancel()


app = FastAPI(title="J1-NOC StackDeploy Dashboard", lifespan=lifespan)
app = FastAPI(title="J1-NOC AutoStack Dashboard", lifespan=lifespan)


@app.get("/api/status")
Expand Down Expand Up @@ -235,8 +235,8 @@ async def healthz():

templates = Jinja2Templates(directory="/app/templates")

REPO_ROOT = Path("/workspace")
CF_DIR = Path("/cloudflared")
REPO_ROOT = Path(os.getenv("REPO_ROOT", "/workspace"))
CF_DIR = Path(os.getenv("CF_DIR", "/cloudflared"))
COMPOSE_FILE = REPO_ROOT / "docker-compose.yml"

@app.get("/setup")
Expand Down Expand Up @@ -281,7 +281,7 @@ async def apply_setup(request: Request):
(REPO_ROOT / "setup-complete.json").write_text(json.dumps(payload, indent=2))

if mode in ("cloudflare", "all") and cf_host and cf_tunnel:
cf_content = f"""tunnel: {cf_tunnel}\ncredentials-file: /home/j1admin/.cloudflared/{cf_tunnel}.json\ningress:\n - hostname: {cf_host}\n path: /honcho/*\n service: http://100.66.142.21:8000\n - hostname: {cf_host}\n path: /qdrant/*\n service: http://100.66.142.21:6333\n - hostname: {cf_host}\n path: /search/*\n service: http://100.66.142.21:8080\n - hostname: {cf_host}\n path: /obsidian/*\n service: http://100.66.142.21:8083\n - hostname: {cf_host}\n path: /costforge/*\n service: http://100.66.142.21:8090\n - hostname: {cf_host}\n path: /noc/*\n service: http://100.66.142.21:9500\n - service: http_status:404\n"""
cf_content = f"""tunnel: {cf_tunnel}\ncredentials-file: {os.getenv("CLOUDFLARED_HOME", "/home/j1admin/.cloudflared")}/{cf_tunnel}.json\ningress:\n - hostname: {cf_host}\n path: /honcho/*\n service: http://{os.getenv("SERVER_IP", "100.66.142.21")}:8000\n - hostname: {cf_host}\n path: /qdrant/*\n service: http://{os.getenv("SERVER_IP", "100.66.142.21")}:6333\n - hostname: {cf_host}\n path: /search/*\n service: http://{os.getenv("SERVER_IP", "100.66.142.21")}:8080\n - hostname: {cf_host}\n path: /obsidian/*\n service: http://{os.getenv("SERVER_IP", "100.66.142.21")}:8083\n - hostname: {cf_host}\n path: /costforge/*\n service: http://{os.getenv("SERVER_IP", "100.66.142.21")}:8090\n - hostname: {cf_host}\n path: /noc/*\n service: http://{os.getenv("SERVER_IP", "100.66.142.21")}:9500\n - service: http_status:404\n"""
CF_DIR.mkdir(parents=True, exist_ok=True)
(CF_DIR / "config.yml").write_text(cf_content)

Expand Down
2 changes: 1 addition & 1 deletion noc-dashboard/backend/standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ async def lifespan(app: FastAPI):
task.cancel()


app = FastAPI(title="J1-NOC StackDeploy Dashboard", lifespan=lifespan)
app = FastAPI(title="J1-NOC AutoStack Dashboard", lifespan=lifespan)


@app.get("/api/status")
Expand Down
Loading
Loading