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: jobs:
check: check:
name: Type-check & lint name: Type-check & lint
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -43,7 +43,7 @@ jobs:
name: Build & push worker image name: Build & push worker image
needs: check needs: check
if: github.event_name == 'push' && github.ref == 'refs/heads/main' if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: read contents: read
packages: write packages: write
@@ -68,14 +68,14 @@ jobs:
context: . context: .
push: true push: true
tags: | tags: |
ghcr.io/farhoodliquor/shannon:latest ghcr.io/farhoodlabs/shannon:latest
ghcr.io/farhoodliquor/shannon:sha-${{ github.sha }} ghcr.io/farhoodlabs/shannon:sha-${{ github.sha }}
build-api: build-api:
name: Build & push API image name: Build & push API image
needs: check needs: check
if: github.event_name == 'push' && github.ref == 'refs/heads/main' if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: read contents: read
packages: write packages: write
@@ -102,5 +102,5 @@ jobs:
push: true push: true
no-cache: true no-cache: true
tags: | tags: |
ghcr.io/farhoodliquor/hightower-api:latest ghcr.io/farhoodlabs/hightower-api:latest
ghcr.io/farhoodliquor/hightower-api:sha-${{ github.sha }} ghcr.io/farhoodlabs/hightower-api:sha-${{ github.sha }}
+5 -5
View File
@@ -13,7 +13,7 @@ concurrency:
jobs: jobs:
preflight: preflight:
name: Preflight name: Preflight
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
outputs: outputs:
version: ${{ steps.version.outputs.version }} version: ${{ steps.version.outputs.version }}
@@ -47,7 +47,7 @@ jobs:
build-docker: build-docker:
name: Build Docker (worker) name: Build Docker (worker)
needs: preflight needs: preflight
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: read contents: read
@@ -76,7 +76,7 @@ jobs:
build-docker-api: build-docker-api:
name: Build Docker (API) name: Build Docker (API)
needs: preflight needs: preflight
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: read contents: read
@@ -106,7 +106,7 @@ jobs:
sign-docker: sign-docker:
name: Sign Docker images name: Sign Docker images
needs: [preflight, build-docker, build-docker-api] needs: [preflight, build-docker, build-docker-api]
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: read contents: read
id-token: write id-token: write
@@ -165,7 +165,7 @@ jobs:
publish-npm: publish-npm:
name: Publish npm (beta) name: Publish npm (beta)
needs: [preflight, sign-docker] needs: [preflight, sign-docker]
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: read contents: read
id-token: write id-token: write
+6 -6
View File
@@ -13,7 +13,7 @@ concurrency:
jobs: jobs:
preflight: preflight:
name: Preflight name: Preflight
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: write contents: write
outputs: outputs:
@@ -60,7 +60,7 @@ jobs:
name: Build Docker (worker) name: Build Docker (worker)
needs: preflight needs: preflight
if: needs.preflight.outputs.should_release == 'true' if: needs.preflight.outputs.should_release == 'true'
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: read contents: read
@@ -92,7 +92,7 @@ jobs:
name: Build Docker (API) name: Build Docker (API)
needs: preflight needs: preflight
if: needs.preflight.outputs.should_release == 'true' if: needs.preflight.outputs.should_release == 'true'
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: read contents: read
@@ -124,7 +124,7 @@ jobs:
sign-docker: sign-docker:
name: Sign Docker images name: Sign Docker images
needs: [preflight, build-docker, build-docker-api] needs: [preflight, build-docker, build-docker-api]
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: read contents: read
id-token: write id-token: write
@@ -183,7 +183,7 @@ jobs:
publish-npm: publish-npm:
name: Publish npm name: Publish npm
needs: [preflight, sign-docker] needs: [preflight, sign-docker]
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: read contents: read
id-token: write id-token: write
@@ -228,7 +228,7 @@ jobs:
release: release:
name: Create GitHub release name: Create GitHub release
needs: [preflight, publish-npm] needs: [preflight, publish-npm]
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
permissions: permissions:
contents: write contents: write
+1 -1
View File
@@ -18,7 +18,7 @@ concurrency:
jobs: jobs:
rollback: rollback:
name: Roll back npm beta dist-tag name: Roll back npm beta dist-tag
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
steps: steps:
- name: Validate target version - name: Validate target version
id: target id: target
+1 -1
View File
@@ -18,7 +18,7 @@ concurrency:
jobs: jobs:
rollback: rollback:
name: Roll back npm, Docker, and GitHub release latest name: Roll back npm, Docker, and GitHub release latest
runs-on: runners-farhoodliquor runs-on: runners-farhoodlabs
steps: steps:
- name: Checkout tags - name: Checkout tags
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+25 -110
View File
@@ -1,78 +1,12 @@
# CLAUDE.md # 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 ## 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 ```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) # Build TypeScript (development)
pnpm run build # Build all packages via Turborepo pnpm run build # Build all packages via Turborepo
pnpm run check # Type-check all packages 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. **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 ## Architecture
### Monorepo Layout ### Monorepo Layout
``` ```
apps/cli/ — @keygraph/shannon (published to npm, bundled with tsdown) apps/api/ — @shannon/api (Hightower REST API, K8s-native)
apps/worker/ — @shannon/worker (private, Temporal worker + pipeline logic) 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/`) ### 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. Upstream Shannon CLI — kept for backporting compatibility. Not used in Hightower's K8s deployment.
- `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
### Worker Package (`apps/worker/`) ### 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/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/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 - `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/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/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 - `apps/worker/src/temporal/shared.ts` — Types, interfaces, query definitions
### Five-Phase Pipeline ### Five-Phase Pipeline
1. **Pre-Recon** (`pre-recon`) — External scans (nmap, subfinder, whatweb) + source code analysis 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 4. **Exploitation** (5 parallel agents, conditional) — Exploits confirmed vulnerabilities
5. **Reporting** (`report`) — Executive-level security report 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 ### 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` - **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 - **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 - **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) - **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 - **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) - **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 ### Security
Defensive security tool only. Use only on systems you own or have explicit permission to test. 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 ## 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` **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/` **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 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. 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');