Skip to content

sloppy run

Run a Sloppy app — either as a long-lived HTTP server or as a single synthetic request. run executes handlers, so source builds need the handler execution runtime enabled.

text
sloppy run [source | artifacts-dir | package-dir | --artifacts <dir>] [--stdlib <dir>]
           [--environment <name>] [--host <ip>] [--port <n>]
           [--kind web|program]
           [--once METHOD TARGET] [--header "Name: value"]
           [--body text | --body-file path | --json json]
           [--diagnostics-json] [-- <program-args...>]

Modes

Project mode (no positional, no --artifacts):

sh
sloppy run

Reads sloppy.json, compiles, then runs the artifacts.

Source input:

sh
sloppy run src/main.ts

Compiles the supplied source through sloppyc into .sloppy, validates artifacts, then runs.

Pre-built artifacts:

sh
sloppy run .sloppy

Loads app.plan.json, app.js, and app.js.map from the directory and runs them directly. sloppy run --artifacts .sloppy is the explicit form for scripts that prefer named flags.

Package directory:

sh
sloppy run .sloppy/package -- one two

Loads .sloppy/package/manifest.json, then runs the copied artifacts from .sloppy/package/artifacts. The current runner expects the canonical artifacts/app.plan.json, artifacts/app.js, and artifacts/app.js.map layout recorded by sloppy package; it does not resolve arbitrary manifest artifact paths. Package runs do not need the original source checkout or node_modules for dependency modules that were bundled into the artifact graph.

One-shot requests

--once METHOD TARGET runs a single synthetic request through the runtime and exits. Use it for smoke tests:

sh
sloppy run .sloppy --once GET /health
sloppy run src/main.ts --once POST /users --json '{"name":"Ada"}'
sloppy run .sloppy --once POST /upload --header content-type:text/plain --body-file request.txt
sloppy run .sloppy --header "content-type: application/x-www-form-urlencoded" --body-file form.txt --once POST /login

The full HTTP response is written to stdout — status line, response headers, blank line, and body — using the same serializer the real HTTP transport uses. Pipe through head if you only want the status line.

http
$ sloppy run .sloppy --once GET /health
HTTP/1.1 200 OK
content-type: text/plain; charset=utf-8
content-length: 2

ok

Exit status is 0 if the dispatch produced a response (including mapped error responses like 404). It is non-zero only on internal failures (parse, V8 init, target validation).

--once doesn't open a listener, so --host and --port are ignored.

Use --header "Name: value" to add request headers. The flag is repeatable. Header names must be HTTP token names, leading spaces or tabs after the colon are ignored, and header names/values cannot contain CR or LF bytes.

Use one body flag at most:

  • --body <text> sends text exactly as provided by the shell.
  • --body-file <path> reads bounded bytes from a local file.
  • --json <json> sends JSON text and adds Content-Type: application/json; charset=utf-8.

When a body is present, sloppy run adds Content-Length. Do not pass your own Content-Length header. For --body and --body-file, pass an explicit Content-Type such as application/json, text/plain, or application/octet-stream; --body-file is also useful for URL-encoded forms, multipart fixtures, and upload handlers.

sh
printf "name=Ada" > form.txt
sloppy run .sloppy --header "content-type: application/x-www-form-urlencoded" --body-file form.txt --once POST /form

Header and body one-shot dispatch currently requires static route metadata. Dynamic fallback routes still support method-and-target one-shot requests only.

Diagnostics

--diagnostics-json renders runtime diagnostics on stderr using the local diagnostic report shape. It is separate from --json, which is a one-shot request-body shorthand. The report output is local only and does not enable telemetry.

Flags

FlagDefaultPurpose
--artifacts <dir>Explicitly load already-built artifacts
--stdlib <dir>bundledOverride the bootstrap stdlib path
--environment <name>DevelopmentEnvironment name + overlay selection
--host <ip>127.0.0.1Server bind host
--port <n>5173Server bind port (1–65535)
--kind web|programinferred for direct source, web for project mode without kindOverride source kind
--once METHOD TARGETRun one synthetic request and exit
--header "Name: value"emptyAdd a synthetic one-shot request header
--body <text>emptyAdd a synthetic one-shot text body
--body-file <path>emptyRead a synthetic one-shot body from a file
--json <json>emptyAdd a JSON one-shot body and JSON content type
--diagnostics-jsonoffRender local runtime diagnostics on stderr; no telemetry
-- <program-args...>emptyArguments passed to Program Mode main(args, ctx)

--artifacts and a positional source or artifact path are mutually exclusive. Arguments after -- are valid only for Program Plans. --header, --body, --body-file, and --json are valid only with --once.

Program Mode

Program Plans run a route-free main/default export instead of preparing a web route table. --once is web-only and is rejected for Program Plans. A non-V8 source build can compile and inspect Program Mode artifacts, but sloppy run still fails before execution with the same handler-execution diagnostic used by web artifacts.

The current Program runtime calls a named main export first, then a default function export, then relies on top-level module execution. main and default functions receive (args, ctx), where args is the list after -- and ctx contains kind, args, cwd, environment, and plan.metadataCompleteness.

sh
sloppy run src/main.ts -- --name Ada
sloppy run --artifacts .sloppy -- --name Ada
sloppy run .sloppy/package -- --name Ada

console.log, console.info, and console.debug write to stdout. console.warn and console.error write to stderr. Returning an integer from 0 through 255 sets the process exit code. Throwing, rejecting, or returning an out-of-range exit code exits non-zero with a diagnostic. Program console output is currently buffered until the Program entrypoint completes.

Logging Config

sloppy run creates the native logging runtime from Plan/config metadata. Console logging is enabled by default. Configure it in appsettings.json:

json5
{
  "logging": {
    "minimumLevel": "info",
    "queueCapacity": 64,
    "console": {
      "enabled": true,
      "format": "pretty"
    },
    "file": {
      "path": "app.jsonl",
      "format": "jsonl"
    }
  }
}

Supported console formats are pretty and jsonl. The file sink writes JSONL only, opens in append mode, and expects the parent directory to exist.

Server Capacity Config

sloppy run reads Plan config metadata emitted from appsettings*.json and environment overlays. The development listener keeps request storage bounded, but the main admission and buffer limits are separately configurable:

KeyPurpose
Sloppy:Server:MaxConnectionsaccepted connection admission
Sloppy:Server:MaxActiveRequestsbackend request slots
Sloppy:Server:ConnectionCapacityaccepted-connection table allocation; must be at least MaxConnections
Sloppy:Server:Backlogplatform listen backlog
Sloppy:Server:MaxRequestHeadBytesHTTP/1 request head bytes
Sloppy:Server:MaxRequestBodyBytesdecoded request body bytes
Sloppy:Server:MaxRequestWireBodyBytesraw body bytes retained before parsing completes
Sloppy:Server:RequestArenaBytesper-connection request arena bytes
Sloppy:Server:MaxResponseBytesfixed response serialization buffer bytes
Sloppy:Server:MaxPendingWriteBytessingle write/backpressure guard
Sloppy:Server:Http2MaxStreamsHTTP/2 stream concurrency
Sloppy:Server:DispatchOnEventLoopqueue HTTP/1 handler dispatch onto the event loop dispatch phase
Sloppy:Server:MaxDispatchesPerTickmaximum queued HTTP/1 dispatches drained in one loop tick

If MaxConnections is raised without ConnectionCapacity, sloppy run raises the connection table capacity to match. It no longer raises MaxActiveRequests or HTTP/2 stream concurrency implicitly. If MaxRequestBodyBytes is raised without RequestArenaBytes, the request arena is raised only as far as needed to hold the decoded body. HTTP/1 handler dispatch is queued out of the read/parser callback by default so one socket read does not monopolize the loop before other loop work can run.

Examples

sh
# Build and run on the default host/port.
sloppy run

# Run already-built artifacts.
sloppy run .sloppy

# Bind to all interfaces, custom port.
sloppy run .sloppy --host 0.0.0.0 --port 8080

# Smoke a single request.
sloppy run src/main.ts --once GET /health

# Smoke a JSON POST.
sloppy run src/main.ts --once POST /users --json "{\"name\":\"Ada Lovelace\",\"email\":\"ada@example.test\"}"

# Use a non-Development environment overlay.
sloppy run --environment Staging

What happens at startup

  1. Parse CLI flags and resolve project config.
  2. If source input, invoke sloppyc build and write artifacts.
  3. Read app.plan.json, validate schema, hashes, target metadata, and required features.
  4. Prepare capabilities, dependency metadata, server config, logging config, and the Plan-backed route table for web Plans.
  5. Stage the bootstrap stdlib.
  6. Initialize the native logging runtime.
  7. Initialize the V8 isolate and engine bridge.
  8. Evaluate the artifact bundle and register handlers or the Program entrypoint.
  9. Start the listener, run the --once request, or call the Program entrypoint.

If any step fails the runtime exits with a diagnostic and a non-zero status.

Shutdown

For web servers, Ctrl+C (SIGINT) requests shutdown. The runtime stops accepting new connections, flushes configured logging sinks, and exits. Production-style graceful drain (long timeouts, in-flight connection completion, signaled load-balancer drain) is not implemented today — terminate behind a reverse proxy that handles connection draining for that.

Public alpha. APIs and artifact formats may still change between alpha revisions.