DEV Community

Jun
Jun

Posted on

How I Created a Live Online Demo for A GitHub Repo in 5 Minutes

The “Last Mile” Problem for Open Source Projects

You’ve probably stumbled upon hidden gems on GitHub: a README full of promises and features that look amazing. You want to try it out, but then you see the installation steps—"Requires Python 3.9+, PostgreSQL 14, Redis, and more..."—and your enthusiasm instantly halves.

If you’re an open-source author, you’ve probably felt the same frustration. You pour your heart into building a fantastic tool, but complex environment setups keep 99% of potential users and contributors from ever trying it.

Between a GitHub repo and a user-ready demo lies a chasm called “environment setup.” This is the so-called “last mile” problem for countless great open-source projects.

Today, we’ll show you how AgentSphere helps you effortlessly bridge that gap.


A New Paradigm: From “Install Instructions” to “Live Links”

We believe the best way to showcase an open-source project isn’t with a long installation guide—it’s with a one-click, live, interactive demo.

Imagine adding a prominent “Live Demo” badge in your GitHub README. Users click it and instantly enter a real, working environment to try out your project themselves. How much more compelling would that be?

AgentSphere makes this incredibly simple. With just a few lines of code, you can package any public GitHub repository into a temporary, secure, publicly accessible cloud sandbox.


Hands-On: Creating an Online Demo for a Popular Open-Source Project

Let’s try this with a real project. Uptime Kuma is a popular, visually appealing self-hosted monitoring tool. Its installation isn’t overly complex, but users still need to prepare a Node.js environment and a server.

Now, let’s create a “no-installation” online demo for it.

1. Prepare a Simple Startup Script

All you need is a simple Node.js script to tell AgentSphere what to do:

import { Sandbox } from 'agentsphere-js';
import 'dotenv/config';

// Extract client ID from sandboxId to ensure URL uniqueness in multi-client environments
async function getClientId(sandbox) {
  // Method 1: Check environment variable (optional, user manual setting)
  const envClientId = process.env.AGENTSPHERE_CLIENT_ID;
  if (envClientId) {
    console.log('🔍 Using client ID from environment variable:', envClientId);
    return envClientId;
  }

  // Method 2: Auto-extract client ID from sandboxId
  try {
    const info = await sandbox.getInfo();
    console.log('📋 Sandbox info:', JSON.stringify(info, null, 2));

    // sandboxId format: "random_part-client_id"
    const sandboxId = info.sandboxId;
    if (sandboxId && sandboxId.includes('-')) {
      const parts = sandboxId.split('-');
      if (parts.length >= 2) {
        const clientId = parts[parts.length - 1]; // Take the last part as client ID
        console.log('🔍 Extracted client ID from sandboxId:', clientId);
        return clientId;
      }
    }
  } catch (error) {
    console.log('⚠️  Could not retrieve sandbox info:', error.message);
  }

  // Method 3: If client ID cannot be obtained, return null and use basic URL
  console.log('⚠️  Client ID not found. Using basic URL format.');
  return null;
}

// Generate URL with automatic client ID handling
async function generateSecureUrl(host, port, sandboxId, sandbox) {
  const clientId = await getClientId(sandbox);

  // If no client ID, use basic URL
  if (!clientId) {
    console.log('📍 Using basic URL format (single-client mode)');
    return `https://${host}`;
  }

  // Check host format and build URL with client ID
  if (host.includes('-') && host.split('.')[0].split('-').length >= 2) {
    const [portPart, ...rest] = host.split('.');
    const domain = rest.join('.');
    const newHost = `${port}-${sandboxId}-${clientId}.${domain}`;

    console.log(`🔒 Enhanced URL with client ID for multi-client security`);
    console.log(`🔍 Client ID: ${clientId}`);
    return `https://${newHost}`;
  }

  // Fallback to original URL
  return `https://${host}`;
}

async function createUptimeKumaDemo() {
  console.log('Starting to create a live demo for Uptime Kuma...');

  const sandbox = await Sandbox.create({
    template: 'agentsphere-code-interpreter-v1',
    apiKey: process.env.AGENTSPHERE_API_KEY,
    timeoutMs: 10 * 60 * 1000,
  });

  console.log(`Sandbox created: ${sandbox.sandboxId}`);

  try {
    console.log('Cloning Uptime Kuma from GitHub...');
    await sandbox.commands.run('git clone https://github.com/louislam/uptime-kuma.git');
    console.log('Repository cloned.');

    console.log('Running official setup... (This may take a few minutes)');

    // Use the officially recommended setup command
    const setupResult = await sandbox.commands.run('cd uptime-kuma && npm run setup', {
      onStdout: (data) => console.log('Setup:', data),
      onStderr: (data) => console.log('Setup Error:', data)
    });

    console.log('Setup completed.');
    console.log('Starting the Uptime Kuma server...');

    // Start server in background
    const proc = await sandbox.commands.run(
      'cd uptime-kuma && node server/server.js',
      {
        background: true,
        onStdout: async (data) => {
          console.log('Server output:', data);

          // Dynamically detect port number
          const portMatch = data.match(/(?:Listening on port|HTTP Server on port)\s*(\d+)/i) || 
                           data.match(/port\s*(\d+)/i);

          if (portMatch) {
            const port = parseInt(portMatch[1]);
            const host = sandbox.getHost(port);
            console.log(`🔍 Debug - getHost(${port}) returned: ${host}`);

            // Build secure URL with client identifier
            const url = await generateSecureUrl(host, port, sandbox.sandboxId, sandbox);
            console.log('\n✅ Your Uptime Kuma Live Demo is Ready!');
            console.log(`🔗 Access it here: ${url}`);
            console.log(`🔢 Detected port: ${port}`);
            console.log('⏰ (This sandbox will self-destruct in 10 minutes)');
          } else if (data.includes('Server is ready') ||
                    data.includes('Server Type: HTTP') ||
                    data.includes('Creating express and socket.io instance')) {
            // If no specific port detected, try default port 3001
            const host = sandbox.getHost(3001);
            console.log(`🔍 Debug - getHost(3001) returned: ${host}`);

            const url = await generateSecureUrl(host, 3001, sandbox.sandboxId, sandbox);
            console.log('\n✅ Your Uptime Kuma Live Demo is Ready!');
            console.log(`🔗 Access it here: ${url}`);
            console.log('🔢 Using default port: 3001');
            console.log('⏰ (This sandbox will self-destruct in 10 minutes)');
          }
        },
        onStderr: (data) => {
          console.log('Server error:', data);
        }
      }
    );

    console.log('Server started in background. Waiting for full timeout...');

    // Keep running for the full 10 minutes
    await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000));

  } catch (error) {
    console.error('Error occurred:', error.message);
    console.error('Full error:', error);

    // Don't destroy sandbox immediately on error - give it time
    console.log('Keeping sandbox alive for 5 more minutes to debug...');
    await new Promise(resolve => setTimeout(resolve, 5 * 60 * 1000));

  } finally {
    try {
      await sandbox.kill();
      console.log('Demo sandbox has been destroyed.');
    } catch (killError) {
      console.log('Error destroying sandbox:', killError.message);
    }
  }
}

createUptimeKumaDemo().catch(console.error);
Enter fullscreen mode Exit fullscreen mode

2. Run the Script

# First, install the AgentSphere SDK
npm install agentsphere-js dotenv

# Then, run the script with your API key
AGENTSPHERE_API_KEY=your_api_key node uptime-kuma-demo.mjs
Enter fullscreen mode Exit fullscreen mode

3. Witness the Magic

In a few minutes (mainly depending on npm install speed), your terminal will print a public URL.

Anyone can use this link to access a fully functional Uptime Kuma instance running in a cloud sandbox!

A screenshot of Uptime Kuma deployed in AgentSphere Sandbox

A screenshot of Uptime Kuma deployed in AgentSphere Sandbox

What This Means for the Open Source World

This “one-click demo” capability brings huge value to the open-source ecosystem:

For project owners:

  • Boost project appeal: A live demo speaks louder than a thousand words in a README.

  • Collect feedback faster: Users can “try before they install” and give feedback sooner.

  • Simplify contributor onboarding: Provide instant, standardized development environments for potential contributors.

For project users:

  • Zero-cost trial: Safely evaluate a tool without touching your local environment or paying for servers.

  • Avoid security risks: Run unknown open-source code in an isolated sandbox, protecting your computer and data.


Conclusion: Become Your Favorite Project’s Advocate

AgentSphere is more than a development tool—it’s a connector and amplifier.

Next time you discover an amazing open-source project but struggle to showcase it to colleagues or friends, try creating an online demo with AgentSphere.

You’ll help the project gain visibility while enjoying a smooth, safe, and interactive software experience yourself.

Watch more demos of non-technical staff showcases | Try AgentSphere for Free | Join our Discord Community

Top comments (0)