Skip to content
This repository was archived by the owner on Jun 28, 2026. It is now read-only.
Closed
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
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,9 @@ When adding code that needs a new string, decide up front which rule it falls un
- `/api/automation/*` → automation backend (:18001)
- `/api/*`, `/sockets`, etc. → agent server (:18000)
- `/*` (default) → frontend server (:3001), either Vite or static depending on launcher mode
- Environment variables: `PORT` (ingress port, default: 8000), `OH_AUTOMATION_GIT_REF` (git ref, overrides default version), `OH_AUTOMATION_VERSION` (default: `1.0.0a3`), `AUTOMATION_LOCAL_API_KEY` (optional, use a fixed key; default: persisted generated key), `OH_AUTOMATION_API_KEY_PATH` (override the persisted default key path)
- Environment variables: `PORT` (ingress port, default: 8000), `OH_AUTOMATION_GIT_REF` (git ref, overrides default version), `OH_AUTOMATION_VERSION` (default: `1.0.0a3`), `AUTOMATION_DB_URL` (optional override for the automation SQLite DB), `AUTOMATION_LOCAL_API_KEY` (optional, use a fixed key; default: persisted generated key), `OH_AUTOMATION_API_KEY_PATH` (override the persisted default key path)
- For local cross-repo test harnesses, prefer overriding `AUTOMATION_DB_URL` rather than `OH_CANVAS_SAFE_STATE_DIR` when you need a clean automation scheduler state but want to keep the user's existing LLM profiles/secrets. A fresh state dir also changes `OH_PERSISTENCE_DIR`, which can make the stack look like LLM setup was lost.
- The launcher should wait for both the automation backend (`/api/automation/health`) and the frontend (`/`) to become reachable before starting ingress and printing the ready banner; otherwise first-load requests hit proxy errors (`/api/automation/health`, `/`, `/favicon.ico`) and the Automations page can incorrectly show Backend Not Configured on a healthy-but-still-booting stack.
- `scripts/check-sdk-version-sync.mjs` checks the released `openhands-automation` package against `versions.automationSdk` in `config/defaults.json`; that value may intentionally lag `versions.agentServer` while automation has not yet published a matching release.
- Access points: `http://localhost:8000/` (main UI), `http://localhost:8000/api/automation/docs` (API docs)
- Security: `AUTOMATION_LOCAL_API_KEY` defaults to a generated key persisted across restarts because static frontend builds bake it into `VITE_AUTOMATION_API_KEY`. Set the env var explicitly to rotate or pin it. The cipher key (`OH_SECRET_KEY`) is persisted at `~/.openhands/agent-canvas/secret-key.txt` (same file used by `docker/entrypoint.sh`); both modes share the same key automatically when using the same `~/.openhands` directory.
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@heroui/react": "2.8.10",
"@microlink/react-json-view": "1.31.20",
"@monaco-editor/react": "4.7.0",
"@openhands/extensions": "0.3.0",
"@openhands/extensions": "git+https://github.com/jamiechicago312/extensions.git#1566b45055779dd2ef33070e76c0976c4175ebfc",
"@openhands/typescript-client": "1.24.3",
"@react-router/node": "7.17.0",
"@react-router/serve": "7.17.0",
Expand Down Expand Up @@ -70,7 +70,9 @@
"zustand": "5.0.12"
},
"scripts": {
"dev": "node --env-file-if-exists=.env scripts/dev-with-automation.mjs",
"dev": "node --env-file-if-exists=.env scripts/dev-github-windows-stack.mjs",
"dev:default": "node --env-file-if-exists=.env scripts/dev-with-automation.mjs",
"dev:test-github-windows-stack": "node --env-file-if-exists=.env scripts/dev-github-windows-stack.mjs",
"dev:static": "node --env-file-if-exists=.env scripts/dev-static.mjs",
"dev:extra-backend": "node --env-file-if-exists=.env scripts/dev-extra-backend.mjs",
"dev:minimal": "node --env-file-if-exists=.env scripts/dev-safe.mjs",
Expand Down
26 changes: 26 additions & 0 deletions scripts/dev-github-windows-stack.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { homedir } from "node:os";
import { dirname, join } from "node:path";

import { main } from "./dev-with-automation.mjs";

const DEFAULT_STATE_DIR = join(homedir(), ".openhands", "agent-canvas");
const stateDir =
process.env.OH_CANVAS_SAFE_STATE_DIR ||
process.env.STATE_DIR ||
DEFAULT_STATE_DIR;
const automationDbPath = join(
dirname(stateDir),
"automation",
"github-windows-stack.db",
);

process.env.OH_AUTOMATION_REPO ??=
"https://github.com/jamiechicago312/automation.git";
process.env.OH_AUTOMATION_GIT_REF ??=
"d20a68c1ef581370d1297da42a9b43a1de3c87b4";
process.env.AUTOMATION_DB_URL ??=
`sqlite+aiosqlite:///${automationDbPath}`;

await main({
bannerTitle: "Agent Canvas + Automation Development Stack (GitHub Windows test)",
});
42 changes: 38 additions & 4 deletions scripts/dev-with-automation.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* Environment variables:
* - PORT: Ingress port (default: 8000)
* - OH_AUTOMATION_GIT_REF: Git ref for automation (default: main)
* - AUTOMATION_DB_URL: Optional sqlite URL override for the automation DB
* - OH_AGENT_SERVER_LOCAL_PATH: Absolute path to a local software-agent-sdk
* checkout. Highest precedence for agent-server source selection: rebuilds
* the agent-server from local source and installs openhands-sdk,
Expand Down Expand Up @@ -250,6 +251,7 @@ ENVIRONMENT VARIABLES:
PORT Alternative to --port
OH_AUTOMATION_GIT_REF Git ref for automation (overrides default version)
OH_AUTOMATION_VERSION Specific PyPI version for automation (default: ${DEFAULT_AUTOMATION_VERSION})
AUTOMATION_DB_URL Override the automation SQLite DB path/URL
OH_AGENT_SERVER_LOCAL_PATH Absolute path to a local software-agent-sdk checkout (highest precedence)
OH_AGENT_SERVER_GIT_REF Git ref for agent-server SDK (overrides default version)
OH_AGENT_SERVER_VERSION Specific PyPI version for agent-server
Expand Down Expand Up @@ -819,8 +821,13 @@ function startAutomationBackend(config) {
}
: {}),
AUTOMATION_AGENT_SERVER_API_KEY: config.sessionApiKey,
// ~/.openhands/automation/automations.db — matches docker/entrypoint.sh.
AUTOMATION_DB_URL: `sqlite+aiosqlite:///${join(dirname(config.stateDir), SHARED_DEFAULTS.paths.automationDb)}`,
// ~/.openhands/automation/automations.db by default — matches docker/entrypoint.sh.
// Allow callers to override it so local test harnesses can avoid stale
// scheduled automations while still reusing the user's existing LLM
// profiles and secrets.
AUTOMATION_DB_URL:
process.env.AUTOMATION_DB_URL ||
`sqlite+aiosqlite:///${join(dirname(config.stateDir), SHARED_DEFAULTS.paths.automationDb)}`,
// The automation backend uses this as its publicly-reachable base
// URL: it's appended to callback URLs and injected into each
// sandbox as `AUTOMATION_API_URL` (consumed by setup.sh for
Expand Down Expand Up @@ -1319,8 +1326,35 @@ async function main(options = {}) {
}
}

// 5. Wait for services to be ready
await delay(2000);
// 5. Wait for launched services to become reachable before exposing ingress.
// Without this the browser can hit / or /api/automation/health while Vite or
// the automation backend is still booting, which surfaces misleading proxy
// errors and an empty automations screen on first load.
const readinessChecks = [];
if (config.launchAutomation) {
readinessChecks.push(
waitForService(
"automation",
`http://localhost:${config.autoBackendPort}${AUTOMATION_ROUTE_PREFIX}/health`,
60000,
),
);
}
if (config.launchFrontend) {
const frontendUrl = getFrontendBackend(config);
if (frontendUrl) {
readinessChecks.push(
waitForService(
useStaticMode ? "static" : "vite",
frontendUrl,
60000,
),
);
}
}
if (readinessChecks.length > 0) {
await Promise.all(readinessChecks);
}

// 6. Start ingress proxy (routes traffic only to running services)
startIngress(config);
Expand Down