English | Español
This guide explains how to add a VM profile and how to expose agent tools for that profile using the current project architecture. It is not an end-user manual.
There are two separate contracts:
- VM profile: lives in
vm/profiles/<id>.json. It defines the Alpine image, packages, build/boot commands, recommended RAM, andallowedTools. - Tool: lives in
src/browser/chat/tools/definitions/*.ts. It defines the AI SDK schema, argument normalization, command construction, required packages, risk, timeout, and result formatting.
The connection between them is:
- A profile exposes a tool by listing it in
allowedTools. - A tool declares
requiredPackages. scripts/check/vm-profiles.mjsvalidates that tools exist and that the profile includes their required packages.- At runtime,
tool-registry.tsfilters out tools that the active profile cannot support.
Field definitions, validation rules, and required properties for vm/profiles/<id>.json are documented in the VM profile schema reference (generated from vm/profiles/profile.schema.json via npm run docs:schemas).
-
Create
vm/profiles/<id>.json.Start from the closest existing profile:
alpine-base.json: minimal profile.alpine-pentest-lite.json: lightweight tools and wordlists.alpine-pentest-web.json: extra web tools, extra repositories, and richer build commands.
-
Keep
idand filename aligned.If
idisalpine-demo, the file must bevm/profiles/alpine-demo.json. The schema accepts lowercase ids with numbers, dots, and hyphens. -
Declare the structural fields.
Common fields:
{ "$schema": "./profile.schema.json", "id": "alpine-demo", "name": "Alpine Demo", "description": "Example Alpine profile.", "alpineVersion": "3.23.4", "recommendedRamMb": 1024 }The builder derives the initramfs output from
id, for examplev86/images/profiles/alpine-demo-initramfs.gz. The kernel defaults to the shared file for the effective Alpine branch; setkernelOutputonly when a profile needs a custom kernel path.defaultDiskis optional and defaults toinitramfs. -
Declare
packages.Every profile must include
python3, because the guestserial1andserial2runners depend on Python 3. Also add the packages required by your commands and tools."packages": [ "ca-certificates", "curl", "nano", "python3", "iproute2" ]
-
Declare
allowedTools.This list is the profile policy. Only include tools that make sense for that image. Order is preserved and used as the default priority when the UI or model limits the number of visible tools.
"allowedTools": [ "vm.fs.list", "vm.fs.read", "vm.cmd.which", "web.curl.head", "net.ip.status" ]
-
Use
buildCommandsandfirstBootCommandsdeliberately.buildCommands: run during image generation against/rootfs. Use them for symlinks, small wordlist downloads, cache cleanup, or file preparation.firstBootCommands: written to/etc/browser-agent-firstboot.shand run when the VM boots.
If a check must fail image generation, put it in
buildCommands. If it must run once when the VM boots, put it infirstBootCommands. If it proves a tool's real availability and must appear in Run checks, declare it in that tool'sruntimeChecks.Example:
"firstBootCommands": [ "update-ca-certificates >/tmp/update-ca-certificates.log 2>&1 || true" ], "buildCommands": [ "rm -rf /rootfs/var/cache/apk/* /rootfs/tmp/* /rootfs/var/tmp/*" ]
-
Use
extraRepositoriesonly when necessary.If a tool is not available in the main Alpine branch for
x86, add extra repositories and leave a note explaining why.alpine-pentest-webis the current example. -
Validate the profile.
npm run check
This checks schema, duplicate ids,
python3, unknownallowedTools, and missingrequiredPackages. See the schema reference for per-field details. -
Generate the profile assets.
Use
npm run setupas the normal path. It validates all profiles, prepares base assets, generates profile images, updatespublic/v86/images/profiles/index.json, and creates local HDA disks.npm run setup
Command to generate one profile:
node scripts/setup/vm-profile-image.mjs vm/profiles/alpine-demo.json
Replace
alpine-demo.jsonwith the real file. That command generates the profile initramfs and updatespublic/v86/images/profiles/<id>.jsonandindex.json, but it does not create HDA disks or validate the other profiles. Do not edit those manifests by hand; they are regenerated fromvm/profiles/*.json.
-
Create a module in
src/browser/chat/tools/definitions/.The file must export
toolDefinitiontyped asToolDefinition. The build discovers these files and generates the virtualvirtual:ba-toolsmodule; there is no manual index to edit. -
Use a stable name.
Names follow the
area.name.actionstyle, for example:vm.fs.readweb.curl.headnet.nmap.quickweb.nikto.quick
-
Declare the package contract.
If the tool needs an Alpine binary or runtime, declare
requiredPackageswith APK package names. Any profile adding that tool toallowedToolsmust include those packages inpackages. -
Declare runtime availability checks.
If the tool needs concrete commands, add
runtimeCheckswith short labels and minimal commands such ascommand -v curl,command -v nikto.pl, or anhttpxbinary-name fallback. The Run checks panel gets these checks from the registry according toallowedTools; do not add package maps to the UI. -
Normalize arguments and build bounded commands.
Use existing helpers when they fit:
normalizeUrl,normalizeHost,normalizeBool,textValue,toToolArgs.clampIntfor numeric limits.shellQuotefor every value interpolated into shell.captureCommandto wrap commands and detect missing binaries.standardFormat,cleanToolOutput,truncateToolOutput, ortoolFailureDetailfor output formatting.
-
Add AI SDK schema and i18n.
If the tool is exposed to the model, define
buildInputSchema(z)and localized strings insrc/web/locales/en.jsonandsrc/web/locales/es.jsonfor name, description, schema text, and errors. -
Set risk and limits.
riskLevel: 1: bounded reads.riskLevel: 2: low-impact diagnostics.riskLevel: 3: active actions such as commands or light scans.timeoutMsandmaxOutputBytesmust be explicit and conservative.
-
Expose the tool in a profile.
Add the tool name to the profile's
allowedToolsand the required packages topackages. If the tool depends on a specific executable name that differs from the package name, keep these aligned:- Profile
buildCommandsorfirstBootCommands. runtimeChecksin the tool definition when that availability should appear in Run checks.- Tests if the contract is delicate.
Current example:
web.nikto.quickdeclaresrequiredPackagesfor Nikto and the Perl SSL modules, but runsnikto.plthroughtimeout. Thealpine-pentest-webprofile creates aniktosymlink for manual use and the tool validates availability withruntimeChecks. - Profile
After adding or changing profiles/tools:
npm run checkIf you changed profiles, the overlay, or runners:
npm run setupIf you changed tool code, the LLM provider, i18n catalogs, or frontend code:
npm run buildFor a complete local environment:
npm run prepare:local- The profile filename matches its
id. - The profile includes
python3. allowedToolscontains only existing tools.- Every exposed tool has its
requiredPackagesinpackages. - Commands use quoting and limits.
- Outputs have timeout and maximum size.
- The tool has i18n text if it is shown to the user/model.
npm run checkpasses.- After profile changes, the VM boots and Run checks does not report missing packages/tools.