12 KiB
spec, created, status
| spec | created | status |
|---|---|---|
| docs/specs/tasks/remote-contribution-tasks.md | 2026-08-04 | completed |
Implementation Plan: Remote Contribution Tasks
Overview
Teach the existing create_task_kandev.repositories[].repository_url field to recognize GitHub pull
request and GitLab merge request URLs without adding schema properties. Resolve provider-owned source
metadata before task creation, persist a typed contribution binding on the target task-repository
attachment, associate the existing remote change, and reconstruct the exact checkout and push target on
every launch. Keep origin and ordinary repository task behavior unchanged; fork write access is a
narrow, binding-authorized runtime capability.
The implementation follows ADR-2026-08-04-remote-contribution-bindings, provider-neutral remote repositories, and the existing task Git credential policy.
Implementation status
- Task 01 — provider-neutral binding validation and GitHub/GitLab contribution resolution.
- Task 02 — MCP URL resolution, target attachment persistence, existing-change association, and compensation on association failure.
- Task 03 — exact-SHA source materialization, target-origin preservation, restart-safe runtime projection, and collision-safe contribution remotes.
- Task 04 — binding-authorized credential scopes, source-branch push routing, no-force enforcement, dry-run preflight, and existing-change reuse.
- Task 05 — provider/runtime integration coverage, unchanged ordinary repository coverage, and public documentation updates.
Invariants
- The public
create_task_kandevinput property names and count do not change. - Provider APIs, not MCP callers, determine target/source identity, refs, SHA, state, and collaboration.
- One task-repository attachment represents the target repository; the contributor fork is a push destination, not another workspace source.
- All persisted URLs are canonical and credential-free. No provider title, body, token, lease, or credential-helper data enters the binding or trusted prompt.
- Contribution checkout and push paths fail closed on malformed or unknown binding versions, unsafe refs, stale head SHA, or source-scope mismatch.
- Ordinary repository tasks preserve current checkout,
origin, credential, and create-PR behavior.
Backend
Provider-neutral binding and provider resolution
- Add a versioned
RemoteContributiondomain shape beside task repository models with strict encode, decode, validation, and metadata helpers. It carries provider/kind, canonical change URL, number/IID, open state, base/head branches, head SHA, source repository identity/URL, and collaboration eligibility. - Extend GitHub
PRplus PAT andghconversions with the source repository owner/name/clone URL andmaintainer_can_modify. Add a workspace-scoped resolver that parses a canonicalgithub.comPR URL, fetches the PR, verifies returned target identity and open/live head state, and returns the shared binding without title/body content. - Extend GitLab MR transport/domain models with source/target project IDs and collaboration state, and expose enough project lookup data to obtain the source project's canonical clone URL and path. Add a workspace-scoped resolver that reuses configured-host parsing, verifies the target project, fetches the source project, and returns the shared binding.
- Treat same-repository changes as collaboration-eligible. Reject fork changes when GitHub
maintainer_can_modifyor GitLaballow_collaborationis false. Validate provider refs with the shared Git branch/ref validator before returning a binding.
MCP task creation and association
- Add a
RemoteContributionResolverinterface to the backend MCP create-task coordinator. Resolution receives the selected workspace and rawrepository_url, and returnsmatched=falsefor ordinary repository URLs so the existing resolver remains authoritative. - In
handleCreateTask, resolve contribution URLs after workspace/workflow selection but before task persistence. Replace the contribution URL with the canonical target repository input, set base and checkout branches from provider data, and carry the typed binding into the targetTaskRepositoryInput. - Persist
remote_contributionin the existingtask_repositories.metadataJSON during task creation; no schema migration is required. Keep the existing GitHubpr_numbercompatibility metadata where current worktree/read paths still consume it until all runtime reads use the typed binding. - After task persistence and before asynchronous launch, idempotently associate the GitHub PR or GitLab MR with the exact new task-repository attachment. On association failure, compensate the newly created task and return failure rather than launching an unlinked task.
- Wire provider adapters in
internal/backendappusing the existing MCP dependency-setter pattern. Preserve current task/profile/executor inheritance andstart_agentbehavior. - Change only the existing
repository_urlschema description. Add a catalog regression test that asserts the full property-name set is unchanged and that provider-specific source fields are absent.
Runtime projection and worktree materialization
- Thread the validated binding from task-repository metadata through
repoInfo,RepoSpec, lifecycle create/prepare requests, and agentctl repository configuration as one optional typed object rather than a growing list of primitives. - In worktree materialization, fetch the source branch from its credential-free source URL into a deterministic remote-tracking ref. Use a collision-resistant remote name derived from provider, host, and source path so shared repository/worktree Git config cannot alias two contributor forks.
- Require the fetched source ref to equal the persisted head SHA before creating the worktree. Create the
local checkout branch using the existing checked-out-branch collision strategy, then set its upstream
to the contribution remote's exact head branch. Preserve target
originfor base fetches and diffs. - Reconstruct the same remote and upstream on fresh launch, resume, reset, and remote/container materialization. Fail visibly if the source project disappears, the binding version is unsupported, or the remote name already resolves to inconsistent identity.
- Publish only structured contribution URL/provider/number/source-branch guidance to agent context. Never copy remote title, description, comments, or diff content into trusted context.
Credential authorization and push routing
- Extend managed GitHub session scope construction to add the source owner/repository only for a fork binding. Update the broker scope authorizer to prove the requested source identity exactly matches a valid contribution binding on the session's task-repository attachment. Leave ordinary target scope authorization unchanged.
- Carry explicit
push_remoteandpush_branchvalues into agentctl's repository tracker for contribution worktrees. UpdateGitOperator.Pushto use those values while normal repositories still default tooriginand their current local branch. Reject force pushes for remote-contribution tasks. - Before agent process startup, run
git push --dry-run <contribution-remote> HEAD:refs/heads/<head-branch>with the final task environment. This validates managed or executor-owned credentials without mutating the remote. Redact canonical URLs and provider errors in logs and user-visible failure details. - Ensure create-PR/create-MR operations detect the persisted existing-change association and return or
refresh it instead of pushing to
originand opening a duplicate.
Tests
- Provider resolution: table-driven GitHub PAT/CLI and GitLab client/service tests cover canonical URL parsing, returned identity mismatch, same-repository changes, editable/non-editable forks, closed/merged changes, missing heads, invalid refs, and credential-free source URLs.
- Binding persistence: task service and SQLite tests round-trip version 1 in
task_repositories.metadata, preserve unrelated metadata, reject invalid/unknown runtime bindings, and prove ordinary inputs omit the field. - MCP orchestration: handler/server tests cover both providers, current workspace resolution,
target repository creation, association-before-launch, compensation,
start_agent: false, ordinary repository fallback, and unchanged schema properties. - Worktree/runtime: temporary target/source Git repositories prove exact-SHA fetch, target
origin, source upstream, local-branch collision behavior, stale SHA rejection, restart reconstruction, and no cross-task remote aliasing. - Credentials/push: broker tests prove exact binding authorization and reject unrelated forks, malformed bindings, other tasks, and other sessions. Agentctl tests prove explicit source routing, dry-run preflight, redaction, no force push, and unchanged normal push behavior.
- Integration: a focused backend integration test creates a task from each provider URL with fake provider APIs and temporary Git remotes, prepares the session, commits, pushes, and verifies the source branch advances while the target branch and existing-change identity remain unchanged.
Public documentation
- Update the reference page
docs/public/automation-and-mcp.mdto document the polymorphicrepository_url, supported URL shapes, configured-provider prerequisite, unchanged input schema, collaboration requirement, and launch-time write preflight. - Update the task coordination how-to in
docs/public/coordination.mdwith one GitHub and one GitLab example and recovery guidance for disabled collaboration or missing credentials. - Keep security details concise and link to the existing credential-policy explanation rather than documenting tokens or broker internals. These are a reference-page update and a how-to update; no new navigation entry is needed.
Execution order
- Task 01: Provider contribution resolution
- Task 02: MCP creation and persistence
- Task 03: Runtime contribution materialization
- Task 04: Credential and push routing
- Task 05: Integration coverage and public docs
The tasks are intentionally sequential. Each wave establishes a security- or runtime-sensitive contract consumed by the next, and Tasks 02–04 touch shared task-launch types where parallel edits would be more expensive than the saved time.
Final verification
make -C apps/backend test
make -C apps/backend lint
node --test scripts/validate-public-docs.test.mjs
node scripts/validate-public-docs.mjs
No frontend implementation or browser E2E is required because this release changes only the MCP and backend runtime surfaces. If a task-creation UI is added later, it requires a separate mobile-parity design and E2E package.
Verification results
make -C apps/backend test— passed.make -C apps/backend lint— passed with zero backend, web, harness, and architecture issues.node --test scripts/validate-public-docs.test.mjs— 58 tests passed.node scripts/validate-public-docs.mjs— 41 published pages validated.- The affected backend package suite — 5,603 tests passed across 17 packages.
git diff --check— passed.