SuperAPI AI Directory

iblai-vibe-virtual-machine

Agents & models

View repository

Updated 10-15 22:16

About this skill

/iblai-vibe-virtual-machine

Add the organization settings Virtual Machine tab -- "Manage the network policies and secrets available to agents' virtual machines." Agents on the Virtual Machine Shell sandbox kind run each chat in an isolated Linux VM with no network access by default. This surface holds the two organization-wide records that open it up, in two sub-tabs:

  • Network Policies — reusable named lists of the host:port destinations a VM may reach (up to 100 entries each).
  • Secrets — keys the VM can use but never read. Inside the machine the environment variable holds a placeholder; the real value is substituted only on TLS requests to the secret's allowed hosts.

Both are shared by every agent in the organization. Picking them for one agent happens in its Sandbox settings — see /iblai-vibe-agent-virtual-machine.

Virtual Machine — Network Policies

Virtual Machine — Secrets

New Network Policy dialog

New VM Secret dialog — Value Source picks a stored value or an integration credential

Network Policies — empty state

Secrets — empty state

Common setup (brand, conventions, env files, verification): see docs/skill-setup.md.

Related surfaces

  • /iblai-vibe-agent-virtual-machine — the agent's Sandbox → Network Access section: the egress profile, the policy picker and the secrets multi-select that consume these records. Its Manage Policies / Manage Secrets buttons open this exact surface in a popup.
  • /iblai-vibe-agent-sandbox — the Sandbox Type card that turns Virtual Machine Shell on in the first place.
  • /iblai-vibe-account — the Account settings page hosts this surface as its Virtual Machine tab (see Step 2).
  • /iblai-vibe-credential — the organization's integration credentials; a secret can read its value from one field of a saved credential instead of storing its own.

Prerequisites

  • Auth must be set up first (/iblai-vibe-auth)
  • MCP server + skills configured (@iblai/mcp in .mcp.json)
  • The viewer needs Ibl.Mentor/VirtualMachineNetworkPolicies/{list,write,delete} and Ibl.Mentor/VirtualMachineSecrets/{list,write,delete}. Organization admins hold them by default; they are not in the learner baseline. Each section hides on its own list 403, and when both lists are forbidden the tab renders a single permission notice.
  • Only agents on the Virtual Machine Shell kind consume these records. Nothing breaks without one, but nothing uses them either.

Step 1: Check Environment

Before proceeding, check for an iblai.env in the project root. Look for PLATFORM, DOMAIN, and TOKEN variables. If the file does not exist or is missing these variables, tell the user: "You need an iblai.env with your platform configuration. Download the template and fill in your values: curl -o iblai.env https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/iblai.env"

Step 2: Mount it

Two ways, both supported.

As the Account page's Virtual Machine tab (how the SPAs ship it):

// app/(app)/settings/virtual-machine/page.tsx
"use client";

import { Account } from "@iblai/iblai-js/web-containers/next";

export default function OrgVirtualMachinePage() {
  return (
    <div className="flex h-full flex-col bg-white">
      {/* accountProps = your usual <Account> wiring */}
      <Account {...accountProps} targetTab="virtualMachine" />
    </div>
  );
}

See /iblai-vibe-account Step 2 for the full <Account> prop wiring.

Standalone — unlike the Memory admin tab, this one is exported:

"use client";

import { VirtualMachineAdminTab } from "@iblai/iblai-js/web-containers";

export default function VirtualMachinePage({
  tenantKey,
  username,
}: {
  tenantKey: string;
  username: string;
}) {
  return (
    <VirtualMachineAdminTab
      tenantKey={tenantKey}
      username={username}
      defaultTab="network-policies"
    />
  );
}

Step 3: Use MCP Tools for Customization

get_component_info("VirtualMachineAdminTab")
get_component_info("HostPortChipInput")
get_hook_info("useListVirtualMachineSecretsQuery")

Component Props

<VirtualMachineAdminTab> — @iblai/iblai-js/web-containers

Prop Type Required Description
tenantKey string Yes Organization key whose policies and secrets are managed
username string No Signed-in admin. When present, a policy delete refused because agents still use it lists those agents by name instead of by id
defaultTab 'network-policies' | 'secrets' No Which sub-tab opens first; falls back to the other one when that list is forbidden

Component map (web-containers source)

Everything lives under packages/web-containers/src/components/ in the SDK. Only VirtualMachineAdminTab and HostPortChipInput are public exports; the rest are listed as the reference for custom builds.

Component Path Role
VirtualMachineAdminTab profile/virtual-machine-admin/index.tsx The surface: info box, permission gate, Network Policies / Secrets sub-tabs
NetworkPoliciesSection profile/virtual-machine-admin/network-policies-section.tsx Policies table + New / Edit / Delete, including the "still in use" refusal
VmSecretsSection profile/virtual-machine-admin/vm-secrets-section.tsx Secrets table + New / Edit / Delete, and the Source column
NetworkPolicyDialog virtual-machine/network-policy-dialog.tsx Create / edit a policy. Also opened straight from the agent's Create Policy button
VmSecretDialog virtual-machine/vm-secret-dialog.tsx Create / edit a secret, including the Value Source choice
HostPortChipInput virtual-machine/host-port-chip-input.tsx The host:port chip input both dialogs use (Enter / comma / space / paste, per-entry validation, keyboard-removable chips)
toIntegrationCredentialOptions virtual-machine/credential-options.ts Normalises the integration-credential list into { id, name, fields } — only ids, names and the keys of the masked value

What each sub-tab renders

Network Policies

  • New Policy opens the dialog; each row has pencil (edit) and trash (delete) actions.
  • Columns: Name, Allowed Hosts (first 3 as chips, then "+N more"), Description (— when blank), Updated (time-ago), Actions.
  • Empty: "No network policies yet. Create one to let an agent's VM reach specific hosts."
  • New / Edit Network Policy dialog: Name (unique in the organization, ≤ 255 chars), Allowed Hosts (1–100 host:port entries, IP addresses allowed), Description (optional). Editing sends only the fields that changed, and removing a host raises an amber warning that a bound secret needing it will stop working — the backend allows the edit anyway.
  • Delete asks to confirm. If an agent still uses the policy the backend refuses: the dialog then lists the blocking agents (by name when username lets it resolve them, else by id) and hides the Delete button until you move those agents off it.

Secrets

  • New Secret opens the dialog; pencil and trash per row.
  • Columns: Name, Variable (the env var as a code chip), Allowed Hosts, Source (Stored Value, or Credential {name} · {field}), Updated, Actions.
  • Empty: "No VM secrets yet. Create one to let an agent call an API with your organization's key without ever seeing it."
  • New / Edit VM Secret dialog:
    • Name — display name, ≤ 255 chars.
    • Environment Variable — e.g. ACME_KEY; letters, digits and underscores, cannot start with a digit. Read-only once created — delete and recreate to rename.
    • Allowed Hosts — hostnames only, no IPs. These are the only hosts the real value is ever sent to, so keep them narrow.
    • Value Source — Enter a Value (stored encrypted, never shown again, at least 8 characters) or Use an Integration Credential (pick a saved credential and one of its fields; the secret follows rotations automatically).
    • On edit the value field is never prefilled — blank keeps the current value, and typing a new one replaces it (dropping any credential link).
  • Delete warns that the secret is also removed from every agent that uses it, then deletes.

REST API

For custom UI. Both records live under ${dmUrl}/api/ai-account/orgs/{org}/ where dmUrl is NEXT_PUBLIC_API_BASE_URL. Auth: Authorization: Token <token>. Records are keyed in the body, never in the URL.

Network policies — virtual-machine-network-policy/

Method Body / notes
GET [{ id, name, allowed_hosts, description, created_at, updated_at }]
POST { "name": "Acme APIs", "allowed_hosts": ["api.acme.com:443"], "description": "" } → 201
PATCH { "id": 12, … } — any of name, allowed_hosts (replaces the whole list), description
DELETE { "id": 12 } → 204; 400 while an agent still uses it, and the message names the agents

Secrets — virtual-machine-secret/

Method Body / notes
GET [{ id, name, env_var, allow_hosts, source_credential_id, source_field, created_at, updated_at }] — never a value
POST { "name", "env_var": "ACME_KEY", "allow_hosts": ["api.acme.com:443"], "value": "…" } or { …, "source_credential_id": 7, "source_field": "api_key" } — exactly one form
PATCH keyed by { "env_var": "ACME_KEY" }; sending value or a source_credential_id switches the form. env_var itself cannot change
DELETE { "env_var": "ACME_KEY" } → 204; also unbinds it from every agent

Integration credentials for the second form come from GET /api/ai-account/orgs/{org}/integration-credential/, which returns [{ id, name, value: { api_key: "sk-****", … } }]. Only the ids, names and the keys of value are used — masked values are never shown.

Validation the UI mirrors

Rule Constant
host:port, no scheme, path or wildcard; port 1–65535 VIRTUAL_MACHINE_HOST_PORT_PATTERN
localhost, metadata*, instance-data* and .local / .internal / .localhost suffixes refused; reserved IP ranges refused VIRTUAL_MACHINE_REJECTED_HOSTS, VIRTUAL_MACHINE_REJECTED_HOST_SUFFIXES
Policies accept IP addresses, secrets do not HostPortChipInput's allowIpAddresses
≤ 100 hosts per policy VIRTUAL_MACHINE_MAX_POLICY_HOSTS
≤ 20 secrets per agent VIRTUAL_MACHINE_MAX_SECRETS_PER_MENTOR
Stored value ≥ 8 characters, and a masked-looking value (sk-****) is refused VIRTUAL_MACHINE_SECRET_VALUE_MIN_LENGTH
env_var matches ^[A-Za-z_][A-Za-z0-9_]*$ VIRTUAL_MACHINE_ENV_VAR_PATTERN

Every 400 comes back as { error } — either a plain message or { field: ["…"] }.

Related Exports

From @iblai/iblai-js/web-containers:

  • VirtualMachineAdminTab, VirtualMachineAdminTabProps — this surface.
  • HostPortChipInput, HostPortChipInputProps — the host:port chip input, reusable for any allowlist field.
  • VirtualMachineNetworkSection — the per-agent binding section (/iblai-vibe-agent-virtual-machine).

From @iblai/iblai-js/web-containers/next:

  • Account — the settings page hosting this as its Virtual Machine tab (targetTab="virtualMachine").

From @iblai/iblai-js/data-layer:

  • Policies: useListVirtualMachineNetworkPoliciesQuery, useLazyListVirtualMachineNetworkPoliciesQuery, useCreateVirtualMachineNetworkPolicyMutation, useUpdateVirtualMachineNetworkPolicyMutation, useDeleteVirtualMachineNetworkPolicyMutation
  • Secrets: useListVirtualMachineSecretsQuery, useLazyListVirtualMachineSecretsQuery, useCreateVirtualMachineSecretMutation, useUpdateVirtualMachineSecretMutation, useDeleteVirtualMachineSecretMutation
  • Credentials for the Value Source picker: useGetIntegrationCredentialsQuery
  • Helpers: validateHostPort, isValidHostPort, splitHostPortInput, normalizeHostPort, getVirtualMachineApiError, getVirtualMachineErrorStatus, extractBoundMentorIds
  • Constants: VIRTUAL_MACHINE_ENDPOINTS, VIRTUAL_MACHINE_PERMISSIONS, VIRTUAL_MACHINE_EGRESS_PROFILES, VIRTUAL_MACHINE_MAX_POLICY_HOSTS, VIRTUAL_MACHINE_MAX_SECRETS_PER_MENTOR, VIRTUAL_MACHINE_SECRET_VALUE_MIN_LENGTH, VIRTUAL_MACHINE_ENV_VAR_PATTERN, VIRTUAL_MACHINE_HOST_PORT_PATTERN, VIRTUAL_MACHINE_REJECTED_HOSTS, VIRTUAL_MACHINE_REJECTED_HOST_SUFFIXES
  • Types: VirtualMachineNetworkPolicy, VirtualMachineSecret, VirtualMachineApiError, VirtualMachineHostPortIssue

SDK source: packages/web-containers/src/components/profile/virtual-machine-admin/, components/virtual-machine/, and packages/data-layer/src/features/virtual-machine/.

Step 4: Verify

Run /iblai-vibe-ops-test before telling the user the work is ready:

  1. pnpm build -- must pass with zero errors
  2. pnpm test -- vitest must pass
  3. Start dev server and touch test:
    pnpm dev &
    npx playwright screenshot http://localhost:3000/settings/virtual-machine /tmp/org-vm.png
    

Important Notes

  • Redux store: Must include mentorReducer and mentorMiddleware — they register virtualMachineApiSlice, which these hooks live on.
  • initializeDataLayer(): 5 args (v1.2+)
  • @reduxjs/toolkit: Deduplicated via webpack aliases in next.config.ts
  • Peer deps: sonner and @iblai/iblai-web-mentor must be installed (pnpm add sonner @iblai/iblai-web-mentor)
  • Records are keyed in the body. PATCH and DELETE take id (policies) or env_var (secrets) in the request body, not in the path. These endpoints are newer than the pinned @iblai/iblai-api release, so the slice is hand-written.
  • A value is never returned. No endpoint hands back a secret's value, the table only shows its source, and the edit form starts blank. Never build UI that tries to display one.
  • env_var is immutable. Deleting and recreating is the rename path — and the delete unbinds the secret from every agent first.
  • Per-section 403. The two lists gate independently: an admin may see policies but not secrets. Both forbidden → one permission notice for the whole tab.
  • Deleting a policy an agent uses is refused, deliberately, so an agent on the Custom profile never points at a policy that vanished. Move those agents to another policy or profile first.
  • Scope is one organization. Policies and secrets are never shared across organizations.
  • Billing: VM lifetime is charged to the chatting user's credits — $1 per 10 minutes by default, prorated per second and overridable per organization. The agent-side section states this next to the controls.
  • Brand guidelines: BRAND.md