Community pieces run inside the engine subprocess and make their own network calls with the user's stored connection credentials. They never touch the daemon's tool surface, so the workflow Authority boundary added in #459 does not see them: it gates /v1/jarvis/* (tools, notify, agent, workflows, context, llm), which is everything a step can reach through the daemon, and nothing a piece does on its own.
The same is true of CODE steps, which run arbitrary JavaScript in that subprocess. AP_EXECUTION_MODE=SANDBOX_PROCESS is a child process, not an isolate, so code there has host privileges.
This matters because a flow is not always hand-authored. manage_workflow compose builds a FlowVersion from an LLM plan, and LLM output is untrusted in our threat model.
#459 originally closed this with an admission allowlist that refused every non-Jarvis piece and every CODE step. That was removed before merge: it disabled all 657 entries in catalog-generated.ts, including the 10 in VERIFIED (gmail, slack, notion, openai, github, google-calendar, google-drive, discord, telegram-bot, claude), while the install UI, search_library and the composer's suggestedInstalls all kept offering them. Flows failed at run time rather than at authoring time. Removing the catalogue is a product decision, not part of a boundary fix.
Proposed path instead:
- Keep the catalogue open. Community pieces stay installable and runnable as they are today.
- Expand the verified set deliberately, one piece at a time, each in its own PR, by giving it a typed governed adapter: a
ToolDefinition.workflowEffect declaration with an Authority category and a target resolver, so its effect is reviewable on an approval card and dispatched through the same boundary as everything else. effect-capabilities.ts already supports this shape.
- Decide separately what to do about
CODE steps. Options: leave them, gate them behind an explicit user opt-in, or require a real isolate. Worth its own discussion rather than being folded into a piece-adapter change.
Scope note for whoever picks this up: the boundary in #459 is not weakened by any of the above. It lives in the daemon, on the far side of an HTTP hop, so whatever the engine subprocess runs still has to pass it to reach a Jarvis tool, a notification, a delegation, a child run, the vault or the LLM.
Context: #459.
Community pieces run inside the engine subprocess and make their own network calls with the user's stored connection credentials. They never touch the daemon's tool surface, so the workflow Authority boundary added in #459 does not see them: it gates
/v1/jarvis/*(tools, notify, agent, workflows, context, llm), which is everything a step can reach through the daemon, and nothing a piece does on its own.The same is true of
CODEsteps, which run arbitrary JavaScript in that subprocess.AP_EXECUTION_MODE=SANDBOX_PROCESSis a child process, not an isolate, so code there has host privileges.This matters because a flow is not always hand-authored.
manage_workflow composebuilds aFlowVersionfrom an LLM plan, and LLM output is untrusted in our threat model.#459 originally closed this with an admission allowlist that refused every non-Jarvis piece and every
CODEstep. That was removed before merge: it disabled all 657 entries incatalog-generated.ts, including the 10 inVERIFIED(gmail, slack, notion, openai, github, google-calendar, google-drive, discord, telegram-bot, claude), while the install UI,search_libraryand the composer'ssuggestedInstallsall kept offering them. Flows failed at run time rather than at authoring time. Removing the catalogue is a product decision, not part of a boundary fix.Proposed path instead:
ToolDefinition.workflowEffectdeclaration with an Authority category and a target resolver, so its effect is reviewable on an approval card and dispatched through the same boundary as everything else.effect-capabilities.tsalready supports this shape.CODEsteps. Options: leave them, gate them behind an explicit user opt-in, or require a real isolate. Worth its own discussion rather than being folded into a piece-adapter change.Scope note for whoever picks this up: the boundary in #459 is not weakened by any of the above. It lives in the daemon, on the far side of an HTTP hop, so whatever the engine subprocess runs still has to pass it to reach a Jarvis tool, a notification, a delegation, a child run, the vault or the LLM.
Context: #459.