Skip to content

feat(skills/github): ticket-driven PR creation + branch-name helper (closes #70)#71

Merged
initializ-mk merged 2 commits into
mainfrom
feature/github-skill-ticket-driven
May 20, 2026
Merged

feat(skills/github): ticket-driven PR creation + branch-name helper (closes #70)#71
initializ-mk merged 2 commits into
mainfrom
feature/github-skill-ticket-driven

Conversation

@initializ-mk
Copy link
Copy Markdown
Contributor

Summary

Additive update to the existing github embedded skill. No breaking changes — both new github_create_pr parameters (ticket_id, ticket_url) are optional; absent both → byte-identical behaviour to today. Closes #70.

Tools

Tool Status New params Purpose
github_create_pr updated (additive) ticket_id, ticket_url (both optional) When ticket_id is set, auto-suffix the title with [<ticket_id>] if not already present; if ticket_url is set, append a Tracks: [<ticket_id>](<ticket_url>) footer to the body.
github_branch_name_from_ticket new ticket_id, title, optional prefix Pure string transform: lowercase ID + slugify title + compose <prefix>/<lower-id>-<slug>, capped at 60 chars cut at the last hyphen boundary. No network call.
All others (github_clone, github_checkout, github_commit, github_push, github_status, github_create_issue, github_list_issues, github_list_prs, github_get_user, github_list_stargazers, github_list_forks, github_pr_author_profiles, github_stargazer_profiles) unchanged

SKILL.md changes

  • Tags: added ticket-driven and linear-compatible. Everything else preserved.
  • Workflow rule softened with three explicit carve-outs that allow the agent to pause:
    • ticket-driven mode → post linear_add_comment and wait
    • code_plan_create returns complexity: \"high\" or non-empty risks → present to user
    • genuine ambiguity → ask the user
      Outside those, the "complete the full sequence in one session" rule still applies verbatim.
  • New section: Ticket-driven PR conventions — placed after Branch safety rules. Tells the LLM to call github_branch_name_from_ticket first, pass ticket_id / ticket_url to github_create_pr, and post the PR URL back on the originating ticket using the linear skill (not in the PR itself).
  • New section: When working from a ticket (under "Branch safety rules") — points the LLM at github_branch_name_from_ticket and explicitly forbids inventing branch names like claude/fix-thing.
  • github_create_pr docs rebuilt as a proper input table with the two new rows and a one-line explainer of the auto-suffix/auto-footer behaviour. The previous one-line input bullet is unchanged in semantics.
  • New ## Tool: github_branch_name_from_ticket section placed after github_checkout.

github-create-pr.sh changes

Extract ticket_id / ticket_url, then before the gh pr create invocation:

if [ -n \"\$TICKET_ID\" ]; then
  case \"\$TITLE\" in
    *\"[\$TICKET_ID]\"*) ;;
    *) TITLE=\"\$TITLE [\$TICKET_ID]\" ;;
  esac
  if [ -n \"\$TICKET_URL\" ]; then
    BODY=\"\$BODY\\n\\n---\\nTracks: [\$TICKET_ID](\$TICKET_URL)\"
  else
    BODY=\"\$BODY\\n\\n---\\nTracks: \$TICKET_ID\"
  fi
fi

The literal-bracket pattern (*\"[\$TICKET_ID]\"*) intentionally matches only the bracketed form, so a title like \"ENG-123 hotfix\" (no brackets) gets the suffix appended. This matches the documented convention.

github-branch-name-from-ticket.sh (new)

  • Validates prefix against feat|fix|chore|docs|refactor; falls back to feat for any other value.
  • Lowercases ticket ID (ENG-123eng-123).
  • Slugifies: tr [:upper:] → [:lower:], sed -E 's/[^a-z0-9]+/-/g', strip leading/trailing -.
  • Truncates to 60 chars; if a hyphen exists in the truncated string, cuts back to it via \${SLUG%-*} so we never emit a half-word.
  • Returns {\"branch\": \"<prefix>/<lower-id>-<slug>\"}.

Verification (verbatim from #70)

$ echo '{\"ticket_id\":\"ENG-123\",\"title\":\"Add invoice creation endpoint with validation\"}' | bash github-branch-name-from-ticket.sh
{\"branch\":\"feat/eng-123-add-invoice-creation-endpoint-with-validation\"}

$ echo '{\"ticket_id\":\"BUG-7\",\"title\":\"Fix: !!! Refresh token rejects 0-length string @@@\",\"prefix\":\"fix\"}' | bash github-branch-name-from-ticket.sh
{\"branch\":\"fix/bug-7-fix-refresh-token-rejects-0-length-string\"}

Both match the issue's expected outputs exactly. Additional edge cases tested locally:

Input Output
Invalid prefix: \"wip\" Falls back to featfeat/x-1-hello
Long title (130+ chars) Cut at the last hyphen inside 60 chars: feat/ops-999-this-is-a-really-really-really-really-really-really-long
Missing ticket_id {\"error\":\"ticket_id is required\"} on stderr, exit 1

Test plan

  • go test ./forge-skills/... — all green (incl. TestEmbeddedRegistry_GitHubDetails, which counts on gh/git/jq + the egress domain set — none of which changed)
  • go test ./forge-core/... ./forge-cli/... ./forge-plugins/... — no regressions
  • gofmt -w, golangci-lint run ./forge-skills/... — 0 issues
  • shellcheck clean on github-branch-name-from-ticket.sh
  • Both verbatim smoke tests from [Skill]: update github skill — ticket-driven PR creation + branch-name helper #70 pass
  • Edge cases: invalid prefix → fallback, long title → hyphen-boundary truncation, missing required field → structured error
  • Manual: against a sandbox repo with GH_TOKEN, verify the PR title ends with [ENG-DEMO-1] and the body contains Tracks: [ENG-DEMO-1](https://...)

Out of scope per #70

  • No Linear / tracker API calls from github-skill scripts — the LLM does the post-PR ticket comment via the linear skill (PR feat(skills): add linear embedded skill (closes #66) #67)
  • No hardcoded linear.app references — ticket_url is an opaque URL
  • No github_link_issue / github_close_issue_on_merge — separate concern
  • No new egress domains — api.github.com + github.com still the only allowed pair
  • No changes to pagination contract or list-tool behaviour

Pre-existing finding left untouched

shellcheck github-create-pr.sh reports SC2181 on line 88 (the gh pr create exit check uses \$? instead of if !). This exists verbatim on main and is not introduced by this PR — the issue's "additive changes only" rule covers existing style. Happy to fix in a follow-up.

Relation to PRs #67 and #69

This PR is independent of:

The three together form the canonical ticket → plan → branch → commit → PR → comment flow. None of them touch the same files, so they can land in any order.

…loses #70)

Additive update to the existing github skill — no existing tool names,
signatures, or behaviour change. Both new github_create_pr parameters
(ticket_id, ticket_url) are optional; absent both → identical to today.

SKILL.md
- Frontmatter tags: add `ticket-driven` and `linear-compatible`
- Replace the "complete entire workflow" rule with a version that
  carves out three explicit pause cases:
    1. ticket-driven mode (post a linear_add_comment and wait)
    2. code planning (high complexity / risks)
    3. genuine ambiguity
  Outside those exceptions, complete the full sequence in one session.
- New "Ticket-driven PR conventions" section after Branch safety rules:
  use github_branch_name_from_ticket first, pass ticket_id/ticket_url to
  github_create_pr, post the PR URL back on the originating ticket (not
  in the PR itself).
- github_create_pr docs: new input table with the two new optional rows
  (ticket_id, ticket_url) and a one-line explanation that the skill
  auto-suffixes the title and appends a Tracks: back-link footer.
- New ## Tool: github_branch_name_from_ticket section after
  github_checkout.

github-create-pr.sh
- Extract optional ticket_id and ticket_url from input.
- When ticket_id is set:
    - Suffix title with [<ticket_id>] if not already present (case
      pattern matches the literal bracket form, so "ENG-123" embedded
      in prose without brackets is treated as missing).
    - Append a Tracks: footer to body — with markdown link if
      ticket_url is provided, plain ID otherwise.

github-branch-name-from-ticket.sh (new)
- Validates prefix against feat|fix|chore|docs|refactor allow-list
  (invalid → feat fallback).
- Lowercases ticket ID.
- Slugifies title: tr to lowercase, sed -E to collapse non-alnum runs
  to a single -, strip leading/trailing -.
- Truncates to 60 chars cutting at the last hyphen boundary so we don't
  emit a half-word at the end.
- Returns {"branch": "<prefix>/<lower-id>-<slug>"}.

Verification (verbatim from #70):
- ENG-123 happy path:
    in:  {"ticket_id":"ENG-123","title":"Add invoice creation endpoint with validation"}
    out: {"branch":"feat/eng-123-add-invoice-creation-endpoint-with-validation"}
- BUG-7 with garbage chars:
    in:  {"ticket_id":"BUG-7","title":"Fix: !!! Refresh token rejects 0-length string @@@","prefix":"fix"}
    out: {"branch":"fix/bug-7-fix-refresh-token-rejects-0-length-string"}

Additional edge cases tested:
- Invalid prefix ("wip") → feat fallback.
- Long title truncated at the last hyphen inside 60 chars.
- Missing ticket_id or title → {"error":"..."} on stderr, exit 1.

Out of scope per #70 anti-patterns: no Linear calls from github-skill
scripts (the LLM is responsible for the post-PR ticket comment via the
linear skill), no hardcoded linear.app references, no new tools beyond
github_branch_name_from_ticket. The pre-existing SC2181 finding in
github-create-pr.sh line 88 was left untouched because the "additive
changes only" rule covers existing style.

go test ./forge-skills/... — all green including
TestEmbeddedRegistry_GitHubDetails. shellcheck clean on
github-branch-name-from-ticket.sh.
Mirrors the SKILL.md updates from this PR into the user-facing index:

- Tools table count "fourteen" → "fifteen" with a new row for
  github_branch_name_from_ticket (slugifier, no network call), and the
  github_create_pr row updated to mention the new optional ticket_id /
  ticket_url parameters and the auto-suffix / Tracks-footer behaviour.
- New "Workflow-completion rule" paragraph below the existing Workflow
  one-liner — documents the three pause carve-outs (ticket-driven mode,
  code-plan high complexity, genuine ambiguity).
- New "Ticket-driven PR conventions" paragraph — the four-step
  ticket workflow plus the title-format examples plus the
  branch-name-helper algorithm (prefix allow-list, lowercase id,
  slugify, 60-char hyphen-boundary truncation).

All identical in spirit to the SKILL.md edits already in this PR — no
new behaviour. Doc-link check (37 files) clean.
@initializ-mk initializ-mk merged commit acc7c23 into main May 20, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Skill]: update github skill — ticket-driven PR creation + branch-name helper

1 participant