{% extends "base.html" %} {% block title %}Workflows{% endblock %} {% block content %}

Workflows

{{ workflows|length }} registered. {% if allow_run %} Click Run to execute one. Output streams below. {% else %} Read-only mode — restart without --read-only to run from the dashboard. {% endif %}

{% if workflows %} {% if allow_run %}{% endif %} {% for w in workflows %} {# data-scope-default carries the first-paint default scope for this workflow, auto-derived server-side from features.yaml. runner.js reads it on DOMContentLoaded if localStorage has no saved scope. Empty string means "project-wide is the default" — explicitly chosen for workflows like release-prep / health-check that don't map to a single feature. #} {# Chip text: humanized stage name + friendly tier descriptor. - Stage names like ``agent-review`` strip the ``agent-`` prefix and title-case for readability (``Review``). - Tier names like ``capable`` map through TIER_LABEL to ``Standard``; the underlying Claude model class is surfaced in the tooltip via TIER_TOOLTIP so the chip stays compact while the hover affordance carries the detail. #} {# Scope cell renders in both run and read-only modes (AC-6). In read-only mode the picker still pre-selects the saved scope so the choice persists for when the user enables runs; only the Action column hides. #} {% if allow_run %} {% endif %} {% endfor %}
Name Tier map Description ScopeAction
{{ w.name }} {% for stage, tier in w.tier_map.items() %} {% set stage_label = stage.replace('agent-', '').replace('-', ' ').replace('_', ' ').title() %} {{ stage_label }} {{ tier_label.get(tier|lower, tier) }} {% endfor %} {% if not w.tier_map %} {% endif %} {{ w.description }}
{% if w.name == "discovery-sweep" %} {# Phase 3 chips. Server-rendered for first paint; runner.js refreshes them on scope-picker change via /api/workflows/discovery-sweep/chips. Anchor hrefs link to the scope-keyed detail page filtered by bucket. #}
queue: {{ sweep_chips.queue }} questions: {{ sweep_chips.questions }} rejected: {{ sweep_chips.rejected }} {% if sweep_chips.has_result %}latest result{% else %}no sweep recorded for this scope yet{% endif %}
{% endif %}
{% if supports_path[w.name] %} {% else %} n/a {% endif %}
{% else %}

No workflows are visible. Make sure attune-ai is installed in the same venv as attune-ops.

{% endif %} {% endblock %} {% block scripts %} {# Server-injected workspace root, read by runner.js to validate that a saved scope from localStorage is still under this workspace (catches stale scopes from a different worktree). The old firstFeaturePath / allCodePath fields used to live here too but moved to per-row ``data-scope-default`` attributes (rendered above) so each workflow can default to its own most-relevant scope. #} {# runner.js is loaded unconditionally so the recent-runs strip renders in both run and read-only modes. The script's DOMContentLoaded handler queries for run-button / scope-picker elements that only exist when allow_run is True, so the read-only page sees a no-op for those features. #} {% endblock %}