picatz / picatz/flowstate

Design: git, vcs and forge plugins — precise where it can be, portable where it should be

Open
#149 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

design enhancement kind/design-record
Dominant language
Go
Stars
9
Forks
0
Avg merge
3h 3m
Merged PRs (30d)
509

Description

#148 shipped vcs.log/vcs.diff on go-git and github.pull_request_get/github.issue_comment on go-github. Two things about it are wrong or too narrow, and unwinding them properly is worth doing before the ecosystem grows around the mistakes.

1. vcs alone is the wrong shape — there should be both

Someone reaching for version control types git. Naming the only implementation vcs makes the common case discover the abstraction rather than the tool, and it forces git's own vocabulary — refs, objects, trees, packfiles, notes, submodules, worktrees — through a lowest-common-denominator vocabulary that cannot express it. That is precisely the Backstage failure the research found: an integration interface that works for the universal operations and sends everyone around it for the ones that matter.

Proposal: three plugins, three honest scopes.

Plugin Provides Character
git git.* Rich, precise, idiomatic git. Git's own nouns, no apology for being git-specific. This is what people look for.
vcs vcs.* A small portable core — the handful of verbs that survive git → jj → hg honestly. Deliberately not comprehensive.
github github.* The forge. A gitlab, gitea or forgejo plugin is a peer, not a subclass.

This respects the schema's unforgeable-prefix rule (a plugin's qualifier comes from discovery, never from self-declaration) rather than fighting it: three prefixes means three binaries, which is exactly what the rule wants.

vcs being backed by go-git today and by jj tomorrow is binary substitution by an operator, not runtime task-name resolution. That is a much weaker and entirely legitimate form of the indirection previously rejected: nothing about a Flowfile's meaning depends on which binary is installed, because vcs.log means the portable thing either way.

What vcs.* may promise (must survive jj, which has no index and no stable commit-hash identity): vcs.log, vcs.diff, vcs.show, vcs.refs. Not vcs.stage, not vcs.rebase — jj's conflict model makes the latter a different operation with the same name.

What git.* should grow, precisely because it need not be portable: git.clone, git.fetch, git.checkout, git.commit, git.tag, git.push, git.merge_base, git.blame, git.ls_tree, git.rev_parse, git.submodule.*, git.notes.*. Each with git's semantics, not an approximation of them.

2. In-memory-only does not scale — see the corrected rule in #145

Every clone in #148 is in-memory, which caps the plugin at what fits in a worker's RAM. #145's rule has been corrected: the danger is shared storage, not disk. Disk scoped to one activity invocation and destroyed on return is fine and is how scale gets served. A task's result stays content, never a path.

Consequences to design for:

  • Prefer not cloning at all. github.compare answers "what changed between these commits" without fetching a repository. When a forge can answer, that path should be preferred and documented as preferred.
  • Partial by default. Shallow, single-ref, blobless. Most operations need a fraction of the history, and the default should reflect that rather than making every caller opt out of a full clone.
  • Bounded by bytes, objects, depth and time — a repository is attacker-chosen input.
  • Heartbeat and honour cancellation. A clone is the archetypal long activity; v1.ReportProgress exists now, and heartbeats are how a cancellation reaches a running activity at all.
  • Retry hygiene. A fresh attempt gets a fresh directory. Never the previous attempt's tree.

3. GitHub auth needs to be genuinely complete

#148 has App-or-PAT. The full set worth supporting, in preference order, with the argument for the order written down:

  1. Workload identity federation → scoped installation token. Flowstate already exchanges its workload identity for short-lived credentials. An App installation token minted per run and scoped down to the repositories that run needs is the least-privilege end state, and strictly better than any stored credential.
  2. GitHub App — private key as a secret reference, JWT → installation token, cached for its lifetime. Note that installation tokens can be narrowed at mint time; take that.
  3. Fine-grained PAT, then classic PAT — supported because it is what people have, documented as the weakest.
  4. GitHub Enterprise Server base URLs, still governed by netpolicy rather than becoming a hole around it.

4. Fitting together

The composition to make work end to end, because it is the one everybody actually wants:

- id: changes
  github.compare: { base: ${inputs.base}, head: ${inputs.head} }

- id: review
  call: ./review.yaml
  with: { files: ${steps.changes.files} }

- id: comment
  github.issue_comment: { body: ${steps.review.summary} }

Note it needs no clone at all — which is the point.

Open questions

  • Does vcs earn its existence before a second backend exists? A case can be made for shipping git alone first and adding vcs when jj arrives, so the portable core is designed against two real implementations rather than one and a guess.
  • Does git.commit/git.push belong at all, given a result must be content rather than a path? Probably yes, as a single task that materialises, commits and pushes within one invocation — but that is a design, not an obvious extension.

Blocked on nothing; the reasoning above should be argued before code.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the implementations delivered in #148 and the corrected storage rule in #145, then trace v1.ReportProgress and netpolicy integration points. Compare the proposed git, vcs, and github boundaries, clone behavior, authentication options, and end-to-end composition. Done means the open design questions have settled scope, semantics, constraints, and an implementation plan.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, github, go
Domain
backend-api-design, devtools, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.