Two sources
A Git Project resolves through a Connection: Checkfu reads the repository using the acting Principal’s authorized provider identity and never handles a raw provider token.
acted_as must own and hold use_connection on that Connection.
Immutable revisions
You never edit a Project in place. Every change produces a new immutable revision:- An uploaded Project gets a new revision when you push new
files(withexpected_versionfor optimistic concurrency). - A Git Project gets a new revision when you
POST /v1/projects/{id}/refresh, which re-resolves therefto an exact commit and records thecommit_sha(and tree).
Create and refresh a Git Project
Create the Project with the Principal that owns the GitHub Connection:latest_revision: 1
and version: 2: the revision counter and the resource version are separate, and publishing that
first revision already moved the version. Read GET /v1/projects/{id}/revisions/1 for its exact
commit and tree. When the ref advances, refresh with the Project’s current version:
expected_version fails with 409; read the Project again
before retrying. If the ref still identifies the recorded commit and tree, refresh also returns a
conflict rather than creating a duplicate revision.
Use GET /v1/projects/{id}/revisions/{revision} for the exact revision and
GET /v1/projects/{id}/revisions/{revision}/tree for its ordered file metadata. The public
/file body endpoint serves uploaded revisions only. Git bodies stay behind the live Run lease so
each read can re-check Connection authority and integrity immediately before staging.
latest, a pinned revision, or a published Git ref
A Session mounts a Project with latest, a pinned revision, or a Git ref policy. This is one half of the platform’s two freeze horizons:
latestre-resolves to whatever the newest revision is at the start of each Run, and is fixed for that Run. Refresh the Git Project between Runs and the next Run picks up the new commit.pinnedlocks one revision for the Session’s life, regardless of later refreshes.refselects the newest immutable revision already published for that exact Git ref. It performs no provider I/O during Run preflight and fails closed when no such revision exists.
session.mounts_resolved.
Repository Skills
At the same Run boundary, an eligible Git mount inspects exactly.claude/skills/<name>/SKILL.md in that frozen revision. Valid manifests use
the same Agent Skills parser as catalog Skills, but they remain repository
content at their mounted paths: Checkfu creates no Skill aggregate or release
pin. Duplicate names remain available by path. Nested, rootless, package-local,
malformed, and name-mismatched entries are not announced.
When the Agent has the built-in read tool, Checkfu stages a read-only index at
/environment/.checkfu/repository-skills.md and adds a bounded pointer to it.
Without read, the pointer is omitted. Treat mounting as a trust decision:
repository Skills are instruction input and may include contributions from
people outside your organization.
Writable overlays and opt-in pull-request writeback
A mount isread_only or read_write, but even read_write does not mutate the Project. Runtime writes land in a disposable sandbox overlay: they exist for that Run and vanish with the sandbox. Publishing a new uploaded revision or pushing a Git tree is a separate, explicit, governed action.
For a Git-backed Project under standard retention, a read_write mount can opt into Session-owned
publication with writeback: { "kind": "pull_request" }. Checkfu captures the complete delta at
Run settlement, closes the sandbox, and reconciles it without holding compute: one
platform-derived branch, non-force exact-head updates, one pull request, and one immutable branch
revision selected only by that Session mount. A missing policy remains byte-for-byte the
disposable-overlay behavior; uploaded Projects and ZDR reject writeback.
The policy accepts bounded static commit_message, pull_request_title, and
pull_request_body overrides. Omitted values use deterministic platform defaults; an omitted body
uses a bounded default PR template from .github/, the repository root, or docs/ at the frozen
target ref when one is present. Provider credentials, hidden reasoning, and event history never
enter the commit or PR body.
Standard interactive Sessions attach one reusable Watch after the PR’s fresh baseline is known,
so external comments, reviews, and checks can wake the same Session and the next writeback can
advance the same branch and PR. D127 still excludes Automation-owned Sessions
from Watch-driven runs; their writeback produces the PR receipt without claiming an unsupported
feedback wake.
Write back to Git
A Git Project is not read-only. Two governed endpoints turn a tree you have staged into a branch and then a pull request, through the same Connection thatrefresh reads with. Checkfu still never handles a raw provider token, and acted_as must own the Connection and hold use_connection.
POST /v1/projects/{id}/push writes one commit and returns 201 with the new branch, its commit_sha, the base_revision and base_commit_sha it was built on, plus file_count and total_bytes. POST /v1/projects/{id}/pull-requests then takes head, base, title, and an optional body, and returns the pull request number and url. Provider validation refusals (no commits between the two branches, or a pull request already open for them) come back as a reasoned 409 validation.conflict. The merge itself stays human.
Both calls require Idempotency-Key. Retry an interrupted response with the same key and the identical request: after the live lease expires, Checkfu returns the retained provider result without repeating the push or opening a second pull request.
Three rules make the write safe to automate:
base_revisionis a compare-and-swap. It names an immutable revision of this Project, and that revision’s exact commit must still head the Project’s sourceref. If the ref moved, the push refuses with409 validation.conflictrather than silently dropping the newer work. Refresh, rebuild the tree on the new revision, and push again.- A push only ever creates a branch. It never force-pushes and never updates an existing one, so a replayed push cannot overwrite a colleague’s branch. The destination ref is checked before any blob is uploaded, so a name collision fails early with
409 validation.conflictinstead of after the whole tree is written. - Neither call touches the Project. The source ref is never advanced, no revision is published, and the Project’s
versiondoes not move. Adoption stays a human merge plus an explicitrefresh. Each success appends one audit fact (project.pushedorproject.pull_request_opened) that records coordinates, never file bodies.
Because a push stores no file bodies (the tree streams to the provider and Checkfu retains only
coordinates and hashes), it works in a zero-data-retention Workspace, where publishing an uploaded
revision does not.
Managed runs materialize both uploaded and Git Project revisions through a credential-free,
integrity-checked handoff. A Git plan contains the pinned commit, tree, and ordered blob
locators, not a provider credential. The API re-checks the live Connection PermissionAssignment for each
lease-fenced blob read, and both the API and Runner verify its Git digest and byte count before
staging it.
Next steps
Sessions and runs
How a mount resolves per Run, and the two freeze horizons.
Capabilities
The Connection a Git Project reads through.