Skip to main content
Glama

startup

Verify GitHub authentication, validate state files, and check configuration status before starting operations.

Instructions

Run startup checks including GitHub auth verification, state file validation, and configuration status.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Main tool handler: runStartup() — runs startup checks (setup, auth, daily fetch, dashboard launch, issue list detection) and returns structured StartupOutput.
    export async function runStartup(): Promise<StartupOutput> {
      const version = getCLIVersion();
      const stateManager = getStateManager();
    
      // 1. Check setup — auto-detect if incomplete
      let autoDetected = false;
      if (!stateManager.isSetupComplete()) {
        const detectedUsername = await detectGitHubUsername();
        if (detectedUsername) {
          try {
            stateManager.initializeWithDefaults(detectedUsername);
            autoDetected = true;
          } catch (err) {
            console.error(
              `[STARTUP] Auto-detected username "${detectedUsername}" but failed to save config:`,
              errorMessage(err),
            );
            return { version, setupComplete: false };
          }
        } else {
          return { version, setupComplete: false };
        }
      }
    
      // 2. Check auth — use the async variant so the `gh auth token` CLI fallback
      // fires for users who ran `gh auth login` but never exported $GITHUB_TOKEN.
      // The sync `getGitHubToken()` reads only the env var, matching the `preAction`
      // token check that the CLI's `localOnly: true` flag on `startup` deliberately
      // skips — the mismatch produced a spurious `authError` for valid users.
      const token = await getGitHubTokenAsync();
      if (!token) {
        return {
          version,
          setupComplete: true,
          authError:
            'GitHub authentication required. Install GitHub CLI (https://cli.github.com/) and run "gh auth login", or set GITHUB_TOKEN.',
        };
      }
    
      // 3. Run daily check
      const daily = await executeDailyCheck(token);
    
      // 4. Launch interactive SPA dashboard.
      //
      // Launched unconditionally once setup and auth pass. A prior heuristic skipped
      // launch whenever `totalActivePRs === 0`, assuming that meant a genuine first
      // run and deferring to the CLI's welcome flow. That gate also swallowed the
      // dashboard in three legitimate cases: a misconfigured/stale `githubUsername`
      // (Search API returns zero), transient GitHub API flakes (state still holds
      // merged PRs but the live count is zero), and users genuinely between PRs.
      // The dashboard's own empty-state UI renders "no PRs" cleanly, so always
      // surfacing it is the right default.
      let dashboardUrl: string | undefined;
      let dashboardStatus: 'opened' | 'refreshed' | 'running' | undefined;
      let dashboardError: string | undefined;
    
      try {
        const spaResult = await launchDashboardServer();
        if (spaResult) {
          dashboardUrl = spaResult.url;
          if (spaResult.alreadyRunning) {
            const refreshed = await triggerDashboardRefresh(spaResult.port);
            dashboardStatus = refreshed ? 'refreshed' : 'running';
          } else {
            dashboardStatus = 'opened';
          }
          // `open`/`xdg-open`/`start` focus an existing tab matching the URL
          // instead of duplicating it, so this is safe whether the server was
          // just started or was already running. Closes #830 properly — a user
          // can close the dashboard tab while the daemon keeps running, leaving
          // subsequent /oss runs with no visible dashboard if we didn't re-open.
          openInBrowser(spaResult.url);
        } else {
          dashboardError = 'Dashboard SPA assets not found. Build with: cd packages/dashboard && pnpm run build';
          console.error(`[STARTUP] ${dashboardError}`);
        }
      } catch (error) {
        dashboardError = `SPA dashboard launch failed: ${errorMessage(error)}`;
        console.error(`[STARTUP] ${dashboardError}`);
      }
    
      // Append dashboard status to brief summary
      if (dashboardStatus === 'opened') {
        daily.briefSummary += ' | Dashboard opened in browser';
      } else if (dashboardStatus === 'refreshed') {
        daily.briefSummary += ' | Dashboard refreshed';
      } else if (dashboardStatus === 'running') {
        daily.briefSummary += ' | Dashboard running';
      }
    
      // 5. Detect issue list
      const issueList = detectIssueList();
    
      return {
        version,
        setupComplete: true,
        autoDetected,
        daily,
        dashboardUrl,
        dashboardError,
        issueList,
      };
    }
  • StartupOutput interface defining the schema for the startup command's return value (version, setupComplete, authError, daily, dashboardUrl, dashboardError, issueList).
    export interface StartupOutput {
      version: string;
      setupComplete: boolean;
      /** True when username was auto-detected on first run (zero-config). */
      autoDetected?: boolean;
      authError?: string;
      daily?: DailyOutput;
      /** URL of the interactive SPA dashboard server, when running (e.g., "http://localhost:3000") */
      dashboardUrl?: string;
      /**
       * Set when the dashboard launch or refresh failed (assets missing, port
       * conflict, spawn error, etc.). The dashboard is always attempted, so JSON
       * consumers — which previously saw only a missing `dashboardUrl` — now have
       * a structured signal to surface or recover from the failure.
       */
      dashboardError?: string;
      issueList?: IssueListInfo;
    }
  • IssueListInfo interface used in StartupOutput (path, source, availableCount, completedCount, skippedIssuesPath).
    export interface IssueListInfo {
      path: string;
      source: 'configured' | 'auto-detected';
      availableCount: number;
      completedCount: number;
      skippedIssuesPath?: string;
    }
  • MCP tool registration for 'startup' — registers the tool with empty input schema, description, and wrapTool(runStartup) as the handler.
    // 15. startup — Run startup checks
    server.registerTool(
      'startup',
      {
        description:
          'Run startup checks including GitHub auth verification, state file validation, and configuration status.',
        inputSchema: {},
        annotations: { readOnlyHint: false, destructiveHint: false },
      },
      wrapTool(runStartup),
    );
  • detectIssueList() helper — detects issue list from state config, legacy config.md, or known paths, and counts items.
    export function detectIssueList(): IssueListInfo | undefined {
      let issueListPath = '';
      let source: IssueListInfo['source'] = 'auto-detected';
    
      // 1. Check state.json config (primary)
      try {
        const stateManager = getStateManager();
        const configuredPath = stateManager.getState().config.issueListPath;
        if (configuredPath && fs.existsSync(configuredPath)) {
          issueListPath = configuredPath;
          source = 'configured';
        }
      } catch (error) {
        // State manager may not be initialized yet — fall through to legacy config.md
        warn('startup', `Could not read issueListPath from state: ${errorMessage(error)}`);
      }
    
      // 2. Fallback: config.md (legacy — will be removed in future)
      if (!issueListPath) {
        const configPath = '.claude/oss-autopilot/config.md';
        if (fs.existsSync(configPath)) {
          try {
            const configContent = fs.readFileSync(configPath, 'utf8');
            const configuredPath = parseIssueListPathFromConfig(configContent);
            if (configuredPath && fs.existsSync(configuredPath)) {
              issueListPath = configuredPath;
              source = 'configured';
            }
          } catch (error) {
            console.error('[STARTUP] Failed to read config:', errorMessage(error));
          }
        }
      }
    
      // 3. Probe known paths
      if (!issueListPath) {
        const probes = ['open-source/potential-issue-list.md', 'oss/issue-list.md', 'issues.md'];
        for (const probe of probes) {
          if (fs.existsSync(probe)) {
            issueListPath = probe;
            source = 'auto-detected';
            break;
          }
        }
      }
    
      if (!issueListPath) return undefined;
    
      // 4. Count available/completed items
      let availableCount = 0;
      let completedCount = 0;
      try {
        const content = fs.readFileSync(issueListPath, 'utf8');
        ({ availableCount, completedCount } = countIssueListItems(content));
      } catch (error) {
        console.error(`[STARTUP] Failed to read issue list at ${issueListPath}:`, errorMessage(error));
      }
    
      // 5. Detect skipped issues file
      let skippedIssuesPath: string | undefined;
    
      // Check config first
      try {
        const stateManager = getStateManager();
        const configuredSkipPath = stateManager.getState().config.skippedIssuesPath;
        if (configuredSkipPath && fs.existsSync(configuredSkipPath)) {
          skippedIssuesPath = configuredSkipPath;
        }
      } catch (err) {
        // State access can fail on a degraded state file (corrupt JSON, EACCES).
        // Default-path probe below still runs; warn so the underlying cause is visible (#994).
        // Matches the sibling warn at line 64 for `issueListPath` read failures.
        warn('startup', `Could not read skippedIssuesPath from state: ${errorMessage(err)}`);
      }
    
      // Probe default path: same directory as issue list, named skipped-issues.md
      if (!skippedIssuesPath && issueListPath) {
        const defaultSkipPath = path.join(path.dirname(issueListPath), 'skipped-issues.md');
        if (fs.existsSync(defaultSkipPath)) {
          skippedIssuesPath = defaultSkipPath;
        }
      }
    
      return { path: issueListPath, source, availableCount, completedCount, skippedIssuesPath };
    }
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description states it runs checks, which suggests read-only behavior, but annotations indicate readOnlyHint=false, implying possible state modification. This contradiction is not resolved, and no details on side effects are given.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single clear sentence that directly conveys the tool's purpose without extraneous content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description lists the checks performed but omits return value information (no output schema) and does not clarify the apparent contradiction with annotations. It is partially complete but missing important behavioral context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are no parameters, so schema coverage is 100%. The description adds no parameter details but this is acceptable since no parameters exist. Baseline of 4 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool runs startup checks and lists specific items (GitHub auth, state file, config status). However, it does not differentiate from sibling tool 'check-setup', which may have similar functionality.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives like 'check-setup', 'setup', or 'init'. The description implies it is for initial startup checks but lacks explicit context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/costajohnt/oss-autopilot'

If you have feedback or need assistance with the MCP directory API, please join our Discord server