🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Mission Control Builder

by @shukiclaw

Build a personal dashboard for OpenClaw with task management, memory browser, calendar, team tracking, and GitHub trends. Use when the user wants to create a...

Versionv1.0.0
Downloads1,123
Stars⭐ 1
TERMINAL
clawhub install mission-control-builder

πŸ“– About This Skill


name: mission-control description: Build a personal dashboard for OpenClaw with task management, memory browser, calendar, team tracking, and GitHub trends. Use when the user wants to create a web-based mission control dashboard for their OpenClaw instance, track tasks, view memories, manage calendar events, or build a custom dashboard interface.

Mission Control Skill

Build your own personal dashboard for OpenClaw - a central command center for tasks, memories, calendar, and team management.

What You'll Build

A Next.js web dashboard that connects to your OpenClaw instance and provides:

  • Task Board - Kanban-style task management
  • Memory Browser - Search and view your OpenClaw memories
  • Calendar View - See scheduled events and cron jobs
  • Team Status - Track who's working on what
  • GitHub Trends - Discover trending repositories
  • Architecture Overview

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚         Next.js Frontend            β”‚
    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
    β”‚  β”‚  Task   β”‚ β”‚ Memory  β”‚ β”‚Calendarβ”‚ β”‚
    β”‚  β”‚  Board  β”‚ β”‚  List   β”‚ β”‚  View  β”‚ β”‚
    β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β”‚
    β”‚       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚
    β”‚              β”‚                       β”‚
    β”‚       β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”                β”‚
    β”‚       β”‚   API Routes β”‚               β”‚
    β”‚       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜                β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
           β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”
           β”‚               β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
    β”‚ Local JSON  β”‚ β”‚  OpenClaw   β”‚
    β”‚   Files     β”‚ β”‚   Memory    β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    

    Prerequisites

  • Node.js 18+
  • OpenClaw installed and running
  • Basic knowledge of React/Next.js
  • Step-by-Step Guide

    Step 1: Initialize Project

    npx create-next-app@latest mission-control --typescript --tailwind
    

    Step 2: Install Dependencies

    cd mission-control
    npm install lucide-react
    

    Step 3: Create Data Layer

    Create src/lib/data.ts for file-based storage:

    import fs from "fs/promises";
    import path from "path";

    const DATA_DIR = path.join(process.cwd(), "src", "data");

    // Types export interface Task { id: string; title: string; description: string; status: "todo" | "in-progress" | "done"; assignee: string; createdAt: string; updatedAt: string; }

    // Initialize data files async function initDataFile(filename: string, defaultData: unknown) { const filepath = path.join(DATA_DIR, filename); try { await fs.access(filepath); } catch { await fs.mkdir(DATA_DIR, { recursive: true }); await fs.writeFile(filepath, JSON.stringify(defaultData, null, 2)); } return filepath; }

    // Tasks export async function getTasks(): Promise { const filepath = await initDataFile("tasks.json", []); const data = await fs.readFile(filepath, "utf-8"); return JSON.parse(data); }

    export async function addTask(task: Omit): Promise { const tasks = await getTasks(); const newTask: Task = { ...task, id: Date.now().toString(), createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; tasks.push(newTask); await fs.writeFile( path.join(DATA_DIR, "tasks.json"), JSON.stringify(tasks, null, 2) ); return newTask; }

    export async function updateTask(id: string, updates: Partial): Promise { const tasks = await getTasks(); const index = tasks.findIndex((t) => t.id === id); if (index === -1) return null; tasks[index] = { ...tasks[index], ...updates, updatedAt: new Date().toISOString() }; await fs.writeFile( path.join(DATA_DIR, "tasks.json"), JSON.stringify(tasks, null, 2) ); return tasks[index]; }

    Step 4: Create API Routes

    Create src/app/api/tasks/route.ts:

    import { NextRequest, NextResponse } from "next/server";
    import { getTasks, addTask, updateTask } from "@/lib/data";

    export async function GET() { const tasks = await getTasks(); return NextResponse.json(tasks); }

    export async function POST(request: NextRequest) { try { const body = await request.json(); const task = await addTask(body); return NextResponse.json(task, { status: 201 }); } catch (error) { return NextResponse.json( { error: "Failed to create task" }, { status: 500 } ); } }

    export async function PUT(request: NextRequest) { try { const { id, ...updates } = await request.json(); const task = await updateTask(id, updates); if (!task) { return NextResponse.json({ error: "Task not found" }, { status: 404 }); } return NextResponse.json(task); } catch (error) { return NextResponse.json( { error: "Failed to update task" }, { status: 500 } ); } }

    Step 5: Create Components

    Navigation Component (src/components/Navigation.tsx):

    "use client";

    import Link from "next/link"; import { usePathname } from "next/navigation"; import { useState } from "react"; import { LayoutDashboard, ClipboardList, Menu, X } from "lucide-react";

    const navItems = [ { href: "/", label: "Dashboard", icon: LayoutDashboard }, { href: "/tasks", label: "Tasks", icon: ClipboardList }, ];

    export function Navigation() { const pathname = usePathname(); const [mobileMenuOpen, setMobileMenuOpen] = useState(false);

    return ( <> {/* Desktop Sidebar */}

    {/* Mobile Header */}

    Mission Control

    {/* Mobile Drawer */} {mobileMenuOpen && (

    )} ); }

    Step 6: Create Task Board

    "use client";

    import { useState, useEffect } from "react";

    interface Task { id: string; title: string; description: string; status: "todo" | "in-progress" | "done"; assignee: string; }

    export function TaskBoard() { const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true);

    useEffect(() => { fetchTasks(); }, []);

    const fetchTasks = async () => { try { const response = await fetch("/api/tasks"); const data = await response.json(); setTasks(data); } finally { setLoading(false); } };

    const handleUpdateStatus = async (taskId: string, newStatus: Task["status"]) => { await fetch("/api/tasks", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id: taskId, status: newStatus }), }); fetchTasks(); };

    const tasksByStatus = { todo: tasks.filter((t) => t.status === "todo"), "in-progress": tasks.filter((t) => t.status === "in-progress"), done: tasks.filter((t) => t.status === "done"), };

    if (loading) return

    Loading...
    ;

    return (

    {Object.entries(tasksByStatus).map(([status, statusTasks]) => (

    {status}

    {statusTasks.map((task) => (

    {task.title}

    ))}
    ))}
    ); }

    Step 7: OpenClaw Memory Sync

    Create src/app/api/sync/route.ts:

    import { NextResponse } from "next/server";
    import fs from "fs/promises";
    import path from "path";

    export async function GET() { try { // Read OpenClaw memory files const memoryDir = path.join(process.env.HOME || "", "clawd", "memory"); const files = await fs.readdir(memoryDir); const memories = []; for (const file of files.filter(f => f.endsWith('.md'))) { const content = await fs.readFile(path.join(memoryDir, file), 'utf-8'); memories.push({ id: file, title: file.replace('.md', ''), content: content.slice(0, 500) + '...', createdAt: new Date().toISOString(), }); } return NextResponse.json(memories); } catch (error) { return NextResponse.json([]); } }

    Step 8: Create Layout

    import type { Metadata } from "next";
    import "./globals.css";
    import { Navigation } from "@/components/Navigation";

    export const metadata: Metadata = { title: "Mission Control", description: "Personal dashboard for OpenClaw", };

    export default function RootLayout({ children, }: { children: React.ReactNode; }) { return (

    {children}
    ); }

    Step 9: Start Script

    Create start.sh:

    #!/bin/bash
    cd "$(dirname "$0")"
    npm run dev
    

    Make it executable:

    chmod +x start.sh
    

    Step 10: Run

    ./start.sh
    

    Open http://localhost:3000

    Extending Mission Control

    Add GitHub Trends

    // src/app/api/github-trends/route.ts
    export async function GET() {
      const response = await fetch(
        "https://api.github.com/search/repositories?q=stars:>1000&sort=stars&per_page=10"
      );
      const data = await response.json();
      return NextResponse.json(data.items);
    }
    

    Add Calendar Events

    Store events in src/data/calendar.json and create similar API routes.

    Add Team Members

    Create src/data/team.json with member info and current tasks.

    Mobile Responsiveness Tips

    1. Use Tailwind breakpoints: lg: for desktop, default for mobile 2. Touch targets: Minimum 40px for buttons 3. Horizontal scroll: For Kanban board on mobile 4. Drawer navigation: Slide-in menu for mobile

    Security Considerations

  • Store personal data in src/data/ (gitignored)
  • Keep template data in the skill
  • No authentication included - add your own if needed
  • Run locally or behind a VPN
  • Troubleshooting

    Port already in use?

    PORT=3001 ./start.sh
    

    Data not saving? Ensure src/data/ directory exists and is writable.

    OpenClaw sync not working? Check that OpenClaw memory path is correct in your environment.

    Resources

  • Next.js docs: https://nextjs.org/docs
  • Tailwind CSS: https://tailwindcss.com
  • Lucide icons: https://lucide.dev
  • License

    MIT - Built for the OpenClaw community 🦞

    βš™οΈ Configuration

  • Node.js 18+
  • OpenClaw installed and running
  • Basic knowledge of React/Next.js
  • πŸ“‹ Tips & Best Practices

    Port already in use?

    PORT=3001 ./start.sh
    

    Data not saving? Ensure src/data/ directory exists and is writable.

    OpenClaw sync not working? Check that OpenClaw memory path is correct in your environment.