Project
Planning and decision records live here so the runtime documentation stays focused on how git-pont works.
Planning
Records
Decision records are intentionally separate from runtime documentation.
Implementation Plan
This plan is intended for another implementation agent. Keep commits small and test each layer before adding providers. The canonical API is in Architecture and Provider Model.
Phase 0: Platform Contract Hygiene
- Treat the Swift Package as the Swift library, not as the only possible
git-pontimplementation. - Keep core model names, enum raw values, and error cases portable to Kotlin/TypeScript-style representations.
- Keep provider fixtures JSON-compatible so future kits can reuse them.
- Avoid Apple-only types in
GitPontCoreexcept where Swift requires a standard-library/Foundation representation such asURL,Data, orDate.
Done when:
- README, Decisions, Architecture, and Provider Model clearly distinguish the shared contract from the Swift library.
- v1 scope still targets Apple only.
Phase 1: Core
- Create Swift Package for the Swift library.
- Add
GitPontCore. - Define all model types from Provider Model.
- Define
GitProvider,HTTPClient,CredentialStore,ConnectionStore,RetryPolicy, andGitPontError. - Define
GitAuthenticationProvider, OAuth start/completion models, and refresh contracts. - Add
InMemoryCredentialStore,InMemoryConnectionStore, andFileConnectionStore. - Add URL normalization helpers (strip query/fragment/
.git, hex-ref detection, ambiguity candidate generation). - Add pagination helper (
Linkheader andx-next-pagefollower, safety cap,GitList). - Add the
GitPontfacade skeleton with connection resolution rules. - Keep Git CLI methods out of the core facade implementation; they are added later by
GitPontGitCLI. - Add path safety validation (traversal, absolute paths, control characters, empty message).
- Add test fixture helpers and
MockHTTPClient. - Add model, URL parser, pagination, and safety tests.
Done when:
- Package builds.
- Core tests pass.
- No provider modules yet.
Phase 2: GitHub
- Add
GitPontGitHub. - Implement GitHub URL parser (blob, raw, tree, repo, permalink, ambiguous refs).
- Implement account validation (
GET /user). - Implement provider construction with explicit instance registration.
- Implement GitHub device-flow start/complete where
OAuthAppConfigis provided. - Implement repository list/get with permission mapping, branch list.
- Implement file read (including >1 MB blob fallback), directory list.
- Implement file commit and delete with
shaconflict protection. - Implement branch create, repository create, fork create (with readiness polling).
- Implement pull request create (same-repo and fork head).
- Implement mocked HTTP tests for all operations.
Done when:
- GitHub module has full mocked tests.
- GitHub provider supports the Lezin open/commit flow and fork+PR flow.
Phase 3: GitLab
- Add
GitPontGitLab. - Implement GitLab.com preset and self-hosted instance config (including path-prefixed base URLs).
- Implement GitLab URL parser including subgroups,
/-/raw/, ambiguous refs. - Implement account, project list/get with permission mapping, branch list.
- Implement provider construction with GitLab.com and explicit self-hosted instance registration.
- Implement Repository Files API read/update/create/delete with
last_commit_id, plus the follow-up read that populatesnewVersion. - Implement tree (directory) listing.
- Implement branch create, project create, fork (with
import_statuspolling). - Implement merge request create (same-project and fork with
target_project_id). - Add tests for GitLab.com and self-hosted URLs.
Done when:
- GitLab provider supports file open/commit/delete and MR creation including fork MRs.
- Self-hosted URL parsing works without hardcoded host assumptions.
Phase 4: Forgejo and Gitea
- Add
GitPontForge. - Add the Codeberg preset instance (kind
.forgejo). - Add custom Forgejo/Gitea instance support.
- Implement provider construction with Codeberg and explicit custom instance registration.
- Implement URL parser for
/src/branch/...,/src/commit/...,/raw/branch/.... - Implement account, repo list/get, branch list.
- Implement file read/write/delete using contents APIs (
sharequired on update/delete). - Implement directory listing.
- Implement branch create, repository create, fork create.
- Implement pull request creation (same-repo and fork head).
- Add version variance handling: map missing endpoints to
.unsupportedCapability.
Done when:
- Codeberg preset works in tests.
- Custom Forgejo/Gitea instances are configured explicitly.
Phase 5: Auth, Refresh, and Keychain
- Add provider-neutral auth abstractions and injected
OAuthAppConfig. - Add PAT/token setup support for all providers.
- Add GitHub device flow.
- Add OAuth PKCE for GitLab (access tokens expire in ~2h — refresh is required, not optional) and Forgejo/Gitea where configured.
- Implement
GitAuthenticationProvider.refreshCredentialfor OAuth providers and.unsupportedCapabilityfor unsupported refresh cases. - Implement per-connection refresh serialization (actor) with store-before-release semantics.
- Add
GitPontKeychain. - Add refresh race tests and Keychain tests where feasible.
Done when:
- Apps can store/reuse connections without handling tokens directly.
- A GitLab OAuth connection survives past token expiry in tests.
Phase 6: Change Submission
- Implement
submitChangeon the facade:.directCommit,.branchAndPullRequest,.forkAndPullRequest,.automatic. - Implement permission-based strategy selection for
.automatic. - Implement fork reuse detection and readiness polling.
- Implement
.partialSubmissionerror reporting. - Add orchestration tests per provider (mocked).
Done when:
- Lezin can save a file it cannot push to, via fork + PR, in a single call.
Phase 7: Git CLI Credentials
- Add
GitPontGitCLI. - Add
GitCLICredentialContextinGitPontGitCLIand exposegitCredentialContextthrough a Swift extension onGitPont. - Resolve credentials for HTTPS remote URLs (normalize, match instance, resolve connection with
preferredConnectionID). - Refresh expiring tokens before building the context.
- Return provider-specific credential helper config and environment.
- Add tests that token values never appear in arguments.
Done when:
- GitFolder can replace its GitHub-only token plumbing with GitPont credential context.
Phase 8: App Integration Guides
- Add small sample integrations for Lezin and GitFolder.
- Document migration from GitFolder
github_token. - Document connection setup UI expectations.
Suggested Commit Split
feat(core): add provider-neutral git-pont models and facadefeat(github): support file, branch, repo, fork, and pr operationsfeat(gitlab): support cloud and self-hosted instancesfeat(forge): support forgejo, gitea, and codeberg presetfeat(auth): add credential/connection stores, refresh, and keychainfeat(core): add change submission orchestrationfeat(cli): add git credential contextstest: add provider contract fixturesdocs: document lezin and gitfolder integrations
Acceptance Criteria
Use this checklist before handing git-pont to Lezin or GitFolder.
Items marked "current" are covered by the checked-in Swift package and local validation. Items marked "release" are still required before declaring v1 complete.
Package
- Current:
swift buildpasses from the root public SwiftPM manifest. - Current:
swift testpasses from the root public SwiftPM manifest. - Current:
swift build --package-path libs/swiftpasses. - Current:
swift test --package-path libs/swiftpasses. - Current:
npm run docs:buildpasses. - Current:
npm run validatepasses. - Current: public top-level types have concise documentation comments.
- Current: modules are split so apps can depend on only the providers they need.
- Current: Core has no Apple Keychain dependency.
- Current: Core has no UI framework dependency.
- Current: Core has no dependency on
GitPontGitCLI; Git CLI support is exposed by importing the Git CLI module. - Current: public API matches Architecture signatures, including provider-neutral OAuth start/complete convenience methods.
- Current: docs distinguish the shared
git-pontcontract from the v1 Apple Swift Package. - Current: repo uses the monorepo layout documented in the README.
- Current: docs site can be built from
docs/contentthroughdocs/site/girk.json. - Current: core model semantics are portable: no app-specific names, no UI framework types, no Apple-only storage assumptions in
GitPontCore. - Current: provider response fixtures use portable JSON/data files for representative read/list contract tests, so future kits can reuse the same shape.
URL Parsing
- GitHub blob/raw/tree/repo URLs parse, including commit permalinks.
- GitLab blob/raw/repo URLs parse, including subgroups and self-hosted instances.
- Codeberg/Forgejo/Gitea
src/branch,src/commit, and raw URLs parse. - Query strings, fragments (
#L10), and trailing.gitare stripped. - Slashed branch names produce
.ambiguousand resolve correctly against the branch list. - Custom hosts require explicit instance configuration.
Providers
For each of GitHub, GitLab (cloud + self-hosted), and Forgejo/Gitea (incl. Codeberg preset):
- Account validation loads the current account.
- Repository list (paginated) and repository metadata with permissions work.
- Branch list (paginated) works.
- File read works, including binary files and provider size-limit handling (
.fileTooLarge, GitHub blob fallback). - Directory listing works.
- File commit (create and update) works with version conflict protection;
newVersionis populated. - File delete works with version conflict protection.
- Branch creation works.
- Current: branch deletion works and is used by opt-in live write cleanup.
- Repository creation works.
- Current: fork creation works.
- Current: fork creation reuses an existing connected-account fork and confirms newly created forks before returning.
- Current: pull/merge request creation works, same-repo and cross-fork.
- Current: file write/delete conflict responses map to
.conflictwith populatedGitConflict.
Change Submission
- Current:
.directCommit,.branchAndPullRequest,.forkAndPullRequestwork through the provider-neutral facade. - Current:
.automaticselects direct commit, branch + PR, or fork + PR from repository permissions and branch protection. - Current: partial failures return
.partialSubmissionwith enough context to retry only the missing step.
Auth
- Current: connections store metadata only; persistence goes through
ConnectionStore. - Current: credentials are stored through
CredentialStore. - Current: in-memory stores exist for tests;
FileConnectionStoreexists for apps. - Current: Apple Keychain credential storage exists in
GitPontKeychain. - Current: PAT/token setup works for all providers.
- Current: OAuth start/complete models exist in core.
- Current: GitHub device flow works with an injected client ID.
- Current: GitLab OAuth PKCE works, and automatic refresh keeps a connection alive past the approximate two-hour token expiry.
- Current: Forgejo/Gitea browser OAuth works for configured instances.
- Current: refresh is serialized per connection and persisted before dependent requests proceed.
- Current: provider refresh hooks are covered by tests.
- Current: reactive refresh-and-retry after an unexpected provider authentication failure is implemented and tested.
- Current: multiple accounts on one instance resolve via
preferredConnectionID/.ambiguousConnection. - Current: OAuth code is isolated so apps can choose whether to use it.
Git CLI
- Current: HTTPS remote credential context works for GitHub, GitLab.com, self-hosted GitLab, and Codeberg/Forgejo/Gitea.
- Current: the credential context API is available only when importing
GitPontGitCLI. - Current: tokens do not appear in command arguments.
- Current:
GIT_TERMINAL_PROMPT=0is set. - Current: expiring tokens are refreshed before the context is built.
Tests
- Current: URL parser matrix covers the provider forms in the mocked tests, including ambiguity.
- Current: request construction tests exist for provider write endpoints.
- Current: response decoding tests exist for provider read endpoints.
- Current: pagination tests exist for provider list endpoints.
- Current: conflict mapping tests exist for provider file write/delete endpoints.
- Current: change submission tests exist for direct, branch + PR, fork + PR, and automatic selection.
- Current: change submission tests cover partial failures.
- Current: credential and connection store tests exist.
- Current: refresh race tests exist.
- Current: Git CLI credential tests exist.
- Current: safety tests exist for path traversal, token exposure, delete-without-version, empty commit messages, provider file size limits, delete-is-explicit behavior, and blind-overwrite create/update protection.
- Current: no default test hits the network.
- Current: live account smoke tests are opt-in through environment variables only.
- Current: opt-in live write tests cover disposable branch/file create/read/delete operations and branch cleanup when dedicated test repositories are configured.
- Release: run the opt-in live write tests against dedicated GitHub, GitLab, and Forgejo/Gitea repositories before tagging v1.
App Readiness
- Lezin can open a remote file from URL.
- Lezin can save by committing without local Git.
- Lezin can propose a change to a repo it cannot push to (fork + PR) in one call.
- Lezin can check staleness via
checkForRemoteChange. - GitFolder can resolve provider credentials for
git pullandgit push. - GitFolder can list repositories and branches, and create a new remote repository during folder setup.
- Existing GitFolder GitHub token migration path is documented.
Decisions
Formerly "Open Questions". All of these are decided; the implementation agent should not revisit them.
Kit Strategy
v1 is a Swift library implemented as a Swift Package for Apple platforms.
Reason:
- Lezin is native Apple.
- GitFolder is native macOS.
- Keychain and OAuth browser flows are Apple-native.
Future platform kits may mirror the same contract for Android, web, and backend use. Nothing in the provider model, error model, URL parsing rules, or authentication concepts may depend on Swift-only behavior that could not be represented in Kotlin, TypeScript, or another mainstream runtime.
The Swift library is the only implementation target for v1. Future libraries or kits must not expand the v1 definition of done.
Repository Location
/Users/silvandiepen/Repositories/_libs/git-pont, as its own Git repository and internal monorepo.
The Swift library lives under libs/swift. Future reusable platform libraries should be added as siblings such as libs/kotlin, libs/typescript, or libs/server. The kits/ namespace is reserved for app/demo kits if needed later. Shared documentation lives under docs/content; the docs site builder lives under docs/site.
OAuth App Ownership
- Core supports injected
OAuthAppConfigonly; GitPont ships no default client IDs. - Each consuming app (Lezin, GitFolder) registers and provides its own OAuth apps.
- PAT/token auth works without any OAuth app setup and is the guaranteed path for every provider.
Codeberg
Codeberg is a preset Forgejo GitProviderInstance, not a GitProviderKind. There is exactly one Forgejo/Gitea code path in GitPontForge.
Pull Requests vs Merge Requests
One capability (pullRequestCreate), one request/result type. Wording is a UI concern exposed via GitProvider.changeRequestTerm.
Conflict Protection
Mandatory by default. Updating or deleting an existing file without an expected version requires allowBlindOverwrite = true. This is not configurable globally.
Pagination
Handled inside providers; apps receive complete GitList results with a truncated flag, capped at 30 pages of 100 items. Exposed page tokens are a possible v2 addition, not v1.
SSH
Not in v1, in any module. GitFolder's existing SSH mode stays app-owned.
Naming
Use GitPont in Swift types, repository/package family name git-pont, and Apple product names like GitPontCore.
Use "library" for reusable implementation packages and "kit" only for app/demo bundles or composed starter integrations. Do not name future libraries or kits in code until they exist.
Avoid GitBridge in docs/code to prevent naming drift.
Source of Truth
Where docs disagree, Architecture and Provider Model win. Any API rename must update those two first, then the README and integration docs.