Summary
The app→agent exposure surface is spec-complete and parse-only, but runtime-absent. An app can declare exposes-as-agent: true + an exposed-commands: block, the manifest parses it, the app-spec describes the registry synthesizing an agent from it — but no code path ever reads exposed_commands, so a workflow exposed as an agent cannot actually be invoked as one, and a caller cannot route per-command inputs into the nested app's chain.
This blocks a high-value capability ("build a multi-node workflow, then bake it into a single reusable agent that other workflows call, still setting its inputs"). Filing per the verified-gap rule, not speculation — every claim below is cited.
Verified evidence (AWARE 0.51, this repo)
-
exposed_commands is dead code. cli/src/manifest/app.rs:21-23:
#[allow(dead_code)]
#[serde(rename = "exposed-commands", default)]
pub exposed_commands: Option<Value>,
A grep across all of cli/src/ finds exposed_commands referenced only at this declaration — no orchestrator, invoker, registry, or compiler code reads it.
-
No agent-manifest synthesis. The app-spec (10-core/app-spec.md ~832-874) describes the registry/orchestrator synthesizing an agent manifest from exposed-commands at install/compile, after which the registry "treats it like an agent" callable via agent: <ns>/<app>. No such synthesis exists in cli/src/runtime/orchestrator.rs or cli/src/runtime/invoker.rs.
-
No per-command input routing. RuntimeContext.inputs is a single flat map. Nothing maps a caller's per-command inputs into a nested app's inputs:, validates against the declared exposed-commands.<cmd>.inputs types, or namespaces them per command. So the declared inputs: (e.g. welded-to-tc's tc-project-id, or a hypothetical phase) are documentation only at the agent boundary.
-
No CLI verb. AppCommand (cli/src/commands/app.rs) has 12 variants — list, show, install, uninstall, validate, export, run, explain, compile, inspect, stop, logs — none bake/expose/publish/convert an app into an agent. publish exists only under AgentCommand (hand-written agents).
-
Zero end-to-end usage. 30-apps/_examples/welded-to-tc.flo:13-30 is the only app that sets exposes-as-agent: true (declares a start command with inputs: tc-project-id, tc-folder-id + a stream output). Nothing anywhere invokes an exposed app as an agent — only doc examples.
Observed vs expected
- Observed:
exposes-as-agent: true + exposed-commands: parse cleanly and have no runtime effect. An app so declared cannot be called as an agent by another app, and its declared command inputs are inert.
- Expected (per app-spec): at install/compile, an agent manifest is synthesized from
exposed-commands; the app becomes callable as agent: <ns>/<app>, command: <cmd>; the caller's command inputs route into the nested app's inputs: and are type-validated.
Repro
# welded-to-tc declares exposes-as-agent: true + exposed-commands.start
aware app install ./30-apps/_examples/welded-to-tc.flo
# There is no synthesized agent to call, and no verb to produce one:
aware agent list # welded-to-tc does not appear as a callable agent
# No app→agent verb exists (no bake/expose/publish under `aware app`).
Suggested scope (the wiring this asks for)
- At compile/install, when
exposes-as-agent: true, synthesize an agent manifest from exposed-commands (commands, lifecycle, inputs/outputs schema) and register it so agent: <ns>/<app> resolves.
- In the orchestrator/invoker, when a node calls an app-backed agent, dispatch into the nested app's node chain and route the caller's per-command inputs into that app's
inputs: map (with type validation against the declared command inputs).
- Drop
#[allow(dead_code)] once exposed_commands is consumed.
- (Optional) an end-to-end example/test: app B calls
welded-to-tc (or a phase-parameterized app) as an agent and sets its inputs.
Why it matters / cross-ref
This is the substrate prerequisite for a "bake a working workflow into a reusable, input-controllable agent" feature in floless.app (designed, gated on this — UI deliberately not built against dead code). Related: #101 (floless.app capability audit). Until this lands, the working path to set an app's inputs is a direct aware app run <app> --input k=v, which functions correctly.
Summary
The app→agent exposure surface is spec-complete and parse-only, but runtime-absent. An app can declare
exposes-as-agent: true+ anexposed-commands:block, the manifest parses it, the app-spec describes the registry synthesizing an agent from it — but no code path ever readsexposed_commands, so a workflow exposed as an agent cannot actually be invoked as one, and a caller cannot route per-command inputs into the nested app's chain.This blocks a high-value capability ("build a multi-node workflow, then bake it into a single reusable agent that other workflows call, still setting its inputs"). Filing per the verified-gap rule, not speculation — every claim below is cited.
Verified evidence (AWARE 0.51, this repo)
exposed_commandsis dead code.cli/src/manifest/app.rs:21-23:A grep across all of
cli/src/findsexposed_commandsreferenced only at this declaration — no orchestrator, invoker, registry, or compiler code reads it.No agent-manifest synthesis. The app-spec (
10-core/app-spec.md~832-874) describes the registry/orchestrator synthesizing an agent manifest fromexposed-commandsat install/compile, after which the registry "treats it like an agent" callable viaagent: <ns>/<app>. No such synthesis exists incli/src/runtime/orchestrator.rsorcli/src/runtime/invoker.rs.No per-command input routing.
RuntimeContext.inputsis a single flat map. Nothing maps a caller's per-command inputs into a nested app'sinputs:, validates against the declaredexposed-commands.<cmd>.inputstypes, or namespaces them per command. So the declaredinputs:(e.g.welded-to-tc'stc-project-id, or a hypotheticalphase) are documentation only at the agent boundary.No CLI verb.
AppCommand(cli/src/commands/app.rs) has 12 variants — list, show, install, uninstall, validate, export, run, explain, compile, inspect, stop, logs — none bake/expose/publish/convert an app into an agent.publishexists only underAgentCommand(hand-written agents).Zero end-to-end usage.
30-apps/_examples/welded-to-tc.flo:13-30is the only app that setsexposes-as-agent: true(declares astartcommand withinputs: tc-project-id, tc-folder-id+ astreamoutput). Nothing anywhere invokes an exposed app as an agent — only doc examples.Observed vs expected
exposes-as-agent: true+exposed-commands:parse cleanly and have no runtime effect. An app so declared cannot be called as an agent by another app, and its declared command inputs are inert.exposed-commands; the app becomes callable asagent: <ns>/<app>, command: <cmd>; the caller's command inputs route into the nested app'sinputs:and are type-validated.Repro
Suggested scope (the wiring this asks for)
exposes-as-agent: true, synthesize an agent manifest fromexposed-commands(commands, lifecycle, inputs/outputs schema) and register it soagent: <ns>/<app>resolves.inputs:map (with type validation against the declared command inputs).#[allow(dead_code)]onceexposed_commandsis consumed.welded-to-tc(or aphase-parameterized app) as an agent and sets its inputs.Why it matters / cross-ref
This is the substrate prerequisite for a "bake a working workflow into a reusable, input-controllable agent" feature in floless.app (designed, gated on this — UI deliberately not built against dead code). Related: #101 (floless.app capability audit). Until this lands, the working path to set an app's inputs is a direct
aware app run <app> --input k=v, which functions correctly.