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
22 changes: 17 additions & 5 deletions .github/agents/speckit.taskstoissues.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ description: Convert existing tasks into actionable, dependency-ordered GitHub i
tools: ['github/github-mcp-server/issue_write']
---

# Speckit Tasks To Issues Agent

## User Input

```text
Expand All @@ -14,6 +16,7 @@ You **MUST** consider the user input before proceeding (if not empty).
## Pre-Execution Checks

**Check for extension hooks (before tasks-to-issues conversion)**:

- Check if `.specify/extensions.yml` exists in the project root.
- If it exists, read it and look for entries under the `hooks.before_taskstoissues` key
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
Expand All @@ -23,7 +26,8 @@ You **MUST** consider the user input before proceeding (if not empty).
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
- For each executable hook, output the following based on its `optional` flag:
- **Optional hook** (`optional: true`):
```

```text
## Extension Hooks

**Optional Pre-Hook**: {extension}
Expand All @@ -33,8 +37,10 @@ You **MUST** consider the user input before proceeding (if not empty).
Prompt: {prompt}
To execute: `/{command}`
```

- **Mandatory hook** (`optional: false`):
```

```text
## Extension Hooks

**Automatic Pre-Hook**: {extension}
Expand All @@ -43,6 +49,7 @@ You **MUST** consider the user input before proceeding (if not empty).

Wait for the result of the hook command before proceeding to the Outline.
```

- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently

## Outline
Expand All @@ -66,7 +73,8 @@ git config --get remote.origin.url
## Post-Execution Checks

**Check for extension hooks (after tasks-to-issues conversion)**:
Check if `.specify/extensions.yml` exists in the project root.

- Check if `.specify/extensions.yml` exists in the project root.
- If it exists, read it and look for entries under the `hooks.after_taskstoissues` key
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
Expand All @@ -75,7 +83,8 @@ Check if `.specify/extensions.yml` exists in the project root.
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
- For each executable hook, output the following based on its `optional` flag:
- **Optional hook** (`optional: true`):
```

```text
## Extension Hooks

**Optional Hook**: {extension}
Expand All @@ -85,12 +94,15 @@ Check if `.specify/extensions.yml` exists in the project root.
Prompt: {prompt}
To execute: `/{command}`
```

- **Mandatory hook** (`optional: false`):
```

```text
## Extension Hooks

**Automatic Hook**: {extension}
Executing: `/{command}`
EXECUTE_COMMAND: {command}
```

- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
2 changes: 2 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Copilot Instructions

<!-- SPECKIT START -->
For additional context about technologies to be used, project structure,
shell commands, and other important information, read the current plan
Expand Down
12 changes: 11 additions & 1 deletion .markdownlint.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
{
"MD013": false
"MD013": false,
"MD029": false,
"MD031": false,
"MD032": false,
"MD033": false,
"MD040": false,
"MD041": false,
"MD047": false,
"MD060": {
"style": "spaced"
}
}
1 change: 1 addition & 0 deletions .specify/extensions/git/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ specify extension enable git
## Graceful Degradation

When Git is not installed or the directory is not a Git repository:

- Spec directories are still created under `specs/`
- Branch creation is skipped with a warning
- Branch validation is skipped with a warning
Expand Down
5 changes: 5 additions & 0 deletions .specify/extensions/git/commands/speckit.git.feature.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ You **MUST** consider the user input before proceeding (if not empty).
## Environment Variable Override

If the user explicitly provided `GIT_BRANCH_NAME` (e.g., via environment variable, argument, or in their request), pass it through to the script by setting the `GIT_BRANCH_NAME` environment variable before invoking the script. When `GIT_BRANCH_NAME` is set:

- The script uses the exact value as the branch name, bypassing all prefix/suffix generation
- `--short-name`, `--number`, and `--timestamp` flags are ignored
- `FEATURE_NUM` is extracted from the name if it starts with a numeric prefix, otherwise set to the full branch name
Expand All @@ -37,6 +38,7 @@ Determine the branch numbering strategy by checking configuration in this order:
## Execution

Generate a concise short name (2-4 words) for the branch:

- Analyze the feature description and extract the most meaningful keywords
- Use action-noun format when possible (e.g., "add-user-auth", "fix-payment-bug")
- Preserve technical terms and acronyms (OAuth2, API, JWT, etc.)
Expand All @@ -49,6 +51,7 @@ Run the appropriate script based on your platform:
- **PowerShell (timestamp)**: `.specify/extensions/git/scripts/powershell/create-new-feature.ps1 -Json -Timestamp -ShortName "<short-name>" "<feature description>"`

**IMPORTANT**:

- Do NOT pass `--number` — the script determines the correct next number automatically
- Always include the JSON flag (`--json` for Bash, `-Json` for PowerShell) so the output can be parsed reliably
- You must only ever run this script once per feature
Expand All @@ -57,11 +60,13 @@ Run the appropriate script based on your platform:
## Graceful Degradation

If Git is not installed or the current directory is not a Git repository:

- Branch creation is skipped with a warning: `[specify] Warning: Git repository not detected; skipped branch creation`
- The script still outputs `BRANCH_NAME` and `FEATURE_NUM` so the caller can reference them

## Output

The script outputs JSON with:

- `BRANCH_NAME`: The branch name (e.g., `003-user-auth` or `20260319-143022-user-auth`)
- `FEATURE_NUM`: The numeric or timestamp prefix used
6 changes: 6 additions & 0 deletions .specify/extensions/git/commands/speckit.git.initialize.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@ Run the appropriate script from the project root:
- **PowerShell**: `.specify/extensions/git/scripts/powershell/initialize-repo.ps1`

If the extension scripts are not found, fall back to:

- **Bash**: `git init && git add . && git commit -m "Initial commit from Specify template"`
- **PowerShell**: `git init; git add .; git commit -m "Initial commit from Specify template"`

The script handles all checks internally:

- Skips if Git is not available
- Skips if already inside a Git repository
- Runs `git init`, `git add .`, and `git commit` with an initial commit message

## Customization

Replace the script to add project-specific Git initialization steps:

- Custom `.gitignore` templates
- Default branch naming (`git config init.defaultBranch`)
- Git LFS setup
Expand All @@ -35,15 +38,18 @@ Replace the script to add project-specific Git initialization steps:
## Output

On success:

- `✓ Git repository initialized`

## Graceful Degradation

If Git is not installed:

- Warn the user
- Skip repository initialization
- The project continues to function without Git (specs can still be created under `specs/`)

If Git is installed but `git init`, `git add .`, or `git commit` fails:

- Surface the error to the user
- Stop this command rather than continuing with a partially initialized repository
5 changes: 4 additions & 1 deletion .specify/extensions/git/commands/speckit.git.remote.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ Detect the Git remote URL for integration with GitHub services (e.g., issue crea

- Check if Git is available by running `git rev-parse --is-inside-work-tree 2>/dev/null`
- If Git is not available, output a warning and return empty:
```

```text
[specify] Warning: Git repository not detected; cannot determine remote URL
```

Expand All @@ -31,6 +32,7 @@ Parse the remote URL and determine:
3. **Is GitHub**: Whether the remote points to a GitHub repository

Supported URL formats:

- HTTPS: `https://github.com/<owner>/<repo>.git`
- SSH: `git@github.com:<owner>/<repo>.git`

Expand All @@ -41,5 +43,6 @@ Supported URL formats:
## Graceful Degradation

If Git is not installed, the directory is not a Git repository, or no remote is configured:

- Return an empty result
- Do NOT error — other workflows should continue without Git remote information
6 changes: 5 additions & 1 deletion .specify/extensions/git/commands/speckit.git.validate.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ Validate that the current Git branch follows the expected feature branch naming

- Check if Git is available by running `git rev-parse --is-inside-work-tree 2>/dev/null`
- If Git is not available, output a warning and skip validation:
```

```text
[specify] Warning: Git repository not detected; skipped branch validation
```

Expand All @@ -30,6 +31,7 @@ The branch name must match one of these patterns:
## Execution

If on a feature branch (matches either pattern):

- Output: `✓ On feature branch: <branch-name>`
- Check if the corresponding spec directory exists under `specs/`:
- For sequential branches, look for `specs/<prefix>-*` where prefix matches the numeric portion
Expand All @@ -38,12 +40,14 @@ If on a feature branch (matches either pattern):
- If spec directory missing: `⚠ No spec directory found for prefix <prefix>`

If NOT on a feature branch:

- Output: `✗ Not on a feature branch. Current branch: <branch-name>`
- Output: `Feature branches should be named like: 001-feature-name or 20260319-143022-feature-name`

## Graceful Degradation

If Git is not installed or the directory is not a Git repository:

- Check the `SPECIFY_FEATURE` environment variable as a fallback
- If set, validate that value against the naming patterns
- If not set, skip validation with a warning
2 changes: 1 addition & 1 deletion Models/OllamaModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace SymptomCheckerApp.Models
public class OllamaChatRequest
{
[JsonPropertyName("model")]
public string Model { get; set; } = "kimi-k2.6";
public string Model { get; set; } = "gemma4";

[JsonPropertyName("messages")]
public List<OllamaChatMessage> Messages { get; set; } = new();
Expand Down
59 changes: 10 additions & 49 deletions Services/OllamaService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace SymptomCheckerApp.Services
public class OllamaService : IDisposable
{
public const string DefaultBaseUrl = "http://localhost:11434";
public const string DefaultModelName = "kimi-k2.6";
public const string DefaultModelName = "gemma4";
private const int DiagnosisMaxTokens = 2600;
private const int MedicationMaxTokens = 2200;

Expand Down Expand Up @@ -129,57 +129,18 @@ public async Task<List<string>> ListModelsAsync(CancellationToken ct = default)
return exactMatch;
}

string? bestModel = null;
int bestScore = int.MinValue;

foreach (var model in availableModels)
{
int score = ScoreModelPreference(model, requested);
if (score > bestScore)
{
bestScore = score;
bestModel = model;
}
}

return bestModel ?? availableModels[0];
}

private static int ScoreModelPreference(string modelName, string preferredModel)
{
var normalizedName = NormalizeModelName(modelName);
var normalizedPreferred = NormalizeModelName(preferredModel);
int score = 0;

if (normalizedName == normalizedPreferred)
// If the requested value is a family name (e.g. "gemma4"), allow
// selecting tagged variants like "gemma4:latest".
var normalizedRequested = NormalizeModelName(requested);
var familyMatch = availableModels.FirstOrDefault(model =>
NormalizeModelName(model).StartsWith(normalizedRequested, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(familyMatch))
{
score += 1000;
return familyMatch;
}

if (normalizedPreferred.Contains("kimi", StringComparison.OrdinalIgnoreCase) &&
normalizedName.Contains("kimi", StringComparison.OrdinalIgnoreCase))
{
score += 500;
}

if (normalizedPreferred.Contains("k2", StringComparison.OrdinalIgnoreCase) &&
normalizedName.Contains("k2", StringComparison.OrdinalIgnoreCase))
{
score += 250;
}

if (normalizedPreferred.Contains("26", StringComparison.OrdinalIgnoreCase) &&
normalizedName.Contains("26", StringComparison.OrdinalIgnoreCase))
{
score += 120;
}

if (normalizedName.Contains("kimi", StringComparison.OrdinalIgnoreCase)) score += 300;
if (normalizedName.Contains("k2", StringComparison.OrdinalIgnoreCase)) score += 150;
if (normalizedName.Contains("llama", StringComparison.OrdinalIgnoreCase)) score += 50;
if (normalizedName.Contains("mistral", StringComparison.OrdinalIgnoreCase)) score += 40;

return score;
// Requested default not available: choose the first existing model.
return availableModels[0];
}

private static string NormalizeModelName(string value)
Expand Down
Loading
Loading