diff options
| author | soryu <soryu@soryu.co> | 2026-02-21 19:33:44 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-21 19:33:44 +0000 |
| commit | d670dcb72984cfa483063d161bb468704038895c (patch) | |
| tree | 885ea969d2c5ea5c026d1caf25cd0a15f6753ca1 /makima/src | |
| parent | 61442ea1cb92ce8c28fe0622aa19d4e2947a8fd0 (diff) | |
| download | soryu-d670dcb72984cfa483063d161bb468704038895c.tar.gz soryu-d670dcb72984cfa483063d161bb468704038895c.zip | |
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
Diffstat (limited to 'makima/src')
| -rw-r--r-- | makima/src/bin/makima.rs | 12 | ||||
| -rw-r--r-- | makima/src/daemon/cli/directive.rs | 39 | ||||
| -rw-r--r-- | makima/src/daemon/cli/mod.rs | 3 | ||||
| -rw-r--r-- | makima/src/daemon/skills/directive.md | 27 | ||||
| -rw-r--r-- | makima/src/orchestration/directive.rs | 64 |
5 files changed, 142 insertions, 3 deletions
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<String>, + + /// Context about what this relates to + #[arg(long)] + pub context: Option<String>, + + /// 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 "<url>" --pr-branch "<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 "<question>" +``` +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 "<context>"` - Additional context to help the user understand the question +- `--timeout <seconds>` - 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 <general|phase_confirmation|contract_complete>` - 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 <step_id>\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 \"<question>\" --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 <the-failing-branch> -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 <the-failing-branch> -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 <step_id> 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 "<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, )); |
