Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .agent-os/specs/2025-10-12-stop-hook-context-#98/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Spec Requirements Document

> Spec: Stop-Hook Context Enhancement
> Created: 2025-10-12
> GitHub Issue: #98
> Status: Planning

## Overview

Enhance the stop-hook commit reminder system to provide context-aware information (GitHub issue, active spec, current branch) making commit messages more actionable and reducing friction in the commit workflow.

## User Stories

### Context-Aware Commit Reminders

As a developer using Agent OS, I want the stop-hook to show me what issue I'm working on and my current branch, so that I can quickly write meaningful commit messages without context-switching to check my current work.

When I see the stop-hook reminder, I often need to run `git branch` or check my GitHub issues to remember what I'm working on. This breaks my flow and adds unnecessary friction. The stop-hook should automatically show me the relevant context including the issue number from my branch name, the active spec folder if I'm in an Agent OS workflow, and suggest a properly formatted commit message with the issue reference.

### Smart Commit Message Suggestions

As a developer who wants to follow commit conventions, I want the stop-hook to suggest commit messages based on my current work context, so that I can maintain consistent, well-formatted commit messages without thinking about the format.

Instead of seeing a generic "describe your work" placeholder, I want to see a suggested commit message like `feat: add context extraction to stop-hook #98` that already includes the issue number and follows conventional commit format.

## Spec Scope

1. **Branch Context Extraction** - Display current branch name in stop-hook message
2. **Issue Number Detection** - Extract and show GitHub issue number from branch name (supports #123, 123-, and other patterns)
3. **Active Spec Display** - Show active Agent OS spec folder when working on a spec
4. **Smart Commit Suggestions** - Generate context-aware commit message suggestions with issue references
5. **Performance Optimization** - Keep message generation fast (<50ms) with no external API calls

## Out of Scope

- GitHub CLI integration for issue titles (future enhancement)
- Cached issue metadata with TTL
- Conventional commit type detection based on changed files
- Work session mode integration (separate feature)

## Expected Deliverable

1. **Enhanced Stop-Hook Messages** - Stop-hook displays branch, issue #, and spec context when available, with graceful fallback when context is missing
2. **Commit Message Generation** - Smart suggestions include issue number in proper format (`feat: description #123`)
3. **Performance Maintained** - Message generation adds <50ms latency, no external dependencies or API calls

## Spec Documentation

- Tasks: @.agent-os/specs/2025-10-12-stop-hook-context-#98/tasks.md
- Technical Specification: @.agent-os/specs/2025-10-12-stop-hook-context-#98/sub-specs/technical-spec.md
- Tests Specification: @.agent-os/specs/2025-10-12-stop-hook-context-#98/sub-specs/tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# Technical Specification

This is the technical specification for the spec detailed in @.agent-os/specs/2025-10-12-stop-hook-context-#98/spec.md

> Created: 2025-10-12
> Version: 1.0.0

## Technical Requirements

### Context Extraction Functions

All required helper functions already exist in sourced libraries:

- **`get_current_branch()`** - `hooks/lib/git-utils.sh:23-30`
- Returns current git branch name
- Handles error cases (not-a-git-repo, unknown)

- **`extract_github_issue(source)`** - `hooks/lib/git-utils.sh:136-152`
- Extracts issue number from branch name or commits
- Supports patterns: `feature-#123`, `#123-feature`, `123-feature`
- Returns empty string if no issue found

- **`detect_current_spec()`** - `hooks/lib/workflow-detector.sh:156-169`
- Finds most recent spec in `.agent-os/specs/`
- Returns basename like "2025-10-12-feature-name-#98"
- Returns empty if no specs found

### Message Generation Enhancement

**Current implementation:** `hooks/stop-hook.sh:190-210`

The `generate_stop_message()` function needs modification to:
1. Call git context functions (already sourced at lines 18-29)
2. Build context lines conditionally
3. Generate smart commit message suggestions
4. Insert context into message template

### Performance Requirements

- **Target latency**: < 50ms added to existing message generation
- **No external dependencies**: Git commands only, no GitHub CLI
- **Graceful degradation**: Empty strings when context unavailable
- **Rate limiting preserved**: Existing 5-minute TTL still applies

## Approach Options

### Option A: Inline Context Extraction (Selected)

Extract context directly in `generate_stop_message()` function.

**Pros:**
- Simple, straightforward implementation
- No new functions needed
- Easy to test and debug
- Minimal code changes

**Cons:**
- Slightly longer function body
- Context extraction happens on every call (but rate-limited anyway)

### Option B: Separate Context Builder Function

Create new `build_commit_context()` function that returns structured data.

**Pros:**
- Cleaner separation of concerns
- Easier to unit test context extraction
- Reusable if other hooks need context

**Cons:**
- More complex implementation
- Additional function adds indirection
- Over-engineering for current need

**Rationale:** Option A is selected for simplicity. The context extraction is straightforward and only used in one place. The existing rate limiting (5-minute TTL) means performance impact is negligible. If other hooks need similar context in the future, we can refactor to Option B.

## Implementation Details

### Context Lines Construction

```bash
# Extract context
local current_branch=""
local issue_num=""
local spec_folder=""

if is_git_repo "$project_root"; then
current_branch=$(git -C "$project_root" branch --show-current 2>/dev/null || echo "")

if [ -n "$current_branch" ]; then
issue_num=$(cd "$project_root" && extract_github_issue "branch")
fi

if [ -d "$project_root/.agent-os/specs" ]; then
spec_folder=$(cd "$project_root" && detect_current_spec)
fi
fi

# Build context lines
local context_lines=""
if [ -n "$current_branch" ]; then
context_lines="${context_lines}Branch: $current_branch\n"
fi
if [ -n "$issue_num" ]; then
context_lines="${context_lines}GitHub Issue: #$issue_num\n"
fi
if [ -n "$spec_folder" ]; then
context_lines="${context_lines}Active Spec: $spec_folder\n"
fi
```

### Commit Message Suggestion Logic

```bash
# Generate smart commit message suggestion
local commit_suggestion=""
if [ -n "$issue_num" ]; then
# With issue number
commit_suggestion=" git commit -m \"feat: describe changes #${issue_num}\""
else
# Without issue number (fallback)
commit_suggestion=" git commit -m \"describe your work\""
fi
```

### Message Template Integration

Insert context lines after "Project:" line and before "Detected X files..." line.

Insert suggested commit as new section after file count and before "Next steps:".

## External Dependencies

No new external dependencies required. All functionality uses:
- **Existing git commands** - Already used throughout stop-hook
- **Sourced helper functions** - Already loaded from lib/ directory
- **Bash string manipulation** - Standard bash features

## Error Handling

### Missing Git Repository
- `is_git_repo()` check prevents execution in non-git directories
- Already handled by existing stop-hook logic

### Branch Name Edge Cases
- Detached HEAD: `get_current_branch()` returns "unknown"
- No branches: Empty string returned, gracefully skipped

### Issue Number Patterns
- Multiple patterns supported by `extract_github_issue()`
- No issue found: Empty string, suggestion shows generic message

### Missing Spec Folder
- `.agent-os/specs` doesn't exist: Directory check fails, skipped
- No specs in folder: `detect_current_spec()` returns empty string

All error cases result in graceful degradation - context lines simply omitted from message.

## Testing Strategy

### Unit Tests Required

1. **Branch extraction** - Test `get_current_branch()` with various repo states
2. **Issue parsing** - Test all supported branch naming patterns
3. **Spec detection** - Test with/without specs, multiple specs
4. **Message generation** - Test complete message with all context variations

### Integration Tests Required

1. **Stop-hook with context** - Full hook execution with branch/issue/spec
2. **Stop-hook without context** - Verify graceful fallback
3. **Performance measurement** - Ensure < 50ms added latency

### Test File Locations

- `tests/test-stop-hook-context.sh` - Unit tests for context extraction
- `tests/integration/test-stop-hook-full.sh` - Integration test (if needed)
122 changes: 122 additions & 0 deletions .agent-os/specs/2025-10-12-stop-hook-context-#98/sub-specs/tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Tests Specification

This is the tests coverage details for the spec detailed in @.agent-os/specs/2025-10-12-stop-hook-context-#98/spec.md

> Created: 2025-10-12
> Version: 1.0.0

## Test Coverage

### Unit Tests

**Context Extraction Functions**
- Test `extract_github_issue("branch")` with pattern: `feature-#123-description`
- Test `extract_github_issue("branch")` with pattern: `123-feature-name`
- Test `extract_github_issue("branch")` with pattern: `#123-feature`
- Test `extract_github_issue("branch")` with no issue number (returns empty)
- Test `get_current_branch()` in normal repository
- Test `get_current_branch()` in detached HEAD state
- Test `get_current_branch()` in non-git directory
- Test `detect_current_spec()` with single spec folder
- Test `detect_current_spec()` with multiple spec folders (returns most recent)
- Test `detect_current_spec()` with no spec folders (returns empty)

**Message Generation**
- Test `generate_stop_message()` with all context available (branch, issue, spec)
- Test `generate_stop_message()` with only branch available
- Test `generate_stop_message()` with only issue available
- Test `generate_stop_message()` with no context (graceful fallback)
- Test commit message suggestion with issue number
- Test commit message suggestion without issue number
- Verify context lines formatting (newlines, spacing)

### Integration Tests

**Stop-Hook Execution**
- Test stop-hook triggers with uncommitted changes on feature branch with issue
- Test stop-hook message includes branch name
- Test stop-hook message includes GitHub issue number
- Test stop-hook message includes active spec folder
- Test stop-hook message includes suggested commit format
- Test stop-hook rate limiting still functions (5-minute TTL)
- Test stop-hook suppression still works (AGENT_OS_HOOKS_QUIET=true)

**Performance Tests**
- Measure message generation latency with context extraction
- Verify total added time is < 50ms
- Test with large number of spec folders (performance doesn't degrade)

### Edge Case Tests

**Branch Naming Variations**
- Branch with multiple # symbols: `feature-#123-#456-name` (should extract first)
- Branch with issue at end: `feature-name-#123`
- Branch with issue in middle: `feature-#123-more-stuff`
- Branch without issue: `feature-branch` (empty issue, generic suggestion)
- Main/master branch: (empty issue, generic suggestion)

**Repository States**
- Not a git repository: stop-hook exits early (existing behavior)
- Git repo without .agent-os: no spec context shown
- Git repo with .agent-os but no specs: no spec context shown
- Detached HEAD state: shows "(detached)" or "unknown", no issue

**Error Conditions**
- Permission denied reading .agent-os/specs: graceful failure, no spec shown
- Invalid branch name characters: handled by git command
- Very long branch names: truncation if needed (test output formatting)

## Mocking Requirements

### File System Mocking
- **Mock .agent-os/specs/ directory** - Create temporary test directories with date-prefixed folders
- **Mock git repository** - Use temporary git repos for testing branch operations
- **Mock stop-hook environment** - Set project_root to test directory

### Git Command Mocking
- **Mock `git branch --show-current`** - Return controlled branch names for testing
- **Mock `git status --porcelain`** - Trigger stop-hook conditions
- **Mock `is_git_repo()`** - Control git repository detection

### Time-Based Mocking
- **Mock file timestamps** - Test "most recent spec" detection with controlled mtimes
- **Mock rate limiting** - Test TTL expiration without waiting 5 minutes

## Test Execution

### Running Tests

```bash
# Unit tests
bats tests/test-stop-hook-context.sh

# Integration tests (if created)
bash tests/integration/test-stop-hook-full.sh

# Performance tests
bash tests/performance/test-stop-hook-latency.sh
```

### Success Criteria

- All unit tests pass (100%)
- All integration tests pass (100%)
- Performance tests show < 50ms added latency
- Edge cases handled gracefully (no errors or crashes)
- Existing stop-hook functionality unchanged (regression tests pass)

## Test Maintenance

### When to Update Tests

- Any change to message format
- New branch naming patterns added
- Changes to context extraction logic
- Performance optimization changes

### Test Data

Store test data in `tests/fixtures/stop-hook-context/`:
- Sample branch names
- Mock spec folder structures
- Expected message outputs
Loading
Loading