Skip to main content

create-lightflows

Guides the design, authoring, compilation, and verification of new Python DAG workflows using Lightflow (YAML or JSON). Use when building a new multi-stage pipeline, authoring `actions.py` and `lightflow.yaml`, or scaffolding a workflow with the `create_lightflow` meta-workflow. For merely running or resuming an existing workflow, use `run_lightflows` instead.

Informations de source

Dépôt
google/lightflow
Dernière activité de la source
22 octobre 2026 à 11:17
Langue détectée de SKILL.md
anglais
Étoiles
14
Forks
3

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
create_lightflows
description
Guides the design, authoring, compilation, and verification of new Python DAG workflows using Lightflow (YAML or JSON). Use when building a new multi-stage pipeline, authoring `actions.py` and `lightflow.yaml`, or scaffolding a workflow with the `create_lightflow` meta-workflow. For merely running or resuming an existing workflow, use `run_lightflows` instead.
# Creating Lightflow Workflows (`create_lightflows`) Lightflow coordinates multi-step operations between AI agents and human operators using an append-only state ledger (`passport.json`), safe AST-based CEL-like expressions, and selective subgraph re-arming. > **Note**: If you only need to execute, inspect, or resume an *existing* > Lightflow workflow, read the `run_lightflows` skill instead. ## 1. Scaffolding a New Workflow via `create_lightflow` (3-Phase Meta-Workflow) Instead of authoring a workflow from scratch in one shot, run the built-in 3-phase meta-workflow, which gates progress on deterministic AST signature checks, `sample_payload` return-contract smoke tests, unit test execution, and `payload.outputs.<stage>` DAG cross-checks. The meta-workflow ships in the Lightflow repository under `examples/create_lightflow/`: run it from a clone of `github.com/google/lightflow`, or pass the absolute path to `examples/create_lightflow` in your clone: ```bash lightflow start \ --lightflow=/path/to/lightflow/examples/create_lightflow \ --log_id=scaffold_<workflow_name> ``` (`python3 -m lightflow` is equivalent to `lightflow` whenever the console script is not on `PATH`.) 1. **`align_on_design`** (`operator_action`): Align with the user on stage boundaries (separate read/compute stages from external write/mutate stages), `operator_action` gates, and the output keys each stage produces under `payload.outputs.<stage>`. 2. **`implement_and_test_actions` $\rightarrow$ `verify_actions`**: Write `actions.py` + unit tests (or pass `sample_payload`); `verify_actions` parses the AST, smoke-tests that every action returns a JSON-serializable `(dict, str)` tuple, and runs `unittest`. 3. **`draft_and_explain_manifest` $\rightarrow$ `prove_manifest_dry_run`**: Write `lightflow.yaml` and explain the DAG to the user; `prove_manifest_dry_run` compiles the DAG, verifies that every `payload.outputs.<stage>` reference points to an upstream dependency in `run_after`, runs `dry_run`, and emits `visualizer.html`. ## 1b. Starting From an Existing `SKILL.md` Most procedures worth moving into Lightflow already exist as a skill: a numbered list of steps an agent follows by hand. The translation is mechanical once each step is classified: A step that… | becomes | because ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------- runs a command, calls an API, transforms data, writes a file | `python_action` | deterministic, testable, retryable; the agent never re-derives it needs judgment but no outside decision (triage findings, draft text, pick a remediation) | `operator_action` whose `instructions` tell the agent what to produce | the gate pauses the run, the agent does the work, then resumes with the result as payload needs a decision from a person (approve spend, confirm a destructive change) | `operator_action` whose `instructions` say who must decide | the resume stamp records who decided and from which session Worked example. A skill that reads: ``` 1. Query last week's incidents from the tracker. 2. Group them by service and draft a summary. 3. Get the on-call lead to confirm the summary. 4. Post it to the channel. ``` maps to: ```yaml name: weekly_incident_digest actions: - {id: fetch, python_import: digest.actions.fetch_incidents} - {id: group, python_import: digest.actions.group_by_service} - {id: post, python_import: digest.actions.post_to_channel} stages: - name: fetch_incidents # step 1: mechanical python_action: {action_id: fetch} retry_policy: {max_attempts: 3, initial_backoff_seconds: 5} - name: group_by_service # step 2a: mechanical run_after: [fetch_incidents] python_action: {action_id: group} - name: draft_summary # step 2b: agent judgment run_after: [group_by_service] operator_action: instructions: "'Draft a 5-line summary of ' + string(payload.outputs.group_by_service.count) + ' incidents grouped by service; resume with summary_md.'" json_schema: '{"type": "object", "required": ["summary_md"], "properties": {"summary_md": {"type": "string"}}}' - name: lead_confirms # step 3: a person decides run_after: [draft_summary] operator_action: instructions: "'Ask the on-call lead to confirm this summary before it is posted: ' + payload.outputs.draft_summary.summary_md" - name: post_to_channel # step 4: mechanical run_after: [lead_confirms] python_action: {action_id: post} ``` Keep the skill: replace its step list with `lightflow start --lightflow=<dir>` and the gate-handling rules from `skills/run_lightflows/SKILL.md`. The judgment and the decision stay where they were; only the mechanical steps and the ordering move into code. Run the `create_lightflow` meta-workflow above to scaffold and prove the result. ## 2. Workflow Manifest Reference (`lightflow.yaml`) Define actions and stages in `lightflow.yaml` (or `.json`). `python_import` resolves relative to the workflow's directory (e.g. `actions.fetch_metrics` for `actions.py` in the same folder) as well as package paths: ```yaml name: release_verification_pipeline description: Fetch metrics, pause for operator review, and publish report. # Optional: payload keys (any depth) shown as <redacted> in the visualizer, # status --verbose and dry-run output. passport.json keeps the real values. secret_keys: [api_token] actions: - id: fetch_metrics python_import: actions.fetch_metrics - id: publish_report python_import: actions.publish_report - id: cleanup_temp python_import: actions.cleanup_temp stages: - name: fetch description: Fetch latest metrics timeout_seconds: 60 python_action: action_id: fetch_metrics static_kwargs: limit: 500 retry_policy: max_attempts: 3 initial_backoff_seconds: 5 backoff_multiplier: 2.0 rollback_action: action_id: cleanup_temp - name: approve description: Operator approval gate run_after: [fetch] operator_action: # CEL-like expression: string literals MUST be quoted inside the string. instructions: "'Ready to publish: ' + payload.outputs.fetch.summary" json_schema: type: object required: [approved] properties: approved: type: boolean - name: publish description: Publish verified report run_after: [approve] run_if: "payload.outputs.approve.approved == true" python_action: action_id: publish_report - name: always_cleanup run_after: [publish] trigger_rule: ALL_DONE python_action: action_id: cleanup_temp ``` ## 3. Rules for Crash-Free Python Actions ```python from typing import Any def fetch_metrics( payload: dict[str, Any], **static_kwargs: Any ) -> tuple[dict[str, Any], str]: limit = static_kwargs.get("limit", 100) return {"row_count": limit, "summary": f"{limit} rows"}, "Fetched metrics" ``` 1. **One Side Effect per Stage**: Separate read/compute stages from external write/mutate stages. Lightflow's `Passport` never re-runs `COMPLETED` stages on `resume`; make write stages safe to retry if they fail mid-execution (overwrite files instead of appending, or attach a `rollback_action`). 2. **Consistent Output Keys (`payload.outputs.<stage_name>`)**: Every return path of an action (including any `offline` test mode for external APIs) must return a JSON-serializable `(dict, str)` with the **exact same dictionary keys** so downstream `run_if` and `instructions` expressions never crash. 3. **Cross-Check `payload.outputs.<stage>` Against `run_after`**: Any stage whose `run_if` or `instructions` reads `payload.outputs.<upstream>.<key>` must list `<upstream>` (directly or transitively) in `run_after`. 4. **Timeouts, Polling & Resilience**: Set stage-level `timeout_seconds` (`0`–`86400`; `0` disables the bound) on a stage to bound a `python_action` (or individual poll tick); for long-running external jobs, prefer `polling_policy` (`condition`, `interval_seconds`, `timeout_seconds`, `max_attempts`, optional `poll_tick_action`), which persists each tick's progress message to `passport.json` so `lightflow status` shows live progress. Use `retry_policy` for transient errors and `rollback_action` / `trigger_rule: ALL_DONE` for cleanup; keep cleanup stages idempotent, since an `ALL_DONE` stage that ran on a failure path runs again after `resume`. A polling stage in YAML (the tick action goes under `poll_tick_action`; a stage may not also set `python_action`): ```yaml - name: await_job run_after: [submit_job] polling_policy: condition: "payload.outputs.await_job.status == 'READY'" interval_seconds: 5 timeout_seconds: 600 # or max_attempts: 120 poll_tick_action: action_id: check_job # (dict, message) per tick ``` Each tick's returned dict is merged into `payload.outputs.await_job` before `condition` is evaluated, so a tick can read its own previous output. 5. **Converging After a Conditional Branch**: Two stages with complementary `run_if` conditions leave one of them `SKIPPED`. A stage that `run_after`s both must set `trigger_rule: NONE_FAILED` to run (the default `ALL_SUCCESS` skips it because an upstream was skipped; `ALL_DONE` would also run it after an upstream *failure*, which is only right for cleanup stages). `dry_run` points this out when it sees it. 6. **Optional Keys with `has(...)`**: Under `strict_expressions`, read a key that may be absent (e.g. an optional gate field) as `!has(payload.outputs.gate.note) || payload.outputs.gate.note != 'skip'`. `has()` never raises. 7. **Strict Expressions \& Explicit Namespaces**: Set top-level `strict_expressions: true` on new lightflows so a misspelled or not-yet-populated key in `run_if` / `condition` / `instructions` fails the stage instead of silently evaluating to `null` (guard optional keys with `has(...)`). Read upstream values as `payload.outputs.<stage>.<key>` rather than the top-level mirror, which is last-writer-wins across stages; the engine warns when a stage overwrites a top-level key that an expression reads. `outputs` is a reserved top-level key (`--payload` may not set it). ## 4. Validating Your New Workflow Before handing off or running in production, always verify compilation, CEL-like expression evaluation, and gate schemas: ```bash lightflow dry_run --lightflow=lightflow.yaml lightflow render --lightflow=lightflow.yaml lightflow visualize --lightflow=lightflow.yaml --output=/tmp/visualizer.html ```
Voir sur GitHub