# Gito Control Plane Contract Candidates ## Transport Policy - External provider and consumer integrations use REST APIs and HTTP webhook/callback delivery. Gito should feel compatible with GitHub/GitLab/Gitea webhook integration patterns rather than requiring a Gito-specific binary client. - proto-socket is internal-only control/runtime transport. It is not an external provider, consumer, IOP, or fallback integration contract. - REST remains for health/readiness, provider callbacks, external webhook delivery, smoke/curl, and simple bootstrap endpoints. - gRPC is excluded from the first design. ## Internal proto-socket Channels These channels describe Gito-internal control/runtime surfaces. They must not be used as the canonical contract for external consumers or sibling projects. | Channel | Purpose | | --- | --- | | `repo` | Register, inspect, and list managed repositories. | | `workspace` | Lease, release, and inspect workspace slots. | | `operation` | Create, cancel, inspect, and stream operations. | | `git` | Request platformless Git operations. | | `change_request` | Manage provider-neutral PR/MR operations. | | `agent_shell` | Reserved/legacy shell scaffold metadata; canonical agent UI is `../agent-shell` and backend/runtime is `../iop`. | | `event` | Internal subscription/projection of normalized events. | ## Internal proto-socket Action Registry Scaffold The first internal proto-socket surface exposes channel/action registry metadata before real command execution. Every listed action starts as `placeholder` until its own Milestone wires storage, worker, or provider behavior. | Channel | Placeholder actions | | --- | --- | | `repo` | `register`, `get`, `list` | | `workspace` | `lease`, `release`, `get` | | `operation` | `create`, `cancel`, `get`, `stream` | | `git` | `clone`, `fetch`, `status`, `diff`, `commit`, `push` | | `change_request` | `create`, `update`, `comment`, `request_review`, `merge`, `close`, `list` | | `agent_shell` | `heartbeat`, `dispatch`, `stream_logs` remain placeholder-only until an explicit compatibility Milestone scopes them. | | `event` | `subscribe`, `list`, `ack` | ## REST Bootstrap Exceptions REST is the canonical external surface for provider callbacks, public APIs, and webhook delivery. Temporary repo bootstrap helpers for smoke/curl setup may exist while richer operation APIs are still placeholder-only. Those helpers must stay limited to bootstrap registration, lookup, and listing, and must use the same Repo DTO fields documented below. ## Agent Shell / IOP Boundary `../agent-shell` is the product-agnostic Flutter package for agent interaction UI and domain models. It is not the Gito backend. Hosts that use that package should depend on it as `agent_shell: path: ../agent-shell` and route agent runtime/backend behavior through the sibling `../iop` project. Gito's responsibility is the Git control plane boundary: repository registry, workspace leases, operations, revision events, durable event records, and provider-neutral Git results. IOP owns agent execution, shell command execution, model/runtime routing, command policy, cancellation, and log redaction source of truth. Gito may persist IOP results only after they are expressed as operation state, Git revision/diff, workspace lease state, or normalized event records. The IOP bridge below keeps the payload fields transport-neutral, while the external IOP connection shape is HTTP dispatch/callback. It does not choose the concrete IOP CLI command, profile/model, stdin/input-file shape, or secret injection mechanism. proto-socket is not part of the IOP contract. ## IOP Agent Run Bridge Gito creates and owns an `agent_run` Operation, then hands execution intent to IOP through an adapter boundary. Gito must not execute the IOP CLI or arbitrary workspace commands directly. IOP may run through CLI, Edge, Node, or another runtime, but Gito only records the result once it is expressed as operation state, Git workspace evidence, or normalized event records. The preferred external shape is GitHub-like webhook/callback: Gito sends an agent run intent to an IOP HTTP endpoint or registered runtime adapter, and IOP posts sanitized state/result updates back to a Gito callback endpoint. ### AgentRunInput | Field | Meaning | | --- | --- | | `operation_id` | Existing Gito operation id with `type=agent_run`. | | `repo` | Repo snapshot containing `id`, `remote_url`, `default_branch`, and optional `credential_ref`; raw credential values are forbidden. | | `branch` | Branch checked out in the leased workspace. | | `workspace_path` | Absolute path of the leased workspace slot that IOP may use. | | `instruction` | User or automation instruction text for the run. | | `policy_context` | JSON object with Gito-known policy context, approvals, and allowed result actions; IOP remains source of truth for command policy decisions. See policy keys below. | | `expected_revision` | Optional workspace HEAD before IOP starts, used later for revision diff checks. | | `credential_refs` | Optional list or map of credential references. Values point to secrets outside tracked contracts and logs. | | `result_callback` | Optional HTTP callback descriptor for IOP state/result delivery. Raw callback secrets are forbidden; use `credential_ref` or `secret_ref` references only. | #### policy_context Keys Transport-independent keys Gito reads from `policy_context`. IOP may add its own keys; Gito ignores unknown ones. | Key | Type | Meaning | | --- | --- | --- | | `commit_push` | boolean | `true` to allow Gito to commit and push after a successful agent run. | | `allowed_result_actions` | string array | Alternative form; presence of `"commit_push"` in the list enables commit and push. | | `commit_message` | string | Commit message to use when commit/push is allowed. Defaults to `"agent run result: "`. | | `remote` | string | Git remote name for push. Defaults to `"origin"`. | | `branch` | string | Branch to push. Defaults to `AgentRunInput.branch`. | Raw credential values must not appear in `policy_context`. When commit/push is allowed, Gito uses the credential environment already present in the workspace; it does not inject secrets from `policy_context`. ### AgentRunState Mapping | IOP run state | Gito operation lifecycle | | --- | --- | | `queued` | Operation exists as `queued`; IOP execution has not been accepted yet. | | `running` | Operation moves to `running`; Gito may append `operation.started` and `agent.run.started` records. | | `succeeded` | IOP reports successful execution. Gito marks `succeeded` only after the Git result confirmation step accepts workspace status and revision evidence. | | `failed` | Operation moves to `failed`; Gito records sanitized failure context without raw logs or secrets. | | `cancelled` | Operation moves to terminal `cancelled`; cancellation policy/event details belong to the command policy and cancellation Milestone. | Structured IOP output is advisory. The success source of truth for this bridge is the Git workspace after the run: status, before/after revision, changed files, and any later commit/push result allowed by policy. When a policy-allowed push is completed, Gito triggers a revision scan to detect the newly updated revision and emit the corresponding branch update event. The results are recorded in the operation completion payload: - `revision_scan_attempted` (boolean): `true` if a revision scan was triggered after a successful push. - `revision_event_matched` (boolean): `true` if the scanner matched the new revision and successfully generated/published the event. - `revision_event_id` (string, optional): The ID of the generated revision event if matched. If the scan fails, the operation moves to `failed` and a sanitized scan error message is recorded. ## MVP: Forgejo Branch Event Flow Forgejo branch event delivery is now a provided contract: `agent-contract/provided/gito-forgejo-branch-events-v1.md`. Read that contract when working on Forgejo webhook intake, `branch.updated` events, outbound HTTP webhook delivery, NomadCode branch event wakeups, or the `/callbacks/forgejo/push`, `/api/listeners/branches`, and webhook subscription surfaces. This note keeps only the internal proto-socket channel registry and DTO candidate overview. ## Core DTO Candidates ### Repo | Field | Meaning | | --- | --- | | `id` | Stable Gito repo id. | | `name` | Display name. | | `remote_url` | Git remote URL. | | `default_branch` | Default source-of-truth branch. | | `workspace_root` | Local workspace root for slots. | | `credential_ref` | Reference to credentials, never the raw secret. | ### WorkspaceLease | Field | Meaning | | --- | --- | | `id` | Lease id. | | `repo_id` | Managed repo id. | | `slot` | Zero-padded slot index. | | `path` | Local workspace path. | | `state` | `available`, `leased`, `dirty`, or `error`. | | `expires_at` | Optional lease expiry. | ### Operation | Field | Meaning | | --- | --- | | `id` | Operation id. | | `repo_id` | Target repo. | | `type` | `clone`, `fetch`, `commit`, `push`, `agent_run`, etc. | | `state` | `queued`, `running`, `succeeded`, `failed`, `cancelled`. | | `idempotency_key` | Duplicate guard. | | `created_by` | Actor id or system source. | ### RevisionEvent | Field | Meaning | | --- | --- | | `repo_id` | Target repo. | | `branch` | Branch name. | | `before` | Previous revision. | | `after` | New revision. | | `changed_files` | Changed file paths and change types. | | `observed_at` | Observation timestamp. | ### ChangeRequest Provider-neutral abstraction for GitHub PR, GitLab MR, Gitea PR, and similar platform features. | Field | Meaning | | --- | --- | | `provider` | `github`, `gitlab`, `gitea`, etc. | | `external_id` | Provider PR/MR id. | | `repo_id` | Target repo. | | `source_branch` | Source branch. | | `target_branch` | Target branch. | | `title` | Provider-neutral title. | | `body` | Provider-neutral body or description. | | `draft` | Boolean draft marker; draft is orthogonal to lifecycle state. | | `state` | Lifecycle state: `open`, `merged`, or `closed`. | ### ChangeRequest Actions Provider adapters expose a provider-neutral action set before mapping to provider-specific PR/MR APIs. | Action | Meaning | | --- | --- | | `create` | Create a PR/MR-like object from source branch, target branch, title, body, and draft state. | | `update` | Update mutable title, body, draft state, or target branch fields. | | `comment` | Add a comment body to an existing change request. | | `request_review` | Request individual or team review by provider-neutral reviewer identifiers. | | `merge` | Merge the change request with optional commit title/message metadata. | | `close` | Close the change request without merging. | ### ChangeRequest Provider Mapping Boundary Provider-specific PR/MR fields stay behind `services/core/internal/provider` mapping candidates and adapter implementations. The common `ChangeRequest` DTO contains only the fields listed above; provider-only metadata such as merge method, repository fork metadata, detailed merge status, labels, milestones, and review-provider details stays outside the common DTO until a later milestone promotes a field into the transport-independent model. ## Normalized Events Durable event records use a stable envelope: | Field | Meaning | | --- | --- | | `id` | Stable event id generated by Gito. | | `type` | Normalized event name from the table below. | | `subject` | Entity anchor such as `operation:` or `repo:`. | | `payload` | JSON object encoded as `application/json`; raw provider secrets and credential values are forbidden. | | `created_at` | Time Gito recorded the event. | | Event | Meaning | | --- | --- | | `repo.changed` | Repo registry changed. | | `branch.updated` | Watched branch revision changed, initially from Forgejo push webhooks or future revision scans. | | `workspace.leased` | Workspace lease acquired. | | `workspace.released` | Workspace lease released. | | `workspace.dirty` | Workspace has uncommitted changes. | | `operation.started` | Operation execution started. | | `operation.completed` | Operation succeeded. | | `operation.failed` | Operation failed. | | `agent.run.started` | Agent execution started. | | `agent.run.completed` | Agent execution completed. | | `change_request.opened` | PR/MR-like object opened. | | `change_request.updated` | PR/MR-like object changed. | | `change_request.merged` | PR/MR-like object merged. | | `change_request.closed` | PR/MR-like object closed without merge. | | `provider.webhook.received` | Provider webhook received. | ### Operation Event Payloads Operation lifecycle events are stored in the outbox as normalized event records with `subject=operation:`. | Event | Required payload fields | | --- | --- | | `operation.started` | `operation_id`, `repo_id`, `type`, `state`, `started_at` | | `operation.completed` | `operation_id`, `repo_id`, `type`, `state`, `completed_at` | | `operation.failed` | `operation_id`, `repo_id`, `type`, `state`, `failed_at`, optional `error` | ### Outbox Storage Contract - PostgreSQL is the source of truth for durable events. - Stored payloads are JSON objects and map to `events.Event.Payload` with `events.PayloadEncodingJSON`. - Outbox readers list events in `(created_at, id)` order. - Publish retry state belongs to the outbox/webhook delivery boundary; Redis, if added later, only accelerates fanout. ### External Webhook Delivery - Registered consumers provide an HTTP endpoint, accepted event types, optional repo/branch filters, and a `secret_ref` for delivery signing. - Gito delivers normalized events as JSON over HTTP POST. The body uses the durable event envelope and payload fields, without provider secrets or raw credential values. - Delivery headers include event type, delivery id, and an HMAC signature when a signing secret is configured. - Consumers treat webhook deliveries as wakeup signals and verify final state through Git revision scans or provider read APIs before mutating their own source-of-truth state. - Delivery idempotency, retry/backoff, and failed delivery state belong to the webhook delivery worker, backed by PostgreSQL. ### Internal proto-socket Event Projection - Stored `type` may map to proto-socket `action` on the internal `event` channel for Gito-owned control/runtime consumers. - Stored `payload` maps to the proto-socket envelope `payload` object without provider secrets or credential values. - This projection is internal-only and must not be documented as an external consumer integration path.