summaryrefslogtreecommitdiff
path: root/makima/src
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-26 20:26:28 +0000
committersoryu <soryu@soryu.co>2026-01-26 20:26:28 +0000
commit3dd8f32bad2b3ba886f0b0ab4c4796fd67ec0bca (patch)
tree8571846b2534d5ff3ec9335ed2aa75c07c4a176f /makima/src
parent04e1e8f0dd85d19917ac5ba0b73cba65ebac8976 (diff)
parent4c94ee44ca71eb2e80ed2bba3efb2f9cff581ae6 (diff)
downloadsoryu-3dd8f32bad2b3ba886f0b0ab4c4796fd67ec0bca.tar.gz
soryu-3dd8f32bad2b3ba886f0b0ab4c4796fd67ec0bca.zip
Phase 1.1: Add local_only flag to contracts
Diffstat (limited to 'makima/src')
-rw-r--r--makima/src/db/models.rs15
-rw-r--r--makima/src/db/repository.rs19
-rw-r--r--makima/src/server/handlers/contract_chat.rs1
-rw-r--r--makima/src/server/handlers/contracts.rs4
-rw-r--r--makima/src/server/handlers/transcript_analysis.rs1
5 files changed, 33 insertions, 7 deletions
diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs
index 95517a1..21e5370 100644
--- a/makima/src/db/models.rs
+++ b/makima/src/db/models.rs
@@ -1326,6 +1326,10 @@ pub struct Contract {
#[sqlx(json)]
#[serde(default)]
pub completed_deliverables: serde_json::Value,
+ /// When true, tasks do not auto-execute completion actions and work stays in worktrees.
+ /// Used for local-only workflows where changes are managed manually.
+ #[serde(default)]
+ pub local_only: bool,
pub version: i32,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
@@ -1441,6 +1445,9 @@ pub struct ContractSummary {
pub status: String,
/// Supervisor task ID for contract orchestration
pub supervisor_task_id: Option<Uuid>,
+ /// When true, tasks do not auto-execute completion actions and work stays in worktrees.
+ #[serde(default)]
+ pub local_only: bool,
pub file_count: i64,
pub task_count: i64,
pub repository_count: i64,
@@ -1495,6 +1502,10 @@ pub struct CreateContractRequest {
/// phase outputs before progressing to the next phase.
#[serde(default)]
pub phase_guard: Option<bool>,
+ /// Enable local-only mode for this contract.
+ /// When true, tasks do not auto-execute completion actions and work stays in worktrees.
+ #[serde(default)]
+ pub local_only: Option<bool>,
}
/// Request payload for updating a contract
@@ -1516,6 +1527,10 @@ pub struct UpdateContractRequest {
/// phase outputs before progressing to the next phase.
#[serde(default)]
pub phase_guard: Option<bool>,
+ /// Enable or disable local-only mode for this contract.
+ /// When true, tasks do not auto-execute completion actions and work stays in worktrees.
+ #[serde(default)]
+ pub local_only: Option<bool>,
/// Version for optimistic locking
pub version: Option<i32>,
}
diff --git a/makima/src/db/repository.rs b/makima/src/db/repository.rs
index b55b05e..6d6642b 100644
--- a/makima/src/db/repository.rs
+++ b/makima/src/db/repository.rs
@@ -2175,11 +2175,12 @@ pub async fn create_contract_for_owner(
let autonomous_loop = req.autonomous_loop.unwrap_or(false);
let phase_guard = req.phase_guard.unwrap_or(false);
+ let local_only = req.local_only.unwrap_or(false);
sqlx::query_as::<_, Contract>(
r#"
- INSERT INTO contracts (owner_id, name, description, contract_type, phase, autonomous_loop, phase_guard)
- VALUES ($1, $2, $3, $4, $5, $6, $7)
+ INSERT INTO contracts (owner_id, name, description, contract_type, phase, autonomous_loop, phase_guard, local_only)
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING *
"#,
)
@@ -2190,6 +2191,7 @@ pub async fn create_contract_for_owner(
.bind(phase)
.bind(autonomous_loop)
.bind(phase_guard)
+ .bind(local_only)
.fetch_one(pool)
.await
}
@@ -2222,7 +2224,7 @@ pub async fn list_contracts_for_owner(
r#"
SELECT
c.id, c.name, c.description, c.contract_type, c.phase, c.status,
- c.supervisor_task_id, c.version, c.created_at,
+ c.supervisor_task_id, c.local_only, c.version, c.created_at,
(SELECT COUNT(*) FROM files WHERE contract_id = c.id) as file_count,
(SELECT COUNT(*) FROM tasks WHERE contract_id = c.id) as task_count,
(SELECT COUNT(*) FROM contract_repositories WHERE contract_id = c.id) as repository_count
@@ -2246,7 +2248,7 @@ pub async fn get_contract_summary_for_owner(
r#"
SELECT
c.id, c.name, c.description, c.contract_type, c.phase, c.status,
- c.supervisor_task_id, c.version, c.created_at,
+ c.supervisor_task_id, c.local_only, c.version, c.created_at,
(SELECT COUNT(*) FROM files WHERE contract_id = c.id) as file_count,
(SELECT COUNT(*) FROM tasks WHERE contract_id = c.id) as task_count,
(SELECT COUNT(*) FROM contract_repositories WHERE contract_id = c.id) as repository_count
@@ -2290,14 +2292,15 @@ pub async fn update_contract_for_owner(
let supervisor_task_id = req.supervisor_task_id.or(existing.supervisor_task_id);
let autonomous_loop = req.autonomous_loop.unwrap_or(existing.autonomous_loop);
let phase_guard = req.phase_guard.unwrap_or(existing.phase_guard);
+ let local_only = req.local_only.unwrap_or(existing.local_only);
let result = if req.version.is_some() {
sqlx::query_as::<_, Contract>(
r#"
UPDATE contracts
SET name = $3, description = $4, phase = $5, status = $6,
- supervisor_task_id = $7, autonomous_loop = $8, phase_guard = $9, version = version + 1, updated_at = NOW()
- WHERE id = $1 AND owner_id = $2 AND version = $10
+ supervisor_task_id = $7, autonomous_loop = $8, phase_guard = $9, local_only = $10, version = version + 1, updated_at = NOW()
+ WHERE id = $1 AND owner_id = $2 AND version = $11
RETURNING *
"#,
)
@@ -2310,6 +2313,7 @@ pub async fn update_contract_for_owner(
.bind(supervisor_task_id)
.bind(autonomous_loop)
.bind(phase_guard)
+ .bind(local_only)
.bind(req.version.unwrap())
.fetch_optional(pool)
.await?
@@ -2318,7 +2322,7 @@ pub async fn update_contract_for_owner(
r#"
UPDATE contracts
SET name = $3, description = $4, phase = $5, status = $6,
- supervisor_task_id = $7, autonomous_loop = $8, phase_guard = $9, version = version + 1, updated_at = NOW()
+ supervisor_task_id = $7, autonomous_loop = $8, phase_guard = $9, local_only = $10, version = version + 1, updated_at = NOW()
WHERE id = $1 AND owner_id = $2
RETURNING *
"#,
@@ -2332,6 +2336,7 @@ pub async fn update_contract_for_owner(
.bind(supervisor_task_id)
.bind(autonomous_loop)
.bind(phase_guard)
+ .bind(local_only)
.fetch_optional(pool)
.await?
};
diff --git a/makima/src/server/handlers/contract_chat.rs b/makima/src/server/handlers/contract_chat.rs
index e035368..8c5509e 100644
--- a/makima/src/server/handlers/contract_chat.rs
+++ b/makima/src/server/handlers/contract_chat.rs
@@ -2574,6 +2574,7 @@ async fn handle_contract_request(
initial_phase: Some("research".to_string()),
autonomous_loop: None,
phase_guard: None,
+ local_only: None,
};
let contract = match repository::create_contract_for_owner(pool, owner_id, contract_req).await {
diff --git a/makima/src/server/handlers/contracts.rs b/makima/src/server/handlers/contracts.rs
index de3164c..3498063 100644
--- a/makima/src/server/handlers/contracts.rs
+++ b/makima/src/server/handlers/contracts.rs
@@ -366,6 +366,7 @@ pub async fn create_contract(
phase: contract.phase,
status: contract.status,
supervisor_task_id: contract.supervisor_task_id,
+ local_only: contract.local_only,
file_count: 0,
task_count: 0,
repository_count: 0,
@@ -387,6 +388,7 @@ pub async fn create_contract(
phase: contract.phase,
status: contract.status,
supervisor_task_id: contract.supervisor_task_id,
+ local_only: contract.local_only,
file_count: 0,
task_count: 0,
repository_count: 0,
@@ -515,6 +517,7 @@ pub async fn update_contract(
phase: contract.phase,
status: contract.status,
supervisor_task_id: contract.supervisor_task_id,
+ local_only: contract.local_only,
file_count: 0,
task_count: 0,
repository_count: 0,
@@ -1399,6 +1402,7 @@ pub async fn change_phase(
phase: updated_contract.phase,
status: updated_contract.status,
supervisor_task_id: updated_contract.supervisor_task_id,
+ local_only: updated_contract.local_only,
file_count: 0,
task_count: 0,
repository_count: 0,
diff --git a/makima/src/server/handlers/transcript_analysis.rs b/makima/src/server/handlers/transcript_analysis.rs
index 3b71eca..8eb50c7 100644
--- a/makima/src/server/handlers/transcript_analysis.rs
+++ b/makima/src/server/handlers/transcript_analysis.rs
@@ -278,6 +278,7 @@ pub async fn create_contract_from_analysis(
initial_phase: Some("research".to_string()),
autonomous_loop: None,
phase_guard: None,
+ local_only: None,
};
let contract = match repository::create_contract_for_owner(pool, auth.owner_id, contract_req).await {