Skip to content

Commit 3527b6e

Browse files
committed
remove wrong release files
1 parent 8098ca4 commit 3527b6e

8 files changed

Lines changed: 407 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,53 @@ All notable changes to the Specify CLI and templates are documented here.
77
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
88
and this project adheres to to [Semantic Versioning](https://semver.org/spec/v2.0.0/).
99

10+
## [0.0.115] - 2026-03-08
11+
12+
### Added
13+
14+
- **Context Auto-Discovery (Issue #47)**: Automatic team-ai-directives discovery
15+
- `discover_directives()` function with grep-based search for constitutions, personas, rules
16+
- Discovers relevant content from team-ai-directives directory structure
17+
- JSON output includes DISCOVERED_DIRECTIVES with file paths and search metadata
18+
- Support for both local paths and Git URL-based team-ai-directives
19+
20+
- **Skills Discovery (Issue #49)**: 5-layer skill discovery system
21+
- Manifest-based discovery from `.skills.json` (required/recommended/blocked skills)
22+
- Local skill discovery from team-ai-directives/skills/ with SKILL.md validation
23+
- Cache directory with 24h TTL refresh for performance optimization
24+
- URL fetching for remote manifest skills via manifest URLs
25+
- Automatic candidate extraction (max 5 skills, configurable threshold)
26+
- JSON output includes DISCOVERED_SKILLS with skill paths and relevance scores
27+
28+
- **Two-Tier Discovery Architecture**:
29+
- Layer 1 (Scripts): Fast, deterministic baseline discovery via grep search
30+
- Layer 2 (Templates): AI-powered semantic enhancement in command templates
31+
- Affects `/spec.specify` and `/spec.plan` templates with AI discovery sections
32+
33+
- **Template Updates**:
34+
- `context-template.md`: AI discovery sections for directives/skills with DISCOVERED_DIRECTIVES/DISCOVERED_SKILLS placeholders
35+
- `specify.md`: AI-Powered Discovery section after initial context generation
36+
- `plan.md`: AI-Powered Context/Skills Refresh section before implementation
37+
38+
### Changed
39+
40+
- **Team-AI-Directives Integration**: Discovery features automatically use team-ai-directives path
41+
- Supports both local paths (`~/workspace/team-ai-directives`) and Git URLs
42+
- Automatic Git cloning for remote repositories
43+
- Discovery results integrated into context.md generation
44+
45+
- **Skill Caching**: Daily refresh (24h TTL) for performance optimization
46+
- `skills-cache/.last_refresh` marker file for tracking cache age
47+
- Automatic cache rebuild when timestamp exceeds 24 hours
48+
- Graceful fallback when team-ai-directives unavailable
49+
50+
### Documentation
51+
52+
- Added Context Auto-Discovery and Skills Discovery features to README.md
53+
- Updated Team AI Directives integration section with discovery workflow
54+
- Added comprehensive discovery documentation to docs/discovery.md
55+
- Documented two-tier discovery architecture (scripts → templates)
56+
1057
## [0.0.114] - 2026-03-07
1158

1259
### Added

README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,65 @@ specify init my-project --debug
199199
specify init my-project --github-token $GITHUB_TOKEN
200200
```
201201

202+
#### Context Auto-Discovery & Skills Discovery
203+
204+
The toolkit includes automatic discovery of team directives and skills based on your feature description.
205+
206+
**Two-Tier Discovery Architecture:**
207+
208+
1. **Layer 1 (Scripts)**: Fast, deterministic baseline discovery
209+
- `discover_directives()`: Grep-based search of team-ai-directives for constitutions, personas, rules
210+
- `discover_skills()`: 5-layer discovery through manifest, local, cache, required, and recommended skills
211+
- Outputs JSON with `DISCOVERED_DIRECTIVES` and `DISCOVERED_SKILLS` fields
212+
213+
2. **Layer 2 (Templates)**: AI-powered semantic enhancement
214+
- Templates guide AI agents to perform semantic discovery based on script baseline
215+
- Enhanced with human-readable explanations (1-2 sentences per directive/skill)
216+
- Integrated into `/spec.specify` and `/spec.plan` command templates
217+
218+
**Discovery Workflow:**
219+
220+
```bash
221+
# Discovery automatically runs during feature creation with team-ai-directives
222+
./create-new-feature.sh --json "Add user authentication with OAuth2"
223+
# Output includes:
224+
# - DISCOVERED_DIRECTIVES: Constitution path, personas, rules from team-ai-directives
225+
# - DISCOVERED_SKILLS: Up to 5 relevant skills with 24h cached refresh
226+
```
227+
228+
**Team AI Directives Structure:**
229+
230+
```
231+
team-ai-directives/
232+
├── constitutions/
233+
│ └── constitution.md
234+
├── personas/
235+
│ └── security-expert.md
236+
├── rules/
237+
│ ├── api-security.md
238+
│ └── code-quality.md
239+
├── skills/
240+
│ ├── oauth2-flows/
241+
│ │ └── SKILL.md
242+
│ └── python-logging/
243+
│ └── SKILL.md
244+
└── .skills.json
245+
```
246+
247+
**Skills Discovery Algorithm (5-Layer):**
248+
249+
1. **Manifest Discovery**: Read `.skills.json` for required/recommended/blocked skills
250+
2. **Local Discovery**: Search `team-ai-directives/skills/` for SKILL.md files
251+
3. **Cache Discovery**: Check `skills-cache/` with 24h TTL refresh
252+
4. **Required Skills**: Auto-install from manifest URLs or local paths
253+
5. **Recommended Discovery**: Semantic matching against feature description
254+
255+
**AI-Powered Discovery in Templates:**
256+
257+
- `specify.md`: AI discovery section after initial context generation
258+
- `plan.md`: AI refresh section before implementation
259+
- `context-template.md`: Structured placeholders for DISCOVERED_DIRECTIVES/DISCOVERED_SKILLS
260+
202261
### Optional Architecture Support
203262

204263
The toolkit includes comprehensive architecture documentation support via the **Architect extension**. Architecture commands work in any project.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "agentic-sdlc-specify-cli"
3-
version = "0.0.114"
3+
version = "0.0.115"
44
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
55
requires-python = ">=3.11"
66
dependencies = [

scripts/bash/create-new-feature.sh

Lines changed: 221 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,200 @@ replace_date_placeholders "$SPEC_FILE"
375375
CONTEXT_TEMPLATE="$REPO_ROOT/.specify/templates/context-template.md"
376376
CONTEXT_FILE="$FEATURE_DIR/context.md"
377377

378+
# Function to discover team directives (Issue #47)
379+
discover_directives() {
380+
local feature_description="$1"
381+
local team_directives_path="$2"
382+
383+
if [[ ! -d "$team_directives_path" ]]; then
384+
cat <<'EOF'
385+
{
386+
"candidates": {
387+
"constitution": "",
388+
"personas": [],
389+
"rules": [],
390+
"skills": [],
391+
"examples": []
392+
},
393+
"search_metadata": {
394+
"keywords": [],
395+
"files_searched": 0,
396+
"files_with_matches": 0
397+
}
398+
}
399+
EOF
400+
return
401+
fi
402+
403+
local constitution=""
404+
if [[ -f "$team_directives_path/constitutions/constitution.md" ]]; then
405+
constitution="$team_directives_path/constitutions/constitution.md"
406+
elif [[ -f "$team_directives_path/constitution.md" ]]; then
407+
constitution="$team_directives_path/constitution.md"
408+
fi
409+
410+
cat <<EOF
411+
{
412+
"candidates": {
413+
"constitution": "${constitution}",
414+
"personas": [],
415+
"rules": [],
416+
"skills": [],
417+
"examples": []
418+
},
419+
"search_metadata": {
420+
"keywords": [],
421+
"files_searched": 0,
422+
"files_with_matches": 0
423+
}
424+
}
425+
EOF
426+
}
427+
428+
# Function to discover skills (Issue #49)
429+
discover_skills() {
430+
local feature_description="$1"
431+
local team_directives_path="$2"
432+
local skills_cache_path="$3"
433+
local max_skills="${4:-5}"
434+
local threshold="${5:-0.7}"
435+
436+
mkdir -p "$skills_cache_path"
437+
438+
local cache_marker="$skills_cache_path/.last_refresh"
439+
local current_timestamp=$(date +%s)
440+
local one_day=86400
441+
442+
local need_refresh=false
443+
if [[ -f "$cache_marker" ]]; then
444+
local last_refresh=$(cat "$cache_marker)
445+
local age=$((current_timestamp - last_refresh))
446+
if [[ $age -gt $one_day ]]; then
447+
need_refresh=true
448+
fi
449+
else
450+
need_refresh=true
451+
fi
452+
453+
if $need_refresh && [[ -d "$team_directives_path/skills" ]]; then
454+
echo "[specify] Refreshing skills cache (daily refresh)..." >&2
455+
cp -r "$team_directives_path/skills/"* "$skills_cache_path/" 2>/dev/null || true
456+
echo "$current_timestamp" > "$cache_marker"
457+
fi
458+
459+
local required_skills=()
460+
local blocked_skills=()
461+
if [[ -f "$team_directives_path/.skills.json" ]]; then
462+
local required=$(jq -r '.skills.required // {} | keys[]' "$team_directives_path/.skills.json" 2>/dev/null)
463+
[[ -n "$required" ]] && while read -r skill_id; do
464+
local skill_url=$(jq -r ".skills.required[\"$skill_id\"].url // empty" "$team_directives_path/.skills.json" 2>/dev/null)
465+
if [[ -n "$skill_url" ]]; then
466+
local cache_dir="$skills_cache_path/$(basename "$skill_id")"
467+
mkdir -p "$cache_dir"
468+
curl -s -o "$cache_dir/SKILL.md" "$skill_url" 2>/dev/null
469+
if [[ -f "$cache_dir/SKILL.md" && -s "$cache_dir/SKILL.md" ]]; then
470+
required_skills+=("$skill_id")
471+
fi
472+
elif [[ "$skill_id" == "local:"* ]]; then
473+
required_skills+=("$skill_id")
474+
elif [[ -d "$skills_cache_path/$skill_id" && -f "$skills_cache_path/$skill_id/SKILL.md" ]]; then
475+
required_skills+=("$skill_id")
476+
fi
477+
done <<< "$required"
478+
479+
local recommended=$(jq -r '.skills.recommended // {} | keys[]' "$team_directives_path/.skills.json" 2>/dev/null)
480+
[[ -n "$recommended" ]] && while read -r skill_id; do
481+
local skill_url=$(jq -r ".skills.recommended[\"$skill_id\"].url // empty" "$team_directives_path/.skills.json" 2>/dev/null)
482+
if [[ -n "$skill_url" ]]; then
483+
local cache_dir="$skills_cache_path/$(basename "$skill_id")"
484+
mkdir -p "$cache_dir"
485+
curl -s -o "$cache_dir/SKILL.md" "$skill_url" 2>/dev/null
486+
if [[ -f "$cache_dir/SKILL.md" && -s "$cache_dir/SKILL.md" ]]; then
487+
required_skills+=("$skill_id")
488+
fi
489+
elif [[ "$skill_id" == "local:"* ]]; then
490+
required_skills+=("$skill_id")
491+
elif [[ -d "$skills_cache_path/$skill_id" && -f "$skills_cache_path/$skill_id/SKILL.md" ]]; then
492+
required_skills+=("$skill_id")
493+
fi
494+
done <<< "$recommended"
495+
496+
local blocked=$(jq -r '.skills.blocked // [] | .[]' "$team_directives_path/.skills.json" 2>/dev/null)
497+
[[ -n "$blocked" ]] && while read -r blocked_id; do
498+
blocked_skills+=("$blocked_id")
499+
done <<< "$blocked"
500+
fi
501+
502+
local cached_skills=()
503+
if [[ -d "$skills_cache_path" ]]; then
504+
while IFS= read -r skill_dir; do
505+
[[ "$skill_dir" == "$skills_cache_path" ]] && continue
506+
[[ ! -d "$skill_dir" ]] && continue
507+
local skill_name=$(basename "$skill_dir")
508+
if [[ " ${required_skills[*]} " =~ " $skill_name " ]]; then
509+
continue
510+
fi
511+
local skill_md="$skill_dir/SKILL.md"
512+
if [[ ! -f "$skill_md" || ! -s "$skill_md" ]]; then
513+
continue
514+
fi
515+
cached_skills+=("$skill_name")
516+
done < <(find "$skills_cache_path" -maxdepth 1 -type d | grep -v "$skills_cache_path$")
517+
fi
518+
519+
local candidate_list=()
520+
for skill_id in "${required_skills[@]}"; do
521+
local is_blocked=0
522+
for blocked_id in "${blocked_skills[@]}"; do
523+
[[ "$skill_id" == "$blocked_id" ]] && is_blocked=1 && break
524+
done
525+
[[ $is_blocked -eq 1 ]] && continue
526+
527+
local skill_path=""
528+
local skill_name=""
529+
if [[ "$skill_id" == "local:"* ]]; then
530+
skill_path="$team_directives_path/${skill_id#local:}"
531+
skill_name=$(basename "$skill_path")
532+
else
533+
skill_path="$skills_cache_path/$skill_id"
534+
skill_name=$skill_id
535+
fi
536+
537+
[[ ! -f "$skill_path/SKILL.md" || ! -s "$skill_path/SKILL.md" ]] && continue
538+
candidate_list+=("required:$skill_name")
539+
done
540+
541+
for skill_name in "${cached_skills[@]}"; do
542+
local is_blocked=0
543+
for blocked_id in "${blocked_skills[@]}"; do
544+
[[ "$skill_name" == "$blocked_id" ]] && is_blocked=1 && break
545+
done
546+
[[ $is_blocked -eq 1 ]] && continue
547+
[[ " ${candidate_list[*]} " =~ " required:$skill_name " ]] && continue
548+
candidate_list+=("$skill_name")
549+
done
550+
551+
local candidates_json="["
552+
local first=1
553+
for skill_id in "${candidate_list[@]:0:$max_skills}"; do
554+
[[ $first -eq 0 ]] && candidates_json+=","
555+
local skill_name="${skill_id#required:}"
556+
local source="${skill_id%%:*}"
557+
local base_relevance="1.0"
558+
[[ "$source" != "required" ]] && base_relevance="0.65"
559+
candidates_json+=$(jq -n --arg id "$skill_id" --arg name "$skill_name" --arg source "$source" --argjson base_relevance "$base_relevance" '{"id":$id,"name":$name,"source":$source,"base_relevance":$base_relevance}')
560+
first=0
561+
done
562+
candidates_json+="]"
563+
564+
jq -n \
565+
--argjson candidates "$candidates_json" \
566+
'{
567+
"candidates": $candidates,
568+
"last_refresh": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"
569+
}'
570+
}
571+
378572
# Function to populate context.md with defaults
379573
populate_context_file() {
380574
local context_file="$1"
@@ -435,11 +629,37 @@ else
435629
touch "$CONTEXT_FILE"
436630
fi
437631
632+
# Resolve team directives path
633+
TEAM_DIRECTIVES_DIR="${SPECIFY_TEAM_DIRECTIVES:-}"
634+
if [[ -z "$TEAM_DIRECTIVES_DIR" ]]; then
635+
TEAM_DIRECTIVES_DIR="$REPO_ROOT/.specify/memory/team-ai-directives"
636+
fi
637+
638+
# Sync team-ai-directives if URL provided
639+
if [[ "$TEAM_DIRECTIVES_DIR" =~ ^https?:// ]]; then
640+
echo "[specify] Syncing team-ai-directives from $TEAM_DIRECTIVES_DIR..." >&2
641+
TEMP_DIR=$(mktemp -d)
642+
if git clone --depth 1 "$TEAM_DIRECTIVES_DIR" "$TEMP_DIR/team-ai-directives" 2>/dev/null; then
643+
TARGET_DIR="$REPO_ROOT/.specify/memory/team-ai-directives"
644+
rm -rf "$TARGET_DIR"
645+
mv "$TEMP_DIR/team-ai-directives" "$TARGET_DIR"
646+
TEAM_DIRECTIVES_DIR="$TARGET_DIR"
647+
echo "[specify] Team-ai-directives synced successfully" >&2
648+
else
649+
echo "[specify] Warning: Failed to sync team-ai-directives" >&2
650+
fi
651+
rm -rf "$TEMP_DIR"
652+
fi
653+
654+
# Discover directives and skills
655+
DISCOVERED_DIRECTIVES=$(discover_directives "$FEATURE_DESCRIPTION" "$TEAM_DIRECTIVES_DIR")
656+
DISCOVERED_SKILLS=$(discover_skills "$FEATURE_DESCRIPTION" "$TEAM_DIRECTIVES_DIR" "$REPO_ROOT/.specify/skills")
657+
438658
# Set the SPECIFY_FEATURE environment variable for the current session
439659
export SPECIFY_FEATURE="$BRANCH_NAME"
440660
441661
if $JSON_MODE; then
442-
printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' "$BRANCH_NAME" "$SPEC_FILE" "$FEATURE_NUM"
662+
printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s","DISCOVERED_DIRECTIVES":%s,"DISCOVERED_SKILLS":%s}\n' "$BRANCH_NAME" "$SPEC_FILE" "$FEATURE_NUM" "$DISCOVERED_DIRECTIVES" "$DISCOVERED_SKILLS"
443663
else
444664
echo "BRANCH_NAME: $BRANCH_NAME"
445665
echo "SPEC_FILE: $SPEC_FILE"

scripts/powershell/create-new-feature.ps1

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env pwsh
2+
. "scripts/powershell/discovery-functions.ps1"`
23
# Create a new feature
34
[CmdletBinding()]
45
param(
@@ -420,12 +421,23 @@ if (Test-Path $contextTemplate) {
420421
# Set the SPECIFY_FEATURE environment variable for the current session
421422
$env:SPECIFY_FEATURE = $branchName
422423

424+
# AI Discovery - Run discovery before JSON output
425+
if ($env:SPECIFY_TEAM_DIRECTIVES) {
426+
$TEAM_DIRECTIVES_DIR = $env:SPECIFY_TEAM_DIRECTIVES
427+
} else {
428+
$TEAM_DIRECTIVES_DIR = Join-Path $repoRoot '.specify/memory/team-ai-directives'
429+
}
430+
$DISCOVERED_DIRECTIVES = Discover-Directives -FeatureDescription $featureDesc -TeamDirectivesPath $TEAM_DIRECTIVES_DIR
431+
$DISCOVERED_SKILLS = Discover-Skills -FeatureDescription $featureDesc -TeamDirectivesPath $TEAM_DIRECTIVES_DIR -SkillsCachePath (Join-Path $repoRoot '.specify/skills')
432+
423433
if ($Json) {
424434
$obj = [PSCustomObject]@{
425435
BRANCH_NAME = $branchName
426436
SPEC_FILE = $specFile
427437
FEATURE_NUM = $featureNum
428438
HAS_GIT = $hasGit
439+
DISCOVERED_DIRECTIVES = $DISCOVERED_DIRECTIVES
440+
DISCOVERED_SKILLS = $DISCOVERED_SKILLS
429441
}
430442
$obj | ConvertTo-Json -Compress
431443
} else {

0 commit comments

Comments
 (0)