# Exec and HTTP

Exec commands declare a literal absolute executable path, argv entries, named
temporary outputs, limits, and a clean environment. Executable paths remain
literal because controller policy compares them with its own allowlist. Dynamic
loader variables and undeclared output references are rejected.

```xml
<edge-app format="1" handle="pdf-inspector" name="PDF inspector">
  <handlers>
    <handler name="inspect"><![CDATA[
return bridge.exec.run("qpdf-check", {
  inputs = { event.path },
  outputs = { "report" }
})
    ]]></handler>
  </handlers>
  <triggers>
    <file-created name="incoming-pdf" handler="inspect" path="/var/spool/incoming" pattern="*.pdf"/>
  </triggers>
  <exec-commands>
    <command name="qpdf-check" path="/usr/bin/qpdf" timeout-ms="30000" max-stdout-bytes="1048576">
      <arg>--check</arg>
      <arg>${input}</arg>
      <arg>--report=${output:report}</arg>
      <output name="report"/>
      <env name="LANG">C.UTF-8</env>
    </command>
  </exec-commands>
</edge-app>
```

HTTP routes declare method, path pattern, handler, explicit authentication mode,
body limit, and timeout. Basic credentials and bearer tokens are installation
bindings only. Route patterns support named segments and a final wildcard tail.

```xml
<edge-app format="1" handle="webhook-receiver" name="Webhook receiver">
  <config-schema>
    <schema type="object" xmlns="urn:cococo:json-schema:1">
      <additional-properties boolean="false"/>
      <property name="HTTP_BASIC_CREDENTIAL" type="string" write-only="true"/>
      <property name="HTTP_BEARER_TOKEN" type="string" write-only="true"/>
      <required name="HTTP_BASIC_CREDENTIAL"/>
      <required name="HTTP_BEARER_TOKEN"/>
    </schema>
  </config-schema>
  <handlers>
    <handler name="health"><![CDATA[
return { status = "ok" }
    ]]></handler>
    <handler name="receive"><![CDATA[
return { accepted = true, id = params.path.id }
    ]]></handler>
  </handlers>
  <http-routes>
    <route method="get" path="/health" handler="health" timeout-ms="5000">
      <auth mode="none"/>
    </route>
    <route method="post" path="/basic/{id}" handler="receive" max-body-bytes="1048576" timeout-ms="30000">
      <auth mode="basic">
        <credential config="HTTP_BASIC_CREDENTIAL"/>
      </auth>
    </route>
    <route method="post" path="/bearer/{id}" handler="receive">
      <auth mode="bearer">
        <token config="HTTP_BEARER_TOKEN"/>
      </auth>
    </route>
  </http-routes>
</edge-app>
```