use anyhow::{bail, Result};
use serde::Serialize;
#[derive(Clone, Debug, Serialize)]
pub struct AgentManifest {
pub id: &'static str,
pub role: &'static str,
pub stages: &'static [&'static str],
pub skills: &'static [&'static str],
pub commands: &'static [&'static str],
pub mcp_tools: &'static [&'static str],
pub permissions: &'static [&'static str],
pub provider_policy: &'static str,
pub worktree_policy: &'static str,
pub checkpoints: &'static [&'static str],
pub inputs: &'static [&'static str],
pub outputs: &'static [&'static str],
pub fallback: &'static str,
}
pub fn agent_manifest(agent_id: &str) -> Result<AgentManifest> {
match agent_id {
"sdd-orchestrator" => Ok(sdd_orchestrator_manifest()),
other => bail!("unknown SDD agent `{other}`"),
}
}
pub fn sdd_orchestrator_manifest() -> AgentManifest {
AgentManifest {
id: "sdd-orchestrator",
role: "Agente principal do SDD Layer para conduzir demandas por Discovery, Risk, Idea, PRD, Tech Spec, Tasks, Refinement opcional, Execution, ADR, Review e Memory.",
stages: &[
"project-discovery",
"risk",
"idea",
"prd",
"techspec",
"tasks",
"refinement",
"execution",
"adr",
"review",
"memory",
],
skills: &[
"orchestration",
"output-quality",
"provider-compatibility",
"prompt-craft",
"humanizer",
"product-discovery-frameworks",
"project-discovery",
"risk-classifier",
"code-intelligence",
"traceability",
"checkpoints",
"execution-discipline",
"code-review",
"frontend-design",
"interface-design",
"visual-review",
"design-extraction",
"impeccable-design",
"systematic-debugging",
"subagent-orchestration",
"reflexion-loop",
"memory",
],
commands: &[
"sdd workflow run agentic-sdd-loop --input \"<demanda>\" --max-iterations 3 --json",
"sdd orchestration \"<ideia>\" --name \"<ciclo>\"",
"sdd context build --name \"<ciclo>\" --stage <stage> --write",
"sdd trace summary --orchestration \"<ciclo>\" --json",
"sdd clients doctor --strict",
"sdd capabilities doctor --targets all",
],
mcp_tools: &[
"sdd_trace_list",
"sdd_trace_show",
"sdd_trace_summary",
"sdd_artifact_status",
"sdd_context_build",
"sdd_context_bundle",
"sdd_clients_doctor",
"sdd_project_status",
"sdd_search",
"sdd_runtime_adapters",
"sdd_optimize_status",
"sdd_context_handoff",
"sdd_readiness_summary",
"sdd_capabilities_status",
"sdd_agents_manifest",
],
permissions: &[
"read artifacts",
"read traces",
"read context packs",
"read capability catalog",
"request explicit human checkpoint approval",
],
provider_policy: "Provider-neutral: use configured providers when available, keep Markdown/CLI artifact fallback, never copy secrets into prompts, traces, artifacts or memory.",
worktree_policy: "Isolamento config-driven via `orchestration.isolation` no sdd.config.yaml: `local` (default — checkout normal no branch da orquestração), `worktree` (cópias isoladas em `.worktree/<key>/`) ou `cloud` (reservado, ainda sem integração — o `next` falha se selecionado). NÃO pergunte ao usuário a cada orquestração: rode `sdd orchestration next \"$ARGUMENTS\"` direto; use `--worktree yes` ou `--worktree no` somente como override pontual quando o usuário pedir explicitamente. O destino dos artefatos vem de `orchestration.artifacts` (`local` default em docs/<slug>/, ou `cloud` para providers integrados — Jira/Confluence/GitHub — com o Markdown local como espelho).",
checkpoints: &[
"prd",
"techspec",
"refinement when risk requires",
"merge",
"deploy when risk requires",
],
inputs: &[
"texto livre",
"card id",
"webhook payload",
"artifact store local",
"context pack",
"trace summary",
],
outputs: &[
"docs/<slug>/traceability-map.yaml",
"docs/<slug>/<stage>.md",
".sdd/events.jsonl",
".sdd/workflows/*.json",
".sdd/acp/sessions/*.json",
],
fallback: "Quando ACP, MCP, subagents ou tool calling estiverem indisponíveis, rode comandos `sdd` pelo terminal e persista artefatos Markdown em `docs/<slug>/`.",
}
}
pub fn sdd_orchestrator_agent_markdown() -> String {
let manifest = sdd_orchestrator_manifest();
render_agent_manifest_markdown(&manifest)
}
pub fn render_agent_manifest_markdown(manifest: &AgentManifest) -> String {
let mut out = String::new();
out.push_str("---\n");
out.push_str(&format!("id: {}\n", manifest.id));
out.push_str("kind: agent\n");
out.push_str("protocols:\n");
out.push_str(" - sdd-cli\n");
out.push_str(" - mcp-read-only\n");
out.push_str(" - acp-v1\n");
out.push_str("---\n\n");
out.push_str(&format!("# Agent - {}\n\n", manifest.id));
out.push_str("## Role\n\n");
out.push_str(manifest.role);
out.push_str("\n\n## Stages\n\n");
push_list(&mut out, manifest.stages);
out.push_str("\n## Skills\n\n");
push_list(&mut out, manifest.skills);
out.push_str("\n## Commands\n\n");
push_list(&mut out, manifest.commands);
out.push_str("\n## MCP Tools\n\n");
push_list(&mut out, manifest.mcp_tools);
out.push_str("\n## Permissions\n\n");
push_list(&mut out, manifest.permissions);
out.push_str("\n## Provider Policy\n\n");
out.push_str(manifest.provider_policy);
out.push_str("\n\n## Isolamento de execução e destino de artefatos (config-driven)\n\n");
out.push_str(manifest.worktree_policy);
out.push_str("\n\n## Checkpoints\n\n");
push_list(&mut out, manifest.checkpoints);
out.push_str("\n## Inputs\n\n");
push_list(&mut out, manifest.inputs);
out.push_str("\n## Outputs\n\n");
push_list(&mut out, manifest.outputs);
out.push_str("\n## Fallback\n\n");
out.push_str(manifest.fallback);
out.push('\n');
out
}
fn push_list(out: &mut String, items: &[&str]) {
for item in items {
out.push_str(&format!("- `{item}`\n"));
}
}