Skip to content
Draft
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
11 changes: 11 additions & 0 deletions .cursor/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM node:22-bookworm-slim

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
git \
curl \
ca-certificates \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/* \
&& corepack enable
9 changes: 9 additions & 0 deletions .cursor/environment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "Hermes Workspace",
"build": {
"dockerfile": "Dockerfile",
"context": "."
},
"install": "bash .cursor/scripts/cloud-install.sh",
"start": "bash .cursor/scripts/cloud-bootstrap-env.sh && export PATH=\"$HOME/.local/bin:$PATH\" && exec pnpm exec concurrently -n gateway,dashboard,workspace -c blue,green,magenta \"hermes gateway run\" \"hermes dashboard --port 9119 --host 127.0.0.1 --no-open\" \"pnpm dev\""
}
29 changes: 29 additions & 0 deletions .cursor/scripts/cloud-bootstrap-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail

API_KEY="${HERMES_DEV_API_KEY:-dev-cloud-agent-local-key}"
ROOT="${WORKSPACE_ROOT:-/workspace}"

mkdir -p "${HOME}/.hermes"

ensure_env_key() {
local file="$1"
local key="$2"
local value="$3"
if [[ -f "${file}" ]] && grep -q "^${key}=" "${file}"; then
return 0
fi
echo "${key}=${value}" >>"${file}"
}

ensure_env_key "${HOME}/.hermes/.env" API_SERVER_ENABLED true
ensure_env_key "${HOME}/.hermes/.env" API_SERVER_HOST 127.0.0.1
ensure_env_key "${HOME}/.hermes/.env" API_SERVER_KEY "${API_KEY}"

cd "${ROOT}"
if [[ ! -f .env ]]; then
cp .env.example .env
fi
ensure_env_key .env HERMES_API_URL http://127.0.0.1:8642
ensure_env_key .env HERMES_DASHBOARD_URL http://127.0.0.1:9119
ensure_env_key .env HERMES_API_TOKEN "${API_KEY}"
15 changes: 15 additions & 0 deletions .cursor/scripts/cloud-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail

export PATH="${HOME}/.local/bin:${PATH}"
ROOT="${WORKSPACE_ROOT:-/workspace}"
cd "${ROOT}"

corepack enable
corepack prepare pnpm@10 --activate

pnpm install

pip3 install --user hermes-agent aiohttp

mkdir -p "${HOME}/.hermes"
77 changes: 77 additions & 0 deletions .cursor/scripts/cloud-start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env bash
set -euo pipefail

export PATH="${HOME}/.local/bin:${PATH}"
ROOT="${WORKSPACE_ROOT:-/workspace}"
LOG_DIR="${HOME}/.hermes/logs"
API_KEY="${HERMES_DEV_API_KEY:-dev-cloud-agent-local-key}"

mkdir -p "${LOG_DIR}" "${HOME}/.hermes"

ensure_env_key() {
local file="$1"
local key="$2"
local value="$3"
if [[ -f "${file}" ]] && grep -q "^${key}=" "${file}"; then
return 0
fi
echo "${key}=${value}" >>"${file}"
}

ensure_env_key "${HOME}/.hermes/.env" API_SERVER_ENABLED true
ensure_env_key "${HOME}/.hermes/.env" API_SERVER_HOST 127.0.0.1
ensure_env_key "${HOME}/.hermes/.env" API_SERVER_KEY "${API_KEY}"

cd "${ROOT}"
if [[ ! -f .env ]]; then
cp .env.example .env
fi
ensure_env_key .env HERMES_API_URL http://127.0.0.1:8642
ensure_env_key .env HERMES_DASHBOARD_URL http://127.0.0.1:9119
ensure_env_key .env HERMES_API_TOKEN "${API_KEY}"

port_open() {
python3 -c "import socket; s=socket.socket(); s.settimeout(0.5); raise SystemExit(0 if s.connect_ex(('127.0.0.1', ${1})) == 0 else 1)"
}

start_if_needed() {
local name="$1"
shift
if port_open "${1}"; then
return 0
fi
if pgrep -f "${name}" >/dev/null 2>&1; then
return 0
fi
nohup "$@" >>"${LOG_DIR}/${name}.log" 2>&1 &
disown || true
}

start_if_needed gateway 8642 hermes gateway run
start_if_needed dashboard 9119 hermes dashboard --port 9119 --host 127.0.0.1 --no-open
start_if_needed workspace 3000 pnpm --dir "${ROOT}" dev

for _ in $(seq 1 45); do
gateway_ok=0
dashboard_ok=0
workspace_ok=0

if curl -fsS -H "Authorization: Bearer ${API_KEY}" http://127.0.0.1:8642/health >/dev/null 2>&1; then
gateway_ok=1
fi
if curl -fsS http://127.0.0.1:9119/api/status >/dev/null 2>&1; then
dashboard_ok=1
fi
if curl -fsS http://127.0.0.1:3000/api/sessions >/dev/null 2>&1; then
workspace_ok=1
fi

if [[ ${gateway_ok} -eq 1 && ${dashboard_ok} -eq 1 && ${workspace_ok} -eq 1 ]]; then
exit 0
fi

sleep 2
done

echo "Hermes Workspace services failed readiness checks within timeout" >&2
exit 1
11 changes: 11 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ This workspace uses semantic Hermes swarm workers, not numbered-only lanes. The
- For local Workspace pairing/debugging, treat **one gateway + one dashboard** as canonical: `hermes gateway run` on `:8642` and `hermes dashboard` on `:9119`. Before starting another gateway, verify `curl http://127.0.0.1:3000/api/sessions` (or the active workspace port) first. If Sessions already returns data, refresh/reprobe the UI instead of spawning a duplicate gateway.
- If the default model is `gpt-5.4` / `openai-codex`, remember that chat depends on a live local Codex CLI login (`codex login`).

## Cursor Cloud specific instructions

Cloud Agent environments use `.cursor/environment.json` (`cloud-install.sh` + `cloud-start.sh`) to bootstrap the full dev stack.

- **Canonical three-service dev stack**: gateway `:8642`, dashboard `:9119`, workspace `:3000`. The start script launches all three idempotently; do not spawn duplicates if health checks already pass.
- **Gateway API server**: Hermes Agent 0.19+ requires `API_SERVER_ENABLED=true`, `API_SERVER_KEY`, and the `aiohttp` pip package before `:8642/health` responds. The start script sets a loopback dev key and mirrors it to `HERMES_API_TOKEN` in the workspace `.env`.
- **Health checks**: `curl -H "Authorization: Bearer $HERMES_API_TOKEN" http://127.0.0.1:8642/health`, `curl http://127.0.0.1:9119/api/status`, `curl http://127.0.0.1:3000/api/sessions`.
- **Lint / test / build**: see `package.json` — `pnpm lint`, `pnpm test` (Vitest, no external services), `pnpm build`. Typecheck: `pnpm exec tsc --noEmit`.
- **Chat E2E** needs an LLM provider key in `.env` or `~/.hermes/.env`; UI/navigation/sessions work without one.
- **Service logs** (if manually debugging): `~/.hermes/logs/{gateway,dashboard,workspace}.log`.

## Windows-specific notes (2026-06-01)

- **Three services required**: Gateway (:8642) + Dashboard (:9119) + Workspace (:3000). All must be running for full functionality.
Expand Down