- name
- smart-submit
- description
- Stage, audit, commit, and submit uncommitted changes via Graphite, with parallel code-review agents. Use when user says "submit this", "ship it", or "commit and push", or has uncommitted work to turn into a PR. Requires uncommitted changes — a clean, already-committed branch needs only gt submit; amending an already-submitted branch is the gt-amend skill.
- user-invocable
- false
## What It Does
Conducts a systematic code quality audit of all uncommitted changes using
specialized agents, then creates a conventional commit and submits via
Graphite. Ensures no anti-patterns, secrets, or silent failures enter the
codebase.
## When to Use
- User says "submit this", "ship it", or "commit and push", or has
uncommitted work to turn into a PR.
- Requires uncommitted changes — a clean, already-committed branch needs
only `gt submit`; amending an already-submitted branch is the `gt-amend`
skill instead.
## Usage
Optional arguments:
- `--amend` — Amend the current branch commit instead of creating a new branch
- `--dry-run` — Run the audit but skip the actual submission
- `--no-verify` — Skip the audit and submit directly (use with caution)
- `--publish` — Override draft mode: submit as published even if `submit.draft: true` in `.graphite.yml`
The argument text provided after the skill name (if any) is available as
context for this invocation.
### Phase 0: Read Convention File
Before any other work, check for a `.graphite.yml` convention file and parse
repo-level settings. Run a single Bash call:
```bash
REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo ".")
GW_DRAFT=""
GW_MERGE_WHEN_READY=""
GW_RESTACK_BEFORE=""
GW_AUDIT_AGENTS=""
GW_SKIP_ON_DRAFT=""
GW_BRANCH_PREFIX=""
if command -v yq >/dev/null 2>&1 && \
yq --help 2>&1 | grep -qi 'jq wrapper\|kislyuk' && \
[ -f "$REPO_TOP/.graphite.yml" ]; then
yq_err=""
GW_DRAFT=$(yq -r '.submit.draft // ""' "$REPO_TOP/.graphite.yml" 2>/dev/null) || yq_err="submit.draft"
GW_MERGE_WHEN_READY=$(yq -r '.submit.merge_when_ready // ""' "$REPO_TOP/.graphite.yml" 2>/dev/null) || yq_err="${yq_err:+$yq_err, }merge_when_ready"
GW_RESTACK_BEFORE=$(yq -r '.submit.restack_before // ""' "$REPO_TOP/.graphite.yml" 2>/dev/null) || yq_err="${yq_err:+$yq_err, }restack_before"
GW_AUDIT_AGENTS=$(yq -r '.audit.agents // ""' "$REPO_TOP/.graphite.yml" 2>/dev/null) || yq_err="${yq_err:+$yq_err, }audit.agents"
GW_SKIP_ON_DRAFT=$(yq -r '.audit.skip_on_draft // ""' "$REPO_TOP/.graphite.yml" 2>/dev/null) || yq_err="${yq_err:+$yq_err, }skip_on_draft"
GW_BRANCH_PREFIX=$(yq -r '.branch.prefix // ""' "$REPO_TOP/.graphite.yml" 2>/dev/null) || yq_err="${yq_err:+$yq_err, }branch.prefix"
if [ -n "$yq_err" ]; then
printf '[gt-workflow] Warning: yq failed to parse fields: %s. Using defaults for those.\n' "$yq_err" >&2
else
printf '[gt-workflow] Convention file loaded: %s/.graphite.yml\n' "$REPO_TOP" >&2
fi
elif [ -f "$REPO_TOP/.graphite.yml" ]; then
printf '[gt-workflow] Warning: .graphite.yml exists but yq (kislyuk) is not installed. Using defaults.\n' >&2
printf '[gt-workflow] Install yq: pip install yq\n' >&2
fi
# Validate and clamp audit.agents to 1-3 range
if [ -n "$GW_AUDIT_AGENTS" ]; then
case "$GW_AUDIT_AGENTS" in
*[!0-9]*) printf '[gt-workflow] Warning: audit.agents value "%s" is not an integer. Using default 3.\n' "$GW_AUDIT_AGENTS" >&2; GW_AUDIT_AGENTS=3 ;;
esac
if [ "$GW_AUDIT_AGENTS" -lt 1 ] 2>/dev/null; then
printf '[gt-workflow] Warning: audit.agents=%s is below minimum. Using 1.\n' "$GW_AUDIT_AGENTS" >&2
GW_AUDIT_AGENTS=1
elif [ "$GW_AUDIT_AGENTS" -gt 3 ] 2>/dev/null; then
printf '[gt-workflow] Warning: audit.agents=%s exceeds maximum. Using 3.\n' "$GW_AUDIT_AGENTS" >&2
GW_AUDIT_AGENTS=3
fi
fi
# Validate branch.prefix against allow-list
if [ -n "$GW_BRANCH_PREFIX" ]; then
if ! printf '%s' "$GW_BRANCH_PREFIX" | grep -qE '^[a-z0-9][a-z0-9/_-]*$'; then
printf '[gt-workflow] Error: branch.prefix "%s" contains invalid characters. Using empty prefix.\n' "$GW_BRANCH_PREFIX" >&2
GW_BRANCH_PREFIX=""
fi
fi
```
Store these values for use in subsequent phases. When a value is empty, use the
hardcoded default (draft=false, merge_when_ready=false, restack_before=true,
audit_agents=3, skip_on_draft=false, branch_prefix="").
### Phase 1: Understand Current State
#### 1. Check for Changes
Run these commands in parallel to understand the working tree and stack
position:
```bash
git status --short
```
```bash
git diff --stat
```
```bash
gt log short
```
```bash
gt trunk
```
If there are no uncommitted changes, tell the user and exit.
#### 2. Determine Branch Context
Check whether the current branch is trunk or a feature branch:
```bash
current=$(git branch --show-current)
trunk=$(gt trunk)
echo "current=$current trunk=$trunk"
```
- If `current == trunk` → will use `gt create <branch-name> -m "message"` to
create a new branch
- If `current != trunk` → will use `gt modify -m "message"` to update the
current branch
- If `--amend` argument was passed and on a feature branch → will use
`gt commit amend` instead
### Phase 2: Audit (skip if `--no-verify`)
**Skip-on-draft check:** If `$GW_SKIP_ON_DRAFT` is `true` and `$GW_DRAFT` is
`true` (from `.graphite.yml`), skip the entire audit phase and proceed to
Phase 3.
> **Note:** This check uses the config-derived values in `$GW_SKIP_ON_DRAFT`
> and `$GW_DRAFT` from `.graphite.yml`. CLI flags such as `--publish` affect
> the eventual submit mode, but they do not override the audit skip decision in
> this phase.
#### 0. Capture the Diff Once
Before spawning auditors, capture the full diff — staged and unstaged — so
all agents can use it without redundant calls. Use `git diff HEAD` rather
than a bare `git diff`: a bare `git diff` only shows unstaged changes, so
any changes the user staged with `git add` before invoking this skill would
be silently excluded from the audit while still ending up in the commit
(Phase 3 generates the commit message from `git diff --cached` and commits
the full index).
```bash
git diff HEAD
```
Store this output as `$DIFF_OUTPUT` (pass it as context to each agent below).
#### 1. Run the Audit
Invoke the `Skill` tool with `skill: "audit-review"`, passing `$DIFF_OUTPUT`
and `$GW_AUDIT_AGENTS` as context. (On Codex there is no `Skill` tool — read
the Codex-exposed `audit-review` skill and follow it directly with the same
context.) It runs the appropriate quick-code-review
/ quick-security-scan / quick-error-check prompts (1-3 of them, per
`$GW_AUDIT_AGENTS`) and returns a CRITICAL / MINOR / CLEAN verdict with
file:line findings.
#### 2. Gate Check
If `audit-review` reports a dispatch failure (an audit failed to run or
timed out), inform the user which audit is missing and ask whether to
proceed with partial results or abort.
**IF CRITICAL ISSUES** (secrets, production mocks, silent failures):
1. Display blocking issues with file:line references
2. Use AskUserQuestion (on Codex, which lacks that tool: present the same
options as a numbered list in your reply and wait for the user's answer)
to ask:
- "Fix issues before submitting (Recommended)"
- "Submit anyway"
- "Abort"
3. If "Fix issues" → stop and let the user fix them
4. If "Abort" → stop entirely
**IF MINOR ISSUES** (TODOs, style, minor logic):
1. Display warnings
2. Proceed but note them in the output
**IF CLEAN**: Proceed automatically.
### Phase 3: Stage & Commit
#### 1. Stage Specific Files
**IMPORTANT**: Do NOT use `git add .` or `git add -A`. Instead, stage only the
specific changed files to avoid accidentally committing secrets, binaries, or
unrelated files.
```bash
# Get the list of changed/untracked files
git diff --name-only
git ls-files --others --exclude-standard
```
Review the file list. Exclude any files that look like:
- `.env*` files
- Credential/key files
- Large binaries
- Build artifacts
Stage the appropriate files by name:
```bash
git add -- "<file1>" "<file2>"
```
#### 2. Generate Conventional Commit Message
Analyze the staged diff to determine the commit type and scope:
```bash
git diff --cached --stat
git diff --cached
```
Generate a conventional commit message following this format:
- `feat:` — new feature
- `fix:` — bug fix
- `refactor:` — code restructuring
- `docs:` — documentation changes
- `test:` — test additions/changes
- `chore:` — maintenance, config, dependencies
The message should be concise (under 72 chars for the subject line). Include a
body if the changes are complex.
#### 3. Create Commit via Graphite
**If on trunk** (creating new branch):
Derive the branch name from the commit type and a short slug (e.g.,
`feat/add-user-auth`, `fix/null-pointer-crash`). If `$GW_BRANCH_PREFIX` is set,
prepend it to the branch name:
```bash
gt create "<GW_BRANCH_PREFIX><branch-name>" -m "<conventional commit message>"
```
For example, with `branch.prefix: "agent/"` and slug `feat/add-user-auth`, the
branch name becomes `agent/feat/add-user-auth`.
**If on feature branch** (adding to existing):
```bash
gt modify -m "<conventional commit message>"
```
**If `--amend`** (modifying current branch):
```bash
gt commit amend -m "<conventional commit message>"
```
### Phase 4: Submit
#### 1. Push to GitHub
If `--dry-run` was provided, skip this step and do not run `gt submit`; instead,
only simulate the submission and proceed to the result summary without making
any remote changes.
Build the submit command with convention file flags. First, if `$GW_RESTACK_BEFORE`
is `true`, run restack as a **separate preceding command**:
```bash
gt stack restack
```
Then submit with flags based on `.graphite.yml` values:
```bash
gt submit --no-interactive
```
Append flags to the submit command (only if set and non-empty):
- If `$GW_DRAFT` is `true` (and no explicit `--publish` argument): add `--draft`
- If `$GW_MERGE_WHEN_READY` is `true`: add `--merge-when-ready`
After submitting, confirm the new stack state:
```bash
gt log short
```
```bash
gt pr
```
Output a summary:
- Commit message used
- Branch created/amended
- PR link
- Stack visualization
- Any audit warnings that were noted
### Success Criteria
- All uncommitted code audited by 1-3 specialized agents (unless `--no-verify`)
- No critical issues committed
- Files staged individually (no blanket `git add .`)
- Conventional commit message generated from diff analysis
- Graphite stack created/updated and submitted (or a dry-run summary produced
when `--dry-run` is used)
- User provided with PR link and stack context
Ver en GitHub