product
Forma Actions And Triggers Concept
Goal
Define the early product model for configurable Actions and Triggers in Choral Forma.
Actions and Triggers should let a workspace describe repeatable behavior in reviewable repository configuration without turning Forma into a hidden workflow engine or arbitrary plugin runtime.
Design Direction
Actions are reusable, reviewable, configuration-defined executable processes. They define the execution content: expected inputs and ordered steps. Actions are not owned by one Trigger and may be invoked by a WebApp button, CLI/RPC call, Agent, or Trigger.
Triggers are event matching and invocation bindings. A Trigger listens for a Forma event, matches event context, and invokes one or more Actions with explicit inputs and an execution effect. Trigger configuration should not contain the core business logic; that logic belongs in Actions.
Events are explicit facts emitted by Forma. The long-term event model should support both operation-originated events and file-change events, but the first implementation should prioritize operation-originated events. File watcher, explicit workspace rescan/check, or direct Markdown edit events should be added later when the watch/discovery pipeline is mature enough.
Action Shape
An Action should be shaped like a small configuration or DSL-backed procedure, not an arbitrary script:
actions:
markTodoDone:
title: Mark Todo Done
input:
schema:
type: object
fields:
path:
type: string
required: true
steps:
- kind: setField
target:
entry: "{{ input.path }}"
field: status
value: done
The first version does not need a policy field. Execution control can be strengthened later with an optional policy section for maximum effect, allowed callers, affected scope, confirmation rules, or batch limits.
The invocation should provide the effect for that run:
triggers:
onKanbanDone:
on: action.requested
match:
action: markTodoDone
run:
action: markTodoDone
effect: applyChange
input:
path: "{{ event.entry.path }}"
Useful effect levels are:
dryRun: compute planned changes and diagnostics without writing files.proposeChange: produce a reviewable change proposal.applyChange: write the resulting file changes directly.
MVP Boundary
The first implementation should stay intentionally narrow. It should validate the Action/Trigger model through single-entry metadata changes before adding broader automation.
Candidate first step kinds:
setFieldunsetFieldappendListItem
MVP constraints:
- steps run in order;
- targets must resolve to a clear entry path;
- writes are limited to entry frontmatter metadata;
- no arbitrary shell, JavaScript, Python, WASM, network calls, or executable triggers;
- no loops, conditionals, cross-action calls, or external plugin execution;
- no file watcher or direct-edit trigger requirement;
- every execution should be able to produce planned changes, applied changes, and diagnostics.
Kanban Example
Kanban card movement should not introduce a second persistent card-state store. The card move should trigger a metadata Action, such as setting frontmatter.status, and the Kanban view should then classify the card from the updated metadata.
This keeps the repository file as the durable source of truth and avoids divergence between "which column the card is in" and "what the entry metadata says."
Daily Note Example
Daily Notes should not be a hidden built-in product feature. A workspace that wants Daily Notes can define a daily space, a template, and a createTodayDailyNote Action.
That Action would need a future createEntry step:
actions:
createTodayDailyNote:
title: Create Today Daily Note
input:
schema:
type: object
fields:
date:
type: date
default: "{{ runtime.currentDate }}"
steps:
- kind: createEntry
space: daily
input:
date: "{{ input.date }}"
title: "{{ input.date }}"
createEntry is not part of the first Action MVP. Daily Note creation should remain a later extension example or optional preset capability.
Configuration Placement
Actions should tend toward centralized definition because they are executable capabilities and may write files. Centralizing them makes team review easier.
Triggers may be centralized or placed near the space, view, or action that uses them. The exact file layout should remain open until implementation pressure clarifies the tradeoff.
Phasing
Actions and Triggers should be recorded as a P1+ product direction, but they should not be implemented immediately.
Suggested delivery sequence:
- P1: manual Actions MVP for single-entry metadata changes. This includes explicit invocation through CLI/RPC, WebApp, or Agent surfaces, but does not require Triggers.
- P1/P2: operation-originated Triggers after manual Actions are stable. Triggers should match explicit Forma operation events and invoke configured Actions.
- P2: richer Action steps such as
createEntry, enabling optional workspace patterns like Daily Notes without making them built-in product behavior. - P2/P3: file-change Triggers from watcher, explicit workspace rescan/check, or direct Markdown edit events after the watch/discovery pipeline is mature.
- P3: external automation such as Agent/MCP handoff, webhooks, network access, or plugin-like execution, gated by a stronger security and review model.
The near-term product work should continue without committing to an implementation task for this capability. When implementation becomes relevant, the first task should be scoped to the manual Actions MVP rather than the full Actions and Triggers model.
Open Questions
- What exact
.forma/file layout should store Action definitions and Trigger bindings? - What expression syntax should Actions and Triggers use for
input,event, andruntimereferences? - Should
policybe accepted as a reserved optional field in the first parser, or introduced only when enforcement is implemented? - How should
proposeChangeintegrate with the future reviewable knowledge change proposal model? - Which operation events are required for the first implementation?