Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
# Changelog

## [0.9.0] - 2026-03-23

### Added
- **Interactive `tt init`**: Progressive disclosure bootstrap — auto-detects repo
type, shows a team preview table ("character creation screen"), then offers
Launch / Customize / Quit. One command to working agents.
- **Customize mode**: Swap runtimes for roles, remove agents, change project name
— all with a live preview that re-renders after each change.
- **Auto-launch**: Press L during `tt init` to write config and immediately launch
all agents via `tt up`.
- **Re-init with backup**: Running `tt init` when tutti.toml exists offers to back
up the existing config instead of refusing.
- **Node.js template** (`node-fullstack`): 4-agent team with frontend/backend split,
detects `package.json`, includes sdlc-gstack workflow.
- **Python template** (`python-api`): 3-agent team, detects `pyproject.toml` and
`requirements.txt`, includes simplified sdlc-gstack workflow with pytest.
- **`tt template list`**: New subcommand showing all built-in and custom templates
with detection rules and descriptions.
- **Custom template discovery**: Place `.toml` template files in
`~/.config/tutti/templates/` — they're auto-discovered and participate in repo
detection scoring.
- **Run telemetry**: After each `tt run` completes, step-level timing and pass/fail
data is emitted to `.tutti/state/run-telemetry.jsonl` for future evidence-backed
template comparison.
- **`InputSource` trait**: Interactive prompts are testable via mock input — enables
full coverage of the init flow without stdin.

### Fixed
- EOF stdin no longer causes infinite loop in interactive prompts — returns default
on EOF or read error.
- Template detection scoring unified: `detect_templates` and custom template
discovery now use the same `score_template_detection` function.
- Negative telemetry durations clamped to zero.

## [0.8.1] - 2026-03-23

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tutti"
version = "0.8.1"
version = "0.9.0"
edition = "2024" # intentional: codebase uses Rust 2024 let-chain syntax
description = "Multi-agent orchestration CLI — your agents, all together"
license = "MIT"
Expand Down
54 changes: 49 additions & 5 deletions src/automation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ use crate::permissions::evaluate_command_policy;
use crate::runtime::{self, AgentStatus};
use crate::session::TmuxSession;
use crate::state::{
AutomationRunRecord, ControlEvent, VerifyLastSummary, WorkflowStepIntentRecord,
WorkflowStepOutcomeRecord, append_automation_run, append_control_event, append_policy_decision,
load_workflow_checkpoint, load_workflow_intent, save_verify_last_summary,
save_workflow_checkpoint, save_workflow_intent, save_workflow_output,
AutomationRunRecord, ControlEvent, RunTelemetryEntry, StepTimingEntry, VerifyLastSummary,
WorkflowStepIntentRecord, WorkflowStepOutcomeRecord, append_automation_run,
append_control_event, append_policy_decision, append_run_telemetry, load_workflow_checkpoint,
load_workflow_intent, save_verify_last_summary, save_workflow_checkpoint, save_workflow_intent,
save_workflow_output,
};
use chrono::Utc;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -2578,10 +2579,53 @@ impl<'a> WorkflowExecutor<'a> {
agent_scope: agent_scope.map(|s| s.to_string()),
hook_event: options.hook_event.clone(),
hook_agent: options.hook_agent.clone(),
template_id: template_id.clone(),
template_version: template_version.clone(),
},
)?;

// Emit run telemetry (best-effort — failures log a warning but don't fail the run).
let duration_secs =
((result.finished_at - result.started_at).num_milliseconds() as f64 / 1000.0).max(0.0);
let step_timings: Vec<StepTimingEntry> = result
.step_results
.iter()
.map(|s| StepTimingEntry {
id: s.step_type.clone(),
duration_secs: s.duration_ms as f64 / 1000.0,
status: match s.status {
StepStatus::Success => "success".to_string(),
StepStatus::Warning => "warning".to_string(),
StepStatus::Failed => "failed".to_string(),
},
})
.collect();
let passed = result
.step_results
.iter()
.filter(|s| matches!(s.status, StepStatus::Success | StepStatus::Warning))
.count();
let failed = result
.step_results
.iter()
.filter(|s| s.status == StepStatus::Failed)
.count();
append_run_telemetry(
self.project_root,
&RunTelemetryEntry {
run_id: result.run_id.clone(),
workflow: result.workflow_name.clone(),
template_id,
template_version,
started_at: result.started_at,
completed_at: result.finished_at,
duration_secs,
total_steps: result.step_results.len(),
passed_steps: passed,
failed_steps: failed,
step_timings,
},
)?;
);

save_execution_checkpoint(self.project_root, options, agent_scope, &result)?;

Expand Down
Loading
Loading