From d670dcb72984cfa483063d161bb468704038895c Mon Sep 17 00:00:00 2001 From: soryu Date: Sat, 21 Feb 2026 19:33:44 +0000 Subject: feat: add directive ask command, log backfill & specialized DAG steps (#75) * feat: soryu-co/soryu - makima: Add makima directive ask CLI command * feat: soryu-co/soryu - makima: Update directive skill docs and planning prompt to support asking questions * feat: soryu-co/soryu - makima: Add log stream backfill for directive tasks * feat: soryu-co/soryu - makima: Update planning prompts to inform tasks they can ask questions * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Add ask command to directive SKILL.md documentation * feat: soryu-co/soryu - makima: Add log stream backfill for directive task output history * feat: soryu-co/soryu - makima: Update planning prompt to tell planning tasks they can ask questions * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Show Planning, PR, and Cleanup tasks as specialized steps in DAG --- makima/src/bin/makima.rs | 12 +++++++ makima/src/daemon/cli/directive.rs | 39 +++++++++++++++++++++ makima/src/daemon/cli/mod.rs | 3 ++ makima/src/daemon/skills/directive.md | 27 +++++++++++++++ makima/src/orchestration/directive.rs | 64 +++++++++++++++++++++++++++++++++-- 5 files changed, 142 insertions(+), 3 deletions(-) (limited to 'makima/src') diff --git a/makima/src/bin/makima.rs b/makima/src/bin/makima.rs index 070e28e..aaf5a08 100644 --- a/makima/src/bin/makima.rs +++ b/makima/src/bin/makima.rs @@ -800,6 +800,18 @@ async fn run_directive( .await?; println!("{}", serde_json::to_string(&result.0)?); } + DirectiveCommand::Ask(args) => { + let client = ApiClient::new(args.common.api_url.clone(), args.common.api_key.clone())?; + eprintln!("Asking user: {}...", args.question); + let choices = args + .choices + .map(|c| c.split(',').map(|s| s.trim().to_string()).collect()) + .unwrap_or_default(); + let result = client + .supervisor_ask(&args.question, choices, args.context, args.timeout, args.phaseguard, args.multi_select, args.non_blocking, args.question_type) + .await?; + println!("{}", serde_json::to_string(&result.0)?); + } } Ok(()) diff --git a/makima/src/daemon/cli/directive.rs b/makima/src/daemon/cli/directive.rs index 8a6a9f2..7c8451f 100644 --- a/makima/src/daemon/cli/directive.rs +++ b/makima/src/daemon/cli/directive.rs @@ -111,6 +111,45 @@ pub struct BatchAddStepsArgs { pub json: String, } +/// Arguments for ask command (ask user a question from directive context). +#[derive(Args, Debug)] +pub struct AskArgs { + #[command(flatten)] + pub common: DirectiveArgs, + + /// The question to ask + #[arg(index = 1)] + pub question: String, + + /// Optional choices (comma-separated) + #[arg(long)] + pub choices: Option, + + /// Context about what this relates to + #[arg(long)] + pub context: Option, + + /// Timeout in seconds (default: 3600 = 1 hour) + #[arg(long, default_value = "3600")] + pub timeout: i32, + + /// Block indefinitely until user responds (no timeout) + #[arg(long, default_value = "false")] + pub phaseguard: bool, + + /// Allow selecting multiple choices (response will be comma-separated) + #[arg(long, default_value = "false")] + pub multi_select: bool, + + /// Non-blocking mode - returns immediately without waiting for response + #[arg(long, default_value = "false")] + pub non_blocking: bool, + + /// Question type (general, phase_confirmation, contract_complete) + #[arg(long, default_value = "general")] + pub question_type: String, +} + /// Arguments for update command. #[derive(Args, Debug)] pub struct UpdateArgs { diff --git a/makima/src/daemon/cli/mod.rs b/makima/src/daemon/cli/mod.rs index bcaaa70..8063541 100644 --- a/makima/src/daemon/cli/mod.rs +++ b/makima/src/daemon/cli/mod.rs @@ -249,6 +249,9 @@ pub enum DirectiveCommand { /// Update directive metadata (PR URL, etc.) Update(directive::UpdateArgs), + + /// Ask a question and wait for user feedback + Ask(directive::AskArgs), } impl Cli { diff --git a/makima/src/daemon/skills/directive.md b/makima/src/daemon/skills/directive.md index 9d2b644..02de836 100644 --- a/makima/src/daemon/skills/directive.md +++ b/makima/src/daemon/skills/directive.md @@ -82,6 +82,32 @@ makima directive update --pr-url "" --pr-branch "" ``` Updates the directive's PR URL and/or PR branch. Used by completion tasks to store the PR URL after creating it. +### Ask User a Question +```bash +makima directive ask "" +``` +Asks the user a question and waits for their response. Questions appear on the directive page with a yellow indicator and can be answered inline. + +Options: +- `--choices "opt1,opt2,opt3"` - Provide choices for the user to select from +- `--context ""` - Additional context to help the user understand the question +- `--timeout ` - Wait timeout (default: 3600 = 1 hour) +- `--phaseguard` - Block indefinitely until the user responds (no timeout). Recommended for critical decisions during planning. +- `--multi-select` - Allow the user to select multiple choices +- `--non-blocking` - Return immediately without waiting for a response +- `--question-type ` - Question type + +**When to use:** +- During planning, when you need clarification on requirements or approach +- When there are multiple valid approaches and user preference matters +- When a decision requires domain knowledge you don't have +- Always use `--phaseguard` for questions that block progress (the reconcile mode on the directive also controls this) + +**Example:** +```bash +makima directive ask "Should we use REST or GraphQL for the new API?" --choices "REST,GraphQL" --context "The existing codebase uses REST but the frontend team prefers GraphQL" --phaseguard +``` + ## Memory Commands Directives have an optional key-value memory system that persists across steps and planning cycles. Use memory to share context, decisions, and learned information between steps — so downstream tasks don't need to re-discover what earlier steps already figured out. @@ -167,6 +193,7 @@ makima directive memory-batch-set --json '{"framework": "axum", "orm": "sqlx", " ### Initial Setup 1. Check the directive status to understand the goal 2. Decompose the goal into steps with clear dependencies + - If requirements are unclear, use `makima directive ask` to get clarification before finalizing the plan 3. Add steps using `add-step` with appropriate `--depends-on` flags 4. Start the directive with `start` 5. Steps with no dependencies will become `ready` immediately diff --git a/makima/src/orchestration/directive.rs b/makima/src/orchestration/directive.rs index 420b3e1..b91781c 100644 --- a/makima/src/orchestration/directive.rs +++ b/makima/src/orchestration/directive.rs @@ -165,7 +165,9 @@ impl DirectiveOrchestrator { {merge_preamble}\ INSTRUCTIONS:\n{task_plan}\n\ When done, the system will automatically mark this step as completed.\n\ - If you cannot complete the task, report the failure clearly.", + If you cannot complete the task, report the failure clearly.\n\n\ + If you need clarification or encounter a decision that requires user input, you can ask:\n\ + \x20 makima directive ask \"Your question\" --phaseguard", directive_title = step.directive_title, step_name = step.step_name, description = step.step_description.as_deref().unwrap_or("(none)"), @@ -1308,7 +1310,9 @@ fn build_planning_prompt( \x20 makima directive remove-step \n\ 2. Then, add new steps for the updated goal. Use generation {}.\n\ 3. New steps that build on completed work MUST use --depends-on to inherit the worktree.\n\ - 4. Ensure the new plan fully addresses the UPDATED goal.\n\n", + 4. Ensure the new plan fully addresses the UPDATED goal.\n\ + 5. If the updated goal is unclear or ambiguous, ask the user for clarification using:\n\ + \x20 makima directive ask \"\" --phaseguard\n\n", generation )); } @@ -1359,6 +1363,28 @@ Guidelines: they should BOTH list that prior step in dependsOn. IMPORTANT: Each step's taskPlan must be self-contained. The executing instance won't have your planning context. + +ASKING QUESTIONS: +If you need clarification from the user before finalizing the plan, you can ask questions: + makima directive ask "Your question here" + makima directive ask "Which approach?" --choices "Option A,Option B" --phaseguard + makima directive ask "Confirm this approach?" --context "Additional context here" --phaseguard + +Use --phaseguard for questions that block progress (the question will wait indefinitely for a response). +Without --phaseguard, questions timeout based on the directive's reconcile mode: +- Reconcile ON: questions block indefinitely until answered +- Reconcile OFF: questions timeout after 30 seconds with no response + +When to ask: +- Requirements are ambiguous and multiple interpretations are valid +- There are multiple equally valid technical approaches +- You need domain-specific knowledge that cannot be inferred from the codebase +- A decision has significant downstream impact and user preference matters + +Do NOT ask questions for: +- Implementation details you can determine from the codebase +- Standard engineering decisions with clear best practices +- Trivial choices that do not significantly affect the outcome "#, title = directive.title, goal = directive.goal, @@ -1480,6 +1506,9 @@ Already-merged branches will be a no-op. If a merge fails with conflicts: 1. First try: `git merge --abort` then retry with `git merge -X theirs --no-edit` 2. If that also fails, manually resolve the conflicts, `git add .`, and `git commit --no-edit` 3. Continue with remaining merges + +If you encounter issues you cannot resolve (e.g., persistent merge conflicts, PR update failures), you can ask for help: + makima directive ask "Your question" --phaseguard "#, title = directive.title, goal = directive.goal, @@ -1539,6 +1568,9 @@ For each step branch merge, if a merge fails with conflicts: 1. First try: `git merge --abort` then retry with `git merge -X theirs --no-edit` 2. If that also fails, manually resolve the conflicts, `git add .`, and `git commit --no-edit` 3. Continue with remaining merges + +If you encounter issues you cannot resolve (e.g., persistent merge conflicts, PR creation failures), you can ask for help: + makima directive ask "Your question" --phaseguard "#, title = directive.title, goal = directive.goal, @@ -1679,7 +1711,10 @@ makima directive remove-step 6. After processing all steps, report a summary of what was cleaned up and what was left. -IMPORTANT: Only remove steps whose task branches have been verified as merged. Never remove unmerged steps."#, +IMPORTANT: Only remove steps whose task branches have been verified as merged. Never remove unmerged steps. + +If you encounter issues you cannot resolve during cleanup, you can ask for help: + makima directive ask "Your question" --phaseguard"#, title = directive.title, pr_branch = pr_branch, base_branch = base_branch, @@ -1900,6 +1935,29 @@ Guidelines: they should BOTH list that prior step in dependsOn. IMPORTANT: Each step's taskPlan must be self-contained. The executing instance won't have your planning context. + +## Asking Questions + +If you need clarification about the goal, requirements, or implementation approach, you can ask the user: +```bash +makima directive ask "Your question here" +``` + +Options: +- `--choices "opt1,opt2,opt3"` - Provide choices +- `--context ""` - Additional context +- `--phaseguard` - Block until response (recommended for important questions) + +The question will appear in the directive UI. Behavior depends on reconcile mode: +- Reconcile ON: blocks until user responds +- Reconcile OFF: times out after 30s (use for non-critical questions) + +Use this when: +- The goal is ambiguous and could be interpreted multiple ways +- You need to choose between significantly different implementation approaches +- You discover constraints that affect the plan + +Do NOT ask questions for trivial decisions — use your best judgment. "#, generation = generation, )); -- cgit v1.2.3