Outcome
Allow a repository-scoped Projects V2 board to track issues from other repositories. Keep the repository that owns the project as the project authorization boundary, and treat each issue repository as a separate source and visibility boundary.
This limitation currently prevents the Cloud computer platform project from including OpenAgentsInc/openagents.com#37 and OpenAgentsInc/openagents.com#38.
Current behavior
POST /api/v3/repos/{project_owner}/{project_repo}/projectsV2/{project_number}/items accepts only issue_number. The implementation always resolves that number inside the repository that owns the project.
The current implementation reinforces that assumption:
OpenAgents.Projects.create_project_item/3 queries the issue with repository_id: project.repository_id.
OpenAgentsWeb.ProjectController.create_item/2 casts only issue_number.
project_items.repository_id and its composite foreign keys require the project and issue to share one repository.
- Project item list and get queries scope both the project and item through the same repository.
This design conflates project ownership with source-issue identity.
API contract
Keep the existing request backward compatible. A request with only issue_number continues to resolve the issue in the repository that owns the project:
{
"issue_number": 37,
"values": {
"Status": "To Do"
}
}
Add a canonical cross-repository request shape:
{
"issue": {
"owner": "OpenAgentsInc",
"repo": "openagents.com",
"number": 37
},
"values": {
"Status": "To Do"
}
}
Return the source identity in project item responses so API and CLI clients do not need to interpret an internal issue ID:
{
"issue": {
"owner": "OpenAgentsInc",
"repo": "openagents.com",
"number": 37,
"url": "https://openagents.com/api/v3/repos/OpenAgentsInc/openagents.com/issues/37",
"html_url": "https://openagents.com/OpenAgentsInc/openagents.com/issues/37"
}
}
Preserve existing response fields during the compatibility period.
Data model and migration
Separate project tenancy from source-issue tenancy.
Prefer a normalized project_id foreign key and issue_id foreign key, with repository identities derived through those records. If tenant-scoped composite foreign keys remain necessary, store distinct project_repository_id and issue_repository_id columns instead of one ambiguous repository_id.
The migration must:
- Preserve every existing project item.
- Remove the constraint that requires a project and issue to share a repository.
- Keep an explicit foreign key from the item to its project and source issue.
- Enforce one item per
project_id and issue_id.
- Define cleanup behavior when the project, source issue, or source repository is deleted.
- Support a safe rollback.
Authorization and visibility
Use both authorization boundaries:
- Require writable membership in the repository that owns the project to add, update, or remove a project item.
- Require read access to the source issue repository to add its issue. Project write access plus source read access is sufficient; changing the issue still requires source-repository write access.
- Return
404 for a source repository or issue that the actor cannot read.
- Never make a private source issue visible because it appears on a public or otherwise readable project.
- On project reads, omit an inaccessible source item or return a typed inaccessible placeholder that contains no repository name, issue number, title, body, labels, assignees, or other source metadata. Choose one behavior, document it, and test it consistently.
- Apply the same visibility rules to HTML, JSON, LiveView events, PubSub payloads, logs, and analytics.
Web and serialization behavior
- Preload each source issue and its repository without assuming that they match the project repository.
- Render cross-repository items as
owner/repo#number and link to the source issue.
- Keep project field values, status updates, ordering, and item removal scoped to the project.
- Do not expose private repository names or issue metadata through counts, empty states, errors, or live updates.
Documentation and CLI coverage
- Update
docs/openagents-cli/api.md with local and cross-repository openagents api --input examples.
- Update
docs/github-api-issues-projects-assessment.md to describe the new contract, authorization rules, response shape, and remaining compatibility differences.
- Keep the generic CLI API path working with nested JSON. A named project command is not required for this issue.
Acceptance criteria
- A project can add and list a public issue from another repository.
- A project writer with read-only access to a private source repository can add that issue.
- A project reader cannot add an issue even when they can write to the source repository.
- An actor without source-repository read access receives
404 and learns no private metadata.
- A viewer who loses source access cannot retrieve private issue metadata through the project.
- The same issue number in two repositories resolves to the explicit
owner, repo, and number.
- Adding the same source issue twice does not create duplicate project items.
- A nonexistent source repository or issue returns
404.
- The legacy
issue_number request continues to add an issue from the project repository.
- Project item JSON includes the source repository identity and issue number.
- The web project board labels and links cross-repository issues correctly.
- Controller, context, migration, authorization, LiveView, and repository-isolation tests cover these cases.
mix precommit passes.
Related work
Outcome
Allow a repository-scoped Projects V2 board to track issues from other repositories. Keep the repository that owns the project as the project authorization boundary, and treat each issue repository as a separate source and visibility boundary.
This limitation currently prevents the Cloud computer platform project from including OpenAgentsInc/openagents.com#37 and OpenAgentsInc/openagents.com#38.
Current behavior
POST /api/v3/repos/{project_owner}/{project_repo}/projectsV2/{project_number}/itemsaccepts onlyissue_number. The implementation always resolves that number inside the repository that owns the project.The current implementation reinforces that assumption:
OpenAgents.Projects.create_project_item/3queries the issue withrepository_id: project.repository_id.OpenAgentsWeb.ProjectController.create_item/2casts onlyissue_number.project_items.repository_idand its composite foreign keys require the project and issue to share one repository.This design conflates project ownership with source-issue identity.
API contract
Keep the existing request backward compatible. A request with only
issue_numbercontinues to resolve the issue in the repository that owns the project:Add a canonical cross-repository request shape:
Return the source identity in project item responses so API and CLI clients do not need to interpret an internal issue ID:
Preserve existing response fields during the compatibility period.
Data model and migration
Separate project tenancy from source-issue tenancy.
Prefer a normalized
project_idforeign key andissue_idforeign key, with repository identities derived through those records. If tenant-scoped composite foreign keys remain necessary, store distinctproject_repository_idandissue_repository_idcolumns instead of one ambiguousrepository_id.The migration must:
project_idandissue_id.Authorization and visibility
Use both authorization boundaries:
404for a source repository or issue that the actor cannot read.Web and serialization behavior
owner/repo#numberand link to the source issue.Documentation and CLI coverage
docs/openagents-cli/api.mdwith local and cross-repositoryopenagents api --inputexamples.docs/github-api-issues-projects-assessment.mdto describe the new contract, authorization rules, response shape, and remaining compatibility differences.Acceptance criteria
404and learns no private metadata.owner,repo, andnumber.404.issue_numberrequest continues to add an issue from the project repository.mix precommitpasses.Related work