chore: rebrand farhoodliquor → farhoodlabs, API-only mode, split infra

- Rename org references from farhoodliquor to farhoodlabs in CI workflows
  and GHCR image tags
- Rewrite README for Hightower as API-driven K8s fork of Shannon
- Update CLAUDE.md to reflect API-only deployment model
- Delete docker-compose files (K8s only, no Docker Compose support)
- Delete shannon CLI entry point (API-only going forward)
- Move K8s manifests to farhoodlabs/hightower-infra

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-22 07:19:56 -04:00
parent 0013776646
commit 325eac98ea
19 changed files with 110 additions and 1453 deletions
+7 -7
View File
@@ -16,7 +16,7 @@ concurrency:
jobs:
check:
name: Type-check & lint
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -43,7 +43,7 @@ jobs:
name: Build & push worker image
needs: check
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: read
packages: write
@@ -68,14 +68,14 @@ jobs:
context: .
push: true
tags: |
ghcr.io/farhoodliquor/shannon:latest
ghcr.io/farhoodliquor/shannon:sha-${{ github.sha }}
ghcr.io/farhoodlabs/shannon:latest
ghcr.io/farhoodlabs/shannon:sha-${{ github.sha }}
build-api:
name: Build & push API image
needs: check
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: read
packages: write
@@ -102,5 +102,5 @@ jobs:
push: true
no-cache: true
tags: |
ghcr.io/farhoodliquor/hightower-api:latest
ghcr.io/farhoodliquor/hightower-api:sha-${{ github.sha }}
ghcr.io/farhoodlabs/hightower-api:latest
ghcr.io/farhoodlabs/hightower-api:sha-${{ github.sha }}
+5 -5
View File
@@ -13,7 +13,7 @@ concurrency:
jobs:
preflight:
name: Preflight
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
outputs:
version: ${{ steps.version.outputs.version }}
@@ -47,7 +47,7 @@ jobs:
build-docker:
name: Build Docker (worker)
needs: preflight
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: read
@@ -76,7 +76,7 @@ jobs:
build-docker-api:
name: Build Docker (API)
needs: preflight
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: read
@@ -106,7 +106,7 @@ jobs:
sign-docker:
name: Sign Docker images
needs: [preflight, build-docker, build-docker-api]
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: read
id-token: write
@@ -165,7 +165,7 @@ jobs:
publish-npm:
name: Publish npm (beta)
needs: [preflight, sign-docker]
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: read
id-token: write
+6 -6
View File
@@ -13,7 +13,7 @@ concurrency:
jobs:
preflight:
name: Preflight
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: write
outputs:
@@ -60,7 +60,7 @@ jobs:
name: Build Docker (worker)
needs: preflight
if: needs.preflight.outputs.should_release == 'true'
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: read
@@ -92,7 +92,7 @@ jobs:
name: Build Docker (API)
needs: preflight
if: needs.preflight.outputs.should_release == 'true'
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: read
@@ -124,7 +124,7 @@ jobs:
sign-docker:
name: Sign Docker images
needs: [preflight, build-docker, build-docker-api]
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: read
id-token: write
@@ -183,7 +183,7 @@ jobs:
publish-npm:
name: Publish npm
needs: [preflight, sign-docker]
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: read
id-token: write
@@ -228,7 +228,7 @@ jobs:
release:
name: Create GitHub release
needs: [preflight, publish-npm]
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
permissions:
contents: write
+1 -1
View File
@@ -18,7 +18,7 @@ concurrency:
jobs:
rollback:
name: Roll back npm beta dist-tag
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
steps:
- name: Validate target version
id: target
+1 -1
View File
@@ -18,7 +18,7 @@ concurrency:
jobs:
rollback:
name: Roll back npm, Docker, and GitHub release latest
runs-on: runners-farhoodliquor
runs-on: runners-farhoodlabs
steps:
- name: Checkout tags
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+25 -110
View File
@@ -1,78 +1,12 @@
# CLAUDE.md
AI-powered penetration testing agent for defensive security analysis. Automates vulnerability assessment by combining reconnaissance tools with AI-powered code analysis.
Hightower is a fork of [Shannon](https://github.com/KeygraphHQ/shannon) by Keygraph — an AI-powered penetration testing agent for defensive security analysis. It wraps Shannon's autonomous pentesting engine with a REST API and Kubernetes deployment tooling.
**Upstream policy:** `apps/cli/` and `apps/worker/` are kept as close to upstream Shannon as possible for backporting. Only `apps/api/`, CI/CD workflows, and infra are Hightower-specific.
## Commands
**Prerequisites:** Docker, AI provider credentials (`.env` for local, `shn setup` or env vars for npx)
### Dual CLI
Shannon supports two CLI modes, auto-detected based on the current working directory:
| | **npx** (`npx @keygraph/shannon`) | **Local** (`./shannon`) |
|---|---|---|
| **Install** | Zero-install via npm | Clone the repo |
| **Image** | Pulled from Docker Hub (`keygraph/shannon:latest`) | Built locally (`shannon-worker`) |
| **State** | `~/.shannon/` | Project directory |
| **Credentials** | `~/.shannon/config.toml` (via `shn setup`) or env vars | `./.env` |
| **Config** | `~/.shannon/config.toml` (via `shn setup`) | N/A |
| **Prompts** | Bundled in Docker image | Mounted from `./apps/worker/prompts/` (live-editable) |
Mode auto-detection: local mode activates when env var `SHANNON_LOCAL=1` is set by the `./shannon` entry point (`apps/cli/src/mode.ts`). Otherwise npx mode.
### npx Quick Start
```bash
# Configure credentials (interactive wizard)
npx @keygraph/shannon setup
# Or export env vars directly (non-interactive / CI)
export ANTHROPIC_API_KEY=your-key
# Run
npx @keygraph/shannon start -u <url> -r /path/to/repo
```
### Local (Development) Quick Start
```bash
# Setup
echo "ANTHROPIC_API_KEY=your-key" > .env
# Build (auto-runs if image missing)
./shannon build
# Run
./shannon start -u <url> -r my-repo
./shannon start -u <url> -r my-repo -c ./apps/worker/configs/my-config.yaml
./shannon start -u <url> -r /any/path/to/repo
```
### Common Commands
```bash
# Setup (npx mode only — one-time credential configuration)
npx @keygraph/shannon setup
# Workspaces & Resume
./shannon start -u <url> -r my-repo -w my-audit # New named workspace
./shannon start -u <url> -r my-repo -w my-audit # Resume (same command)
./shannon workspaces # List all workspaces
# Monitor
./shannon logs <workspace> # Tail workflow log
./shannon status # Show running workers
# Temporal Web UI: http://localhost:8233
# Stop
./shannon stop # Preserves workflow data
./shannon stop --clean # Full cleanup including volumes (confirms first)
# Image management
./shannon build [--no-cache] # Local mode: build worker image
npx @keygraph/shannon uninstall # npx mode: remove ~/.shannon/ (confirms first)
# Build TypeScript (development)
pnpm run build # Build all packages via Turborepo
pnpm run check # Type-check all packages
@@ -82,42 +16,25 @@ pnpm biome:fix # Auto-fix lint, format, and import sorting
**Monorepo tooling:** pnpm workspaces, Turborepo for task orchestration, Biome for linting/formatting. TypeScript compiler options shared via `tsconfig.base.json` at the root. All packages extend it, overriding only `rootDir` and `outDir`. Shared devDependencies (`typescript`, `@types/node`, `turbo`, `@biomejs/biome`) are hoisted to the root workspace.
**Options:** `-c <file>` (YAML config), `-o <path>` (output directory), `-w <name>` (named workspace; auto-resumes if exists), `--pipeline-testing` (minimal prompts, 10s retries), `--router` (multi-model routing via [claude-code-router](https://github.com/musistudio/claude-code-router))
## Architecture
### Monorepo Layout
```
apps/cli/ — @keygraph/shannon (published to npm, bundled with tsdown)
apps/worker/ — @shannon/worker (private, Temporal worker + pipeline logic)
apps/api/ — @shannon/api (Hightower REST API, K8s-native)
apps/cli/ — @keygraph/shannon (upstream CLI, not used in production)
apps/worker/ — @shannon/worker (upstream Temporal worker + pipeline logic)
```
### API Package (`apps/api/`)
Hightower-specific REST API for triggering and managing pentests. Deployed on Kubernetes.
### CLI Package (`apps/cli/`)
Published as `@keygraph/shannon` on npm. Contains only Docker orchestration logic — no Temporal SDK, business logic, or prompts. Bundled with tsdown for single-file ESM output.
- `apps/cli/src/index.ts` — CLI dispatcher (`setup`, `start`, `stop`, `logs`, `workspaces`, `status`, `build`, `uninstall`, `info`)
- `apps/cli/src/mode.ts` — Auto-detection: local mode if `SHANNON_LOCAL=1` env var is set
- `apps/cli/src/docker.ts` — Compose lifecycle, image pull/build, ephemeral `docker run` worker spawning
- `apps/cli/src/home.ts` — State directory management (`~/.shannon/` for npx, `./` for local)
- `apps/cli/src/env.ts``.env` loading, TOML fallback (npx only) via `apps/cli/src/config/resolver.ts`, credential validation, env flag building
- `apps/cli/src/config/resolver.ts` — Cascading config (npx only): env vars → `~/.shannon/config.toml` (parsed with `smol-toml`)
- `apps/cli/src/config/writer.ts` — TOML serialization and secure file persistence (0o600)
- `apps/cli/src/commands/setup.ts` — Interactive TUI wizard (`@clack/prompts`) for provider credential setup (npx only)
- `apps/cli/src/paths.ts` — Repo/config path resolution (bare name → `./repos/<name>`, or any absolute/relative path)
- `apps/cli/src/commands/` — Command handlers
- `apps/cli/infra/compose.yml` — Bundled Temporal + router compose file for npx mode
- `apps/cli/tsdown.config.ts` — tsdown bundler config
- `shannon` — Node.js entry point (`#!/usr/bin/env node`) that delegates to `apps/cli/dist/index.mjs`
### Docker Architecture
Infra (Temporal + router) runs via `docker-compose.yml`. Workers are ephemeral `docker run --rm` containers, one per scan, each with a unique task queue and isolated volume mounts.
- `docker-compose.yml` — Infra only: `shannon-temporal` (port 7233/8233) and `shannon-router` (port 3456, optional via profile). Network: `shannon-net`
- `Dockerfile` — 2-stage build (builder + Chainguard Wolfi runtime). Uses pnpm. Entrypoint: `CMD ["node", "apps/worker/dist/temporal/worker.js"]`
- No `docker-compose.docker.yml` — host gateway handled via `--add-host` flag in CLI
Upstream Shannon CLI — kept for backporting compatibility. Not used in Hightower's K8s deployment.
### Worker Package (`apps/worker/`)
Upstream Shannon worker — Temporal worker + pipeline logic. Runs as ephemeral K8s Jobs.
- `apps/worker/src/paths.ts` — Centralized path constants (`PROMPTS_DIR`, `CONFIGS_DIR`, `WORKSPACES_DIR`)
- `apps/worker/src/session-manager.ts` — Agent definitions (`AGENTS` record). Agent types in `apps/worker/src/types/agents.ts`
- `apps/worker/src/config-parser.ts` — YAML config parsing with JSON Schema validation
@@ -135,6 +52,7 @@ Durable workflow orchestration with crash recovery, queryable progress, intellig
- `apps/worker/src/temporal/summary-mapper.ts` — Maps `PipelineSummary` to `WorkflowSummary`
- `apps/worker/src/temporal/worker.ts` — Combined worker + client entry point (per-invocation task queue, submits workflow, waits for result)
- `apps/worker/src/temporal/shared.ts` — Types, interfaces, query definitions
### Five-Phase Pipeline
1. **Pre-Recon** (`pre-recon`) — External scans (nmap, subfinder, whatweb) + source code analysis
@@ -143,8 +61,15 @@ Durable workflow orchestration with crash recovery, queryable progress, intellig
4. **Exploitation** (5 parallel agents, conditional) — Exploits confirmed vulnerabilities
5. **Reporting** (`report`) — Executive-level security report
### Docker Images
- `Dockerfile` — Worker image: 2-stage build (builder + Chainguard Wolfi runtime). Uses pnpm. Entrypoint: `CMD ["node", "apps/worker/dist/temporal/worker.js"]`
- `apps/api/Dockerfile` — API image: minimal Alpine build
### Kubernetes Infrastructure
K8s manifests live in a separate repository: [farhoodlabs/hightower-infra](https://github.com/farhoodlabs/hightower-infra).
### Supporting Systems
- **Configuration** — YAML configs in `apps/worker/configs/` with JSON Schema validation (`config-schema.json`). Supports auth settings, MFA/TOTP, and per-app testing parameters. Credential resolution — local mode: env vars → `./.env`; npx mode: env vars → `~/.shannon/config.toml` (via `shn setup`)
- **Configuration** — YAML configs in `apps/worker/configs/` with JSON Schema validation (`config-schema.json`). Supports auth settings, MFA/TOTP, and per-app testing parameters
- **Prompts** — Per-phase templates in `apps/worker/prompts/` with variable substitution (`{{TARGET_URL}}`, `{{CONFIG_CONTEXT}}`). Shared partials in `apps/worker/prompts/shared/` via `apps/worker/src/services/prompt-manager.ts`
- **SDK Integration** — Uses `@anthropic-ai/claude-agent-sdk` with `maxTurns: 10_000` and `bypassPermissions` mode. Browser automation via `playwright-cli` with session isolation (`-s=<session>`). TOTP generation via `generate-totp` CLI tool. Login flow template at `apps/worker/prompts/shared/login-instructions.txt` supports form, SSO, API, and basic auth
- **Audit System** — Crash-safe append-only logging in `workspaces/{hostname}_{sessionId}/`. Tracks session metrics, per-agent logs, prompts, and deliverables. WorkflowLogger (`apps/worker/src/audit/workflow-logger.ts`) provides unified human-readable per-workflow logs, backed by LogStream (`apps/worker/src/audit/log-stream.ts`) shared stream primitive
@@ -171,7 +96,7 @@ Durable workflow orchestration with crash recovery, queryable progress, intellig
- **Modular Error Handling** — `ErrorCode` enum, `Result<T,E>` for explicit error propagation, automatic retry (3 attempts per agent)
- **Services Boundary** — Activities are thin Temporal wrappers; `apps/worker/src/services/` owns business logic, accepts `ActivityLogger`, returns `Result<T,E>`. No Temporal imports in services
- **DI Container** — Per-workflow in `apps/worker/src/services/container.ts`. `AuditSession` excluded (parallel safety)
- **Ephemeral Workers** — Each scan runs in its own `docker run --rm` container with a per-invocation task queue. Temporal routes activities by queue name, so per-scan queues ensure activities never land on a worker with the wrong repo mounted
- **Ephemeral Workers** — Each scan runs in its own container with a per-invocation task queue. Temporal routes activities by queue name, so per-scan queues ensure activities never land on a worker with the wrong repo mounted
### Security
Defensive security tool only. Use only on systems you own or have explicit permission to test.
@@ -223,26 +148,16 @@ Comments must be **timeless** — no references to this conversation, refactorin
## Key Files
**CLI:** `shannon` (entry point), `apps/cli/src/index.ts` (dispatcher), `apps/cli/src/docker.ts` (orchestration), `apps/cli/src/mode.ts` (auto-detection)
**API:** `apps/api/src/` (Hightower REST API), `apps/api/Dockerfile`
**Entry Points:** `apps/worker/src/temporal/workflows.ts`, `apps/worker/src/temporal/activities.ts`, `apps/worker/src/temporal/worker.ts`
**Core Logic:** `apps/worker/src/session-manager.ts`, `apps/worker/src/ai/claude-executor.ts`, `apps/worker/src/config-parser.ts`, `apps/worker/src/services/`, `apps/worker/src/audit/`
**Config:** `docker-compose.yml`, `apps/cli/infra/compose.yml`, `apps/worker/configs/`, `apps/worker/prompts/`, `tsconfig.base.json` (shared compiler options), `turbo.json`, `biome.json`
**Config:** `Dockerfile`, `apps/worker/configs/`, `apps/worker/prompts/`, `tsconfig.base.json` (shared compiler options), `turbo.json`, `biome.json`
**CI/CD:** `.github/workflows/release.yml` (Docker Hub push + npm publish + GitHub release, manual dispatch)
**CI/CD:** `.github/workflows/ci.yml` (type-check, lint, build & push images to GHCR), `.github/workflows/release.yml` (Docker Hub push + GitHub release, manual dispatch)
## Package Installation
Package managers are configured with a minimum release age (7 days). Requires pnpm >= 10.16.0. If `pnpm install` fails due to a package being too new, **do not attempt to bypass it** — report the blocked package to the user and stop.
## Troubleshooting
- **"Repository not found"** — Pass a bare name (`-r my-repo`) for `./repos/my-repo`, or a path (`-r /path/to/repo`) for any directory
- **"Temporal not ready"** — Wait for health check or `docker compose logs temporal`
- **Worker not processing** — Check `docker ps --filter "name=shannon-worker-"`
- **Reset state** — `./shannon stop --clean`
- **Local apps unreachable** — Use `host.docker.internal` instead of `localhost`
- **Missing tools** — Use `--pipeline-testing` to skip nmap/subfinder/whatweb (graceful degradation)
- **Container permissions** — On Linux, may need `sudo` for docker commands
+65 -884
View File
File diff suppressed because it is too large Load Diff
-62
View File
@@ -1,62 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: hightower-api
namespace: hightower
labels:
app: hightower-api
spec:
replicas: 1
selector:
matchLabels:
app: hightower-api
template:
metadata:
labels:
app: hightower-api
annotations:
kubectl.kubernetes.io/restartedAt: "2026-04-21T22:21:00Z"
spec:
serviceAccountName: hightower-api
containers:
- name: api
image: ghcr.io/farhoodliquor/hightower-api:sha-a0efe7604ebc2f27cc37ee88f117ae619e57003f
imagePullPolicy: Always
ports:
- containerPort: 3000
name: http
env:
- name: TEMPORAL_ADDRESS
value: hightower-temporal:7233
- name: WORKER_IMAGE
value: ghcr.io/farhoodliquor/shannon:latest
- name: K8S_NAMESPACE
value: hightower
envFrom:
- secretRef:
name: hightower-credentials
volumeMounts:
- name: workspaces
mountPath: /app/workspaces
livenessProbe:
httpGet:
path: /healthz
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /readyz
port: 3000
initialDelaySeconds: 10
periodSeconds: 10
resources:
requests:
memory: 128Mi
cpu: 100m
limits:
memory: 256Mi
volumes:
- name: workspaces
persistentVolumeClaim:
claimName: hightower-workspaces
-7
View File
@@ -1,7 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- serviceaccount.yaml
- rbac.yaml
-53
View File
@@ -1,53 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: hightower-api
namespace: hightower
rules:
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["create", "get", "list", "delete", "watch"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: hightower-api
namespace: hightower
subjects:
- kind: ServiceAccount
name: hightower-api
namespace: hightower
roleRef:
kind: Role
name: hightower-api
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: hightower-deploy-manager
namespace: hightower
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: farh-net-deploy-manager
namespace: hightower
subjects:
- kind: ServiceAccount
name: farh-net-paperclip
namespace: farh-net
roleRef:
kind: Role
name: hightower-deploy-manager
apiGroup: rbac.authorization.k8s.io
-12
View File
@@ -1,12 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: hightower-api
namespace: hightower
spec:
selector:
app: hightower-api
ports:
- name: http
port: 3000
targetPort: 3000
-5
View File
@@ -1,5 +0,0 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: hightower-api
namespace: hightower
@@ -1,16 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: hightower-api
spec:
template:
spec:
containers:
- name: api
imagePullPolicy: Never
-50
View File
@@ -1,50 +0,0 @@
networks:
default:
name: shannon-net
services:
temporal:
image: temporalio/temporal:latest
container_name: shannon-temporal
command: ["server", "start-dev", "--db-filename", "/home/temporal/temporal.db", "--ip", "0.0.0.0"]
ports:
- "127.0.0.1:7233:7233"
- "127.0.0.1:8233:8233"
volumes:
- temporal-data:/home/temporal
healthcheck:
test: ["CMD", "temporal", "operator", "cluster", "health", "--address", "localhost:7233"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
router:
image: node:20-slim
container_name: shannon-router
profiles: ["router"]
command: >
sh -c "apt-get update && apt-get install -y gettext-base &&
npm install -g @musistudio/claude-code-router &&
mkdir -p /root/.claude-code-router &&
envsubst < /config/router-config.json > /root/.claude-code-router/config.json &&
ccr start"
ports:
- "127.0.0.1:3456:3456"
volumes:
- ./router-config.json:/config/router-config.json:ro
environment:
- HOST=0.0.0.0
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-}
- ROUTER_DEFAULT=${ROUTER_DEFAULT:-openai,gpt-4o}
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3456/health', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
volumes:
temporal-data:
-69
View File
@@ -1,69 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: hightower-router
namespace: hightower
labels:
app: hightower-router
spec:
replicas: 1
selector:
matchLabels:
app: hightower-router
template:
metadata:
labels:
app: hightower-router
spec:
containers:
- name: router
image: node:20-slim
command:
- sh
- -c
- |
apt-get update && apt-get install -y gettext-base &&
npm install -g @musistudio/claude-code-router &&
mkdir -p /root/.claude-code-router &&
envsubst < /config/router-config.json > /root/.claude-code-router/config.json &&
ccr start
ports:
- containerPort: 3456
envFrom:
- secretRef:
name: hightower-credentials
env:
- name: HOST
value: "0.0.0.0"
volumeMounts:
- name: config
mountPath: /config
readOnly: true
readinessProbe:
httpGet:
path: /health
port: 3456
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 5
resources:
requests:
memory: 128Mi
cpu: 100m
volumes:
- name: config
configMap:
name: hightower-router-config
---
apiVersion: v1
kind: Service
metadata:
name: hightower-router
namespace: hightower
spec:
selector:
app: hightower-router
ports:
- port: 3456
targetPort: 3456
-98
View File
@@ -1,98 +0,0 @@
# CNPG PostgreSQL cluster for Temporal persistence
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: hightower-temporal-db
namespace: hightower
spec:
instances: 1
storage:
size: 5Gi
storageClass: ceph-block
bootstrap:
initdb:
database: temporal
owner: temporal
postInitSQL:
- CREATE DATABASE temporal_visibility OWNER temporal;
---
# Temporal auto-setup — handles schema creation/migration automatically
apiVersion: apps/v1
kind: Deployment
metadata:
name: hightower-temporal
namespace: hightower
labels:
app: hightower-temporal
spec:
replicas: 1
selector:
matchLabels:
app: hightower-temporal
template:
metadata:
labels:
app: hightower-temporal
spec:
containers:
- name: temporal
image: temporalio/auto-setup:latest
ports:
- containerPort: 7233
name: grpc
- containerPort: 8233
name: web-ui
env:
- name: DB
value: postgres12
- name: DB_PORT
value: "5432"
- name: POSTGRES_SEEDS
value: hightower-temporal-db-rw
- name: DBNAME
value: temporal
- name: VISIBILITY_DBNAME
value: temporal_visibility
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: hightower-temporal-db-app
key: username
- name: POSTGRES_PWD
valueFrom:
secretKeyRef:
name: hightower-temporal-db-app
key: password
- name: NUM_HISTORY_SHARDS
value: "4"
- name: SKIP_DB_CREATE
value: "true"
readinessProbe:
tcpSocket:
port: 7233
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 15
resources:
requests:
memory: 512Mi
cpu: 250m
limits:
memory: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: hightower-temporal
namespace: hightower
spec:
selector:
app: hightower-temporal
ports:
- name: grpc
port: 7233
targetPort: 7233
- name: web-ui
port: 8233
targetPort: 8233
-12
View File
@@ -1,12 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: hightower-workspaces
namespace: hightower
spec:
accessModes:
- ReadWriteMany
storageClassName: ceph-filesystem
resources:
requests:
storage: 10Gi
-52
View File
@@ -1,52 +0,0 @@
networks:
default:
name: shannon-net
services:
temporal:
image: temporalio/temporal:latest
container_name: shannon-temporal
command: ["server", "start-dev", "--db-filename", "/home/temporal/temporal.db", "--ip", "0.0.0.0"]
ports:
- "127.0.0.1:7233:7233" # gRPC
- "127.0.0.1:8233:8233" # Web UI (built-in)
volumes:
- temporal-data:/home/temporal
healthcheck:
test: ["CMD", "temporal", "operator", "cluster", "health", "--address", "localhost:7233"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
# Optional: claude-code-router for multi-model support
# Start with: ROUTER=true ./shannon start ...
router:
image: node:20-slim
container_name: shannon-router
profiles: ["router"] # Only starts when explicitly requested
command: >
sh -c "apt-get update && apt-get install -y gettext-base &&
npm install -g @musistudio/claude-code-router &&
mkdir -p /root/.claude-code-router &&
envsubst < /config/router-config.json > /root/.claude-code-router/config.json &&
ccr start"
ports:
- "127.0.0.1:3456:3456"
volumes:
- ./apps/cli/infra/router-config.json:/config/router-config.json:ro
environment:
- HOST=0.0.0.0
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-}
- ROUTER_DEFAULT=${ROUTER_DEFAULT:-openai,gpt-4o}
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3456/health', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
volumes:
temporal-data:
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env node
process.env.SHANNON_LOCAL = '1';
import('./apps/cli/dist/index.mjs');