6.2 KiB
Native agent work grants — MCP adapter v1
Implementation source; live deployment and end-to-end acceptance are separate.
This is the thin Laboratory adapter for the reviewed Core
.forgejo/AGENT_WORK_GRANT_V1.md design and the
visible delegation requirements. A matching Core must
implement the native routes, browser session approval and durable transaction
boundary. The adapter does not create that authority itself.
Authenticated tools and native routes
| Tool | Inputs | Native operation |
|---|---|---|
list_agent_work_grants |
optional positive page, optional state |
GET /api/v1/agent-work-grants outside /user |
get_agent_work_grant |
owner, repo, positive native grant_id |
GET /api/v1/repos/{owner}/{repo}/agent-work-grants/{grant_id} |
confirm_agent_work_grant |
context plus exact proposal triple | POST .../{grant_id}/confirm |
submit_agent_work_proposal |
context, proposal triple, durable request_key, title, body |
POST .../{grant_id}/issues |
get_agent_work_submission |
context and the same request_key |
GET .../{grant_id}/submissions/{request_key} |
The proposal triple is scalar: proposal_schema="agent_work_grant.v1",
proposal_version=1 (JSON integer), and the native lowercase 64-hex
proposal_digest. The client must repeat the read proposal exactly. It does
not supply the server's mutable CAS state_revision. IDs are positive native
signed 64-bit integers, not names, booleans or numeric strings. Request keys
are canonical lowercase UUIDv4 strings, safely escaped as a complete path
segment for readback. The adapter never generates or replaces one.
The only submission fields sent to Core are the triple plus
request_key/title/body. Unknown inputs, including human authorization,
caller-defined issuer/agent IDs, sponsorship, scope changes or a claimed
approval, are refused before upstream work. The current request bearer takes
precedence over process configuration; stdio retains its existing own-token
or Basic-auth configuration. No human browser credential is forwarded.
Core rechecks the actual native bot, selected grant, current repository
permissions and credential scope/resource reducer. Confirm/submission require
read:repository and write:issue, including the bot's existing code/issue
reads. No read:user scope is added by this adapter. Preparing a grant is not
approval; bot confirmation is not human approval. Human preparation, review,
approval and withdrawal remain native browser-session operations. Missing
private access is an explicit collaboration prerequisite, never an implicit
membership or credential grant.
Native results and uncertain delivery
Single-grant tools return the complete native grant plus native_status.
Submit/readback return native {grant,submission} plus native_status.
Core's native participant/repository/Issue IDs and submission status are
validated for consistency; requested owner/repo or caller text never invents
missing attribution. New submission is HTTP201; a matching committed replay
is HTTP200. The adapter sends each POST once and has no write retry/fallback.
HTTP400/401/403/404/409 retain their native meaning in bounded MCP errors.
No redirect is followed. Raw upstream error bodies, Location headers, malformed
protocol bytes and reflected credentials are not exposed. Malformed/incomplete
success responses do not publish a receipt. A lost response, unexpected status
or malformed write response leaves delivery uncertain: read back the same
owner/repo/grant/key with get_agent_work_submission. Do not infer failure,
generate a new key or automatically submit again. For uncertain confirmation,
read the grant before deciding whether the identical confirmation is needed.
Local input/credential/budget refusal happens before a native request.
Native receipts retain historical Issue ID/index/URL with outcomes submitted,
issue_deleted or issue_binding_changed. A deleted Issue does not make its
key available again. Withdrawal prevents new grant operations while an
authorized receipt read can still reconcile a prior commit. A receipt remains
review_state="awaiting_review"; it is not human result acceptance. Native
Issue/API/list verified attribution is Core-owned; ordinary API/MCP/Git activity
does not gain an assignment marker.
Title/body and native task/summary text remain whole strict UTF-8, without a new gateway text cap, excerpt or replacement. Existing native validation, gateway budgets, the remote MCP 1MiB request-body limit and the existing native client socket timeout still apply. This adapter does not remove those transport bounds or promise that every large request is accepted.
Discovery and acceptance
List requests ask Core for limit=30 and one positive page. Omit state for
the native nonrevoked default, or use awaiting_agent, awaiting_human,
active, revoked or all. Continue with next_page until has_more=false.
Native total/Link relations determine continuation even if Core clamps the
width. Link addresses are never followed; each page makes a fresh fixed-origin
authenticated request. Pages are current observations (snapshot=false).
There is no cursor, grant cache or atomic-list claim.
test_agent_work_grants.py uses real loopback HTTP and MCP dispatch, normally
and under -O: strict inputs, credential choice, native errors, redirect
refusal, complete text, pagination, malformed/lost responses, same-key readback,
no hidden repeated write, receipt consistency and unchanged public four tools.
The required full scripts/e2e-local.sh invokes
test_agent_work_grants_native.py on a fresh isolated stack with the tested
Core image. Actual native HTML forms and session nonces prepare/approve/withdraw;
real native bots call authenticated HTTP MCP. Separate setup privilege creates
fixtures/deletes the Issue and never enters the MCP child. The fixture exercises
31 pending grants across real pages, full Issue body/actor readback, wrong bot
and scope, ordinary unassigned activity, same-key replay/deletion tombstone,
withdrawal, independent grants and current access loss. Core's separate real
browser and SQLite/PostgreSQL gates remain required. Tests and source do not
constitute runtime admission. See the runbook.