Task Visibility¶
Task visibility controls which tasks are exposed as entry points, which are accessible across package boundaries, and which are internal implementation details. The visibility system helps package authors create clean APIs while hiding internal complexity.
Visibility Scopes¶
DV Flow Manager supports three visibility scopes that can be assigned to tasks:
Scope |
Description |
|---|---|
|
Task is an executable entry point. Shown in task listing when running |
|
Task is visible outside the package. Other packages can reference this task in their |
|
Task is only visible within its declaration fragment (e.g., within a task body or fragment file). |
Tasks without any scope specifier have package visibility - they can be referenced by other tasks in the same package but are not shown as entry points and will generate a warning if referenced from other packages.
Specifying Scope¶
There are two ways to specify task visibility:
Using the scope Field¶
The scope field can be a single string or a list of scopes:
tasks:
# Single scope
- name: build
scope: root
run: make build
# Multiple scopes
- name: public_entry
scope: [root, export]
desc: "Public entry point visible to other packages"
run: ./run.sh
Using Inline Scope Markers¶
For convenience, you can use root:, export:, or local: instead of
name: to simultaneously name the task and set its scope:
tasks:
# Equivalent to name: build + scope: root
- root: build
run: make build
# Equivalent to name: format + scope: export
- export: format
run: format.sh
# Equivalent to name: helper + scope: local
- local: helper
run: echo "internal"
Both inline markers and explicit scope: can be combined:
tasks:
# root inline marker + scope: export = both root and export
- root: main
scope: export
run: ./main.sh
Only one of name:, root:, export:, local:, or override:
can be specified per task.
Root Scope¶
Tasks marked with scope: root are executable entry points. When you run
dfm run without specifying a task, only root tasks are displayed:
package:
name: my_project
tasks:
- root: build
desc: "Build the project"
run: make build
- root: test
desc: "Run tests"
needs: [build]
run: make test
- name: internal_helper
run: echo "helper"
Running dfm run without arguments:
$ dfm run
No task specified. Available Tasks:
my_project.build - Build the project
my_project.test - Run tests
Note that internal_helper is not shown because it lacks scope: root.
Note
Any task can still be run directly by name, regardless of visibility. Visibility only affects what is listed, not what is runnable.
Export Scope¶
Tasks marked with scope: export are visible outside the package. This is
essential for creating reusable packages where other packages depend on your tasks.
# utils/flow.yaml
package:
name: utils
tasks:
- export: format
desc: "Format source files"
run: format.sh
- name: check_syntax
run: check.sh
# main/flow.yaml
package:
name: main
imports:
- utils/flow.yaml
tasks:
- name: build
needs:
- utils.format # OK - format is export
- utils.check_syntax # WARNING - not marked export
When a task references a non-export task from another package, DV Flow Manager issues a warning:
Warning: Task 'main.build' references task 'utils.check_syntax'
in package 'utils' that is not marked 'export'
This warning helps identify unintended dependencies on internal implementation details of other packages.
Local Scope¶
Tasks marked with scope: local are only visible within their declaration
context. This is useful for helper tasks in compound task bodies:
tasks:
- name: process_files
body:
- local: prepare
run: ./prepare.sh
- local: transform
needs: [prepare]
run: ./transform.sh
- name: finalize
needs: [transform]
run: ./finalize.sh
Local tasks cannot be referenced from outside their containing body or fragment.
Default Package Visibility¶
Tasks without any scope specifier have package visibility:
Can be referenced by other tasks in the same package
Can be run directly by fully-qualified name
Are NOT shown in task listings (
dfm runwithout arguments)Generate a warning if referenced from other packages
package:
name: my_pkg
tasks:
- name: internal_task
run: echo "package-visible only"
- root: public_entry
needs: [internal_task] # OK - same package
run: echo "entry point"
Combining Scopes¶
Scopes can be combined for tasks that serve multiple purposes:
tasks:
# Entry point AND visible to other packages
- name: main
scope: [root, export]
run: ./main.sh
# Or using inline marker plus scope field
- root: main
scope: export
run: ./main.sh
Common combinations:
[root, export]- Public entry point (both CLI and API)rootalone - Entry point only for this package (not for dependents)exportalone - API for other packages, but not a primary entry point
Best Practices¶
Entry Point Selection¶
Mark tasks as root when they represent meaningful operations a user would
run directly:
tasks:
# Good: Clear entry points
- root: build
desc: "Build the project"
- root: test
desc: "Run all tests"
- root: clean
desc: "Clean build artifacts"
# Not root: Implementation details
- name: compile_rtl
- name: compile_tb
- name: link
API Design¶
For reusable packages, carefully consider which tasks to export:
package:
name: my_library
tasks:
# Export: Stable API that users should depend on
- export: compile
desc: "Compile with library settings"
# Not export: Internal implementation
- name: gather_sources
- name: process_includes
# Export with root: Both API and entry point
- root: test
scope: export
desc: "Run library self-tests"
Compound Task Organization¶
Use local scope for helper tasks that should not leak outside:
tasks:
- name: full_flow
rundir: inherit
body:
# Local helpers - not visible outside
- local: step1
run: ./step1.sh
- local: step2
needs: [step1]
run: ./step2.sh
# Final step produces output
- name: result
needs: [step2]
uses: std.FileSet
with:
include: "*.out"
Warning Resolution¶
If you see warnings about referencing non-export tasks:
If intentional: Mark the referenced task as
exportIf unintentional: Refactor to not depend on internal tasks
If transitional: Add TODO comment and plan to fix
# Before: Warning about using internal task
- name: my_task
needs: [other_pkg.internal_task]
# After: Either export the task or restructure
# Option 1: Ask other_pkg maintainer to export it
# Option 2: Restructure to use exported task
- name: my_task
needs: [other_pkg.public_api]
Visibility in Fragments¶
Visibility works the same way in package fragments:
# src/rtl/flow.yaml
fragment:
tasks:
- root: compile_rtl
desc: "Compile RTL"
run: ./compile_rtl.sh
- name: helper
run: ./helper.sh
All visibility rules apply across the entire package, including all fragments.
Task Listing Behavior Summary¶
Scope |
In Listing |
Cross-Pkg |
Direct Run |
|---|---|---|---|
root |
Yes |
Warning |
Yes |
export |
No |
Yes |
Yes |
[root, export] |
Yes |
Yes |
Yes |
local |
No |
No |
Limited |
(none) |
No |
Warning |
Yes |
In Listing: Shown by
dfm runwithout argumentsCross-Pkg: Can be referenced in
needsfrom another packageDirect Run: Can be executed by name