From f63df2d6b085972c4ce8ab16711500a0270ec64c Mon Sep 17 00:00:00 2001 From: Roberdan Date: Thu, 30 Apr 2026 22:48:02 +0200 Subject: [PATCH] =?UTF-8?q?feat(cli):=20cvg=20session=20resume=20=E2=80=94?= =?UTF-8?q?=20live=20cold-start=20brief=20from=20the=20daemon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes T1.23. Replaces the time-specific halves of STATUS.md and the agent-resume-packet (section 9 first-wave list) with a daemon query that prints daemon health, audit chain integrity, the active plan, the next-priority pending tasks (ordered by wave/sequence), and open PRs (best-effort via gh). Architectural smell F33: state that lives in markdown goes stale; state that lives in the daemon does not. EN+IT i18n; --output human|json|plain. session.rs split into session.rs + session_render.rs to honor the 300-line cap. STATUS.md trimmed to a thin pointer; agent-resume-packet section 2 now leads with cvg session resume, section 9 names the principle (housekeeping → retrieval → architecture) and points at the daemon for the live queue. --- STATUS.md | 122 ++------ crates/convergio-cli/src/commands/mod.rs | 2 + crates/convergio-cli/src/commands/session.rs | 260 ++++++++++++++++++ .../src/commands/session_render.rs | 184 +++++++++++++ crates/convergio-cli/src/main.rs | 6 + crates/convergio-i18n/locales/en/main.ftl | 17 ++ crates/convergio-i18n/locales/it/main.ftl | 17 ++ docs/INDEX.md | 4 +- docs/agent-resume-packet.md | 70 +++-- 9 files changed, 544 insertions(+), 138 deletions(-) create mode 100644 crates/convergio-cli/src/commands/session.rs create mode 100644 crates/convergio-cli/src/commands/session_render.rs diff --git a/STATUS.md b/STATUS.md index f6d6232..ac05d52 100644 --- a/STATUS.md +++ b/STATUS.md @@ -1,114 +1,40 @@ -# STATUS — where convergio-local is today +# STATUS — pointer to live state -**Snapshot:** 2026-04-30, end of the office-hours dogfood marathon -+ handoff cleanup. -**Daemon running:** v0.1.2 (T11 + wave-gate-fix live, -dogfood-verified). Release v0.2.0 queued via release-please #18. -**Repo legibility score:** 82 / 100 (floor 70, target 85; the gap -is durability split + near-cap files, both tracked). -**Fresh-eyes resume test:** ✅ **PASSED** — a sub-agent with no -conversation context shipped PR #32 in 25 min from cold context. -Full report: [`docs/plans/v0.2-fresh-eyes-test-result.md`](./docs/plans/v0.2-fresh-eyes-test-result.md). -**Cold-start protocol for the next session:** -[`docs/agent-resume-packet.md`](./docs/agent-resume-packet.md) — -read this first. +> **For current state, run `cvg session resume`.** +> It prints daemon health, audit chain integrity, the active plan, +> the next-priority pending tasks, and open PRs — all queried live +> from the daemon, never stale. JSON: `cvg session resume --output json`. -This page is one of the four documents an agent loads on cold -start: `README.md`, `STATUS.md` (this), `ROADMAP.md` (target -work), `docs/INDEX.md` (file map). Together they fit in ~few KB. +This file used to be a hand-written snapshot. It went stale within +hours. The daemon is the source of truth; this page now exists only +to point you at the right command. ## In one paragraph Convergio is a local-first daemon that **refuses agent work whose -evidence does not match the claim of done**. v0.1.0 shipped with the -gate pipeline, hash-chained audit, and a basic CLI. The -office-hours dogfood session of 2026-04-30 ran the project as its -own first real user, surfaced ~20 concrete frictions, and closed -the most important: T11 (`done` is set only by Thor) is live, the -demo example exists, the workspace coordination + capability -registry surfaces are in place, and `cvg pr stack` + `cvg pr -queue` keep the merge graph honest. The next milestone is **smart -Thor** (T3.02): the validator runs the project's actual test -pipeline, not just an evidence-shape check. - -## What shipped - -| Surface | State | -|---|---| -| Gate pipeline (NoDebt, NoStub, ZeroWarnings, NoSecrets, EvidenceGate, WaveSequence) | shipped, all green in production daemon | -| Hash-chained audit (ADR-0002) | shipped, 385+ entries integrity-verified | -| Thor as the only path to `done` (ADR-0011) | shipped (PR #15), live in v0.2.0 | -| `cvg task create` with rich fields (T0) | shipped (PR #22) | -| `cvg pr stack` (T2.03) | shipped (PR #28) — i18n + manifest validation deferred | -| Examples: `examples/claude-skill-quickstart/` (T2.01) | shipped (PR #27) | -| Constitution §13 agent context budget | shipped (PR #17) | -| Constitution §15 worktree discipline | shipped (PR #20) | -| Constitution §16 legibility score | shipped (PR #29) | -| ADR-0012 OODA-aware validation roadmap | shipped (PR #25) | -| `docs/INDEX.md` Tier-1 retrieval | shipped (PR #30) | -| Wave-gate fix (failed = terminal) | shipped (PR #26) | -| Public release v0.2.0 (release-please) | unblocked (Cargo.lock just synced) | - -## What is in flight, paused, or queued - -| Item | Status | Why paused | -|---|---|---| -| `cvg pr stack` i18n + manifest validation | git stash on `fix/cvg-pr-stack-i18n-and-manifest-validation` | paused for this consolidation wave | -| Plan task T2.04 (auto-close PR → task) | not started | waits for the consolidation to settle | -| Plan task T2.05 (split convergio-durability) | not started | the big architectural piece for v0.3 | -| Plan task T3.02 (smart Thor) | not started | the most important next step strategically | -| Plan task T1.17 (Tier-2 frontmatter + `cvg coherence`) | not started | follows naturally from T1.16 | -| Plan task T4.07 (local RAG over corpus) | future | only when the static index runs out | -| Plan task T4.08 (LLM Wiki, AI-maintained `docs/learnings/`) | future | needs T3.02 + T4.02 first | -| Multi-vendor model routing (T4.04) | future | needs reputation T4.03 first | +evidence does not match the claim of done**. The gate pipeline, +hash-chained audit, and `cvg` CLI ship together; the validator +(Thor) is the only path that promotes a task to `done`. The product +is eaten by its own users — Convergio is built while building +Convergio. ## Direction -Convergio v3 is on the trajectory the user named explicitly: - > "Build Convergio while building Convergio. Each round you learn > first-hand, you find what works, what doesn't, and you improve." -Concrete examples of that loop closing in this session: - -- The agent (Claude) registered in `agent_registry`, claimed - `workspace_lease` on the file it edited, published bus messages - on the plan, and transitioned tasks through the canonical - pending → in_progress → submitted lifecycle. Every refusal - landed in the audit chain. The product was eaten by its first - real user. -- The legibility audit found durability at 8059 LOC (soft-warn) and - 12 near-cap files: both already tracked as plan tasks before the - audit existed. The score now keeps the next regression honest. -- The friction log F1-F20 turned every unmet expectation into a - durable plan task instead of disappearing into chat history. -- ADR-0012 mapped Karpathy's 2026 LLM-Wiki + AutoResearch direction - onto eight plan tasks (T3.02-3.04 + T4.01-4.05). - -## What we are at risk of becoming - -The same thing v2 became: **too big to follow**. The legibility -score, `docs/INDEX.md`, the worktree discipline, and the single -dogfood plan are the controls keeping that risk visible. The -consolidation wave that produced this STATUS.md is the reflex -itself — when `cvg status` becomes illegible, stop and fix. +The legibility score, `docs/INDEX.md`, worktree discipline, and the +single durable plan are the controls keeping the project from +becoming what v2 became: too big to follow. ## How to navigate this repo as an agent -1. Read this file (`STATUS.md`). -2. Read [`AGENTS.md`](./AGENTS.md) for the cross-vendor agent rules. -3. Read [`CONSTITUTION.md`](./CONSTITUTION.md) for the - non-negotiables. +1. Run `cvg session resume` for live state (this is your cold-start). +2. Read [`docs/agent-resume-packet.md`](./docs/agent-resume-packet.md) + for the timeless protocol (worktree, lease, pipeline, constitution + touchstones). +3. Read [`AGENTS.md`](./AGENTS.md) for cross-vendor agent rules and + [`CONSTITUTION.md`](./CONSTITUTION.md) for the non-negotiables. 4. Open [`docs/INDEX.md`](./docs/INDEX.md) and pick the doc relevant - to the task. Do not load the whole repo. -5. If the task is durable, claim it through `cvg task create` on - plan `8cb75264-8c89-4bf7-b98d-44408b30a8ae` (the office-hours - plan) so the audit chain captures it. -6. Use `cvg pr stack` before merging anything — it surfaces the - conflict matrix. - -## Plan in one screen - -The single durable plan is `8cb75264-8c89-4bf7-b98d-44408b30a8ae`. -Live counts via `cvg status --project convergio-local`. The -distilled queue is in [`ROADMAP.md`](./ROADMAP.md). + to your task — do not load the whole repo. +5. Use `cvg pr stack` before merging — it surfaces the conflict matrix. diff --git a/crates/convergio-cli/src/commands/mod.rs b/crates/convergio-cli/src/commands/mod.rs index 08a7da3..96eafb9 100644 --- a/crates/convergio-cli/src/commands/mod.rs +++ b/crates/convergio-cli/src/commands/mod.rs @@ -15,6 +15,8 @@ pub mod pr; mod pr_diff; mod pr_render; pub mod service; +pub mod session; +mod session_render; pub mod setup; pub mod solve; pub mod status; diff --git a/crates/convergio-cli/src/commands/session.rs b/crates/convergio-cli/src/commands/session.rs new file mode 100644 index 0000000..95ad022 --- /dev/null +++ b/crates/convergio-cli/src/commands/session.rs @@ -0,0 +1,260 @@ +//! `cvg session ...` — cold-start brief from the daemon. +//! +//! Replaces the static handoff markdown that goes stale. Every value +//! printed here comes from a live daemon query (health, audit, plan +//! tasks) plus an optional `gh pr list` shell-out for the queue. +//! +//! The markdown packet (`docs/agent-resume-packet.md`) is now the +//! TIMELESS half of the cold-start; this command is the time-specific +//! half — read both, in that order, after a session reset. +//! +//! Renderers live in the sibling [`super::session_render`] module to +//! keep both files under the 300-line cap. + +use super::session_render::{self, Brief}; +use super::{Client, OutputMode}; +use anyhow::{anyhow, Context, Result}; +use clap::Subcommand; +use convergio_i18n::Bundle; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::process::Command; + +/// Session subcommands. +#[derive(Subcommand)] +pub enum SessionCommand { + /// Print a cold-start brief: daemon health, audit chain, the + /// active plan, top pending tasks, and open PRs. + Resume { + /// Plan id. If omitted, resolves the most recently updated + /// plan in `--project`. + plan_id: Option, + /// Project filter when no plan id is given. + #[arg(long, default_value = "convergio-local")] + project: String, + /// Number of next-priority pending tasks to surface. + #[arg(long, default_value_t = 5)] + next_limit: usize, + }, +} + +/// Entry point. +pub async fn run( + client: &Client, + bundle: &Bundle, + output: OutputMode, + cmd: SessionCommand, +) -> Result<()> { + match cmd { + SessionCommand::Resume { + plan_id, + project, + next_limit, + } => resume(client, bundle, output, plan_id, &project, next_limit).await, + } +} + +async fn resume( + client: &Client, + bundle: &Bundle, + output: OutputMode, + plan_id: Option, + project: &str, + next_limit: usize, +) -> Result<()> { + let health: Value = client.get("/v1/health").await.context("GET /v1/health")?; + let audit: Value = client + .get("/v1/audit/verify") + .await + .context("GET /v1/audit/verify")?; + + let plan = resolve_plan(client, plan_id.as_deref(), project).await?; + let tasks: Vec = client + .get(&format!("/v1/plans/{}/tasks", plan.id)) + .await + .context("GET plan tasks")?; + let counts = TaskCounts::from(tasks.as_slice()); + let next = top_pending(&tasks, next_limit); + + let prs = fetch_open_prs().ok(); + + let brief = Brief { + health: &health, + audit: &audit, + plan: &plan, + counts: &counts, + next: &next, + prs: prs.as_deref(), + }; + session_render::render(bundle, output, &brief) +} + +async fn resolve_plan(client: &Client, plan_id: Option<&str>, project: &str) -> Result { + if let Some(id) = plan_id { + return client + .get(&format!("/v1/plans/{id}")) + .await + .with_context(|| format!("GET /v1/plans/{id}")); + } + let plans: Vec = client.get("/v1/plans").await.context("GET /v1/plans")?; + plans + .into_iter() + .filter(|p| p.project.as_deref() == Some(project)) + .filter(|p| p.status != "archived") + .max_by(|a, b| a.updated_at.cmp(&b.updated_at)) + .ok_or_else(|| anyhow!("no active plan found for project={project}")) +} + +fn top_pending(tasks: &[Task], limit: usize) -> Vec { + let mut pending: Vec = tasks + .iter() + .filter(|t| t.status == "pending") + .cloned() + .collect(); + pending.sort_by(|a, b| { + a.wave + .cmp(&b.wave) + .then(a.sequence.cmp(&b.sequence)) + .then(a.created_at.cmp(&b.created_at)) + }); + pending.truncate(limit); + pending +} + +fn fetch_open_prs() -> Result> { + let out = Command::new("gh") + .args([ + "pr", + "list", + "--state", + "open", + "--json", + "number,title,headRefName,isDraft", + ]) + .output() + .context("spawn gh")?; + if !out.status.success() { + anyhow::bail!( + "gh pr list failed: {}", + String::from_utf8_lossy(&out.stderr) + ); + } + serde_json::from_slice(&out.stdout).context("parse gh output") +} + +#[derive(Debug, Deserialize, Serialize)] +pub(super) struct Plan { + pub(super) id: String, + pub(super) title: String, + #[serde(default)] + pub(super) description: Option, + #[serde(default)] + pub(super) project: Option, + pub(super) status: String, + pub(super) updated_at: String, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub(super) struct Task { + pub(super) id: String, + pub(super) title: String, + pub(super) status: String, + pub(super) wave: i64, + pub(super) sequence: i64, + pub(super) created_at: String, +} + +#[derive(Debug, Default, Serialize)] +pub(super) struct TaskCounts { + pub(super) total: usize, + pub(super) done: usize, + pub(super) pending: usize, + pub(super) in_progress: usize, + pub(super) submitted: usize, + pub(super) failed: usize, +} + +impl From<&[Task]> for TaskCounts { + fn from(tasks: &[Task]) -> Self { + let mut c = TaskCounts { + total: tasks.len(), + ..Default::default() + }; + for t in tasks { + match t.status.as_str() { + "done" => c.done += 1, + "pending" => c.pending += 1, + "in_progress" => c.in_progress += 1, + "submitted" => c.submitted += 1, + "failed" => c.failed += 1, + _ => {} + } + } + c + } +} + +#[derive(Debug, Deserialize, Serialize)] +pub(super) struct PrSummary { + pub(super) number: i64, + pub(super) title: String, + #[serde(rename = "headRefName")] + pub(super) head_ref_name: String, + #[serde(rename = "isDraft", default)] + pub(super) is_draft: bool, +} + +#[cfg(test)] +mod tests { + use super::*; + + fn task(status: &str, wave: i64, sequence: i64) -> Task { + Task { + id: format!("id-{wave}-{sequence}"), + title: format!("t{wave}.{sequence}"), + status: status.into(), + wave, + sequence, + created_at: "2026-01-01T00:00:00Z".into(), + } + } + + #[test] + fn counts_groups_by_status() { + let tasks = vec![ + task("done", 1, 1), + task("pending", 1, 2), + task("pending", 2, 1), + task("in_progress", 1, 3), + task("submitted", 1, 4), + task("failed", 3, 1), + ]; + let c = TaskCounts::from(tasks.as_slice()); + assert_eq!(c.total, 6); + assert_eq!(c.done, 1); + assert_eq!(c.pending, 2); + assert_eq!(c.in_progress, 1); + assert_eq!(c.submitted, 1); + assert_eq!(c.failed, 1); + } + + #[test] + fn top_pending_orders_by_wave_then_sequence() { + let tasks = vec![ + task("pending", 2, 1), + task("done", 1, 1), + task("pending", 1, 5), + task("pending", 1, 2), + ]; + let next = top_pending(&tasks, 10); + let order: Vec = next.iter().map(|t| t.title.clone()).collect(); + assert_eq!(order, vec!["t1.2", "t1.5", "t2.1"]); + } + + #[test] + fn top_pending_respects_limit() { + let tasks: Vec = (0..10).map(|i| task("pending", 1, i)).collect(); + let next = top_pending(&tasks, 3); + assert_eq!(next.len(), 3); + } +} diff --git a/crates/convergio-cli/src/commands/session_render.rs b/crates/convergio-cli/src/commands/session_render.rs new file mode 100644 index 0000000..3712847 --- /dev/null +++ b/crates/convergio-cli/src/commands/session_render.rs @@ -0,0 +1,184 @@ +//! Renderers for `cvg session resume` (human / json / plain). +//! +//! Split out of [`super::session`] to honour the 300-line per-file +//! cap (CONSTITUTION § 13). + +use super::session::{Plan, PrSummary, Task, TaskCounts}; +use super::OutputMode; +use anyhow::Result; +use convergio_i18n::Bundle; +use serde_json::Value; + +/// Aggregated cold-start payload — borrowed view, never owned. +pub(super) struct Brief<'a> { + pub(super) health: &'a Value, + pub(super) audit: &'a Value, + pub(super) plan: &'a Plan, + pub(super) counts: &'a TaskCounts, + pub(super) next: &'a [Task], + pub(super) prs: Option<&'a [PrSummary]>, +} + +pub(super) fn render(bundle: &Bundle, output: OutputMode, brief: &Brief<'_>) -> Result<()> { + match output { + OutputMode::Json => render_json(brief), + OutputMode::Plain => { + render_plain(brief); + Ok(()) + } + OutputMode::Human => { + render_human(bundle, brief); + Ok(()) + } + } +} + +fn render_json(brief: &Brief<'_>) -> Result<()> { + let value = serde_json::json!({ + "health": brief.health, + "audit": brief.audit, + "plan": brief.plan, + "task_counts": brief.counts, + "next_tasks": brief.next, + "open_prs": brief.prs, + }); + println!("{}", serde_json::to_string_pretty(&value)?); + Ok(()) +} + +fn render_plain(brief: &Brief<'_>) { + let pr_count = brief.prs.map(|p| p.len()).unwrap_or(0); + println!( + "health={} audit_ok={} plan_id={} done={} total={} in_progress={} submitted={} pending={} next={} open_prs={}", + bool_field(brief.health, "ok"), + bool_field(brief.audit, "ok"), + brief.plan.id, + brief.counts.done, + brief.counts.total, + brief.counts.in_progress, + brief.counts.submitted, + brief.counts.pending, + brief.next.len(), + pr_count, + ); +} + +fn render_human(bundle: &Bundle, brief: &Brief<'_>) { + println!("{}", bundle.t("session-resume-header", &[])); + + let health_ok = bool_field(brief.health, "ok"); + let version = brief + .health + .get("version") + .and_then(Value::as_str) + .unwrap_or("?"); + println!( + "{}", + bundle.t( + if health_ok { + "session-resume-health-ok" + } else { + "session-resume-health-down" + }, + &[("version", version)], + ) + ); + + let audit_ok = bool_field(brief.audit, "ok"); + let checked = brief + .audit + .get("checked") + .and_then(Value::as_i64) + .unwrap_or(0) + .to_string(); + println!( + "{}", + bundle.t( + if audit_ok { + "session-resume-audit-ok" + } else { + "session-resume-audit-broken" + }, + &[("count", &checked)], + ) + ); + + println!( + "{}", + bundle.t( + "session-resume-plan-line", + &[ + ("title", &brief.plan.title), + ("status", &brief.plan.status), + ("project", brief.plan.project.as_deref().unwrap_or("-")), + ("id", &brief.plan.id), + ], + ) + ); + println!( + "{}", + bundle.t( + "session-resume-counts-line", + &[ + ("done", &brief.counts.done.to_string()), + ("total", &brief.counts.total.to_string()), + ("in_progress", &brief.counts.in_progress.to_string()), + ("submitted", &brief.counts.submitted.to_string()), + ("pending", &brief.counts.pending.to_string()), + ], + ) + ); + + if brief.next.is_empty() { + println!("{}", bundle.t("session-resume-next-empty", &[])); + } else { + println!("{}", bundle.t("session-resume-next-header", &[])); + for task in brief.next { + println!( + "{}", + bundle.t( + "session-resume-next-line", + &[ + ("wave", &task.wave.to_string()), + ("sequence", &task.sequence.to_string()), + ("title", &task.title), + ("id", &short_id(&task.id)), + ], + ) + ); + } + } + + match brief.prs { + None => println!("{}", bundle.t("session-resume-prs-unavailable", &[])), + Some([]) => println!("{}", bundle.t("session-resume-prs-empty", &[])), + Some(prs) => { + println!("{}", bundle.t("session-resume-prs-header", &[])); + for pr in prs { + println!( + "{}", + bundle.t( + if pr.is_draft { + "session-resume-pr-line-draft" + } else { + "session-resume-pr-line" + }, + &[ + ("number", &pr.number.to_string()), + ("title", &pr.title), + ("branch", &pr.head_ref_name), + ], + ) + ); + } + } + } +} + +fn bool_field(v: &Value, key: &str) -> bool { + v.get(key).and_then(Value::as_bool).unwrap_or(false) +} + +fn short_id(id: &str) -> String { + id.chars().take(8).collect() +} diff --git a/crates/convergio-cli/src/main.rs b/crates/convergio-cli/src/main.rs index a63f532..5d2458f 100644 --- a/crates/convergio-cli/src/main.rs +++ b/crates/convergio-cli/src/main.rs @@ -115,6 +115,11 @@ enum Command { #[command(subcommand)] sub: commands::service::ServiceCommand, }, + /// Cold-start brief from the daemon (replaces handoff markdown). + Session { + #[command(subcommand)] + sub: commands::session::SessionCommand, + }, /// Solve a mission into a plan (Layer 4 planner). Solve { /// Mission text — newline-separated tasks. @@ -162,6 +167,7 @@ async fn main() -> Result<()> { Command::Mcp { sub } => commands::mcp::run(&bundle, sub).await, Command::Pr { sub } => commands::pr::run(&client, &bundle, cli.output, sub).await, Command::Service { sub } => commands::service::run(&bundle, sub).await, + Command::Session { sub } => commands::session::run(&client, &bundle, cli.output, sub).await, Command::Solve { mission } => commands::solve::run(&client, &mission).await, Command::Dispatch => commands::dispatch::run(&client).await, Command::Validate { plan_id } => commands::validate::run(&client, &plan_id).await, diff --git a/crates/convergio-i18n/locales/en/main.ftl b/crates/convergio-i18n/locales/en/main.ftl index dd086bc..056ddca 100644 --- a/crates/convergio-i18n/locales/en/main.ftl +++ b/crates/convergio-i18n/locales/en/main.ftl @@ -108,3 +108,20 @@ pr-stack-files-summary = { $count -> *[other] { $count } files } pr-stack-suggested-order = Suggested merge order: + +# ---------- CLI: session resume ---------- +session-resume-header = Convergio session resume +session-resume-health-ok = Daemon: ok (version { $version }) +session-resume-health-down = Daemon: NOT ok (version { $version }) +session-resume-audit-ok = Audit chain: ok ({ $count } events) +session-resume-audit-broken = Audit chain: BROKEN ({ $count } events checked) +session-resume-plan-line = Plan: { $title } [{ $status }] project: { $project } id: { $id } +session-resume-counts-line = Tasks: { $done }/{ $total } done — in_progress: { $in_progress }, submitted: { $submitted }, pending: { $pending } +session-resume-next-empty = Next priority: none (no pending tasks). +session-resume-next-header = Next priority (top pending): +session-resume-next-line = - w{ $wave }.{ $sequence } { $title } [{ $id }] +session-resume-prs-empty = Open PRs: none. +session-resume-prs-unavailable = Open PRs: gh not available (skipped). +session-resume-prs-header = Open PRs: +session-resume-pr-line = - #{ $number } { $title } ({ $branch }) +session-resume-pr-line-draft = - #{ $number } [draft] { $title } ({ $branch }) diff --git a/crates/convergio-i18n/locales/it/main.ftl b/crates/convergio-i18n/locales/it/main.ftl index 9d9493f..21d51d0 100644 --- a/crates/convergio-i18n/locales/it/main.ftl +++ b/crates/convergio-i18n/locales/it/main.ftl @@ -108,3 +108,20 @@ pr-stack-files-summary = { $count -> *[other] { $count } file } pr-stack-suggested-order = Ordine di merge suggerito: + +# ---------- CLI: session resume ---------- +session-resume-header = Riavvio sessione Convergio +session-resume-health-ok = Daemon: ok (versione { $version }) +session-resume-health-down = Daemon: NON attivo (versione { $version }) +session-resume-audit-ok = Catena audit: ok ({ $count } eventi) +session-resume-audit-broken = Catena audit: ROTTA ({ $count } eventi verificati) +session-resume-plan-line = Piano: { $title } [{ $status }] progetto: { $project } id: { $id } +session-resume-counts-line = Task: { $done }/{ $total } completati — in corso: { $in_progress }, in revisione: { $submitted }, da fare: { $pending } +session-resume-next-empty = Prossima priorità: nessuna (nessun task aperto). +session-resume-next-header = Prossima priorità (primi task aperti): +session-resume-next-line = - w{ $wave }.{ $sequence } { $title } [{ $id }] +session-resume-prs-empty = PR aperte: nessuna. +session-resume-prs-unavailable = PR aperte: gh non disponibile (saltato). +session-resume-prs-header = PR aperte: +session-resume-pr-line = - #{ $number } { $title } ({ $branch }) +session-resume-pr-line-draft = - #{ $number } [bozza] { $title } ({ $branch }) diff --git a/docs/INDEX.md b/docs/INDEX.md index 3d0df7a..2e9ce69 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -27,7 +27,7 @@ the task. See ADR-0012 (OODA-aware validation) and plan task T4.07 | `README.md` | entry | - | - | 223 | | `ROADMAP.md` | roadmap | - | - | 143 | | `SECURITY.md` | governance | - | - | 53 | -| `STATUS.md` | - | - | - | 114 | +| `STATUS.md` | - | - | - | 40 | | `crates/AGENTS.md` | - | - | - | 28 | | `crates/convergio-api/AGENTS.md` | crate-rules | - | - | 14 | | `crates/convergio-api/README.md` | crate-readme | - | - | 7 | @@ -70,7 +70,7 @@ the task. See ADR-0012 (OODA-aware validation) and plan task T4.07 | `docs/adr/README.md` | adr | - | - | 28 | | `docs/agent-instruction-guidelines.md` | - | - | - | 123 | | `docs/agent-protocol.md` | - | - | - | 113 | -| `docs/agent-resume-packet.md` | - | - | - | 239 | +| `docs/agent-resume-packet.md` | - | - | - | 233 | | `docs/agents/README.md` | agent-docs | - | - | 66 | | `docs/multi-agent-operating-model.md` | - | - | - | 250 | | `docs/plans/AGENTS.md` | plan | - | - | 22 | diff --git a/docs/agent-resume-packet.md b/docs/agent-resume-packet.md index 3b850c5..f3dfa29 100644 --- a/docs/agent-resume-packet.md +++ b/docs/agent-resume-packet.md @@ -52,26 +52,25 @@ curl -fsS -X POST http://127.0.0.1:8420/v1/agent-registry/agents \ }' ``` -## 2. Cold-start reads (in order, ~3KB total) +## 2. Cold-start reads (in order) + +Live state first — every value below is a daemon query, never stale: ```bash -cat STATUS.md # where the project is today -cat AGENTS.md # cross-vendor agent rules -cat CONSTITUTION.md # 16 non-negotiables (§ 6, § 11, § 13, § 15, § 16, P5) -cat ROADMAP.md # priorities v0.2.x → v0.3 → v0.4+ -cat docs/INDEX.md # auto-generated file map -cat docs/plans/v0.2-friction-log.md # frictions F11..F26 -cat docs/plans/v0.2-fresh-eyes-test-result.md # the resume validation +cvg session resume # daemon, audit, active plan, next tasks, open PRs +cvg session resume --output json # same brief, machine-readable +cvg pr stack # merge order + conflict matrix (uses gh) +git log --oneline main -10 # what landed recently ``` -Then ground yourself in live state: +Then the timeless reference set: ```bash -cvg status --project convergio-local # the active plan, no artefact noise -cvg pr list --state open # what is queued for review -cvg pr stack # suggested merge order + conflict matrix -cvg audit verify # chain integrity (expect ok=true) -git log --oneline main -10 # what landed recently +cat AGENTS.md # cross-vendor agent rules +cat CONSTITUTION.md # 16 non-negotiables (§ 6, § 11, § 13, § 15, § 16, P5) +cat ROADMAP.md # priorities v0.2.x → v0.3 → v0.4+ +cat docs/INDEX.md # auto-generated file map +cat docs/plans/v0.2-friction-log.md # accumulated frictions ``` ## 3. Worktree discipline (CONSTITUTION § 15) @@ -188,30 +187,25 @@ A future T1.20 ships this as `docs/wip-commit-template.md`. ## 9. The first wave for a new session -Per the user's explicit ask after the 2026-04-30 marathon, the -**first wave** of any new session is repo optimisation — make the -repo more legible to the next agent, in this order: - -1. **T1.21** `scripts/install-local.sh` runs `lefthook install` - automatically (every fresh checkout gets the file-size guard + - commitlint hooks; F31 close). -2. **T1.18** lefthook pre-commit hook that warns when not in a - worktree but has uncommitted edits on a non-main branch - (CONSTITUTION § 15 enforcement, F28 close). -3. **T1.19** scan `scripts/` for any locale-sensitive command, - pin `LC_ALL=C` (F27 close). -4. **T1.20** write `docs/wip-commit-template.md` with the protocol - from § 7 above (F29 + F30 close). -5. **T1.17** add machine-readable YAML frontmatter to every ADR - plus a `cvg coherence check` that refuses cross-references to - non-existent ADRs / crates (Tier-2 retrieval). -6. **T2.05** split `convergio-durability` (currently 8059 LOC) along - the audit + gates / plan-task-evidence / workspace + crdt + - capability seams. Biggest legibility win, deserves its own ADR. - -Tasks 1-4 are the *housekeeping wave* (~2 hours total). Task 5 is -~2 hours. Task 6 is ~3-4 hours. Run them in that order; check the -legibility score after each PR to see the trend. +The user's standing ask is that any new session opens with a repo +optimisation pass — make the codebase more legible for the next +agent before adding new surface. The concrete queue is **not** +listed here on purpose: it goes stale, and the daemon already knows +the order. + +```bash +cvg session resume # next-priority pending tasks, ordered by wave/sequence +``` + +The principle that shapes the queue is constant: +- *Housekeeping first* — install-script, hooks, locale pins, WIP protocol. +- *Then retrieval* — frontmatter, coherence checks, file-map quality. +- *Then architecture* — splitting near-cap crates (durability is + the standing candidate; check `./scripts/legibility-audit.sh` for + the current LOC). + +Run wave 1 tasks in `wave/sequence` order; check the legibility +score after each PR to see the trend. ## 10. After the optimisation wave