@@ -13,34 +13,110 @@ type tokenSpec struct {
1313 Name string
1414 When string
1515 Description string
16+ Optional bool
17+ }
18+
19+ // getRecommendedTokensForEngine returns token specs based on the workflow engine
20+ func getRecommendedTokensForEngine (engine string ) []tokenSpec {
21+ // Base tokens needed for most workflows
22+ tokens := []tokenSpec {
23+ {
24+ Name : "GH_AW_GITHUB_TOKEN" ,
25+ When : "Cross-repo Project Ops / remote GitHub tools" ,
26+ Description : "Fine-grained or classic PAT with contents/issues/pull-requests read+write on the repos gh-aw will touch." ,
27+ Optional : false ,
28+ },
29+ }
30+
31+ // Engine-specific tokens
32+ switch engine {
33+ case "copilot" :
34+ tokens = append (tokens , tokenSpec {
35+ Name : "COPILOT_GITHUB_TOKEN" ,
36+ When : "Copilot workflows (CLI, engine, agent tasks, etc.)" ,
37+ Description : "PAT with Copilot Requests permission and repo access where Copilot workflows run." ,
38+ Optional : false ,
39+ })
40+ case "claude" :
41+ tokens = append (tokens , tokenSpec {
42+ Name : "ANTHROPIC_API_KEY" ,
43+ When : "Claude engine workflows" ,
44+ Description : "API key from Anthropic Console for Claude API access." ,
45+ Optional : false ,
46+ })
47+ case "codex" :
48+ tokens = append (tokens , tokenSpec {
49+ Name : "OPENAI_API_KEY" ,
50+ When : "Codex/OpenAI engine workflows" ,
51+ Description : "API key from OpenAI for Codex/GPT API access." ,
52+ Optional : false ,
53+ })
54+ }
55+
56+ // Optional tokens for advanced use cases
57+ tokens = append (tokens ,
58+ tokenSpec {
59+ Name : "GH_AW_AGENT_TOKEN" ,
60+ When : "Assigning agents/bots to issues or pull requests" ,
61+ Description : "PAT for agent assignment with issues and pull-requests write on the repos where agents act." ,
62+ Optional : true ,
63+ },
64+ tokenSpec {
65+ Name : "GH_AW_GITHUB_MCP_SERVER_TOKEN" ,
66+ When : "Isolating MCP server permissions (advanced, optional)" ,
67+ Description : "Optional read-mostly token for the GitHub MCP server when you want different scopes than GH_AW_GITHUB_TOKEN." ,
68+ Optional : true ,
69+ },
70+ )
71+
72+ return tokens
1673}
1774
1875// recommendedTokenSpecs defines the core tokens we surface in tokens.md
76+ // This is kept for backward compatibility and default listing
1977var recommendedTokenSpecs = []tokenSpec {
2078 {
2179 Name : "GH_AW_GITHUB_TOKEN" ,
2280 When : "Cross-repo Project Ops / remote GitHub tools" ,
2381 Description : "Fine-grained or classic PAT with contents/issues/pull-requests read+write on the repos gh-aw will touch." ,
82+ Optional : false ,
2483 },
2584 {
2685 Name : "COPILOT_GITHUB_TOKEN" ,
2786 When : "Copilot workflows (CLI, engine, agent tasks, etc.)" ,
2887 Description : "PAT with Copilot Requests permission and repo access where Copilot workflows run." ,
88+ Optional : true ,
89+ },
90+ {
91+ Name : "ANTHROPIC_API_KEY" ,
92+ When : "Claude engine workflows" ,
93+ Description : "API key from Anthropic Console for Claude API access." ,
94+ Optional : true ,
95+ },
96+ {
97+ Name : "OPENAI_API_KEY" ,
98+ When : "Codex/OpenAI engine workflows" ,
99+ Description : "API key from OpenAI for Codex/GPT API access." ,
100+ Optional : true ,
29101 },
30102 {
31103 Name : "GH_AW_AGENT_TOKEN" ,
32104 When : "Assigning agents/bots to issues or pull requests" ,
33105 Description : "PAT for agent assignment with issues and pull-requests write on the repos where agents act." ,
106+ Optional : true ,
34107 },
35108 {
36109 Name : "GH_AW_GITHUB_MCP_SERVER_TOKEN" ,
37110 When : "Isolating MCP server permissions (advanced, optional)" ,
38111 Description : "Optional read-mostly token for the GitHub MCP server when you want different scopes than GH_AW_GITHUB_TOKEN." ,
112+ Optional : true ,
39113 },
40114}
41115
42116// NewTokensBootstrapSubcommand creates the `tokens bootstrap` subcommand
43117func NewTokensBootstrapSubcommand () * cobra.Command {
118+ var engineFlag string
119+
44120 cmd := & cobra.Command {
45121 Use : "bootstrap" ,
46122 Short : "Check and suggest setup for gh-aw GitHub token secrets" ,
@@ -55,24 +131,35 @@ available) and prints the exact secrets to add and suggested scopes.
55131For full details, including precedence rules, see the GitHub Tokens
56132reference in the documentation.` ,
57133 RunE : func (cmd * cobra.Command , args []string ) error {
58- return runTokensBootstrap ()
134+ return runTokensBootstrap (engineFlag )
59135 },
60136 }
61137
138+ cmd .Flags ().StringVarP (& engineFlag , "engine" , "e" , "" , "Check tokens for specific engine (copilot, claude, codex)" )
139+
62140 return cmd
63141}
64142
65- func runTokensBootstrap () error {
143+ func runTokensBootstrap (engine string ) error {
66144 repoSlug , err := GetCurrentRepoSlug ()
67145 if err != nil {
68146 return fmt .Errorf ("failed to detect current repository: %w" , err )
69147 }
70148
71149 fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("Checking recommended gh-aw token secrets in %s..." , repoSlug )))
72150
73- missing := make ([]tokenSpec , 0 , len (recommendedTokenSpecs ))
151+ // Get tokens based on engine or use all recommended tokens
152+ var tokensToCheck []tokenSpec
153+ if engine != "" {
154+ tokensToCheck = getRecommendedTokensForEngine (engine )
155+ fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("Checking tokens for engine: %s" , engine )))
156+ } else {
157+ tokensToCheck = recommendedTokenSpecs
158+ }
159+
160+ missing := make ([]tokenSpec , 0 , len (tokensToCheck ))
74161
75- for _ , spec := range recommendedTokenSpecs {
162+ for _ , spec := range tokensToCheck {
76163 exists , err := checkSecretExists (spec .Name )
77164 if err != nil {
78165 // If we hit a 403 or other error, surface a friendly message and abort
@@ -88,13 +175,37 @@ func runTokensBootstrap() error {
88175 return nil
89176 }
90177
91- fmt .Fprintln (os .Stderr , console .FormatWarningMessage ("Some recommended gh-aw token secrets are missing:" ))
178+ // Separate required and optional missing secrets
179+ var requiredMissing , optionalMissing []tokenSpec
92180 for _ , spec := range missing {
181+ if spec .Optional {
182+ optionalMissing = append (optionalMissing , spec )
183+ } else {
184+ requiredMissing = append (requiredMissing , spec )
185+ }
186+ }
187+
188+ if len (requiredMissing ) > 0 {
189+ fmt .Fprintln (os .Stderr , console .FormatErrorMessage ("Required gh-aw token secrets are missing:" ))
190+ for _ , spec := range requiredMissing {
191+ fmt .Fprintln (os .Stderr , "" )
192+ fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("Secret: %s" , spec .Name )))
193+ fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("When needed: %s" , spec .When )))
194+ fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("Recommended scopes: %s" , spec .Description )))
195+ fmt .Fprintln (os .Stderr , console .FormatCommandMessage (fmt .Sprintf ("gh aw secret set %s --owner <owner> --repo <repo>" , spec .Name )))
196+ }
197+ }
198+
199+ if len (optionalMissing ) > 0 {
93200 fmt .Fprintln (os .Stderr , "" )
94- fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("Secret: %s" , spec .Name )))
95- fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("When needed: %s" , spec .When )))
96- fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("Recommended scopes: %s" , spec .Description )))
97- fmt .Fprintln (os .Stderr , console .FormatCommandMessage (fmt .Sprintf ("gh secret set %s -a actions" , spec .Name )))
201+ fmt .Fprintln (os .Stderr , console .FormatWarningMessage ("Optional gh-aw token secrets are missing:" ))
202+ for _ , spec := range optionalMissing {
203+ fmt .Fprintln (os .Stderr , "" )
204+ fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("Secret: %s (optional)" , spec .Name )))
205+ fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("When needed: %s" , spec .When )))
206+ fmt .Fprintln (os .Stderr , console .FormatInfoMessage (fmt .Sprintf ("Recommended scopes: %s" , spec .Description )))
207+ fmt .Fprintln (os .Stderr , console .FormatCommandMessage (fmt .Sprintf ("gh aw secret set %s --owner <owner> --repo <repo>" , spec .Name )))
208+ }
98209 }
99210
100211 fmt .Fprintln (os .Stderr , "" )
0 commit comments