| name | gt-setup |
| description | Validate Graphite CLI prerequisites and configure settings for AI agent workflows. Use when first installing the plugin, after Graphite auth changes, or when gt commands fail. |
| user-invocable | false |
What It Does
Validates that Graphite CLI is installed, authenticated, and initialized
for the current repository. Then configures Graphite CLI settings for AI
agent workflows and generates a .graphite.yml convention file.
When to Use
- First installing the plugin.
- After Graphite auth changes.
- When
gt commands fail.
Usage
Phase 1: Validate Prerequisites
Step 1: Check Graphite Prerequisites
Run a single Bash call:
version_gte() {
local IFS=.
local i a=($1) b=($2)
for ((i=0; i<${#b[@]}; i++)); do
local av="${a[i]:-0}" bv="${b[i]:-0}"
if ((av > bv)); then return 0; fi
if ((av < bv)); then return 1; fi
done
return 0
}
printf '=== Prerequisites ===\n'
if command -v gt >/dev/null 2>&1; then
gt_version_full=$(gt --version 2>/dev/null)
gt_version_exit=$?
gt_version_raw=$(printf '%s' "$gt_version_full" | head -n1)
if [ "$gt_version_exit" -ne 0 ]; then
printf 'gt: BROKEN (exited with code %s)\n' "$gt_version_exit"
printf 'mcp_server: SKIPPED (gt is broken)\n'
elif [ -n "$gt_version_raw" ]; then
printf 'gt: ok (%s)\n' "$gt_version_raw"
gt_ver=$(printf '%s' "$gt_version_raw" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
if [ -z "$gt_ver" ]; then
printf 'mcp_server: UNKNOWN (could not parse version from: %s)\n' "$gt_version_raw"
elif version_gte "$gt_ver" "1.6.7"; then
printf 'mcp_server: ok (gt >= 1.6.7)\n'
else
printf 'mcp_server: UPGRADE NEEDED (current: %s, need 1.6.7+)\n' "$gt_ver"
fi
else
printf 'gt: ok (version unknown)\n'
printf 'mcp_server: UNKNOWN (gt --version returned no output)\n'
fi
else
printf 'gt: NOT FOUND\n'
printf 'mcp_server: SKIPPED (gt not found)\n'
fi
command -v jq >/dev/null 2>&1 && printf 'jq: ok\n' || printf 'jq: NOT FOUND\n'
if command -v yq >/dev/null 2>&1; then
if yq --help 2>&1 | grep -qi 'jq wrapper\|kislyuk'; then
printf 'yq: ok\n'
else
printf 'yq: WRONG VARIANT (found non-kislyuk yq; .graphite.yml parsing will be skipped)\n'
fi
else
printf 'yq: NOT FOUND (optional — needed by consumer commands to read .graphite.yml)\n'
fi
printf '\n=== Repository ===\n'
repo_top=$(git rev-parse --show-toplevel 2>/dev/null || true)
[ -n "$repo_top" ] && printf 'git_repo: ok\n' || printf 'git_repo: NOT A GIT REPOSITORY\n'
graphite_repo_config=$(git rev-parse --git-path .graphite_repo_config 2>/dev/null || true)
[ -n "$graphite_repo_config" ] && [ -f "$graphite_repo_config" ] && printf 'repo_config: present (%s)\n' "$graphite_repo_config" || printf 'repo_config: missing\n'
if command -v gt >/dev/null 2>&1 && git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
trunk=$(gt trunk 2>/dev/null || true)
[ -n "$trunk" ] && printf 'gt_trunk: %s\n' "$trunk" || printf 'gt_trunk: UNAVAILABLE\n'
else
printf 'gt_trunk: SKIPPED\n'
fi
printf '\n=== Graphite Auth ===\n'
auth_ok=0
for path in \
"$HOME/.graphite_user_config" \
"${XDG_CONFIG_HOME:-$HOME/.config}/graphite/user_config" \
"$HOME/.config/graphite/user_config"; do
if [ -f "$path" ]; then
auth_ok=1
printf 'auth_config: present (%s)\n' "$path"
break
fi
done
[ "$auth_ok" -eq 1 ] || printf 'auth_config: missing\n'
printf '\n=== Convention Files ===\n'
[ -n "$repo_top" ] && [ -f "$repo_top/.graphite.yml" ] && printf 'graphite_yml: present\n' || printf 'graphite_yml: not found\n'
[ -n "$repo_top" ] && [ -f "$repo_top/.github/pull_request_template.md" ] && printf 'pr_template: present\n' || printf 'pr_template: not found\n'
printf '\n=== Merge Queue Compatibility ===\n'
mq_err_log=$(mktemp 2>/dev/null) || mq_err_log=""
[ -n "$mq_err_log" ] && trap 'rm -f "$mq_err_log"' EXIT
if command -v gh >/dev/null 2>&1; then
repo_nwo=$(gh repo view --json nameWithOwner -q .nameWithOwner 2>"${mq_err_log:-/dev/null}")
repo_view_status=$?
if [ "$repo_view_status" -ne 0 ]; then
if [ -n "$mq_err_log" ] && [ -s "$mq_err_log" ]; then
printf '[gt-workflow] Warning: gh repo view failed (exit %d): %s\n' "$repo_view_status" "$(head -c 200 "$mq_err_log" | tr '\n' ' ')" >&2
else
printf '[gt-workflow] Warning: gh repo view failed (exit %d)\n' "$repo_view_status" >&2
fi
printf 'gh_native_queue: COULD NOT CHECK (gh repo view failed)\n'
elif [ -z "$repo_nwo" ]; then
printf 'gh_native_queue: COULD NOT CHECK (gh repo view returned no name)\n'
else
repo_owner="${repo_nwo%/*}"
repo_name="${repo_nwo#*/}"
[ -n "$mq_err_log" ] && : > "$mq_err_log"
mq_check=$(gh api graphql -f query='
query($owner:String!,$name:String!){
repository(owner:$owner,name:$name){ mergeQueue { url } }
}' -f owner="$repo_owner" -f name="$repo_name" --jq 'if .data.repository == null then error("repo null") else (.data.repository.mergeQueue | if . != null then "configured" else empty end) end' 2>"${mq_err_log:-/dev/null}")
mq_status=$?
if [ "$mq_status" -ne 0 ]; then
if [ -n "$mq_err_log" ] && [ -s "$mq_err_log" ]; then
printf '[gt-workflow] Warning: merge queue check failed (gh api graphql): %s\n' "$(head -c 200 "$mq_err_log" | tr '\n' ' ')" >&2
else
printf '[gt-workflow] Warning: merge queue check failed (gh api graphql)\n' >&2
fi
printf 'gh_native_queue: COULD NOT CHECK (gh api graphql failed)\n'
elif [ -n "$mq_check" ]; then
printf 'gh_native_queue: WARNING (configured — disable at https://github.com/%s/settings/branches)\n' "$repo_nwo"
else
printf 'gh_native_queue: ok (not configured)\n'
fi
fi
else
printf 'gh_native_queue: COULD NOT CHECK (gh not installed)\n'
fi
[ -n "$mq_err_log" ] && rm -f "$mq_err_log"
Step 2: Interpret Results
Failures (hard stop) — stop after reporting all that apply:
gt missing: "Graphite CLI is required. Install it from https://graphite.dev/docs/cli and re-run gt-setup."
jq missing: "jq is required by gt-workflow (the gt-cleanup skill uses it to parse PR-status JSON). Install it from https://jqlang.github.io/jq/download/."
git_repo not ok: "gt-workflow must be run inside a git repository."
auth_config missing: "Graphite auth was not detected. Run gt auth or sign in through the Graphite CLI, then re-run gt-setup."
repo_config missing OR gt_trunk unavailable: "This repository is not initialized for Graphite. Run gt init, confirm gt trunk works, then re-run gt-setup."
If any hard-stop failures exist, stop here. Do not proceed to Phase 2.
Warnings (do not block setup — CLI commands still work):
mcp_server UPGRADE NEEDED: "Graphite MCP server requires gt v1.6.7+. The gt mcp stdio server registered in plugin.json will fail to start and Graphite MCP tools will be unavailable until you upgrade. Run npm i -g @withgraphite/graphite-cli@latest to upgrade, then re-run gt-setup. All CLI-based skills (smart-submit, gt-sync, etc.) continue to work without MCP."
mcp_server SKIPPED or UNKNOWN: note accordingly.
yq NOT FOUND: "yq (kislyuk variant) is optional but recommended. Without it, consumer skills (smart-submit, gt-stack-plan, gt-amend) will use hardcoded defaults instead of .graphite.yml settings. Install with: pip install yq"
gh_native_queue WARNING (configured): "GitHub native merge queue is configured for this repo. Graphite and GitHub native merge queue are incompatible — running both causes Graphite to restart CI on queued commits and may produce out-of-order merges. To disable: open https://github.com///settings/branches, edit the branch protection rule for your trunk branch, and uncheck Require merge queue. Setup proceeds, but the warning will repeat each time you run gt-setup until resolved."
gh_native_queue COULD NOT CHECK: informational only — but not necessarily safe to ignore. The parenthetical reason in the output line indicates which probe failed (gh missing/unauthenticated, gh repo view, or gh api graphql); the captured stderr is appended to the [gt-workflow] Warning: line on failure to aid debugging. Three documented false-negative paths exist for the repository.mergeQueue { url } proxy: (1) the GitHub token lacks the admin scope needed to read merge queue config, (2) the repository is not visible to the token, (3) merge queue is configured but mergeQueue.url is null. Any of these can produce COULD NOT CHECK or even a misleading ok (not configured) while the queue is actually active. If your token is scope-limited (e.g., a CI/automation token), re-run gt-setup with an admin-scoped token before relying on the result. Setup itself proceeds normally; the proxy is fail-open by design.
Step 3: Validation Report
If all checks pass, show:
gt-workflow Validation
──────────────────────
Graphite CLI: ready
jq: ready
yq: ready (or: not found — optional)
Auth: detected
Repository: initialized (trunk: <branch>)
MCP Server: available (or: unavailable — gt < 1.6.7)
Merge Queue: ok (or: WARNING — native queue active / COULD NOT CHECK)
Proceeding to AI agent configuration...
Phase 2: Configure Graphite Settings for AI Agents
Step 4: Show Planned Changes
Before applying any settings, read current values and show what will change.
Run a single Bash call:
printf '=== Current Graphite User Settings ===\n'
gt user branch-prefix 2>/dev/null || printf 'branch-prefix: (not set / command unavailable)\n'
gt user branch-date 2>/dev/null || printf 'branch-date: (command unavailable)\n'
gt user restack-date 2>/dev/null || printf 'restack-date: (command unavailable)\n'
gt user submit-body 2>/dev/null || printf 'submit-body: (command unavailable)\n'
gt user pager 2>/dev/null || printf 'pager: (command unavailable)\n'
Present a summary table showing current vs recommended AI-agent values for each
setting. Then proceed to the interactive prompts below.
Step 5: Branch Prefix Prompt
(AskUserQuestion is a Claude Code tool — on Codex, ask each question as a
numbered-option list in your reply and wait for the user's answer before
proceeding; this applies to every AskUserQuestion mention in this skill.)
Use AskUserQuestion to ask: "What branch prefix should AI agents use?"
Options:
"agent/" (Recommended) — flat namespace for agent-created branches
"Skip" — keep the current branch-prefix setting unchanged
The "Other" button allows free-text input for a custom prefix.
If the user provides a custom prefix via "Other", validate it:
- Must start with a lowercase letter or digit (
[a-z0-9])
- Allowed subsequent characters: lowercase letters, digits,
/, _, - only
- Reject if it contains
.., ~, spaces, or any character outside [a-z0-9/_-]
- Normalize: append trailing
/ if missing
- Max length: 20 characters (checked after normalization, so the effective
input limit is 19 characters when a trailing
/ is appended)
- If validation fails, explain the constraint and re-prompt with AskUserQuestion
Store the chosen prefix (or empty string if skipped) for use in Step 7 and
Phase 3.
Step 6: Pager Prompt
Use AskUserQuestion to ask: "Disable the Graphite CLI pager? AI agents hang when pager is enabled."
Options:
"Disable pager (Recommended for AI agents)" — will run gt user pager --disable