FG

Fancy Git

Git as a first-class, agent-driveable surface — a headless engine with proposal-first mutations, normalized provider adapters for GitHub / GitLab / Bitbucket, and a React UI. Mirrored in PHP and Node.

Poly9 packages · one productPHPNode / TypeScriptReact

Everything in this family ships against one shared contract — install only the pieces your stack needs. Language mirrors behave identically, so you pick your backend and get the same product.

Engine

Local Git + GitHub / GitLab / Bitbucket collaboration

PHPPHP
particle-academy/fancy-git
$composer require particle-academy/fancy-git

Framework-agnostic PHP Git engine with normalized provider contracts and proposal-first mutations.

TSNode / TypeScript
@particle-academy/fancy-git
$npm install @particle-academy/fancy-git

Node/TypeScript Git engine and normalized GitHub, GitLab, and Bitbucket provider contracts.

React UI

TSReact8 components
@particle-academy/fancy-git-ui
$npm install @particle-academy/fancy-git-ui

Controlled Human+ React surfaces for repositories, working trees, diffs, commits, branches, and pull/merge requests.

GitHub provider

GitHub.com / GitHub Enterprise provider adapter

PHPPHP
particle-academy/fancy-git-github
$composer require particle-academy/fancy-git-github

GitHub.com and GitHub Enterprise adapter for particle-academy/fancy-git.

TSNode / TypeScript
@particle-academy/fancy-git-github
$npm install @particle-academy/fancy-git-github

GitHub.com and GitHub Enterprise adapter for @particle-academy/fancy-git.

GitLab provider

GitLab.com / Self-Managed provider adapter

PHPPHP
particle-academy/fancy-git-gitlab
$composer require particle-academy/fancy-git-gitlab

GitLab.com and Self-Managed adapter for particle-academy/fancy-git.

TSNode / TypeScript
@particle-academy/fancy-git-gitlab
$npm install @particle-academy/fancy-git-gitlab

GitLab.com and GitLab Self-Managed adapter for @particle-academy/fancy-git.

Bitbucket provider

Bitbucket Cloud provider adapter

PHPPHP
particle-academy/fancy-git-bitbucket
$composer require particle-academy/fancy-git-bitbucket

Bitbucket Cloud adapter for particle-academy/fancy-git.

TSNode / TypeScript
@particle-academy/fancy-git-bitbucket
$npm install @particle-academy/fancy-git-bitbucket

Bitbucket Cloud adapter for @particle-academy/fancy-git.

Why
Anything that automates Git ends up writing the same two layers twice. First a shell of exec('git status --porcelain') calls with hand-rolled parsing, which works until a path has a space in it or the porcelain format shifts. Then, separately, a REST client per host — because GitHub calls it a pull request, GitLab a merge request, and Bitbucket a pull request with an entirely different payload — so supporting a second host means writing the feature again. fancy-git is that work done once, in two languages: local operations over the installed git binary, and a provider-neutral contract for the hosted side, so one code path serves GitHub, GitLab and Bitbucket.

It is also built for Human+ UX, and that shows up as a design constraint rather than a feature: every mutation takes a propose flag. Called with it, the operation returns an OperationProposal describing exactly what it would run instead of running it. An agent can therefore stage, branch, or push through the same API a human uses, and a human confirms before anything touches the repository — trust-but-verify in the contract, not bolted on by the caller.
What
The family is nine packages in a deliberate shape: a matched PHP + TypeScript core, a React UI, and a per-host adapter pair.

The engineparticle-academy/fancy-git (PHP) and @particle-academy/fancy-git (TypeScript) are twins, not a port and an afterthought. Both expose a GitRepository over the installed binary: info(), status(), log(), diff(), branches(), and the mutations stage() / unstage() / checkout() / fetch() / pull() / push(), each taking that propose flag. Invocation goes through a process runner (Symfony Process on PHP), never a shell string, so a branch named --upload-pack=… is an argument rather than an injection.

The hosted contractGitProvider normalises the three hosts to one vocabulary: repository(), listReviews(), getReview(), createReview(), compare(), checks(). A pull request and a merge request are both a Review, with the host's extras preserved under extensions rather than flattened away. Adapters register on a ProviderRegistry, and identify() maps a remote URL back to the provider that owns it — so code written against the contract works on a host it has never seen.

The adapters — six packages, one pair per host: fancy-git-github-{php,js}, fancy-git-gitlab-{php,js}, fancy-git-bitbucket-{php,js}. You install only the hosts you actually talk to; the core carries no HTTP client for the other two.

The surface@particle-academy/fancy-git-ui ships eight controlled React components over that data: <RepositoryBrowser>, <WorkingTree>, <CommitHistory>, <DiffViewer>, <BranchPicker>, <ReviewList>, <CommitComposer> and <CreateReviewForm>. Every one is fully controlled and provider-neutral — it renders what you pass and emits intents, holding no Git state of its own, which is what lets an agent drive the same surface a person is looking at.
How
Pick the runtime that executes your workflow, then add the hosts you use. On PHP: composer require particle-academy/fancy-git particle-academy/fancy-git-github. On Node: npm install @particle-academy/fancy-git @particle-academy/fancy-git-github. The React surface is additional and orthogonal — npm install @particle-academy/fancy-git-ui — because a Laravel app still renders its editor in a browser.

Local operations read the same on both sides: $repository = new GitRepository(base_path()); $status = $repository->status(); in PHP, const status = await new GitRepository(process.cwd()).status() in TypeScript. To let an agent act without letting it act unsupervised, pass the flag: $repository->push(propose: true) returns an OperationProposal you can render for a human to approve, then re-run without it once they do.

For the hosted side, register the adapters you installed and let the remote choose: $registry = (new ProviderRegistry)->register(new GitHubProvider($token)); [$provider, $ref] = $registry->identify($remote); — from there $provider->listReviews($ref) is the same call whether that remote points at GitHub, GitLab or Bitbucket. And if you would rather drive all of this from a workflow than from code, the marketplace ships five PR-lifecycle nodes built on exactly this contract: npx fancy-cli add node @particle-academy/git_pr_open.
readmeShared model & API — README.md

Fancy Git for PHP

Framework-agnostic local Git operations and normalized provider contracts.

use FancyGit\GitRepository;

$repository = new GitRepository(getcwd());
$status = $repository->status();

The core uses Symfony Process for safe, portable invocation of the installed Git binary. GitHub, GitLab, and Bitbucket clients live in separate adapter packages.