@xenon-device-management/xenon
v1.7.0
Published
Xenon - Intelligent Mobile Infrastructure. A self-healing device orchestration platform for Appium.
Downloads
484
Readme
Xenon
✨ What is Xenon?
Xenon is an intelligent Appium plugin that transforms your mobile device lab into a self-healing, autonomous infrastructure. Named after the noble gas known for its stability and reliability, Xenon brings enterprise-grade device orchestration to your testing pipeline.
Why Xenon?
| Problem | Xenon Solution | |---------|----------------| | Tests fail due to device state | Auto-recovery - Devices heal themselves | | Manual device management | Smart allocation - Queue, reserve, prioritize | | Debugging is painful | Interactive control - Live stream, touch, shell | | No visibility into failures | Rich artifacts - Video, screenshots, profiling | | Infrastructure silos | Unified dashboard - One view for all devices |
🚀 Features
Device Orchestration
- ✅ Automatic device discovery - Android (USB + emulators), iOS (devices + simulators)
- ✅ Smart session allocation - Queue management with ETA
- ✅ WebSocket-First Sync - Real-time Hub-Node-Dashboard bidirectional sync
- ✅ Device reservation - Manual mode for debugging
- ✅ Team-based quotas - Fair resource sharing
Interactive Control
- ✅ Live streaming - Real-time device screen in browser
- ✅ Touch interaction - Tap, swipe, scroll remotely
- ✅ App management - Install, uninstall, clear data
- ✅ Interactive Shell - Execute ADB/iOS commands directly
- ✅ Device information - Battery, storage, network status
🧠 AI Self-Healing (Flagship)
- ✅ 5-Tier Healing Orchestration - From DOM to LLM recovery
- ✅ Signature-Based Learning - Persistent "Etalon" signatures for high-confidence recovery
- ✅ Multi-Modal Fallback - Syntactic -> OCR -> Visual AI -> LLM reasoning
- ✅ Infrastructure-Free - Works with existing LokiJS (local) or PostgreSQL (remote)
Selector lifecycle (Trust & Truth layer)
Healed selectors flow through a state machine: Active → Pending → Resolved, with an optional Muted branch.
- Active — a hot selector that's healing in flight; surfaces on the Selector Health dashboard, the CI gate, and the webhook digest.
- Mark as Fixed — after rewriting the selector in your test source, click "Mark as Fixed" in the dashboard. The row moves to Pending.
- Pending — Xenon watches subsequent CI builds. When 3 distinct
build_ids have run the selector with no heals, it auto-promotes to Resolved (SelectorVerificationJobruns every 15 minutes). - Resolved — the rewrite stuck. Excluded from the CI gate and digest. A future heal flips the row back to Active with a regression badge (institutional memory).
- Muted — a selector you've intentionally chosen to ignore (legacy flow, etc.). Hidden from dashboard, CI gate, and digest until unmuted.
The dashboard shows strategy + value (Accessibility ID: login-btn) so suggested rewrites are copy-ready in JS / Java / Python / C# / Ruby — your client language is remembered in localStorage.xenon.copyLang.
CI gate behavior change: muted/pending/resolved selectors no longer count toward
/healing/hotspots/violations. If your CI was passing/failing based on that endpoint, the signal will get quieter after this release — selectors actively being managed are no longer flagged. Pass?status=allto opt back into the old behavior.
Recording & Artifacts
- ✅ Video recording - Full session capture
- ✅ Screenshot capture - On-demand and per-command
- ✅ Network interceptor - Live HTTP/HTTPS capture, mocking, and HAR export (docs)
- ✅ Distributed Tracing - OpenTelemetry spans for exact command latency
- ✅ Performance profiling - CPU, memory, FPS metrics
- ✅ Log aggregation - Appium, device, app logs
- ✅ OpenTelemetry Integration - Standardized distributed tracing for all sessions
Intelligence (Roadmap)
- 🔲 Flaky test detection - Auto-identify unstable tests
- 🔲 Error categorization - Crash vs timeout vs element not found
- 🔲 Predictive health - USB/battery failure prediction
⚡ Quick Start
Installation
# Install Xenon plugin
appium plugin install --source=npm @xenon-device-management/xenon
# Or install from source
git clone https://github.com/xenon-platform/xenon.git
cd xenon
npm install
npm run build:all
appium plugin install --source=local .Running
# Start Appium with Xenon
appium server --use-plugins=xenon \
--plugin-xenon-platform=both \
--plugin-xenon-enable-dashboard🔧 Configuration
Xenon supports configuration via CLI arguments or a configuration file (YAML/JSON). We recommend using a configuration file for production deployments.
Using Configuration File (Recommended)
Create a xenon-config.yaml file:
server:
usePlugins: ["xenon"]
plugin:
xenon:
platform: both
maxSessions: 8
enableDashboard: true
enableSelfHealing: trueRun Appium with the config:
appium server --config xenon-config.yamlRuntime Configuration ⚡️
You can update configuration options at runtime without restarting the server using the API:
# Get current config
GET /xenon/api/config
# Update config (e.g. change max sessions)
PUT /xenon/api/config
{ "maxSessions": 10 }Note: Some changes (like
platformorhubURL) require a server restart to take full effect. The API response will indicate if a restart is required.
Build & Session Retention 🧹
Xenon includes an enterprise-ready cleanup job that automatically purges older builds, sessions, and associated assets (videos/screenshots) to manage disk space.
| Option | Description | Default |
|--------|-------------|---------|
| buildCleanupDays | Retention period in days | 30 |
| buildCleanupMaxCount | Maximum number of builds to keep | 100 |
| buildCleanupSchedule | Cron schedule for the cleanup job | "0 0 * * *" |
| deleteBuildAssets | Delete video recordings and screenshots from disk | true |
Example (YAML):
plugin:
xenon:
buildCleanupDays: 14
buildCleanupMaxCount: 50
buildCleanupSchedule: "0 0 * * *"
deleteBuildAssets: trueDetailed explanation of how the retention logic works can be found in the Data Retention & Maintenance Guide.
See docs/server-args.md for all available options.
📋 Capabilities
Xenon uses the xe: prefix for its custom capabilities. You can also use xenon: as an alternative.
Session & Build Tracking
| Capability | Description | Example |
|------------|-------------|---------|
| xe:build | Build name for grouping sessions | "xe:build": "Release-v2.0" |
| xe:name | Session name for identification | "xe:name": "Login Test Suite" |
Recording & Screenshots
| Capability | Description | Default |
|------------|-------------|---------|
| xe:record_video | Enable video recording | true |
| xe:screenshot_on_failure | Capture screenshot on test failure | true |
| xe:screenshot_on_every_command | Capture screenshot after each command | false |
| xe:save_device_logs | Save device logs (logcat/syslog) | false |
Device Filtering
| Capability | Description | Example |
|------------|-------------|---------|
| appium:udids | Comma-separated list of allowed UDIDs | "device1,device2" |
| appium:minSDK | Minimum OS version | "15" |
| appium:maxSDK | Maximum OS version | "17" |
| appium:iPhoneOnly | Use only iPhone simulators | true |
| appium:iPadOnly | Use only iPad simulators | true |
| appium:filterByHost | Filter by node IP address | "192.168.0.100" |
Timeouts
| Capability | Description | Default |
|------------|-------------|---------|
| appium:deviceAvailabilityTimeout | Wait time for device availability (ms) | 180000 |
| appium:deviceRetryInterval | Polling interval for device check (ms) | 10000 |
Example Configuration
const capabilities = {
platformName: 'iOS',
'appium:automationName': 'XCUITest',
'appium:app': '/path/to/app.ipa',
// Xenon capabilities
'xe:build': 'Sprint-42',
'xe:name': 'Login Flow Test',
'xe:record_video': true,
'xe:screenshot_on_failure': true,
'xe:save_device_logs': true,
// Device filtering
'appium:minSDK': '16',
'appium:iPhoneOnly': true
};Custom Execute Script Commands
Xenon supports extended control and reporting via the xenon: execute script namespace. These commands allow you to interact with the Xenon dashboard and session management directly from your test code.
| Command | Description | Example |
|---------|-------------|---------|
| xenon: setSessionStatus | Mark session as passed/failed in dashboard | {"status": "passed", "reason": "All steps OK"} |
| xenon: setSessionName | Update session name at runtime | {"name": "Step 2: Payment Verification"} |
| xenon: captureEvidence | Trigger manual screenshot with custom label | {"reason": "Checkpoint reached", "label": "success"} |
| xenon: addTag | Add searchable tags to the session | {"tag": "regression"} |
| xenon: debug | Send custom debug logs to Xenon dashboard | {"message": "API Response: 200 OK"} |
Full reference for these commands is in the Swagger UI at /xenon/api-docs.
🧠 AI Self-Healing
Xenon features a best-in-class, 5-tier self-healing system that ensures your tests never fail due to minor UI changes. It automatically intercepts NoSuchElementError and attempts to recover the locator using increasingly advanced methods.
🛡️ The 5-Tier Strategy
| Tier | Provider | Mechanism | Stability |
|:---|:---|:---|:---|
| 1 | Native | Standard Appium findElement | Baseline |
| 2 | Fuzzy XML| Weighted Signature Matching (Dice Coefficient) | 85%+ |
| 3 | OCR | Local Text Recognition (Tesseract.js) | High |
| 4 | Visual AI| AI-powered coordinate discovery | High |
| 5 | LLM | Deep Reasoning (Gemini/OpenAI) | Absolute |
⚡ Signature-Based Learning (Etalon)
Xenon "learns" during every successful run. When an element is found, it captures a persistent Element Signature (Etalon).
- Zero Configuration: Learning is fully automatic and backgrounded.
- Persistent Memory: Signatures are stored in your database (LokiJS or PostgreSQL).
- Extreme Precision: Even if
id,text, orclasschanges, Xenon uses anchor attributes (content-desc,resource-id) from its memory to find the match with industrial-grade confidence.
🎛️ Control & Transparency
Xenon provides full visibility and control over its self-healing system:
- Global Toggle: Enable or disable healing via CLI:
appium server --use-plugins=xenon --plugin-xenon-enable-self-healing=true - Live Configuration: Toggle self-healing directly from the Xenon Dashboard Settings at runtime without restarting the server.
- Audit Logs: Every healing event is recorded in the session command history. You can see:
- Original Selector: The locator that failed.
- Recovered Selector: The replacement locator found by Xenon.
- Confidence Score: The mathematical match probability (0-1.0).
- Healing Tier: Which tier (Fuzzy XML, OCR, etc.) performed the recovery.
📖 API Documentation
Xenon provides a comprehensive REST API for device management, session control, and more.
Swagger UI
Access interactive API documentation at:
http://localhost:4723/xenon/api-docsOpenAPI Spec
Get the raw OpenAPI specification:
http://localhost:4723/xenon/api-docs.jsonAPI Categories
| Category | Base Path | Description |
|----------|-----------|-------------|
| Devices | /xenon/api/devices | Device discovery and management |
| Sessions | /xenon/api/session | Session management and logs |
| Builds | /xenon/api/build | Build and test execution tracking |
| Control | /xenon/api/control | Interactive device control |
| Reservations | /xenon/api/reservation | Device reservation for exclusive use |
| Applications | /xenon/api/apps | App repository and installation |
| Webhooks | /xenon/api/webhook | Notification webhook configuration |
Key Endpoints
Devices
# Get all devices
GET /xenon/api/devices
# Get device by platform
GET /xenon/api/device/{platform}
# Block/Unblock device
POST /xenon/api/device/{udid}/block
POST /xenon/api/device/{udid}/unblockControl API
# Take screenshot
GET /xenon/api/control/{udid}/screenshot
# Tap at coordinates
POST /xenon/api/control/{udid}/tap
{ "x": 100, "y": 200 }
# Swipe gesture
POST /xenon/api/control/{udid}/swipe
{ "x": 100, "y": 500, "endX": 100, "endY": 100, "duration": 1000 }
# Type text
POST /xenon/api/control/{udid}/text
{ "text": "Hello World" }
# Execute shell command (Android)
POST /xenon/api/control/{udid}/shell
{ "command": "pm list packages" }
# Live stream
GET /xenon/api/control/{udid}/streamReservations
# Reserve a device
POST /xenon/api/reservation
{ "udid": "...", "host": "...", "reservedBy": "John", "duration": "2h" }
# Release reservation
DELETE /xenon/api/reservation/{udid}/{host}
# Extend reservation
POST /xenon/api/reservation/{udid}/{host}/extend
{ "duration": "1h" }🎨 Dashboard
Access the dashboard at http://localhost:4723/xenon/
Views
| View | Description | |------|-------------| | Devices | Real-time device grid with status indicators | | Sessions | Active and historical session management | | Builds | Test runs grouped by build identifier | | Control | Interactive device control interface |
📚 Documentation
The full documentation is available at: https://xenon-docs.vercel.app/
Quick Links
- Server arguments & env vars
- Node provisioning — pair-auth credentials for hub-node deployments
- Teams & device access
- Data retention & cleanup
- API reference: live Swagger at
/xenon/api-docs
🏗️ Development
# Clone and install
git clone https://github.com/xenon-platform/xenon.git
cd xenon
npm install
# Build everything (Plugin + Dashboard)
npm run build:all
# High-velocity development loop
# (Auto-rebuilds and restarts Appium server)
npm run dev
# Run tests
npm run test:all # Unit tests
npm run test:android # Android integration
npm run test:ios # iOS integration🔐 Authentication
All /xenon/api/* endpoints are authenticated. Xenon supports three shapes — pick whichever matches your caller.
Identity model
Xenon ships an enterprise identity stack: users with roles (SUPER_ADMIN / ADMIN / MEMBER), teams that scope which devices a user can reach, and API tokens minted per-user with their own scope set. The dashboard, programmatic clients, and hub-node channel all flow through the same identity.
Auth shapes
| Shape | Header(s) | When to use |
|---|---|---|
| Cookie session | Cookie: xenon_dashboard_session=… | Dashboard browser sessions. Set by POST /api/auth/login with {email, password}. |
| Pair auth | X-Xenon-Access-Key + X-Xenon-Token | Programmatic clients (CI, SDK, hub→node). Each user has one access key (rotatable) and any number of scoped tokens. |
| Auth disabled | (none) | Local dev only. Set --plugin-xenon-auth-disabled (or XENON_AUTH_DISABLED=true). A WARN logs every 60 s. |
First-run bootstrap
On first start Xenon creates a SUPER_ADMIN user from these env vars (defaults [email protected] / Admin@123):
export XENON_BOOTSTRAP_ADMIN_EMAIL="[email protected]"
export XENON_BOOTSTRAP_ADMIN_PASSWORD="..." # change meSign in at https://<host>/xenon/ with these credentials. From /profile you can mint API tokens and rotate your access key. For CI use, programmatically POST /api/auth/login to get the cookie, then POST /api/profile/tokens to mint a scoped token.
Generating a programmatic token
# 1. Get your access key + a fresh token from /profile in the dashboard, or:
curl -s -X POST -b "xenon_dashboard_session=$COOKIE" \
-H 'Content-Type: application/json' \
-d '{"name":"ci","scopes":["sessions","read"]}' \
http://localhost:4723/xenon/api/profile/tokens
# 2. Use it on every subsequent call:
curl -H "X-Xenon-Access-Key: xen_..." -H "X-Xenon-Token: ..." \
http://localhost:4723/xenon/api/devicesScopes
Tokens carry one or more scopes; the user's role controls which scopes they can grant.
| Scope | Access |
|-------|--------|
| read | GET sessions, devices, logs, apps |
| sessions | Create/delete sessions and reservations |
| devices | Block/unblock devices, install apps, hub-node /register and /unblock |
| admin | User / team / API-key management, webhooks |
Teams (device access control)
Scopes govern which verbs a token can call; teams govern which devices it can reach. A user bound to a team sees the team's devices plus the shared pool (teamId = null). admin-scope tokens bypass team filtering.
Test clients pass the access key via the xenon:accessKey capability:
const caps = {
platformName: 'iOS',
'appium:automationName': 'XCUITest',
'xenon:accessKey': process.env.XENON_CI_KEY, // user with team membership
// optional: 'xenon:team': '<team-id>' to pin allocation (admins only for cross-team)
};See docs/teams.md for creating teams, assigning devices, and the full error taxonomy.
Hub-node channel
Hub and node authenticate using the same pair-auth shape. Provision a User on the hub for each node, mint a devices-scoped token, and set both env vars on the node:
export XENON_HUB_ACCESS_KEY="xen_..."
export XENON_HUB_TOKEN="..."Both REST /register calls and the Socket.io handshake will use this pair. See docs/node-provisioning.md for the full provisioning + recovery flow.
🌱 Environment Variables
Xenon reads these env vars in addition to the CLI flags. Prefer env vars for credentials so keys don't end up in shell history or config files.
| Variable | Purpose |
|----------|---------|
| XENON_AI_PROVIDER | AI backend: gemini, openai, anthropic, or ollama. Same as --plugin-xenon-aiProvider. |
| XENON_AI_MODEL | Override the default model for the selected provider. |
| XENON_AI_BASE_URL | Custom base URL (local Ollama, OpenAI-compatible gateway). |
| XENON_GEMINI_API_KEY / GEMINI_API_KEY | Gemini credentials. XENON_-prefixed form wins if both set. |
| XENON_OPENAI_API_KEY / OPENAI_API_KEY | OpenAI credentials. |
| XENON_ANTHROPIC_API_KEY / ANTHROPIC_API_KEY | Anthropic credentials. |
| XENON_OPENAI_MODEL | Alternate way to set the OpenAI model. |
| XENON_OTEL_DEBUG | When true, OpenTelemetry adds a ConsoleSpanExporter so every span is logged. Dev/tracing only. |
| XENON_DB_PROVIDER | sqlite or postgresql. Same as --plugin-xenon-databaseProvider. |
| DATABASE_URL | Prisma database URL. Falls back to file:~/.cache/xenon/xenon.db. |
| XENON_HUB_ACCESS_KEY | Node→hub outbound: access key the node sends in X-Xenon-Access-Key. Required alongside XENON_HUB_TOKEN. See docs/node-provisioning.md. |
| XENON_HUB_TOKEN | Node→hub outbound: token the node sends in X-Xenon-Token. Required alongside XENON_HUB_ACCESS_KEY. |
| XENON_BOOTSTRAP_ADMIN_EMAIL / XENON_BOOTSTRAP_ADMIN_PASSWORD | First-run super-admin user, created on first hub boot. Defaults [email protected] / Admin@123. Change in any non-throwaway environment. |
| XENON_AUTH_DISABLED | true to disable all auth. Local dev only. |
| XENON_AUTO_MIGRATE | When true (default), the hub auto-applies pending schema changes at startup (prisma db push for SQLite, prisma migrate deploy for PostgreSQL). Set false if you manage migrations externally via CI for auditable change-control. |
See docs/server-args.md for the full CLI-flag reference and how these variables interact with config files.
🤝 Contributing
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
Contributors
📜 License
ISC License - See LICENSE for details.
