diff options
| author | soryu <soryu@soryu.co> | 2026-01-29 01:26:17 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-29 01:26:17 +0000 |
| commit | 45a433c0eb63cae1322203ee14292f1c427a09c9 (patch) | |
| tree | d25e9f2734fde266e4cf9e6a1262d3e33f205375 | |
| parent | f6a40e2304585f140ed5766b25fe71a6958f4425 (diff) | |
| download | soryu-45a433c0eb63cae1322203ee14292f1c427a09c9.tar.gz soryu-45a433c0eb63cae1322203ee14292f1c427a09c9.zip | |
feat: Add Red Team UI to makima/frontend contract creation (#45)
- Add redTeamEnabled and redTeamPrompt state to contracts page
- Add "Enable Red Team Monitoring" checkbox with description
- Add conditional "Custom Review Criteria" textarea when enabled
- Include redTeamEnabled/redTeamPrompt in CreateContractRequest
- Reset red team fields when canceling contract creation
- Add redTeamEnabled to ContractSummary and Contract types
- Add redTeamEnabled/redTeamPrompt to CreateContractRequest type
- Add Red Team badge (🔍) to ContractList for enabled contracts
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
| -rw-r--r-- | makima/frontend/src/components/contracts/ContractList.tsx | 5 | ||||
| -rw-r--r-- | makima/frontend/src/lib/api.ts | 10 | ||||
| -rw-r--r-- | makima/frontend/src/routes/contracts.tsx | 59 |
3 files changed, 74 insertions, 0 deletions
diff --git a/makima/frontend/src/components/contracts/ContractList.tsx b/makima/frontend/src/components/contracts/ContractList.tsx index 98f8ff6..532ab87 100644 --- a/makima/frontend/src/components/contracts/ContractList.tsx +++ b/makima/frontend/src/components/contracts/ContractList.tsx @@ -136,6 +136,11 @@ export function ContractList({ Local </span> )} + {contract.redTeamEnabled && ( + <span className="px-1.5 py-0.5 font-mono text-[9px] uppercase text-cyan-400 border border-cyan-400/30 bg-cyan-400/10 shrink-0" title="Red Team monitoring enabled"> + 🔍 Red Team + </span> + )} </div> <span className={`text-[10px] font-mono uppercase shrink-0 ${ diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts index c9648a2..8838dbd 100644 --- a/makima/frontend/src/lib/api.ts +++ b/makima/frontend/src/lib/api.ts @@ -1682,6 +1682,8 @@ export interface ContractSummary { supervisorTaskId: string | null; /** When true, tasks won't auto-push or create PRs - use patch files instead */ localOnly: boolean; + /** When true, a red team task monitors work output for quality */ + redTeamEnabled: boolean; fileCount: number; taskCount: number; repositoryCount: number; @@ -1706,6 +1708,10 @@ export interface Contract { phaseGuard: boolean; /** When true, tasks won't auto-push or create PRs - use patch files instead */ localOnly: boolean; + /** When true, a red team task monitors work output for quality */ + redTeamEnabled: boolean; + /** Custom criteria for the red team to evaluate */ + redTeamPrompt: string | null; version: number; createdAt: string; updatedAt: string; @@ -1741,6 +1747,10 @@ export interface CreateContractRequest { initialPhase?: ContractPhase; /** When true, tasks won't auto-push or create PRs - use patch files instead */ localOnly?: boolean; + /** When true, spawn a red team task to monitor work output */ + redTeamEnabled?: boolean; + /** Custom criteria for the red team to evaluate */ + redTeamPrompt?: string; } export interface UpdateContractRequest { diff --git a/makima/frontend/src/routes/contracts.tsx b/makima/frontend/src/routes/contracts.tsx index 9891f29..bb66215 100644 --- a/makima/frontend/src/routes/contracts.tsx +++ b/makima/frontend/src/routes/contracts.tsx @@ -93,6 +93,8 @@ function ContractsPageContent() { const [contractTypes, setContractTypes] = useState<ContractTypeTemplate[]>([]); const [contractTypesLoading, setContractTypesLoading] = useState(false); const [localOnly, setLocalOnly] = useState(false); + const [redTeamEnabled, setRedTeamEnabled] = useState(false); + const [redTeamPrompt, setRedTeamPrompt] = useState(""); // Fetch contract types when modal opens - merges built-in types with user templates useEffect(() => { @@ -266,6 +268,8 @@ function ContractsPageContent() { contractType: contractType, initialPhase: initialPhase !== defaultPhaseForType ? initialPhase : undefined, localOnly: localOnly || undefined, + redTeamEnabled: redTeamEnabled || undefined, + redTeamPrompt: redTeamEnabled && redTeamPrompt.trim() ? redTeamPrompt.trim() : undefined, }; try { @@ -341,6 +345,8 @@ function ContractsPageContent() { setRepoUrl(""); setRepoPath(""); setLocalOnly(false); + setRedTeamEnabled(false); + setRedTeamPrompt(""); setCreateError(null); }, []); @@ -712,6 +718,59 @@ function ContractsPageContent() { </p> </div> + {/* Red Team Monitoring */} + <div className="border-t border-[rgba(117,170,252,0.2)] pt-4"> + <div className="flex items-center gap-3"> + <button + type="button" + onClick={() => setRedTeamEnabled(!redTeamEnabled)} + className={`w-5 h-5 flex items-center justify-center border transition-colors ${ + redTeamEnabled + ? "bg-[#0f3c78] border-[#75aafc] text-[#dbe7ff]" + : "bg-[#0d1b2d] border-[#3f6fb3] text-transparent" + }`} + > + {redTeamEnabled && ( + <svg + xmlns="http://www.w3.org/2000/svg" + width="12" + height="12" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + strokeWidth="3" + strokeLinecap="round" + strokeLinejoin="round" + > + <polyline points="20 6 9 17 4 12" /> + </svg> + )} + </button> + <label + className="font-mono text-sm text-[#dbe7ff] cursor-pointer select-none" + onClick={() => setRedTeamEnabled(!redTeamEnabled)} + > + Enable Red Team Monitoring + </label> + </div> + <p className="font-mono text-xs text-[#8b949e] pl-8"> + Spawns a parallel task to monitor work output for quality and compliance. + </p> + {redTeamEnabled && ( + <div className="mt-3 pl-8"> + <label className="block font-mono text-xs text-[#75aafc] uppercase mb-2"> + Custom Review Criteria (Optional) + </label> + <textarea + value={redTeamPrompt} + onChange={(e) => setRedTeamPrompt(e.target.value)} + placeholder="e.g., 'Focus on security best practices' or 'Ensure all functions have tests'" + className="w-full px-3 py-2 bg-[#0d1b2d] border border-[#3f6fb3] text-[#dbe7ff] text-sm font-mono h-20 resize-none focus:border-[#75aafc] focus:outline-none" + /> + </div> + )} + </div> + {/* Repository Configuration */} <div className="border-t border-[rgba(117,170,252,0.2)] pt-4"> <label className="block font-mono text-xs text-[#75aafc] uppercase mb-3"> |
