Install
$ agentstack add skill-meta-quest-agentic-tools-portal Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Pipes remote content directly into a shell (remote code execution).
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Portal
This skill is for building Android apps that target Meta's Portal device family. Portal devices are discontinued (sales stopped end of 2022), but ADB is now enabled, so owners can sideload their own apps.
The hardware: Snapdragon-based Android tablets and TV sticks running a modified AOSP without Google Mobile Services. Several models, all touch or TV. minSdkVersion 28 (Android 9) or 29 (Android 10) depending on device.
This skill pairs with metavr (Meta VR CLI) — install it first. Use metavr adb in place of raw adb everywhere. See resources/hzdb.md for the one-line install (via npx), the MCP-into-your-editor setup, and the Portal-relevant command surface. The full metavr-cli skill ships in the same repo and can also be loaded for deeper reference.
Hard constraints — read before writing any code
If you only remember a few things, remember these. Each is a class of bug Portal apps hit constantly.
- No Google Mobile Services. No Play Services, no Firebase, no FCM, no Play Billing, no Google Sign-In, no Google Maps SDK, no AdMob, no ML Kit. Apps with hard GMS deps will crash on launch. Pick non-GMS alternatives — see
resources/app-requirements.md. minSdkVersion ≤ 28is required (Portal hardware tops out at API 29). For new apps,targetSdkVersion 29is the safest default. For porting existing apps,targetSdkVersionhigher than 29 usually works fine — verified empirically withtargetSdk = 36. Don't waste time downgrading the target SDK of an existing app unless you observe a concrete runtime issue.- Launcher intent-filter is required. Touch devices need
MAIN + LAUNCHER; Portal TV needsMAIN + LEANBACK_LAUNCHER. TheDEFAULTcategory is not required (verified empirically on Portal — apps with onlyMAIN + LAUNCHERappear on the home tile grid). Without one of these, the app installs but never appears on the home screen. - App icon must include a PNG in
mipmap-xxxhdpi/as a fallback. Declareandroid:icon(touch) orandroid:banner(TV) on the launcher activity. You can also ship adaptive icons (mipmap-anydpi-v26/) and other density PNGs alongside — Portal's launcher correctly falls back to themipmap-xxxhdpiPNG when the adaptive XML can't be rendered. Apps with only adaptive icons (no PNG fallback) will not have a visible icon on Portal. - No contacts API. No account/credentials API.
READ_CONTACTSis denied. The account provider returns nothing.
5a. Basic mic capture works; the far-field / beamformed mic array does not. Standard RECORD_AUDIO opens an AudioRecord stream and delivers real audio from handset-mic (the single-channel mic). The far-field beamformed array used by "Hey Portal" wake-word is gated by a Meta-signed native permission (com.facebook.alohasdk.permission.RECORD_AUDIO_PRIVILEGED) and is not available to sideloaded apps. So basic voice features work; sideloaded wake-word detection and high-quality room-distance pickup do not. See resources/app-requirements.md § Microphone capture for details.
- Touch UI for tabletop, not phone form factor. Portal sits on a counter or stand. Users interact from 50–100 cm. Hit targets ≥ 64 dp (96 dp for primary actions), body text ≥ 16 sp (18 sp on Portal+), landscape-first. Full Portal design system (typography, spacing, palette, WCAG ratios, TalkBack rules) is in
resources/design-guidelines.md; for Jetpack Compose apps,resources/compose-theme.mdis a copy-paste theme starter that bakes these rules intoColor.kt/Theme.kt/Type.kt. - Reserve the top ~64 dp (only if your top content sits within 64 dp of the canvas edge). Portal has a persistent system overlay strip at the top: back / home buttons (top-left) and Wi-Fi / status (top-right). It floats above app content with no automatic safe-area inset. Apps whose top UI hugs the edge (edge-to-edge toolbars, sticky headers, full-bleed modals) will tuck under it. Apps whose top content naturally sits ≥80 dp below the canvas edge don't need any change. The overlay pills are white, so apps with a light background in the top region need an additional dark scrim even after inset — see
resources/app-requirements.md§ Top system overlay.
Device matrix
| Device | minSdkVersion | Connection | |---|---|---| | Portal (1st and 2nd gen) | 28 / 29 | USB-C (back) | | Portal Mini | 29 | USB-C (back) | | Portal+ (1st and 2nd gen) | 28 / 29 | USB-C (back) | | Portal Go | 29 | USB-C (under rubber cover on back) | | Portal TV | 29 | USB-C |
Set minSdkVersion 28 if you want to cover everything. If you don't need to support 1st-gen Portal / Portal+, you can target 29.
Quickstart
Toolchain first — don't hand-hunt for it. Building needs two host-machine pieces: a JDK (Gradle/AGP run on it) and the Android SDK. Install the SDK with Google's android CLI — don't go scavenging the filesystem for an SDK. For the JDK, point JAVA_HOME at Android Studio's bundled JBR if Android Studio is installed, otherwise install Temurin 17. The android CLI installs the SDK only — it does not provide a JDK. Full walkthrough: resources/android-sdk-setup.md.
# 1) Get a JDK 17 (one-time, host machine — Gradle / AGP run on it; the `android` CLI does NOT install one)
# If Android Studio is installed, reuse its bundled JBR (no install needed):
# export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
# Otherwise install Temurin 17:
# brew install --cask temurin@17 && export JAVA_HOME="$(/usr/libexec/java_home -v 17)"
java -version # should report 17.x (or 21.x if using Android Studio JBR)
# 2) Install Google's `android` CLI (it manages the SDK), then install the SDK packages
# macOS: brew tap android/tap && brew install android-cli
# Any OS: curl -fsSL https://dl.google.com/android/cli/latest/darwin_arm64/install.sh | bash (see § 1 for other OSes)
# Windows: winget install --id Google.AndroidCLI
android update # keep the CLI current
# Install the SDK. For a new project: API 28 + 29. For porting, also install whatever compileSdk needs (often 35/36).
android sdk install platforms/android-28 platforms/android-29 platform-tools build-tools/34.0.0
export ANDROID_HOME="$HOME/Library/Android/sdk" # macOS — Linux uses ~/Android/Sdk
# 3) Install metavr (one-time, host machine — requires Node.js 20+)
# See resources/hzdb.md for full details and MCP-into-your-editor setup.
npx -y metavr --version
# (or install globally)
npm install -g @meta-quest/metavr
# 4) Enable ADB on the Portal
# Portal: Settings → Debug → ADB Enabled. Enter PIN if prompted.
# Connect USB-C. Tap "Allow" on the device the first time you connect.
# 5) Verify
metavr device list
# Should list one Portal device. Example: 819PGF02P010SL23 device Portal aloha
# (or npx -y metavr device list)
# 6) Build + install + launch
# No ./gradlew in the project? Bootstrap the wrapper first — see resources/android-sdk-setup.md § 0a.
./gradlew assembleDebug
metavr app install -r app/build/outputs/apk/debug/app-debug.apk # -r/--replace reinstalls, keeping data
metavr app launch com.example.myapp # or: metavr adb shell am start -n com.example.myapp/.MainActivity
# (or use npx -y metavr instead of metavr if not globally installed)
If the device is missing from metavr device list, tap ADB Enabled on the Portal again — the toggle can race the USB connect.
Build configuration
app/build.gradle.kts:
android {
compileSdk = 35
defaultConfig {
minSdk = 28
targetSdk = 29
}
}
compileSdk = 35 (or whatever's latest) is fine. The min/target are what matters for Portal compatibility.
Manifest
The launcher entry varies by device family.
Touch devices (Portal, Portal Mini, Portal+, Portal Go):
Portal TV (use LEANBACK_LAUNCHER and android:banner in place of android:icon):
Without these, the app installs but is invisible. To support both families from one APK, declare both intent filters on the same activity.
Permissions that work / don't work
| Capability | Status | |---|---| | Camera | Regular CAMERA permission | | Microphone | Regular RECORD_AUDIO permission | | Speaker | No permission needed | | Bluetooth | Regular BLUETOOTH* permissions | | Network | Regular INTERNET / ACCESS_NETWORK_STATE | | Touch / keyboard input | No permission needed | | Storage write | Regular WRITE_EXTERNAL_STORAGE (Android 9 model) | | Storage delete (cross-app) | App-owned only. Otherwise: metavr adb shell rm, or install a file-manager app | | Contacts (READ_CONTACTS) | Not available. Denied at runtime | | Device accounts (AccountManager) | Not available. Account provider returns nothing |
Smart Camera SDK (binary pending)
Portal's camera is driven by a system Smart Camera service that owns face/body tracking, framing, and auto-pan-zoom to keep people in frame. Apps do not drive the camera directly with Camera2 to get that behavior — they request a session from the Smart Camera service and pass a ModeSpec (auto-frame, desk framing, meeting framing, fixed crop, etc.).
A standalone Smart Camera SDK is in development. Planned Gradle coordinate: com.facebook.portal:smartcamera:1.1.+. Until the binary ships, see resources/smart-camera-sdk.md for the API sketch — same shape, same ModeSpec modes, same SmartCameraControlConnectionFactory entry point.
Raw video frames are still available via the standard Camera2 API; the Smart Camera SDK is for controlling the framing, not the pixels.
Debug loop
metavr adb logcat # full logcat
metavr adb logcat *:E # errors only
metavr adb logcat -s AndroidRuntime DEBUG libc # crash signals
metavr log -c # clear the log buffer (NOT `metavr adb logcat -c` — that flag is rejected)
metavr adb shell dumpsys activity activities # what's running
metavr app clear com.example.myapp # wipe app data (or: metavr adb shell pm clear )
metavr app uninstall com.example.myapp # uninstall
metavr capture screenshot -o screen.png # save a PNG of the screen
See resources/debugging.md for more patterns and common failure modes (icon missing, app invisible after install, app crashes on first launch, etc.).
Resources
resources/hzdb.md— what metavr is, one-line install, MCP-into-your-editor, Portal-relevant commandsresources/device-setup.md— full device prep walkthrough for a human userresources/android-sdk-setup.md— install JDK 17, Android CLI, SDK platforms / build-toolsresources/native-toolchain.md— NDK / CMake / Ninja setup (use this when the project has native code; covers the deep-validation contract becausesource.propertiesalone isn't enough)resources/app-requirements.md— manifest, icons, no-GMS, design checklist (deep)resources/porting-existing-apps.md— playbook for taking an existing Android app and getting it onto Portal (no-GMS flavor, native code, common failures)resources/design-guidelines.md— typography, spacing, color, accessibility, TV / D-pad, Smart Camera UXresources/compose-theme.md— copy-paste Jetpack Compose theme starter (dark-forced theme, Portal palette, bundled-Inter typography, hit targets) with the no-GMS font fixresources/smart-camera-sdk.md— Smart Camera API surface (binary pending)resources/debugging.md—metavr adblogcat / screenshot / dumpsys patternsresources/sample-prompts.md— starter prompts to feed to Claude / Cursor / etc.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: meta-quest
- Source: meta-quest/agentic-tools
- License: Apache-2.0
- Homepage: https://developers.meta.com/horizon
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.