Skip to content

feat: add prompt input for custom automation runs#103

Open
eric-factory wants to merge 1 commit into
devfrom
eric/custom-automation-prompt
Open

feat: add prompt input for custom automation runs#103
eric-factory wants to merge 1 commit into
devfrom
eric/custom-automation-prompt

Conversation

@eric-factory

Copy link
Copy Markdown
Contributor

Description

Adds a prompt input so the action can run arbitrary custom automation tasks. This is the runtime half of Factory's Custom CI automations (factory-mono#16011): the Automations UI generates workflows that pass the user's task as prompt:, but the action previously had no such input, so scheduled Custom automations ran the action and did nothing.

Behavior:

  • New prompt input (PROMPT env into the prepare step) parsed onto context.inputs.prompt.
  • New src/custom-automation/ mode: writes the task (with an environment preamble: repo, triggering event, non-interactive expectations, open-a-PR-instead-of-pushing guidance) to the standard prompt file and passes user droid_args through untouched (this is how the Factory UI carries the -m <model> selection). No tool restrictions are imposed; the task is arbitrary by design.
  • Trigger detection: contains_trigger is now shouldTriggerTag || shouldTriggerCustomAutomation. Dispatch in src/prepare/index.ts gives the tag/review flows strict precedence: explicit @droid commands and automatic_review / automatic_security_review always win; the prompt only runs when no tag/review flow claimed the event.
  • Runs on automation events (schedule, workflow_dispatch, repository_dispatch, workflow_run) and on entity events that carry no command. Entity-triggered prompt runs keep the existing security posture: checkWritePermissions (prepare entrypoint) plus checkHumanActor (bots only when allow-listed).
  • README: prompt + droid_args documented in Core Inputs, plus a Custom Automations section with a scheduled example.

Backwards compatible: workflows without a prompt behave exactly as before (automation events still produce contains_trigger=false and skip).

How Has This Been Tested?

  • bun test: 460 passing, including new test/custom-automation.test.ts covering trigger detection (automation events, whitespace-only prompts, command-less entity events, precedence of automatic review), prompt-file content, droid_args pass-through, entity descriptions, and bot-actor rejection.
  • tsc --noEmit clean; prettier applied.

Factory-managed Custom CI automations generate workflows that pass a free-text
task prompt, but the action had no input to receive it, so scheduled runs did
nothing. Add a prompt input that runs droid exec directly with the given task
on automation events (schedule/workflow_dispatch/repository_dispatch/
workflow_run) and on entity events carrying no @droid command; explicit
commands and automatic-review flows keep precedence. Entity-triggered prompt
runs keep the human-actor and write-permission checks.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@factory-droid

factory-droid Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Droid finished @eric-factory's task —— View job


Security Review

The PR cleanly adds a custom-automation prompt mode and wiring, with sensible precedence over existing tag and review flows. The main correctness risk is that action_inputs_present can become inaccurate due to missing-key handling, and the new free-text prompt increases sensitivity and size risks when inputs are serialized or logged.

factory_api_key: "",
github_token: "",
droid_args: "",
prompt: "",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Fix action input presence detection for missing keys

collectActionInputsPresence() treats missing keys as an empty string (allInputs[name] || ""), which means any key absent from toJson(inputs) but with a non-empty default gets incorrectly marked as "present" ("" !== defaultValue). Since inputDefaults includes keys that are not defined as action inputs in action.yml (e.g. mode, branch_prefix, allowed_tools), action_inputs_present can become unreliable for downstream consumers.

Comment thread action.yml
DROID_ARGS: ${{ inputs.droid_args }}
PROMPT: ${{ inputs.prompt }}
INCLUDE_SUGGESTIONS: ${{ inputs.include_suggestions }}
ALL_INPUTS: ${{ toJson(inputs) }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Avoid serializing full custom prompt into ALL_INPUTS

With the new prompt input, ALL_INPUTS: ${{ toJson(inputs) }} can now embed arbitrary multi-line free text into an environment variable even though collectActionInputsPresence() only needs default-vs-present booleans. This can create brittle failures with very large prompts (environment size limits) and increases the blast radius of sensitive prompt content, so it would be safer to compute presence directly from known inputs or omit prompt from the serialized blob.

Comment on lines +60 to +68
const promptContent = buildCustomAutomationPrompt(context);

console.log("===== CUSTOM AUTOMATION PROMPT =====");
console.log(promptContent);
console.log("====================================");

const promptDir = `${process.env.RUNNER_TEMP || "/tmp"}/droid-prompts`;
await mkdir(promptDir, { recursive: true });
await writeFile(`${promptDir}/droid-prompt.txt`, promptContent);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] [security] Avoid logging raw custom automation prompt content

prepareCustomAutomationMode() logs the full generated prompt (including the user-provided task) to stdout. For custom automations this prompt can contain sensitive internal details, and GitHub Actions runners interpret certain log lines (for example ones starting with ::) as workflow commands. Consider avoiding verbatim logging, sanitizing ::-style sequences, and/or redacting or truncating prompt content before writing it to logs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant