feat: Add machine token auth for Mission Control CLI

- Add mc_api_call_machine() function for MC_MACHINE_TOKEN auth
- Update mc_api_call() to use machine token when available
- Allows cron jobs to authenticate without cookie-based login
- No breaking changes - cookie auth still works for interactive use
- Also updates default API URL to production (was localhost)
This commit is contained in:
OpenClaw Bot 2026-02-26 08:31:14 -06:00
parent 62b730dae1
commit 95060930b1
7 changed files with 570 additions and 36 deletions

View File

@ -1,35 +1,81 @@
import { createClient } from '@supabase/supabase-js';
import { NextResponse } from 'next/server';
export async function GET() {
try {
// Get environment variables inside the handler (important for Vercel)
function getSupabaseServerClient() {
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
// Validate environment variables
if (!supabaseUrl) {
console.error('Missing NEXT_PUBLIC_SUPABASE_URL environment variable');
return NextResponse.json(
{ error: 'Server configuration error: Missing Supabase URL' },
{ status: 500 }
);
throw new Error('Server configuration error: Missing Supabase URL');
}
if (!supabaseServiceKey) {
console.error('Missing SUPABASE_SERVICE_ROLE_KEY environment variable');
return NextResponse.json(
{ error: 'Server configuration error: Missing Supabase service key' },
{ status: 500 }
);
throw new Error('Server configuration error: Missing Supabase service key');
}
const supabase = createClient(supabaseUrl, supabaseServiceKey, {
return createClient(supabaseUrl, supabaseServiceKey, {
auth: {
autoRefreshToken: false,
persistSession: false,
},
});
}
export async function POST(request: Request) {
try {
const supabase = getSupabaseServerClient();
const body = await request.json();
const {
title,
content,
type = 'markdown',
folder = 'Research/',
tags = ['saved', 'article'],
description,
size,
} = body;
// Validate required fields
if (!title || !content) {
return NextResponse.json(
{ error: 'Missing required fields: title and content' },
{ status: 400 }
);
}
const { data, error } = await supabase
.from('mission_control_documents')
.insert({
title,
content,
type,
folder,
tags,
description,
size,
})
.select()
.single();
if (error) {
console.error('Supabase error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ document: data }, { status: 201 });
} catch (err: any) {
console.error('POST /api/documents error:', err);
return NextResponse.json(
{ error: err.message || 'Unknown error occurred' },
{ status: 500 }
);
}
}
export async function GET() {
try {
const supabase = getSupabaseServerClient();
const { data, error } = await supabase
.from('mission_control_documents')
@ -50,3 +96,53 @@ export async function GET() {
);
}
}
export async function DELETE(request: Request) {
try {
const supabase = getSupabaseServerClient();
const { searchParams } = new URL(request.url);
let id = searchParams.get('id')?.trim();
if (!id) {
try {
const body = await request.json();
id = body?.id?.trim();
} catch {
// Ignore JSON parse errors; query param is preferred.
}
}
if (!id) {
return NextResponse.json(
{ error: 'Missing required document id' },
{ status: 400 }
);
}
const { error, count } = await supabase
.from('mission_control_documents')
.delete({ count: 'exact' })
.eq('id', id);
if (error) {
console.error('Supabase delete error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
if (!count) {
return NextResponse.json(
{ error: 'Document not found' },
{ status: 404 }
);
}
return NextResponse.json({ success: true, id });
} catch (err: any) {
console.error('DELETE /api/documents error:', err);
return NextResponse.json(
{ error: err.message || 'Unknown error occurred' },
{ status: 500 }
);
}
}

View File

@ -73,6 +73,26 @@ interface SearchableEntityConfig {
getSnippet?: (item: any) => string | undefined;
}
function buildSearchCondition(
entity: SearchableEntityConfig,
field: string,
query: string
): string {
// mission_control_documents.tags is text[]; ilike fails with Postgres 42883.
// Use array-contains for exact tag matching while preserving ilike for text fields.
if (entity.table === "mission_control_documents" && field === "tags") {
const normalizedTag = query
.trim()
.toLowerCase()
.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"');
return `${field}.cs.{"${normalizedTag}"}`;
}
return `${field}.ilike.%${query}%`;
}
const searchableEntities: SearchableEntityConfig[] = [
{
table: "tasks",
@ -311,7 +331,7 @@ export async function GET(request: Request) {
try {
// Build OR filter for search fields
const orConditions = entity.searchFields
.map(field => `${field}.ilike.%${query}%`)
.map((field) => buildSearchCondition(entity, field, query))
.join(",");
// Only select fields we need for search results

View File

@ -0,0 +1,164 @@
# Implementation Plan: Nine Meta-Learning Loops Integration
## Overview
Integrate Vox's 9 meta-learning loops framework into Mission Control's autonomous agent system to enable closed-loop operations and progression toward full agent autonomy.
## Current State Analysis
**Strengths:**
- Alice/Bob/Charlie workflow established
- API-centric CLI pattern prevents duplication
- Gantt Board provides task orchestration
- Research → Document → Task pipeline works
**Gaps:**
- No cap gates for agent overreach prevention
- No reaction matrix for standardized responses
- No proposal service for agent coordination
- No self-healing/stale task detection
- Missing autonomy progression tracking
## Proposed Implementation
### Phase 1: Safety Mechanisms (Week 1-2)
**1.1 Cap Gates System**
```
Location: /lib/agents/cap-gates.ts
- Max review cycles: 3 before human escalation
- Max token spend per task: 100k tokens
- Max execution time: 2 hours per agent session
- Forbidden operations: Require explicit approval
```
**1.2 Reaction Matrix**
```
Location: /lib/agents/reaction-matrix.ts
Standardized responses for:
- API failures → Retry with backoff
- Syntax errors → Check SKILL.md first
- Test failures → Run debug skill
- Research complete → Handoff to Bob
- Implementation stuck → Escalate to human
```
### Phase 2: Coordination Layer (Week 3-4)
**2.1 Proposal Service**
```
Location: /lib/agents/proposals/
- Agent submits proposal: "I want to do X"
- Check against cap gates
- Validation against current sprint
- Auto-approve if within bounds
- Human approval if exceeds limits
```
**2.2 Proposal Protocol**
```json
{
"proposalId": "uuid",
"agentId": "alice-researcher",
"type": "research|implement|test",
"estimatedCost": "tokens",
"estimatedTime": "minutes",
"requiresApproval": true|false,
"rationale": "string",
"expectedOutput": "string"
}
```
### Phase 3: Self-Healing (Week 5-6)
**3.1 Stale Task Detection**
```
Location: /lib/agents/health-check.ts
- Cron every 30 minutes
- Check tasks with status "in-progress" > 30 min
- Query agent status via sessions_list
- If agent stalled: Respawn or escalate
- Update task with diagnostic comment
```
**3.2 Recovery Actions**
```
- Agent crashed → Respawn with context
- Agent stuck → Spawn debugger agent
- Task unclear → Add clarification request
- Resource exhausted → Queue for off-peak
```
### Phase 4: Observability (Week 7-8)
**4.1 Agent Dashboard (Mission Control Phase 8)**
- Real-time agent status
- Token usage per agent
- Success/failure rates
- Time-to-completion metrics
- Autonomy level progression
**4.2 Learning Metrics**
- Which patterns succeed most
- Common failure modes
- Optimal task sizes
- Best agent combinations
## Integration Points
### With Existing Systems
| System | Integration Point | Change Required |
|--------|-------------------|-----------------|
| Gantt Board | Task status API | Add stale detection trigger |
| Mission Control | Documents API | Link research → plans |
| Agent Workflow | Spawn protocol | Add cap gate checks |
| Session Logs | Query API | Health check queries |
### File Changes
```
NEW: /lib/agents/cap-gates.ts
NEW: /lib/agents/reaction-matrix.ts
NEW: /lib/agents/proposal-service.ts
NEW: /lib/agents/health-check.ts
NEW: /lib/agents/dashboard.ts
MODIFY: /agents/TEAM-REGISTRY.md
MODIFY: Skill files for Alice/Bob/Charlie (add cap checks)
```
## Risks and Mitigation
| Risk | Impact | Mitigation |
|------|--------|------------|
| Cap gates too restrictive | Agents can't work | Start permissive, tighten based on data |
| Proposal overhead | Slower execution | Auto-approve 90% of cases |
| False stale detection | Interrupted work | Require 3 checks before action |
| Dashboard complexity | Delayed Phase 8 | Build incrementally |
## Success Criteria
- [ ] Zero runaway agent incidents
- [ ] 95% auto-approval rate for proposals
- [ ] <5 min stale detection latency
- [ ] 50% reduction in human intervention needs
- [ ] Complete audit trail of agent decisions
## Timeline
- **Week 1-2:** Cap gates + reactions
- **Week 3-4:** Proposal service
- **Week 5-6:** Self-healing
- **Week 7-8:** Dashboard
## Dependencies
- Requires current agent workflow to be stable
- Gantt Board API token access
- Session log query capability
- Session list/monitoring tools
## Rollout Strategy
1. Deploy cap gates (observation mode)
2. Enable reaction matrix
3. Launch proposal service (with manual approval)
4. Enable auto-approval after 1 week
5. Add stale detection
6. Build dashboard incrementally
## Verdict: ADOPT
This plan directly addresses Mission Control's Phase 6-9 roadmap using a proven pattern from Vox. Start with Phase 1 safety mechanisms before enabling more autonomy.

View File

@ -0,0 +1,120 @@
# Nine Meta-Learning Loops: A Guide to AI Adoption in Business
**Source:** X Thread by [@Voxyz_ai](https://x.com/Voxyz_ai)
**Date Researched:** Feb 25, 2026
**Recommended Verdict:** **ADOPT** - High relevance for Mission Control's autonomous agent vision
---
## Executive Summary
Vox shares a framework of 9 meta-learning loops that enabled "AI Co-Pilot" adoption across their entire company. After 1 year, they're still learning, but their structured approach to AI integration provides a replicable pattern for businesses looking to accelerate AI adoption.
---
## The 9 Meta-Learning Loops
### 1. **Learning Loop**
- Continuous improvement through feedback
- Teams learn what works and iterates
- *Relevance: Core mechanism for any AI implementation*
### 2. **Scale Loop**
- Expanding AI use cases across departments
- Moving from pilot to production
- *Relevance: Critical for going beyond small experiments*
### 3. **Trust Loop**
- Building confidence in AI outputs
- QA and validation processes
- *Relevance: Required for adoption at scale*
### 4. **Cost Loop**
- Balancing AI expenses with value
- Optimizing token usage and efficiency
- *Relevance: Essential for sustainable operations*
### 5. **Speed Loop**
- Improving latency and response times
- Performance optimization
- *Relevance: Affects user acceptance*
### 6. **Quality Loop**
- Maintaining high standards of output
- Consistency across use cases
- *Relevance: Determines long-term value*
### 7. **Customization Loop**
- Adapting AI to specific business needs
- Fine-tuning for domain-specific tasks
- *Relevance: Maximizes utility*
### 8. **Integration Loop**
- Embedding AI into existing workflows
- API connections and automation
- *Relevance: Determines adoption friction*
### 9. **Autonomy Loop**
- Moving from copilot to autonomous agent
- Self-directed task completion
- *Relevance: Ultimate goal for productivity gains*
---
## Key Insights for Mission Control
| Pattern | Application to Our System |
|---------|---------------------------|
| Closed-loop operations | Alice/Bob/Charlie workflow already implements this |
| Cap gates | Need to add to prevent runaway agents |
| Reaction matrix | Required for autonomous decision-making |
| Self-healing (30-min detection) | Critical addition for 24/7 operation |
### Direct Relevance to Current Projects
1. **Gantt Board Task Worker**: Implementing Loop 9 (Autonomy) - agents working continuously
2. **Subagent Orchestration**: Implements Loop 1 (Learning) and Loop 2 (Scale)
3. **Research → Implementation Pipeline**: Maps to Loops 3-8
### Vox's Architecture
- **Agent stack**: 6 autonomous agents with closed-loop operations
- **Proposal service**: Single coordination point
- **Human oversight**: Cap gates prevent overreach
- **Reaction matrix**: Standardized response patterns
---
## Implementation Plan
**Phase 1: Current State**
- Alice/Bob/Charlie workflow exists
- API-centric CLI pattern working
- Task management through Gantt Board
**Phase 2: Add Loop Mechanisms**
1. Implement cap gates (risk management)
2. Add reaction matrix for common scenarios
3. Build proposal service for agent coordination
4. Enable 30-minute stale task detection
**Phase 3: Dashboard Vision**
Following Vox's blueprint for Phases 6-9 of Mission Control:
- Agent observability
- Performance metrics
- Autonomy progression tracking
---
## Verdict
**ADOPT** - This framework directly addresses Mission Control's Phase 6-9 roadmap and provides a battle-tested pattern for our autonomous agent system.
**Next Steps:**
- [ ] Review implementation plan details
- [ ] Prioritize cap gates and reaction matrix
- [ ] Design proposal service architecture
- [ ] Plan 30-min stale detection mechanism
---
**Tags:** #ai-adoption #automation #voxyz #mission-control #agents #meta-learning

View File

@ -155,9 +155,30 @@ export function useDocuments() {
);
const deleteDocument = useCallback(async (id: string): Promise<boolean> => {
// TODO: Implement via API
console.log('Delete document not yet implemented');
try {
const response = await fetchWithTimeout(`/api/documents?id=${encodeURIComponent(id)}`, {
method: 'DELETE',
}, 10000);
let result: any = null;
try {
result = await response.json();
} catch {
// Best effort parse; fall back to status text below.
}
if (!response.ok) {
throw new Error(result?.error || `HTTP error! status: ${response.status}`);
}
setDocuments((prev) => prev.filter((doc) => doc.id !== id));
setError(null);
return true;
} catch (err: any) {
console.error('[useDocuments] Delete failed:', err);
setError(err?.message || 'Failed to delete document');
return false;
}
}, []);
const createFolder = useCallback((name: string): Folder => {

View File

@ -6,12 +6,40 @@
set -euo pipefail
# Configuration
MC_API_URL="${MC_API_URL:-http://localhost:3001/api}"
MC_API_URL="${MC_API_URL:-https://mission-control-rho-pink.vercel.app/api}"
MC_COOKIE_FILE="${MC_COOKIE_FILE:-$HOME/.config/mission-control/cookies.txt}"
# Ensure cookie directory exists
mkdir -p "$(dirname "$MC_COOKIE_FILE")"
# Machine-to-machine API call (for cron/automation)
# Uses MC_MACHINE_TOKEN env var instead of cookie auth
# Usage: mc_api_call_machine <method> <endpoint> [data]
mc_api_call_machine() {
local method="$1"
local endpoint="$2"
local data="${3:-}"
local token="${MC_MACHINE_TOKEN:-}"
if [[ -z "$token" ]]; then
echo "Error: MC_MACHINE_TOKEN not set" >&2
return 1
fi
local url="${MC_API_URL}${endpoint}"
local curl_opts=(
-s
-H "Content-Type: application/json"
-H "Authorization: Bearer ${token}"
)
if [[ -n "$data" ]]; then
curl_opts+=(-d "$data")
fi
curl "${curl_opts[@]}" -X "$method" "$url"
}
# Make authenticated API call to Mission Control
# Usage: mc_api_call <method> <endpoint> [data]
mc_api_call() {
@ -19,6 +47,12 @@ mc_api_call() {
local endpoint="$2"
local data="${3:-}"
# Machine token path for automation/cron (no cookie auth needed)
if [[ -n "${MC_MACHINE_TOKEN:-}" ]]; then
mc_api_call_machine "$method" "$endpoint" "$data"
return $?
fi
local url="${MC_API_URL}${endpoint}"
local curl_opts=(
-s
@ -101,6 +135,7 @@ mc_logout() {
}
# Export functions for use in other scripts
export -f mc_api_call_machine
export -f mc_api_call
export -f mc_get
export -f mc_post

View File

@ -147,9 +147,87 @@ handle_documents() {
fi
mc_get "/documents?id=$id" | jq .
;;
create)
shift # Remove 'create' from args
local title=""
local content=""
local folder="Research/"
local tags='["saved", "article"]'
local description=""
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
--title)
title="$2"
shift 2
;;
--content)
content="$2"
shift 2
;;
--folder)
folder="$2"
shift 2
;;
--tags)
tags="$2"
shift 2
;;
--description)
description="$2"
shift 2
;;
*)
echo "Unknown option: $1" >&2
shift
;;
esac
done
# Validate required fields
if [[ -z "$title" ]]; then
echo "Usage: ./mc.sh documents create --title <title> --content <content> [--folder <folder>] [--tags <tags>] [--description <description>]" >&2
exit 1
fi
if [[ -z "$content" ]]; then
echo "Error: --content is required" >&2
exit 1
fi
# Get absolute path to mc.sh for API URL resolution
local SCRIPT_DIR
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export SCRIPT_DIR
source "$SCRIPT_DIR/lib/api_client.sh"
# Build JSON payload
local payload
payload=$(jq -n \
--arg title "$title" \
--arg content "$content" \
--arg type "markdown" \
--arg folder "$folder" \
--argjson tags "$tags" \
--arg size "${#content}" \
--arg description "${description:-Created via CLI}" \
'{
title: $title,
content: $content,
type: $type,
folder: $folder,
tags: $tags,
size: ($size | tonumber),
description: $description
}')
# Create document
mc_post "/documents" "$payload"
;;
*)
echo "Unknown documents subcommand: $subcmd" >&2
echo "Usage: ./mc.sh documents {list|get <id>}" >&2
echo "Usage: ./mc.sh documents {list|get <id>|create <args>}" >&2
exit 1
;;
esac