Skip to main content

Overview

Mission Control’s GitHub integration enables seamless synchronization between GitHub Issues and Mission Control tasks. Import issues as tasks, post comments, and close issues directly from Mission Control.
Requires GITHUB_TOKEN environment variable with repo scope.

Setup

1

Generate GitHub Token

Create a Personal Access Token (classic) with repo scope:
  1. Go to GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
  2. Click “Generate new token (classic)”
  3. Select scopes:
    • repo (Full control of private repositories)
  4. Copy the generated token
Store the token securely. GitHub only shows it once.
2

Configure Environment Variable

Add to your Mission Control .env file:
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Optionally set a default repository:
GITHUB_DEFAULT_REPO=owner/repo-name
3

Restart Mission Control

pnpm dev  # Development
# or
systemctl restart mission-control  # Production

Sync GitHub Issues to Tasks

Preview Issues

Fetch issues from a repository without importing:
curl "http://localhost:3000/api/github?action=issues&repo=owner/repo&state=open&labels=bug" \
  -H "x-api-key: YOUR_API_KEY"
Query Parameters:
action
string
required
Must be issues for preview or stats for repository statistics
repo
string
required
Repository in owner/repo format (overrides GITHUB_DEFAULT_REPO)
state
string
default:"open"
Issue state: open, closed, or all
labels
string
Comma-separated label filter (e.g., bug,enhancement)
Response:
{
  "issues": [
    {
      "number": 42,
      "title": "Fix authentication bug",
      "body": "Users cannot log in with GitHub OAuth",
      "state": "open",
      "labels": [
        {"name": "bug", "color": "d73a4a"},
        {"name": "priority:high", "color": "e99695"}
      ],
      "assignee": {
        "login": "alice",
        "avatar_url": "https://avatars.githubusercontent.com/u/..."
      },
      "html_url": "https://github.com/owner/repo/issues/42",
      "created_at": "2024-03-04T10:30:00Z",
      "updated_at": "2024-03-04T15:45:00Z"
    }
  ],
  "total": 1,
  "repo": "owner/repo"
}

Import Issues as Tasks

curl -X POST http://localhost:3000/api/github \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "action": "sync",
    "repo": "owner/repo",
    "state": "open",
    "labels": "bug,priority:high",
    "assignAgent": "debugging-agent"
  }'
action
string
required
Must be sync
repo
string
required
Repository in owner/repo format
state
string
default:"open"
Issue state to sync: open, closed, or all
labels
string
Comma-separated label filter
assignAgent
string
Automatically assign imported tasks to this agent
Response:
{
  "imported": 5,
  "skipped": 2,
  "errors": 0,
  "tasks": [
    {
      "id": 101,
      "title": "Fix authentication bug",
      "description": "Users cannot log in with GitHub OAuth",
      "status": "inbox",
      "priority": "high",
      "assigned_to": "debugging-agent",
      "tags": ["bug", "priority:high"],
      "metadata": {
        "github_repo": "owner/repo",
        "github_issue_number": 42,
        "github_issue_url": "https://github.com/owner/repo/issues/42",
        "github_synced_at": "2024-03-04T15:50:00.000Z",
        "github_state": "open"
      }
    }
  ]
}
Sync Behavior:
  • Duplicate Prevention: Issues already imported (matching github_repo + github_issue_number) are skipped
  • Status Mapping: openinbox, closeddone
  • Priority Mapping: Extracted from labels (see below)
  • Tags: All GitHub labels are imported as task tags

Label to Priority Mapping

Mission Control automatically maps GitHub labels to task priorities:
GitHub LabelTask Priority
priority:critical, criticalcritical
priority:high, highhigh
priority:mediummedium
priority:low, lowlow
(no match)medium
Add priority labels to your GitHub issues for better task organization:
  • priority:critical - Production outages, security issues
  • priority:high - Blocking bugs, urgent features
  • priority:medium - Standard work
  • priority:low - Nice-to-have improvements

Post Comments to Issues

Send a comment to a GitHub issue:
curl -X POST http://localhost:3000/api/github \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "action": "comment",
    "repo": "owner/repo",
    "issueNumber": 42,
    "body": "This issue has been assigned to debugging-agent in Mission Control."
  }'
action
string
required
Must be comment
repo
string
required
Repository in owner/repo format
issueNumber
number
required
GitHub issue number
body
string
required
Comment text (Markdown supported)
Response:
{"ok": true}

Close GitHub Issues

Close an issue (optionally with a final comment):
curl -X POST http://localhost:3000/api/github \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "action": "close",
    "repo": "owner/repo",
    "issueNumber": 42,
    "comment": "Fixed in #123. Closing this issue."
  }'
action
string
required
Must be close
repo
string
required
Repository in owner/repo format
issueNumber
number
required
GitHub issue number to close
comment
string
Optional closing comment (posted before closing)
Response:
{"ok": true}
Behavior:
  • Posts comment (if provided)
  • Closes the GitHub issue
  • Updates linked Mission Control task metadata: github_stateclosed

Sync History

Retrieve recent sync operations:
curl -X POST http://localhost:3000/api/github \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{"action": "status"}'
Response:
{
  "syncs": [
    {
      "id": 5,
      "repo": "owner/repo",
      "last_synced_at": 1709582400,
      "issue_count": 5,
      "sync_direction": "inbound",
      "status": "success",
      "error": null,
      "created_at": 1709582400
    }
  ]
}

GitHub Stats

Fetch authenticated user profile and repository statistics:
curl "http://localhost:3000/api/github?action=stats" \
  -H "x-api-key: YOUR_API_KEY"
Response:
{
  "user": {
    "login": "alice",
    "name": "Alice Developer",
    "avatar_url": "https://avatars.githubusercontent.com/u/...",
    "public_repos": 42,
    "followers": 120,
    "following": 85
  },
  "repos": {
    "total": 42,
    "public": 35,
    "private": 7,
    "total_stars": 523,
    "total_forks": 89,
    "total_open_issues": 34
  },
  "topLanguages": [
    {"name": "TypeScript", "count": 18},
    {"name": "Python", "count": 12},
    {"name": "JavaScript", "count": 8}
  ],
  "recentRepos": [
    {
      "name": "alice/mission-control",
      "description": "AI agent orchestration dashboard",
      "language": "TypeScript",
      "stars": 234,
      "forks": 45,
      "open_issues": 8,
      "pushed_at": "2024-03-04T12:00:00Z",
      "is_fork": false,
      "is_private": false,
      "html_url": "https://github.com/alice/mission-control"
    }
  ]
}
Stats endpoint filters out inactive forks (forks where you’ve never pushed commits).

Automation Examples

Daily Issue Sync (Cron)

Sync high-priority bugs daily:
#!/bin/bash
# sync-github-issues.sh

API_KEY="operator:abc123"
REPO="owner/repo"
BASE_URL="http://localhost:3000"

curl -X POST "${BASE_URL}/api/github" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ${API_KEY}" \
  -d "{
    \"action\": \"sync\",
    \"repo\": \"${REPO}\",
    \"state\": \"open\",
    \"labels\": \"bug,priority:high\",
    \"assignAgent\": \"triaging-agent\"
  }"
Add to crontab:
0 9 * * * /path/to/sync-github-issues.sh

Auto-comment on Task Assignment

When an agent is assigned to a GitHub-linked task, post a comment:
// webhook-receiver.js
const express = require('express');
const crypto = require('crypto');

const app = express();
app.use(express.json());

app.post('/webhook', (req, res) => {
  const event = req.body;
  
  if (event.event === 'activity.task_assigned' && event.data.metadata?.github_repo) {
    const { github_repo, github_issue_number } = event.data.metadata;
    const assignedAgent = event.data.assigned_to;
    
    // Post comment to GitHub
    fetch('http://localhost:3000/api/github', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': process.env.MC_API_KEY,
      },
      body: JSON.stringify({
        action: 'comment',
        repo: github_repo,
        issueNumber: github_issue_number,
        body: `🤖 Assigned to **${assignedAgent}** in Mission Control.`,
      }),
    });
  }
  
  res.json({ ok: true });
});

app.listen(3001, () => console.log('Webhook receiver running on :3001'));

Close Issue When Task Completes

Automatically close GitHub issues when tasks are marked done:
// task-completion-handler.js
eventBus.on('task.status_changed', async (event) => {
  const { id, status, metadata } = event.data;
  
  if (status === 'done' && metadata?.github_repo) {
    await fetch('http://localhost:3000/api/github', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': process.env.MC_API_KEY,
      },
      body: JSON.stringify({
        action: 'close',
        repo: metadata.github_repo,
        issueNumber: metadata.github_issue_number,
        comment: `✅ Task completed in Mission Control. Closing this issue.`,
      }),
    });
  }
});

API Rate Limits

GitHub API rate limits:
  • Authenticated: 5,000 requests/hour
  • Search API: 30 requests/minute
Mission Control includes:
  • 15-second timeout per request
  • Exponential backoff on errors
  • Automatic retry on rate limit (429)
Batch sync operations count as multiple API calls (1 per issue). Plan accordingly.

Troubleshooting

Error: {"error": "GITHUB_TOKEN not configured"}Solution:
  1. Verify .env file contains GITHUB_TOKEN=ghp_...
  2. Restart Mission Control
  3. Check token has repo scope in GitHub settings
Cause: Token lacks permissions or repository is private.Solution:
  • For private repos: Token needs repo scope (not just public_repo)
  • Verify token owner has access to the repository
  • Check repository name format: owner/repo (not URL)
Cause: GitHub labels don’t match expected format.Solution: Add labels to your GitHub repo:
  • priority:critical → critical
  • priority:high → high
  • priority:low → low
Alternatively, edit mapPriority() function in /src/app/api/github/route.ts.
Cause: Task metadata doesn’t match expected schema.Solution: Mission Control prevents duplicates by checking:
json_extract(metadata, '$.github_repo') = 'owner/repo'
AND json_extract(metadata, '$.github_issue_number') = 42
Ensure tasks have this metadata structure. Re-import will skip existing tasks.

Security Best Practices

Rotate Tokens

Rotate GitHub tokens every 90 days:
  1. Generate new token
  2. Update GITHUB_TOKEN
  3. Restart Mission Control
  4. Revoke old token

Scope Principle

Use minimum required scopes:
  • Read-only sync: repo (read)
  • Comment/close: repo (write)
  • Never use admin:org unless necessary

Webhook Security

If receiving GitHub webhooks:
  • Verify X-Hub-Signature-256 header
  • Use webhook secrets
  • Validate payload structure

Token Storage

Never commit tokens:
  • Use .env files (gitignored)
  • Or environment variables
  • Or secrets management (Vault, AWS Secrets Manager)

Webhooks

Receive events when tasks change

Tasks API

Programmatic task management

CLI Integration

Connect agents directly