diff options
| author | soryu <soryu@soryu.co> | 2026-02-09 00:11:51 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-09 00:11:51 +0000 |
| commit | 8c23b3ab6f7fabca01b0468911bae073aa5ced32 (patch) | |
| tree | f50159aee13b13f0b55618ac09e9be1f89a41bb2 /makima/src/daemon | |
| parent | 3662b334dfd68cfdf00ed44ae88927c2e1b2aabe (diff) | |
| download | soryu-8c23b3ab6f7fabca01b0468911bae073aa5ced32.tar.gz soryu-8c23b3ab6f7fabca01b0468911bae073aa5ced32.zip | |
Add new directive mechanism v3
Diffstat (limited to 'makima/src/daemon')
| -rw-r--r-- | makima/src/daemon/api/directive.rs | 124 | ||||
| -rw-r--r-- | makima/src/daemon/api/mod.rs | 1 | ||||
| -rw-r--r-- | makima/src/daemon/cli/directive.rs | 101 | ||||
| -rw-r--r-- | makima/src/daemon/cli/mod.rs | 49 | ||||
| -rw-r--r-- | makima/src/daemon/skills/directive.md | 111 | ||||
| -rw-r--r-- | makima/src/daemon/skills/mod.rs | 4 |
6 files changed, 390 insertions, 0 deletions
diff --git a/makima/src/daemon/api/directive.rs b/makima/src/daemon/api/directive.rs new file mode 100644 index 0000000..fbd27fe --- /dev/null +++ b/makima/src/daemon/api/directive.rs @@ -0,0 +1,124 @@ +//! Directive API methods. + +use serde::Serialize; +use uuid::Uuid; + +use super::client::{ApiClient, ApiError}; +use super::supervisor::JsonValue; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateStepRequest { + pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + pub task_plan: Option<String>, + pub depends_on: Vec<Uuid>, + pub order_index: i32, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct UpdateGoalRequest { + pub goal: String, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct UpdateStepDepsRequest { + pub depends_on: Vec<Uuid>, +} + +impl ApiClient { + /// List all directives. + pub async fn list_directives(&self) -> Result<JsonValue, ApiError> { + self.get("/api/v1/directives").await + } + + /// Get a directive with its steps. + pub async fn get_directive(&self, directive_id: Uuid) -> Result<JsonValue, ApiError> { + self.get(&format!("/api/v1/directives/{}", directive_id)).await + } + + /// Add a step to a directive. + pub async fn directive_add_step( + &self, + directive_id: Uuid, + req: CreateStepRequest, + ) -> Result<JsonValue, ApiError> { + self.post(&format!("/api/v1/directives/{}/steps", directive_id), &req).await + } + + /// Remove a step from a directive. + pub async fn directive_remove_step( + &self, + directive_id: Uuid, + step_id: Uuid, + ) -> Result<(), ApiError> { + self.delete(&format!("/api/v1/directives/{}/steps/{}", directive_id, step_id)).await + } + + /// Set dependencies for a step. + pub async fn directive_set_deps( + &self, + directive_id: Uuid, + step_id: Uuid, + depends_on: Vec<Uuid>, + ) -> Result<JsonValue, ApiError> { + let req = UpdateStepDepsRequest { depends_on }; + self.put(&format!("/api/v1/directives/{}/steps/{}", directive_id, step_id), &req).await + } + + /// Start a directive. + pub async fn directive_start(&self, directive_id: Uuid) -> Result<JsonValue, ApiError> { + self.post_empty(&format!("/api/v1/directives/{}/start", directive_id)).await + } + + /// Pause a directive. + pub async fn directive_pause(&self, directive_id: Uuid) -> Result<JsonValue, ApiError> { + self.post_empty(&format!("/api/v1/directives/{}/pause", directive_id)).await + } + + /// Advance the directive DAG. + pub async fn directive_advance(&self, directive_id: Uuid) -> Result<JsonValue, ApiError> { + self.post_empty(&format!("/api/v1/directives/{}/advance", directive_id)).await + } + + /// Mark a step as completed. + pub async fn directive_complete_step( + &self, + directive_id: Uuid, + step_id: Uuid, + ) -> Result<JsonValue, ApiError> { + self.post_empty(&format!("/api/v1/directives/{}/steps/{}/complete", directive_id, step_id)).await + } + + /// Mark a step as failed. + pub async fn directive_fail_step( + &self, + directive_id: Uuid, + step_id: Uuid, + ) -> Result<JsonValue, ApiError> { + self.post_empty(&format!("/api/v1/directives/{}/steps/{}/fail", directive_id, step_id)).await + } + + /// Mark a step as skipped. + pub async fn directive_skip_step( + &self, + directive_id: Uuid, + step_id: Uuid, + ) -> Result<JsonValue, ApiError> { + self.post_empty(&format!("/api/v1/directives/{}/steps/{}/skip", directive_id, step_id)).await + } + + /// Update the directive's goal. + pub async fn directive_update_goal( + &self, + directive_id: Uuid, + goal: &str, + ) -> Result<JsonValue, ApiError> { + let req = UpdateGoalRequest { goal: goal.to_string() }; + self.put(&format!("/api/v1/directives/{}/goal", directive_id), &req).await + } +} diff --git a/makima/src/daemon/api/mod.rs b/makima/src/daemon/api/mod.rs index 49d80e0..2d1efbf 100644 --- a/makima/src/daemon/api/mod.rs +++ b/makima/src/daemon/api/mod.rs @@ -2,6 +2,7 @@ pub mod client; pub mod contract; +pub mod directive; pub mod supervisor; pub use client::ApiClient; diff --git a/makima/src/daemon/cli/directive.rs b/makima/src/daemon/cli/directive.rs new file mode 100644 index 0000000..5de60ed --- /dev/null +++ b/makima/src/daemon/cli/directive.rs @@ -0,0 +1,101 @@ +//! Directive subcommand - directive management commands for orchestrator tasks. + +use clap::Args; +use uuid::Uuid; + +/// Common arguments for directive commands. +#[derive(Args, Debug, Clone)] +pub struct DirectiveArgs { + /// API URL + #[arg(long, env = "MAKIMA_API_URL", default_value = "https://api.makima.jp", global = true)] + pub api_url: String, + + /// API key for authentication + #[arg(long, env = "MAKIMA_API_KEY", global = true)] + pub api_key: String, + + /// Directive ID + #[arg(long, env = "MAKIMA_DIRECTIVE_ID", global = true)] + pub directive_id: Uuid, +} + +/// Arguments for listing directives (no directive_id required). +#[derive(Args, Debug, Clone)] +pub struct DirectiveListArgs { + /// API URL + #[arg(long, env = "MAKIMA_API_URL", default_value = "https://api.makima.jp", global = true)] + pub api_url: String, + + /// API key for authentication + #[arg(long, env = "MAKIMA_API_KEY", global = true)] + pub api_key: String, +} + +/// Arguments for add-step command. +#[derive(Args, Debug)] +pub struct AddStepArgs { + #[command(flatten)] + pub common: DirectiveArgs, + + /// Step name + pub name: String, + + /// Step description + #[arg(long)] + pub description: Option<String>, + + /// Task plan for the step + #[arg(long)] + pub task_plan: Option<String>, + + /// Comma-separated UUIDs of dependency steps + #[arg(long)] + pub depends_on: Option<String>, + + /// Order index + #[arg(long, default_value = "0")] + pub order_index: i32, +} + +/// Arguments for remove-step command. +#[derive(Args, Debug)] +pub struct RemoveStepArgs { + #[command(flatten)] + pub common: DirectiveArgs, + + /// Step ID to remove + pub step_id: Uuid, +} + +/// Arguments for set-deps command. +#[derive(Args, Debug)] +pub struct SetDepsArgs { + #[command(flatten)] + pub common: DirectiveArgs, + + /// Step ID to update + pub step_id: Uuid, + + /// Comma-separated UUIDs of dependency steps + pub depends_on: String, +} + +/// Arguments for complete-step/fail-step/skip-step commands. +#[derive(Args, Debug)] +pub struct StepActionArgs { + #[command(flatten)] + pub common: DirectiveArgs, + + /// Step ID + pub step_id: Uuid, +} + +/// Arguments for update-goal command. +#[derive(Args, Debug)] +pub struct UpdateGoalArgs { + #[command(flatten)] + pub common: DirectiveArgs, + + /// New goal text + pub goal: String, +} diff --git a/makima/src/daemon/cli/mod.rs b/makima/src/daemon/cli/mod.rs index 0805edd..faafaea 100644 --- a/makima/src/daemon/cli/mod.rs +++ b/makima/src/daemon/cli/mod.rs @@ -3,6 +3,7 @@ pub mod config; pub mod contract; pub mod daemon; +pub mod directive; pub mod server; pub mod supervisor; pub mod view; @@ -12,6 +13,7 @@ use clap::{Parser, Subcommand}; pub use config::CliConfig; pub use contract::ContractArgs; pub use daemon::DaemonArgs; +pub use directive::DirectiveArgs; pub use server::ServerArgs; pub use supervisor::SupervisorArgs; pub use view::ViewArgs; @@ -41,6 +43,10 @@ pub enum Commands { #[command(subcommand)] Contract(ContractCommand), + /// Directive commands for DAG-based project management + #[command(subcommand)] + Directive(DirectiveCommand), + /// Interactive TUI browser for contracts and tasks /// /// Provides a drill-down interface for browsing contracts, viewing their @@ -196,6 +202,49 @@ pub enum ContractCommand { CreateFile(contract::CreateFileArgs), } +/// Directive subcommands for DAG-based project management. +#[derive(Subcommand, Debug)] +pub enum DirectiveCommand { + /// List all directives + List(directive::DirectiveListArgs), + + /// Get directive status with steps + Get(DirectiveArgs), + + /// Get directive status (alias for get) + Status(DirectiveArgs), + + /// Add a step to the directive + AddStep(directive::AddStepArgs), + + /// Remove a step from the directive + RemoveStep(directive::RemoveStepArgs), + + /// Set dependencies for a step + SetDeps(directive::SetDepsArgs), + + /// Start the directive (begin executing steps) + Start(DirectiveArgs), + + /// Pause the directive + Pause(DirectiveArgs), + + /// Advance the DAG (find newly-ready steps) + Advance(DirectiveArgs), + + /// Mark a step as completed + CompleteStep(directive::StepActionArgs), + + /// Mark a step as failed + FailStep(directive::StepActionArgs), + + /// Mark a step as skipped + SkipStep(directive::StepActionArgs), + + /// Update the directive's goal (triggers re-planning) + UpdateGoal(directive::UpdateGoalArgs), +} + impl Cli { /// Parse command-line arguments pub fn parse_args() -> Self { diff --git a/makima/src/daemon/skills/directive.md b/makima/src/daemon/skills/directive.md new file mode 100644 index 0000000..7c55cf8 --- /dev/null +++ b/makima/src/daemon/skills/directive.md @@ -0,0 +1,111 @@ +--- +name: makima-directive +description: Directive commands for makima DAG-based project orchestration. Use these commands to manage long-lived directives with auto-progressing steps. +--- + +# Makima Directive Skill + +You are orchestrating a **directive** — a long-lived project managed through a DAG (directed acyclic graph) of steps. Unlike contracts which are finite and phase-based, directives are **ongoing and continuous**: they stay active as the project evolves, and new features/requirements can be added at any time. + +## Key Concepts + +- **Directive**: A long-lived top-level entity with a goal, repository info, and a mutable DAG of steps +- **Steps**: Nodes in the DAG. Each step can spawn a task using the mesh infrastructure +- **Auto-progression**: When a step completes, newly-ready steps (whose dependencies are met) automatically become ready +- **Continuous evolution**: The goal can be updated at any time. When all steps complete, the directive goes `idle` (not completed) — waiting for new work +- **Statuses**: `draft` → `active` ↔ `idle` → `archived`. Directives are never "completed" — they go idle and wait + +## Commands + +### Check Status +```bash +makima directive status +``` +Returns the directive with all steps, their statuses, and dependency information. + +### Add a Step +```bash +makima directive add-step "Step Name" --description "What this step does" --task-plan "Detailed instructions for the task" --depends-on "uuid1,uuid2" --order-index 1 +``` + +### Remove a Step +```bash +makima directive remove-step <step_id> +``` + +### Set Dependencies +```bash +makima directive set-deps <step_id> "dep_uuid1,dep_uuid2" +``` + +### Start the Directive +```bash +makima directive start +``` +Sets status to `active` and advances any steps with no dependencies to `ready`. + +### Advance the DAG +```bash +makima directive advance +``` +Finds newly-ready steps (all dependencies met) and marks them ready. If all steps are in terminal states, sets the directive to `idle`. + +### Complete a Step +```bash +makima directive complete-step <step_id> +``` + +### Fail a Step +```bash +makima directive fail-step <step_id> +``` + +### Skip a Step +```bash +makima directive skip-step <step_id> +``` + +### Update the Goal +```bash +makima directive update-goal "New or expanded goal text" +``` +Updates the goal and bumps `goalUpdatedAt`. If the directive is `idle`, it reactivates to `active`. + +### Pause +```bash +makima directive pause +``` + +## Orchestration Workflow + +### Initial Setup +1. Check the directive status to understand the goal +2. Decompose the goal into steps with clear dependencies +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 + +### Monitoring and Advancing +1. Periodically check status to see step progress +2. When tasks complete, the DAG auto-advances — newly-ready steps appear +3. Use `advance` to manually trigger DAG progression if needed +4. Mark steps as complete/failed/skipped as appropriate + +### Re-planning (When Goal Updates) +When the goal is updated (you'll see a new `goalUpdatedAt` timestamp): +1. Check the current status to see completed and in-progress steps +2. Identify what's new in the updated goal +3. Add new steps that depend on existing completed steps as appropriate +4. The DAG will auto-advance any newly-ready steps + +### Idle State +When all steps complete, the directive enters `idle` state. This is normal — it means: +- All current work is done +- The directive is waiting for new requirements +- When the user updates the goal, it reactivates automatically +- You should add new steps based on the updated goal + +## Environment Variables +- `MAKIMA_API_URL` - API server URL +- `MAKIMA_API_KEY` - Authentication key +- `MAKIMA_DIRECTIVE_ID` - Current directive ID (set automatically) diff --git a/makima/src/daemon/skills/mod.rs b/makima/src/daemon/skills/mod.rs index 0b05f3a..0c015ba 100644 --- a/makima/src/daemon/skills/mod.rs +++ b/makima/src/daemon/skills/mod.rs @@ -9,8 +9,12 @@ pub const SUPERVISOR_SKILL: &str = include_str!("supervisor.md"); /// Contract skill content - task-contract interaction commands pub const CONTRACT_SKILL: &str = include_str!("contract.md"); +/// Directive skill content - DAG-based project orchestration commands +pub const DIRECTIVE_SKILL: &str = include_str!("directive.md"); + /// All skills as (name, content) pairs for installation pub const ALL_SKILLS: &[(&str, &str)] = &[ ("makima-supervisor", SUPERVISOR_SKILL), ("makima-contract", CONTRACT_SKILL), + ("makima-directive", DIRECTIVE_SKILL), ]; |
