Skip to content

Examples

Beetroot ships a handful of starter beetroot.yaml files under the examples/ directory of the repository. They are documentation only — the CLI does not load or reference them. Each file is a hand-readable, copy-pasteable snippet you drop over a fresh beetroot.yaml when you want that configuration as your starting point.

beetroot create <name> always writes a minimal beetroot.yaml:

api_version: 8
android:
  version: 14

That's the full file. Every other field falls back to schema defaults (see the config reference). To start from a richer baseline, copy one of the examples below over the generated YAML and re-run beetroot apply <name>.

Available examples

default.yaml

The lightweight baseline — GMS is denylisted from Magisk root, but no additional stealth modules are installed.

examples/default.yaml
api_version: 8

android:
  version: 14

magisk:
  denylist:
    - com.google.android.gms
    - com.google.android.gms/com.google.android.gms.unstable

Use this when you're testing something that doesn't perform anti-root checks, or when you want the lightest-weight setup with sensible defaults.

Denylist entries are package[/process]

Each magisk.denylist entry is a package, optionally followed by a slash and a process that belongs to it (package/process). No slash means the process is the package itself. This shape matters because Magisk keys the denylist on (package_name, process): DroidGuard (Play Integrity) runs as the com.google.android.gms.unstable process of the com.google.android.gms package — it is not an installed package of its own. So the schema default enrols it as:

magisk:
  denylist:
    - com.google.android.gms
    - com.google.android.gms/com.google.android.gms.unstable  # DroidGuard process

Enrolling the bare com.google.android.gms.unstable as if it were a package matches no installed app, and vanilla (non-Shamiko) Magisk then never hides root in DroidGuard. See the magisk config reference.

stealth.yaml

A wider Magisk denylist suitable for use with a root-hider like Shamiko. Shamiko turns Magisk's denylist mode into a true allowlist-based hide — processes on the denylist can't detect Magisk at all. The denylist below covers all GMS variants and the Play Store.

examples/stealth.yaml
api_version: 8

android:
  version: 14

# To add a root-hider module, look up a current release URL (e.g. for
# Shamiko: https://github.com/LSPosed/LSPosed.github.io/releases) and
# fill the block below in. The sha256 is optional but recommended —
# beetroot will verify it on every stage.
#
# modules:
#   - url: https://github.com/.../<release>/<asset>.zip
#     sha256: <hex-digest>

magisk:
  denylist:
    - com.google.android.gms
    - com.google.android.gms/com.google.android.gms.unstable
    - com.google.android.gms/com.google.android.gms.persistent
    - com.android.vending

Pin the sha256

The modules: block is commented out by default because the upstream Shamiko release URL changes whenever LSPosed cuts a new tag — shipping a hard-coded URL here means this example goes stale silently the moment that release is retired. Pick a current release, paste its URL into url:, and (recommended) pre-compute the sha256 with curl -sL <url> | sha256sum so Beetroot can verify on every stage.

no-gapps.yaml

Same as default.yaml but with android.gapps: none. Use this if you want a stripped-down Android without Google Mobile Services — fewer running processes, smaller /data, no GMS-specific anti-emulator checks. Requires beetroot build none to have produced a matching base image.

examples/no-gapps.yaml
api_version: 8

android:
  version: 14
  gapps: none

with-frida.yaml

The baseline plus an explicit, version-pinned frida-server. Copy this over a freshly-generated beetroot.yaml whenever you want Frida on for that instance — the version pin must match your host-side frida-tools on major + minor. (Prefer version: auto, the default, to track your host frida-tools automatically; pin only when you need a reproducible server build. See the frida config reference.)

examples/with-frida.yaml
api_version: 8

android:
  version: 14

frida:
  version: "16.4.10"

magisk:
  denylist:
    - com.google.android.gms
    - com.google.android.gms/com.google.android.gms.unstable

Drop the frida: block (or copy examples/default.yaml) to turn Frida back off.

custom-ports.yaml

Demonstrates the generalized ports: list (issue #108): pin a well-known host port, and forward arbitrary in-guest services beyond adb/frida. See the ports config reference and the port allocation page for the resolution rules.

examples/custom-ports.yaml
api_version: 8

android:
  version: 14

ports:
  - {service: adb, guest: 5555, host: 9000}   # pin ADB to a stable host port
  - {service: frida, guest: 27042}            # host unset → stride default
  - {service: frida_control, guest: 27043}
  - {guest: 8080, host: 9090}                 # arbitrary service, explicit host
  - {service: metrics, guest: 9100}           # arbitrary, auto-allocated host

An entry whose host is unset auto-allocates — a stride base for a well-known service, or a dedicated extra-pool slot (40000 + index×10 + slot) for an arbitrary one.

adb-device.yaml

Documentation only — unlike the others, this file is not a copy-pasteable beetroot.yaml. adb-backed instances (created via beetroot adopt <serial>) have no instance directory and no beetroot.yaml; they're managed outside Beetroot (a real phone, a third-party emulator, or an adb connect-ed network device). The file documents the conceptual shape of the registry row beetroot adopt writes — the actual storage is JSON in $XDG_CONFIG_HOME/beetroot/instances.json under the InstanceMeta schema.

examples/adb-device.yaml (conceptual registry row)
name: phone

backend:
  kind: adb
  serial: emulator-5554   # passed verbatim to `adb -s <serial> ...`

index: 0
created_at: "2026-05-19T00:00:00+00:00"

Produce it with beetroot adopt emulator-5554 --name phone. adb-backed devices have no android:, frida:, modules:, magisk:, or resource blocks — manage Zygisk, the denylist, and modules via the Magisk app on the device itself.

vm.yaml

Runs redroid inside an emulated QEMU micro-VM that ships its own binder-enabled kernel — for hosts with no kernel binder driver (hardened CI, nomodule cloud sandboxes). Build the guest artifacts once with beetroot build --vm-kernel, then beetroot apply + beetroot up.

examples/vm.yaml
api_version: 8

binder: vm

vm:
  kernel: ~/.cache/beetroot/vm/bzImage
  rootfs: ~/.cache/beetroot/vm/rootdisk.img
  accel: auto
  smp: auto
  memory_mib: 8192

smp: auto pins -smp to the host's physical core count (HT siblings collapsed, capped by CPU affinity) — the measured optimum for the redroid boot (it scales with vCPUs up to the host core count, then regresses past it, so a logical-CPU count would oversubscribe on a hyperthreaded host). accel: auto prefers KVM when /dev/kvm is available (near-native) and falls back to TCG (software emulation, ~5–20× slower) otherwise. A slow first boot under TCG is expected, not a hang.

Using an example

beetroot create research-clean
cp examples/stealth.yaml research-clean/beetroot.yaml
beetroot apply research-clean
beetroot up research-clean

The examples/ directory is a sibling of docs/ in the Beetroot repo. If you installed via uv tool install and don't have a checkout handy, copy the YAML from this page directly into your instance's beetroot.yaml.

Modifying your config

Edit the instance's beetroot.yaml directly, then apply:

# Example: bump Frida version
vim "$(beetroot ls --json | jq -r .alpha.path)/beetroot.yaml"
# change frida.version to "16.5.0"

beetroot apply alpha
beetroot down alpha && beetroot up alpha

beetroot apply is idempotent. Run it after any YAML edit; it only re-downloads things that changed.

Writing your own starter config

There is no plugin or extension hook for adding new examples — they're just documentation. For a custom starting point, hand-write a beetroot.yaml in a new directory and adopt it:

mkdir my-custom-instance
cat > my-custom-instance/beetroot.yaml <<'YAML'
api_version: 8
android:
  version: 14
  gapps: none
display:
  width: 1080
  height: 1920
  fps: 30
YAML
beetroot register ./my-custom-instance --name my-custom
beetroot apply my-custom
beetroot up my-custom