Feature gaps identified by comparing gitAICommit against crabclaw's commit,
PR, branch, and provider orchestration. Each section now points at the exact
crabclaw file/function we can port or adapt, plus the current
gitAICommit code that would receive the change.
Gap: gitAICommit generates commit messages only. No PR support exists.
gitAICommit touch points:
src/main.rs:104-155— current generate/confirm/commit flowsrc/formatting/prompt.rs:21-150— commit-only prompt builder/template
crabclaw sources to port:
rust/crates/claw-cli/src/main.rs:1708-1738—run_pr()- builds a PR prompt from context + diff summary
- sanitizes output
- parses title/body
- shells out to
gh pr create --title ... --body-file ...
rust/crates/claw-cli/src/main.rs:2314-2322—parse_titled_body()rust/crates/claw-cli/src/main.rs:2301-2308—truncate_for_prompt()rust/crates/claw-cli/src/main.rs:2310-2312—sanitize_generated_message()
Adoption plan:
- Add
--pror aprsubcommand tosrc/cli/args.rs - Add a PR prompt mode to
PromptBuilder - Port
parse_titled_body()nearly verbatim - Reuse
truncate_for_prompt()for PR prompt payload limits - Write PR body to a temp file and call
gh pr create - Fallback to printing a draft when
ghis missing or fails
Gap: gitAICommit stops after git commit.
gitAICommit touch points:
src/main.rs:126-183— commit confirmation +perform_commit()src/git/collector.rs:232-245— current branch lookup
crabclaw sources to port:
rust/crates/commands/src/lib.rs:683-688—CommitPushPrRequestrust/crates/commands/src/lib.rs:810-915—handle_commit_push_pr_slash_command()rust/crates/commands/src/lib.rs:917-935—detect_default_branch()rust/crates/commands/src/lib.rs:1016-1050—build_branch_name()+slugify()rust/crates/commands/src/lib.rs:1052-1065— PR URL parsing helpersrust/crates/commands/src/lib.rs:1006-1013—write_temp_text_file()
Adoption plan:
- Add composable
--push,--pr, and--push-prflags - Extract post-generation workflow out of
src/main.rs - Port the commit/push/PR orchestration flow from
handle_commit_push_pr_slash_command() - Reuse the branch diff check against
<default>...HEAD - Reuse
gh pr view --json urlfallback when PR already exists
Gap: gitAICommit is Ollama-only.
gitAICommit touch points:
src/main.rs:58-65— hardwiresOllamaManagersrc/cli/args.rs:105-123— model selection assumes Ollamasrc/ollama/mod.rs:14-35—OllamaClientTraitsrc/ollama/client.rs— Ollama-only HTTP clientsrc/ollama/manager.rs— Ollama lifecycle management
crabclaw sources to port:
rust/crates/api/src/providers/mod.rs:12-24—Providertraitrust/crates/api/src/providers/mod.rs:26-32—ProviderKindrust/crates/api/src/providers/mod.rs:144-209— model aliasing + provider detectionrust/crates/api/src/client.rs:21-90—ProviderClientdispatch layerrust/crates/api/src/providers/openai_compat.rs:26-117—OpenAiCompatConfig+OpenAiCompatClient::{new,from_env,for_ollama}rust/crates/claw-cli/src/main.rs:1617-1622— provider-agnostic call site viarun_internal_prompt_text()
Adoption plan:
- Replace
OllamaClientTraitwith a provider-neutral trait/interface - Add a small
ProviderKindenum andProviderClient-style dispatch layer - Keep Ollama as one backend
- Port the OpenAI-compatible client shape for OpenAI and other
/v1/chat/completionsproviders - Move provider/base URL/API key selection into config + env resolution
- Completed TDD slice: route the real CLI through a provider-neutral manager while preserving Ollama as the default backend
tests/list_models_test.rs— addedtest_list_models_with_explicit_ollama_provider_flagsrc/main.rs— replaced the top-levelOllamaManagerwiring withllm::LlmManager, so--list-models, model checks, startup, and generation now go through one provider-neutral entrypointsrc/llm/mod.rs— addedProviderKind,LlmManagerOptions, andLlmManagerwith realOllamaandOpenAiCompatiblebackendssrc/llm/mod.rs— added an OpenAI-compatible/v1/modelsand/v1/chat/completionsclient shape so the abstraction is real, not a placeholdersrc/cli/args.rs— added--provider,--base-url, and--api-keysrc/config.rs— added persistedprovider,base_url, andapi_keyfields so provider selection is not CLI-onlytests/cli_args_test.rsandtests/config_test.rs— extended coverage for provider/base URL/API key parsing and config loading- Leveraged
gitsumintelligence's provider-neutral config and enum shape from/home/npiesco/gitsumintelligence/src/llm/provider.rsinstead of inventing another provider descriptor - Leveraged
ailighter's factory and OpenAI-compatible client pattern from /home/npiesco/ailighter/src-tauri/src/llm/factory.rs and /home/npiesco/ailighter/src-tauri/src/llm/providers/generic_openai.rs instead of inventing another HTTP shape
- Completed TDD slice:
openai-compatiblenow honors the local provider port when no explicit base URL is suppliedtests/list_models_test.rs— addedtest_list_models_with_openai_compatible_provider_uses_local_ollama_porttests/list_models_test.rs— boots a real local Ollama process throughOllamaManager::ensure_running()and then exercises the realgit-ai-commitbinary with--provider openai-compatible --port 11434 --list-modelssrc/llm/mod.rs— changedLlmManager::new()so theopenai-compatiblebackend defaults tohttp://localhost:{port}instead ofhttps://api.openai.comwhen--base-urlis omittedsrc/llm/mod.rs— keeps explicit--base-urloverride behavior intact while making the local-provider path usable for Ollama's/v1/modelsand/v1/chat/completionsendpoints- Leveraged
ailighter's local OpenAI-format provider pattern from /home/npiesco/ailighter/src-tauri/src/llm/factory.rs and /home/npiesco/ailighter/src-tauri/src/llm/providers/generic_openai.rs, specifically the idea that a local OpenAI-compatible backend should be addressable from local connection settings rather than hardcoded cloud defaults
- Completed TDD slice: non-Ollama providers no longer inherit Ollama default-model discovery
tests/cli_args_test.rs— addedtest_openai_compatible_provider_requires_explicit_modelsrc/cli/args.rs—Args::normalize_provider_defaults()now clears the implicit Ollama-derived model when--provider openai-compatibleis selected without an explicit--modelsrc/main.rs— added a provider-aware runtime guard so non-Ollama providers fail clearly if--modelis omitted- Leveraged
gitsumintelligence's provider-aware config semantics from/home/npiesco/gitsumintelligence/src/llm/provider.rsandcrabclaw's provider dispatch direction fromrust/crates/api/src/providers/mod.rs:144-209instead of keeping Ollama-specific defaulting logic at the top level
- Completed TDD slice: end-to-end
openai-compatiblegeneration now works against the real local Ollama pathtests/interactive_test.rs— addedtest_openai_compatible_provider_generates_commit_message_via_local_ollamasrc/llm/mod.rs—OpenAiCompatibleManager::generate_commit()now tries/v1/chat/completionsfirst, then falls back to native Ollama endpoints on local404responsessrc/llm/mod.rs— native fallback now supports both/api/chatand/api/generate, reusing the message-oriented Ollama shape instead of assuming one endpointsrc/ollama/client.rs— tightenedOllamaClient::is_running()so only successful/api/tagsresponses count as a healthy Ollama server;404no longer fools the provider tests into skipping real startuptests/interactive_test.rsandtests/list_models_test.rs— real Ollama-backed integration tests now run on a serializedserial(ollama)lane and keep the bootedOllamaManageralive for the duration of the test instead of dropping it immediately- Leveraged
crabclaw's OpenAI-compatible client boundary fromrust/crates/api/src/providers/openai_compat.rs:26-117,gitsumintelligence's native Ollama chat request shape from/home/npiesco/gitsumintelligence/src/llm/providers/ollama.rs, andailighter's native Ollama generate path from/home/npiesco/ailighter/src-tauri/src/llm/providers/ollama.rsrather than inventing another local-provider compatibility layer
- Completed TDD slice: provider-specific empty-list guidance for
--list-modelsnow lives behind the provider-neutral managertests/list_models_test.rs— addedtest_list_models_with_openai_compatible_provider_does_not_print_ollama_pull_hintsrc/llm/mod.rs— addedModelListingsoLlmManager::list_models()returns both model names and provider-aware empty-state guidance instead of a bareVec<String>src/llm/mod.rs—Ollamakeeps the existingollama pull <model>hint, whileOpenAiCompatiblenow returns the neutral messageNo models found for provider 'openai-compatible'.src/main.rs— the CLI now renders provider-aware empty-state text fromLlmManagerinstead of hardcoding an Ollama-only hint at the top level- Leveraged
crabclaw's provider-dispatch shape fromrust/crates/api/src/client.rs:21-90andrust/crates/api/src/providers/mod.rs:144-209by pushing provider-specific behavior behind the provider-neutral boundary instead of adding anotherif provider == ...branch inmain.rs
- Completed TDD slice: provider-specific model readiness now lives behind the provider-neutral manager
tests/interactive_test.rs— addedtest_openai_compatible_provider_fails_early_when_model_is_missingsrc/llm/mod.rs—LlmManager::ensure_model_available()now delegates readiness checks foropenai-compatibleinstead of silently no-oping outside Ollamasrc/llm/mod.rs—OpenAiCompatibleManager::ensure_model_available()now verifies the selected model against/v1/modelsbefore generation and fails withModel '<name>' is not available for provider 'openai-compatible'src/llm/mod.rs— extractedfetch_model_ids()so list-models and readiness checks share the same provider-native discovery path instead of duplicating endpoint logic- Leveraged
crabclaw's provider-neutral dispatch boundary fromrust/crates/api/src/client.rs:21-90andrust/crates/api/src/providers/mod.rs:144-209by moving readiness into the provider layer, not by adding another startup special-case inmain.rs
- Next TDD target:
- move provider-specific startup assumptions fully behind the provider-neutral layer so non-Ollama providers no longer emit Ollama-shaped startup logging like
[START] Starting Ollama...
- move provider-specific startup assumptions fully behind the provider-neutral layer so non-Ollama providers no longer emit Ollama-shaped startup logging like
- Completed TDD slice: route the real CLI through a provider-neutral manager while preserving Ollama as the default backend
Gap: gitAICommit commits raw model output.
gitAICommit touch points:
src/main.rs:114-150— generated text is displayed and committed without cleanupsrc/main.rs:170-183—perform_commit()usesgit commit -m
crabclaw sources to port:
rust/crates/claw-cli/src/main.rs:2310-2312—sanitize_generated_message()rust/crates/claw-cli/src/main.rs:1684-1694— sanitized commit flow usinggit commit --file
Adoption plan:
- Add
sanitize_commit_message()insrc/main.rsor a small helper module - Sanitize before dry-run display and before actual commit
- Prefer
git commit --file <tempfile>overgit commit -mso multi-line messages remain intact - Extend the sanitizer slightly beyond
crabclawto strip common LLM preambles if needed
Gap: gitAICommit uses file-name/stat summaries only, with rough line-cost heuristics.
gitAICommit touch points:
src/formatting/prompt.rs:32-128— staged/unstaged summary assembly + heuristic truncationsrc/git/collector.rs:121-157— collectsgit diff --numstat, not hunkssrc/git/collector.rs:160-209— collects file change list
crabclaw sources to port:
rust/crates/claw-cli/src/main.rs:1709-1715— usesgit diff --statin prompt constructionrust/crates/claw-cli/src/main.rs:2301-2308—truncate_for_prompt()
Adoption plan:
- Keep
gitAICommit's staged/unstaged grouping and file tagging - Port
truncate_for_prompt()for deterministic character-bound truncation - Add an optional hunk mode that collects real staged diff content
- Sort/prioritize files by change magnitude before truncation
- Preserve config/test tagging in the prompt output
Gap: gitAICommit does not know the repository default branch.
gitAICommit touch points:
src/git/collector.rs:232-245— only current branch detection exists- future push/PR workflow in
src/main.rs
crabclaw sources to port:
rust/crates/commands/src/lib.rs:917-935—detect_default_branch()rust/crates/commands/src/lib.rs:974-995—branch_exists()+current_branch()
Adoption plan:
- Add a
git::detect_default_branch()utility - Use it for PR base selection
- Use it for deciding whether to auto-create a feature branch
- Use it for the "no branch changes" diff check
Gap: gitAICommit has no branch management.
gitAICommit touch points:
- future push/PR workflow in
src/main.rs - possibly a new helper in
src/git/
crabclaw sources to port:
rust/crates/commands/src/lib.rs:1016-1050—build_branch_name()+slugify()
Adoption plan:
- Port
slugify()directly - Adapt
build_branch_name()to use commit subject or PR title as the hint - Add
--branch <name>override - Only auto-create when current branch equals detected default branch
Gap: --template exists but is ignored.
gitAICommit touch points:
src/cli/args.rs:183-195—template: Option<PathBuf>src/main.rs:61—PromptBuilder::new(...)receives no template inputsrc/formatting/prompt.rs:11-18— constructor always loadsdefault_template()src/formatting/prompt.rs:130-150— hardcoded default template
crabclaw sources to port/adapt:
- No direct template-loader exists in
crabclaw - Best reusable pattern is limited to prompt string assembly:
rust/crates/claw-cli/src/main.rs:1708-1715— build prompt from structured partsrust/crates/claw-cli/src/main.rs:2301-2308— trim prompt payloads before sending
Adoption plan:
- Change
PromptBuilder::new(...)to accept an optional template string/path - Load
--templateinsrc/main.rsbefore building the prompt - Keep
{CONTEXT}as the required placeholder in external templates - Optionally support named templates later, but first fix the broken file-path case
Gap: core git/CLI paths remain lightly tested.
gitAICommit undertested code:
src/git/collector.rs:77-293—GitCollectorsrc/git/status.rs:14-55—GitStatus::parse()src/git/diff.rs:20-57—DiffInfo::parse()src/git/files.rs:24-76—FileChange::parse_list()/parse_line()src/main.rs:71-155— staging, dry-run, confirm, commit flowsrc/ollama/manager.rs— lifecycle behavior
crabclaw sources to port:
rust/crates/commands/src/lib.rs:1669-1748— temp repo helpers:temp_dir(),env_lock(),run_command(),init_git_repo(),init_bare_repo()rust/crates/commands/src/lib.rs:1747-1760—write_fake_gh()rust/crates/commands/src/lib.rs:2421-2510— real repo integration tests for commit and commit+push+PRrust/crates/api/src/client.rs:128-147andrust/crates/api/src/providers/mod.rs:221-245— simple provider selection unit test style
Adoption plan:
- Add a shared test helper module for temp git repos
- Port the fake
ghbinary pattern for future PR tests - Add parser tests for rename/copy/unmerged cases
- Add integration tests for
--dry-run,--add-unstaged, and real commit creation - Set
user.name/user.emailinside test repos explicitly
Gap: gitAICommit has no explicit way to capture intent beyond git metadata.
gitAICommit touch points:
src/cli/args.rs— add a new--context <TEXT>flagsrc/formatting/prompt.rs:22-99— include user context in prompt rendering
crabclaw sources to port/adapt:
rust/crates/claw-cli/src/main.rs:2273-2299—recent_user_context()rust/crates/claw-cli/src/main.rs:1710-1714— PR prompt includesContext hint: ...rust/crates/claw-cli/src/main.rs:1680-1684— commit prompt includes extra context text
Adoption plan:
- Add a plain
--context "what changed and why"flag - Render that context ahead of diff data in the prompt
- Keep this simple;
crabclaw's session history logic is not directly portable, but the prompt shape is
| Priority | Feature | Effort | Impact | Best crabclaw source |
|---|---|---|---|---|
| P0 | Fix --template |
S | Medium | claw-cli/src/main.rs:1708-1715 |
| P0 | AI output sanitization | S | High | claw-cli/src/main.rs:2310-2312 |
| P1 | Test coverage gaps | M | High | commands/src/lib.rs:1669-1760, 2421-2510 |
| P1 | Multiple LLM providers | L | High | api/src/providers/mod.rs:12-24, api/src/client.rs:21-90 |
| P2 | PR title+body generation | M | High | claw-cli/src/main.rs:1708-1738, 2314-2322 |
| P2 | Default branch detection | S | Medium | commands/src/lib.rs:917-935 |
| P2 | --context flag |
S | Medium | claw-cli/src/main.rs:1680-1684, 2273-2299 |
| P3 | Combined commit+push+PR flow | L | High | commands/src/lib.rs:810-915 |
| P3 | Auto branch name generation | S | Medium | commands/src/lib.rs:1016-1050 |
| P3 | Smarter diff context | M | Medium | claw-cli/src/main.rs:2301-2308 |
| P3 | Commit message style parity with crabclaw |
M | High | claw-cli/src/main.rs:1680-1715, 2301-2312 |
-
P0 Fix
--template- Added a real file-backed template loading path in
gitAICommit:src/formatting/prompt.rs— addedPromptBuilder::from_template_file()and validated{CONTEXT}placeholder usagesrc/main.rs— now routesargs.templateinto the prompt builder instead of always usingPromptBuilder::new(...)
- Red test:
tests/prompt_builder_test.rs—test_prompt_builder_uses_custom_template_file
- Validation:
- focused red/green test passed
- full
cargo testpassed cargo fmt --allpassedcargo clippy --all-targets --all-features -- -D warningspassed- second full
cargo testpassed after lint fixes cargo build --releasepassed
- Porting note:
- leveraged
crabclawprompt assembly shape fromnpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:1708-1715 - reused the existing
gitAICommit{CONTEXT}substitution path rather than inventing a second prompt system
- leveraged
- Added a real file-backed template loading path in
-
P0 AI output sanitization
- Added a shared sanitized commit path in
gitAICommit:src/commit.rs— addedsanitize_commit_message()andcommit_message_to_repo()src/lib.rs— exported the new commit helpers for integration tests and reusesrc/main.rs— now sanitizes generated text before preview/dry-run and commits viagit commit --file
- Red test:
tests/commit_sanitization_test.rs—test_commit_message_is_sanitized_before_commit
- Validation:
- focused red/green test passed
- full
cargo testpassed cargo fmt --allpassedcargo clippy --all-targets --all-features -- -D warningspassed- second full
cargo testpassed after lint cargo build --releasepassed
- Porting note:
- leveraged
crabclawsanitizer behavior fromnpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:2310-2312—sanitize_generated_message() - leveraged
crabclaw's temp-file commit flow fromnpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:1684-1694instead of keepinggit commit -m - extended that port narrowly to strip common LLM preambles like
Here is the commit message:because the red integration test covered that real failure mode
- leveraged
- Remaining gap:
- this ports sanitization, not full message-style parity
gitAICommitstill lackscrabclaw's tighter prompt shaping and smarter diff/context trimming, so model output can still drift into chatty or overlong commit text- exact
crabclawsources still to port for style consistency:npiesco/crabclaw/rust/crates/claw-cli/src/main.rs:1680-1715— commit prompt shaping and structured context assemblynpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:2301-2308— smarter diff truncation before generation
- Added a shared sanitized commit path in
-
P1 Test coverage gaps
- Completed TDD slice: real staged rename coverage
tests/interactive_test.rs— addedtest_collect_all_reports_staged_rename_with_old_and_new_pathssrc/git/status.rs— fixedGitStatus::parse()so porcelain rename/copy entries record the destination path instaged_files
- Completed TDD slice: merge conflicts count as real repository changes
tests/interactive_test.rs— addedtest_collect_all_treats_merge_conflicts_as_non_empty_changessrc/git/status.rs— extendedGitStatus::parse()to capture porcelain unmerged states inunmerged_filessrc/git/collector.rs— updatedGitInfo::is_empty()so conflicted repos are not treated as empty
- Completed TDD slice: deduplicate diff stats when one file has both staged and unstaged edits
tests/interactive_test.rs— addedtest_collect_all_deduplicates_diff_stats_for_staged_and_unstaged_same_filesrc/git/diff.rs— updatedDiffInfo::parse()to merge repeated filenames into one aggregatedFileStatentry before computing totals
- Completed TDD slice: display untracked files only once in repository analysis output
tests/interactive_test.rs— addedtest_git_info_display_lists_untracked_files_oncesrc/git/collector.rs— updatedGitInfo::display()to rely onGitStatus::display()for untracked output instead of appending a duplicate section
- Completed TDD slice:
--add-unstagedstages deleted-only repos in the real CLI flowtests/interactive_test.rs— addedtest_add_unstaged_flag_stages_deleted_files_in_main_flowsrc/main.rs— updated the--add-unstagedgate so deleted files triggerstage_all_unstaged()alongside modified and untracked files
- Completed TDD slice: detect staged copies with original and new paths
tests/interactive_test.rs— addedtest_collect_all_reports_staged_copy_with_old_and_new_pathssrc/git/collector.rs— updatedget_file_changes()to request git rename/copy detection with--find-copies-harder, so staged copies are emitted asC...records instead of plain addssrc/git/files.rs— reused the existingFileChange::parse_line()support forChangeType::Copiedandold_pathpreservation rather than introducing a second copy parser
- Validation:
- focused red/green test passed
- full
cargo testpassed cargo fmt --allpassedcargo clippy --all-targets --all-features -- -D warningspassed- second full
cargo testpassed after lint cargo build --releasepassed
- Porting note:
- leveraged
crabclaw's real temp-repo integration testing style fromnpiesco/crabclaw/rust/crates/commands/src/lib.rs:1669-1748, specifically the helper-driven repo setup pattern behindtemp_dir(),env_lock(),run_command(), andinit_git_repo() - followed the same behavior-first repo test shape used by
npiesco/crabclaw/rust/crates/commands/src/lib.rs:2421-2510instead of adding another synthetic parser-only test
- leveraged
- Completed TDD slice: real staged rename coverage
-
P1 Multiple LLM providers
-
P2 PR title+body generation
-
P2 Default branch detection
-
P2
--contextflag -
P3 Combined commit+push+PR flow
-
P3 Auto branch name generation
-
P3 Smarter diff context
-
P3 Commit message style parity with
crabclaw- Goal:
- make generated commit messages consistently match
crabclaw's tighter style constraints instead of only sanitizing obviously bad output afterward
- make generated commit messages consistently match
- Completed TDD slice: prefer the conventional-commit line from chatty AI output
tests/commit_sanitization_test.rs— addedtest_commit_message_prefers_conventional_commit_from_chatty_outputsrc/commit.rs— extendedsanitize_commit_message()to extract the first conventional-commit-style subject line from mixed prose output before writing the commitsrc/commit.rs— added narrow conventional-commit detection sofix: ...andtype(scope): ...subjects are kept while explanatory chatter is dropped
- Completed TDD slice: default prompt uses staged-only commit context
tests/interactive_test.rs— addedtest_prompt_uses_staged_diff_summary_and_excludes_unstaged_detailstests/interactive_test.rs— updated the older prompt integration assertion to match staged-only commit behaviortests/prompt_builder_test.rs— updated prompt-builder expectations from the old broad template to the narrower staged-only commit contractsrc/formatting/prompt.rs— changedPromptBuilder::build()to include only staged file changes and staged diff statistics in the default commit promptsrc/formatting/prompt.rs— replaced the old generic template with a tightercrabclaw-style commit instruction focused on staged diff summary input
- Completed TDD slice: mark truncated staged prompt context explicitly
tests/interactive_test.rs— addedtest_prompt_marks_truncated_staged_context_when_limits_are_exceededsrc/formatting/prompt.rs— updatedadd_file_changes_to_context()to append…[truncated]when the staged prompt context exceeds configured limitssrc/formatting/prompt.rs— kept the existing structured section truncation flow, but aligned the truncation signal withcrabclawso prompt consumers can see that input was intentionally shortened
- Completed TDD slice: deterministically truncate staged prompt context by character budget
tests/interactive_test.rs— addedtest_prompt_truncates_single_oversized_staged_entry_by_character_budgetsrc/formatting/prompt.rs— replaced the rough staged entry size heuristic with atruncate_for_prompt()-style character-budget truncation pass over the rendered staged contextsrc/formatting/prompt.rs— kept the explicit…[truncated]marker and made oversized single entries truncate correctly instead of slipping past the budget because they counted as only one estimated file
- Completed TDD slice: remove extra default prompt scaffolding while preserving richer custom-template context
tests/prompt_builder_test.rs— addedtest_default_prompt_avoids_extra_instruction_block_and_repo_metadata_scaffoldingsrc/formatting/prompt.rs— removed the extraRequirements:block from the built-in default commit template so it matchescrabclaw's tighterrun_commit()contract more closelysrc/formatting/prompt.rs— stopped prependingCurrent branch:andLast commit:metadata in the built-in default prompt path, but preserved that richer context forPromptBuilder::from_template_file(...)and other custom-template renderstests/prompt_builder_test.rs— updated the older default-prompt assertions to reflect the narrower built-in contract while keeping the custom-template metadata assertion intact
- Completed TDD slice: explicit
--contextflag feeds a bounded conversation-context lane into the real CLI prompt flowtests/interactive_test.rs— addedtest_context_flag_is_included_in_default_prompt_via_real_cli_flowtests/cli_args_test.rs— addedtest_context_flagand extended the combined-options parse coveragesrc/cli/args.rs— added--context <TEXT>as a first-class customization flagsrc/main.rs— routedargs.contextinto the default prompt builder path without changing custom-template renderingsrc/formatting/prompt.rs— added an explicitRecent conversation context:lane for the built-in default prompt when user context is provided, bounded by the same prompt truncation helper
- Completed TDD slice: default prompt now follows
crabclaw's compact staged diff-stat contract instead of injecting extra staged-file scaffoldingtests/prompt_builder_test.rs— addedtest_default_prompt_uses_diff_stat_contract_without_extra_staged_file_scaffoldingtests/prompt_builder_test.rs— updated older default-prompt assertions so they validate compact staged diff-stat lines instead of the pre-portStaged changes (will be committed):blocktests/interactive_test.rs— updatedtest_prompt_prefers_staged_changes_onlyto assert staged diff summary plus staged filenames without reintroducing the removed scaffoldingsrc/formatting/prompt.rs— split built-in default prompt context from custom-template context so only the default path adopts the tightercrabclawcontractsrc/formatting/prompt.rs— changed the built-in default prompt to render staged diff summary plus compact per-file stat lines (path | +N -M) and to truncate that block on line boundaries with the existing…[truncated]markersrc/formatting/prompt.rs— preserved the richer staged file/change sections for custom templates so--templateusers still get the fuller{CONTEXT}payload
- Completed TDD slice: prose-only weak-model output now collapses to a single subject line instead of committing the whole paragraph block
tests/commit_sanitization_test.rs— addedtest_commit_message_falls_back_to_first_meaningful_line_when_model_returns_prosesrc/commit.rs— kept conventional-commit extraction as the primary path, but added a fallback to the first meaningful non-empty line when no conventional subject is presentsrc/commit.rs— preserved the temp-filegit commit --fileflow; the change stays strictly in the sanitizer boundary and does not invent a new commit pipeline
- Completed TDD slice: malformed single-line weak-model label echoes are stripped before commit
tests/commit_sanitization_test.rs— addedtest_commit_message_strips_malformed_single_line_prompt_labelssrc/commit.rs— added a narrow single-line cleanup pass that strips malformed... commit message:prefixes and leading bracketed prompt-label remnants before the existing fallback logic runssrc/commit.rs— kept conventional-commit extraction and first-line fallback unchanged as the primary decision path; this only removes weak-model prompt-label noise at the sanitizer boundary
- Completed TDD slice: glossary-style all-caps weak-model prefixes are stripped before commit
tests/commit_sanitization_test.rs— addedtest_commit_message_strips_glossary_style_all_caps_prefixessrc/commit.rs— extended the single-line cleanup pass withstrip_glossary_style_prefix()so outputs likeLORE (Logical OR Evaluator) [PRINCIPLE #3]: ...collapse to the usable subject instead of being committed verbatimsrc/commit.rs— kept this as a narrow sanitizer-boundary extension on top of the existing conventional-commit extraction and first-meaningful-line fallback, matchingcrabclaw's final-write cleanup placement rather than inventing a new generation path
- Completed TDD slice: trailing echoed prompt scaffolding is stripped from single-line conventional subjects
tests/commit_sanitization_test.rs— addedtest_commit_message_strips_trailing_echoed_prompt_scaffolding_from_single_line_subjectsrc/commit.rs— extended the single-line cleanup path withstrip_trailing_echoed_prompt_scaffolding()so outputs likefeat: ... - [Commit Message]: ...keep the conventional subject and drop the echoed prompt tailsrc/commit.rs— kept the change at the same final sanitizer boundary used bycrabclaw'ssanitize_generated_message()innpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:2310-2312, instead of inventing another prompt or generation flow
- Completed TDD slice: bracket-only boilerplate is rejected instead of being committed
tests/commit_sanitization_test.rs— addedtest_commit_message_rejects_bracket_only_boilerplate_after_sanitizationsrc/commit.rs— addedlooks_like_bracket_only_boilerplate()and madestrip_single_line_prompt_labels()collapse single-line bracket-only outputs like[Lorem Ipsum]to empty before conventional-subject extractionsrc/commit.rs— reused the existinggenerated commit message was emptyguard incommit_message_to_repo()so the real commit path now fails cleanly instead of creating a garbage commit, keeping the fix at the same final-write boundarycrabclawuses innpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:2310-2312
- Completed TDD slice: raw git commit-hash metadata is rejected instead of being committed
tests/commit_sanitization_test.rs— addedtest_commit_message_rejects_raw_git_commit_hash_metadatasrc/commit.rs— addedlooks_like_raw_git_metadata()and madestrip_single_line_prompt_labels()collapse single-line outputs likecommit 3d89b7c2f5a6...to empty before fallback selectionsrc/commit.rs— reused the samegenerated commit message was emptyguard incommit_message_to_repo(), preservingcrabclaw's final-write sanitizer boundary fromnpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:2310-2312instead of adding another prompt-time workaround
- Completed TDD slice: literal
git commit -mshell wrappers are rejected instead of being committedtests/commit_sanitization_test.rs— addedtest_commit_message_rejects_literal_git_commit_shell_wrappersrc/commit.rs— addedlooks_like_git_commit_shell_wrapper()and madestrip_single_line_prompt_labels()collapse single-line outputs likegit commit -m "..."to empty before fallback selectionsrc/commit.rs— reused the samegenerated commit message was emptyguard incommit_message_to_repo(), preservingcrabclaw's final-write sanitizer boundary fromnpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:2310-2312instead of adding another generation path
- Primary
gitAICommittouch points:src/formatting/prompt.rs— tighten prompt instructions and output contractsrc/main.rs— keep the generation path wired through the stricter prompt buildersrc/commit.rs— preserve sanitizer as a safety net, not the primary style control
crabclawfiles/functions to leverage instead of reinventing:npiesco/crabclaw/rust/crates/claw-cli/src/main.rs:1680-1715— commit prompt construction pathnpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:1795— exact defaultrun_commit()prompt wording centered on staged diff summary inputnpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:1862-1867—run_commit()uses onlygit diff --cached --statplus recent context, which is the compact default prompt contract now mirrored ingitAICommitnpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:1795and1842-1849—Recent conversation context:lane shape and bounded context injectionnpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:2301-2308—truncate_for_prompt()and its explicit…[truncated]marker used before generationnpiesco/crabclaw/rust/crates/claw-cli/src/main.rs:2310-2312— sanitizer remains the last-line cleanup layer
- Next TDD target:
- tighten sanitizer handling for remaining weak-model outputs that echo literal shell command wrappers like
git commit -m "..."as the entire generated "commit message"
- tighten sanitizer handling for remaining weak-model outputs that echo literal shell command wrappers like
- Validation:
- focused red/green test passed
- full
cargo testpassed cargo fmt --allpassedcargo clippy --all-targets --all-features -- -D warningspassed- second full
cargo testpassed after lint cargo build --releasepassed
- Goal: