tasktree 0.0.17__tar.gz → 0.0.19__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. tasktree-0.0.19/.github/ISSUE_TEMPLATES/bug_report.yml +75 -0
  2. tasktree-0.0.19/.github/ISSUE_TEMPLATES/feature_request.yml +59 -0
  3. {tasktree-0.0.17 → tasktree-0.0.19}/.github/workflows/claude-code-review.yml +2 -0
  4. {tasktree-0.0.17 → tasktree-0.0.19}/PKG-INFO +217 -1
  5. {tasktree-0.0.17 → tasktree-0.0.19}/README.md +216 -0
  6. {tasktree-0.0.17 → tasktree-0.0.19}/pyproject.toml +1 -1
  7. {tasktree-0.0.17 → tasktree-0.0.19}/schema/README.md +6 -2
  8. {tasktree-0.0.17 → tasktree-0.0.19}/schema/tasktree-schema.json +53 -7
  9. {tasktree-0.0.17 → tasktree-0.0.19}/src/tasktree/__init__.py +2 -0
  10. {tasktree-0.0.17 → tasktree-0.0.19}/src/tasktree/cli.py +21 -5
  11. {tasktree-0.0.17 → tasktree-0.0.19}/src/tasktree/executor.py +28 -2
  12. {tasktree-0.0.17 → tasktree-0.0.19}/src/tasktree/graph.py +116 -1
  13. {tasktree-0.0.17 → tasktree-0.0.19}/src/tasktree/hasher.py +32 -3
  14. {tasktree-0.0.17 → tasktree-0.0.19}/src/tasktree/parser.py +134 -15
  15. {tasktree-0.0.17 → tasktree-0.0.19}/src/tasktree/substitution.py +82 -0
  16. {tasktree-0.0.17 → tasktree-0.0.19}/tasktree.yaml +1 -1
  17. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_builtin_variables.py +0 -8
  18. tasktree-0.0.19/tests/integration/test_dependency_outputs.py +313 -0
  19. tasktree-0.0.19/tests/integration/test_private_tasks_execution.py +264 -0
  20. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_list_formatting.py +61 -0
  21. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_parser.py +269 -0
  22. tasktree-0.0.19/tests/unit/test_private_tasks.py +141 -0
  23. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_substitution.py +203 -0
  24. {tasktree-0.0.17 → tasktree-0.0.19}/.claude/settings.local.json +0 -0
  25. {tasktree-0.0.17 → tasktree-0.0.19}/.github/workflows/claude.yml +0 -0
  26. {tasktree-0.0.17 → tasktree-0.0.19}/.github/workflows/release.yml +0 -0
  27. {tasktree-0.0.17 → tasktree-0.0.19}/.github/workflows/test.yml +0 -0
  28. {tasktree-0.0.17 → tasktree-0.0.19}/.github/workflows/validate-pipx-install.yml +0 -0
  29. {tasktree-0.0.17 → tasktree-0.0.19}/.gitignore +0 -0
  30. {tasktree-0.0.17 → tasktree-0.0.19}/.python-version +0 -0
  31. {tasktree-0.0.17 → tasktree-0.0.19}/CLAUDE.md +0 -0
  32. {tasktree-0.0.17 → tasktree-0.0.19}/example/source.txt +0 -0
  33. {tasktree-0.0.17 → tasktree-0.0.19}/example/tasktree.yaml +0 -0
  34. {tasktree-0.0.17 → tasktree-0.0.19}/schema/vscode-settings-snippet.json +0 -0
  35. {tasktree-0.0.17 → tasktree-0.0.19}/src/__init__.py +0 -0
  36. {tasktree-0.0.17 → tasktree-0.0.19}/src/tasktree/docker.py +0 -0
  37. {tasktree-0.0.17 → tasktree-0.0.19}/src/tasktree/state.py +0 -0
  38. {tasktree-0.0.17 → tasktree-0.0.19}/src/tasktree/types.py +0 -0
  39. {tasktree-0.0.17 → tasktree-0.0.19}/tests/e2e/__init__.py +0 -0
  40. {tasktree-0.0.17 → tasktree-0.0.19}/tests/e2e/test_docker_basic.py +0 -0
  41. {tasktree-0.0.17 → tasktree-0.0.19}/tests/e2e/test_docker_environment.py +0 -0
  42. {tasktree-0.0.17 → tasktree-0.0.19}/tests/e2e/test_docker_ownership.py +0 -0
  43. {tasktree-0.0.17 → tasktree-0.0.19}/tests/e2e/test_docker_volumes.py +0 -0
  44. {tasktree-0.0.17 → tasktree-0.0.19}/tests/e2e/test_non_docker.py +0 -0
  45. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_arg_choices.py +0 -0
  46. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_arg_min_max.py +0 -0
  47. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_clean_state.py +0 -0
  48. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_cli_options.py +0 -0
  49. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_dependency_execution.py +0 -0
  50. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_docker_build_args.py +0 -0
  51. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_end_to_end.py +0 -0
  52. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_exported_args.py +0 -0
  53. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_input_detection.py +0 -0
  54. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_missing_outputs.py +0 -0
  55. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_nested_imports.py +0 -0
  56. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_parameterized_dependencies.yaml +0 -0
  57. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_parameterized_deps_execution.py +0 -0
  58. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_parameterized_deps_templates.py +0 -0
  59. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_state_persistence.py +0 -0
  60. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_variables.py +0 -0
  61. {tasktree-0.0.17 → tasktree-0.0.19}/tests/integration/test_working_directory.py +0 -0
  62. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_cli.py +0 -0
  63. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_dependency_parsing.py +0 -0
  64. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_docker.py +0 -0
  65. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_environment_tracking.py +0 -0
  66. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_executor.py +0 -0
  67. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_graph.py +0 -0
  68. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_hasher.py +0 -0
  69. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_parameterized_graph.py +0 -0
  70. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_state.py +0 -0
  71. {tasktree-0.0.17 → tasktree-0.0.19}/tests/unit/test_types.py +0 -0
  72. {tasktree-0.0.17 → tasktree-0.0.19}/uv.lock +0 -0
@@ -0,0 +1,75 @@
1
+ name: Bug report
2
+ description: Create a report to help us improve
3
+ title: "[BUG] <describe bug>"
4
+ labels: [bug]
5
+ assignees: []
6
+ body:
7
+ - type: markdown
8
+ attributes:
9
+ value: |
10
+ **Please fill out as much of this form as possible. Incomplete reports may slow triage.**
11
+
12
+ - type: input
13
+ id: summary
14
+ attributes:
15
+ label: Bug Summary
16
+ description: Short summary of the bug (1-2 sentences).
17
+ placeholder: "Unexpected crash when saving file"
18
+
19
+ - type: textarea
20
+ id: steps
21
+ attributes:
22
+ label: Steps to Reproduce
23
+ description: Step-by-step description to reproduce the bug.
24
+ placeholder: |
25
+ 1. Open the application
26
+ 2. Click on "Save"
27
+ 3. Observe the error
28
+
29
+ - type: textarea
30
+ id: expected
31
+ attributes:
32
+ label: Expected Behavior
33
+ description: What did you expect to happen?
34
+ placeholder: App should save the file without errors.
35
+
36
+ - type: textarea
37
+ id: actual
38
+ attributes:
39
+ label: Actual Behavior
40
+ description: What actually happens?
41
+ placeholder: "Error dialog appears: 'Failed to save'."
42
+
43
+ - type: dropdown
44
+ id: system
45
+ attributes:
46
+ label: Environment
47
+ multiple: true
48
+ options:
49
+ - Linux (Debian-based)
50
+ - Linux (other)
51
+ - Windows
52
+ - macOS
53
+ - Other (please describe below)
54
+ description: Select all platforms where this bug occurs.
55
+
56
+ - type: input
57
+ id: version
58
+ attributes:
59
+ label: Version(s)
60
+ description: App and/or OS version numbers (paste output, e.g. `git describe`, `uname -a`, etc.)
61
+ placeholder: "v1.2.3, Debian 12.4, kernel 6.1.0..."
62
+
63
+ - type: textarea
64
+ id: logs
65
+ attributes:
66
+ label: Relevant Logs/Backtrace
67
+ description: Paste relevant logs, stack traces, or error messages. Use triple backticks for code.
68
+ render: shell
69
+
70
+ - type: textarea
71
+ id: extra
72
+ attributes:
73
+ label: Additional Context
74
+ description: Anything else useful for diagnosis? (Configurations, screenshots, external resources, etc.)
75
+ placeholder: "N/A"
@@ -0,0 +1,59 @@
1
+ name: Feature request
2
+ description: Suggest a new feature or improvement for this project
3
+ title: "[Feature] <concise feature title>"
4
+ labels: [enhancement]
5
+ assignees: []
6
+ body:
7
+ - type: markdown
8
+ attributes:
9
+ value: |
10
+ **Thanks for suggesting an improvement! Please provide as much context as possible.**
11
+
12
+ - type: input
13
+ id: summary
14
+ attributes:
15
+ label: Feature Summary
16
+ description: Short, high-level summary of the requested feature.
17
+ placeholder: "Add support for IPv6 packet inspection"
18
+
19
+ - type: textarea
20
+ id: motivation
21
+ attributes:
22
+ label: Motivation & Use Case
23
+ description: What problem does this solve? Who benefits? Why is this needed?
24
+ placeholder: |
25
+ Currently, only IPv4 is supported in the firewall module. Many environments use IPv6 and need equivalent inspection features.
26
+
27
+ - type: textarea
28
+ id: description
29
+ attributes:
30
+ label: Feature Description & Requirements
31
+ description: Describe the change or new capability. List any requirements or constraints.
32
+ placeholder: |
33
+ - Support parsing and filtering of IPv6 packets in filter mode.
34
+ - Update UI to allow IPv6 rule specification.
35
+ - Follow current module design patterns.
36
+
37
+ - type: textarea
38
+ id: impact
39
+ attributes:
40
+ label: Impact/Alternatives
41
+ description: How does this improve the project? Are there workarounds or competing solutions?
42
+ placeholder: |
43
+ Improves feature parity with other products; current workaround requires separate external processing.
44
+
45
+ - type: textarea
46
+ id: implementation
47
+ attributes:
48
+ label: Implementation notes (optional)
49
+ description: If you have ideas about implementing this, list them here (API ideas, design notes, related RFCs, etc.)
50
+ placeholder: |
51
+ - May require libc updates (for older distros)
52
+ - Reference: RFC 8200
53
+
54
+ - type: textarea
55
+ id: extra
56
+ attributes:
57
+ label: Additional context
58
+ description: Add any other context, mockups, references, or screenshots here.
59
+ placeholder: "N/A"
@@ -48,6 +48,8 @@ jobs:
48
48
  - Test coverage
49
49
 
50
50
  Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback.
51
+
52
+ At the end of the review, create a tickbox list of the actions arising from the review, suitable for pasting into a comment for Claude Code to work on.
51
53
 
52
54
  Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR.
53
55
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tasktree
3
- Version: 0.0.17
3
+ Version: 0.0.19
4
4
  Summary: A task automation tool with incremental execution
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: click>=8.1.0
@@ -248,6 +248,7 @@ tasks:
248
248
  outputs: [dist/binary] # Output files (glob patterns)
249
249
  working_dir: subproject/ # Execution directory (default: project root)
250
250
  env: bash-strict # Execution environment (optional)
251
+ private: false # Hide from --list output (default: false)
251
252
  args: # Task parameters
252
253
  - param1 # Simple argument
253
254
  - param2: { type: path, default: "." } # With type and default
@@ -687,6 +688,185 @@ tasks:
687
688
  cmd: echo "All tests passed"
688
689
  ```
689
690
 
691
+ ### Dependency Output References
692
+
693
+ Tasks can reference named outputs from their dependencies, enabling dynamic workflows where build artifacts, generated filenames, and other values are passed between tasks.
694
+
695
+ **Named Outputs:**
696
+
697
+ Tasks can define outputs with names for easy referencing:
698
+
699
+ ```yaml
700
+ tasks:
701
+ build:
702
+ outputs:
703
+ - bundle: "dist/app.js" # Named output
704
+ - sourcemap: "dist/app.js.map" # Named output
705
+ cmd: webpack build
706
+
707
+ deploy:
708
+ deps: [build]
709
+ cmd: |
710
+ echo "Deploying {{ dep.build.outputs.bundle }}"
711
+ scp {{ dep.build.outputs.bundle }} server:/var/www/
712
+ scp {{ dep.build.outputs.sourcemap }} server:/var/www/
713
+ ```
714
+
715
+ **Syntax:**
716
+
717
+ - **Defining named outputs**: `outputs: [{ name: "path/to/file" }]`
718
+ - **Referencing outputs**: `{{ dep.task_name.outputs.output_name }}`
719
+ - **Mixed format**: Can combine named and anonymous outputs in the same task
720
+
721
+ **Examples:**
722
+
723
+ ```yaml
724
+ tasks:
725
+ # Generate a config file
726
+ generate-config:
727
+ outputs:
728
+ - config: "build/config.json"
729
+ cmd: |
730
+ mkdir -p build
731
+ echo '{"version": "1.0.0"}' > build/config.json
732
+
733
+ # Compile using the generated config
734
+ compile:
735
+ deps: [generate-config]
736
+ outputs:
737
+ - binary: "build/app"
738
+ - symbols: "build/app.sym"
739
+ cmd: |
740
+ echo "Using config: {{ dep.generate-config.outputs.config }}"
741
+ gcc -o build/app src/*.c
742
+
743
+ # Package multiple dependency outputs
744
+ package:
745
+ deps: [compile]
746
+ outputs:
747
+ - archive: "dist/app.tar.gz"
748
+ cmd: |
749
+ mkdir -p dist
750
+ tar czf {{ dep.package.outputs.archive }} \
751
+ {{ dep.compile.outputs.binary }} \
752
+ {{ dep.compile.outputs.symbols }}
753
+ ```
754
+
755
+ **Mixed Named and Anonymous Outputs:**
756
+
757
+ Tasks can have both named and anonymous outputs:
758
+
759
+ ```yaml
760
+ tasks:
761
+ build:
762
+ outputs:
763
+ - binary: "build/app" # Named - can be referenced
764
+ - "build/app.debug" # Anonymous - tracked but not referenceable
765
+ - manifest: "build/manifest.json" # Named - can be referenced
766
+ cmd: make all
767
+ ```
768
+
769
+ **Transitive References:**
770
+
771
+ Output references work across multiple levels of dependencies:
772
+
773
+ ```yaml
774
+ tasks:
775
+ base:
776
+ outputs:
777
+ - lib: "out/libbase.a"
778
+ cmd: gcc -c base.c -o out/libbase.a
779
+
780
+ middleware:
781
+ deps: [base]
782
+ outputs:
783
+ - lib: "out/libmiddleware.a"
784
+ cmd: |
785
+ # Reference the base library
786
+ gcc -c middleware.c {{ dep.base.outputs.lib }} -o out/libmiddleware.a
787
+
788
+ app:
789
+ deps: [middleware]
790
+ cmd: |
791
+ # Reference middleware, which transitively used base
792
+ gcc main.c {{ dep.middleware.outputs.lib }} -o app
793
+ ```
794
+
795
+ **Key Behaviors:**
796
+
797
+ - **Template resolution**: Output references are resolved during dependency graph planning (in topological order)
798
+ - **Fail-fast validation**: Errors are caught before execution begins
799
+ - **Clear error messages**: If an output name doesn't exist, you get a list of available named outputs
800
+ - **Backward compatible**: Existing anonymous outputs (`outputs: ["file.txt"]`) work unchanged
801
+ - **Automatic input tracking**: Named outputs are automatically tracked as implicit inputs for dependent tasks
802
+
803
+ **Error Messages:**
804
+
805
+ If you reference a non-existent output:
806
+
807
+ ```yaml
808
+ tasks:
809
+ build:
810
+ outputs:
811
+ - bundle: "dist/app.js"
812
+ cmd: webpack build
813
+
814
+ deploy:
815
+ deps: [build]
816
+ cmd: echo "{{ dep.build.outputs.missing }}" # Error!
817
+ ```
818
+
819
+ You'll get a clear error before execution:
820
+
821
+ ```
822
+ Task 'deploy' references output 'missing' from task 'build',
823
+ but 'build' has no output named 'missing'.
824
+ Available named outputs in 'build': bundle
825
+ Hint: Define named outputs like: outputs: [{ missing: 'path/to/file' }]
826
+ ```
827
+
828
+ **Use Cases:**
829
+
830
+ - **Dynamic artifact names**: Pass generated filenames between tasks
831
+ - **Build metadata**: Reference manifests, checksums, or version files
832
+ - **Multi-stage builds**: Chain compilation steps with specific output references
833
+ - **Deployment pipelines**: Reference exact artifacts to deploy
834
+ - **Configuration propagation**: Pass generated config files through build stages
835
+
836
+
837
+ ### Private Tasks
838
+
839
+ Sometimes you may want to define helper tasks that are useful as dependencies but shouldn't be listed when users run `tt --list`. Mark these tasks as private:
840
+
841
+ ```yaml
842
+ tasks:
843
+ # Private helper task - hidden from --list
844
+ setup-deps:
845
+ private: true
846
+ cmd: |
847
+ npm install
848
+ pip install -r requirements.txt
849
+
850
+ # Public task that uses the helper
851
+ build:
852
+ deps: [setup-deps]
853
+ cmd: npm run build
854
+ ```
855
+
856
+ **Behavior:**
857
+ - `tt --list` shows only public tasks (`build` in this example)
858
+ - Private tasks can still be executed: `tt setup-deps` works
859
+ - Private tasks work normally as dependencies
860
+ - By default, all tasks are public (`private: false`)
861
+
862
+ **Use cases:**
863
+ - Internal helper tasks that shouldn't be run directly
864
+ - Implementation details you want to hide from users
865
+ - Shared setup tasks across multiple public tasks
866
+
867
+ Note that private tasks remain fully functional - they're only hidden from the list view. Users who know the task name can still execute it directly.
868
+
869
+
690
870
  ## Environment Variables
691
871
 
692
872
  Task Tree supports reading environment variables in two ways:
@@ -1028,6 +1208,42 @@ At the start of each invocation, state is checked for invalid task hashes and no
1028
1208
 
1029
1209
  Task Tree provides several command-line options for controlling task execution:
1030
1210
 
1211
+ ### Recipe File Selection
1212
+
1213
+ Task Tree automatically discovers recipe files in the current directory and parent directories. You can also explicitly specify which file to use.
1214
+
1215
+ **Automatic Discovery:**
1216
+
1217
+ Task Tree searches for recipe files in the following order of preference:
1218
+
1219
+ 1. **Standard recipe files** (searched first, in order):
1220
+ - `tasktree.yaml`
1221
+ - `tasktree.yml`
1222
+ - `tt.yaml`
1223
+
1224
+ 2. **Import files** (searched only if no standard files found):
1225
+ - `*.tasks` files (e.g., `build.tasks`, `deploy.tasks`)
1226
+
1227
+ If multiple files of the same priority level exist in the same directory, Task Tree will report an error and ask you to specify which file to use with `--tasks`.
1228
+
1229
+ **Manual Selection:**
1230
+
1231
+ ```bash
1232
+ # Specify a recipe file explicitly
1233
+ tt --tasks build.tasks build
1234
+ tt -T custom-recipe.yaml test
1235
+
1236
+ # Useful when you have multiple recipe files in the same directory
1237
+ tt --tasks ci.yaml deploy
1238
+ ```
1239
+
1240
+ **File Search Behavior:**
1241
+
1242
+ - Task Tree searches **upward** from the current directory to find recipe files
1243
+ - **Standard recipe files** (`.yaml`/`.yml`) are always preferred over `*.tasks` files
1244
+ - `*.tasks` files are typically used for imports and are only used as main recipes if no standard files exist
1245
+ - The `.tasktree-state` file is created in the directory containing the recipe file
1246
+
1031
1247
  ### Execution Control
1032
1248
 
1033
1249
  ```bash
@@ -233,6 +233,7 @@ tasks:
233
233
  outputs: [dist/binary] # Output files (glob patterns)
234
234
  working_dir: subproject/ # Execution directory (default: project root)
235
235
  env: bash-strict # Execution environment (optional)
236
+ private: false # Hide from --list output (default: false)
236
237
  args: # Task parameters
237
238
  - param1 # Simple argument
238
239
  - param2: { type: path, default: "." } # With type and default
@@ -672,6 +673,185 @@ tasks:
672
673
  cmd: echo "All tests passed"
673
674
  ```
674
675
 
676
+ ### Dependency Output References
677
+
678
+ Tasks can reference named outputs from their dependencies, enabling dynamic workflows where build artifacts, generated filenames, and other values are passed between tasks.
679
+
680
+ **Named Outputs:**
681
+
682
+ Tasks can define outputs with names for easy referencing:
683
+
684
+ ```yaml
685
+ tasks:
686
+ build:
687
+ outputs:
688
+ - bundle: "dist/app.js" # Named output
689
+ - sourcemap: "dist/app.js.map" # Named output
690
+ cmd: webpack build
691
+
692
+ deploy:
693
+ deps: [build]
694
+ cmd: |
695
+ echo "Deploying {{ dep.build.outputs.bundle }}"
696
+ scp {{ dep.build.outputs.bundle }} server:/var/www/
697
+ scp {{ dep.build.outputs.sourcemap }} server:/var/www/
698
+ ```
699
+
700
+ **Syntax:**
701
+
702
+ - **Defining named outputs**: `outputs: [{ name: "path/to/file" }]`
703
+ - **Referencing outputs**: `{{ dep.task_name.outputs.output_name }}`
704
+ - **Mixed format**: Can combine named and anonymous outputs in the same task
705
+
706
+ **Examples:**
707
+
708
+ ```yaml
709
+ tasks:
710
+ # Generate a config file
711
+ generate-config:
712
+ outputs:
713
+ - config: "build/config.json"
714
+ cmd: |
715
+ mkdir -p build
716
+ echo '{"version": "1.0.0"}' > build/config.json
717
+
718
+ # Compile using the generated config
719
+ compile:
720
+ deps: [generate-config]
721
+ outputs:
722
+ - binary: "build/app"
723
+ - symbols: "build/app.sym"
724
+ cmd: |
725
+ echo "Using config: {{ dep.generate-config.outputs.config }}"
726
+ gcc -o build/app src/*.c
727
+
728
+ # Package multiple dependency outputs
729
+ package:
730
+ deps: [compile]
731
+ outputs:
732
+ - archive: "dist/app.tar.gz"
733
+ cmd: |
734
+ mkdir -p dist
735
+ tar czf {{ dep.package.outputs.archive }} \
736
+ {{ dep.compile.outputs.binary }} \
737
+ {{ dep.compile.outputs.symbols }}
738
+ ```
739
+
740
+ **Mixed Named and Anonymous Outputs:**
741
+
742
+ Tasks can have both named and anonymous outputs:
743
+
744
+ ```yaml
745
+ tasks:
746
+ build:
747
+ outputs:
748
+ - binary: "build/app" # Named - can be referenced
749
+ - "build/app.debug" # Anonymous - tracked but not referenceable
750
+ - manifest: "build/manifest.json" # Named - can be referenced
751
+ cmd: make all
752
+ ```
753
+
754
+ **Transitive References:**
755
+
756
+ Output references work across multiple levels of dependencies:
757
+
758
+ ```yaml
759
+ tasks:
760
+ base:
761
+ outputs:
762
+ - lib: "out/libbase.a"
763
+ cmd: gcc -c base.c -o out/libbase.a
764
+
765
+ middleware:
766
+ deps: [base]
767
+ outputs:
768
+ - lib: "out/libmiddleware.a"
769
+ cmd: |
770
+ # Reference the base library
771
+ gcc -c middleware.c {{ dep.base.outputs.lib }} -o out/libmiddleware.a
772
+
773
+ app:
774
+ deps: [middleware]
775
+ cmd: |
776
+ # Reference middleware, which transitively used base
777
+ gcc main.c {{ dep.middleware.outputs.lib }} -o app
778
+ ```
779
+
780
+ **Key Behaviors:**
781
+
782
+ - **Template resolution**: Output references are resolved during dependency graph planning (in topological order)
783
+ - **Fail-fast validation**: Errors are caught before execution begins
784
+ - **Clear error messages**: If an output name doesn't exist, you get a list of available named outputs
785
+ - **Backward compatible**: Existing anonymous outputs (`outputs: ["file.txt"]`) work unchanged
786
+ - **Automatic input tracking**: Named outputs are automatically tracked as implicit inputs for dependent tasks
787
+
788
+ **Error Messages:**
789
+
790
+ If you reference a non-existent output:
791
+
792
+ ```yaml
793
+ tasks:
794
+ build:
795
+ outputs:
796
+ - bundle: "dist/app.js"
797
+ cmd: webpack build
798
+
799
+ deploy:
800
+ deps: [build]
801
+ cmd: echo "{{ dep.build.outputs.missing }}" # Error!
802
+ ```
803
+
804
+ You'll get a clear error before execution:
805
+
806
+ ```
807
+ Task 'deploy' references output 'missing' from task 'build',
808
+ but 'build' has no output named 'missing'.
809
+ Available named outputs in 'build': bundle
810
+ Hint: Define named outputs like: outputs: [{ missing: 'path/to/file' }]
811
+ ```
812
+
813
+ **Use Cases:**
814
+
815
+ - **Dynamic artifact names**: Pass generated filenames between tasks
816
+ - **Build metadata**: Reference manifests, checksums, or version files
817
+ - **Multi-stage builds**: Chain compilation steps with specific output references
818
+ - **Deployment pipelines**: Reference exact artifacts to deploy
819
+ - **Configuration propagation**: Pass generated config files through build stages
820
+
821
+
822
+ ### Private Tasks
823
+
824
+ Sometimes you may want to define helper tasks that are useful as dependencies but shouldn't be listed when users run `tt --list`. Mark these tasks as private:
825
+
826
+ ```yaml
827
+ tasks:
828
+ # Private helper task - hidden from --list
829
+ setup-deps:
830
+ private: true
831
+ cmd: |
832
+ npm install
833
+ pip install -r requirements.txt
834
+
835
+ # Public task that uses the helper
836
+ build:
837
+ deps: [setup-deps]
838
+ cmd: npm run build
839
+ ```
840
+
841
+ **Behavior:**
842
+ - `tt --list` shows only public tasks (`build` in this example)
843
+ - Private tasks can still be executed: `tt setup-deps` works
844
+ - Private tasks work normally as dependencies
845
+ - By default, all tasks are public (`private: false`)
846
+
847
+ **Use cases:**
848
+ - Internal helper tasks that shouldn't be run directly
849
+ - Implementation details you want to hide from users
850
+ - Shared setup tasks across multiple public tasks
851
+
852
+ Note that private tasks remain fully functional - they're only hidden from the list view. Users who know the task name can still execute it directly.
853
+
854
+
675
855
  ## Environment Variables
676
856
 
677
857
  Task Tree supports reading environment variables in two ways:
@@ -1013,6 +1193,42 @@ At the start of each invocation, state is checked for invalid task hashes and no
1013
1193
 
1014
1194
  Task Tree provides several command-line options for controlling task execution:
1015
1195
 
1196
+ ### Recipe File Selection
1197
+
1198
+ Task Tree automatically discovers recipe files in the current directory and parent directories. You can also explicitly specify which file to use.
1199
+
1200
+ **Automatic Discovery:**
1201
+
1202
+ Task Tree searches for recipe files in the following order of preference:
1203
+
1204
+ 1. **Standard recipe files** (searched first, in order):
1205
+ - `tasktree.yaml`
1206
+ - `tasktree.yml`
1207
+ - `tt.yaml`
1208
+
1209
+ 2. **Import files** (searched only if no standard files found):
1210
+ - `*.tasks` files (e.g., `build.tasks`, `deploy.tasks`)
1211
+
1212
+ If multiple files of the same priority level exist in the same directory, Task Tree will report an error and ask you to specify which file to use with `--tasks`.
1213
+
1214
+ **Manual Selection:**
1215
+
1216
+ ```bash
1217
+ # Specify a recipe file explicitly
1218
+ tt --tasks build.tasks build
1219
+ tt -T custom-recipe.yaml test
1220
+
1221
+ # Useful when you have multiple recipe files in the same directory
1222
+ tt --tasks ci.yaml deploy
1223
+ ```
1224
+
1225
+ **File Search Behavior:**
1226
+
1227
+ - Task Tree searches **upward** from the current directory to find recipe files
1228
+ - **Standard recipe files** (`.yaml`/`.yml`) are always preferred over `*.tasks` files
1229
+ - `*.tasks` files are typically used for imports and are only used as main recipes if no standard files exist
1230
+ - The `.tasktree-state` file is created in the directory containing the recipe file
1231
+
1016
1232
  ### Execution Control
1017
1233
 
1018
1234
  ```bash
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tasktree"
3
- version = "0.0.17"
3
+ version = "0.0.19"
4
4
  description = "A task automation tool with incremental execution"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -44,7 +44,7 @@ tasks:
44
44
  - **Name**: Task Tree
45
45
  - **Schema file**: Point to `schema/tasktree-schema.json`
46
46
  - **Schema version**: JSON Schema version 7
47
- - **File path pattern**: `tasktree.yaml` or `tt.yaml`
47
+ - **File path pattern**: `*.tasks`, `tasktree.yaml`, `tt.yaml`, `tasktree.yml` or `tt.yml`
48
48
 
49
49
  ### Command Line Validation
50
50
 
@@ -86,7 +86,9 @@ tasks:
86
86
  desc: Build the application
87
87
  deps: [base.setup]
88
88
  inputs: ["src/**/*.rs"]
89
- outputs: [target/release/bin]
89
+ outputs:
90
+ - binary: target/release/bin # Named output - can be referenced
91
+ - target/release/bin.map # Anonymous output
90
92
  cmd: cargo build --release
91
93
 
92
94
  test:
@@ -100,6 +102,8 @@ tasks:
100
102
  args: [environment, region=us-west-1]
101
103
  cmd: |
102
104
  echo "Deploying to {{ arg.environment }} in {{ arg.region }}"
105
+ # Reference named output from dependency
106
+ scp {{ dep.build.outputs.binary }} server:/opt/
103
107
  ./deploy.sh {{ arg.environment }} {{ arg.region }}
104
108
  ```
105
109