From ea4751cdea21da5e41d77dd467e7415d85288950 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Thu, 9 Jul 2026 20:07:58 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20add=20push-remote=20workfl?= =?UTF-8?q?ow=20to=20trunk-first-repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split initialization into Initialize and Push Remote workflows so users can provision the trunk-first git structure before the remote URL is available. Add Step 0 to detect mode, Push Remote Workflow (Steps P1-P3) with branch and remote validation, and updated summary with push-remote guidance. Extends evals with test cases for post-initialization remote push scenarios. --- README.md | 5 +- skills/trunk-first-repo/SKILL.md | 147 +++++++++++++++++++---- skills/trunk-first-repo/evals/evals.json | 25 +++- 3 files changed, 149 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index ad3260c..b45a2c1 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ npx skills add https://github.com/codebeltnet/agentic --skill dotnet-docfx-diges | [git-repo-digest](skills/git-repo-digest/SKILL.md) | Turns any full repository URL into a deterministic digest workspace using the bundled .NET file-based runner `scripts/digest.cs`. Requires explicit `--repo-url`, resolves omitted output paths to `/.bot/digests` and passes that as `--output-root`, maps multiple positional URLs the same way for slash commands, bare pasted URLs, and natural-language requests by treating the first URL as the digest repo and every later URL as repeated `--external-repo-url`, always writes into `{output-root}/{repo-id}/{yyyyMMdd-HHmmssZ}`, accepts repeated curated public consumer repos, derives `{repo-id}`, fixes `result/`, performs shallow git clones, packs local tracked files with the bundled C# packer using `git ls-files`, separates XML evidence into `source.xml`, `tests.xml`, `projects.xml`, editorial `readmes.xml`, and scenario-only `external-usage.xml`, writes package and conceptual overview prompts under `prompts/`, emits public API summaries, engineering signals, evidence indexes, ordered XML chunks, referenced-package evidence maps for aggregate examples, and manifest-backed frontmatter hints, treats previous digest prose as contamination during fresh generation, then guides the agent to fully read the current phase's required evidence before writing package digests and a concept-led `result/Index.md` with YAML frontmatter containing Product-derived overview title metadata, validated documentation URLs resolved from PackageProjectUrl, documentation-host-filtered exact `.nuget//README.md` documentation links including emoji-prefixed Documentation headings and "More documentation..." blocks, DocFX `metadata[].dest` API paths, and source namespace page candidates from `src//**/*.cs`, target frameworks, package/library counts, external links, package-family links, and context glyphs, and validates authored result examples with `--validate-results` as a deterministic API-shape, Codebelt.Extensions.Xunit shape, PascalCase `MethodName_Scenario_ExpectedBehavior` test-method naming, Basic usage quality, and optimized NuGet-backed executable test gate with bounded parallelism. | | [dotnet-new-lib-slnx](skills/dotnet-new-lib-slnx/SKILL.md) | Scaffold a new .NET NuGet library solution following codebeltnet engineering conventions. Dynamic defaults for TFM/repository metadata, latest-stable NuGet package resolution, tuning projects plus a tooling-based benchmark runner, TFM-aware test environments, strong-name signing, NuGet packaging, DocFX documentation, CI/CD pipeline, and code quality tooling. | | [dotnet-new-app-slnx](skills/dotnet-new-app-slnx/SKILL.md) | Scaffold a new .NET standalone application solution following codebeltnet engineering conventions. Supports Console, Web, and Worker host families with Startup or Minimal hosting patterns; Web expands into Empty Web, Web API, MVC, or Web App / Razor, plus functional tests and a simplified CI pipeline. | -| [trunk-first-repo](skills/trunk-first-repo/SKILL.md) | Initialize a git repository following [scaled trunk-based development](https://trunkbaseddevelopment.com/#scaled-trunk-based-development). Seeds an empty `main` branch and creates a versioned feature branch (`v0.1.0/init`), enforcing a PR-first workflow where content only reaches main through peer-reviewed pull requests. | +| [trunk-first-repo](skills/trunk-first-repo/SKILL.md) | Initialize a git repository following [scaled trunk-based development](https://trunkbaseddevelopment.com/#scaled-trunk-based-development). Seeds an empty `main` branch, creates a versioned feature branch (`v0.1.0/init`), and supports a later `push remote ` mode that pushes `main` before feature branches so new remotes keep the right default branch while content reaches main only through peer-reviewed pull requests. | | [dotnet-strong-name-signing](skills/dotnet-strong-name-signing/SKILL.md) | Generate a strong name key (`.snk`) file for signing .NET assemblies using pure .NET cryptography — no Visual Studio Developer PowerShell or `sn.exe` required. Works in any terminal. Defaults to 1024-bit RSA (matching `sn.exe`), with 2048 and 4096 available as options. | | [git-remote-release](skills/git-remote-release/SKILL.md) | Generate GitHub release notes by summarizing all commits and pull requests between two Git tags or branches in a remote GitHub repository. Accepts a compare URL or separate owner/repo, previous ref, and current ref values; falls back to comparing the current branch against the upstream default branch when no input is provided. Produces a human-friendly `## What's Changed` summary with optional GitHub alert blocks, a `Sources:` section preserving PR and commit references, and a full changelog compare link. | | [dotnet-change-impact](skills/dotnet-change-impact/SKILL.md) | Classify .NET library or NuGet package changes and recommend the correct release bump — `Major`, `Minor`, or `Patch` — for both Semantic Versioning (`MAJOR.MINOR.PATCH`) and .NET assembly/file versioning (`Major.Minor.Build.Revision`), grounded in Microsoft's official .NET compatibility rules. Uses the current Git branch by default when no explicit change details or compare range are provided, resolving it against the upstream/default base branch with local read-only git state. Always returns structured behavioral/binary/source/design-time/backwards compatibility reasoning with the recommendation, even when the bump is clear. | @@ -508,11 +508,12 @@ Generating a `.snk` file traditionally requires `sn.exe`, which is only availabl Most repositories start with `git init` followed by committing everything directly to `main`. This works — until someone force-pushes to main, or a half-finished feature lands without review. By the time you add branch protection, the history is already messy. -**trunk-first-repo** flips this: main starts empty and stays clean from the very first commit. Every piece of content enters through a pull request. This gives you: +**trunk-first-repo** flips this: main starts empty and stays clean from the very first commit. Every piece of content enters through a pull request, and `push remote ` can be invoked later when the remote is ready so the first remote push sends `main` before any feature branch. This gives you: - **Review from day one** — no "we'll add branch protection later" that never happens - **Clean, meaningful history** — main tells the story of reviewed, approved changes - **Version-aware branches** — `v0.0.1/spike-auth` vs `v1.0.0/release-prep` signals project maturity at a glance +- **Safer first push** — invoke `push remote ` to push `main` by ref from the feature branch, then push the feature branch without manually deleting files or checking out `main` - **Zero-friction setup** — one skill invocation, not a 10-step checklist ### Why git-remote-release? diff --git a/skills/trunk-first-repo/SKILL.md b/skills/trunk-first-repo/SKILL.md index f0b0289..16b5dc5 100644 --- a/skills/trunk-first-repo/SKILL.md +++ b/skills/trunk-first-repo/SKILL.md @@ -1,7 +1,7 @@ --- name: trunk-first-repo -description: > - Initialize a folder as a git repository following scaled trunk-based development. Sets up an empty main branch (seed commit only), creates a versioned feature branch, and enforces a PR-first workflow where content only reaches main through pull requests. Use this skill when the user wants to initialize a git repo, set up a new repository, start a project with proper git workflow, or mentions "trunk-based", "PR workflow", "branch protection", "git init", or wants to follow GitHub PR best practices. ALWAYS use this skill when asked to initialize or set up a git repository. +description: > + Initialize a folder as a git repository following scaled trunk-based development. Sets up an empty main branch (seed commit only), creates a versioned feature branch, pushes main before feature branches, and enforces a PR-first workflow where content only reaches main through pull requests. Use this skill when the user wants to initialize a git repo, set up a new repository, start a project with proper git workflow, safely push the first trunk-first branches later with "push remote", or mentions "trunk-based", "PR workflow", "branch protection", "git init", or wants to follow GitHub PR best practices. ALWAYS use this skill when asked to initialize or set up a git repository. --- # Trunk-First Repo @@ -12,9 +12,17 @@ Initialize a folder as a git repository following [scaled trunk-based developmen This matters because it prevents accidental pushes to main, establishes a clean PR-based workflow from day one, and makes the git history meaningful by design rather than as an afterthought. -## Workflow - -### Step 1: Collect Parameters +## Workflow + +### Step 0: Select Mode + +If the user says `push remote`, do not initialize the repository again. Use the Push Remote Workflow below. + +Otherwise, use the Initialize Workflow. + +## Initialize Workflow + +### Step 1: Collect Parameters Read `FORMS.md` and collect all parameters by presenting each field to the user one at a time using the agent's native input mechanism. Follow the presentation rules defined in the form. Do not proceed to Step 2 until all required fields are collected and the user confirms the summary. @@ -46,15 +54,46 @@ After step 5, the user is on the feature branch (e.g. `v0.1.0/init`) with all th If the user provided a remote URL: ```bash -git remote add origin {REMOTE_URL} -git push -u origin main -``` - -If skipped, remind the user they can add it later: - -> When you're ready, run: `git remote add origin ` followed by `git push -u origin main` - -### Step 4: Summary +git remote add origin {REMOTE_URL} +git push -u origin main:main +``` + +Run the push while still on the feature branch. Do not switch to `main` just to push it; Git can push the branch ref by name without changing the working tree. + +If skipped, remind the user they can add it later: + +> When you're ready, invoke this skill with `push remote ` from the feature branch, or run `git remote add origin ` followed by `git push -u origin main:main` + +### Step 3a: First Feature Push + +After the user commits the first project files on the feature branch, push in this order: + +```bash +git push -u origin main:main +git push -u origin HEAD +``` + +This order matters. `main` must exist on the remote before the feature branch is pushed so hosts such as GitHub do not make the feature branch the default branch for a brand-new remote. + +If the remote was added only after the first feature commit, still run the same order from the feature branch: + +```bash +git remote add origin {REMOTE_URL} +git push -u origin main:main +git push -u origin HEAD +``` + +Do not manually delete project files from the working tree to "clean" `main`. When the user is worried about files appearing on `main`, explicitly explain that untracked or ignored checkout files can remain visible in the directory but are not part of the `main` branch. If the user needs to verify that `main` is empty, inspect the branch tree instead of the checkout directory: + +```bash +git ls-tree -r --name-only main +``` + +An empty output means `main` contains only the seed commit. Untracked or ignored files in the checkout directory are not part of `main`. + +If the feature branch was accidentally pushed before `main`, push `main` next and change the remote repository's default branch to `main` before opening the PR. + +### Step 4: Summary After initialization, display a summary: @@ -65,11 +104,68 @@ After initialization, display a summary: feature branch: v0.1.0/init (current — start working here) remote: not configured (add later with `git remote add origin `) - Next steps: - 1. Stage and commit your files on this branch - 2. Push the feature branch and open a PR to main - 3. After review, merge the PR — main stays clean -``` + Next steps: + 1. Stage and commit your files on this branch + 2. When the remote is ready, invoke `push remote ` from this branch + 3. Push main first with `git push -u origin main:main` + 4. Push the feature branch with `git push -u origin HEAD` and open a PR to main + 5. After review, merge the PR — main stays clean +``` + +## Push Remote Workflow + +Use this workflow when the user invokes `push remote`, especially when the remote URL was not available during initialization. + +### Step P1: Confirm Current State + +Inspect the current branch: + +```bash +git branch --show-current +``` + +If the current branch is `main`, stop and ask the user to switch to the feature branch first. Do not push the first feature branch while checked out on `main`. + +Verify `main` is still the empty seed branch: + +```bash +git ls-tree -r --name-only main +``` + +Empty output is expected. If output is not empty, stop and explain that `main` already contains files, so this is no longer the empty trunk-first seed state. + +When explaining this check, explicitly say that untracked or ignored files can remain visible in the checkout directory but are not part of `main` unless they appear in `git ls-tree -r --name-only main`. + +### Step P2: Resolve Remote + +Check whether `origin` already exists: + +```bash +git remote get-url origin +``` + +If `origin` exists, use it. + +If `origin` does not exist and the user provided a URL after `push remote`, add it: + +```bash +git remote add origin {REMOTE_URL} +``` + +If `origin` does not exist and the user did not provide a URL, ask for the remote URL before proceeding. Do not guess or use a placeholder. + +### Step P3: Push in Safe Order + +Run these commands from the feature branch: + +```bash +git push -u origin main:main +git push -u origin HEAD +``` + +Do not switch to `main` just to push it. Git can push the `main` branch ref by name while the checkout stays on the feature branch. + +After pushing, tell the user to open a PR from the pushed feature branch to `main`. ## Conventions @@ -99,11 +195,12 @@ The version prefix groups branches by project maturity. The context should be sh Once initialized, the day-to-day workflow is: -1. **Create a feature branch** from main: `git checkout -b v0.1.0/my-feature main` -2. **Work and commit** on the feature branch -3. **Push and open a PR** to main -4. **Review, approve, and merge** the PR -5. **Delete the feature branch** after merge -6. **Pull main** and create the next feature branch +1. **Create a feature branch** from main: `git checkout -b v0.1.0/my-feature main` +2. **Work and commit** on the feature branch +3. **Push main by ref if the remote does not have it yet**: `git push -u origin main:main` +4. **Push the feature branch and open a PR** to main: `git push -u origin HEAD` +5. **Review, approve, and merge** the PR +6. **Delete the feature branch** after merge +7. **Pull main** and create the next feature branch Feature branches should be short-lived — ideally merged within hours or a few days, not weeks. diff --git a/skills/trunk-first-repo/evals/evals.json b/skills/trunk-first-repo/evals/evals.json index eaf4659..43c2bf4 100644 --- a/skills/trunk-first-repo/evals/evals.json +++ b/skills/trunk-first-repo/evals/evals.json @@ -17,7 +17,7 @@ "expected_output": "The workflow initializes trunk-first git history and adds the provided remote origin.", "expectations": [ "Adds the provided remote URL after initialization", - "Pushes or documents pushing main when a remote is provided", + "Pushes or documents pushing main with an explicit main:main ref while staying on the feature branch", "Summarizes next steps after setup" ] }, @@ -30,6 +30,29 @@ "Creates branch name v1.0.0/release-prep", "Reinforces never committing directly to main after the seed commit" ] + }, + { + "id": 4, + "prompt": "I initialized a trunk-first repo, committed my first files on v0.1.0/init, and only now added a GitHub remote. Help me push without making the feature branch the default branch or manually deleting files from main.", + "expected_output": "The workflow pushes main to the remote first by ref, then pushes the current feature branch, without checking out main or deleting working-tree files.", + "expectations": [ + "Runs or recommends git push -u origin main:main before pushing the feature branch", + "Runs or recommends git push -u origin HEAD for the current feature branch", + "Avoids switching to main just to push it", + "Explains that untracked or ignored files in the checkout are not part of main and suggests git ls-tree -r --name-only main to verify branch contents" + ] + }, + { + "id": 5, + "prompt": "trunk-first-repo push remote https://github.com/example/demo.git", + "expected_output": "The workflow recognizes push remote as a publish-only mode for an already-initialized trunk-first repository, validates the current branch and empty main tree, adds origin if needed, then pushes main before the current feature branch.", + "expectations": [ + "Does not run git init, git checkout --orphan main, or recreate the feature branch", + "Checks the current branch and refuses to continue from main", + "Checks main with git ls-tree -r --name-only main before pushing", + "Adds origin from the provided URL only if origin does not already exist", + "Runs or recommends git push -u origin main:main before git push -u origin HEAD" + ] } ] }