OSP logo
os://protocol

Apps

Distribution manifests for the Agentic OS — declare which vendors implement which protocol interfaces in a complete agentic system configuration.

This feature is experimental. The App schema and distribution manifest format have no real implementation yet and are subject to change.

Overview

An app is a distribution of the Agentic OS — a manifest that declares which vendors implement which protocol interfaces, forming a complete agentic system configuration. Think of it like package.json for Node.js, docker-compose.yml for containers, or vercel.json for deployments: a single file that describes how all the pieces fit together.

The format is YAML frontmatter for the structured, machine-readable manifest, combined with a free-form markdown body for human-readable documentation. The filename is up to the author — SYNER.md, APP.md, ACADEMY.md, or anything else. The format is what matters.

Distribution File

An app file combines a YAML frontmatter manifest with a markdown documentation body:

---
name: '@synerops/syner-os'
version: '1.0.0'
description: 'Syner OS — AI-powered development platform'
protocol: '0.1.0'
providers:
  system:
    sandbox: { provider: '@vercel/sandbox' }
    fs: { provider: '@vercel/blob' }
  context:
    embeddings: { provider: '@upstash/vector' }
---

# Syner OS

Syner OS is an AI-powered development platform...

The frontmatter declares the distribution metadata and provider bindings. The markdown body is free-form — documentation, usage instructions, architecture notes, or anything else relevant to the distribution.

TypeScript API

Import types from @osprotocol/schema/apps:

import type { App, AppMetadata, ProviderMap, ProviderEntry } from '@osprotocol/schema/apps'

ProviderEntry

A single vendor binding for a protocol interface:

interface ProviderEntry {
  provider: string
  version?: string
  enabled?: boolean
  metadata?: Record<string, unknown>
}
FieldTypeDescription
providerstringPackage name or identifier of the vendor implementation
versionstringOptional semver range for the provider
enabledbooleanWhether this binding is active. Defaults to true if omitted
metadataRecord<string, unknown>Arbitrary provider-specific configuration

ProviderMap

Maps protocol domains to their provider bindings, one entry per interface:

interface ProviderMap {
  system?: Record<string, ProviderEntry>
  context?: Record<string, ProviderEntry>
  actions?: Record<string, ProviderEntry>
  checks?: Record<string, ProviderEntry>
}

Each key within a domain corresponds to a specific protocol interface (e.g., sandbox, fs, embeddings), not the domain as a whole. Granularity is per interface.

AppMetadata

The structured frontmatter of a distribution file:

interface AppMetadata {
  name: string
  version: string
  description?: string
  protocol?: string
  providers?: ProviderMap
  metadata?: Record<string, unknown>
}
FieldTypeDescription
namestringDistribution name, typically a scoped package identifier
versionstringSemver version of this distribution
descriptionstringHuman-readable description
protocolstringOS Protocol spec version this distribution targets
providersProviderMapVendor bindings per domain and interface
metadataRecord<string, unknown>Arbitrary additional metadata

App

The parsed representation of a full distribution file:

interface App {
  metadata: AppMetadata
  content: string
  path: string
}
FieldTypeDescription
metadataAppMetadataParsed frontmatter
contentstringRaw markdown body after the frontmatter
pathstringFilesystem path to the distribution file

Provider Bindings

The providers field in the frontmatter maps each protocol domain's interfaces to concrete vendor implementations. Each domain (system, context, actions, checks) contains a record where each key is a specific interface name and each value is a ProviderEntry.

providers:
  system:
    env:
      provider: '@vercel/env'
    sandbox:
      provider: '@vercel/sandbox'
      version: '^1.0.0'
  context:
    embeddings: { provider: '@upstash/vector' }
  checks:
    screenshot: { provider: 'playwright' }
    judge: { provider: '@braintrust/judge' }

This declaration says: for the system domain, use @vercel/env for environment access and @vercel/sandbox for sandboxed execution; for context, use @upstash/vector for embeddings; for checks, use Playwright for screenshots and Braintrust for LLM-as-judge evaluation.

Provider bindings are resolved at runtime by the OS Protocol host. Interfaces with no binding fall back to any default registered by the host environment.

Usage Examples

Load an app manifest

import { readFileSync } from 'fs'
import matter from 'gray-matter'
import type { App, AppMetadata } from '@osprotocol/schema/apps'

function loadApp(filePath: string): App {
  const raw = readFileSync(filePath, 'utf-8')
  const { data, content } = matter(raw)
  return {
    metadata: data as AppMetadata,
    content,
    path: filePath,
  }
}

const app = loadApp('./SYNER.md')
console.log(app.metadata.name)    // '@synerops/syner-os'
console.log(app.metadata.version) // '1.0.0'

Validate provider bindings

import type { ProviderMap } from '@osprotocol/schema/apps'

function getProviderForInterface(
  providers: ProviderMap,
  domain: keyof ProviderMap,
  interfaceName: string
): string | undefined {
  return providers[domain]?.[interfaceName]?.provider
}

const sandboxProvider = getProviderForInterface(
  app.metadata.providers ?? {},
  'system',
  'sandbox'
)
// '@vercel/sandbox'

Compare two distributions

import type { App } from '@osprotocol/schema/apps'

function diffProviders(a: App, b: App): string[] {
  const differences: string[] = []
  const domains = ['system', 'context', 'actions', 'checks'] as const

  for (const domain of domains) {
    const aBindings = a.metadata.providers?.[domain] ?? {}
    const bBindings = b.metadata.providers?.[domain] ?? {}
    const allInterfaces = new Set([...Object.keys(aBindings), ...Object.keys(bBindings)])

    for (const iface of allInterfaces) {
      const aProvider = aBindings[iface]?.provider
      const bProvider = bBindings[iface]?.provider
      if (aProvider !== bProvider) {
        differences.push(`${domain}.${iface}: ${aProvider ?? 'none'} → ${bProvider ?? 'none'}`)
      }
    }
  }

  return differences
}

Cross-References

The app manifest format is analogous to other ecosystem configuration files:

FormatEcosystemDefines
package.jsonNode.js / npmPackage dependencies and scripts
docker-compose.ymlDockerService definitions and bindings
Chart.yamlHelm / KubernetesChart metadata and dependencies
claude_desktop_config.jsonClaude DesktopMCP server registrations
mcp.json (Cursor)CursorMCP server registrations for Cursor
.vscode/mcp.jsonVS CodeMCP server registrations for VS Code
vercel.jsonVercelDeployment configuration and routing
App manifest (*.md)OS ProtocolAgentic OS provider bindings and distribution metadata

The app manifest occupies the same role in the Agentic OS ecosystem that these files occupy in their respective ecosystems: a single source of truth for how a system is configured and what implements each capability.

Integration

Provider bindings in an app manifest map to the following protocol domains:

  • System — environment, sandboxing, storage, file system interfaces
  • Context — memory, embeddings, and knowledge retrieval interfaces
  • Actions — external integrations and side-effect interfaces
  • Checks — validation, evaluation, and quality assurance interfaces