From eff0d844ca6e35bfbc2d5fdaa2d2f92177611f2e Mon Sep 17 00:00:00 2001
From: soryu <soryu@soryu.co>
Date: Thu, 15 Jan 2026 00:23:44 +0000
Subject: Contract type system

---
 makima/frontend/src/routes/contracts.tsx | 72 +++++++++++++++++++++++++++-----
 1 file changed, 62 insertions(+), 10 deletions(-)

(limited to 'makima/frontend/src/routes/contracts.tsx')

diff --git a/makima/frontend/src/routes/contracts.tsx b/makima/frontend/src/routes/contracts.tsx
index 8c90804..f09ec5b 100644
--- a/makima/frontend/src/routes/contracts.tsx
+++ b/makima/frontend/src/routes/contracts.tsx
@@ -11,10 +11,12 @@ import type {
   ContractWithRelations,
   ContractPhase,
   ContractStatus,
+  ContractType,
   CreateContractRequest,
   RepositorySourceType,
   DaemonDirectory,
 } from "../lib/api";
+import { getValidPhases, getDefaultPhase } from "../lib/api";
 
 export default function ContractsPage() {
   const { isAuthenticated, isAuthConfigured, isLoading: authLoading } = useAuth();
@@ -71,7 +73,8 @@ function ContractsPageContent() {
   const [isCreating, setIsCreating] = useState(false);
   const [newContractName, setNewContractName] = useState("");
   const [newContractDescription, setNewContractDescription] = useState("");
-  const [initialPhase, setInitialPhase] = useState<ContractPhase>("research");
+  const [contractType, setContractType] = useState<ContractType>("simple");
+  const [initialPhase, setInitialPhase] = useState<ContractPhase>("plan");
   const [repoType, setRepoType] = useState<RepositorySourceType>("remote");
   const [repoName, setRepoName] = useState("");
   const [repoUrl, setRepoUrl] = useState("");
@@ -136,7 +139,8 @@ function ContractsPageContent() {
     const data: CreateContractRequest = {
       name: newContractName.trim(),
       description: newContractDescription.trim() || undefined,
-      initialPhase: initialPhase !== "research" ? initialPhase : undefined,
+      contractType: contractType,
+      initialPhase: initialPhase !== getDefaultPhase(contractType) ? initialPhase : undefined,
     };
 
     try {
@@ -171,7 +175,8 @@ function ContractsPageContent() {
         setIsCreating(false);
         setNewContractName("");
         setNewContractDescription("");
-        setInitialPhase("research");
+        setContractType("simple");
+        setInitialPhase("plan");
         setRepoType("remote");
         setRepoName("");
         setRepoUrl("");
@@ -184,6 +189,8 @@ function ContractsPageContent() {
   }, [
     newContractName,
     newContractDescription,
+    contractType,
+    initialPhase,
     repoType,
     repoName,
     repoUrl,
@@ -200,7 +207,8 @@ function ContractsPageContent() {
     setIsCreating(false);
     setNewContractName("");
     setNewContractDescription("");
-    setInitialPhase("research");
+    setContractType("simple");
+    setInitialPhase("plan");
     setRepoType("remote");
     setRepoName("");
     setRepoUrl("");
@@ -424,6 +432,48 @@ function ContractsPageContent() {
                   />
                 </div>
 
+                {/* Contract Type */}
+                <div>
+                  <label className="block font-mono text-xs text-[#8b949e] uppercase mb-1">
+                    Contract Type
+                  </label>
+                  <div className="flex gap-2">
+                    <button
+                      type="button"
+                      onClick={() => {
+                        setContractType("simple");
+                        setInitialPhase("plan");
+                      }}
+                      className={`flex-1 px-3 py-2 font-mono text-xs uppercase transition-colors ${
+                        contractType === "simple"
+                          ? "bg-[#0f3c78] text-[#dbe7ff] border border-[#75aafc]"
+                          : "bg-[#0d1b2d] text-[#8b949e] border border-[#3f6fb3] hover:border-[#75aafc]"
+                      }`}
+                    >
+                      Simple
+                    </button>
+                    <button
+                      type="button"
+                      onClick={() => {
+                        setContractType("specification");
+                        setInitialPhase("research");
+                      }}
+                      className={`flex-1 px-3 py-2 font-mono text-xs uppercase transition-colors ${
+                        contractType === "specification"
+                          ? "bg-[#0f3c78] text-[#dbe7ff] border border-[#75aafc]"
+                          : "bg-[#0d1b2d] text-[#8b949e] border border-[#3f6fb3] hover:border-[#75aafc]"
+                      }`}
+                    >
+                      Specification
+                    </button>
+                  </div>
+                  <p className="mt-1 font-mono text-xs text-[#8b949e]">
+                    {contractType === "simple"
+                      ? "Plan → Execute: Simple workflow with a plan document"
+                      : "Research → Specify → Plan → Execute → Review: Full specification-driven development with TDD"}
+                  </p>
+                </div>
+
                 {/* Starting Phase */}
                 <div>
                   <label className="block font-mono text-xs text-[#8b949e] uppercase mb-1">
@@ -434,14 +484,16 @@ function ContractsPageContent() {
                     onChange={(e) => setInitialPhase(e.target.value as ContractPhase)}
                     className="w-full px-3 py-2 bg-[#0d1b2d] border border-[#3f6fb3] text-[#dbe7ff] font-mono text-sm focus:outline-none focus:border-[#75aafc]"
                   >
-                    <option value="research">Research</option>
-                    <option value="specify">Specify</option>
-                    <option value="plan">Plan</option>
-                    <option value="execute">Execute</option>
-                    <option value="review">Review</option>
+                    {getValidPhases(contractType).map((phase) => (
+                      <option key={phase} value={phase}>
+                        {phase.charAt(0).toUpperCase() + phase.slice(1)}
+                      </option>
+                    ))}
                   </select>
                   <p className="mt-1 font-mono text-xs text-[#8b949e]">
-                    Skip earlier phases if you already have requirements defined
+                    {contractType === "simple"
+                      ? "Start in Plan to define what to build, or Execute if already planned"
+                      : "Skip earlier phases if you already have requirements defined"}
                   </p>
                 </div>
 
-- 
cgit v1.2.3

