Repository navigation
Design: repository-scoped task keys (PROJ-REPO-N, e.g. TRIM-UI-200) for multi-repo projects #649
Description
Follow-up to the discussion in Paca-AI/paca-plugins#34. This is a text-only proposal: I'd like agreement on the semantics before I write any code. It builds on #648 (project connections, several repositories per project).
Problem
A project can now link several repositories, possibly from different providers. Its task keys (TRIM-200) don't say which repository the work belongs to:
- An agent picking up
TRIM-200has no signal for which linked repo to work in. - A branch or change-request title that names a task links it in every linked repo where the key appears, even when the work belongs to one repo only.
- Making the key optional doesn't fix this: a team that works for months with
TRIM-200on one repo and then links a second one ends up with ambiguous keys and two naming conventions. - Existing bug: the matcher in
service/git/service.go(taskRefRE = (?i)\b([a-z][a-z0-9]{0,9})-(\d{1,7})\b) parsesTRIM-UI-200asUI-200, because\bmatches after the first hyphen. So a 3-part key today links to nothing, or to a different project whose prefix happens to beUI.
Proposal
1. Per-link repository short key (required, auto-suggested)
- New column
git_repositories.short_key TEXT NOT NULL, with a check that it is never empty.- Unique index on
(project_id, upper(short_key)).
- Unique index on
- Format
^[A-Z][A-Z0-9]{0,9}$:- Uppercased, like
task_id_prefix. - No hyphen, so parsing stays unambiguous.
- Must not equal the project's own
task_id_prefix.
- Uppercased, like
- Required on every linked repository, even when the project has only one. A repository can never be in a "no key" state, so linking another repo later changes nothing for the existing ones.
- Auto-suggested in the link form, which arrives pre-filled. This mirrors how
suggestPrefixpre-fillstask_id_prefix. The suggestion comes from the last segment offull_path:- initials of
-/_/.-separated words:ui-app→UA; - otherwise the first 4 letters:
frontend→FRON; - a numeric suffix if the key is taken in the project:
FRON2.
The user can change the key but not clear it.
- initials of
- Editable later through PATCH. Existing branch and CR links are stored rows and are kept. Only new branches using the old key stop matching, and the UI says so.
- The key belongs to the link, so the same repo can carry a different key in each project that links it.
2. Key grammar and matching
- Two forms:
PROJ-N: today's form, behaviour unchanged.PROJ-REPO-N: new.
REPOis a routing and validation hint, not part of the task's identity. Task numbers stay per project, soTRIM-UI-200andTRIM-200refer to the same task.- A new pure parser
parseTaskRefs(text)tries the 3-part form first, then the 2-part form on the remaining text, so a matched 3-part key is never re-read asUI-200. - In
saveChangeRequest, for an event on repo R of project P:PROJ-N: still accepted for backward compatibility. It links in the repo the event came from, as today. Agents, branch hints and docs always use the 3-part form.PROJ-REPO-N: link only whenPROJmatches P'stask_id_prefixandREPOmatchesR.short_key. A key that names another repository of the project is ignored on R.
FindTaskByRefis reused unchanged.
3. API
short_keyis added to:- the link request (
LinkGitRepositoryRequest/LinkInput): required in the UI; if an API call omits it, the server applies the suggestion; GitRepositoryResponse;- the task git view (
TaskChangeRequest/TaskBranch).
- the link request (
- New route
PATCH /projects/{id}/git/repositories/{repositoryId}to set or change the key, gated bygit:write. - New errors
GIT_SHORT_KEY_INVALIDandGIT_SHORT_KEY_TAKEN.
4. Agents and MCP
- In the agent prompt (
prompt.go):- The repository bullet shows its short key.
- The branch hint becomes
paca/<PROJ>-<REPO>-<N>-<topic>.
list_repositoriesexposesshort_key.- The
change_request_opendescription mentionsPACA-12andPACA-UI-12. - Optional:
CreateTaskBranchderives a default branch name from the key when none is given.
5. Web
- Project Settings → Git → Repositories:
- A required, pre-filled "Short key" field in the link form.
- A key badge with inline edit on each row.
- Task detail shows the key next to the repository path.
- Strings are added in all 9 locales.
6. Docs
docs/ai-agent/git-agent-workflow.md: task-key linking, schema.- One line in
docs/plugins/git-provider-spi.md: providers never see task keys.
7. Related: connections per repository
With multi-repo projects, GitLab users will often add one project access token per repository, or a group token. Recognizing each token's type and reach (and not binding a public repo to a token that can't write to it) is provider work, tracked in Paca-AI/paca-plugin-gitlab#2. It is independent of short keys: each repo has its own key whatever connection serves it.
Migration / upgrade path
There are three separate layers:
- Core schema.
000073_add_git_integration(git_repositories) is not in any release yet: v0.19.2 stops at000072.- If this lands before v0.20 ships, the column can go straight into
000073, the same way feat(git): enhance project connection management #648 edits it in place. No backfill is needed. - Otherwise, a new migration backfills every existing link in SQL:
- derive the key from the last path segment (uppercase, strip non-alphanumerics, truncate);
- de-duplicate per project with
row_number(), adding a numeric suffix; - avoid the project prefix;
- then add
NOT NULLand the unique index.
- If this lands before v0.20 ships, the column can go straight into
- Existing branch names and links. Stored
git_task_branchesandgit_task_linksrows are untouched.PROJ-Nkeeps matching, so no existing branch or CR stops working.- Note for users coming from the community GitLab plugin v0.5.x: it also auto-linked
feat/TRIM/200-xand number-onlyfeat/200-xbranches. Core never did, so those forms are not carried over.
- Note for users coming from the community GitLab plugin v0.5.x: it also auto-linked
- Plugin data from the previous releases. Per-project tokens, linked repos and task↔MR/branch links lived in the plugin's own tables.
- The new GitLab provider's
0002drops them, and the plugin id change (com.gorlix.gitlab→com.paca.gitlab) means its migrations run in a fresh schema anyway. Today an upgrading user loses their connection, repositories and task links and must relink by hand. - feat(git): enhance project connection management #648 says the GitHub plugin will migrate the previous release's per-project tokens, repositories and PR/branch links into project-scoped token connections. GitLab should get the same path.
- What I'd need to know: how a plugin migration can create core
git_identities/git_repositories/git_task_*rows, and whether it can read the old plugin schema. - Once the new repos exist, the short keys come from layer 1.
- The new GitLab provider's
Optional follow-up: plugin-sdk-go (additive, stays gitprovider.v1)
Everything above is core-only. An SDK change is needed only if we also want to link from change-request descriptions and commit messages, which the SPI doesn't carry today:
- SDK:
- Add
EventSubject.Title/Body(omitempty). - Add
PushInfo.Commits []CommitInfo{SHA, Message}. - Update the golden wire shapes, the fake provider and the conformance fixtures.
- Add
- Core:
- Run
sync-git-spi.sh. - Scan the body in
trackChangeRequest. - Handle
EventPushat ingest, linking only and never triggering agents.
- Run
- Providers: fill these fields. For GitLab:
object_attributes.descriptionandcommits[].message.
I'd rather keep the key grammar in core than have providers emit extracted task_refs. Otherwise every plugin has to reimplement the same parser.
Open questions
- When
PROJ-REPO-Nnames another repo of the project: ignore it (my proposal) or link anyway? - Should the SDK follow-up go in the same PR or a separate one?
- Should this wait for feat(git): enhance project connection management #648 to merge, or be based on its branch? And can the column still be folded into
000073before v0.20? - Plugin data migration: what mechanism will the GitHub plugin use to move legacy per-project tokens, repos and links into core? I'd like to do the same for GitLab, including reading from the old
com.gorlix.gitlabschema.
Testing plan
- Parser unit tests:
TRIM-UI-200,feat/TRIM-UI-200-x,TRIM-200, andfix TRIM-UI-200 and TRIM-7. None of them may yieldUI-200. - Service tests: right repo vs. wrong repo, and legacy
PROJ-N. - Postgres tests: uniqueness of
short_keyper project, and the backfill migration (duplicates, prefix collision). - Web tests:
GitSettingsand locale parity. - e2e:
git-settings. - Manual:
- Project
TRIMwith two GitLab repos keyedUIandAPI. - A change request on
feat/TRIM-UI-200-xin theUIrepo links task 200. - The same branch in the
APIrepo links nothing.
- Project
Activity
pullfrog commentedon Oct 28, 2026
pikann commentedon Oct 28, 2026
Hi @gorlix ,
Thanks for the detailed write-up!
I have a concern regarding cross-repo tasks. Quite often, a single task spans multiple repositories (e.g., a backend API change and its frontend implementation). Hardcoding a repo key like TRIM-UI-200 feels a bit too rigid for these cases and might force teams to create duplicate tasks.
Right now, we solve this by clearly documenting each repo's scope in the docs, which gives agents all the context they need to pick the right repo(s). Keeping PROJ-N as the main identifier feels more flexible overall.
gorlix commentedon Oct 28, 2026
Hi @pikann, a quick update and one question.
The two parts you approved are open: the parser fix in #657 and the repository description in #658. Testing them end to end against a real GitLab also produced #656 (with #659 and #660), and on the plugin side Paca-AI/paca-plugin-gitlab#3 and #4.
Question: migration from the community GitLab plugin (0.5.x). It is the open point from the "Migration" section above. #648 says
paca-plugin-githubmigrates the previous release's per-project tokens, repositories and PR/branch links into project-scoped token connections. The GitLab provider has no equivalent: its0002drops the old tables. On top of that, the plugin id changes fromcom.gorlix.gitlabtocom.paca.gitlab, so its migrations run in a fresh schema. Users upgrading from 0.5.x would lose their token, linked repositories and task↔MR/branch links, and have to relink by hand.Are you planning to do this migration yourself, the same way as for GitHub? You know the mechanism best (how a plugin migration creates core
git_identities/git_repositories/git_task_*rows, and whether it can read the oldcom.gorlix.gitlabschema). If you'd rather I take it, a pointer to how the GitHub one does it would be enough to get me started.pikann commentedon Oct 29, 2026
Hi @gorlix ,
Thanks for catching this! Please feel free to open a PR for the migration if you're up for it.
Thanks again for all your work on this!