From 52560792c4a65bc15be66a2713941e425d457629 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 5 Aug 2026 18:31:15 +0000 Subject: [PATCH] Add Cursor Cloud development environment configuration Introduce .cursor/environment.json with Dockerfile, install/start scripts for the full Hermes Workspace dev stack (gateway, dashboard, workspace). Document Cloud Agent operating notes in AGENTS.md. Co-authored-by: Gokul K G --- .cursor/Dockerfile | 11 ++++ .cursor/environment.json | 9 +++ .cursor/scripts/cloud-bootstrap-env.sh | 29 ++++++++++ .cursor/scripts/cloud-install.sh | 15 +++++ .cursor/scripts/cloud-start.sh | 77 ++++++++++++++++++++++++++ AGENTS.md | 11 ++++ 6 files changed, 152 insertions(+) create mode 100644 .cursor/Dockerfile create mode 100644 .cursor/environment.json create mode 100755 .cursor/scripts/cloud-bootstrap-env.sh create mode 100755 .cursor/scripts/cloud-install.sh create mode 100755 .cursor/scripts/cloud-start.sh diff --git a/.cursor/Dockerfile b/.cursor/Dockerfile new file mode 100644 index 0000000000..f3cbee8914 --- /dev/null +++ b/.cursor/Dockerfile @@ -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 diff --git a/.cursor/environment.json b/.cursor/environment.json new file mode 100644 index 0000000000..a5ac981bb6 --- /dev/null +++ b/.cursor/environment.json @@ -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\"" +} diff --git a/.cursor/scripts/cloud-bootstrap-env.sh b/.cursor/scripts/cloud-bootstrap-env.sh new file mode 100755 index 0000000000..6feba8380a --- /dev/null +++ b/.cursor/scripts/cloud-bootstrap-env.sh @@ -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}" diff --git a/.cursor/scripts/cloud-install.sh b/.cursor/scripts/cloud-install.sh new file mode 100755 index 0000000000..6e68815eb8 --- /dev/null +++ b/.cursor/scripts/cloud-install.sh @@ -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" diff --git a/.cursor/scripts/cloud-start.sh b/.cursor/scripts/cloud-start.sh new file mode 100755 index 0000000000..fde9acd754 --- /dev/null +++ b/.cursor/scripts/cloud-start.sh @@ -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 diff --git a/AGENTS.md b/AGENTS.md index b7a9591050..216a992579 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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.