8000 feat(workflows): an event scope for automations, with action and decide nodes by adeelahmad · Pull Request #436 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(workflows): an event scope for automations, with action and decide nodes - #436

Merged
adeelahmad merged 8 commits into
mainfrom
claude/project-thread-sxrerj
Oct 16, 2026
Merged

adeelahmad merged 8 commits into
mainfrom
claude/project-thread-sxrerj

Conversation

@adeelahmad
@adeelahmad adeelahmad commented Oct 15, 2026 •
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: a workflow ran on assets, organised the graph, or was an assistant tool's body. Nothing could describe what an automation does.

After: a workflow of scope event is what an automation does (workflow studio M6, part 1 of 5). Its input passes on the run context (the event, the automation, the person, steps...), and its action nodes fill their params in from it ("text": "New: {{ event.object.name }}"), work out effect and risk, and make an intent: done at once, asked first, or waiting for a time. An action that asks first or waits passes nothing on, so the nodes after it are skipped and the log says where it stopped. POST /api/v1/workflows/test with scope: event tries one on a real activity (by id) or a kind's sample and lists what each action would do. The decide node is in the catalog with a port per option plus unsure, and is refused as coming soon until the decision model lands (M5).

How: flow.Kit gains three optional hooks that default to today's behaviour: ports(node) (decide's ports), keeps(node) (an action node counts as doing something without being terminal, so it keeps its out port) and check_graph(nodes, edges) (the leaf rule: an action that reaches outside Lens or waits has nothing after it, on every save path including /api/v1/workflows). app/domain/automation_nodes.py holds the kit: checks, rendering (a param that is exactly one {{ }} expression keeps its type), the baseline run context, and an Intents box the automations module will keep and hand off from. It calls the variables, timers and match modules once they exist and keeps a baseline until then. Event workflows are left out of the canvas's list (?scope=event lists them) and refused as a pipeline step, a routine's action or a run on an asset.

With the M7 actions now on main, an action node also fills in the action's defaults before rendering (so ask_agent's about: "{{ event }}" and run_workflow's asset: "{{ event.object.id }}" are filled in), renders prompt params ("format": "prompt") with actions.render_prompt so outside text is marked as data, and counts a node whose output says untrusted (an http_request answer) as outside text for the params that read it.

Motivation and Context

Workflow studio, module M6 (automation engine), brief section 2 "The event workflow scope". Next PRs: storing automations and their API, the dispatcher and runs, agent tools, drafting from a sentence.

Defaults I picked: event workflows are hidden from the generic list so the canvas (which doesn't draw them yet) is unchanged; delay/when on an action and the decide node refuse to save as "coming soon" until timers and the decision model are merged.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change; ! in the title)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project (make hooks checks it on commit).
  • I added or updated tests.
  • My change requires documentation updates, and I have updated docs/ accordingly.
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md. (n/a: plumbing for automations; the changelog line comes with storing and running them)

Done questions (AGENTS.md)

  • Goal: one module of the studio's engine; merged on green CI.
  • Agents: saved and tried through the workflows API; automations' MCP and assistant tools follow in this module.
  • Zero setup: nothing to install or configure.
  • Fewest clicks and keystrokes: n/a, API only until the builder (M11).
  • Configurable: n/a, no new setting.
  • Light: no new dependency; Jinja (already used) renders params.
  • Private and secure: params are rendered in the existing sandboxed template environment; prompts mark outside text as data; outside text reaching an action (from the activity or an earlier node) marks its intent untrusted; anything reaching outside asks first. Threat model entries come with running automations.
  • Cost: no model calls here (decide comes with M5).
  • User decides: actions with effect out, or lens outside the event's own object, ask first; no defaults change.
  • Upgrades: no stored-data change; existing workflows keep their scopes.
  • Honest: docs label the scope built and the decide node planned.
  • Tests, docs and generated files updated (make openapi).
  • Open standards; no new dependencies.
  • Result reported with evidence; "refine later" items written in docs/automations.md.

Tests: tests/domain/test_automation_nodes.py, tests/api/test_event_workflows.py; full backend suite passed locally (1201 passed), ruff, mypy, frontend tsc, mkdocs build --strict.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VCAZ9NEmBJNovqdzxvK3qi


Generated by Claude Code

…de nodes

What an automation does is a workflow of scope event: its input passes on the
run context, and action nodes render their params from it, work out effect and
risk, and make intents (done at once, asked first, or waiting for a time). The
leaf rule keeps anything after an action that reaches outside or waits off every
save path. flow.Kit gains optional ports, keeps and check_graph hooks; decide
nodes are refused as coming soon until the decision model lands. Event
workflows are tried on an activity or a kind's sample, kept out of the canvas
list, and never run by pipelines, routines or on an asset.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCAZ9NEmBJNovqdzxvK3qi
@adeelahmad adeelahmad self-assigned this Oct 15, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCAZ9NEmBJNovqdzxvK3qi
…faults before rendering

An action node renders a prompt param (format prompt) with actions.render_prompt, so what the run
read from outside Lens is marked as data; fills the action's defaults before rendering, so a default
that is a template (ask_agent's about) is filled in; and counts a node whose output says untrusted
(an http_request answer) as outside text for the params that read it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCAZ9NEmBJNovqdzxvK3qi
@adeelahmad
adeelahmad merged commit 7f39320 into main Oct 16, 2026
10 checks passed
@adeelahmad
adeelahmad deleted the claude/project-thread-sxrerj branch October 16, 2026 00:19
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.

2 participants

0