Project Structure

CLI commands, templates, generated file structure, and build configuration

Project Structure

The tos CLI (included with the TelemetryOS Developer App) scaffolds a complete, production-ready application in seconds. The generated project follows TelemetryOS conventions — mount points are wired up, the SDK is pre-configured, and the development environment is ready to run.

Creating a Project

tos init my-weather-app

This creates a my-weather-app/ directory with the full project structure, installs dependencies, and initializes a Git repository. The project is ready to run immediately:

cd my-weather-app
tos dev

Generated Structure

my-weather-app/
├── src/
│   ├── render/           # Display component shown on devices
│   │   ├── index.tsx
│   │   └── App.tsx
│   ├── settings/         # Configuration UI shown in Studio sidebar
│   │   ├── index.tsx
│   │   └── Settings.tsx
│   └── shared/           # Shared code and types
├── public/               # Static assets
├── telemetry.config.json # TelemetryOS platform configuration
├── vite.config.ts        # Build configuration
├── tsconfig.json         # TypeScript configuration
├── package.json          # Dependencies and scripts
└── .gitignore            # Git ignore rules

The src/render/ directory contains the display component that runs on devices. The src/settings/ directory contains the configuration interface that appears in the Studio sidebar. Both components come pre-configured with SDK imports and example storage patterns so you can see the settings-to-render communication working immediately.

Configuration

The telemetry.config.json file tells the platform where to find each component and how to run the development server:

{
  "name": "my-weather-app",
  "version": "2026.1.0",
  "mountPoints": {
    "render": "/render",
    "settings": "/settings"
  },
  "devServer": {
    "runCommand": "vite --port $PORT",
    "url": "http://localhost:$PORT",
    "readyPattern": "VITE.*ready in"
  }
}

The mountPoints paths correspond to the directory structure under src/. The $PORT variable is replaced at runtime by the Developer App with an available port. See Configuration for the complete reference.

Build Configuration

The generated vite.config.ts is pre-configured with multiple entry points:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    rollupOptions: {
      input: {
        render: '/render/index.html',
        settings: '/settings/index.html'
      }
    }
  }
});

CLI Commands

tos init

Create a new application from a template.

tos init [project-path] [options]
OptionDescription
-d, --description <string>Application description
-a, --author <string>Application author
-v, --version <string>Application version (default: CalVer e.g. 2026.4.0)
-t, --template <string>Template to use (default: vite-react-typescript)
-y, --yesSkip prompts and use defaults

To scaffold into the current directory, use . as the path:

tos init .

When run without --yes, the CLI interactively prompts for the project name, description, author, version, template, and whether to include Claude Code skills and settings.

tos dev

Open a project in the Developer App.

tos dev [project-path]

tos serve is an alias for tos dev.

tos auth

Authenticate with TelemetryOS by saving your API token. Required before tos publish.

tos auth [options]
OptionDescription
-t, --token <string>Provide the API token directly (skip interactive prompt)
-f, --forceReplace existing token without confirmation

Tokens are obtained from Studio > Settings > API Tokens.

tos publish

Publish an application to TelemetryOS. Archives the project, uploads it, and streams build logs.

tos publish [project-path] [options]
OptionDescription
-i, --interactiveInteractively prompt for all build configuration
--name <name>Application name (overrides config)
--base-image <image>Docker base image for build (default: node:20)
--build-script <script>Build commands (default: npm install && npm run build)
--build-output <path>Build output directory (default: /dist)
--working-path <path>Working directory in container (default: /)

Build configuration options only apply when creating a new application. For existing applications, these are ignored.

tos version

Bump the project version (CalVer patch increment).

tos version [project-path]

tos archive

Archive a project as a .tar.gz file, respecting .gitignore rules.

tos archive [project-path] [options]
OptionDescription
-o, --output <path>Output directory for the archive

tos migrate

Detect and apply project migrations (SDK updates, config schema changes).

tos migrate [project-path] [options]
OptionDescription
-y, --yesSkip confirmation prompt

tos mcp

Connect AI agents to the Developer App via MCP (Model Context Protocol). Acts as a stdio-to-HTTP proxy when the Developer App is running, or starts a lightweight fallback server when it is not.

tos mcp [project-path]

tos claude-code

Apply or update Claude Code skills and settings in a project.

tos claude-code [project-path]

Templates

Specify a template with the --template flag:

tos init my-app --template vite-react-typescript-web

vite-react-typescript (default) — React with TypeScript and Vite. Full type safety with SDK type definitions, hot module replacement, and the fastest build times. Includes render and settings mount points.

vite-react-typescript-web — Same as the default template, plus a Web mount point for browser-accessible interfaces (staff dashboards, public kiosks, etc.).

Adding Components

Workers

To add a background worker, create the worker file and update the configuration:

// src/worker/index.ts
import { configure, store } from '@telemetryos/sdk';

configure();

async function syncData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    await store().application.set('latest-data', data);
  } catch (error) {
    console.error('Sync failed:', error);
  }
  setTimeout(syncData, 60000);
}

syncData();
{
  "backgroundWorkers": {
    "sync": "workers/sync.js"
  }
}

Containers

To add a Docker container for backend services, add the container definition to telemetry.config.json:

{
  "containers": {
    "api-server": { "image": "myapp/api:latest", "port": 3000 }
  }
}

The container key becomes a hostname accessible from your application code: fetch('http://api-server:3000/data'). Containers only run on physical devices, not in Studio or the local development server.


What’s Next