/smart-submit
Stage, audit, commit, and submit changes via Graphite with parallel code review agents
From gt-workflownpx claudepluginhub kinginyellows/yellow-plugins --plugin gt-workflowSmart Submit (Graphite Edition)
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.
Input
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)
#$ARGUMENTS
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:
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:
git status --short
git diff --stat
gt log short
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:
current=$(git branch --show-current)
trunk=$(gt trunk)
echo "current=$current trunk=$trunk"
- If
current == trunk→ will usegt create <branch-name> -m "message"to create a new branch - If
current != trunk→ will usegt modify -m "message"to update the current branch - If
--amendargument was passed and on a feature branch → will usegt commit amendinstead
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.
0. Capture the Diff Once
Before spawning auditors, capture the full diff so all agents can use it without redundant calls:
git diff
Store this output as $DIFF_OUTPUT (pass it as context to each agent below).
1. Spawn Parallel Auditors
Determine the number of audit agents to spawn: use $GW_AUDIT_AGENTS if set
(1-3), otherwise default to 3. If the count is 1, spawn only
quick-code-review. If 2, spawn quick-code-review and
quick-security-scan. If 3, spawn all three.
Use the Task tool to launch agents in parallel in a single message, passing
$DIFF_OUTPUT as context to each:
quick-code-review (subagent_type: general-purpose):
Analyze the following uncommitted diff for:
- Mock/stub code in production paths
- Placeholder or TODO implementations that shouldn't be committed
- Commented-out code blocks
- Obvious logic errors
Diff:
$DIFF_OUTPUTReport findings as a list with file:line references. If nothing found, say "CLEAN".
quick-security-scan (subagent_type: general-purpose):
Scan the following uncommitted diff for:
- Hardcoded credentials, API keys, tokens, or secrets
- Private keys or certificates
- PII exposure (emails, passwords in plaintext)
- .env files or sensitive config being committed
Diff:
$DIFF_OUTPUTBe extremely strict. Report findings with file:line references. If nothing found, say "CLEAN".
quick-error-check (subagent_type: general-purpose):
Analyze the following uncommitted diff for:
- Empty catch/except blocks
- Swallowed errors (caught but not logged or re-thrown)
- Fallback values without logging
- Missing error boundaries or error handling
Diff:
$DIFF_OUTPUTReport findings with file:line references. If nothing found, say "CLEAN".
2. Gate Check
First, verify all spawned agents completed successfully. If any agent failed to run or timed out, inform the user which audit is missing and ask whether to proceed with partial results or abort.
Synthesize findings from all spawned agents.
IF CRITICAL ISSUES (secrets, production mocks, silent failures):
- Display blocking issues with file:line references
- Use AskUserQuestion to ask:
- "Fix issues before submitting (Recommended)"
- "Submit anyway"
- "Abort"
- If "Fix issues" → stop and let the user fix them
- If "Abort" → stop entirely
IF MINOR ISSUES (TODOs, style, minor logic):
- Display warnings
- 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.
# 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:
git add -- "<file1>" "<file2>"
2. Generate Conventional Commit Message
Analyze the staged diff to determine the commit type and scope:
git diff --cached --stat
git diff --cached
Generate a conventional commit message following this format:
feat:— new featurefix:— bug fixrefactor:— code restructuringdocs:— documentation changestest:— test additions/changeschore:— 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:
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):
gt modify -m "<conventional commit message>"
If --amend (modifying current branch):
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:
gt stack restack
Then submit with flags based on .graphite.yml values:
gt submit --no-interactive
Append flags to the submit command (only if set and non-empty):
- If
$GW_DRAFTistrue(and no explicit--publishargument): add--draft - If
$GW_MERGE_WHEN_READYistrue: add--merge-when-ready
After submitting, confirm the new stack state:
gt log short
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-runis used) - User provided with PR link and stack context