{
  "schemaVersion": "1.0",
  "item": {
    "slug": "mission-control-builder",
    "name": "Mission Control Builder",
    "source": "tencent",
    "type": "skill",
    "category": "效率提升",
    "sourceUrl": "https://clawhub.ai/Shukiclaw/mission-control-builder",
    "canonicalUrl": "https://clawhub.ai/Shukiclaw/mission-control-builder",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/mission-control-builder",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=mission-control-builder",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/mission-control-builder"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/mission-control-builder",
    "agentPageUrl": "https://openagent3.xyz/skills/mission-control-builder/agent",
    "manifestUrl": "https://openagent3.xyz/skills/mission-control-builder/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/mission-control-builder/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Mission Control Skill",
        "body": "Build your own personal dashboard for OpenClaw - a central command center for tasks, memories, calendar, and team management."
      },
      {
        "title": "What You'll Build",
        "body": "A Next.js web dashboard that connects to your OpenClaw instance and provides:\n\nTask Board - Kanban-style task management\nMemory Browser - Search and view your OpenClaw memories\nCalendar View - See scheduled events and cron jobs\nTeam Status - Track who's working on what\nGitHub Trends - Discover trending repositories"
      },
      {
        "title": "Architecture Overview",
        "body": "┌─────────────────────────────────────┐\n│         Next.js Frontend            │\n│  ┌─────────┐ ┌─────────┐ ┌────────┐ │\n│  │  Task   │ │ Memory  │ │Calendar│ │\n│  │  Board  │ │  List   │ │  View  │ │\n│  └────┬────┘ └────┬────┘ └───┬────┘ │\n│       └───────────┴──────────┘       │\n│              │                       │\n│       ┌──────┴──────┐                │\n│       │   API Routes │               │\n│       └──────┬──────┘                │\n└──────────────┼───────────────────────┘\n               │\n       ┌───────┴───────┐\n       │               │\n┌──────┴──────┐ ┌──────┴──────┐\n│ Local JSON  │ │  OpenClaw   │\n│   Files     │ │   Memory    │\n└─────────────┘ └─────────────┘"
      },
      {
        "title": "Prerequisites",
        "body": "Node.js 18+\nOpenClaw installed and running\nBasic knowledge of React/Next.js"
      },
      {
        "title": "Step 1: Initialize Project",
        "body": "npx create-next-app@latest mission-control --typescript --tailwind"
      },
      {
        "title": "Step 2: Install Dependencies",
        "body": "cd mission-control\nnpm install lucide-react"
      },
      {
        "title": "Step 3: Create Data Layer",
        "body": "Create src/lib/data.ts for file-based storage:\n\nimport fs from \"fs/promises\";\nimport path from \"path\";\n\nconst DATA_DIR = path.join(process.cwd(), \"src\", \"data\");\n\n// Types\nexport interface Task {\n  id: string;\n  title: string;\n  description: string;\n  status: \"todo\" | \"in-progress\" | \"done\";\n  assignee: string;\n  createdAt: string;\n  updatedAt: string;\n}\n\n// Initialize data files\nasync function initDataFile(filename: string, defaultData: unknown) {\n  const filepath = path.join(DATA_DIR, filename);\n  try {\n    await fs.access(filepath);\n  } catch {\n    await fs.mkdir(DATA_DIR, { recursive: true });\n    await fs.writeFile(filepath, JSON.stringify(defaultData, null, 2));\n  }\n  return filepath;\n}\n\n// Tasks\nexport async function getTasks(): Promise<Task[]> {\n  const filepath = await initDataFile(\"tasks.json\", []);\n  const data = await fs.readFile(filepath, \"utf-8\");\n  return JSON.parse(data);\n}\n\nexport async function addTask(task: Omit<Task, \"id\" | \"createdAt\" | \"updatedAt\">): Promise<Task> {\n  const tasks = await getTasks();\n  const newTask: Task = {\n    ...task,\n    id: Date.now().toString(),\n    createdAt: new Date().toISOString(),\n    updatedAt: new Date().toISOString(),\n  };\n  tasks.push(newTask);\n  await fs.writeFile(\n    path.join(DATA_DIR, \"tasks.json\"),\n    JSON.stringify(tasks, null, 2)\n  );\n  return newTask;\n}\n\nexport async function updateTask(id: string, updates: Partial<Task>): Promise<Task | null> {\n  const tasks = await getTasks();\n  const index = tasks.findIndex((t) => t.id === id);\n  if (index === -1) return null;\n  \n  tasks[index] = { \n    ...tasks[index], \n    ...updates, \n    updatedAt: new Date().toISOString() \n  };\n  await fs.writeFile(\n    path.join(DATA_DIR, \"tasks.json\"),\n    JSON.stringify(tasks, null, 2)\n  );\n  return tasks[index];\n}"
      },
      {
        "title": "Step 4: Create API Routes",
        "body": "Create src/app/api/tasks/route.ts:\n\nimport { NextRequest, NextResponse } from \"next/server\";\nimport { getTasks, addTask, updateTask } from \"@/lib/data\";\n\nexport async function GET() {\n  const tasks = await getTasks();\n  return NextResponse.json(tasks);\n}\n\nexport async function POST(request: NextRequest) {\n  try {\n    const body = await request.json();\n    const task = await addTask(body);\n    return NextResponse.json(task, { status: 201 });\n  } catch (error) {\n    return NextResponse.json(\n      { error: \"Failed to create task\" },\n      { status: 500 }\n    );\n  }\n}\n\nexport async function PUT(request: NextRequest) {\n  try {\n    const { id, ...updates } = await request.json();\n    const task = await updateTask(id, updates);\n    if (!task) {\n      return NextResponse.json({ error: \"Task not found\" }, { status: 404 });\n    }\n    return NextResponse.json(task);\n  } catch (error) {\n    return NextResponse.json(\n      { error: \"Failed to update task\" },\n      { status: 500 }\n    );\n  }\n}"
      },
      {
        "title": "Step 5: Create Components",
        "body": "Navigation Component (src/components/Navigation.tsx):\n\n\"use client\";\n\nimport Link from \"next/link\";\nimport { usePathname } from \"next/navigation\";\nimport { useState } from \"react\";\nimport { LayoutDashboard, ClipboardList, Menu, X } from \"lucide-react\";\n\nconst navItems = [\n  { href: \"/\", label: \"Dashboard\", icon: LayoutDashboard },\n  { href: \"/tasks\", label: \"Tasks\", icon: ClipboardList },\n];\n\nexport function Navigation() {\n  const pathname = usePathname();\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n\n  return (\n    <>\n      {/* Desktop Sidebar */}\n      <aside className=\"hidden lg:flex w-64 bg-gray-800 border-r border-gray-700 flex-col h-screen\">\n        <div className=\"p-6 border-b border-gray-700\">\n          <h1 className=\"text-xl font-bold text-blue-400\">Mission Control</h1>\n        </div>\n        <nav className=\"flex-1 p-4\">\n          <ul className=\"space-y-2\">\n            {navItems.map((item) => {\n              const Icon = item.icon;\n              const isActive = pathname === item.href;\n              return (\n                <li key={item.href}>\n                  <Link\n                    href={item.href}\n                    className={`flex items-center gap-3 px-4 py-3 rounded-lg transition-colors ${\n                      isActive\n                        ? \"bg-blue-600 text-white\"\n                        : \"text-gray-300 hover:bg-gray-700\"\n                    }`}\n                  >\n                    <Icon size={20} />\n                    <span>{item.label}</span>\n                  </Link>\n                </li>\n              );\n            })}\n          </ul>\n        </nav>\n      </aside>\n\n      {/* Mobile Header */}\n      <div className=\"lg:hidden fixed top-0 left-0 right-0 z-40 bg-gray-800 border-b border-gray-700\">\n        <div className=\"flex items-center justify-between px-4 py-3\">\n          <h1 className=\"text-lg font-bold text-blue-400\">Mission Control</h1>\n          <button\n            onClick={() => setMobileMenuOpen(!mobileMenuOpen)}\n            className=\"p-2 rounded-lg bg-gray-700\"\n          >\n            {mobileMenuOpen ? <X size={24} /> : <Menu size={24} />}\n          </button>\n        </div>\n      </div>\n\n      {/* Mobile Drawer */}\n      {mobileMenuOpen && (\n        <aside className=\"lg:hidden fixed top-[60px] left-0 bottom-0 w-64 bg-gray-800 z-40\">\n          {/* Same nav as desktop */}\n        </aside>\n      )}\n    </>\n  );\n}"
      },
      {
        "title": "Step 6: Create Task Board",
        "body": "\"use client\";\n\nimport { useState, useEffect } from \"react\";\n\ninterface Task {\n  id: string;\n  title: string;\n  description: string;\n  status: \"todo\" | \"in-progress\" | \"done\";\n  assignee: string;\n}\n\nexport function TaskBoard() {\n  const [tasks, setTasks] = useState<Task[]>([]);\n  const [loading, setLoading] = useState(true);\n\n  useEffect(() => {\n    fetchTasks();\n  }, []);\n\n  const fetchTasks = async () => {\n    try {\n      const response = await fetch(\"/api/tasks\");\n      const data = await response.json();\n      setTasks(data);\n    } finally {\n      setLoading(false);\n    }\n  };\n\n  const handleUpdateStatus = async (taskId: string, newStatus: Task[\"status\"]) => {\n    await fetch(\"/api/tasks\", {\n      method: \"PUT\",\n      headers: { \"Content-Type\": \"application/json\" },\n      body: JSON.stringify({ id: taskId, status: newStatus }),\n    });\n    fetchTasks();\n  };\n\n  const tasksByStatus = {\n    todo: tasks.filter((t) => t.status === \"todo\"),\n    \"in-progress\": tasks.filter((t) => t.status === \"in-progress\"),\n    done: tasks.filter((t) => t.status === \"done\"),\n  };\n\n  if (loading) return <div>Loading...</div>;\n\n  return (\n    <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n      {Object.entries(tasksByStatus).map(([status, statusTasks]) => (\n        <div key={status} className=\"bg-gray-800/50 rounded-xl p-4\">\n          <h3 className=\"font-semibold text-gray-300 mb-4 capitalize\">{status}</h3>\n          <div className=\"space-y-3\">\n            {statusTasks.map((task) => (\n              <div key={task.id} className=\"bg-gray-800 p-4 rounded-lg\">\n                <h4 className=\"font-medium\">{task.title}</h4>\n                <select\n                  value={task.status}\n                  onChange={(e) => handleUpdateStatus(task.id, e.target.value as Task[\"status\"])}\n                  className=\"mt-2 text-sm bg-gray-700 border border-gray-600 rounded px-2 py-1\"\n                >\n                  <option value=\"todo\">To Do</option>\n                  <option value=\"in-progress\">In Progress</option>\n                  <option value=\"done\">Done</option>\n                </select>\n              </div>\n            ))}\n          </div>\n        </div>\n      ))}\n    </div>\n  );\n}"
      },
      {
        "title": "Step 7: OpenClaw Memory Sync",
        "body": "Create src/app/api/sync/route.ts:\n\nimport { NextResponse } from \"next/server\";\nimport fs from \"fs/promises\";\nimport path from \"path\";\n\nexport async function GET() {\n  try {\n    // Read OpenClaw memory files\n    const memoryDir = path.join(process.env.HOME || \"\", \"clawd\", \"memory\");\n    const files = await fs.readdir(memoryDir);\n    \n    const memories = [];\n    for (const file of files.filter(f => f.endsWith('.md'))) {\n      const content = await fs.readFile(path.join(memoryDir, file), 'utf-8');\n      memories.push({\n        id: file,\n        title: file.replace('.md', ''),\n        content: content.slice(0, 500) + '...',\n        createdAt: new Date().toISOString(),\n      });\n    }\n    \n    return NextResponse.json(memories);\n  } catch (error) {\n    return NextResponse.json([]);\n  }\n}"
      },
      {
        "title": "Step 8: Create Layout",
        "body": "import type { Metadata } from \"next\";\nimport \"./globals.css\";\nimport { Navigation } from \"@/components/Navigation\";\n\nexport const metadata: Metadata = {\n  title: \"Mission Control\",\n  description: \"Personal dashboard for OpenClaw\",\n};\n\nexport default function RootLayout({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  return (\n    <html lang=\"en\">\n      <body className=\"bg-gray-900 text-white\">\n        <div className=\"flex flex-col lg:flex-row min-h-screen\">\n          <Navigation />\n          <main className=\"flex-1 overflow-auto pt-[60px] lg:pt-0 p-6\">\n            {children}\n          </main>\n        </div>\n      </body>\n    </html>\n  );\n}"
      },
      {
        "title": "Step 9: Start Script",
        "body": "Create start.sh:\n\n#!/bin/bash\ncd \"$(dirname \"$0\")\"\nnpm run dev\n\nMake it executable:\n\nchmod +x start.sh"
      },
      {
        "title": "Step 10: Run",
        "body": "./start.sh\n\nOpen http://localhost:3000"
      },
      {
        "title": "Add GitHub Trends",
        "body": "// src/app/api/github-trends/route.ts\nexport async function GET() {\n  const response = await fetch(\n    \"https://api.github.com/search/repositories?q=stars:>1000&sort=stars&per_page=10\"\n  );\n  const data = await response.json();\n  return NextResponse.json(data.items);\n}"
      },
      {
        "title": "Add Calendar Events",
        "body": "Store events in src/data/calendar.json and create similar API routes."
      },
      {
        "title": "Add Team Members",
        "body": "Create src/data/team.json with member info and current tasks."
      },
      {
        "title": "Mobile Responsiveness Tips",
        "body": "Use Tailwind breakpoints: lg: for desktop, default for mobile\nTouch targets: Minimum 40px for buttons\nHorizontal scroll: For Kanban board on mobile\nDrawer navigation: Slide-in menu for mobile"
      },
      {
        "title": "Security Considerations",
        "body": "Store personal data in src/data/ (gitignored)\nKeep template data in the skill\nNo authentication included - add your own if needed\nRun locally or behind a VPN"
      },
      {
        "title": "Troubleshooting",
        "body": "Port already in use?\n\nPORT=3001 ./start.sh\n\nData not saving?\nEnsure src/data/ directory exists and is writable.\n\nOpenClaw sync not working?\nCheck that OpenClaw memory path is correct in your environment."
      },
      {
        "title": "Resources",
        "body": "Next.js docs: https://nextjs.org/docs\nTailwind CSS: https://tailwindcss.com\nLucide icons: https://lucide.dev"
      },
      {
        "title": "License",
        "body": "MIT - Built for the OpenClaw community 🦞"
      }
    ],
    "body": "Mission Control Skill\n\nBuild your own personal dashboard for OpenClaw - a central command center for tasks, memories, calendar, and team management.\n\nWhat You'll Build\n\nA Next.js web dashboard that connects to your OpenClaw instance and provides:\n\nTask Board - Kanban-style task management\nMemory Browser - Search and view your OpenClaw memories\nCalendar View - See scheduled events and cron jobs\nTeam Status - Track who's working on what\nGitHub Trends - Discover trending repositories\nArchitecture Overview\n┌─────────────────────────────────────┐\n│         Next.js Frontend            │\n│  ┌─────────┐ ┌─────────┐ ┌────────┐ │\n│  │  Task   │ │ Memory  │ │Calendar│ │\n│  │  Board  │ │  List   │ │  View  │ │\n│  └────┬────┘ └────┬────┘ └───┬────┘ │\n│       └───────────┴──────────┘       │\n│              │                       │\n│       ┌──────┴──────┐                │\n│       │   API Routes │               │\n│       └──────┬──────┘                │\n└──────────────┼───────────────────────┘\n               │\n       ┌───────┴───────┐\n       │               │\n┌──────┴──────┐ ┌──────┴──────┐\n│ Local JSON  │ │  OpenClaw   │\n│   Files     │ │   Memory    │\n└─────────────┘ └─────────────┘\n\nPrerequisites\nNode.js 18+\nOpenClaw installed and running\nBasic knowledge of React/Next.js\nStep-by-Step Guide\nStep 1: Initialize Project\nnpx create-next-app@latest mission-control --typescript --tailwind\n\nStep 2: Install Dependencies\ncd mission-control\nnpm install lucide-react\n\nStep 3: Create Data Layer\n\nCreate src/lib/data.ts for file-based storage:\n\nimport fs from \"fs/promises\";\nimport path from \"path\";\n\nconst DATA_DIR = path.join(process.cwd(), \"src\", \"data\");\n\n// Types\nexport interface Task {\n  id: string;\n  title: string;\n  description: string;\n  status: \"todo\" | \"in-progress\" | \"done\";\n  assignee: string;\n  createdAt: string;\n  updatedAt: string;\n}\n\n// Initialize data files\nasync function initDataFile(filename: string, defaultData: unknown) {\n  const filepath = path.join(DATA_DIR, filename);\n  try {\n    await fs.access(filepath);\n  } catch {\n    await fs.mkdir(DATA_DIR, { recursive: true });\n    await fs.writeFile(filepath, JSON.stringify(defaultData, null, 2));\n  }\n  return filepath;\n}\n\n// Tasks\nexport async function getTasks(): Promise<Task[]> {\n  const filepath = await initDataFile(\"tasks.json\", []);\n  const data = await fs.readFile(filepath, \"utf-8\");\n  return JSON.parse(data);\n}\n\nexport async function addTask(task: Omit<Task, \"id\" | \"createdAt\" | \"updatedAt\">): Promise<Task> {\n  const tasks = await getTasks();\n  const newTask: Task = {\n    ...task,\n    id: Date.now().toString(),\n    createdAt: new Date().toISOString(),\n    updatedAt: new Date().toISOString(),\n  };\n  tasks.push(newTask);\n  await fs.writeFile(\n    path.join(DATA_DIR, \"tasks.json\"),\n    JSON.stringify(tasks, null, 2)\n  );\n  return newTask;\n}\n\nexport async function updateTask(id: string, updates: Partial<Task>): Promise<Task | null> {\n  const tasks = await getTasks();\n  const index = tasks.findIndex((t) => t.id === id);\n  if (index === -1) return null;\n  \n  tasks[index] = { \n    ...tasks[index], \n    ...updates, \n    updatedAt: new Date().toISOString() \n  };\n  await fs.writeFile(\n    path.join(DATA_DIR, \"tasks.json\"),\n    JSON.stringify(tasks, null, 2)\n  );\n  return tasks[index];\n}\n\nStep 4: Create API Routes\n\nCreate src/app/api/tasks/route.ts:\n\nimport { NextRequest, NextResponse } from \"next/server\";\nimport { getTasks, addTask, updateTask } from \"@/lib/data\";\n\nexport async function GET() {\n  const tasks = await getTasks();\n  return NextResponse.json(tasks);\n}\n\nexport async function POST(request: NextRequest) {\n  try {\n    const body = await request.json();\n    const task = await addTask(body);\n    return NextResponse.json(task, { status: 201 });\n  } catch (error) {\n    return NextResponse.json(\n      { error: \"Failed to create task\" },\n      { status: 500 }\n    );\n  }\n}\n\nexport async function PUT(request: NextRequest) {\n  try {\n    const { id, ...updates } = await request.json();\n    const task = await updateTask(id, updates);\n    if (!task) {\n      return NextResponse.json({ error: \"Task not found\" }, { status: 404 });\n    }\n    return NextResponse.json(task);\n  } catch (error) {\n    return NextResponse.json(\n      { error: \"Failed to update task\" },\n      { status: 500 }\n    );\n  }\n}\n\nStep 5: Create Components\n\nNavigation Component (src/components/Navigation.tsx):\n\n\"use client\";\n\nimport Link from \"next/link\";\nimport { usePathname } from \"next/navigation\";\nimport { useState } from \"react\";\nimport { LayoutDashboard, ClipboardList, Menu, X } from \"lucide-react\";\n\nconst navItems = [\n  { href: \"/\", label: \"Dashboard\", icon: LayoutDashboard },\n  { href: \"/tasks\", label: \"Tasks\", icon: ClipboardList },\n];\n\nexport function Navigation() {\n  const pathname = usePathname();\n  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);\n\n  return (\n    <>\n      {/* Desktop Sidebar */}\n      <aside className=\"hidden lg:flex w-64 bg-gray-800 border-r border-gray-700 flex-col h-screen\">\n        <div className=\"p-6 border-b border-gray-700\">\n          <h1 className=\"text-xl font-bold text-blue-400\">Mission Control</h1>\n        </div>\n        <nav className=\"flex-1 p-4\">\n          <ul className=\"space-y-2\">\n            {navItems.map((item) => {\n              const Icon = item.icon;\n              const isActive = pathname === item.href;\n              return (\n                <li key={item.href}>\n                  <Link\n                    href={item.href}\n                    className={`flex items-center gap-3 px-4 py-3 rounded-lg transition-colors ${\n                      isActive\n                        ? \"bg-blue-600 text-white\"\n                        : \"text-gray-300 hover:bg-gray-700\"\n                    }`}\n                  >\n                    <Icon size={20} />\n                    <span>{item.label}</span>\n                  </Link>\n                </li>\n              );\n            })}\n          </ul>\n        </nav>\n      </aside>\n\n      {/* Mobile Header */}\n      <div className=\"lg:hidden fixed top-0 left-0 right-0 z-40 bg-gray-800 border-b border-gray-700\">\n        <div className=\"flex items-center justify-between px-4 py-3\">\n          <h1 className=\"text-lg font-bold text-blue-400\">Mission Control</h1>\n          <button\n            onClick={() => setMobileMenuOpen(!mobileMenuOpen)}\n            className=\"p-2 rounded-lg bg-gray-700\"\n          >\n            {mobileMenuOpen ? <X size={24} /> : <Menu size={24} />}\n          </button>\n        </div>\n      </div>\n\n      {/* Mobile Drawer */}\n      {mobileMenuOpen && (\n        <aside className=\"lg:hidden fixed top-[60px] left-0 bottom-0 w-64 bg-gray-800 z-40\">\n          {/* Same nav as desktop */}\n        </aside>\n      )}\n    </>\n  );\n}\n\nStep 6: Create Task Board\n\"use client\";\n\nimport { useState, useEffect } from \"react\";\n\ninterface Task {\n  id: string;\n  title: string;\n  description: string;\n  status: \"todo\" | \"in-progress\" | \"done\";\n  assignee: string;\n}\n\nexport function TaskBoard() {\n  const [tasks, setTasks] = useState<Task[]>([]);\n  const [loading, setLoading] = useState(true);\n\n  useEffect(() => {\n    fetchTasks();\n  }, []);\n\n  const fetchTasks = async () => {\n    try {\n      const response = await fetch(\"/api/tasks\");\n      const data = await response.json();\n      setTasks(data);\n    } finally {\n      setLoading(false);\n    }\n  };\n\n  const handleUpdateStatus = async (taskId: string, newStatus: Task[\"status\"]) => {\n    await fetch(\"/api/tasks\", {\n      method: \"PUT\",\n      headers: { \"Content-Type\": \"application/json\" },\n      body: JSON.stringify({ id: taskId, status: newStatus }),\n    });\n    fetchTasks();\n  };\n\n  const tasksByStatus = {\n    todo: tasks.filter((t) => t.status === \"todo\"),\n    \"in-progress\": tasks.filter((t) => t.status === \"in-progress\"),\n    done: tasks.filter((t) => t.status === \"done\"),\n  };\n\n  if (loading) return <div>Loading...</div>;\n\n  return (\n    <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n      {Object.entries(tasksByStatus).map(([status, statusTasks]) => (\n        <div key={status} className=\"bg-gray-800/50 rounded-xl p-4\">\n          <h3 className=\"font-semibold text-gray-300 mb-4 capitalize\">{status}</h3>\n          <div className=\"space-y-3\">\n            {statusTasks.map((task) => (\n              <div key={task.id} className=\"bg-gray-800 p-4 rounded-lg\">\n                <h4 className=\"font-medium\">{task.title}</h4>\n                <select\n                  value={task.status}\n                  onChange={(e) => handleUpdateStatus(task.id, e.target.value as Task[\"status\"])}\n                  className=\"mt-2 text-sm bg-gray-700 border border-gray-600 rounded px-2 py-1\"\n                >\n                  <option value=\"todo\">To Do</option>\n                  <option value=\"in-progress\">In Progress</option>\n                  <option value=\"done\">Done</option>\n                </select>\n              </div>\n            ))}\n          </div>\n        </div>\n      ))}\n    </div>\n  );\n}\n\nStep 7: OpenClaw Memory Sync\n\nCreate src/app/api/sync/route.ts:\n\nimport { NextResponse } from \"next/server\";\nimport fs from \"fs/promises\";\nimport path from \"path\";\n\nexport async function GET() {\n  try {\n    // Read OpenClaw memory files\n    const memoryDir = path.join(process.env.HOME || \"\", \"clawd\", \"memory\");\n    const files = await fs.readdir(memoryDir);\n    \n    const memories = [];\n    for (const file of files.filter(f => f.endsWith('.md'))) {\n      const content = await fs.readFile(path.join(memoryDir, file), 'utf-8');\n      memories.push({\n        id: file,\n        title: file.replace('.md', ''),\n        content: content.slice(0, 500) + '...',\n        createdAt: new Date().toISOString(),\n      });\n    }\n    \n    return NextResponse.json(memories);\n  } catch (error) {\n    return NextResponse.json([]);\n  }\n}\n\nStep 8: Create Layout\nimport type { Metadata } from \"next\";\nimport \"./globals.css\";\nimport { Navigation } from \"@/components/Navigation\";\n\nexport const metadata: Metadata = {\n  title: \"Mission Control\",\n  description: \"Personal dashboard for OpenClaw\",\n};\n\nexport default function RootLayout({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  return (\n    <html lang=\"en\">\n      <body className=\"bg-gray-900 text-white\">\n        <div className=\"flex flex-col lg:flex-row min-h-screen\">\n          <Navigation />\n          <main className=\"flex-1 overflow-auto pt-[60px] lg:pt-0 p-6\">\n            {children}\n          </main>\n        </div>\n      </body>\n    </html>\n  );\n}\n\nStep 9: Start Script\n\nCreate start.sh:\n\n#!/bin/bash\ncd \"$(dirname \"$0\")\"\nnpm run dev\n\n\nMake it executable:\n\nchmod +x start.sh\n\nStep 10: Run\n./start.sh\n\n\nOpen http://localhost:3000\n\nExtending Mission Control\nAdd GitHub Trends\n// src/app/api/github-trends/route.ts\nexport async function GET() {\n  const response = await fetch(\n    \"https://api.github.com/search/repositories?q=stars:>1000&sort=stars&per_page=10\"\n  );\n  const data = await response.json();\n  return NextResponse.json(data.items);\n}\n\nAdd Calendar Events\n\nStore events in src/data/calendar.json and create similar API routes.\n\nAdd Team Members\n\nCreate src/data/team.json with member info and current tasks.\n\nMobile Responsiveness Tips\nUse Tailwind breakpoints: lg: for desktop, default for mobile\nTouch targets: Minimum 40px for buttons\nHorizontal scroll: For Kanban board on mobile\nDrawer navigation: Slide-in menu for mobile\nSecurity Considerations\nStore personal data in src/data/ (gitignored)\nKeep template data in the skill\nNo authentication included - add your own if needed\nRun locally or behind a VPN\nTroubleshooting\n\nPort already in use?\n\nPORT=3001 ./start.sh\n\n\nData not saving? Ensure src/data/ directory exists and is writable.\n\nOpenClaw sync not working? Check that OpenClaw memory path is correct in your environment.\n\nResources\nNext.js docs: https://nextjs.org/docs\nTailwind CSS: https://tailwindcss.com\nLucide icons: https://lucide.dev\nLicense\n\nMIT - Built for the OpenClaw community 🦞"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/Shukiclaw/mission-control-builder",
    "publisherUrl": "https://clawhub.ai/Shukiclaw/mission-control-builder",
    "owner": "Shukiclaw",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/mission-control-builder",
    "downloadUrl": "https://openagent3.xyz/downloads/mission-control-builder",
    "agentUrl": "https://openagent3.xyz/skills/mission-control-builder/agent",
    "manifestUrl": "https://openagent3.xyz/skills/mission-control-builder/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/mission-control-builder/agent.md"
  }
}