il plan cannot create sub-issues on repositories where user lacks write/triage access#729
il plan cannot create sub-issues on repositories where user lacks write/triage access#729
Conversation
Complexity AssessmentClassification: SIMPLE Metrics:
Reasoning: The solution is straightforward: detect when |
Complexity Assessment - Issue #639Progress:
Key Files AffectedSource files to modify:
Test files: Scope SummaryFiles affected: 5 files (4 production + 1 test) Estimated LOC: 260-320 total (60-100 in plan.ts, 30-50 in github.ts, 80-120 in prompt, 100-150 in tests) Breaking changes: YES - User-visible behavior change (plan creates comments instead of child issues when user lacks write access) Cross-cutting changes: YES
File architecture quality: POOR
Architectural complexity signals triggered:
Risk assessment: MEDIUM-HIGH
Complexity AssessmentClassification: COMPLEX Metrics:
Reasoning: This issue appears deceptively simple (permission check) but requires cross-cutting behavioral changes. Permission detection must coordinate between CLI, MCP server tool availability, and agent prompt instructions. Read-only mode fallback is new functionality in already-large files (500+ LOC) with poor architecture. The "how to implement" (especially comment generation as fallback) is not obvious from "what to implement." |
Analysis: Issue #639 - Permission Gating for
|
| Question | Answer |
|---|---|
| Should read-only mode apply to both "existing issue" and "fresh planning" modes? | Yes for existing issue mode (comment on parent issue). For fresh planning mode, there is no parent issue to comment on, so the agent would need to create a single standalone issue with the full breakdown as the body, OR simply output the plan to the terminal without creating any issues. Creating a standalone issue is possible since gh issue create works on public repos without write access. Recommend: in fresh planning + read-only, create a single issue with the full plan (no child issue/dependency linking). |
| Should the user be warned/informed that they're in read-only mode? | Yes. A clear logger.warn() message at plan start, and a template variable so the prompt tells the agent about the constraint. |
What viewerPermission levels constitute "has write access"? |
ADMIN, MAINTAIN, and WRITE should be considered sufficient. TRIAGE and READ are insufficient for sub-issues/dependencies. |
Impact Summary
- 3 files requiring modification:
src/commands/plan.ts,templates/prompts/plan-prompt.txt,src/utils/github.ts - 1 file requiring test updates:
src/commands/plan.test.ts - New utility function needed in
github.tsfor permission detection - Cross-cutting change: Permission flag flows through 4 layers (detection -> template variables -> prompt conditionals -> allowedTools filtering)
Complete Technical Reference (click to expand for implementation details)
Problem Space Research
Problem Understanding
External contributors to open-source repos can create issues on public repos but cannot use the addSubIssue GraphQL mutation (requires triage+) or the createDependency REST API (requires write access). The current il plan workflow assumes write access and fails partway through, creating orphaned issues.
Architectural Context
il plan is a Claude-powered interactive planning session. It assembles a prompt template, configures MCP tools, and launches Claude with specific tool access. The architect agent uses MCP tools to create issues, link child issues, and set up dependencies. The fix requires gating which MCP tools are available and adjusting prompt instructions based on detected permissions.
Edge Cases
- Fork scenarios: User has cloned a fork.
gh repo viewon the fork shows WRITE access, but the upstream repo (where issues live) may have READ-only. The permission check must target the correct repo (the one issues are being created on). - GitHub fine-grained PATs: Some tokens may have limited scopes. The
viewerPermissionfield should still reflect effective permissions. - Non-GitHub providers: Linear and Jira have different permission models. The permission check must only apply when
provider === 'github'. - Offline/API failure: If the permission check fails, the system should default to allowing full access (fail-open) to avoid breaking existing workflows.
Third-Party Research Findings
GitHub CLI viewerPermission field
Source: WebSearch
Key Findings:
gh repo view <repo> --json viewerPermissionreturns the authenticated user's permission level- Possible values:
ADMIN,MAINTAIN,WRITE,TRIAGE,READ,NONE(empty string for no access) - This is a single lightweight API call that doesn't require special scopes
- Works with both
--repo owner/nameflag and current-directory detection
Reference: gh repo view docs
GitHub Sub-Issues Permission Requirements
Source: Issue #639 body + GitHub docs
Key Findings:
addSubIssueGraphQL mutation requires at least triage permissionscreateDependencyREST API requires write accessgh issue createworks on public repos for any authenticated user- Creating a regular issue + commenting on it does NOT require write access
Reference: GitHub Sub-Issues docs
Codebase Research Findings
Affected Area: Plan Command (src/commands/plan.ts)
Entry Point: src/commands/plan.ts:82 - PlanCommand.execute()
Key locations:
- Lines 190-251: Issue decomposition mode detection and context fetching
- Lines 267-352: MCP config generation (calls
generateIssueManagementMcpConfig) - Lines 376-394: Template variables assembly -- new
READ_ONLY_MODEvariable needed here - Lines 401-428:
allowedToolsarray definition -- write tools must be conditionally excluded - Lines 434-441: Claude options assembly
- Lines 486-504: Initial message construction -- may need read-only mode context
Dependencies:
- Uses:
generateIssueManagementMcpConfigfromsrc/utils/mcp.ts,getRepoInfofromsrc/utils/github.ts,PromptTemplateManager,IssueTrackerFactory,launchClaude - Used By: CLI command handler in
src/cli.ts
Affected Area: GitHub Utilities (src/utils/github.ts)
Entry Point: New function needed
Key locations:
- Lines 13-32:
executeGhCommand()-- the base wrapper forghCLI calls - Lines 424-439:
getRepoInfo()-- existing pattern forgh repo view --jsoncalls. NewgetRepoPermission()function should follow this pattern.
Similar Patterns Found:
getRepoInfo()atsrc/utils/github.ts:425-439-- usesexecuteGhCommandwithgh repo view --json owner,name. The new permission function should follow the same pattern with--json viewerPermission.checkGhAuth()atsrc/utils/github.ts:35-104-- returns structured auth status. Permission check can follow a similar return pattern.
Affected Area: Plan Prompt Template (templates/prompts/plan-prompt.txt)
Entry Point: templates/prompts/plan-prompt.txt:1 (full file, 514 lines)
Key locations:
- Lines 273-295: "Issue Creation" section -- must be conditionally replaced in read-only mode
- Lines 296-378: "Issue Decomposition Mode" and "Fresh Planning Mode" -- must have read-only alternatives
- Lines 339-350: Creation order steps (create child issues, set up dependencies, post ADR comment) -- must be replaced with comment-based output in read-only mode
- Lines 358-378: Fresh planning mode steps -- must be replaced with single-issue creation in read-only mode
Affected Area: Allowed Tools Filtering (src/commands/plan.ts:401-428)
Current write tools that must be removed in read-only mode:
mcp__issue_management__create_issue(line 403) -- keep for fresh planning mode (can create standalone issues on public repos)mcp__issue_management__create_child_issue(line 404) -- REMOVE (requires sub-issue linking)mcp__issue_management__create_dependency(line 410) -- REMOVE (requires write access)mcp__issue_management__remove_dependency(line 412) -- REMOVE (requires write access)
Tools to KEEP in read-only mode:
- All read tools (get_issue, get_child_issues, get_comment, get_dependencies)
mcp__issue_management__create_comment(line 407) -- commenting works without write accessmcp__issue_management__create_issue-- creating standalone issues works on public repos- All codebase exploration tools (Read, Glob, Grep, Task, WebFetch, WebSearch, Bash git)
Architectural Flow Analysis
Data Flow: hasWriteAccess permission flag
Entry Point: src/commands/plan.ts:~270 (after MCP config generation, before template variables) -- new permission check call
Flow Path:
src/utils/github.ts(new function) --getRepoPermission(repo?)callsgh repo view --json viewerPermissionand returns permission level stringsrc/commands/plan.ts:~270-- callsgetRepoPermission(), determineshasWriteAccess = ['ADMIN', 'MAINTAIN', 'WRITE'].includes(permission)src/commands/plan.ts:376-394-- addsREAD_ONLY_MODE: !hasWriteAccesstotemplateVariablessrc/commands/plan.ts:401-428-- conditionally filtersallowedToolsbased onhasWriteAccesstemplates/prompts/plan-prompt.txt-- Handlebars{{#if READ_ONLY_MODE}}conditionals change agent instructions
Affected Interfaces (ALL must be updated):
- No TypeScript interface changes needed -- the permission flag is a local boolean in
plan.tsthat feeds into template variables (aRecord<string, unknown>) and theallowedToolsarray (astring[]). Both are already flexible types.
Critical Implementation Note: This is a cross-cutting change affecting 4 layers but requires NO interface changes. The main risk is ensuring consistency between the tools removed from allowedTools and the prompt template instructions. If the prompt tells the agent to use create_child_issue but the tool isn't available, the agent will fail.
Affected Files
/Users/adam/Documents/Projects/iloom-cli/fix-issue-639__no-write-access/src/utils/github.ts:424-439-- Add newgetRepoPermission()function followinggetRepoInfo()pattern/Users/adam/Documents/Projects/iloom-cli/fix-issue-639__no-write-access/src/commands/plan.ts:267-428-- Add permission detection after MCP config generation, addREAD_ONLY_MODEtemplate variable, conditionally filterallowedTools/Users/adam/Documents/Projects/iloom-cli/fix-issue-639__no-write-access/templates/prompts/plan-prompt.txt:273-378-- Add{{#if READ_ONLY_MODE}}conditionals for the "Issue Creation" section with alternative instructions for comment-based output/Users/adam/Documents/Projects/iloom-cli/fix-issue-639__no-write-access/src/commands/plan.test.ts-- Add tests for read-only mode behavior (tool filtering, template variables)
Integration Points
plan.tscallsgetRepoInfo()indirectly viagenerateIssueManagementMcpConfig()at line 272 -- the newgetRepoPermission()call should be placed after this succeeds (since it also callsgh repo view)- The
allowedToolsarray at line 401 directly controls what the launched Claude session can do - The
templateVariablesat line 376 directly control what instructions the prompt template renders - The prompt template's "Issue Creation" section (line 273+) is the primary driver of agent behavior
Medium Severity Risks
- Fork detection: If the user has forked a repo and is working from the fork,
gh repo view(without--repo) will check the fork's permissions (which the user owns). The permission check should use the same repo that MCP tools target (the upstream repo if that's where issues are created). ThegetRepoInfo()call atsrc/utils/mcp.ts:53already resolves the correct owner/name from git remote. - API rate limiting: Adding one more
gh repo viewcall peril planinvocation is minimal overhead, but if the call is made in addition to the existinggetRepoInfo()call insidegenerateIssueManagementMcpConfig, it's a second API call that could be combined into onegh repo view --json viewerPermission,owner,name.
Implementation Plan for Issue #639SummaryWhen users run Questions and Key Decisions
High-Level Execution Phases
Quick Stats
Complete Implementation Guide (click to expand for step-by-step details)Automated Test Cases to CreateTest File:
|
Implementation CompleteSummaryAdded read-only mode to Changes Made
Validation Results
Detailed Changes by File (click to expand)src/utils/github.tsChanges: Added
src/utils/github.test.tsChanges: Added 5 tests for
src/commands/plan.tsChanges: Wired permission detection into plan command
src/commands/plan.test.tsChanges: Added 12 new tests for permission-based behavior
templates/prompts/plan-prompt.txtChanges: Added read-only mode Handlebars conditionals
src/lib/PromptTemplateManager.tsChanges: Added src/types/telemetry.tsChanges: Added docs/iloom-commands.mdChanges: Added "Read-Only Mode (No Write Access)" documentation subsection |
When a user lacks write/triage permissions on a GitHub repository, `il plan` now automatically detects this and switches to read-only mode. Instead of failing when trying to create child issues and dependencies, plan mode produces a detailed issue comment with the suggested breakdown that a maintainer can act on. Changes: - Add getRepoPermission() utility to check GitHub repo permissions - Gate plan command behavior based on detected permission level - Add READ_ONLY_MODE Handlebars conditionals to plan prompt template - Filter write-only MCP tools (create_child_issue, create_dependency, remove_dependency) when in read-only mode - Track read_only_mode in epic.planned telemetry event - Document Read-Only Mode in iloom-commands.md Fixes #639
aceee61 to
4738494
Compare
Analysis: Permission check uses wrong repo in fork workflows
ETA: ~2 minutes Executive SummaryThe Additionally,
HIGH/CRITICAL Risks
Impact Summary
Complete Technical Reference (click to expand for implementation details)Problem Space ResearchProblem UnderstandingWhen a contributor forks an open-source repo and runs Architectural ContextThe plan command has two separate repo resolution paths that should agree but don't in fork scenarios:
Both use Meanwhile, Edge Cases Identified
Codebase Research FindingsAffected Area: Permission check in plan commandEntry Point: The flow:
How
|
- Fix getRepoPermission() to use positional arg instead of broken --repo flag - Have generateIssueManagementMcpConfig() return the resolved repo - Pass resolved repo to permission check so it targets upstream, not fork - Fix IssueEnhancementService test mock not re-seeded after mockReset - Clarify read-only prompt: epic body is overview, breakdown goes in comment - Strengthen prompt language to prevent creating child issues as standalone Fixes #639
Fixes #639
il plan cannot create sub-issues on repositories where user lacks write/triage access
Problem
When using
il planto decompose work on a repository the user does not have write or triage access to (e.g., contributing to an open-source project), the sub-issue creation step fails.GitHub's sub-issues feature requires at least triage permissions on the repository to link a child issue to a parent via the
addSubIssueGraphQL mutation. While anyone can create a regular issue on a public repository, the act of linking it as a sub-issue requires elevated permissions.This means the following workflow breaks for external contributors:
il planto decompose an upstream issue (e.g.,il plan #42)gh issue create-- this succeeds (public repos allow anyone to create issues)addSubIssueGraphQL mutation to link the new issue as a sub-issue of the parent -- this fails because the user doesn't have triage/write accessThe same limitation applies to the
create_dependencyREST API endpoint, which also requires write access.How iloom is affected
In
GitHubIssueManagementProvider.createChildIssue(), the workflow is:gh issue create(succeeds)addSubIssue(parentNodeId, childNodeId)(fails with permission error)This leaves orphaned issues -- the child issues get created but are never linked to the parent, and the error propagates up to the agent.
Relevant GitHub docs
Questions for maintainer
il planwhen used with GitHub on repositories the user doesn't own/have write access to?il plandetect the user's permission level on the target repo before attempting sub-issue creation, and adjust its strategy accordingly?Context
This doesn't affect Linear or Jira integrations -- Linear supports parent-child relationships atomically during issue creation, and Jira handles it through its own permission model. This is specific to the GitHub sub-issues API.
This PR was created automatically by iloom.