paraglide-launch 0.2.2

Analyze a project and detect deployable services, languages, frameworks, commands, and env vars
Documentation

Launch

Analyzes a project and returns structured JSON describing every deployable service: language, version, framework, package manager, install/build/start/dev commands, env vars, and monorepo structure.

$ launch ./my-app
{
  "services": [
    {
      "name": "api",
      "dir": "apps/api",
      "runtimes": [
        {
          "language": "typescript",
          "name": "node",
          "version": "20.11.1",
          "version_source": ".nvmrc",
          "package_manager": { "name": "pnpm" },
          "framework": "next",
          "install": "pnpm install",
          "build": "next build",
          "start": "next start",
          "dev": "next dev"
        }
      ],
      "env": [
        { "key": "DATABASE_URL" },
        { "key": "PORT", "default": "3000" }
      ],
      "detected_by": ["apps/api/package.json"]
    }
  ]
}

Multi-language directories (Rails + React, Django + React, Laravel + Vue) produce a single service with multiple runtimes — the backend runtime first, the JS/TS runtime second.

Install

cargo install paraglide-launch

Usage

launch [PATH] [--format json|json-pretty]
Argument Default Description
PATH . Repository root
--format json-pretty json for compact output

Library

use launch::{discover_local, discover_with_fs, MemoryFs};

// Real filesystem
let discovery = launch::discover_local(Path::new("./my-app"))?;

// In-memory (tests)
let fs = MemoryFs::new(&[
    ("package.json", r#"{"scripts":{"start":"node server.js"}}"#),
    (".nvmrc", "20.11.1"),
]);
let discovery = launch::discover_with_fs(Path::new("."), signals, &fs)?;

What it detects

Service signals — emit named, deployable services:

Signal Files
Fly fly.toml
Vercel vercel.json
Netlify netlify.toml
Heroku Procfile
Railway railway.json, railway.toml
Dockerfile Dockerfile, Dockerfile.*, *.Dockerfile
Docker Compose docker-compose.yml, compose.yml

Context signals — describe language, commands, and env vars at a directory:

Signal Files
Package package.json, go.mod, Cargo.toml, pyproject.toml, mix.exs, Gemfile, composer.json, pom.xml
Framework next.config.*, astro.config.*, and 30+ others
DotEnv .env, .env.*
StructuredConfig Zod schemas, Pydantic models, Go struct tags
LibraryCalls process.env.X, os.Getenv("X"), etc.

A directory with a start command but no service signal is promoted to a service automatically. That's the common case: a plain project with package.json scripts.

Languages: JavaScript, TypeScript, Python, Go, Rust, Ruby, PHP, Java/Kotlin, Elixir.

Custom signals

use launch::{Signal, SignalOutput, FileSystem, DirEntry};
use std::path::Path;

struct MySignal { paths: Vec<PathBuf> }

impl Signal for MySignal {
    fn name(&self) -> &'static str { "my-signal" }

    fn observe(&mut self, dir: &Path, entry: &DirEntry) {
        if entry.name == "my.config" {
            self.paths.push(dir.join(&entry.name));
        }
    }

    fn generate(&mut self, fs: &dyn FileSystem) -> Result<SignalOutput, LaunchError> {
        // read self.paths, return services/context/monorepo
        Ok(SignalOutput::default())
    }
}

let mut signals = launch::signals::default_signals();
signals.push(Box::new(MySignal { paths: vec![] }));
let discovery = launch::discover_with_fs(root, signals, &fs)?;

Architecture

See ARCHITECTURE.md.