Skip to Content
DocumentationRegistryExamplesGitHub OAuth Example

@loopstack/github-oauth-example

An example module for the Loopstack AI  automation framework.

This module demonstrates how to build workflows that interact with the GitHub API using OAuth authentication. It includes two workflows: a structured overview that fetches repository data, and an interactive chat agent powered by Claude that can use all 25 GitHub tools.

Workflows

GitHub Repos Overview (gitHubReposOverview)

A multi-step workflow that fetches and displays a comprehensive overview of a GitHub repository. If the user is not authenticated, it launches the OAuth sub-workflow and retries automatically.

Inputs: owner (default: octocat), repo (default: Hello-World)

Flow:

start -> user_fetched -> orgs_fetched -> repo_fetched -> issues_prs_fetched -> content_actions_fetched -> search_done -> end

With OAuth branching:

user_fetched -> (unauthorized via @Guard) -> awaiting_auth | auth_completed -> start (retry)

Key patterns:

The workflow uses @Guard to check if authentication is needed and routes to the OAuth flow:

@Transition({ from: 'user_fetched', to: 'awaiting_auth', priority: 10 }) @Guard('needsAuth') async authRequired() { const result = await this.oAuth.run( { provider: 'github', scopes: ['repo', 'read:org', 'workflow'] }, { alias: 'oAuth', callback: { transition: 'authCompleted' } }, ); await this.documentStore.save( LinkDocument, { label: 'GitHub authentication required', workflowId: result.workflowId, embed: true, expanded: true, }, { id: `link_${result.workflowId}` }, ); } needsAuth(): boolean { return !!this.requiresAuthentication; }

The auth callback uses wait: true with CallbackSchema to receive the OAuth completion signal:

@Transition({ from: 'awaiting_auth', to: 'start', wait: true, schema: CallbackSchema, }) async authCompleted(payload: { workflowId: string }) { await this.documentStore.save( LinkDocument, { status: 'success', label: 'GitHub authentication completed', workflowId: payload.workflowId, embed: true, expanded: false, }, { id: `link_${payload.workflowId}` }, ); }

Tools exercised in the workflow:

CategoryToolUsed in workflow
UsersgitHubGetAuthenticatedUserYes
UsersgitHubListUserOrgsYes
ReposgitHubListReposNo
ReposgitHubGetRepoYes
ReposgitHubCreateRepoNo
ReposgitHubListBranchesYes
IssuesgitHubListIssuesYes
IssuesgitHubGetIssueNo
IssuesgitHubCreateIssueNo
IssuesgitHubCreateIssueCommentNo
Pull RequestsgitHubListPullRequestsYes
Pull RequestsgitHubGetPullRequestNo
Pull RequestsgitHubCreatePullRequestNo
Pull RequestsgitHubMergePullRequestNo
Pull RequestsgitHubListPrReviewsNo
ContentgitHubGetFileContentNo
ContentgitHubCreateOrUpdateFileNo
ContentgitHubListDirectoryYes
ContentgitHubGetCommitNo
ActionsgitHubListWorkflowRunsYes
ActionsgitHubTriggerWorkflowNo
ActionsgitHubGetWorkflowRunNo
SearchgitHubSearchCodeYes
SearchgitHubSearchReposNo
SearchgitHubSearchIssuesNo

All 25 tools are injected and available; 9 are called directly by the workflow transitions. The remaining 16 (including all write operations) are available for use but not exercised automatically.

GitHub Agent (gitHubAgent)

An interactive chat agent that gives Claude access to all 25 GitHub tools. The agent can manage repositories, issues, pull requests, browse code, check CI/CD status, search across GitHub, and handle OAuth automatically via the AuthenticateGitHubTask custom tool.

How it works:

  1. Sets up a hidden system message describing available GitHub capabilities
  2. Waits for user input via a wait: true transition
  3. Sends the conversation to Claude with all 25 GitHub tools plus authenticateGitHub
  4. If message.stopReason === 'tool_use', delegates tool calls via LlmDelegateToolCallsTool and collects results with LlmUpdateToolResultTool
  5. If a tool returns an auth error, the LLM calls authenticateGitHub which launches OAuth
  6. Loops back to wait for the next user message

Agent loop pattern:

@InjectTool({ provider: 'claude', model: 'claude-sonnet-4-6', system: `You are a helpful GitHub assistant with access to repository, issue, PR, code, actions, and search tools. When a tool returns an unauthorized error, use authenticateGitHub to let the user sign in, then retry. Be concise and format results using markdown.`, tools: [ 'gitHubListRepos', 'gitHubGetRepo', 'gitHubCreateRepo', 'gitHubListBranches', 'gitHubListIssues', 'gitHubGetIssue', 'gitHubCreateIssue', 'gitHubCreateIssueComment', 'gitHubListPullRequests', 'gitHubGetPullRequest', 'gitHubCreatePullRequest', 'gitHubMergePullRequest', 'gitHubListPrReviews', 'gitHubGetFileContent', 'gitHubCreateOrUpdateFile', 'gitHubListDirectory', 'gitHubGetCommit', 'gitHubListWorkflowRuns', 'gitHubTriggerWorkflow', 'gitHubGetWorkflowRun', 'gitHubSearchCode', 'gitHubSearchRepos', 'gitHubSearchIssues', 'gitHubGetAuthenticatedUser', 'gitHubListUserOrgs', 'authenticateGitHub', ], }) llmGenerateText: LlmGenerateTextTool; @InjectTool({ provider: 'claude' }) llmDelegateToolCalls: LlmDelegateToolCallsTool; @Transition({ from: 'ready', to: 'prompt_executed' }) async llmTurn() { const result: ToolResult<LlmGenerateTextResult> = await this.llmGenerateText.call(); this.llmResult = result.data; } @Transition({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 }) @Guard('hasToolCalls') async executeToolCalls() { const result: ToolResult<LlmDelegateResult> = await this.llmDelegateToolCalls.call({ message: this.llmResult!.message, callback: { transition: 'toolResultReceived' }, }); this.delegateResult = result.data; } hasToolCalls(): boolean { return this.llmResult?.message.stopReason === 'tool_use'; }

This is the easiest way to interactively test every GitHub tool — just ask the agent to perform any GitHub operation.

Setup

Environment Variables

Create a GitHub OAuth App at https://github.com/settings/developers  and configure:

GITHUB_CLIENT_ID=your-client-id GITHUB_CLIENT_SECRET=your-client-secret GITHUB_OAUTH_REDIRECT_URI=http://localhost:5173/oauth/callback

For the GitHub Agent workflow, you also need an LLM API key:

ANTHROPIC_API_KEY=your-anthropic-api-key

Dependencies

  • @loopstack/common - Core workflow/runtime APIs (BaseWorkflow, @Workflow, @Transition, @Guard, CallbackSchema, ToolResult, LinkDocument, MarkdownDocument, MessageDocument)
  • @loopstack/llm-provider-module - LLM adapter tools (LlmGenerateTextTool, LlmMessageDocument, LlmDelegateToolCallsTool, LlmUpdateToolResultTool)
  • @loopstack/oauth-module - OAuth infrastructure (OAuthWorkflow)
  • @loopstack/github-module - All 25 GitHub tools

About

Author: Jakob Klippel 

License: MIT

Additional Resources

Last updated on