feat: artifact pipeline — typed artifact flow between workflow stages (v0.7.0) - #111
Conversation
…or prompt steps
Add artifact_glob and artifact_name fields to Prompt workflow steps, enabling
typed artifact flow between pipeline stages. After a skill completes, tutti
globs for new files, captures the newest, and registers it as a step output
available to downstream steps via {{output.step_id.path}} templates.
Key capabilities:
- Pre-step snapshot prevents race conditions with concurrent runs
- inject_files supports {{output.step_id.path}} template expansion
- Variable interpolation: {slug}, {workspace}, {agent}, ~ in glob patterns
- Config validation: requires wait_for_idle, valid artifact_name chars, paired fields
- gstack-slug integration for {slug} resolution
- 15 new tests covering all codepaths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show artifact_glob and artifact_name in dry-run table and JSON output.
Validate gstack-slug availability at dry-run time when {slug} is used
in artifact_glob patterns.
Show artifact names as labels on pipeline flow connectors during active workflow runs. Labels appear above the connector line between stages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThis PR introduces artifact-carrying behavior across workflow stages. Steps can now capture files matching a glob pattern (with variable expansion) and register them as outputs, which downstream steps can reference in file injection and templates. Changes include configuration schema additions, executor-level snapshotting and capture logic, dry-run validation, and dashboard visualization of artifacts between stages. Changes
Sequence DiagramsequenceDiagram
participant Executor
participant FileSystem as File System
participant OutputRegistry as Output Registry
participant Dashboard
Executor->>FileSystem: Snapshot files matching artifact_glob (pre-step)
Note over Executor,FileSystem: Expand variables: ~, {workspace}, {agent}, {slug}
Executor->>Executor: Execute prompt step
Executor->>FileSystem: Scan for new files matching expanded glob (post-step)
FileSystem-->>Executor: Return newest matching file
Executor->>OutputRegistry: Register artifact as step output<br/>(JSON + .raw copy)
OutputRegistry-->>Executor: Output stored
Executor->>Dashboard: Emit step.started event with artifact_name
Dashboard->>Dashboard: Query artifactBetweenStages(prevStage, stage)
Dashboard->>Dashboard: Render artifact label on pipeline connector
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@CHANGELOG.md`:
- Around line 6-12: The changelog uses inconsistent terminology and a mismatched
template key; update the Artifact Pipeline entry to consistently refer to
"skill" (not "prompt steps") and change the template example to the README's
placeholder style by using the `artifact_name` key (and keep `artifact_glob` and
`artifact_name` symbol names intact); also update the inject_files line to show
the supported template reference using `{{output.artifact_name.path}}` and
ensure both descriptions reference "skill" and the `artifact_name` placeholder
consistently so operators know which key to use.
In `@dashboard/app.js`:
- Around line 130-148: artifactBetweenStages currently inspects every run in
appState.runs and can return artifact labels from terminal runs; update the
function to skip any run whose status is not "running" by checking run.status
=== "running" (or !== "running" to continue) before iterating run.steps in
artifactBetweenStages so only active runs contribute labels.
In `@dashboard/style.css`:
- Around line 141-153: The .artifact-label rule uses an incorrect CSS variable
name; replace var(--mono) with the defined variable var(--font-mono) in the
.artifact-label font-family declaration so the label uses the JetBrains Mono
font; update the font-family in the .artifact-label selector accordingly.
In `@README.md`:
- Line 267: The README documents the artifact output interpolation as
{{output.artifact_name.path}} but the changelog uses {{output.step_id.path}},
which will confuse users; update the README text to use the canonical key format
used by the codebase (choose either {{output.artifact_name.path}} or
{{output.step_id.path}}) or explicitly state both supported forms and when to
use each, and ensure the example inject_files snippet and the surrounding
sentence reference the exact template key you choose so docs and changelog
match.
In `@src/automation/mod.rs`:
- Around line 2548-2584: store_artifact_output currently saves a JSON wrapper to
canonical_path and copies the raw artifact to raw_path but returns
StepOutputValue.path = canonical_path, so render_template/inject_files will pick
the JSON wrapper instead of the raw artifact; change the returned/exposed path
to the raw artifact by setting StepOutputValue.path to raw_path (while still
calling save_workflow_output and keeping canonical_path for the persisted JSON),
e.g. keep json_value and canonical_path as-is, perform the std::fs::copy to
produce raw_path, and then return StepOutputValue { path: raw_path, json:
json_value } so {{output.<name>.path}} refers to the raw file that downstream
inject_files should copy.
- Around line 1486-1546: The artifact capture/store logic (using
capture_artifact and store_artifact_output and updating outputs, output_files,
step_results, failed_steps, and success) must be extracted into a small helper
(e.g., capture_and_store_artifact) that accepts the run context (run_id,
step_index, started, artifact_pre_snapshot, artifact_name, project_root, etc.)
and returns a Result<saved_artifact_info, failure_marker>; implement the helper
to perform the sleep, call capture_artifact(expanded_pattern, pre_snap), call
store_artifact_output(self.project_root, &run_id, art_name, &artifact_path),
update outputs/output_files on success or push to failed_steps/step_results and
set success=false on error (constructing the same StepResult shape used
elsewhere); then call this helper from every early-success exit path (the
success continue at the prompt fallthrough and the implement_code
auto-finalization success branches) before returning/continuing so every
successful prompt path registers artifacts.
- Around line 6078-6097: The test
gstack_slug_missing_binary_returns_actionable_error mutates the process HOME and
introduces race conditions; change resolve_gstack_slug to accept an injectable
home directory (e.g., fn resolve_gstack_slug(home: impl AsRef<Path>) ->
Result<...>) or an Option<&Path> defaulting to env::var("HOME") when None,
update all call sites to pass either the real HOME or a test-supplied
non-existent path, and modify the test to call
resolve_gstack_slug("/nonexistent-path-for-test") instead of setting the HOME
env var; ensure signature and uses are updated consistently across the module
and propagate the new parameter through helper functions that locate the
gstack-slug binary.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: aadb3d98-c5aa-4ab3-bf45-4b85da15cbec
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (8)
CHANGELOG.mdCargo.tomlREADME.mddashboard/app.jsdashboard/style.csssrc/automation/mod.rssrc/cli/run.rssrc/config/mod.rs
- Fix terminology in CHANGELOG (skill -> prompt step) and template key (step_id -> artifact_name) - Skip non-running runs in dashboard artifact label derivation - Fix CSS variable typo (--mono -> --font-mono) - Align README artifact docs terminology with changelog - Run artifact capture before every prompt success early exit - Expose raw artifact path via output.<name>.path instead of JSON path - Refactor resolve_gstack_slug() to accept injectable home dir param, removing unsafe env mutation from tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: artifact pipeline — glob-based artifact capture and injection for prompt steps
Add artifact_glob and artifact_name fields to Prompt workflow steps, enabling
typed artifact flow between pipeline stages. After a skill completes, tutti
globs for new files, captures the newest, and registers it as a step output
available to downstream steps via {{output.step_id.path}} templates.
Key capabilities:
- Pre-step snapshot prevents race conditions with concurrent runs
- inject_files supports {{output.step_id.path}} template expansion
- Variable interpolation: {slug}, {workspace}, {agent}, ~ in glob patterns
- Config validation: requires wait_for_idle, valid artifact_name chars, paired fields
- gstack-slug integration for {slug} resolution
- 15 new tests covering all codepaths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: dry-run display and validation for artifact pipeline
Show artifact_glob and artifact_name in dry-run table and JSON output.
Validate gstack-slug availability at dry-run time when {slug} is used
in artifact_glob patterns.
* feat: dashboard artifact edge labels on flow connectors
Show artifact names as labels on pipeline flow connectors during active
workflow runs. Labels appear above the connector line between stages.
* chore: bump version and changelog (v0.7.0)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: document artifact pipeline in README
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address CodeRabbit review comments on PR #111
- Fix terminology in CHANGELOG (skill -> prompt step) and template key
(step_id -> artifact_name)
- Skip non-running runs in dashboard artifact label derivation
- Fix CSS variable typo (--mono -> --font-mono)
- Align README artifact docs terminology with changelog
- Run artifact capture before every prompt success early exit
- Expose raw artifact path via output.<name>.path instead of JSON path
- Refactor resolve_gstack_slug() to accept injectable home dir param,
removing unsafe env mutation from tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use startup_grace_secs for prompt activity timeout instead of hardcoded 20s
The prompt activity check used a hardcoded 20s timeout which was too short
for Claude Code + gstack skill startup. Now uses max(startup_grace_secs, 20s).
Also adds sdlc-gstack workflow to tutti.toml with artifact pipeline flow
and bumps /office-hours startup_grace to 120s for gstack preamble overhead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: artifact-polling mode, permissions fixes, dashboard race condition
- Artifact-polling mode: when artifact_glob is set without wait_for_idle,
tutti polls for the artifact file instead of idle-detecting. Supports
interactive gstack skills (e.g. /office-hours) where the agent waits
for human input.
- Add Skill and AskUserQuestion to CLAUDE_TOOL_NAMES for dontAsk mode
- Fix dashboard focus sidebar race condition where fast poll overwrote
usage stats with zeros from empty response
- Update sdlc-gstack workflow to use artifact-polling for design/eng_review
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: v0.8.0 template packs + role mapping
Add template pack format, `tt init --template <name>`, role-to-runtime
mapping, repo detection, and 3 starter templates (gstack-startup,
rust-cli, minimal). Template-tagged event stream for future telemetry.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add sdlc-gstack workflow to gstack-startup template, use BTreeMap for roles
Addresses tester review feedback:
- gstack-startup template was missing the sdlc-gstack and sdlc-auto workflows
that the design doc specified as "batteries included"
- Role display in `tt init` used HashMap with non-deterministic iteration order;
switched to BTreeMap for consistent alphabetical output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: format automation/mod.rs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address 16 CodeRabbit review comments on PR #113
- Persist resumable JSON path (not raw artifact path) in output_files for
checkpoint/resume compatibility
- Abort prompt step with a clear error when session dies without producing
an artifact
- Surface a validation error instead of masking unresolved runtime as
"unknown" in tt detect
- Register the generated workspace name (not directory basename) in global
config during tt init
- Replace unwrap() calls with fallible error propagation in tt init fallback
paths
- Make resolved_runtime crate-private (pub(crate))
- Add actionable remediation guidance to TemplateParse and TemplateNotFound
error messages
- Make parse_template_tag return Result, propagating IO errors instead of
collapsing to (None, None)
- Reject partial/empty template tags (missing version or empty id)
- Use temp-dir path in nonexistent-file test for cross-platform safety
- Make generate_config fallible, validating rendered TOML before returning
- Narrow gstack-startup template detect to Cargo.toml only (matches the
cargo test validation step)
- Rename implement step id to implement_code for merge-gate enforcement
- Run validation step in implementer worktree (.tutti/worktrees/implementer)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
artifact_globandartifact_namefields{{output.step_id.path}}references allow artifacts from prior steps to be injected into downstream agents{slug}is used in artifact_glob{slug},{workspace},{agent},~expanded in glob patternsTest Coverage
All new code paths have test coverage. 15 new tests added (326 → 341).
Pre-Landing Review
8 issues found and auto-fixed during /review:
Adversarial Review
Large-tier (840 lines): Claude structured + Codex structured + Claude adversarial + Codex adversarial.
All high-confidence findings addressed (Codex P1-P3 + Claude #2,5,6,8,9).
Test plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
{slug},{workspace},{agent}, and~(home directory).Documentation