The Hoody Code orchestrator exposes the embedded VS Code interface, manages password-based session authentication, proxies HTTP and WebSocket traffic to local ports, and serves static metadata files (PWA manifest, robots.txt, security policy). Use these endpoints to embed the editor in your own UI, automate sign-in flows, or reverse-proxy local development servers through Hoody.
Static Assets & Metadata
Section titled “Static Assets & Metadata”GET /robots.txt
Section titled “GET /robots.txt”Returns the standard robots.txt file for the editor deployment. Use this to control search engine indexing.
curl https://code.example.com/robots.txtawait client.code.static.getRobots();Response 200 — The robots file is returned as text/plain:
User-agent: *Disallow: /GET /security.txt
Section titled “GET /security.txt”Returns the security.txt file for vulnerability disclosure. Also served at /.well-known/security.txt.
curl https://code.example.com/security.txtawait client.code.static.getSecurityPolicy();Response 200 — The security policy file is returned as text/plain:
Contact: mailto:security@hoody.comExpires: 2025-12-31T23:59:59zPreferred-Languages: enGET /hoody-code/injected/{script}
Section titled “GET /hoody-code/injected/{script}”Serves injected JavaScript files from the extra/injected/ directory. These scripts run automatically on every page when the --hoody-code flag is enabled. The same files are also available under /vscode/hoody-code/injected/{script}.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
script | path | string | Yes | Script filename |
curl https://code.example.com/hoody-code/injected/branding.jsawait client.code.static.getInjectedScript({ script: "branding.js" });Returns the JavaScript file with Content-Type: application/javascript.
Returned when the requested script does not exist in extra/injected/.
GET /_static/{path}
Section titled “GET /_static/{path}”Serves static files from the editor’s build directory, including the compiled JavaScript and CSS bundles, icons, images, and the service worker.
In production, files are served with long-lived Cache-Control headers keyed to the current git commit. In development, caching is disabled.
The service worker at /_static/out/browser/serviceWorker.js is served with the special header Service-Worker-Allowed: / so it can register at the root scope.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
path | path | string | Yes | Path to static file |
curl https://code.example.com/_static/out/browser/workbench.htmlawait client.code.static.get({ path: "out/browser/workbench.html" });Returns the file content. Service-worker files include Service-Worker-Allowed: /.
Returned when the file does not exist in the build directory.
VS Code Interface
Section titled “VS Code Interface”GET /api/v1/code/manifest.json
Section titled “GET /api/v1/code/manifest.json”Returns the Progressive Web App manifest for installing Hoody Code. Configure the app name with the --app-name flag.
This endpoint takes no parameters.
curl https://code.example.com/api/v1/code/manifest.jsonawait client.code.vscode.getManifest();Response 200 — The manifest is returned as application/manifest+json:
{ "name": "hoody-code", "short_name": "hoody-code", "start_url": ".", "display": "fullscreen", "display_override": ["window-controls-overlay"], "description": "Run Code on a remote server.", "icons": [ { "src": "/_static/out/browser/media/icon-192.png", "type": "image/png", "sizes": "192x192", "purpose": "any" }, { "src": "/_static/out/browser/media/icon-512.png", "type": "image/png", "sizes": "512x512", "purpose": "maskable" } ]}GET /api/v1/code
Section titled “GET /api/v1/code”Returns the main VS Code web interface.
If authentication is enabled and the user is not logged in, the request is redirected to /login with the original URL preserved. Sessions are managed via cookies.
If neither folder nor workspace is provided, the last opened folder (or the value passed on the CLI) is used. Query parameters are persisted to settings for the next session. Both plain folders and .code-workspace files are supported.
Pass ?extension=PUBLISHER.NAME to hide the file explorer and focus the UI on a single extension. This is ideal for embedding extensions as standalone web apps (for example, ms-toolsai.jupyter for notebooks or ms-azuretools.vscode-docker for container management).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
folder | query | string | No | Absolute path to a folder to open. Takes precedence over workspace. |
workspace | query | string | No | Absolute path to a .code-workspace file. Used when folder is not provided. |
extension | query | string | No | Extension ID in PUBLISHER.NAME format. Opens in extension-only mode, hiding the file explorer. |
ew | query | boolean | No | Empty Window flag. When present, clears the last opened folder or workspace from settings. |
locale | query | string | No | IETF language tag for the UI (e.g. en, fr, de, zh-CN). |
curl "https://code.example.com/api/v1/code?folder=/home/user/projects/hoody&locale=en" \ -b "session=$HOODY_SESSION"await client.code.vscode.getVSCode({ folder: "/home/user/projects/hoody", locale: "en"});Returns the VS Code HTML page with Content-Type: text/html; charset=utf-8. A Content-Security-Policy header is included and is updated automatically when --external-js or --external-css is configured.
<!DOCTYPE html><html lang="en"><head> <title>VS Code</title> <meta charset="utf-8"></head><body> <div data-hoody-loader> <div class="hdyldr-spinner"></div> <div class="hdyldr-changing-text">Loading…</div> </div></body></html>Returned when authentication is required. The Location header redirects to the login page with the original URL preserved:
Location: /login?to=%2F%3Ffolder%3D%2Fhome%2Fuser%2FprojectPOST /api/v1/code/mint-key
Section titled “POST /api/v1/code/mint-key”Generates or retrieves the server’s web key half used by VS Code for secure communications. The key is 256 bits (32 bytes) and is generated once on first use, then reused across restarts. It is stored at user-data-dir/serve-web-key-half.
This endpoint takes no parameters.
curl -X POST https://code.example.com/api/v1/code/mint-keyawait client.code.vscode.mintKey();Response 200 — Returns the raw 32-byte key with Content-Type: application/octet-stream. The body is binary and must be treated as a key, not text.
Authentication
Section titled “Authentication”Password-based authentication is only available when the server was started with a password source (--password or --hashed-password).
GET /api/v1/code/login
Section titled “GET /api/v1/code/login”Returns the login page HTML. If the user is already authenticated, the request is redirected to the target URL.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
to | query | string | No | URL to redirect to after successful login. Default: "/". |
curl https://code.example.com/api/v1/code/login?to=/projects/hoodyawait client.code.auth.getLoginPage({ to: "/projects/hoody" });Returns the login form HTML with Content-Type: text/html.
Returned when the user is already authenticated. The Location header contains the destination URL (the value of to, or / by default).
POST /api/v1/code/login
Section titled “POST /api/v1/code/login”Submits credentials to authenticate the user. On success, a session cookie is set and the user is redirected. On failure, the login page is returned with an inline error message.
Login attempts are rate limited: 2 attempts per minute and 12 attempts per hour. Exceeding these limits returns a RATE_LIMITED error.
Passwords configured with --hashed-password are verified with argon2. Passwords configured with --password are verified against a SHA-256 hash. Failed attempts are logged with the source IP and User-Agent.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
to | query | string | No | URL to redirect to after successful login |
Request Body
Section titled “Request Body”application/x-www-form-urlencoded form data:
| Name | Type | Required | Description |
|---|---|---|---|
password | string | Yes | Password to authenticate with. |
curl -X POST "https://code.example.com/api/v1/code/login?to=/projects/hoody" \ -d "password=yourPassword"// Redirect to a specific path after loginawait client.code.auth.login({ to: "/projects/hoody" });
// Or use the default redirect ("/")await client.code.auth.login();Returned when authentication fails. The body is the login page HTML with an inline error.
<!DOCTYPE html><html><head><title>Sign in</title></head><body> <form method="POST"> <p class="error">Invalid password</p> <input type="password" name="password" /> </form></body></html>| Error Code | Title | Description | Resolution |
|---|---|---|---|
INVALID_PASSWORD | Invalid password | The password provided is incorrect | Check your password and try again |
RATE_LIMITED | Too many login attempts | Rate limit exceeded (2 attempts/min or 12 attempts/hour) | Wait a few minutes before trying again |
Returned on success (or on failure when to points elsewhere). On success the Set-Cookie header carries the new session cookie. The Location header points to the destination URL or back to the login page.
GET /api/v1/code/logout
Section titled “GET /api/v1/code/logout”Clears the session cookie and redirects to the home page. Only available when authentication is enabled.
This endpoint takes no parameters.
curl https://code.example.com/api/v1/code/logoutawait client.code.auth.logout();Response 302 — Returned on success. The Location header is /, and Set-Cookie clears the session cookie by setting it to an expired date.
Port Proxying
Section titled “Port Proxying”Hoody Code can forward HTTP and WebSocket traffic to local ports so that web apps running on the host (dev servers, dashboards, custom tools) are reachable through the editor URL.
/proxy/:port/*strips the proxy prefix before forwarding./absproxy/:port/*keeps the full path including/absproxy/:port/. Use this when the proxied app needs to know it is running under a subpath. The base path can be customized with--abs-proxy-base-path.
Both endpoints require authentication unless --skip-auth-preflight is set for OPTIONS requests. WebSocket upgrades are supported.
GET /api/v1/code/proxy/{port}/{path}
Section titled “GET /api/v1/code/proxy/{port}/{path}”Proxies the request to an HTTP service on a local port, stripping /proxy/:port from the path. For example, /api/v1/code/proxy/3000/api/users is forwarded to http://localhost:3000/api/users.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
port | path | integer | Yes | Local port to proxy to |
path | path | string | Yes | Path to append to the proxied request |
curl https://code.example.com/api/v1/code/proxy/3000/api/users \ -b "session=$HOODY_SESSION"await client.code.proxy.resolve({ port: 3000, path: "api/users" });Returns the proxied response from the target service. The body, headers, and status code are passed through unchanged.
Returned when authentication is required.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
AUTHENTICATION_REQUIRED | Authentication required | You must be logged in to access proxied ports | Log in with your password first |
Returned when the target port is not reachable.
| Error Code | Title | Description | Resolution |
|---|---|---|---|
PORT_UNREACHABLE | Cannot connect to local port | The specified port is not accessible or no service is running | Verify the application is running on the specified port |
GET /api/v1/code/absproxy/{port}/{path}
Section titled “GET /api/v1/code/absproxy/{port}/{path}”Like /proxy/:port/*, but preserves the full path including /absproxy/:port/. The target app must be configured to serve from this base path.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
port | path | integer | Yes | Local port to proxy to |
path | path | string | Yes | Path (preserved in forwarded request) |
curl https://code.example.com/api/v1/code/absproxy/8080/dashboard \ -b "session=$HOODY_SESSION"await client.code.proxy.resolveAbsolute({ port: 8080, path: "dashboard" });Returns the proxied response from the target service. The body, headers, and status code are passed through unchanged.
Returned when authentication is required.
Returned when the target port is not reachable.