Skip to content

When an agent deploys an app, it creates a manifest, a description of everything the app needs to run. This is what you see during the approval flow, and understanding it helps you make good decisions about what to approve.

Reading a manifest

Here's an annotated example of a service app manifest:

yaml
# Identity
handle: sales-dashboard          # URL-safe identifier; source lives at apps/sales-dashboard/
                                 # and is served at /apps/sales-dashboard/. Immutable once deployed.
                                 # 2–32 chars, must start with a lowercase letter, then a-z, 0-9, -, _.
name: Sales Dashboard            # Human-readable display name
description: Interactive dashboard showing quarterly sales data
icon: chart-bar                  # Optional icon hint shown in the apps UI

# Mode
kind: service                    # 'service' (running process, default) or 'static' (files only)

# How to run it
command: node server.js          # Start command, run from apps/{handle}/. Must listen on $PORT.
# static_dir: dist/              # For kind: static — directory to serve, relative to apps/{handle}/

# Reverse proxy
expose: true                     # Default true. Set false for background workers (no URL).

# Sandbox policy
sandbox_policy:
  network_access: true           # Master switch for outbound network
  network_destinations:          # Allowlist of "host:port" strings (used when network_access is true)
    - "api.example.com:443"
  read_paths:                    # Extra filesystem reads. Absolute, user://, or agent:// paths only.
    - "user://alice/reports"
  write_paths:                   # Extra filesystem writes
    - "/tmp/cache"
  bind_ports:                    # TCP ports the app may listen on (in addition to $PORT)
    - 9000
  denied_paths:                  # Deny rules layered on top of allows
    - "/etc"
  blocked_networks:              # Block these destinations even if network_access is true
    - "169.254.169.254:80"

# Resource limits
resources:
  memory_mb: 256                 # Max memory
  cpu_shares: 512                # CPU weight
  max_pids: 50                   # Max processes

# Credentials
credentials:                     # Vault items injected as environment variables
  - query: OpenAI API key
    reason: Used for generating chart descriptions
    env_var_prefix: OPENAI       # Creates OPENAI_USERNAME, OPENAI_PASSWORD, etc.

# Health checks (services only)
health_check:
  path: /                        # Default '/'
  interval_secs: 10              # Default 10
  timeout_secs: 2                # Default 2
  initial_delay_secs: 5          # Default 5
  failure_threshold: 3           # Default 3

# Lifecycle
restart_policy: on_failure       # 'on_failure' (default), 'always', or 'never'
hibernate: true                  # Default true. Set false for always-on services.

What to look for when approving

When reviewing a manifest, pay attention to:

  • command. What program will run? Does it look reasonable for what you asked?
  • sandbox_policy.network_destinations. Does the app need to reach external services? If you asked for a simple dashboard, it probably shouldn't need network access.
  • credentials. Is the app requesting API keys or passwords? Make sure the reason is legitimate.
  • sandbox_policy.read_paths / write_paths. What files can the app access? It shouldn't need access beyond its own directory unless there's a specific reason.

These five fields — command, kind, expose, sandbox_policy, credentials — are the ones that trigger a fresh approval prompt when they change on an already-deployed app. Touching code, names, or icons restarts the app silently.

Common manifest patterns

Simple static site (no network, no credentials)

A data visualization page built from a CSV you uploaded:

  • kind: static, no sandbox_policy, no credentials
  • This is the safest kind of app. It's just serving files.

API-connected service

A dashboard that fetches live data from an external API:

  • kind: service, sandbox_policy.network_destinations: ["api.example.com:443"], credentials: [API key]
  • Review that the API destination and credentials match what you expect.

Internal tool

A service that processes workspace files:

  • kind: service, sandbox_policy.network_access: false, sandbox_policy.read_paths: ["user://<handle>/..."]
  • No external access, just reading your files. Relatively safe.

Managing deployed apps

Stopping an app

Stops the running process but keeps the app configuration. You can restart it later.

Restarting an app

Stops and immediately restarts. Useful to pick up environment changes or clear a bad state.

Destroying an app

Permanently removes the app. The source code remains in the agent's workspace, but the app configuration and process are deleted. To run it again, the agent would need to redeploy.

Server-level settings

These settings control app behavior across your entire instance:

SettingDefaultDescription
FRONA_APP_PORT_RANGE_START4000First port available for apps
FRONA_APP_PORT_RANGE_END4100Last port available for apps
FRONA_APP_HEALTH_CHECK_TIMEOUT_SECS30Timeout for health checks
FRONA_APP_MAX_RESTART_ATTEMPTS2How many times to restart a crashed app
FRONA_APP_HIBERNATE_AFTER_SECS259200Inactivity before hibernation (default: 3 days)

Tips

  • Simpler manifests are safer. A static site with no network access is always safer than a service with external connections.
  • Don't over-provision resources. Most simple apps work fine with default memory and CPU settings.
  • Check credentials carefully. If an app requests credentials, make sure you understand why and that the env_var_prefix makes sense.

Next steps