Build, deploy, and run hostfunc functions without leaving your editor.
Status: M2 — sign-in, function browsing with detail views, deploy, run-with-payload, and local file sync with push-on-save. Marketplace and MCP wiring land in later milestones.
Features
- Browser sign-in via the OAuth device flow (RFC 8628). No token to copy — click Sign in, approve in the browser, done. Your access token is stored in VS Code SecretStorage, scoped per workspace/organization.
- Functions explorer — browse the functions in your active workspace with deploy/run status.
- Function detail views — expand a function to inspect its triggers, recent versions, recent executions (with copyable execution ids), and secret key names (values are never shown or transferred).
- Deploy the current draft to a live version, with progress + a copyable run URL.
- Run with payload — invoke a function with a JSON payload; the result and execution logs stream into the hostfunc Output channel.
- Local file sync — pull a function's draft into a folder and push edits back; saving the project's entry file pushes the draft automatically.
- Switch workspace — multiple organizations are supported; switch from the status bar. Each org gets its own token, minted on demand.
Getting started (as a user)
- Open the hostfunc view in the Activity Bar.
- Click Sign in to hostfunc — a code appears and your browser opens to authorize the device.
- Approve, and your functions appear in the Functions view.
See the in-app docs at /docs/vscode-extension for the full user guide.
Configuration
| Setting | Default | Description |
|---|---|---|
hostfunc.baseUrl |
https://hostfunc.io |
Control-plane URL. Point at http://localhost:3000 for local dev, or your self-hosted instance. |
How it works (architecture)
The extension is a thin, native VS Code client over the hostfunc control plane. It shares its API
contract with the hostfunc CLI via the private @hostfunc/api-client workspace package — one
typed fetch client, one device-flow implementation, used by both.
apps/vscode-extension/src
├── extension.ts activate(): wires AuthManager, tree, commands, status bar, context key
├── auth.ts AuthManager — SecretStorage tokens, active org, device-flow sign-in
├── commands.ts command handlers (signIn/out, switchOrg, deploy, run, …)
├── logs.ts RunLogChannel — renders run results + logs into an Output channel
├── views/functions-tree.ts FunctionsTreeProvider — the Functions explorer
└── lib/payload.ts pure JSON-payload parsing/validation (unit-tested)
Shared logic lives in packages/api-client/src:
client.ts—HostfuncApiClient(typed methods for every/api/cli/*route + device exchange).device-flow.ts—requestDeviceCode/pollForToken(RFC 8628),clientId-parameterized so the extension (hostfunc-vscode) and CLI (hostfunc-cli) reuse it.
Authentication flow
requestDeviceCode→ control plane returns auser_code+ verification URL (better-authdevice-authorizationplugin, mounted at/api/auth/device/*).- The browser opens to
/device, where the signed-in user approves the code. pollForTokenpolls/api/auth/device/tokenuntil approval, yielding a session access token.POST /api/cli/device/exchange(Bearer = session token, via better-authbearerplugin) mints an org-scopedhfn_live_personal access token.- The PAT is stored in SecretStorage under
hostfunc.token.<orgId>; the active org is stored in globalState. All subsequent/api/cli/*calls use the PAT.
Switching orgs mints a per-org PAT via POST /api/cli/orgs (authenticated with the current PAT), so
no long-lived session is retained client-side.
Bundling
esbuild bundles src/extension.ts (+ @hostfunc/api-client) into a single CommonJS
dist/extension.js. vscode is marked external (provided by the host); @hostfunc/api-client is
bundled in. The extension is a leaf in the Turbo graph — it is never a build dependency of the
web app.
Local development & testing
Prerequisites: the monorepo installed (pnpm install) and @hostfunc/api-client built
(pnpm --filter @hostfunc/api-client build, or just pnpm build).
# Bundle once / watch
pnpm --filter hostfunc-vscode build
pnpm --filter hostfunc-vscode dev # esbuild --watch
# Gates
pnpm --filter hostfunc-vscode typecheck
pnpm --filter hostfunc-vscode test # Vitest unit tests (pure logic)
Run it in the Extension Development Host
- Start a local control plane:
pnpm dev:web(Next.js onhttp://localhost:3000). Make sure the DB is migrated (pnpm db:migrate) so thedevice_codetable exists. - Open the repo in VS Code and press F5 (launches an Extension Development Host
window with the extension loaded). If prompted, pick the "Run Extension" launch config; if no
config exists, see
.vscode/launch.jsonbelow. - In the dev-host window, set
hostfunc.baseUrltohttp://localhost:3000(Settings → search "hostfunc"). - Open the hostfunc view → Sign in → approve in the browser → your functions load.
- Try Deploy and Run with payload on a function; watch the hostfunc Output channel.
A minimal .vscode/launch.json for the host:
{
"version": "0.2.0",
"configurations": [
{
"name": "Run hostfunc Extension",
"type": "extensionHost",
"request": "launch",
"args": ["--extensionDevelopmentPath=${workspaceFolder}/apps/vscode-extension"],
"outFiles": ["${workspaceFolder}/apps/vscode-extension/dist/**/*.js"],
"preLaunchTask": "npm: build - apps/vscode-extension"
}
]
}
Install the built .vsix locally
pnpm --filter hostfunc-vscode build
pnpm --filter hostfunc-vscode package # → apps/vscode-extension/hostfunc.vsix
code --install-extension apps/vscode-extension/hostfunc.vsix
Releasing to production
See PUBLISHING.md for the full runbook: publisher setup, marketplace tokens, versioning, and the tag-triggered CI workflow that publishes to the VS Marketplace and Open VSX.