mirror of
https://github.com/github/spec-kit.git
synced 2026-07-03 20:36:23 +08:00
Compare commits
643 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48a545f214 | ||
|
|
0aa588a9b4 | ||
|
|
ea92155b52 | ||
|
|
047be2308c | ||
|
|
7d0f670b83 | ||
|
|
5b3ebabcaf | ||
|
|
719eef3ff1 | ||
|
|
fe9f19d569 | ||
|
|
56f9b95b0d | ||
|
|
7b99fef2bc | ||
|
|
bd3ae9aaef | ||
|
|
a0634ef96e | ||
|
|
a918979236 | ||
|
|
3a7f64c8a5 | ||
|
|
77ca5f4ed5 | ||
|
|
171b65ac33 | ||
|
|
232c19cb04 | ||
|
|
ca51d739fb | ||
|
|
03f3024c66 | ||
|
|
aad7b16188 | ||
|
|
6cec171772 | ||
|
|
37745ec2ee | ||
|
|
998f927576 | ||
|
|
9f14dfc6c6 | ||
|
|
8750e94d10 | ||
|
|
52c0a5f88f | ||
|
|
6413414907 | ||
|
|
7f708b9e6f | ||
|
|
13d88d22a6 | ||
|
|
6bf4ebbe33 | ||
|
|
5a52b7623e | ||
|
|
89fc554ce5 | ||
|
|
a067d4c2e3 | ||
|
|
8fefd2a532 | ||
|
|
b278d66b2c | ||
|
|
709457cec2 | ||
|
|
9e259e1f8d | ||
|
|
3970855797 | ||
|
|
f612e1a30d | ||
|
|
ecb3b94b43 | ||
|
|
c5c20134df | ||
|
|
58f7a43ec3 | ||
|
|
efb04e26eb | ||
|
|
c52ea23ba2 | ||
|
|
d402a392c3 | ||
|
|
deb80956f3 | ||
|
|
4dcf2921d1 | ||
|
|
dd9c0b0500 | ||
|
|
22e76995c7 | ||
|
|
569d18a59d | ||
|
|
f10fd07481 | ||
|
|
370b5b4890 | ||
|
|
52afbea47a | ||
|
|
85e00f63d6 | ||
|
|
fc1cec9748 | ||
|
|
ad46da552c | ||
|
|
919f09283d | ||
|
|
8d99f030ce | ||
|
|
b4c4e86cbc | ||
|
|
dc057a2314 | ||
|
|
2568422085 | ||
|
|
c118c1c30f | ||
|
|
fc3d1244c0 | ||
|
|
518dc9ddad | ||
|
|
13b614e9d5 | ||
|
|
3b82e0bcdd | ||
|
|
ba9a8b8e59 | ||
|
|
dedcae7cd8 | ||
|
|
2c11525be5 | ||
|
|
ca382992f7 | ||
|
|
669e253809 | ||
|
|
26fab003ee | ||
|
|
697daec733 | ||
|
|
02a1d610df | ||
|
|
8d2797dc03 | ||
|
|
076bb40f2e | ||
|
|
530d1ce514 | ||
|
|
c717cbb42d | ||
|
|
282dd3da56 | ||
|
|
e0fd355dad | ||
|
|
db8131441e | ||
|
|
752683d347 | ||
|
|
9988a46d96 | ||
|
|
27b4fd2e32 | ||
|
|
8fc2bd3489 | ||
|
|
b78a3cdd88 | ||
|
|
2f5417f0ad | ||
|
|
33a28ec8f7 | ||
|
|
f0886bd089 | ||
|
|
39c7b04e5e | ||
|
|
3467d26b1c | ||
|
|
a00e679918 | ||
|
|
c0152e4f3d | ||
|
|
03a9163633 | ||
|
|
4687c33b0f | ||
|
|
de93528fad | ||
|
|
bb7da09b65 | ||
|
|
fe75a45627 | ||
|
|
aa85b2f166 | ||
|
|
e27896e681 | ||
|
|
b67b2856b1 | ||
|
|
52ed84d723 | ||
|
|
cdbea09e1a | ||
|
|
1cb794e516 | ||
|
|
43cb0fa7ab | ||
|
|
74e3f45aa9 | ||
|
|
97ea7cf6a0 | ||
|
|
f43b85096c | ||
|
|
d1b95c2f59 | ||
|
|
8bb08ae1a0 | ||
|
|
5732de60d0 | ||
|
|
b6e19b49ec | ||
|
|
7f1e38491f | ||
|
|
bc0288832e | ||
|
|
e70495c2b8 | ||
|
|
674a66449a | ||
|
|
efeb5489c3 | ||
|
|
8013d0b57e | ||
|
|
0a121b073c | ||
|
|
6af2e64e88 | ||
|
|
66125a80a9 | ||
|
|
55515093a2 | ||
|
|
aa2282ea04 | ||
|
|
1c41aacbac | ||
|
|
cb0d9612ef | ||
|
|
71143598be | ||
|
|
9c73e68528 | ||
|
|
8472e44215 | ||
|
|
2972dec85c | ||
|
|
838bd0fedc | ||
|
|
3028a00b6e | ||
|
|
ac6714de31 | ||
|
|
4deb90f4f5 | ||
|
|
4d58ee945c | ||
|
|
feb839103d | ||
|
|
1c25b5af3b | ||
|
|
375b2fdb1d | ||
|
|
40fb276023 | ||
|
|
6536bc4102 | ||
|
|
1a9e4d1d8d | ||
|
|
aad6f68ae5 | ||
|
|
473a441720 | ||
|
|
55ff148475 | ||
|
|
7f08f31286 | ||
|
|
8b099585c7 | ||
|
|
9c0be46006 | ||
|
|
f92e7e8096 | ||
|
|
4178b61828 | ||
|
|
d9e63a51f1 | ||
|
|
7dc493e613 | ||
|
|
5678ca7757 | ||
|
|
94ba857b78 | ||
|
|
e1ab4f0486 | ||
|
|
535ddbe0d2 | ||
|
|
8353830f97 | ||
|
|
10be484868 | ||
|
|
48b84cc941 | ||
|
|
fac8e59c02 | ||
|
|
87c9e1ce75 | ||
|
|
d40c9a6428 | ||
|
|
cb508d7a36 | ||
|
|
b8e7851234 | ||
|
|
08f69e3d3e | ||
|
|
c8ccb0609d | ||
|
|
663d679f3b | ||
|
|
b1832c9477 | ||
|
|
a858c1d6da | ||
|
|
d9ce7c1fc0 | ||
|
|
4f9d966beb | ||
|
|
b44ffc0101 | ||
|
|
8e14ab1935 | ||
|
|
0945df9ec8 | ||
|
|
ea60efe2fa | ||
|
|
97b9f0f00d | ||
|
|
4df6d963dc | ||
|
|
682ffbfc0d | ||
|
|
b606b38512 | ||
|
|
255371d367 | ||
|
|
3113b72d6f | ||
|
|
3899dcc0d4 | ||
|
|
b8335a532c | ||
|
|
cb16412f88 | ||
|
|
804cd10c71 | ||
|
|
4dff63a84e | ||
|
|
40ecd44ada | ||
|
|
b19a7eedfa | ||
|
|
9cb3f3d1ad | ||
|
|
f8da535d71 | ||
|
|
edaa5a7ff1 | ||
|
|
5be705e414 | ||
|
|
796b4f47c4 | ||
|
|
6b1f45c50c | ||
|
|
8778c26dcf | ||
|
|
41d1f4b0ac | ||
|
|
9c2481fd67 | ||
|
|
8520241dfe | ||
|
|
362868a342 | ||
|
|
d7206126e0 | ||
|
|
b22f381c0d | ||
|
|
ccc44dd00a | ||
|
|
2c2fea8783 | ||
|
|
4b4bd735a3 | ||
|
|
36019ebf1b | ||
|
|
fb152eb824 | ||
|
|
00e5dc1f91 | ||
|
|
eeda669c19 | ||
|
|
ebc61067e8 | ||
|
|
2c2936022c | ||
|
|
816c1160e9 | ||
|
|
bc766c3101 | ||
|
|
f132f748e3 | ||
|
|
ee65758e2b | ||
|
|
a01180955d | ||
|
|
b1ba972978 | ||
|
|
24247c24c9 | ||
|
|
dc7f09a711 | ||
|
|
b72a5850fe | ||
|
|
a351c826ee | ||
|
|
6223d10d84 | ||
|
|
bf33980426 | ||
|
|
a7606c0f14 | ||
|
|
7d9361c716 | ||
|
|
191f33213c | ||
|
|
65ecd5321d | ||
|
|
d2559d7025 | ||
|
|
f85944aafe | ||
|
|
34171efcef | ||
|
|
c8af730b14 | ||
|
|
a4b60aca7f | ||
|
|
2f25e2d575 | ||
|
|
7484eb521a | ||
|
|
2bf655e261 | ||
|
|
f6794685b6 | ||
|
|
333a76535b | ||
|
|
6d0b84ab5b | ||
|
|
497b5885e1 | ||
|
|
33c83a6162 | ||
|
|
f97c8e95a6 | ||
|
|
cfd99ad499 | ||
|
|
96712e1cdf | ||
|
|
2e55bdd3f2 | ||
|
|
eecb723663 | ||
|
|
1a21bdef01 | ||
|
|
f21eb71990 | ||
|
|
b471b5e6f3 | ||
|
|
489ced56ba | ||
|
|
6644f69a96 | ||
|
|
a177a1a6d1 | ||
|
|
c12b8c1763 | ||
|
|
d2ecf6560d | ||
|
|
7a5762fe6a | ||
|
|
9c0c1446ec | ||
|
|
82b8ce4295 | ||
|
|
2cf332db1b | ||
|
|
b1650f884d | ||
|
|
23bd645054 | ||
|
|
bef9c2cb59 | ||
|
|
4f81fc298f | ||
|
|
4a3234496e | ||
|
|
f92d81bbec | ||
|
|
69ee7a836e | ||
|
|
c883952b43 | ||
|
|
b9c1a1c7bb | ||
|
|
46bc65b1ce | ||
|
|
017e1c4c2f | ||
|
|
7562664fd1 | ||
|
|
976c9981a4 | ||
|
|
d3fc056743 | ||
|
|
58ce653908 | ||
|
|
82f8a13f83 | ||
|
|
0f1cbd74fe | ||
|
|
ec60c5b2fe | ||
|
|
e56d37db8c | ||
|
|
33e853e9c9 | ||
|
|
929fab5d98 | ||
|
|
56095f06d2 | ||
|
|
2632a0f52d | ||
|
|
4ab91fbadf | ||
|
|
5c0bedb410 | ||
|
|
d92798d5b0 | ||
|
|
ee922cbde9 | ||
|
|
1df24f1953 | ||
|
|
3033834d64 | ||
|
|
4b00078907 | ||
|
|
2d72f85790 | ||
|
|
855ac838b8 | ||
|
|
a8ec87e3c2 | ||
|
|
9d6c05ad5b | ||
|
|
3ef12cae3e | ||
|
|
8618d0a53e | ||
|
|
71e6b4da4a | ||
|
|
ad74334a85 | ||
|
|
8c3982d65b | ||
|
|
13dec1de05 | ||
|
|
d0a112c60f | ||
|
|
c84756b7f3 | ||
|
|
524affca79 | ||
|
|
32c6e7f40c | ||
|
|
9cf33e81cc | ||
|
|
254e9bbdf0 | ||
|
|
6757c90dbd | ||
|
|
f6264d4ef4 | ||
|
|
dd8dbf6344 | ||
|
|
bf8fb125ad | ||
|
|
2b92ab444d | ||
|
|
abe1b7085c | ||
|
|
bfaca2c449 | ||
|
|
78ed453e38 | ||
|
|
658ab2a38c | ||
|
|
2c41d3627e | ||
|
|
b55d00beed | ||
|
|
525eae7f7e | ||
|
|
ce7bed4823 | ||
|
|
61b0637a6d | ||
|
|
56deda7be3 | ||
|
|
525cdc17ec | ||
|
|
607760e72f | ||
|
|
c7ecdfb998 | ||
|
|
f444ccba3a | ||
|
|
3040d33c31 | ||
|
|
6cc61025cb | ||
|
|
c1034f1d9d | ||
|
|
cee4f26fac | ||
|
|
6f523ede22 | ||
|
|
68d1d3a0fc | ||
|
|
07077d0fc2 | ||
|
|
aeed11f735 | ||
|
|
12405c01e1 | ||
|
|
fc3b98ea09 | ||
|
|
6150f1e317 | ||
|
|
6fca5d83b2 | ||
|
|
465acd9024 | ||
|
|
04fc3fd1ba | ||
|
|
24d76b5d92 | ||
|
|
0f7d04b12b | ||
|
|
9402ebd00a | ||
|
|
d410d188fc | ||
|
|
686c91f94e | ||
|
|
22036732d8 | ||
|
|
c78f8423f6 | ||
|
|
76cca34293 | ||
|
|
9a1e3037b0 | ||
|
|
f14a47ea7d | ||
|
|
36d97235ad | ||
|
|
4afbd87abb | ||
|
|
b562438df9 | ||
|
|
9111699cd2 | ||
|
|
0049b1cdc2 | ||
|
|
3e883fa32c | ||
|
|
baeb829ed4 | ||
|
|
236bcb3987 | ||
|
|
6c3d698959 | ||
|
|
4d806672d6 | ||
|
|
1c7b09d947 | ||
|
|
3963c2ef10 | ||
|
|
84e1a69edc | ||
|
|
6f22393106 | ||
|
|
5a39f63d1e | ||
|
|
964b1418a3 | ||
|
|
cad12bd2c8 | ||
|
|
8d552e6d11 | ||
|
|
ad3bb1a5fe | ||
|
|
a998d13b73 | ||
|
|
418950ad07 | ||
|
|
952e2bb5f8 | ||
|
|
56085f9323 | ||
|
|
dadda123f0 | ||
|
|
b4e1c07817 | ||
|
|
bb21eedabc | ||
|
|
f65bf6ccb7 | ||
|
|
a0ca101aa4 | ||
|
|
bf5ae42085 | ||
|
|
33df8976ca | ||
|
|
41a9fc8859 | ||
|
|
71a20eb787 | ||
|
|
798015b537 | ||
|
|
42086045cf | ||
|
|
bf6d9e8baf | ||
|
|
694de562cc | ||
|
|
45d5176d07 | ||
|
|
537f349f1b | ||
|
|
15139c1e0f | ||
|
|
f205fa3b58 | ||
|
|
4767d77ab5 | ||
|
|
c88d00d452 | ||
|
|
cf8b67e187 | ||
|
|
7c4294b163 | ||
|
|
2f58f4b9f0 | ||
|
|
7777e145d9 | ||
|
|
7e568c1201 | ||
|
|
f4fcd82920 | ||
|
|
3dcbb6e3a9 | ||
|
|
392f8b7dfa | ||
|
|
24b6d31471 | ||
|
|
960e4c0a32 | ||
|
|
df15b8e2a2 | ||
|
|
161a415274 | ||
|
|
e20d79e78b | ||
|
|
a26ee578ae | ||
|
|
d471a6fa42 | ||
|
|
bcd3f8468a | ||
|
|
d79d99f0a9 | ||
|
|
57c54d3f0a | ||
|
|
e976080cbf | ||
|
|
f438a10c7c | ||
|
|
3c4081d30f | ||
|
|
392dbf20c4 | ||
|
|
d068e1c040 | ||
|
|
0369d2a50e | ||
|
|
de2cdc633d | ||
|
|
891736ffc8 | ||
|
|
02015e512a | ||
|
|
3110452c3f | ||
|
|
c4638a936e | ||
|
|
2a7c2e9398 | ||
|
|
e6d6f3cdee | ||
|
|
598148ca67 | ||
|
|
b40b41cf50 | ||
|
|
1f3d9b5fdd | ||
|
|
f7fe48bd6a | ||
|
|
d6136cb22f | ||
|
|
dafab39483 | ||
|
|
09274437fc | ||
|
|
5f1fc6b445 | ||
|
|
779e1f8afd | ||
|
|
177dcadd8c | ||
|
|
ba861cd165 | ||
|
|
926836e0fc | ||
|
|
af88930ffc | ||
|
|
89f5f9c0b9 | ||
|
|
9809b1a4ab | ||
|
|
7b536b578d | ||
|
|
7522eb3f9d | ||
|
|
d550634d8e | ||
|
|
72cb885eb7 | ||
|
|
a877af5575 | ||
|
|
2508d926c0 | ||
|
|
9f123e013a | ||
|
|
60bd9dc849 | ||
|
|
e77d99abd2 | ||
|
|
eb030dab19 | ||
|
|
be06a23fd7 | ||
|
|
d4d3139d5f | ||
|
|
65f8787b48 | ||
|
|
9786e588b7 | ||
|
|
0ac76c8c7e | ||
|
|
79328aa38d | ||
|
|
f7903192a8 | ||
|
|
115b4335d9 | ||
|
|
37e87c78a0 | ||
|
|
14a574a6a8 | ||
|
|
dbd1437aea | ||
|
|
317ae4dad9 | ||
|
|
8e9d25e9be | ||
|
|
c59be99dc4 | ||
|
|
15a5630047 | ||
|
|
f3ada747cf | ||
|
|
cbc8ab020c | ||
|
|
e0e62f6757 | ||
|
|
6c22085214 | ||
|
|
02c1549f80 | ||
|
|
ab14090813 | ||
|
|
546e9d6617 | ||
|
|
33a07969c3 | ||
|
|
8de5db7a3e | ||
|
|
ea90d02c41 | ||
|
|
3e85f46465 | ||
|
|
015440838a | ||
|
|
7050a3151c | ||
|
|
9e84f46e56 | ||
|
|
5e32de1f3f | ||
|
|
5558b24475 | ||
|
|
f892b9e1cb | ||
|
|
a66af9b7f5 | ||
|
|
a5fdd53a3e | ||
|
|
ed0fa8fffe | ||
|
|
098380a46f | ||
|
|
74f7e508a4 | ||
|
|
8130d98bcc | ||
|
|
315269d9a8 | ||
|
|
71c2c63d55 | ||
|
|
b37a9516d0 | ||
|
|
b009773d5c | ||
|
|
a8514da3e8 | ||
|
|
9d4e8e9eb9 | ||
|
|
f3c77e2f4f | ||
|
|
ecec4bc5e0 | ||
|
|
900bc2ed68 | ||
|
|
03c7021270 | ||
|
|
a97374ded0 | ||
|
|
6b58824a39 | ||
|
|
b291a6efb0 | ||
|
|
3b000fce4d | ||
|
|
c59595d065 | ||
|
|
1c16a68df2 | ||
|
|
39bf3e4d9a | ||
|
|
045696641a | ||
|
|
41690cd1d4 | ||
|
|
e45c469709 | ||
|
|
8c9e586662 | ||
|
|
ce844c6259 | ||
|
|
84b46cd1b9 | ||
|
|
0cca67fcd2 | ||
|
|
66fc4c292d | ||
|
|
2baae57b26 | ||
|
|
514b0548fe | ||
|
|
be7db635cc | ||
|
|
a945077b8d | ||
|
|
7b55522213 | ||
|
|
7ca792509b | ||
|
|
4522fb4c44 | ||
|
|
36ff7e6505 | ||
|
|
defb1870da | ||
|
|
b61f04c898 | ||
|
|
64745162df | ||
|
|
97df98b9a0 | ||
|
|
36383b411f | ||
|
|
3e476c2ba6 | ||
|
|
654a00aac9 | ||
|
|
4690d13f88 | ||
|
|
e7bb98de42 | ||
|
|
d4f5c75519 | ||
|
|
09f57a87fa | ||
|
|
b702fcbbc0 | ||
|
|
2c1de4202e | ||
|
|
e65660ffc3 | ||
|
|
f7ae5781b7 | ||
|
|
d09552fc63 | ||
|
|
ed5dbf197f | ||
|
|
df4d7fa062 | ||
|
|
b4ecd14ffa | ||
|
|
26fde7cfda | ||
|
|
8abc812c57 | ||
|
|
940714df0a | ||
|
|
f393ae9825 | ||
|
|
97dee3e4bf | ||
|
|
aec568949c | ||
|
|
ed9044345b | ||
|
|
058ee510a7 | ||
|
|
e91aca54ee | ||
|
|
9c87fdd5bb | ||
|
|
301a556110 | ||
|
|
bb9ec8e638 | ||
|
|
e83d2c777d | ||
|
|
68809bdacb | ||
|
|
3cc545243b | ||
|
|
9ef389baba | ||
|
|
426ac8ab2e | ||
|
|
4de1b6b6c3 | ||
|
|
199c63901f | ||
|
|
369ed643d7 | ||
|
|
6c947cc8d8 | ||
|
|
07d506feb5 | ||
|
|
0124a0f32e | ||
|
|
e7936c3fd0 | ||
|
|
583d556677 | ||
|
|
72ed39d8a1 | ||
|
|
7c4c1edd85 | ||
|
|
5846a38c68 | ||
|
|
89f4b0b38a | ||
|
|
af2b14e9be | ||
|
|
719ba762bc | ||
|
|
d4cce17f66 | ||
|
|
47e5f7c2e2 | ||
|
|
ec782979f0 | ||
|
|
2ab6e6590f | ||
|
|
15e5572a1d | ||
|
|
cde400f466 | ||
|
|
ba8144da89 | ||
|
|
4dc4887134 | ||
|
|
14ebde575f | ||
|
|
337e192abd | ||
|
|
efe4edc3b1 | ||
|
|
0037a3f484 | ||
|
|
a6be9bea31 | ||
|
|
e71ebbce1e | ||
|
|
4c62cab033 | ||
|
|
80b2544396 | ||
|
|
78638a9a37 | ||
|
|
5333409080 | ||
|
|
08b2a0ae55 | ||
|
|
b06f2b9f89 | ||
|
|
9e0db01b6e | ||
|
|
917f271d74 | ||
|
|
00fe1bb5a9 | ||
|
|
5499d157ab | ||
|
|
83dcb4a2f5 | ||
|
|
8374777206 | ||
|
|
a172e4cb6e | ||
|
|
265534c5ad | ||
|
|
5042c76558 | ||
|
|
e81c3b3c8d | ||
|
|
75df2999f4 | ||
|
|
23e0c5c83c | ||
|
|
3ee225f624 | ||
|
|
12b823e4c2 | ||
|
|
f430138895 | ||
|
|
7fa0cc5e70 | ||
|
|
e3b456c4c8 | ||
|
|
e04175b51e | ||
|
|
cc75a22e45 | ||
|
|
b2f749ef41 | ||
|
|
de1db34b08 | ||
|
|
aa599b8af1 | ||
|
|
09cf4f6cc4 | ||
|
|
321edbc62e | ||
|
|
fadd250a98 | ||
|
|
9ff9c9fd8d | ||
|
|
45f04abd38 | ||
|
|
1c0e7d14d5 | ||
|
|
55555eb39e | ||
|
|
6f3e450cd8 | ||
|
|
8bbacd4adb | ||
|
|
6a3e81f813 | ||
|
|
eb3c63fe0f | ||
|
|
68eba52a40 | ||
|
|
721ecc9bec | ||
|
|
df3e4930cc | ||
|
|
f3d55cff84 | ||
|
|
c6051a0b8a | ||
|
|
04cb5f00d4 | ||
|
|
e924a73625 | ||
|
|
e642acaea4 | ||
|
|
f1ddf33ac4 | ||
|
|
f1063321c6 | ||
|
|
62f20c601c | ||
|
|
26645103a6 | ||
|
|
a4b86f7571 | ||
|
|
adc1417b0f | ||
|
|
c4698b623b | ||
|
|
2c373aa47a | ||
|
|
a0faa222c8 | ||
|
|
2b2f5a7c2a | ||
|
|
c7b61f4bfd | ||
|
|
bc101a4578 | ||
|
|
9319f0425e | ||
|
|
8b09559690 | ||
|
|
5d764e8364 | ||
|
|
1db65aa6aa | ||
|
|
318b76de50 | ||
|
|
a85fdd4051 | ||
|
|
92621bca7d | ||
|
|
9348c45f9e |
75
.devcontainer/devcontainer.json
Normal file
75
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,75 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/python
|
||||
{
|
||||
"name": "SpecKitDevContainer",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/python:3.13-trixie", // based on Debian "Trixie" (13)
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/common-utils:2": {
|
||||
"installZsh": true,
|
||||
"installOhMyZsh": true,
|
||||
"installOhMyZshConfig": true,
|
||||
"upgradePackages": true,
|
||||
"username": "devcontainer",
|
||||
"userUid": "automatic",
|
||||
"userGid": "automatic"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||
"version": "lts"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/git:1": {
|
||||
"ppa": true,
|
||||
"version": "latest"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/node": {
|
||||
"version": "lts"
|
||||
}
|
||||
},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [
|
||||
8080 // for Spec-Kit documentation site
|
||||
],
|
||||
"containerUser": "devcontainer",
|
||||
"updateRemoteUserUID": true,
|
||||
"postCreateCommand": "chmod +x ./.devcontainer/post-create.sh && ./.devcontainer/post-create.sh",
|
||||
"postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"mhutchie.git-graph",
|
||||
"eamodio.gitlens",
|
||||
"anweber.reveal-button",
|
||||
"chrisdias.promptboost",
|
||||
// Github Copilot
|
||||
"GitHub.copilot",
|
||||
"GitHub.copilot-chat",
|
||||
// Codex
|
||||
"openai.chatgpt",
|
||||
// Kilo Code
|
||||
"kilocode.Kilo-Code",
|
||||
// Roo Code
|
||||
"RooVeterinaryInc.roo-cline",
|
||||
// Claude Code
|
||||
"anthropic.claude-code"
|
||||
],
|
||||
"settings": {
|
||||
"debug.javascript.autoAttachFilter": "disabled", // fix running commands in integrated terminal
|
||||
|
||||
// Specify settings for Github Copilot
|
||||
"git.autofetch": true,
|
||||
"chat.promptFilesRecommendations": {
|
||||
"speckit.constitution": true,
|
||||
"speckit.specify": true,
|
||||
"speckit.plan": true,
|
||||
"speckit.tasks": true,
|
||||
"speckit.implement": true
|
||||
},
|
||||
"chat.tools.terminal.autoApprove": {
|
||||
".specify/scripts/bash/": true,
|
||||
".specify/scripts/powershell/": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
114
.devcontainer/post-create.sh
Executable file
114
.devcontainer/post-create.sh
Executable file
@@ -0,0 +1,114 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit immediately on error, treat unset variables as an error, and fail if any command in a pipeline fails.
|
||||
set -euo pipefail
|
||||
|
||||
# Function to run a command and show logs only on error
|
||||
run_command() {
|
||||
local command_to_run="$*"
|
||||
local output
|
||||
local exit_code
|
||||
|
||||
# Capture all output (stdout and stderr)
|
||||
output=$(eval "$command_to_run" 2>&1) || exit_code=$?
|
||||
exit_code=${exit_code:-0}
|
||||
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
echo -e "\033[0;31m[ERROR] Command failed (Exit Code $exit_code): $command_to_run\033[0m" >&2
|
||||
echo -e "\033[0;31m$output\033[0m" >&2
|
||||
|
||||
exit $exit_code
|
||||
fi
|
||||
}
|
||||
|
||||
# Installing CLI-based AI Agents
|
||||
|
||||
echo -e "\n🤖 Installing Copilot CLI..."
|
||||
run_command "npm install -g @github/copilot@latest"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing Claude CLI..."
|
||||
run_command "npm install -g @anthropic-ai/claude-code@latest"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing Codex CLI..."
|
||||
run_command "npm install -g @openai/codex@latest"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing Gemini CLI..."
|
||||
run_command "npm install -g @google/gemini-cli@latest"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing Augie CLI..."
|
||||
run_command "npm install -g @augmentcode/auggie@latest"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing Qwen Code CLI..."
|
||||
run_command "npm install -g @qwen-code/qwen-code@latest"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing OpenCode CLI..."
|
||||
run_command "npm install -g opencode-ai@latest"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing Junie CLI..."
|
||||
run_command "npm install -g @jetbrains/junie-cli@latest"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing Pi Coding Agent..."
|
||||
run_command "npm install -g @mariozechner/pi-coding-agent@latest"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing Kiro CLI..."
|
||||
# https://kiro.dev/docs/cli/
|
||||
KIRO_INSTALLER_URL="https://kiro.dev/install.sh"
|
||||
KIRO_INSTALLER_SHA256="7487a65cf310b7fb59b357c4b5e6e3f3259d383f4394ecedb39acf70f307cffb"
|
||||
KIRO_INSTALLER_PATH="$(mktemp)"
|
||||
|
||||
cleanup_kiro_installer() {
|
||||
rm -f "$KIRO_INSTALLER_PATH"
|
||||
}
|
||||
trap cleanup_kiro_installer EXIT
|
||||
|
||||
run_command "curl -fsSL \"$KIRO_INSTALLER_URL\" -o \"$KIRO_INSTALLER_PATH\""
|
||||
run_command "echo \"$KIRO_INSTALLER_SHA256 $KIRO_INSTALLER_PATH\" | sha256sum -c -"
|
||||
|
||||
run_command "bash \"$KIRO_INSTALLER_PATH\""
|
||||
|
||||
kiro_binary=""
|
||||
if command -v kiro-cli >/dev/null 2>&1; then
|
||||
kiro_binary="kiro-cli"
|
||||
elif command -v kiro >/dev/null 2>&1; then
|
||||
kiro_binary="kiro"
|
||||
else
|
||||
echo -e "\033[0;31m[ERROR] Kiro CLI installation did not create 'kiro-cli' or 'kiro' in PATH.\033[0m" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run_command "$kiro_binary --help > /dev/null"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing Kimi CLI..."
|
||||
# https://code.kimi.com
|
||||
run_command "pipx install kimi-cli"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🤖 Installing CodeBuddy CLI..."
|
||||
run_command "npm install -g @tencent-ai/codebuddy-code@latest"
|
||||
echo "✅ Done"
|
||||
|
||||
# Installing UV (Python package manager)
|
||||
echo -e "\n🐍 Installing UV - Python Package Manager..."
|
||||
run_command "pipx install uv"
|
||||
echo "✅ Done"
|
||||
|
||||
# Installing DocFx (for documentation site)
|
||||
echo -e "\n📚 Installing DocFx..."
|
||||
run_command "dotnet tool update -g docfx"
|
||||
echo "✅ Done"
|
||||
|
||||
echo -e "\n🧹 Cleaning cache..."
|
||||
run_command "sudo apt-get autoclean"
|
||||
run_command "sudo apt-get clean"
|
||||
|
||||
echo "✅ Setup completed. Happy coding! 🚀"
|
||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
||||
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@@ -1,2 +1,3 @@
|
||||
# Global code owner
|
||||
* @localden
|
||||
* @mnriem
|
||||
|
||||
|
||||
141
.github/ISSUE_TEMPLATE/agent_request.yml
vendored
Normal file
141
.github/ISSUE_TEMPLATE/agent_request.yml
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
name: Agent Request
|
||||
description: Request support for a new AI agent/assistant in Spec Kit
|
||||
title: "[Agent]: Add support for "
|
||||
labels: ["agent-request", "enhancement", "needs-triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for requesting a new agent! Before submitting, please check if the agent is already supported.
|
||||
|
||||
**Currently supported agents**: Claude Code, Gemini CLI, GitHub Copilot, Cursor, Qwen Code, opencode, Codex CLI, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy, Qoder CLI, Kiro CLI, Amp, SHAI, Tabnine CLI, Antigravity, IBM Bob, Mistral Vibe, Kimi Code, Trae, Pi Coding Agent, iFlow CLI
|
||||
|
||||
- type: input
|
||||
id: agent-name
|
||||
attributes:
|
||||
label: Agent Name
|
||||
description: What is the name of the AI agent/assistant?
|
||||
placeholder: "e.g., SuperCoder AI"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: website
|
||||
attributes:
|
||||
label: Official Website
|
||||
description: Link to the agent's official website or documentation
|
||||
placeholder: "https://..."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: agent-type
|
||||
attributes:
|
||||
label: Agent Type
|
||||
description: How is the agent accessed?
|
||||
options:
|
||||
- CLI tool (command-line interface)
|
||||
- IDE extension/plugin
|
||||
- Both CLI and IDE
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: cli-command
|
||||
attributes:
|
||||
label: CLI Command (if applicable)
|
||||
description: What command is used to invoke the agent from terminal?
|
||||
placeholder: "e.g., supercode, ai-assistant"
|
||||
|
||||
- type: input
|
||||
id: install-method
|
||||
attributes:
|
||||
label: Installation Method
|
||||
description: How is the agent installed?
|
||||
placeholder: "e.g., npm install -g supercode, pip install supercode, IDE marketplace"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: command-structure
|
||||
attributes:
|
||||
label: Command/Workflow Structure
|
||||
description: How does the agent define custom commands or workflows?
|
||||
placeholder: |
|
||||
- Command file format (Markdown, YAML, TOML, etc.)
|
||||
- Directory location (e.g., .supercode/commands/)
|
||||
- Example command file structure
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: argument-pattern
|
||||
attributes:
|
||||
label: Argument Passing Pattern
|
||||
description: How does the agent handle arguments in commands?
|
||||
placeholder: |
|
||||
e.g., Uses {{args}}, $ARGUMENTS, %ARGS%, or other placeholder format
|
||||
Example: "Run test suite with {{args}}"
|
||||
|
||||
- type: dropdown
|
||||
id: popularity
|
||||
attributes:
|
||||
label: Popularity/Usage
|
||||
description: How widely is this agent used?
|
||||
options:
|
||||
- Widely used (thousands+ of users)
|
||||
- Growing adoption (hundreds of users)
|
||||
- New/emerging (less than 100 users)
|
||||
- Unknown
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: documentation
|
||||
attributes:
|
||||
label: Documentation Links
|
||||
description: Links to relevant documentation for custom commands/workflows
|
||||
placeholder: |
|
||||
- Command documentation: https://...
|
||||
- API/CLI reference: https://...
|
||||
- Examples: https://...
|
||||
|
||||
- type: textarea
|
||||
id: use-case
|
||||
attributes:
|
||||
label: Use Case
|
||||
description: Why do you want this agent supported in Spec Kit?
|
||||
placeholder: Explain your workflow and how this agent fits into your development process
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: example-command
|
||||
attributes:
|
||||
label: Example Command File
|
||||
description: If possible, provide an example of a command file for this agent
|
||||
render: markdown
|
||||
placeholder: |
|
||||
```toml
|
||||
description = "Example command"
|
||||
prompt = "Do something with {{args}}"
|
||||
```
|
||||
|
||||
- type: checkboxes
|
||||
id: contribution
|
||||
attributes:
|
||||
label: Contribution
|
||||
description: Are you willing to help implement support for this agent?
|
||||
options:
|
||||
- label: I can help test the integration
|
||||
- label: I can provide example command files
|
||||
- label: I can help with documentation
|
||||
- label: I can submit a pull request for the integration
|
||||
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Any other relevant information about this agent
|
||||
placeholder: Screenshots, community links, comparison to existing agents, etc.
|
||||
118
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
118
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
name: Bug Report
|
||||
description: Report a bug or unexpected behavior in Specify CLI or Spec Kit
|
||||
title: "[Bug]: "
|
||||
labels: ["bug", "needs-triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to report a bug! Please fill out the sections below to help us diagnose and fix the issue.
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Bug Description
|
||||
description: A clear and concise description of what the bug is.
|
||||
placeholder: What went wrong?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: Steps to reproduce the behavior
|
||||
placeholder: |
|
||||
1. Run command '...'
|
||||
2. Execute script '...'
|
||||
3. See error
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: What did you expect to happen?
|
||||
placeholder: Describe the expected outcome
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: actual
|
||||
attributes:
|
||||
label: Actual Behavior
|
||||
description: What actually happened?
|
||||
placeholder: Describe what happened instead
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Specify CLI Version
|
||||
description: "Run `specify version` or `pip show spec-kit`"
|
||||
placeholder: "e.g., 1.3.0"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: ai-agent
|
||||
attributes:
|
||||
label: AI Agent
|
||||
description: Which AI agent are you using?
|
||||
options:
|
||||
- Claude Code
|
||||
- Gemini CLI
|
||||
- GitHub Copilot
|
||||
- Cursor
|
||||
- Qwen Code
|
||||
- opencode
|
||||
- Codex CLI
|
||||
- Windsurf
|
||||
- Kilo Code
|
||||
- Auggie CLI
|
||||
- Roo Code
|
||||
- CodeBuddy
|
||||
- Qoder CLI
|
||||
- Kiro CLI
|
||||
- Amp
|
||||
- SHAI
|
||||
- IBM Bob
|
||||
- Antigravity
|
||||
- Not applicable
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: Your operating system and version
|
||||
placeholder: "e.g., macOS 14.2, Ubuntu 22.04, Windows 11"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: python
|
||||
attributes:
|
||||
label: Python Version
|
||||
description: "Run `python --version` or `python3 --version`"
|
||||
placeholder: "e.g., Python 3.11.5"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Error Logs
|
||||
description: Please paste any relevant error messages or logs
|
||||
render: shell
|
||||
placeholder: Paste error output here
|
||||
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any other context about the problem
|
||||
placeholder: Screenshots, related issues, workarounds attempted, etc.
|
||||
17
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
17
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 💬 General Discussion
|
||||
url: https://github.com/github/spec-kit/discussions
|
||||
about: Ask questions, share ideas, or discuss Spec-Driven Development
|
||||
- name: 📖 Documentation
|
||||
url: https://github.com/github/spec-kit/blob/main/README.md
|
||||
about: Read the Spec Kit documentation and guides
|
||||
- name: 🛠️ Extension Development Guide
|
||||
url: https://github.com/github/spec-kit/blob/main/extensions/EXTENSION-DEVELOPMENT-GUIDE.md
|
||||
about: Learn how to develop and publish Spec Kit extensions
|
||||
- name: 🤝 Contributing Guide
|
||||
url: https://github.com/github/spec-kit/blob/main/CONTRIBUTING.md
|
||||
about: Learn how to contribute to Spec Kit
|
||||
- name: 🔒 Security Issues
|
||||
url: https://github.com/github/spec-kit/blob/main/SECURITY.md
|
||||
about: Report security vulnerabilities privately
|
||||
280
.github/ISSUE_TEMPLATE/extension_submission.yml
vendored
Normal file
280
.github/ISSUE_TEMPLATE/extension_submission.yml
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
name: Extension Submission
|
||||
description: Submit your extension to the Spec Kit catalog
|
||||
title: "[Extension]: Add "
|
||||
labels: ["extension-submission", "enhancement", "needs-triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for contributing an extension! This template helps you submit your extension to the community catalog.
|
||||
|
||||
**Before submitting:**
|
||||
- Review the [Extension Publishing Guide](https://github.com/github/spec-kit/blob/main/extensions/EXTENSION-PUBLISHING-GUIDE.md)
|
||||
- Ensure your extension has a valid `extension.yml` manifest
|
||||
- Create a GitHub release with a version tag (e.g., v1.0.0)
|
||||
- Test installation: `specify extension add <extension-name> --from <your-release-url>`
|
||||
|
||||
- type: input
|
||||
id: extension-id
|
||||
attributes:
|
||||
label: Extension ID
|
||||
description: Unique extension identifier (lowercase with hyphens only)
|
||||
placeholder: "e.g., jira-integration"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: extension-name
|
||||
attributes:
|
||||
label: Extension Name
|
||||
description: Human-readable extension name
|
||||
placeholder: "e.g., Jira Integration"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: Semantic version number
|
||||
placeholder: "e.g., 1.0.0"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Brief description of what your extension does (under 200 characters)
|
||||
placeholder: Integrates Jira issue tracking with Spec Kit workflows for seamless task management
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: author
|
||||
attributes:
|
||||
label: Author
|
||||
description: Your name or organization
|
||||
placeholder: "e.g., John Doe or Acme Corp"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: repository
|
||||
attributes:
|
||||
label: Repository URL
|
||||
description: GitHub repository URL for your extension
|
||||
placeholder: "https://github.com/your-org/spec-kit-your-extension"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: download-url
|
||||
attributes:
|
||||
label: Download URL
|
||||
description: URL to the GitHub release archive (e.g., v1.0.0.zip)
|
||||
placeholder: "https://github.com/your-org/spec-kit-your-extension/archive/refs/tags/v1.0.0.zip"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: license
|
||||
attributes:
|
||||
label: License
|
||||
description: Open source license type
|
||||
placeholder: "e.g., MIT, Apache-2.0"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: homepage
|
||||
attributes:
|
||||
label: Homepage (optional)
|
||||
description: Link to extension homepage or documentation site
|
||||
placeholder: "https://..."
|
||||
|
||||
- type: input
|
||||
id: documentation
|
||||
attributes:
|
||||
label: Documentation URL (optional)
|
||||
description: Link to detailed documentation
|
||||
placeholder: "https://github.com/your-org/spec-kit-your-extension/blob/main/docs/"
|
||||
|
||||
- type: input
|
||||
id: changelog
|
||||
attributes:
|
||||
label: Changelog URL (optional)
|
||||
description: Link to changelog file
|
||||
placeholder: "https://github.com/your-org/spec-kit-your-extension/blob/main/CHANGELOG.md"
|
||||
|
||||
- type: input
|
||||
id: speckit-version
|
||||
attributes:
|
||||
label: Required Spec Kit Version
|
||||
description: Minimum Spec Kit version required
|
||||
placeholder: "e.g., >=0.1.0"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: required-tools
|
||||
attributes:
|
||||
label: Required Tools (optional)
|
||||
description: List any external tools or dependencies required
|
||||
placeholder: |
|
||||
- jira-cli (>=1.0.0) - required
|
||||
- python (>=3.8) - optional
|
||||
render: markdown
|
||||
|
||||
- type: input
|
||||
id: commands-count
|
||||
attributes:
|
||||
label: Number of Commands
|
||||
description: How many commands does your extension provide?
|
||||
placeholder: "e.g., 3"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: hooks-count
|
||||
attributes:
|
||||
label: Number of Hooks (optional)
|
||||
description: How many hooks does your extension provide?
|
||||
placeholder: "e.g., 0"
|
||||
|
||||
- type: textarea
|
||||
id: tags
|
||||
attributes:
|
||||
label: Tags
|
||||
description: 2-5 relevant tags (lowercase, separated by commas)
|
||||
placeholder: "issue-tracking, jira, atlassian, automation"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: features
|
||||
attributes:
|
||||
label: Key Features
|
||||
description: List the main features and capabilities of your extension
|
||||
placeholder: |
|
||||
- Create Jira issues from specs
|
||||
- Sync task status with Jira
|
||||
- Link specs to existing issues
|
||||
- Generate Jira reports
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: testing
|
||||
attributes:
|
||||
label: Testing Checklist
|
||||
description: Confirm that your extension has been tested
|
||||
options:
|
||||
- label: Extension installs successfully via download URL
|
||||
required: true
|
||||
- label: All commands execute without errors
|
||||
required: true
|
||||
- label: Documentation is complete and accurate
|
||||
required: true
|
||||
- label: No security vulnerabilities identified
|
||||
required: true
|
||||
- label: Tested on at least one real project
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: requirements
|
||||
attributes:
|
||||
label: Submission Requirements
|
||||
description: Verify your extension meets all requirements
|
||||
options:
|
||||
- label: Valid `extension.yml` manifest included
|
||||
required: true
|
||||
- label: README.md with installation and usage instructions
|
||||
required: true
|
||||
- label: LICENSE file included
|
||||
required: true
|
||||
- label: GitHub release created with version tag
|
||||
required: true
|
||||
- label: All command files exist and are properly formatted
|
||||
required: true
|
||||
- label: Extension ID follows naming conventions (lowercase-with-hyphens)
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: testing-details
|
||||
attributes:
|
||||
label: Testing Details
|
||||
description: Describe how you tested your extension
|
||||
placeholder: |
|
||||
**Tested on:**
|
||||
- macOS 14.0 with Spec Kit v0.1.0
|
||||
- Linux Ubuntu 22.04 with Spec Kit v0.1.0
|
||||
|
||||
**Test project:** [Link or description]
|
||||
|
||||
**Test scenarios:**
|
||||
1. Installed extension
|
||||
2. Configured settings
|
||||
3. Ran all commands
|
||||
4. Verified outputs
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: example-usage
|
||||
attributes:
|
||||
label: Example Usage
|
||||
description: Provide a simple example of using your extension
|
||||
render: markdown
|
||||
placeholder: |
|
||||
```bash
|
||||
# Install extension
|
||||
specify extension add <extension-name> --from https://github.com/your-org/spec-kit-your-extension/archive/refs/tags/v1.0.0.zip
|
||||
|
||||
# Use a command
|
||||
/speckit.your-extension.command-name arg1 arg2
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: catalog-entry
|
||||
attributes:
|
||||
label: Proposed Catalog Entry
|
||||
description: Provide the JSON entry for catalog.json (helps reviewers)
|
||||
render: json
|
||||
placeholder: |
|
||||
{
|
||||
"your-extension": {
|
||||
"name": "Your Extension",
|
||||
"id": "your-extension",
|
||||
"description": "Brief description",
|
||||
"author": "Your Name",
|
||||
"version": "1.0.0",
|
||||
"download_url": "https://github.com/your-org/spec-kit-your-extension/archive/refs/tags/v1.0.0.zip",
|
||||
"repository": "https://github.com/your-org/spec-kit-your-extension",
|
||||
"homepage": "https://github.com/your-org/spec-kit-your-extension",
|
||||
"license": "MIT",
|
||||
"requires": {
|
||||
"speckit_version": ">=0.1.0"
|
||||
},
|
||||
"provides": {
|
||||
"commands": 3
|
||||
},
|
||||
"tags": ["category", "tool"],
|
||||
"verified": false,
|
||||
"downloads": 0,
|
||||
"stars": 0,
|
||||
"created_at": "2026-02-20T00:00:00Z",
|
||||
"updated_at": "2026-02-20T00:00:00Z"
|
||||
}
|
||||
}
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Any other information that would help reviewers
|
||||
placeholder: Screenshots, demo videos, links to related projects, etc.
|
||||
104
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
104
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
name: Feature Request
|
||||
description: Suggest a new feature or enhancement for Specify CLI or Spec Kit
|
||||
title: "[Feature]: "
|
||||
labels: ["enhancement", "needs-triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for suggesting a feature! Please provide details below to help us understand and evaluate your request.
|
||||
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Problem Statement
|
||||
description: Is your feature request related to a problem? Please describe.
|
||||
placeholder: "I'm frustrated when..."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Proposed Solution
|
||||
description: Describe the solution you'd like
|
||||
placeholder: What would you like to happen?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives Considered
|
||||
description: Have you considered any alternative solutions or workarounds?
|
||||
placeholder: What other approaches might work?
|
||||
|
||||
- type: dropdown
|
||||
id: component
|
||||
attributes:
|
||||
label: Component
|
||||
description: Which component does this feature relate to?
|
||||
options:
|
||||
- Specify CLI (initialization, commands)
|
||||
- Spec templates (BDD, Testing Strategy, etc.)
|
||||
- Agent integrations (command files, workflows)
|
||||
- Scripts (Bash/PowerShell utilities)
|
||||
- Documentation
|
||||
- CI/CD workflows
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: ai-agent
|
||||
attributes:
|
||||
label: AI Agent (if applicable)
|
||||
description: Does this feature relate to a specific AI agent?
|
||||
options:
|
||||
- All agents
|
||||
- Claude Code
|
||||
- Gemini CLI
|
||||
- GitHub Copilot
|
||||
- Cursor
|
||||
- Qwen Code
|
||||
- opencode
|
||||
- Codex CLI
|
||||
- Windsurf
|
||||
- Kilo Code
|
||||
- Auggie CLI
|
||||
- Roo Code
|
||||
- CodeBuddy
|
||||
- Qoder CLI
|
||||
- Kiro CLI
|
||||
- Amp
|
||||
- SHAI
|
||||
- IBM Bob
|
||||
- Antigravity
|
||||
- Not applicable
|
||||
|
||||
- type: textarea
|
||||
id: use-cases
|
||||
attributes:
|
||||
label: Use Cases
|
||||
description: Describe specific use cases where this feature would be valuable
|
||||
placeholder: |
|
||||
1. When working on large projects...
|
||||
2. During spec review...
|
||||
3. When integrating with CI/CD...
|
||||
|
||||
- type: textarea
|
||||
id: acceptance
|
||||
attributes:
|
||||
label: Acceptance Criteria
|
||||
description: How would you know this feature is complete and working?
|
||||
placeholder: |
|
||||
- [ ] Feature does X
|
||||
- [ ] Documentation is updated
|
||||
- [ ] Works with all supported agents
|
||||
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any other context, screenshots, or examples
|
||||
placeholder: Links to similar features, mockups, related discussions, etc.
|
||||
169
.github/ISSUE_TEMPLATE/preset_submission.yml
vendored
Normal file
169
.github/ISSUE_TEMPLATE/preset_submission.yml
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
name: Preset Submission
|
||||
description: Submit your preset to the Spec Kit preset catalog
|
||||
title: "[Preset]: Add "
|
||||
labels: ["preset-submission", "enhancement", "needs-triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for contributing a preset! This template helps you submit your preset to the community catalog.
|
||||
|
||||
**Before submitting:**
|
||||
- Review the [Preset Publishing Guide](https://github.com/github/spec-kit/blob/main/presets/PUBLISHING.md)
|
||||
- Ensure your preset has a valid `preset.yml` manifest
|
||||
- Create a GitHub release with a version tag (e.g., v1.0.0)
|
||||
- Test installation from the release archive: `specify preset add --from <download-url>`
|
||||
|
||||
- type: input
|
||||
id: preset-id
|
||||
attributes:
|
||||
label: Preset ID
|
||||
description: Unique preset identifier (lowercase with hyphens only)
|
||||
placeholder: "e.g., healthcare-compliance"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: preset-name
|
||||
attributes:
|
||||
label: Preset Name
|
||||
description: Human-readable preset name
|
||||
placeholder: "e.g., Healthcare Compliance"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: Semantic version number
|
||||
placeholder: "e.g., 1.0.0"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Brief description of what your preset does (under 200 characters)
|
||||
placeholder: Enforces HIPAA-compliant spec workflows with audit templates and compliance checklists
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: author
|
||||
attributes:
|
||||
label: Author
|
||||
description: Your name or organization
|
||||
placeholder: "e.g., John Doe or Acme Corp"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: repository
|
||||
attributes:
|
||||
label: Repository URL
|
||||
description: GitHub repository URL for your preset
|
||||
placeholder: "https://github.com/your-org/spec-kit-your-preset"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: download-url
|
||||
attributes:
|
||||
label: Download URL
|
||||
description: URL to the GitHub release archive for your preset (e.g., https://github.com/your-org/spec-kit-preset-your-preset/archive/refs/tags/v1.0.0.zip)
|
||||
placeholder: "https://github.com/your-org/spec-kit-preset-your-preset/archive/refs/tags/v1.0.0.zip"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: license
|
||||
attributes:
|
||||
label: License
|
||||
description: Open source license type
|
||||
placeholder: "e.g., MIT, Apache-2.0"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: speckit-version
|
||||
attributes:
|
||||
label: Required Spec Kit Version
|
||||
description: Minimum Spec Kit version required
|
||||
placeholder: "e.g., >=0.3.0"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: templates-provided
|
||||
attributes:
|
||||
label: Templates Provided
|
||||
description: List the template overrides your preset provides
|
||||
placeholder: |
|
||||
- spec-template.md — adds compliance section
|
||||
- plan-template.md — includes audit checkpoints
|
||||
- checklist-template.md — HIPAA compliance checklist
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: commands-provided
|
||||
attributes:
|
||||
label: Commands Provided (optional)
|
||||
description: List any command overrides your preset provides
|
||||
placeholder: |
|
||||
- speckit.specify.md — customized for compliance workflows
|
||||
|
||||
- type: textarea
|
||||
id: tags
|
||||
attributes:
|
||||
label: Tags
|
||||
description: 2-5 relevant tags (lowercase, separated by commas)
|
||||
placeholder: "compliance, healthcare, hipaa, audit"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: features
|
||||
attributes:
|
||||
label: Key Features
|
||||
description: List the main features and capabilities of your preset
|
||||
placeholder: |
|
||||
- HIPAA-compliant spec templates
|
||||
- Audit trail checklists
|
||||
- Compliance review workflow
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: testing
|
||||
attributes:
|
||||
label: Testing Checklist
|
||||
description: Confirm that your preset has been tested
|
||||
options:
|
||||
- label: Preset installs successfully via `specify preset add`
|
||||
required: true
|
||||
- label: Template resolution works correctly after installation
|
||||
required: true
|
||||
- label: Documentation is complete and accurate
|
||||
required: true
|
||||
- label: Tested on at least one real project
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: requirements
|
||||
attributes:
|
||||
label: Submission Requirements
|
||||
description: Verify your preset meets all requirements
|
||||
options:
|
||||
- label: Valid `preset.yml` manifest included
|
||||
required: true
|
||||
- label: README.md with description and usage instructions
|
||||
required: true
|
||||
- label: LICENSE file included
|
||||
required: true
|
||||
- label: GitHub release created with version tag
|
||||
required: true
|
||||
- label: Preset ID follows naming conventions (lowercase-with-hyphens)
|
||||
required: true
|
||||
22
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
22
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
## Description
|
||||
|
||||
<!-- What does this PR do? Why is it needed? -->
|
||||
|
||||
## Testing
|
||||
|
||||
<!-- How did you test your changes? -->
|
||||
|
||||
- [ ] Tested locally with `uv run specify --help`
|
||||
- [ ] Ran existing tests with `uv sync && uv run pytest`
|
||||
- [ ] Tested with a sample project (if applicable)
|
||||
|
||||
## AI Disclosure
|
||||
|
||||
<!-- Per our Contributing guidelines, AI assistance must be disclosed. -->
|
||||
<!-- See: https://github.com/github/spec-kit/blob/main/CONTRIBUTING.md#ai-contributions-in-spec-kit -->
|
||||
|
||||
- [ ] I **did not** use AI assistance for this contribution
|
||||
- [ ] I **did** use AI assistance (describe below)
|
||||
|
||||
<!-- If you used AI, briefly describe how (e.g., "Code generated by Copilot", "Consulted ChatGPT for approach"): -->
|
||||
|
||||
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
191
.github/workflows/RELEASE-PROCESS.md
vendored
Normal file
191
.github/workflows/RELEASE-PROCESS.md
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
# Release Process
|
||||
|
||||
This document describes the automated release process for Spec Kit.
|
||||
|
||||
## Overview
|
||||
|
||||
The release process is split into two workflows to ensure version consistency:
|
||||
|
||||
1. **Release Trigger Workflow** (`release-trigger.yml`) - Manages versioning and triggers release
|
||||
2. **Release Workflow** (`release.yml`) - Builds and publishes artifacts
|
||||
|
||||
This separation ensures that git tags always point to commits with the correct version in `pyproject.toml`.
|
||||
|
||||
## Before Creating a Release
|
||||
|
||||
**Important**: Write clear, descriptive commit messages!
|
||||
|
||||
### How CHANGELOG.md Works
|
||||
|
||||
The CHANGELOG is **automatically generated** from your git commit messages:
|
||||
|
||||
1. **During Development**: Write clear, descriptive commit messages:
|
||||
```bash
|
||||
git commit -m "feat: Add new authentication feature"
|
||||
git commit -m "fix: Resolve timeout issue in API client (#123)"
|
||||
git commit -m "docs: Update installation instructions"
|
||||
```
|
||||
|
||||
2. **When Releasing**: The release trigger workflow automatically:
|
||||
- Finds all commits since the last release tag
|
||||
- Formats them as changelog entries
|
||||
- Inserts them into CHANGELOG.md
|
||||
- Commits the updated changelog before creating the new tag
|
||||
|
||||
### Commit Message Best Practices
|
||||
|
||||
Good commit messages make good changelogs:
|
||||
- **Be descriptive**: "Add user authentication" not "Update files"
|
||||
- **Reference issues/PRs**: Include `(#123)` for automated linking
|
||||
- **Use conventional commits** (optional): `feat:`, `fix:`, `docs:`, `chore:`
|
||||
- **Keep it concise**: One line is ideal, details go in commit body
|
||||
|
||||
**Example commits that become good changelog entries:**
|
||||
```
|
||||
fix: prepend YAML frontmatter to Cursor .mdc files (#1699)
|
||||
feat: add generic agent support with customizable command directories (#1639)
|
||||
docs: document dual-catalog system for extensions (#1689)
|
||||
```
|
||||
|
||||
## Creating a Release
|
||||
|
||||
### Option 1: Auto-Increment (Recommended for patches)
|
||||
|
||||
1. Go to **Actions** → **Release Trigger**
|
||||
2. Click **Run workflow**
|
||||
3. Leave the version field **empty**
|
||||
4. Click **Run workflow**
|
||||
|
||||
The workflow will:
|
||||
- Auto-increment the patch version (e.g., `0.1.10` → `0.1.11`)
|
||||
- Update `pyproject.toml`
|
||||
- Update `CHANGELOG.md` by adding a new section for the release based on commits since the last tag
|
||||
- Commit changes to a `chore/release-vX.Y.Z` branch
|
||||
- Create and push the git tag from that branch
|
||||
- Open a PR to merge the version bump into `main`
|
||||
- Trigger the release workflow automatically via the tag push
|
||||
|
||||
### Option 2: Manual Version (For major/minor bumps)
|
||||
|
||||
1. Go to **Actions** → **Release Trigger**
|
||||
2. Click **Run workflow**
|
||||
3. Enter the desired version (e.g., `0.2.0` or `v0.2.0`)
|
||||
4. Click **Run workflow**
|
||||
|
||||
The workflow will:
|
||||
- Use your specified version
|
||||
- Update `pyproject.toml`
|
||||
- Update `CHANGELOG.md` by adding a new section for the release based on commits since the last tag
|
||||
- Commit changes to a `chore/release-vX.Y.Z` branch
|
||||
- Create and push the git tag from that branch
|
||||
- Open a PR to merge the version bump into `main`
|
||||
- Trigger the release workflow automatically via the tag push
|
||||
|
||||
## What Happens Next
|
||||
|
||||
Once the release trigger workflow completes:
|
||||
|
||||
1. A `chore/release-vX.Y.Z` branch is pushed with the version bump commit
|
||||
2. The git tag is pushed, pointing to that commit
|
||||
3. The **Release Workflow** is automatically triggered by the tag push
|
||||
4. Release artifacts are built for all supported agents
|
||||
5. A GitHub Release is created with all assets
|
||||
6. A PR is opened to merge the version bump branch into `main`
|
||||
|
||||
> **Note**: Merge the auto-opened PR after the release is published to keep `main` in sync.
|
||||
|
||||
## Workflow Details
|
||||
|
||||
### Release Trigger Workflow
|
||||
|
||||
**File**: `.github/workflows/release-trigger.yml`
|
||||
|
||||
**Trigger**: Manual (`workflow_dispatch`)
|
||||
|
||||
**Permissions Required**: `contents: write`
|
||||
|
||||
**Steps**:
|
||||
1. Checkout repository
|
||||
2. Determine version (manual or auto-increment)
|
||||
3. Check if tag already exists (prevents duplicates)
|
||||
4. Create `chore/release-vX.Y.Z` branch
|
||||
5. Update `pyproject.toml`
|
||||
6. Update `CHANGELOG.md` from git commits
|
||||
7. Commit changes
|
||||
8. Push branch and tag
|
||||
9. Open PR to merge version bump into `main`
|
||||
|
||||
### Release Workflow
|
||||
|
||||
**File**: `.github/workflows/release.yml`
|
||||
|
||||
**Trigger**: Tag push (`v*`)
|
||||
|
||||
**Permissions Required**: `contents: write`
|
||||
|
||||
**Steps**:
|
||||
1. Checkout repository at tag
|
||||
2. Extract version from tag name
|
||||
3. Check if release already exists
|
||||
4. Build release package variants (all agents × shell/powershell)
|
||||
5. Generate release notes from commits
|
||||
6. Create GitHub Release with all assets
|
||||
|
||||
## Version Constraints
|
||||
|
||||
- Tags must follow format: `v{MAJOR}.{MINOR}.{PATCH}`
|
||||
- Example valid versions: `v0.1.11`, `v0.2.0`, `v1.0.0`
|
||||
- Auto-increment only bumps patch version
|
||||
- Cannot create duplicate tags (workflow will fail)
|
||||
|
||||
## Benefits of This Approach
|
||||
|
||||
✅ **Version Consistency**: Git tags point to commits with matching `pyproject.toml` version
|
||||
|
||||
✅ **Single Source of Truth**: Version set once, used everywhere
|
||||
|
||||
✅ **Prevents Drift**: No more manual version synchronization needed
|
||||
|
||||
✅ **Clean Separation**: Versioning logic separate from artifact building
|
||||
|
||||
✅ **Flexibility**: Supports both auto-increment and manual versioning
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Commits Since Last Release
|
||||
|
||||
If you run the release trigger workflow when there are no new commits since the last tag:
|
||||
- The workflow will still succeed
|
||||
- The CHANGELOG will show "- Initial release" if it's the first release
|
||||
- Or it will be empty if there are no commits
|
||||
- Consider adding meaningful commits before releasing
|
||||
|
||||
**Best Practice**: Use descriptive commit messages - they become your changelog!
|
||||
|
||||
### Tag Already Exists
|
||||
|
||||
If you see "Error: Tag vX.Y.Z already exists!", you need to:
|
||||
- Choose a different version number, or
|
||||
- Delete the existing tag if it was created in error
|
||||
|
||||
### Release Workflow Didn't Trigger
|
||||
|
||||
Check that:
|
||||
- The release trigger workflow completed successfully
|
||||
- The tag was pushed (check repository tags)
|
||||
- The release workflow is enabled in Actions settings
|
||||
|
||||
### Version Mismatch
|
||||
|
||||
If `pyproject.toml` doesn't match the latest tag:
|
||||
- Run the release trigger workflow to sync versions
|
||||
- Or manually update `pyproject.toml` and push changes before running the release trigger
|
||||
|
||||
## Legacy Behavior (Pre-v0.1.10)
|
||||
|
||||
Before this change, the release workflow:
|
||||
- Created tags automatically on main branch pushes
|
||||
- Updated `pyproject.toml` AFTER creating the tag
|
||||
- Resulted in tags pointing to commits with outdated versions
|
||||
|
||||
This has been fixed in v0.1.10+.
|
||||
32
.github/workflows/codeql.yml
vendored
Normal file
32
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'actions', 'python' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v4
|
||||
with:
|
||||
category: "/language:${{ matrix.language }}"
|
||||
11
.github/workflows/docs.yml
vendored
11
.github/workflows/docs.yml
vendored
@@ -26,10 +26,11 @@ concurrency:
|
||||
jobs:
|
||||
# Build job
|
||||
build:
|
||||
if: github.repository == 'github/spec-kit'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for git info
|
||||
|
||||
@@ -47,15 +48,16 @@ jobs:
|
||||
docfx docfx.json
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v5
|
||||
uses: actions/configure-pages@v6
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
uses: actions/upload-pages-artifact@v5
|
||||
with:
|
||||
path: 'docs/_site'
|
||||
|
||||
# Deploy job
|
||||
deploy:
|
||||
if: github.repository == 'github/spec-kit'
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
@@ -64,4 +66,5 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
uses: actions/deploy-pages@v5
|
||||
|
||||
|
||||
22
.github/workflows/lint.yml
vendored
Normal file
22
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Lint
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
markdownlint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run markdownlint-cli2
|
||||
uses: DavidAnson/markdownlint-cli2-action@ce4853d43830c74c1753b39f3cf40f71c2031eb9 # v23
|
||||
with:
|
||||
globs: |
|
||||
'**/*.md'
|
||||
!extensions/**/*.md
|
||||
178
.github/workflows/release-trigger.yml
vendored
Normal file
178
.github/workflows/release-trigger.yml
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
name: Release Trigger
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version to release (e.g., 0.1.11). Leave empty to auto-increment patch version.'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
bump-version:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.RELEASE_PAT }}
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Determine version
|
||||
id: version
|
||||
env:
|
||||
INPUT_VERSION: ${{ github.event.inputs.version }}
|
||||
run: |
|
||||
if [[ -n "$INPUT_VERSION" ]]; then
|
||||
# Manual version specified - strip optional v prefix
|
||||
VERSION="${INPUT_VERSION#v}"
|
||||
# Validate strict semver format to prevent injection
|
||||
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Error: Invalid version format '$VERSION'. Must be X.Y.Z (e.g. 1.2.3 or v1.2.3)"
|
||||
exit 1
|
||||
fi
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "tag=v$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Using manual version: $VERSION"
|
||||
else
|
||||
# Auto-increment patch version
|
||||
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
|
||||
echo "Latest tag: $LATEST_TAG"
|
||||
|
||||
# Extract version number and increment
|
||||
VERSION=$(echo $LATEST_TAG | sed 's/v//')
|
||||
IFS='.' read -ra VERSION_PARTS <<< "$VERSION"
|
||||
MAJOR=${VERSION_PARTS[0]:-0}
|
||||
MINOR=${VERSION_PARTS[1]:-0}
|
||||
PATCH=${VERSION_PARTS[2]:-0}
|
||||
|
||||
# Increment patch version
|
||||
PATCH=$((PATCH + 1))
|
||||
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
|
||||
|
||||
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "tag=v$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Auto-incremented version: $NEW_VERSION"
|
||||
fi
|
||||
|
||||
- name: Check if tag already exists
|
||||
run: |
|
||||
if git rev-parse "${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
|
||||
echo "Error: Tag ${{ steps.version.outputs.tag }} already exists!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Create release branch
|
||||
run: |
|
||||
BRANCH="chore/release-${{ steps.version.outputs.tag }}"
|
||||
git checkout -b "$BRANCH"
|
||||
echo "branch=$BRANCH" >> $GITHUB_ENV
|
||||
|
||||
- name: Update pyproject.toml
|
||||
run: |
|
||||
sed -i "s/version = \".*\"/version = \"${{ steps.version.outputs.version }}\"/" pyproject.toml
|
||||
echo "Updated pyproject.toml to version ${{ steps.version.outputs.version }}"
|
||||
|
||||
- name: Update CHANGELOG.md
|
||||
run: |
|
||||
if [ -f "CHANGELOG.md" ]; then
|
||||
DATE=$(date +%Y-%m-%d)
|
||||
|
||||
# Get the previous tag by sorting all version tags numerically
|
||||
# (git describe --tags only finds tags reachable from HEAD,
|
||||
# which misses tags on unmerged release branches)
|
||||
PREVIOUS_TAG=$(git tag -l 'v*' --sort=-version:refname | head -n 1)
|
||||
|
||||
echo "Generating changelog from commits..."
|
||||
if [[ -n "$PREVIOUS_TAG" ]]; then
|
||||
echo "Changes since $PREVIOUS_TAG"
|
||||
COMMITS=$(git log --oneline "$PREVIOUS_TAG"..HEAD --no-merges --pretty=format:"- %s" 2>/dev/null || echo "- Initial release")
|
||||
else
|
||||
echo "No previous tag found - this is the first release"
|
||||
COMMITS="- Initial release"
|
||||
fi
|
||||
|
||||
# Create new changelog entry — insert after the marker comment
|
||||
NEW_ENTRY=$(printf '%s\n' \
|
||||
"" \
|
||||
"## [${{ steps.version.outputs.version }}] - $DATE" \
|
||||
"" \
|
||||
"### Changed" \
|
||||
"" \
|
||||
"$COMMITS")
|
||||
|
||||
awk -v entry="$NEW_ENTRY" '/<!-- insert new changelog below this comment -->/ { print; print entry; next } {print}' CHANGELOG.md > CHANGELOG.md.tmp
|
||||
mv CHANGELOG.md.tmp CHANGELOG.md
|
||||
|
||||
echo "✅ Updated CHANGELOG.md with commits since $PREVIOUS_TAG"
|
||||
else
|
||||
echo "No CHANGELOG.md found"
|
||||
fi
|
||||
|
||||
- name: Commit version bump
|
||||
run: |
|
||||
if [ -f "CHANGELOG.md" ]; then
|
||||
git add pyproject.toml CHANGELOG.md
|
||||
else
|
||||
git add pyproject.toml
|
||||
fi
|
||||
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes to commit"
|
||||
else
|
||||
git commit -m "chore: bump version to ${{ steps.version.outputs.version }}"
|
||||
echo "Changes committed"
|
||||
fi
|
||||
|
||||
- name: Create and push tag
|
||||
run: |
|
||||
git tag -a "${{ steps.version.outputs.tag }}" -m "Release ${{ steps.version.outputs.tag }}"
|
||||
git push origin "${{ env.branch }}"
|
||||
git push origin "${{ steps.version.outputs.tag }}"
|
||||
echo "Branch ${{ env.branch }} and tag ${{ steps.version.outputs.tag }} pushed"
|
||||
|
||||
- name: Bump to dev version
|
||||
id: dev_version
|
||||
run: |
|
||||
IFS='.' read -r MAJOR MINOR PATCH <<< "${{ steps.version.outputs.version }}"
|
||||
NEXT_DEV="$MAJOR.$MINOR.$((PATCH + 1)).dev0"
|
||||
echo "dev_version=$NEXT_DEV" >> $GITHUB_OUTPUT
|
||||
sed -i "s/version = \".*\"/version = \"$NEXT_DEV\"/" pyproject.toml
|
||||
git add pyproject.toml
|
||||
if git diff --cached --quiet; then
|
||||
echo "No dev version changes to commit"
|
||||
else
|
||||
git commit -m "chore: begin $NEXT_DEV development"
|
||||
git push origin "${{ env.branch }}"
|
||||
echo "Bumped to dev version $NEXT_DEV"
|
||||
fi
|
||||
|
||||
- name: Open pull request
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_PAT }}
|
||||
run: |
|
||||
gh pr create \
|
||||
--base main \
|
||||
--head "${{ env.branch }}" \
|
||||
--title "chore: release ${{ steps.version.outputs.version }}, begin ${{ steps.dev_version.outputs.dev_version }} development" \
|
||||
--body "Automated release of ${{ steps.version.outputs.version }}.
|
||||
|
||||
This PR was created by the Release Trigger workflow. The git tag \`${{ steps.version.outputs.tag }}\` has already been pushed and the release artifacts are being built.
|
||||
|
||||
Merging this PR will set \`main\` to \`${{ steps.dev_version.outputs.dev_version }}\` so that development installs are clearly marked as pre-release."
|
||||
|
||||
- name: Summary
|
||||
run: |
|
||||
echo "✅ Version bumped to ${{ steps.version.outputs.version }}"
|
||||
echo "✅ Tag ${{ steps.version.outputs.tag }} created and pushed"
|
||||
echo "✅ Dev version set to ${{ steps.dev_version.outputs.dev_version }}"
|
||||
echo "✅ PR opened to merge version bump into main"
|
||||
echo "🚀 Release workflow is building artifacts from the tag"
|
||||
90
.github/workflows/release.yml
vendored
90
.github/workflows/release.yml
vendored
@@ -2,58 +2,88 @@ name: Create Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'memory/**'
|
||||
- 'scripts/**'
|
||||
- 'templates/**'
|
||||
- '.github/workflows/**'
|
||||
workflow_dispatch:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Get latest tag
|
||||
id: get_tag
|
||||
|
||||
- name: Extract version from tag
|
||||
id: version
|
||||
run: |
|
||||
chmod +x .github/workflows/scripts/get-next-version.sh
|
||||
.github/workflows/scripts/get-next-version.sh
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
echo "tag=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Building release for $VERSION"
|
||||
|
||||
- name: Check if release already exists
|
||||
id: check_release
|
||||
run: |
|
||||
chmod +x .github/workflows/scripts/check-release-exists.sh
|
||||
.github/workflows/scripts/check-release-exists.sh ${{ steps.get_tag.outputs.new_version }}
|
||||
VERSION="${{ steps.version.outputs.tag }}"
|
||||
if gh release view "$VERSION" >/dev/null 2>&1; then
|
||||
echo "exists=true" >> $GITHUB_OUTPUT
|
||||
echo "Release $VERSION already exists, skipping..."
|
||||
else
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
echo "Release $VERSION does not exist, proceeding..."
|
||||
fi
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Create release package variants
|
||||
if: steps.check_release.outputs.exists == 'false'
|
||||
run: |
|
||||
chmod +x .github/workflows/scripts/create-release-packages.sh
|
||||
.github/workflows/scripts/create-release-packages.sh ${{ steps.get_tag.outputs.new_version }}
|
||||
|
||||
- name: Generate release notes
|
||||
if: steps.check_release.outputs.exists == 'false'
|
||||
id: release_notes
|
||||
run: |
|
||||
chmod +x .github/workflows/scripts/generate-release-notes.sh
|
||||
.github/workflows/scripts/generate-release-notes.sh ${{ steps.get_tag.outputs.new_version }} ${{ steps.get_tag.outputs.latest_tag }}
|
||||
VERSION="${{ steps.version.outputs.tag }}"
|
||||
VERSION_NO_V=${VERSION#v}
|
||||
|
||||
# Find previous tag
|
||||
PREVIOUS_TAG=$(git tag -l 'v*' --sort=-version:refname | grep -v "^${VERSION}$" | head -n 1)
|
||||
if [ -z "$PREVIOUS_TAG" ]; then
|
||||
PREVIOUS_TAG=""
|
||||
fi
|
||||
|
||||
# Get commits since previous tag
|
||||
if [ -z "$PREVIOUS_TAG" ]; then
|
||||
COMMIT_COUNT=$(git rev-list --count HEAD)
|
||||
if [ "$COMMIT_COUNT" -gt 20 ]; then
|
||||
COMMITS=$(git log --oneline --pretty=format:"- %s" --no-merges HEAD~20..HEAD)
|
||||
else
|
||||
COMMITS=$(git log --oneline --pretty=format:"- %s" --no-merges)
|
||||
fi
|
||||
else
|
||||
COMMITS=$(git log --oneline --pretty=format:"- %s" --no-merges "$PREVIOUS_TAG"..HEAD)
|
||||
fi
|
||||
|
||||
cat > release_notes.md << NOTES_EOF
|
||||
## Install
|
||||
|
||||
\`\`\`bash
|
||||
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@${VERSION}
|
||||
specify init my-project
|
||||
\`\`\`
|
||||
|
||||
NOTES_EOF
|
||||
|
||||
echo "## What's Changed" >> release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
echo "$COMMITS" >> release_notes.md
|
||||
|
||||
- name: Create GitHub Release
|
||||
if: steps.check_release.outputs.exists == 'false'
|
||||
run: |
|
||||
chmod +x .github/workflows/scripts/create-github-release.sh
|
||||
.github/workflows/scripts/create-github-release.sh ${{ steps.get_tag.outputs.new_version }}
|
||||
VERSION="${{ steps.version.outputs.tag }}"
|
||||
VERSION_NO_V=${VERSION#v}
|
||||
gh release create "$VERSION" \
|
||||
--title "Spec Kit - $VERSION_NO_V" \
|
||||
--notes-file release_notes.md
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Update version in pyproject.toml (for release artifacts only)
|
||||
if: steps.check_release.outputs.exists == 'false'
|
||||
run: |
|
||||
chmod +x .github/workflows/scripts/update-version.sh
|
||||
.github/workflows/scripts/update-version.sh ${{ steps.get_tag.outputs.new_version }}
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# check-release-exists.sh
|
||||
# Check if a GitHub release already exists for the given version
|
||||
# Usage: check-release-exists.sh <version>
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <version>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION="$1"
|
||||
|
||||
if gh release view "$VERSION" >/dev/null 2>&1; then
|
||||
echo "exists=true" >> $GITHUB_OUTPUT
|
||||
echo "Release $VERSION already exists, skipping..."
|
||||
else
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
echo "Release $VERSION does not exist, proceeding..."
|
||||
fi
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# create-github-release.sh
|
||||
# Create a GitHub release with all template zip files
|
||||
# Usage: create-github-release.sh <version>
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <version>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION="$1"
|
||||
|
||||
# Remove 'v' prefix from version for release title
|
||||
VERSION_NO_V=${VERSION#v}
|
||||
|
||||
gh release create "$VERSION" \
|
||||
.genreleases/spec-kit-template-copilot-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-copilot-ps-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-claude-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-claude-ps-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-gemini-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-gemini-ps-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-cursor-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-cursor-ps-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-opencode-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-opencode-ps-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-qwen-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-qwen-ps-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-windsurf-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-windsurf-ps-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-codex-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-codex-ps-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-kilocode-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-kilocode-ps-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-auggie-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-auggie-ps-"$VERSION".zip \
|
||||
--title "Spec Kit Templates - $VERSION_NO_V" \
|
||||
--notes-file release_notes.md
|
||||
225
.github/workflows/scripts/create-release-packages.sh
vendored
225
.github/workflows/scripts/create-release-packages.sh
vendored
@@ -1,225 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# create-release-packages.sh (workflow-local)
|
||||
# Build Spec Kit template release archives for each supported AI assistant and script type.
|
||||
# Usage: .github/workflows/scripts/create-release-packages.sh <version>
|
||||
# Version argument should include leading 'v'.
|
||||
# Optionally set AGENTS and/or SCRIPTS env vars to limit what gets built.
|
||||
# AGENTS : space or comma separated subset of: claude gemini copilot cursor qwen opencode windsurf codex (default: all)
|
||||
# SCRIPTS : space or comma separated subset of: sh ps (default: both)
|
||||
# Examples:
|
||||
# AGENTS=claude SCRIPTS=sh $0 v0.2.0
|
||||
# AGENTS="copilot,gemini" $0 v0.2.0
|
||||
# SCRIPTS=ps $0 v0.2.0
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <version-with-v-prefix>" >&2
|
||||
exit 1
|
||||
fi
|
||||
NEW_VERSION="$1"
|
||||
if [[ ! $NEW_VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Version must look like v0.0.0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Building release packages for $NEW_VERSION"
|
||||
|
||||
# Create and use .genreleases directory for all build artifacts
|
||||
GENRELEASES_DIR=".genreleases"
|
||||
mkdir -p "$GENRELEASES_DIR"
|
||||
rm -rf "$GENRELEASES_DIR"/* || true
|
||||
|
||||
rewrite_paths() {
|
||||
sed -E \
|
||||
-e 's@(/?)memory/@.specify/memory/@g' \
|
||||
-e 's@(/?)scripts/@.specify/scripts/@g' \
|
||||
-e 's@(/?)templates/@.specify/templates/@g'
|
||||
}
|
||||
|
||||
generate_commands() {
|
||||
local agent=$1 ext=$2 arg_format=$3 output_dir=$4 script_variant=$5
|
||||
mkdir -p "$output_dir"
|
||||
for template in templates/commands/*.md; do
|
||||
[[ -f "$template" ]] || continue
|
||||
local name description script_command body
|
||||
name=$(basename "$template" .md)
|
||||
|
||||
# Normalize line endings
|
||||
file_content=$(tr -d '\r' < "$template")
|
||||
|
||||
# Extract description and script command from YAML frontmatter
|
||||
description=$(printf '%s\n' "$file_content" | awk '/^description:/ {sub(/^description:[[:space:]]*/, ""); print; exit}')
|
||||
script_command=$(printf '%s\n' "$file_content" | awk -v sv="$script_variant" '/^[[:space:]]*'"$script_variant"':[[:space:]]*/ {sub(/^[[:space:]]*'"$script_variant"':[[:space:]]*/, ""); print; exit}')
|
||||
|
||||
if [[ -z $script_command ]]; then
|
||||
echo "Warning: no script command found for $script_variant in $template" >&2
|
||||
script_command="(Missing script command for $script_variant)"
|
||||
fi
|
||||
|
||||
# Replace {SCRIPT} placeholder with the script command
|
||||
body=$(printf '%s\n' "$file_content" | sed "s|{SCRIPT}|${script_command}|g")
|
||||
|
||||
# Remove the scripts: section from frontmatter while preserving YAML structure
|
||||
body=$(printf '%s\n' "$body" | awk '
|
||||
/^---$/ { print; if (++dash_count == 1) in_frontmatter=1; else in_frontmatter=0; next }
|
||||
in_frontmatter && /^scripts:$/ { skip_scripts=1; next }
|
||||
in_frontmatter && /^[a-zA-Z].*:/ && skip_scripts { skip_scripts=0 }
|
||||
in_frontmatter && skip_scripts && /^[[:space:]]/ { next }
|
||||
{ print }
|
||||
')
|
||||
|
||||
# Apply other substitutions
|
||||
body=$(printf '%s\n' "$body" | sed "s/{ARGS}/$arg_format/g" | sed "s/__AGENT__/$agent/g" | rewrite_paths)
|
||||
|
||||
case $ext in
|
||||
toml)
|
||||
{ echo "description = \"$description\""; echo; echo "prompt = \"\"\""; echo "$body"; echo "\"\"\""; } > "$output_dir/$name.$ext" ;;
|
||||
md)
|
||||
echo "$body" > "$output_dir/$name.$ext" ;;
|
||||
prompt.md)
|
||||
echo "$body" > "$output_dir/$name.$ext" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
build_variant() {
|
||||
local agent=$1 script=$2
|
||||
local base_dir="$GENRELEASES_DIR/sdd-${agent}-package-${script}"
|
||||
echo "Building $agent ($script) package..."
|
||||
mkdir -p "$base_dir"
|
||||
|
||||
# Copy base structure but filter scripts by variant
|
||||
SPEC_DIR="$base_dir/.specify"
|
||||
mkdir -p "$SPEC_DIR"
|
||||
|
||||
[[ -d memory ]] && { cp -r memory "$SPEC_DIR/"; echo "Copied memory -> .specify"; }
|
||||
|
||||
# Only copy the relevant script variant directory
|
||||
if [[ -d scripts ]]; then
|
||||
mkdir -p "$SPEC_DIR/scripts"
|
||||
case $script in
|
||||
sh)
|
||||
[[ -d scripts/bash ]] && { cp -r scripts/bash "$SPEC_DIR/scripts/"; echo "Copied scripts/bash -> .specify/scripts"; }
|
||||
# Copy any script files that aren't in variant-specific directories
|
||||
find scripts -maxdepth 1 -type f -exec cp {} "$SPEC_DIR/scripts/" \; 2>/dev/null || true
|
||||
;;
|
||||
ps)
|
||||
[[ -d scripts/powershell ]] && { cp -r scripts/powershell "$SPEC_DIR/scripts/"; echo "Copied scripts/powershell -> .specify/scripts"; }
|
||||
# Copy any script files that aren't in variant-specific directories
|
||||
find scripts -maxdepth 1 -type f -exec cp {} "$SPEC_DIR/scripts/" \; 2>/dev/null || true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
[[ -d templates ]] && { mkdir -p "$SPEC_DIR/templates"; find templates -type f -not -path "templates/commands/*" -exec cp --parents {} "$SPEC_DIR"/ \; ; echo "Copied templates -> .specify/templates"; }
|
||||
# Inject variant into plan-template.md within .specify/templates if present
|
||||
local plan_tpl="$base_dir/.specify/templates/plan-template.md"
|
||||
if [[ -f "$plan_tpl" ]]; then
|
||||
plan_norm=$(tr -d '\r' < "$plan_tpl")
|
||||
# Extract script command from YAML frontmatter
|
||||
script_command=$(printf '%s\n' "$plan_norm" | awk -v sv="$script" '/^[[:space:]]*'"$script"':[[:space:]]*/ {sub(/^[[:space:]]*'"$script"':[[:space:]]*/, ""); print; exit}')
|
||||
if [[ -n $script_command ]]; then
|
||||
# Always prefix with .specify/ for plan usage
|
||||
script_command=".specify/$script_command"
|
||||
# Replace {SCRIPT} placeholder with the script command and __AGENT__ with agent name
|
||||
substituted=$(sed "s|{SCRIPT}|${script_command}|g" "$plan_tpl" | tr -d '\r' | sed "s|__AGENT__|${agent}|g")
|
||||
# Strip YAML frontmatter from plan template output (keep body only)
|
||||
stripped=$(printf '%s\n' "$substituted" | awk 'BEGIN{fm=0;dash=0} /^---$/ {dash++; if(dash==1){fm=1; next} else if(dash==2){fm=0; next}} {if(!fm) print}')
|
||||
printf '%s\n' "$stripped" > "$plan_tpl"
|
||||
else
|
||||
echo "Warning: no plan-template script command found for $script in YAML frontmatter" >&2
|
||||
fi
|
||||
fi
|
||||
# NOTE: We substitute {ARGS} internally. Outward tokens differ intentionally:
|
||||
# * Markdown/prompt (claude, copilot, cursor, opencode): $ARGUMENTS
|
||||
# * TOML (gemini, qwen): {{args}}
|
||||
# This keeps formats readable without extra abstraction.
|
||||
|
||||
case $agent in
|
||||
claude)
|
||||
mkdir -p "$base_dir/.claude/commands"
|
||||
generate_commands claude md "\$ARGUMENTS" "$base_dir/.claude/commands" "$script" ;;
|
||||
gemini)
|
||||
mkdir -p "$base_dir/.gemini/commands"
|
||||
generate_commands gemini toml "{{args}}" "$base_dir/.gemini/commands" "$script"
|
||||
[[ -f agent_templates/gemini/GEMINI.md ]] && cp agent_templates/gemini/GEMINI.md "$base_dir/GEMINI.md" ;;
|
||||
copilot)
|
||||
mkdir -p "$base_dir/.github/prompts"
|
||||
generate_commands copilot prompt.md "\$ARGUMENTS" "$base_dir/.github/prompts" "$script" ;;
|
||||
cursor)
|
||||
mkdir -p "$base_dir/.cursor/commands"
|
||||
generate_commands cursor md "\$ARGUMENTS" "$base_dir/.cursor/commands" "$script" ;;
|
||||
qwen)
|
||||
mkdir -p "$base_dir/.qwen/commands"
|
||||
generate_commands qwen toml "{{args}}" "$base_dir/.qwen/commands" "$script"
|
||||
[[ -f agent_templates/qwen/QWEN.md ]] && cp agent_templates/qwen/QWEN.md "$base_dir/QWEN.md" ;;
|
||||
opencode)
|
||||
mkdir -p "$base_dir/.opencode/command"
|
||||
generate_commands opencode md "\$ARGUMENTS" "$base_dir/.opencode/command" "$script" ;;
|
||||
windsurf)
|
||||
mkdir -p "$base_dir/.windsurf/workflows"
|
||||
generate_commands windsurf md "\$ARGUMENTS" "$base_dir/.windsurf/workflows" "$script" ;;
|
||||
codex)
|
||||
mkdir -p "$base_dir/.codex/prompts"
|
||||
generate_commands codex md "\$ARGUMENTS" "$base_dir/.codex/prompts" "$script" ;;
|
||||
kilocode)
|
||||
mkdir -p "$base_dir/.kilocode/workflows"
|
||||
generate_commands kilocode md "\$ARGUMENTS" "$base_dir/.kilocode/workflows" "$script" ;;
|
||||
auggie)
|
||||
mkdir -p "$base_dir/.augment/commands"
|
||||
generate_commands auggie md "\$ARGUMENTS" "$base_dir/.augment/commands" "$script" ;;
|
||||
esac
|
||||
( cd "$base_dir" && zip -r "../spec-kit-template-${agent}-${script}-${NEW_VERSION}.zip" . )
|
||||
echo "Created $GENRELEASES_DIR/spec-kit-template-${agent}-${script}-${NEW_VERSION}.zip"
|
||||
}
|
||||
|
||||
# Determine agent list
|
||||
ALL_AGENTS=(claude gemini copilot cursor qwen opencode windsurf codex kilocode auggie)
|
||||
ALL_SCRIPTS=(sh ps)
|
||||
|
||||
|
||||
norm_list() {
|
||||
# convert comma+space separated -> space separated unique while preserving order of first occurrence
|
||||
tr ',\n' ' ' | awk '{for(i=1;i<=NF;i++){if(!seen[$i]++){printf((out?" ":"") $i)}}}END{printf("\n")}'
|
||||
}
|
||||
|
||||
validate_subset() {
|
||||
local type=$1; shift; local -n allowed=$1; shift; local items=("$@")
|
||||
local ok=1
|
||||
for it in "${items[@]}"; do
|
||||
local found=0
|
||||
for a in "${allowed[@]}"; do [[ $it == "$a" ]] && { found=1; break; }; done
|
||||
if [[ $found -eq 0 ]]; then
|
||||
echo "Error: unknown $type '$it' (allowed: ${allowed[*]})" >&2
|
||||
ok=0
|
||||
fi
|
||||
done
|
||||
return $ok
|
||||
}
|
||||
|
||||
if [[ -n ${AGENTS:-} ]]; then
|
||||
mapfile -t AGENT_LIST < <(printf '%s' "$AGENTS" | norm_list)
|
||||
validate_subset agent ALL_AGENTS "${AGENT_LIST[@]}" || exit 1
|
||||
else
|
||||
AGENT_LIST=("${ALL_AGENTS[@]}")
|
||||
fi
|
||||
|
||||
if [[ -n ${SCRIPTS:-} ]]; then
|
||||
mapfile -t SCRIPT_LIST < <(printf '%s' "$SCRIPTS" | norm_list)
|
||||
validate_subset script ALL_SCRIPTS "${SCRIPT_LIST[@]}" || exit 1
|
||||
else
|
||||
SCRIPT_LIST=("${ALL_SCRIPTS[@]}")
|
||||
fi
|
||||
|
||||
echo "Agents: ${AGENT_LIST[*]}"
|
||||
echo "Scripts: ${SCRIPT_LIST[*]}"
|
||||
|
||||
for agent in "${AGENT_LIST[@]}"; do
|
||||
for script in "${SCRIPT_LIST[@]}"; do
|
||||
build_variant "$agent" "$script"
|
||||
done
|
||||
done
|
||||
|
||||
echo "Archives in $GENRELEASES_DIR:"
|
||||
ls -1 "$GENRELEASES_DIR"/spec-kit-template-*-"${NEW_VERSION}".zip
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# generate-release-notes.sh
|
||||
# Generate release notes from git history
|
||||
# Usage: generate-release-notes.sh <new_version> <last_tag>
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "Usage: $0 <new_version> <last_tag>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NEW_VERSION="$1"
|
||||
LAST_TAG="$2"
|
||||
|
||||
# Get commits since last tag
|
||||
if [ "$LAST_TAG" = "v0.0.0" ]; then
|
||||
# Check how many commits we have and use that as the limit
|
||||
COMMIT_COUNT=$(git rev-list --count HEAD)
|
||||
if [ "$COMMIT_COUNT" -gt 10 ]; then
|
||||
COMMITS=$(git log --oneline --pretty=format:"- %s" HEAD~10..HEAD)
|
||||
else
|
||||
COMMITS=$(git log --oneline --pretty=format:"- %s" HEAD~$COMMIT_COUNT..HEAD 2>/dev/null || git log --oneline --pretty=format:"- %s")
|
||||
fi
|
||||
else
|
||||
COMMITS=$(git log --oneline --pretty=format:"- %s" $LAST_TAG..HEAD)
|
||||
fi
|
||||
|
||||
# Create release notes
|
||||
cat > release_notes.md << EOF
|
||||
This is the latest set of releases that you can use with your agent of choice. We recommend using the Specify CLI to scaffold your projects, however you can download these independently and manage them yourself.
|
||||
|
||||
EOF
|
||||
|
||||
echo "Generated release notes:"
|
||||
cat release_notes.md
|
||||
24
.github/workflows/scripts/get-next-version.sh
vendored
24
.github/workflows/scripts/get-next-version.sh
vendored
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# get-next-version.sh
|
||||
# Calculate the next version based on the latest git tag and output GitHub Actions variables
|
||||
# Usage: get-next-version.sh
|
||||
|
||||
# Get the latest tag, or use v0.0.0 if no tags exist
|
||||
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
|
||||
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
# Extract version number and increment
|
||||
VERSION=$(echo $LATEST_TAG | sed 's/v//')
|
||||
IFS='.' read -ra VERSION_PARTS <<< "$VERSION"
|
||||
MAJOR=${VERSION_PARTS[0]:-0}
|
||||
MINOR=${VERSION_PARTS[1]:-0}
|
||||
PATCH=${VERSION_PARTS[2]:-0}
|
||||
|
||||
# Increment patch version
|
||||
PATCH=$((PATCH + 1))
|
||||
NEW_VERSION="v$MAJOR.$MINOR.$PATCH"
|
||||
|
||||
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "New version will be: $NEW_VERSION"
|
||||
23
.github/workflows/scripts/update-version.sh
vendored
23
.github/workflows/scripts/update-version.sh
vendored
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# update-version.sh
|
||||
# Update version in pyproject.toml (for release artifacts only)
|
||||
# Usage: update-version.sh <version>
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <version>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION="$1"
|
||||
|
||||
# Remove 'v' prefix for Python versioning
|
||||
PYTHON_VERSION=${VERSION#v}
|
||||
|
||||
if [ -f "pyproject.toml" ]; then
|
||||
sed -i "s/version = \".*\"/version = \"$PYTHON_VERSION\"/" pyproject.toml
|
||||
echo "Updated pyproject.toml version to $PYTHON_VERSION (for release artifacts only)"
|
||||
else
|
||||
echo "Warning: pyproject.toml not found, skipping version update"
|
||||
fi
|
||||
43
.github/workflows/stale.yml
vendored
Normal file
43
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Run daily at midnight UTC
|
||||
workflow_dispatch: # Allow manual triggering
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v10
|
||||
with:
|
||||
# Days of inactivity before an issue or PR becomes stale
|
||||
days-before-stale: 150
|
||||
# Days of inactivity before a stale issue or PR is closed (after being marked stale)
|
||||
days-before-close: 30
|
||||
|
||||
# Stale issue settings
|
||||
stale-issue-message: 'This issue has been automatically marked as stale because it has not had any activity for 150 days. It will be closed in 30 days if no further activity occurs.'
|
||||
close-issue-message: 'This issue has been automatically closed due to inactivity (180 days total). If you believe this issue is still relevant, please reopen it or create a new issue.'
|
||||
stale-issue-label: 'stale'
|
||||
|
||||
# Stale PR settings
|
||||
stale-pr-message: 'This pull request has been automatically marked as stale because it has not had any activity for 150 days. It will be closed in 30 days if no further activity occurs.'
|
||||
close-pr-message: 'This pull request has been automatically closed due to inactivity (180 days total). If you believe this PR is still relevant, please reopen it or create a new PR.'
|
||||
stale-pr-label: 'stale'
|
||||
|
||||
# Exempt issues and PRs with these labels from being marked as stale
|
||||
exempt-issue-labels: 'pinned,security'
|
||||
exempt-pr-labels: 'pinned,security'
|
||||
|
||||
# Only issues or PRs with all of these labels are checked
|
||||
# Leave empty to check all issues and PRs
|
||||
any-of-labels: ''
|
||||
|
||||
# Operations per run (helps avoid rate limits)
|
||||
operations-per-run: 250
|
||||
55
.github/workflows/test.yml
vendored
Normal file
55
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
name: Test & Lint Python
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
ruff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Run ruff check
|
||||
run: uvx ruff check src/
|
||||
|
||||
pytest:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
python-version: ["3.11", "3.12", "3.13"]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync --extra test
|
||||
|
||||
# On windows-latest, bash tests auto-skip unless Git-for-Windows
|
||||
# bash (MSYS2/MINGW) is detected. The WSL launcher is rejected
|
||||
# because it cannot handle native Windows paths in test fixtures.
|
||||
# See tests/conftest.py::_has_working_bash() for details.
|
||||
- name: Run tests
|
||||
run: uv run pytest
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -32,6 +32,7 @@ env/
|
||||
*.swp
|
||||
*.swo
|
||||
.DS_Store
|
||||
*.tmp
|
||||
|
||||
# Project specific
|
||||
*.log
|
||||
@@ -42,4 +43,10 @@ env/
|
||||
# Spec Kit-specific files
|
||||
.genreleases/
|
||||
*.zip
|
||||
sdd-*/
|
||||
sdd-*/
|
||||
docs/dev
|
||||
|
||||
# Extension system
|
||||
.specify/extensions/.cache/
|
||||
.specify/extensions/.backup/
|
||||
.specify/extensions/*/local-config.yml
|
||||
|
||||
29
.markdownlint-cli2.jsonc
Normal file
29
.markdownlint-cli2.jsonc
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
// https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
|
||||
"config": {
|
||||
"default": true,
|
||||
"MD003": {
|
||||
"style": "atx"
|
||||
},
|
||||
"MD007": {
|
||||
"indent": 2
|
||||
},
|
||||
"MD013": false,
|
||||
"MD024": {
|
||||
"siblings_only": true
|
||||
},
|
||||
"MD033": false,
|
||||
"MD041": false,
|
||||
"MD049": {
|
||||
"style": "asterisk"
|
||||
},
|
||||
"MD050": {
|
||||
"style": "asterisk"
|
||||
},
|
||||
"MD036": false,
|
||||
"MD060": false
|
||||
},
|
||||
"ignores": [
|
||||
".genreleases/"
|
||||
]
|
||||
}
|
||||
29
.zenodo.json
Normal file
29
.zenodo.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"title": "Spec Kit",
|
||||
"description": "Spec Kit is an open source toolkit for Spec-Driven Development (SDD) — a methodology that helps software teams build high-quality software faster by focusing on product scenarios and predictable outcomes. It provides the Specify CLI, slash-command templates, extensions, presets, workflows, and integrations for popular AI coding agents.",
|
||||
"creators": [
|
||||
{
|
||||
"name": "Delimarsky, Den"
|
||||
},
|
||||
{
|
||||
"name": "Riem, Manfred"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"upload_type": "software",
|
||||
"keywords": [
|
||||
"spec-driven development",
|
||||
"ai coding agents",
|
||||
"software engineering",
|
||||
"cli",
|
||||
"copilot",
|
||||
"specification"
|
||||
],
|
||||
"related_identifiers": [
|
||||
{
|
||||
"identifier": "https://github.com/github/spec-kit",
|
||||
"relation": "isSupplementTo",
|
||||
"scheme": "url"
|
||||
}
|
||||
]
|
||||
}
|
||||
527
AGENTS.md
527
AGENTS.md
@@ -10,203 +10,310 @@ The toolkit supports multiple AI coding assistants, allowing teams to use their
|
||||
|
||||
---
|
||||
|
||||
## General practices
|
||||
## Integration Architecture
|
||||
|
||||
- Any changes to `__init__.py` for the Specify CLI require a version rev in `pyproject.toml` and addition of entries to `CHANGELOG.md`.
|
||||
Each AI agent is a self-contained **integration subpackage** under `src/specify_cli/integrations/<key>/`. The subpackage exposes a single class that declares all metadata and inherits setup/teardown logic from a base class. Built-in integrations are then instantiated and added to the global `INTEGRATION_REGISTRY` by `src/specify_cli/integrations/__init__.py` via `_register_builtins()`.
|
||||
|
||||
## Adding New Agent Support
|
||||
```
|
||||
src/specify_cli/integrations/
|
||||
├── __init__.py # INTEGRATION_REGISTRY + _register_builtins()
|
||||
├── base.py # IntegrationBase, MarkdownIntegration, TomlIntegration, YamlIntegration, SkillsIntegration
|
||||
├── manifest.py # IntegrationManifest (file tracking)
|
||||
├── claude/ # Example: SkillsIntegration subclass
|
||||
│ ├── __init__.py # ClaudeIntegration class
|
||||
│ └── scripts/ # Thin wrapper scripts
|
||||
│ ├── update-context.sh
|
||||
│ └── update-context.ps1
|
||||
├── gemini/ # Example: TomlIntegration subclass
|
||||
│ ├── __init__.py
|
||||
│ └── scripts/
|
||||
├── windsurf/ # Example: MarkdownIntegration subclass
|
||||
│ ├── __init__.py
|
||||
│ └── scripts/
|
||||
├── copilot/ # Example: IntegrationBase subclass (custom setup)
|
||||
│ ├── __init__.py
|
||||
│ └── scripts/
|
||||
└── ... # One subpackage per supported agent
|
||||
```
|
||||
|
||||
This section explains how to add support for new AI agents/assistants to the Specify CLI. Use this guide as a reference when integrating new AI tools into the Spec-Driven Development workflow.
|
||||
The registry is the **single source of truth for Python integration metadata**. Supported agents, their directories, formats, and capabilities are derived from the integration classes for the Python integration layer. However, context-update behavior still requires explicit cases in the shared dispatcher scripts (`scripts/bash/update-agent-context.sh` and `scripts/powershell/update-agent-context.ps1`), which currently maintain their own supported-agent lists and agent-key→context-file mappings until they are migrated to registry-based dispatch.
|
||||
|
||||
### Overview
|
||||
---
|
||||
|
||||
Specify supports multiple AI agents by generating agent-specific command files and directory structures when initializing projects. Each agent has its own conventions for:
|
||||
## Adding a New Integration
|
||||
|
||||
- **Command file formats** (Markdown, TOML, etc.)
|
||||
- **Directory structures** (`.claude/commands/`, `.windsurf/workflows/`, etc.)
|
||||
- **Command invocation patterns** (slash commands, CLI tools, etc.)
|
||||
- **Argument passing conventions** (`$ARGUMENTS`, `{{args}}`, etc.)
|
||||
### 1. Choose a base class
|
||||
|
||||
### Current Supported Agents
|
||||
| Your agent needs… | Subclass |
|
||||
|---|---|
|
||||
| Standard markdown commands (`.md`) | `MarkdownIntegration` |
|
||||
| TOML-format commands (`.toml`) | `TomlIntegration` |
|
||||
| YAML recipe files (`.yaml`) | `YamlIntegration` |
|
||||
| Skill directories (`speckit-<name>/SKILL.md`) | `SkillsIntegration` |
|
||||
| Fully custom output (companion files, settings merge, etc.) | `IntegrationBase` directly |
|
||||
|
||||
| Agent | Directory | Format | CLI Tool | Description |
|
||||
|-------|-----------|---------|----------|-------------|
|
||||
| **Claude Code** | `.claude/commands/` | Markdown | `claude` | Anthropic's Claude Code CLI |
|
||||
| **Gemini CLI** | `.gemini/commands/` | TOML | `gemini` | Google's Gemini CLI |
|
||||
| **GitHub Copilot** | `.github/prompts/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code |
|
||||
| **Cursor** | `.cursor/commands/` | Markdown | `cursor-agent` | Cursor CLI |
|
||||
| **Qwen Code** | `.qwen/commands/` | TOML | `qwen` | Alibaba's Qwen Code CLI |
|
||||
| **opencode** | `.opencode/command/` | Markdown | `opencode` | opencode CLI |
|
||||
| **Windsurf** | `.windsurf/workflows/` | Markdown | N/A (IDE-based) | Windsurf IDE workflows |
|
||||
Most agents only need `MarkdownIntegration` — a minimal subclass with zero method overrides.
|
||||
|
||||
### Step-by-Step Integration Guide
|
||||
### 2. Create the subpackage
|
||||
|
||||
Follow these steps to add a new agent (using Windsurf as an example):
|
||||
Create `src/specify_cli/integrations/<package_dir>/__init__.py`, where `<package_dir>` is the Python-safe directory name derived from `<key>`: use the key as-is when it contains no hyphens (e.g., key `"gemini"` → `gemini/`), or replace hyphens with underscores when it does (e.g., key `"kiro-cli"` → `kiro_cli/`). The `IntegrationBase.key` class attribute always retains the original hyphenated value, since that is what the CLI and registry use. For CLI-based integrations (`requires_cli: True`), the `key` should match the actual CLI tool name (the executable users install and run) so CLI checks can resolve it correctly. For IDE-based integrations (`requires_cli: False`), use the canonical integration identifier instead.
|
||||
|
||||
#### 1. Update AI_CHOICES Constant
|
||||
|
||||
Add the new agent to the `AI_CHOICES` dictionary in `src/specify_cli/__init__.py`:
|
||||
**Minimal example — Markdown agent (Windsurf):**
|
||||
|
||||
```python
|
||||
AI_CHOICES = {
|
||||
"copilot": "GitHub Copilot",
|
||||
"claude": "Claude Code",
|
||||
"gemini": "Gemini CLI",
|
||||
"cursor": "Cursor",
|
||||
"qwen": "Qwen Code",
|
||||
"opencode": "opencode",
|
||||
"windsurf": "Windsurf" # Add new agent here
|
||||
}
|
||||
"""Windsurf IDE integration."""
|
||||
|
||||
from ..base import MarkdownIntegration
|
||||
|
||||
|
||||
class WindsurfIntegration(MarkdownIntegration):
|
||||
key = "windsurf"
|
||||
config = {
|
||||
"name": "Windsurf",
|
||||
"folder": ".windsurf/",
|
||||
"commands_subdir": "workflows",
|
||||
"install_url": None,
|
||||
"requires_cli": False,
|
||||
}
|
||||
registrar_config = {
|
||||
"dir": ".windsurf/workflows",
|
||||
"format": "markdown",
|
||||
"args": "$ARGUMENTS",
|
||||
"extension": ".md",
|
||||
}
|
||||
context_file = ".windsurf/rules/specify-rules.md"
|
||||
```
|
||||
|
||||
Also update the `agent_folder_map` in the same file to include the new agent's folder for the security notice:
|
||||
**TOML agent (Gemini):**
|
||||
|
||||
```python
|
||||
agent_folder_map = {
|
||||
"claude": ".claude/",
|
||||
"gemini": ".gemini/",
|
||||
"cursor": ".cursor/",
|
||||
"qwen": ".qwen/",
|
||||
"opencode": ".opencode/",
|
||||
"codex": ".codex/",
|
||||
"windsurf": ".windsurf/", # Add new agent folder here
|
||||
"kilocode": ".kilocode/",
|
||||
"auggie": ".auggie/",
|
||||
"copilot": ".github/"
|
||||
}
|
||||
"""Gemini CLI integration."""
|
||||
|
||||
from ..base import TomlIntegration
|
||||
|
||||
|
||||
class GeminiIntegration(TomlIntegration):
|
||||
key = "gemini"
|
||||
config = {
|
||||
"name": "Gemini CLI",
|
||||
"folder": ".gemini/",
|
||||
"commands_subdir": "commands",
|
||||
"install_url": "https://github.com/google-gemini/gemini-cli",
|
||||
"requires_cli": True,
|
||||
}
|
||||
registrar_config = {
|
||||
"dir": ".gemini/commands",
|
||||
"format": "toml",
|
||||
"args": "{{args}}",
|
||||
"extension": ".toml",
|
||||
}
|
||||
context_file = "GEMINI.md"
|
||||
```
|
||||
|
||||
#### 2. Update CLI Help Text
|
||||
**Skills agent (Codex):**
|
||||
|
||||
Update all help text and examples to include the new agent:
|
||||
```python
|
||||
"""Codex CLI integration — skills-based agent."""
|
||||
|
||||
- Command option help: `--ai` parameter description
|
||||
- Function docstrings and examples
|
||||
- Error messages with agent lists
|
||||
from __future__ import annotations
|
||||
|
||||
#### 3. Update README Documentation
|
||||
from ..base import IntegrationOption, SkillsIntegration
|
||||
|
||||
Update the **Supported AI Agents** section in `README.md` to include the new agent:
|
||||
|
||||
- Add the new agent to the table with appropriate support level (Full/Partial)
|
||||
- Include the agent's official website link
|
||||
- Add any relevant notes about the agent's implementation
|
||||
- Ensure the table formatting remains aligned and consistent
|
||||
class CodexIntegration(SkillsIntegration):
|
||||
key = "codex"
|
||||
config = {
|
||||
"name": "Codex CLI",
|
||||
"folder": ".agents/",
|
||||
"commands_subdir": "skills",
|
||||
"install_url": "https://github.com/openai/codex",
|
||||
"requires_cli": True,
|
||||
}
|
||||
registrar_config = {
|
||||
"dir": ".agents/skills",
|
||||
"format": "markdown",
|
||||
"args": "$ARGUMENTS",
|
||||
"extension": "/SKILL.md",
|
||||
}
|
||||
context_file = "AGENTS.md"
|
||||
|
||||
#### 4. Update Release Package Script
|
||||
|
||||
Modify `.github/workflows/scripts/create-release-packages.sh`:
|
||||
|
||||
##### Add to ALL_AGENTS array:
|
||||
```bash
|
||||
ALL_AGENTS=(claude gemini copilot cursor qwen opencode windsurf)
|
||||
@classmethod
|
||||
def options(cls) -> list[IntegrationOption]:
|
||||
return [
|
||||
IntegrationOption(
|
||||
"--skills",
|
||||
is_flag=True,
|
||||
default=True,
|
||||
help="Install as agent skills (default for Codex)",
|
||||
),
|
||||
]
|
||||
```
|
||||
|
||||
##### Add case statement for directory structure:
|
||||
```bash
|
||||
case $agent in
|
||||
# ... existing cases ...
|
||||
windsurf)
|
||||
mkdir -p "$base_dir/.windsurf/workflows"
|
||||
generate_commands windsurf md "\$ARGUMENTS" "$base_dir/.windsurf/workflows" "$script" ;;
|
||||
esac
|
||||
#### Required fields
|
||||
|
||||
| Field | Location | Purpose |
|
||||
|---|---|---|
|
||||
| `key` | Class attribute | Unique identifier; for CLI-based integrations (`requires_cli: True`), must match the CLI executable name |
|
||||
| `config` | Class attribute (dict) | Agent metadata: `name`, `folder`, `commands_subdir`, `install_url`, `requires_cli` |
|
||||
| `registrar_config` | Class attribute (dict) | Command output config: `dir`, `format`, `args` placeholder, file `extension` |
|
||||
| `context_file` | Class attribute (str or None) | Path to agent context/instructions file (e.g., `"CLAUDE.md"`, `".github/copilot-instructions.md"`) |
|
||||
|
||||
**Key design rule:** For CLI-based integrations (`requires_cli: True`), `key` must be the actual executable name (e.g., `"cursor-agent"` not `"cursor"`). This ensures `shutil.which(key)` works for CLI-tool checks without special-case mappings. IDE-based integrations (`requires_cli: False`) should use their canonical identifier (e.g., `"windsurf"`, `"copilot"`).
|
||||
|
||||
### 3. Register it
|
||||
|
||||
In `src/specify_cli/integrations/__init__.py`, add one import and one `_register()` call inside `_register_builtins()`. Both lists are alphabetical:
|
||||
|
||||
```python
|
||||
def _register_builtins() -> None:
|
||||
# -- Imports (alphabetical) -------------------------------------------
|
||||
from .claude import ClaudeIntegration
|
||||
# ...
|
||||
from .newagent import NewAgentIntegration # ← add import
|
||||
# ...
|
||||
|
||||
# -- Registration (alphabetical) --------------------------------------
|
||||
_register(ClaudeIntegration())
|
||||
# ...
|
||||
_register(NewAgentIntegration()) # ← add registration
|
||||
# ...
|
||||
```
|
||||
|
||||
#### 4. Update GitHub Release Script
|
||||
### 4. Add scripts
|
||||
|
||||
Modify `.github/workflows/scripts/create-github-release.sh` to include the new agent's packages:
|
||||
Create two thin wrapper scripts in `src/specify_cli/integrations/<package_dir>/scripts/` that delegate to the shared context-update scripts. Each is ~25 lines of boilerplate.
|
||||
|
||||
> **Note on `<package_dir>` vs `<key>`:** `<package_dir>` is the Python-safe directory name for your integration — it matches `<key>` exactly when the key contains no hyphens (e.g., key `"gemini"` → `gemini/`), but uses underscores when it does (e.g., key `"kiro-cli"` → `kiro_cli/`). The `IntegrationBase.key` class attribute always retains the original hyphenated value (e.g., `key = "kiro-cli"`), since that is what the CLI and registry use.
|
||||
|
||||
**`update-context.sh`:**
|
||||
|
||||
```bash
|
||||
gh release create "$VERSION" \
|
||||
# ... existing packages ...
|
||||
.genreleases/spec-kit-template-windsurf-sh-"$VERSION".zip \
|
||||
.genreleases/spec-kit-template-windsurf-ps-"$VERSION".zip \
|
||||
# Add new agent packages here
|
||||
#!/usr/bin/env bash
|
||||
# update-context.sh — <Agent Name> integration: create/update <context_file>
|
||||
set -euo pipefail
|
||||
|
||||
_script_dir="$(cd "$(dirname "$0")" && pwd)"
|
||||
_root="$_script_dir"
|
||||
while [ "$_root" != "/" ] && [ ! -d "$_root/.specify" ]; do _root="$(dirname "$_root")"; done
|
||||
if [ -z "${REPO_ROOT:-}" ]; then
|
||||
if [ -d "$_root/.specify" ]; then
|
||||
REPO_ROOT="$_root"
|
||||
else
|
||||
git_root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
||||
if [ -n "$git_root" ] && [ -d "$git_root/.specify" ]; then
|
||||
REPO_ROOT="$git_root"
|
||||
else
|
||||
REPO_ROOT="$_root"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
exec "$REPO_ROOT/.specify/scripts/bash/update-agent-context.sh" <key>
|
||||
```
|
||||
|
||||
#### 5. Update Agent Context Scripts
|
||||
**`update-context.ps1`:**
|
||||
|
||||
##### Bash script (`scripts/bash/update-agent-context.sh`):
|
||||
|
||||
Add file variable:
|
||||
```bash
|
||||
WINDSURF_FILE="$REPO_ROOT/.windsurf/rules/specify-rules.md"
|
||||
```
|
||||
|
||||
Add to case statement:
|
||||
```bash
|
||||
case "$AGENT_TYPE" in
|
||||
# ... existing cases ...
|
||||
windsurf) update_agent_file "$WINDSURF_FILE" "Windsurf" ;;
|
||||
"")
|
||||
# ... existing checks ...
|
||||
[ -f "$WINDSURF_FILE" ] && update_agent_file "$WINDSURF_FILE" "Windsurf";
|
||||
# Update default creation condition
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
##### PowerShell script (`scripts/powershell/update-agent-context.ps1`):
|
||||
|
||||
Add file variable:
|
||||
```powershell
|
||||
$windsurfFile = Join-Path $repoRoot '.windsurf/rules/specify-rules.md'
|
||||
```
|
||||
# update-context.ps1 — <Agent Name> integration: create/update <context_file>
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
Add to switch statement:
|
||||
```powershell
|
||||
switch ($AgentType) {
|
||||
# ... existing cases ...
|
||||
'windsurf' { Update-AgentFile $windsurfFile 'Windsurf' }
|
||||
'' {
|
||||
foreach ($pair in @(
|
||||
# ... existing pairs ...
|
||||
@{file=$windsurfFile; name='Windsurf'}
|
||||
)) {
|
||||
if (Test-Path $pair.file) { Update-AgentFile $pair.file $pair.name }
|
||||
}
|
||||
# Update default creation condition
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
$repoRoot = try { git rev-parse --show-toplevel 2>$null } catch { $null }
|
||||
if (-not $repoRoot -or -not (Test-Path (Join-Path $repoRoot '.specify'))) {
|
||||
$repoRoot = $scriptDir
|
||||
$fsRoot = [System.IO.Path]::GetPathRoot($repoRoot)
|
||||
while ($repoRoot -and $repoRoot -ne $fsRoot -and -not (Test-Path (Join-Path $repoRoot '.specify'))) {
|
||||
$repoRoot = Split-Path -Parent $repoRoot
|
||||
}
|
||||
}
|
||||
|
||||
& "$repoRoot/.specify/scripts/powershell/update-agent-context.ps1" -AgentType <key>
|
||||
```
|
||||
|
||||
#### 6. Update CLI Tool Checks (Optional)
|
||||
Replace `<key>` with your integration key and `<Agent Name>` / `<context_file>` with the appropriate values.
|
||||
|
||||
For agents that require CLI tools, add checks in the `check()` command and agent validation:
|
||||
You must also add the agent to the shared context-update scripts so the shared dispatcher recognises the new key:
|
||||
|
||||
```python
|
||||
# In check() command
|
||||
tracker.add("windsurf", "Windsurf IDE (optional)")
|
||||
windsurf_ok = check_tool_for_tracker("windsurf", "https://windsurf.com/", tracker)
|
||||
- **`scripts/bash/update-agent-context.sh`** — add a file-path variable and a case in `update_specific_agent()`.
|
||||
- **`scripts/powershell/update-agent-context.ps1`** — add a file-path variable, add the new key to the `AgentType` parameter's `[ValidateSet(...)]`, add a switch case in `Update-SpecificAgent`, and add an entry in `Update-AllExistingAgents`.
|
||||
|
||||
# In init validation (only if CLI tool required)
|
||||
elif selected_ai == "windsurf":
|
||||
if not check_tool("windsurf", "Install from: https://windsurf.com/"):
|
||||
console.print("[red]Error:[/red] Windsurf CLI is required for Windsurf projects")
|
||||
agent_tool_missing = True
|
||||
### 5. Test it
|
||||
|
||||
```bash
|
||||
# Install into a test project
|
||||
specify init my-project --integration <key>
|
||||
|
||||
# Verify files were created in the commands directory configured by
|
||||
# config["folder"] + config["commands_subdir"] (for example, .windsurf/workflows/)
|
||||
ls -R my-project/.windsurf/workflows/
|
||||
|
||||
# Uninstall cleanly
|
||||
cd my-project && specify integration uninstall <key>
|
||||
```
|
||||
|
||||
**Note**: Skip CLI checks for IDE-based agents (Copilot, Windsurf).
|
||||
Each integration also has a dedicated test file at `tests/integrations/test_integration_<key>.py`. Note that hyphens in the key are replaced with underscores in the filename (e.g., key `cursor-agent` → `test_integration_cursor_agent.py`, key `kiro-cli` → `test_integration_kiro_cli.py`). Run it with:
|
||||
|
||||
## Agent Categories
|
||||
```bash
|
||||
pytest tests/integrations/test_integration_<key_with_underscores>.py -v
|
||||
```
|
||||
|
||||
### CLI-Based Agents
|
||||
Require a command-line tool to be installed:
|
||||
- **Claude Code**: `claude` CLI
|
||||
- **Gemini CLI**: `gemini` CLI
|
||||
- **Cursor**: `cursor-agent` CLI
|
||||
- **Qwen Code**: `qwen` CLI
|
||||
- **opencode**: `opencode` CLI
|
||||
### 6. Optional overrides
|
||||
|
||||
### IDE-Based Agents
|
||||
Work within integrated development environments:
|
||||
- **GitHub Copilot**: Built into VS Code/compatible editors
|
||||
- **Windsurf**: Built into Windsurf IDE
|
||||
The base classes handle most work automatically. Override only when the agent deviates from standard patterns:
|
||||
|
||||
| Override | When to use | Example |
|
||||
|---|---|---|
|
||||
| `command_filename(template_name)` | Custom file naming or extension | Copilot → `speckit.{name}.agent.md` |
|
||||
| `options()` | Integration-specific CLI flags via `--integration-options` | Codex → `--skills` flag, Copilot → `--skills` flag |
|
||||
| `setup()` | Custom install logic (companion files, settings merge) | Copilot → `.agent.md` + `.prompt.md` + `.vscode/settings.json` (default) or `speckit-<name>/SKILL.md` (skills mode) |
|
||||
| `teardown()` | Custom uninstall logic | Rarely needed; base handles manifest-tracked files |
|
||||
|
||||
**Example — Copilot (fully custom `setup`):**
|
||||
|
||||
Copilot extends `IntegrationBase` directly because it creates `.agent.md` commands, companion `.prompt.md` files, and merges `.vscode/settings.json`. It also supports a `--skills` mode that scaffolds `speckit-<name>/SKILL.md` under `.github/skills/` using composition with an internal `_CopilotSkillsHelper`. See `src/specify_cli/integrations/copilot/__init__.py` for the full implementation.
|
||||
|
||||
### 7. Update Devcontainer files (Optional)
|
||||
|
||||
For agents that have VS Code extensions or require CLI installation, update the devcontainer configuration files:
|
||||
|
||||
#### VS Code Extension-based Agents
|
||||
|
||||
For agents available as VS Code extensions, add them to `.devcontainer/devcontainer.json`:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
// ... existing extensions ...
|
||||
"[New Agent Extension ID]"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### CLI-based Agents
|
||||
|
||||
For agents that require CLI tools, add installation commands to `.devcontainer/post-create.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Existing installations...
|
||||
|
||||
echo -e "\n🤖 Installing [New Agent Name] CLI..."
|
||||
# run_command "npm install -g [agent-cli-package]@latest"
|
||||
echo "✅ Done"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Command File Formats
|
||||
|
||||
### Markdown Format
|
||||
Used by: Claude, Cursor, opencode, Windsurf
|
||||
|
||||
**Standard format:**
|
||||
|
||||
```markdown
|
||||
---
|
||||
@@ -216,8 +323,18 @@ description: "Command description"
|
||||
Command content with {SCRIPT} and $ARGUMENTS placeholders.
|
||||
```
|
||||
|
||||
**GitHub Copilot Chat Mode format:**
|
||||
|
||||
```markdown
|
||||
---
|
||||
description: "Command description"
|
||||
mode: speckit.command-name
|
||||
---
|
||||
|
||||
Command content with {SCRIPT} and $ARGUMENTS placeholders.
|
||||
```
|
||||
|
||||
### TOML Format
|
||||
Used by: Gemini, Qwen
|
||||
|
||||
```toml
|
||||
description = "Command description"
|
||||
@@ -227,46 +344,108 @@ Command content with {SCRIPT} and {{args}} placeholders.
|
||||
"""
|
||||
```
|
||||
|
||||
## Directory Conventions
|
||||
### YAML Format
|
||||
|
||||
- **CLI agents**: Usually `.<agent-name>/commands/`
|
||||
- **IDE agents**: Follow IDE-specific patterns:
|
||||
- Copilot: `.github/prompts/`
|
||||
- Cursor: `.cursor/commands/`
|
||||
- Windsurf: `.windsurf/workflows/`
|
||||
Used by: Goose
|
||||
|
||||
```yaml
|
||||
version: 1.0.0
|
||||
title: "Command Title"
|
||||
description: "Command description"
|
||||
author:
|
||||
contact: spec-kit
|
||||
extensions:
|
||||
- type: builtin
|
||||
name: developer
|
||||
activities:
|
||||
- Spec-Driven Development
|
||||
prompt: |
|
||||
Command content with {SCRIPT} and {{args}} placeholders.
|
||||
```
|
||||
|
||||
## Argument Patterns
|
||||
|
||||
Different agents use different argument placeholders:
|
||||
- **Markdown/prompt-based**: `$ARGUMENTS`
|
||||
- **TOML-based**: `{{args}}`
|
||||
Different agents use different argument placeholders. The placeholder used in command files is always taken from `registrar_config["args"]` for each integration — check there first when in doubt:
|
||||
|
||||
- **Markdown/prompt-based**: `$ARGUMENTS` (default for most markdown agents)
|
||||
- **TOML-based**: `{{args}}` (e.g., Gemini)
|
||||
- **YAML-based**: `{{args}}` (e.g., Goose)
|
||||
- **Custom**: some agents override the default (e.g., Forge uses `{{parameters}}`)
|
||||
- **Script placeholders**: `{SCRIPT}` (replaced with actual script path)
|
||||
- **Agent placeholders**: `__AGENT__` (replaced with agent name)
|
||||
|
||||
## Testing New Agent Integration
|
||||
## Special Processing Requirements
|
||||
|
||||
1. **Build test**: Run package creation script locally
|
||||
2. **CLI test**: Test `specify init --ai <agent>` command
|
||||
3. **File generation**: Verify correct directory structure and files
|
||||
4. **Command validation**: Ensure generated commands work with the agent
|
||||
5. **Context update**: Test agent context update scripts
|
||||
Some agents require custom processing beyond the standard template transformations:
|
||||
|
||||
### Copilot Integration
|
||||
|
||||
GitHub Copilot has unique requirements:
|
||||
- Commands use `.agent.md` extension (not `.md`)
|
||||
- Each command gets a companion `.prompt.md` file in `.github/prompts/`
|
||||
- Installs `.vscode/settings.json` with prompt file recommendations
|
||||
- Context file lives at `.github/copilot-instructions.md`
|
||||
|
||||
Implementation: Extends `IntegrationBase` with custom `setup()` method that:
|
||||
1. Processes templates with `process_template()`
|
||||
2. Generates companion `.prompt.md` files
|
||||
3. Merges VS Code settings
|
||||
|
||||
**Skills mode (`--skills`):** Copilot also supports an alternative skills-based layout
|
||||
via `--integration-options="--skills"`. When enabled:
|
||||
- Commands are scaffolded as `speckit-<name>/SKILL.md` under `.github/skills/`
|
||||
- No companion `.prompt.md` files are generated
|
||||
- No `.vscode/settings.json` merge
|
||||
- `post_process_skill_content()` injects a `mode: speckit.<stem>` frontmatter field
|
||||
- `build_command_invocation()` returns `/speckit-<stem>` instead of bare args
|
||||
|
||||
The two modes are mutually exclusive — a project uses one or the other:
|
||||
|
||||
```bash
|
||||
# Default mode: .agent.md agents + .prompt.md companions + settings merge
|
||||
specify init my-project --integration copilot
|
||||
|
||||
# Skills mode: speckit-<name>/SKILL.md under .github/skills/
|
||||
specify init my-project --integration copilot --integration-options="--skills"
|
||||
```
|
||||
|
||||
### Forge Integration
|
||||
|
||||
Forge has special frontmatter and argument requirements:
|
||||
- Uses `{{parameters}}` instead of `$ARGUMENTS`
|
||||
- Strips `handoffs` frontmatter key (Forge-specific collaboration feature)
|
||||
- Injects `name` field into frontmatter when missing
|
||||
|
||||
Implementation: Extends `MarkdownIntegration` with custom `setup()` method that:
|
||||
1. Inherits standard template processing from `MarkdownIntegration`
|
||||
2. Adds extra `$ARGUMENTS` → `{{parameters}}` replacement after template processing
|
||||
3. Applies Forge-specific transformations via `_apply_forge_transformations()`
|
||||
4. Strips `handoffs` frontmatter key
|
||||
5. Injects missing `name` fields
|
||||
6. Ensures the shared `update-agent-context.*` scripts include a `forge` case that maps context updates to `AGENTS.md` and lists `forge` in their usage/help text
|
||||
|
||||
### Goose Integration
|
||||
|
||||
Goose is a YAML-format agent using Block's recipe system:
|
||||
- Uses `.goose/recipes/` directory for YAML recipe files
|
||||
- Uses `{{args}}` argument placeholder
|
||||
- Produces YAML with `prompt: |` block scalar for command content
|
||||
|
||||
Implementation: Extends `YamlIntegration` (parallel to `TomlIntegration`):
|
||||
1. Processes templates through the standard placeholder pipeline
|
||||
2. Extracts title and description from frontmatter
|
||||
3. Renders output as Goose recipe YAML (version, title, description, author, extensions, activities, prompt)
|
||||
4. Uses `yaml.safe_dump()` for header fields to ensure proper escaping
|
||||
5. Context updates map to `AGENTS.md` (shared with opencode/codex/pi/forge)
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Forgetting update scripts**: Both bash and PowerShell scripts must be updated
|
||||
2. **Missing CLI checks**: Only add for agents that actually have CLI tools
|
||||
3. **Wrong argument format**: Use correct placeholder format for each agent type
|
||||
4. **Directory naming**: Follow agent-specific conventions exactly
|
||||
5. **Help text inconsistency**: Update all user-facing text consistently
|
||||
|
||||
## Future Considerations
|
||||
|
||||
When adding new agents:
|
||||
- Consider the agent's native command/workflow patterns
|
||||
- Ensure compatibility with the Spec-Driven Development process
|
||||
- Document any special requirements or limitations
|
||||
- Update this guide with lessons learned
|
||||
1. **Using shorthand keys for CLI-based integrations**: For CLI-based integrations (`requires_cli: True`), the `key` must match the executable name (e.g., `"cursor-agent"` not `"cursor"`). `shutil.which(key)` is used for CLI tool checks — mismatches require special-case mappings. IDE-based integrations (`requires_cli: False`) are not subject to this constraint.
|
||||
2. **Forgetting update scripts**: Both bash and PowerShell thin wrappers and the shared context-update scripts must be updated.
|
||||
3. **Incorrect `requires_cli` value**: Set to `True` only for agents that have a CLI tool; set to `False` for IDE-based agents.
|
||||
4. **Wrong argument format**: Use `$ARGUMENTS` for Markdown agents, `{{args}}` for TOML agents.
|
||||
5. **Skipping registration**: The import and `_register()` call in `_register_builtins()` must both be added.
|
||||
|
||||
---
|
||||
|
||||
*This documentation should be updated whenever new agents are added to maintain accuracy and completeness.*
|
||||
*This documentation should be updated whenever new integrations are added to maintain accuracy and completeness.*
|
||||
|
||||
1426
CHANGELOG.md
1426
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
31
CITATION.cff
Normal file
31
CITATION.cff
Normal file
@@ -0,0 +1,31 @@
|
||||
cff-version: 1.2.0
|
||||
message: >-
|
||||
If you use Spec Kit in your research or reference it in a paper,
|
||||
please cite it using the metadata below.
|
||||
type: software
|
||||
title: "Spec Kit"
|
||||
abstract: >-
|
||||
Spec Kit is an open source toolkit for Spec-Driven Development (SDD) —
|
||||
a methodology that helps software teams build high-quality software faster
|
||||
by focusing on product scenarios and predictable outcomes. It provides the
|
||||
Specify CLI, slash-command templates, extensions, presets, workflows, and
|
||||
integrations for popular AI coding agents.
|
||||
authors:
|
||||
- given-names: Den
|
||||
family-names: Delimarsky
|
||||
alias: localden
|
||||
- given-names: Manfred
|
||||
family-names: Riem
|
||||
alias: mnriem
|
||||
repository-code: "https://github.com/github/spec-kit"
|
||||
url: "https://github.github.io/spec-kit/"
|
||||
license: MIT
|
||||
version: "0.7.3"
|
||||
date-released: "2026-04-17"
|
||||
keywords:
|
||||
- spec-driven development
|
||||
- ai coding agents
|
||||
- software engineering
|
||||
- cli
|
||||
- copilot
|
||||
- specification
|
||||
@@ -14,21 +14,21 @@ orientation.
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
@@ -71,4 +71,4 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage], versi
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
|
||||
161
CONTRIBUTING.md
161
CONTRIBUTING.md
@@ -1,4 +1,4 @@
|
||||
## Contributing to Spec Kit
|
||||
# Contributing to Spec Kit
|
||||
|
||||
Hi there! We're thrilled that you'd like to contribute to Spec Kit. Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
|
||||
|
||||
@@ -11,15 +11,32 @@ These are one time installations required to be able to test your changes locall
|
||||
1. Install [Python 3.11+](https://www.python.org/downloads/)
|
||||
1. Install [uv](https://docs.astral.sh/uv/) for package management
|
||||
1. Install [Git](https://git-scm.com/downloads)
|
||||
1. Have an [AI coding agent available](README.md#-supported-ai-agents)
|
||||
1. Have an [AI coding agent available](README.md#-supported-ai-coding-agent-integrations)
|
||||
|
||||
<details>
|
||||
<summary><b>💡 Hint if you are using <code>VSCode</code> or <code>GitHub Codespaces</code> as your IDE</b></summary>
|
||||
|
||||
<br>
|
||||
|
||||
Provided you have [Docker](https://docker.com) installed on your machine, you can leverage [Dev Containers](https://containers.dev) through this [VSCode extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers), to easily set up your development environment, with aforementioned tools already installed and configured, thanks to the `.devcontainer/devcontainer.json` file (located at the root of the project).
|
||||
|
||||
To do so, simply:
|
||||
|
||||
- Checkout the repo
|
||||
- Open it with VSCode
|
||||
- Open the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) and select "Dev Containers: Open Folder in Container..."
|
||||
|
||||
On [GitHub Codespaces](https://github.com/features/codespaces) it's even simpler, as it leverages the `.devcontainer/devcontainer.json` automatically upon opening the codespace.
|
||||
|
||||
</details>
|
||||
|
||||
## Submitting a pull request
|
||||
|
||||
>[!NOTE]
|
||||
>If your pull request introduces a large change that materially impacts the work of the CLI or the rest of the repository (e.g., you're introducing new templates, arguments, or otherwise major changes), make sure that it was **discussed and agreed upon** by the project maintainers. Pull requests with large changes that did not have a prior conversation and agreement will be closed.
|
||||
> [!NOTE]
|
||||
> If your pull request introduces a large change that materially impacts the work of the CLI or the rest of the repository (e.g., you're introducing new templates, arguments, or otherwise major changes), make sure that it was **discussed and agreed upon** by the project maintainers. Pull requests with large changes that did not have a prior conversation and agreement will be closed.
|
||||
|
||||
1. Fork and clone the repository
|
||||
1. Configure and install the dependencies: `uv sync`
|
||||
1. Configure and install the dependencies: `uv sync --extra test`
|
||||
1. Make sure the CLI works on your machine: `uv run specify --help`
|
||||
1. Create a new branch: `git checkout -b my-branch-name`
|
||||
1. Make your change, add tests, and make sure everything still works
|
||||
@@ -27,6 +44,8 @@ These are one time installations required to be able to test your changes locall
|
||||
1. Push to your fork and submit a pull request
|
||||
1. Wait for your pull request to be reviewed and merged.
|
||||
|
||||
Activate the project virtual environment (see [Testing setup](#testing-setup) below), then install the CLI from your working tree (`uv pip install -e .` after `uv sync --extra test`) or otherwise ensure the shell uses the local `specify` binary before running the manual slash-command tests described below.
|
||||
|
||||
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
|
||||
|
||||
- Follow the project's coding conventions.
|
||||
@@ -40,21 +59,147 @@ Here are a few things you can do that will increase the likelihood of your pull
|
||||
|
||||
When working on spec-kit:
|
||||
|
||||
1. Test changes with the `specify` CLI commands (`/specify`, `/plan`, `/tasks`) in your coding agent of choice
|
||||
1. Test changes with the `specify` CLI commands (`/speckit.specify`, `/speckit.plan`, `/speckit.tasks`) in your coding agent of choice
|
||||
2. Verify templates are working correctly in `templates/` directory
|
||||
3. Test script functionality in the `scripts/` directory
|
||||
4. Ensure memory files (`memory/constitution.md`) are updated if major process changes are made
|
||||
|
||||
### Recommended validation flow
|
||||
|
||||
For the smoothest review experience, validate changes in this order:
|
||||
|
||||
1. **Run focused automated checks first** — use the quick verification commands [below](#automated-checks) to catch scaffolding and configuration regressions early.
|
||||
2. **Run manual workflow tests second** — if your change affects slash commands or the developer workflow, follow the [manual testing](#manual-testing) section to choose the right commands, run them in an agent, and capture results for your PR.
|
||||
|
||||
### Automated checks
|
||||
|
||||
#### Agent configuration and wiring consistency
|
||||
|
||||
```bash
|
||||
uv run python -m pytest tests/test_agent_config_consistency.py -q
|
||||
```
|
||||
|
||||
Run this when you change agent metadata, context update scripts, or integration wiring.
|
||||
|
||||
### Manual testing
|
||||
|
||||
#### Testing setup
|
||||
|
||||
```bash
|
||||
# Install the project and test dependencies from your local branch
|
||||
cd <spec-kit-repo>
|
||||
uv sync --extra test
|
||||
source .venv/bin/activate # On Windows (CMD): .venv\Scripts\activate | (PowerShell): .venv\Scripts\Activate.ps1
|
||||
uv pip install -e .
|
||||
# Ensure the `specify` binary in this environment points at your working tree so the agent runs the branch you're testing.
|
||||
|
||||
# Initialize a test project using your local changes
|
||||
uv run specify init <temp-dir>/speckit-test --integration <agent>
|
||||
cd <temp-dir>/speckit-test
|
||||
|
||||
# Open in your agent
|
||||
```
|
||||
|
||||
#### Manual testing process
|
||||
|
||||
Any change that affects a slash command's behavior requires manually testing that command through a coding agent and submitting results with the PR.
|
||||
|
||||
1. **Identify affected commands** — use the [prompt below](#determining-which-tests-to-run) to have your agent analyze your changed files and determine which commands need testing.
|
||||
2. **Set up a test project** — scaffold from your local branch (see [Testing setup](#testing-setup)).
|
||||
3. **Run each affected command** — invoke it in your agent, verify it completes successfully, and confirm it produces the expected output (files created, scripts executed, artifacts populated).
|
||||
4. **Run prerequisites first** — commands that depend on earlier commands (e.g., `/speckit.tasks` requires `/speckit.plan` which requires `/speckit.specify`) must be run in order.
|
||||
5. **Report results** — paste the [reporting template](#reporting-results) into your PR with pass/fail for each command tested.
|
||||
|
||||
#### Reporting results
|
||||
|
||||
Paste this into your PR:
|
||||
|
||||
~~~markdown
|
||||
## Manual test results
|
||||
|
||||
**Agent**: [e.g., GitHub Copilot in VS Code] | **OS/Shell**: [e.g., macOS/zsh]
|
||||
|
||||
| Command tested | Notes |
|
||||
|----------------|-------|
|
||||
| `/speckit.command` | |
|
||||
~~~
|
||||
|
||||
#### Determining which tests to run
|
||||
|
||||
Copy this prompt into your agent. Include the agent's response (selected tests plus a brief explanation of the mapping) in your PR.
|
||||
|
||||
~~~text
|
||||
Read CONTRIBUTING.md, then run `git diff --name-only main` to get my changed files.
|
||||
For each changed file, determine which slash commands it affects by reading
|
||||
the command templates in templates/commands/ to understand what each command
|
||||
invokes. Use these mapping rules:
|
||||
|
||||
- templates/commands/X.md → the command it defines
|
||||
- scripts/bash/Y.sh or scripts/powershell/Y.ps1 → every command that invokes that script (grep templates/commands/ for the script name). Also check transitive dependencies: if the changed script is sourced by other scripts (e.g., common.sh is sourced by create-new-feature.sh, check-prerequisites.sh, setup-plan.sh, update-agent-context.sh), then every command invoking those downstream scripts is also affected
|
||||
- templates/Z-template.md → every command that consumes that template during execution
|
||||
- src/specify_cli/*.py → CLI commands (`specify init`, `specify check`, `specify extension *`, `specify preset *`); test the affected CLI command and, for init/scaffolding changes, at minimum test /speckit.specify
|
||||
- extensions/X/commands/* → the extension command it defines
|
||||
- extensions/X/scripts/* → every extension command that invokes that script
|
||||
- extensions/X/extension.yml or config-template.yml → every command in that extension. Also check if the manifest defines hooks (look for `hooks:` entries like `before_specify`, `after_implement`, etc.) — if so, the core commands those hooks attach to are also affected
|
||||
- presets/*/* → test preset scaffolding via `specify init` with the preset
|
||||
- pyproject.toml → packaging/bundling; test `specify init` and verify bundled assets
|
||||
|
||||
Include prerequisite tests (e.g., T5 requires T3 requires T1).
|
||||
|
||||
Output in this format:
|
||||
|
||||
### Test selection reasoning
|
||||
|
||||
| Changed file | Affects | Test | Why |
|
||||
|---|---|---|---|
|
||||
| (path) | (command) | T# | (reason) |
|
||||
|
||||
### Required tests
|
||||
|
||||
Number each test sequentially (T1, T2, ...). List prerequisite tests first.
|
||||
|
||||
- T1: /speckit.command — (reason)
|
||||
- T2: /speckit.command — (reason)
|
||||
~~~
|
||||
|
||||
## AI contributions in Spec Kit
|
||||
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> If you are using **any kind of AI assistance** to contribute to Spec Kit,
|
||||
> it must be disclosed in the pull request or issue.
|
||||
|
||||
We welcome and encourage the use of AI tools to help improve Spec Kit! Many valuable contributions have been enhanced with AI assistance for code generation, issue detection, and feature definition.
|
||||
|
||||
That being said, if you are using any kind of AI assistance (e.g., agents, ChatGPT) while contributing to Spec Kit,
|
||||
**this must be disclosed in the pull request or issue**, along with the extent to which AI assistance was used (e.g., documentation comments vs. code generation).
|
||||
|
||||
If your PR responses or comments are being generated by an AI, disclose that as well.
|
||||
|
||||
As an exception, trivial spacing or typo fixes don't need to be disclosed, so long as the changes are limited to small parts of the code or short phrases.
|
||||
|
||||
An example disclosure:
|
||||
|
||||
> This PR was written primarily by GitHub Copilot.
|
||||
|
||||
Or a more detailed disclosure:
|
||||
|
||||
> I consulted ChatGPT to understand the codebase but the solution
|
||||
> was fully authored manually by myself.
|
||||
|
||||
Failure to disclose this is first and foremost rude to the human operators on the other end of the pull request, but it also makes it difficult to
|
||||
determine how much scrutiny to apply to the contribution.
|
||||
|
||||
In a perfect world, AI assistance would produce equal or higher quality work than any human. That isn't the world we live in today, and in most cases
|
||||
where human supervision or expertise is not in the loop, it's generating code that cannot be reasonably maintained or evolved.
|
||||
|
||||
### What we're looking for
|
||||
|
||||
When submitting AI-assisted contributions, please ensure they include:
|
||||
|
||||
- **Clear disclosure of AI use** - You are transparent about AI use and degree to which you're using it for the contribution
|
||||
- **Human understanding and testing** - You've personally tested the changes and understand what they do
|
||||
- **Clear rationale** - You can explain why the change is needed and how it fits within Spec Kit's goals
|
||||
- **Clear rationale** - You can explain why the change is needed and how it fits within Spec Kit's goals
|
||||
- **Concrete evidence** - Include test cases, scenarios, or examples that demonstrate the improvement
|
||||
- **Your own analysis** - Share your thoughts on the end-to-end developer experience
|
||||
|
||||
@@ -72,6 +217,8 @@ The key is demonstrating that you understand and have validated your proposed ch
|
||||
|
||||
Contributors who consistently submit low-effort AI-generated changes may be restricted from further contributions at the maintainers' discretion.
|
||||
|
||||
Please be respectful to maintainers and disclose AI assistance.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Spec-Driven Development Methodology](./spec-driven.md)
|
||||
|
||||
24
DEVELOPMENT.md
Normal file
24
DEVELOPMENT.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Development Notes
|
||||
|
||||
Spec Kit is a toolkit for spec-driven development. At its core, it is a coordinated set of prompts, templates, scripts, and CLI/integration assets that define and deliver a spec-driven workflow for AI coding agents. This document is a starting point for people modifying Spec Kit itself, with a compact orientation to the key project documents and repository organization.
|
||||
|
||||
**Essential project documents:**
|
||||
|
||||
| Document | Role |
|
||||
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| [README.md](README.md) | Primary user-facing overview of Spec Kit and its workflow. |
|
||||
| [DEVELOPMENT.md](DEVELOPMENT.md) | This document. |
|
||||
| [spec-driven.md](spec-driven.md) | End-to-end explanation of the Spec-Driven Development workflow supported by Spec Kit. |
|
||||
| [RELEASE-PROCESS.md](.github/workflows/RELEASE-PROCESS.md) | Release workflow, versioning rules, and changelog generation process. |
|
||||
| [docs/index.md](docs/index.md) | Entry point to the `docs/` documentation set. |
|
||||
| [CONTRIBUTING.md](CONTRIBUTING.md) | Contribution process, review expectations, testing, and required development practices. |
|
||||
|
||||
**Main repository components:**
|
||||
|
||||
| Directory | Role |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------- |
|
||||
| `templates/` | Prompt assets and templates that define the core workflow behavior and generated artifacts. |
|
||||
| `scripts/` | Supporting scripts used by the workflow, setup, and repository tooling. |
|
||||
| `src/specify_cli/` | Python source for the `specify` CLI, including agent-specific assets. |
|
||||
| `extensions/` | Extension-related docs, catalogs, and supporting assets. |
|
||||
| `presets/` | Preset-related docs, catalogs, and supporting assets. |
|
||||
1
LICENSE
1
LICENSE
@@ -19,3 +19,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
612
README.md
612
README.md
@@ -1,32 +1,41 @@
|
||||
<div align="center">
|
||||
<img src="./media/logo_small.webp"/>
|
||||
<img src="./media/logo_large.webp" alt="Spec Kit Logo" width="200" height="200"/>
|
||||
<h1>🌱 Spec Kit</h1>
|
||||
<h3><em>Build high-quality software faster.</em></h3>
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<strong>An effort to allow organizations to focus on product scenarios rather than writing undifferentiated code with the help of Spec-Driven Development.</strong>
|
||||
<strong>An open source toolkit that allows you to focus on product scenarios and predictable outcomes instead of vibe coding every piece from scratch.</strong>
|
||||
</p>
|
||||
|
||||
[](https://github.com/github/spec-kit/actions/workflows/release.yml)
|
||||
<p align="center">
|
||||
<a href="https://github.com/github/spec-kit/releases/latest"><img src="https://img.shields.io/github/v/release/github/spec-kit" alt="Latest Release"/></a>
|
||||
<a href="https://github.com/github/spec-kit/stargazers"><img src="https://img.shields.io/github/stars/github/spec-kit?style=social" alt="GitHub stars"/></a>
|
||||
<a href="https://github.com/github/spec-kit/blob/main/LICENSE"><img src="https://img.shields.io/github/license/github/spec-kit" alt="License"/></a>
|
||||
<a href="https://github.github.io/spec-kit/"><img src="https://img.shields.io/badge/docs-GitHub_Pages-blue" alt="Documentation"/></a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [🤔 What is Spec-Driven Development?](#-what-is-spec-driven-development)
|
||||
- [⚡ Get started](#-get-started)
|
||||
- [⚡ Get Started](#-get-started)
|
||||
- [📽️ Video Overview](#️-video-overview)
|
||||
- [🤖 Supported AI Agents](#-supported-ai-agents)
|
||||
- [🧩 Community Extensions](#-community-extensions)
|
||||
- [🎨 Community Presets](#-community-presets)
|
||||
- [🚶 Community Walkthroughs](#-community-walkthroughs)
|
||||
- [🛠️ Community Friends](#️-community-friends)
|
||||
- [🤖 Supported AI Coding Agent Integrations](#-supported-ai-coding-agent-integrations)
|
||||
- [🔧 Specify CLI Reference](#-specify-cli-reference)
|
||||
- [📚 Core philosophy](#-core-philosophy)
|
||||
- [🌟 Development phases](#-development-phases)
|
||||
- [🎯 Experimental goals](#-experimental-goals)
|
||||
- [🧩 Making Spec Kit Your Own: Extensions & Presets](#-making-spec-kit-your-own-extensions--presets)
|
||||
- [📚 Core Philosophy](#-core-philosophy)
|
||||
- [🌟 Development Phases](#-development-phases)
|
||||
- [🎯 Experimental Goals](#-experimental-goals)
|
||||
- [🔧 Prerequisites](#-prerequisites)
|
||||
- [📖 Learn more](#-learn-more)
|
||||
- [📋 Detailed process](#-detailed-process)
|
||||
- [📖 Learn More](#-learn-more)
|
||||
- [📋 Detailed Process](#-detailed-process)
|
||||
- [🔍 Troubleshooting](#-troubleshooting)
|
||||
- [👥 Maintainers](#-maintainers)
|
||||
- [💬 Support](#-support)
|
||||
- [🙏 Acknowledgements](#-acknowledgements)
|
||||
- [📄 License](#-license)
|
||||
@@ -35,54 +44,123 @@
|
||||
|
||||
Spec-Driven Development **flips the script** on traditional software development. For decades, code has been king — specifications were just scaffolding we built and discarded once the "real work" of coding began. Spec-Driven Development changes this: **specifications become executable**, directly generating working implementations rather than just guiding them.
|
||||
|
||||
## ⚡ Get started
|
||||
## ⚡ Get Started
|
||||
|
||||
### 1. Install Specify
|
||||
### 1. Install Specify CLI
|
||||
|
||||
Initialize your project depending on the coding agent you're using:
|
||||
Choose your preferred installation method:
|
||||
|
||||
> **Important:** The only official, maintained packages for Spec Kit are published from this GitHub repository. Any packages with the same name on PyPI are **not** affiliated with this project and are not maintained by the Spec Kit maintainers. Always install directly from GitHub as shown below.
|
||||
|
||||
#### Option 1: Persistent Installation (Recommended)
|
||||
|
||||
Install once and use everywhere. Pin a specific release tag for stability (check [Releases](https://github.com/github/spec-kit/releases) for the latest):
|
||||
|
||||
```bash
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME>
|
||||
# Install a specific stable release (recommended — replace vX.Y.Z with the latest tag)
|
||||
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@vX.Y.Z
|
||||
|
||||
# Or install latest from main (may include unreleased changes)
|
||||
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git
|
||||
|
||||
# Alternative: using pipx (also works)
|
||||
pipx install git+https://github.com/github/spec-kit.git@vX.Y.Z
|
||||
pipx install git+https://github.com/github/spec-kit.git
|
||||
```
|
||||
|
||||
Then verify the correct version is installed:
|
||||
|
||||
```bash
|
||||
specify version
|
||||
```
|
||||
|
||||
And use the tool directly:
|
||||
|
||||
```bash
|
||||
# Create new project
|
||||
specify init <PROJECT_NAME>
|
||||
|
||||
# Or initialize in existing project
|
||||
specify init . --integration copilot
|
||||
# or
|
||||
specify init --here --integration copilot
|
||||
|
||||
# Check installed tools
|
||||
specify check
|
||||
```
|
||||
|
||||
To upgrade Specify, see the [Upgrade Guide](./docs/upgrade.md) for detailed instructions. Quick upgrade:
|
||||
|
||||
```bash
|
||||
uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git@vX.Y.Z
|
||||
# pipx users: pipx install --force git+https://github.com/github/spec-kit.git@vX.Y.Z
|
||||
```
|
||||
|
||||
#### Option 2: One-time Usage
|
||||
|
||||
Run directly without installing:
|
||||
|
||||
```bash
|
||||
# Create new project (pinned to a stable release — replace vX.Y.Z with the latest tag)
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <PROJECT_NAME>
|
||||
|
||||
# Or initialize in existing project
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init . --integration copilot
|
||||
# or
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init --here --integration copilot
|
||||
```
|
||||
|
||||
**Benefits of persistent installation:**
|
||||
|
||||
- Tool stays installed and available in PATH
|
||||
- No need to create shell aliases
|
||||
- Better tool management with `uv tool list`, `uv tool upgrade`, `uv tool uninstall`
|
||||
- Cleaner shell configuration
|
||||
|
||||
#### Option 3: Enterprise / Air-Gapped Installation
|
||||
|
||||
If your environment blocks access to PyPI or GitHub, see the [Enterprise / Air-Gapped Installation](./docs/installation.md#enterprise--air-gapped-installation) guide for step-by-step instructions on using `pip download` to create portable, OS-specific wheel bundles on a connected machine.
|
||||
|
||||
### 2. Establish project principles
|
||||
|
||||
Use the **`/constitution`** command to create your project's governing principles and development guidelines that will guide all subsequent development.
|
||||
Launch your coding agent in the project directory. Most agents expose spec-kit as `/speckit.*` slash commands; Codex CLI in skills mode uses `$speckit-*` instead.
|
||||
|
||||
Use the **`/speckit.constitution`** command to create your project's governing principles and development guidelines that will guide all subsequent development.
|
||||
|
||||
```bash
|
||||
/constitution Create principles focused on code quality, testing standards, user experience consistency, and performance requirements
|
||||
/speckit.constitution Create principles focused on code quality, testing standards, user experience consistency, and performance requirements
|
||||
```
|
||||
|
||||
### 3. Create the spec
|
||||
|
||||
Use the **`/specify`** command to describe what you want to build. Focus on the **what** and **why**, not the tech stack.
|
||||
Use the **`/speckit.specify`** command to describe what you want to build. Focus on the **what** and **why**, not the tech stack.
|
||||
|
||||
```bash
|
||||
/specify Build an application that can help me organize my photos in separate photo albums. Albums are grouped by date and can be re-organized by dragging and dropping on the main page. Albums are never in other nested albums. Within each album, photos are previewed in a tile-like interface.
|
||||
/speckit.specify Build an application that can help me organize my photos in separate photo albums. Albums are grouped by date and can be re-organized by dragging and dropping on the main page. Albums are never in other nested albums. Within each album, photos are previewed in a tile-like interface.
|
||||
```
|
||||
|
||||
### 4. Create a technical implementation plan
|
||||
|
||||
Use the **`/plan`** command to provide your tech stack and architecture choices.
|
||||
Use the **`/speckit.plan`** command to provide your tech stack and architecture choices.
|
||||
|
||||
```bash
|
||||
/plan The application uses Vite with minimal number of libraries. Use vanilla HTML, CSS, and JavaScript as much as possible. Images are not uploaded anywhere and metadata is stored in a local SQLite database.
|
||||
/speckit.plan The application uses Vite with minimal number of libraries. Use vanilla HTML, CSS, and JavaScript as much as possible. Images are not uploaded anywhere and metadata is stored in a local SQLite database.
|
||||
```
|
||||
|
||||
### 5. Break down into tasks
|
||||
|
||||
Use **`/tasks`** to create an actionable task list from your implementation plan.
|
||||
Use **`/speckit.tasks`** to create an actionable task list from your implementation plan.
|
||||
|
||||
```bash
|
||||
/tasks
|
||||
/speckit.tasks
|
||||
```
|
||||
|
||||
### 6. Execute implementation
|
||||
|
||||
Use **`/implement`** to execute all tasks and build your feature according to the plan.
|
||||
Use **`/speckit.implement`** to execute all tasks and build your feature according to the plan.
|
||||
|
||||
```bash
|
||||
/implement
|
||||
/speckit.implement
|
||||
```
|
||||
|
||||
For detailed step-by-step instructions, see our [comprehensive guide](./spec-driven.md).
|
||||
@@ -93,116 +171,245 @@ Want to see Spec Kit in action? Watch our [video overview](https://www.youtube.c
|
||||
|
||||
[](https://www.youtube.com/watch?v=a9eR1xsfvHg&pp=0gcJCckJAYcqIYzv)
|
||||
|
||||
## 🤖 Supported AI Agents
|
||||
## 🧩 Community Extensions
|
||||
|
||||
| Agent | Support | Notes |
|
||||
|-----------------------------------------------------------|---------|---------------------------------------------------|
|
||||
| [Claude Code](https://www.anthropic.com/claude-code) | ✅ | |
|
||||
| [GitHub Copilot](https://code.visualstudio.com/) | ✅ | |
|
||||
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | ✅ | |
|
||||
| [Cursor](https://cursor.sh/) | ✅ | |
|
||||
| [Qwen Code](https://github.com/QwenLM/qwen-code) | ✅ | |
|
||||
| [opencode](https://opencode.ai/) | ✅ | |
|
||||
| [Windsurf](https://windsurf.com/) | ✅ | |
|
||||
| [Kilo Code](https://github.com/Kilo-Org/kilocode) | ✅ | |
|
||||
| [Auggie CLI](https://docs.augmentcode.com/cli/overview) | ✅ | |
|
||||
| [Codex CLI](https://github.com/openai/codex) | ⚠️ | Codex [does not support](https://github.com/openai/codex/issues/2890) custom arguments for slash commands. |
|
||||
> [!NOTE]
|
||||
> Community extensions are independently created and maintained by their respective authors. GitHub and the Spec Kit maintainers may review pull requests that add entries to the community catalog for formatting, catalog structure, or policy compliance, but they do **not review, audit, endorse, or support the extension code itself**. The Community Extensions website is also a third-party resource. Review extension source code before installation and use at your own discretion.
|
||||
|
||||
🔍 **Browse and search community extensions on the [Community Extensions website](https://speckit-community.github.io/extensions/).**
|
||||
|
||||
The following community-contributed extensions are available in [`catalog.community.json`](extensions/catalog.community.json):
|
||||
|
||||
**Categories:**
|
||||
|
||||
- `docs` — reads, validates, or generates spec artifacts
|
||||
- `code` — reviews, validates, or modifies source code
|
||||
- `process` — orchestrates workflow across phases
|
||||
- `integration` — syncs with external platforms
|
||||
- `visibility` — reports on project health or progress
|
||||
|
||||
**Effect:**
|
||||
|
||||
- `Read-only` — produces reports without modifying files
|
||||
- `Read+Write` — modifies files, creates artifacts, or updates specs
|
||||
|
||||
| Extension | Purpose | Category | Effect | URL |
|
||||
|-----------|---------|----------|--------|-----|
|
||||
| Agent Assign | Assign specialized Claude Code agents to spec-kit tasks for targeted execution | `process` | Read+Write | [spec-kit-agent-assign](https://github.com/xymelon/spec-kit-agent-assign) |
|
||||
| AI-Driven Engineering (AIDE) | A structured 7-step workflow for building new projects from scratch with AI assistants — from vision through implementation | `process` | Read+Write | [aide](https://github.com/mnriem/spec-kit-extensions/tree/main/aide) |
|
||||
| Architect Impact Previewer | Predicts architectural impact, complexity, and risks of proposed changes before implementation. | `visibility` | Read-only | [spec-kit-architect-preview](https://github.com/UmmeHabiba1312/spec-kit-architect-preview) |
|
||||
| Archive Extension | Archive merged features into main project memory. | `docs` | Read+Write | [spec-kit-archive](https://github.com/stn1slv/spec-kit-archive) |
|
||||
| Azure DevOps Integration | Sync user stories and tasks to Azure DevOps work items using OAuth authentication | `integration` | Read+Write | [spec-kit-azure-devops](https://github.com/pragya247/spec-kit-azure-devops) |
|
||||
| Blueprint | Stay code-literate in AI-driven development: review a complete code blueprint for every task from spec artifacts before /speckit.implement runs | `docs` | Read+Write | [spec-kit-blueprint](https://github.com/chordpli/spec-kit-blueprint) |
|
||||
| Branch Convention | Configurable branch and folder naming conventions for /specify with presets and custom patterns | `process` | Read+Write | [spec-kit-branch-convention](https://github.com/Quratulain-bilal/spec-kit-branch-convention) |
|
||||
| Brownfield Bootstrap | Bootstrap spec-kit for existing codebases — auto-discover architecture and adopt SDD incrementally | `process` | Read+Write | [spec-kit-brownfield](https://github.com/Quratulain-bilal/spec-kit-brownfield) |
|
||||
| Bugfix Workflow | Structured bugfix workflow — capture bugs, trace to spec artifacts, and patch specs surgically | `process` | Read+Write | [spec-kit-bugfix](https://github.com/Quratulain-bilal/spec-kit-bugfix) |
|
||||
| Canon | Adds canon-driven (baseline-driven) workflows: spec-first, code-first, spec-drift. Requires Canon Core preset installation. | `process` | Read+Write | [spec-kit-canon](https://github.com/maximiliamus/spec-kit-canon/tree/master/extension) |
|
||||
| Catalog CI | Automated validation for spec-kit community catalog entries — structure, URLs, diffs, and linting | `process` | Read-only | [spec-kit-catalog-ci](https://github.com/Quratulain-bilal/spec-kit-catalog-ci) |
|
||||
| CI Guard | Spec compliance gates for CI/CD — verify specs exist, check drift, and block merges on gaps | `process` | Read-only | [spec-kit-ci-guard](https://github.com/Quratulain-bilal/spec-kit-ci-guard) |
|
||||
| Checkpoint Extension | Commit the changes made during the middle of the implementation, so you don't end up with just one very large commit at the end | `code` | Read+Write | [spec-kit-checkpoint](https://github.com/aaronrsun/spec-kit-checkpoint) |
|
||||
| Cleanup Extension | Post-implementation quality gate that reviews changes, fixes small issues (scout rule), creates tasks for medium issues, and generates analysis for large issues | `code` | Read+Write | [spec-kit-cleanup](https://github.com/dsrednicki/spec-kit-cleanup) |
|
||||
| Conduct Extension | Orchestrates spec-kit phases via sub-agent delegation to reduce context pollution. | `process` | Read+Write | [spec-kit-conduct-ext](https://github.com/twbrandon7/spec-kit-conduct-ext) |
|
||||
| Confluence Extension | Create a doc in Confluence summarizing the specifications and planning files | `integration` | Read+Write | [spec-kit-confluence](https://github.com/aaronrsun/spec-kit-confluence) |
|
||||
| DocGuard — CDD Enforcement | Canonical-Driven Development enforcement. Validates, scores, and traces project documentation with automated checks, AI-driven workflows, and spec-kit hooks. Zero NPM runtime dependencies. | `docs` | Read+Write | [spec-kit-docguard](https://github.com/raccioly/docguard) |
|
||||
| Extensify | Create and validate extensions and extension catalogs | `process` | Read+Write | [extensify](https://github.com/mnriem/spec-kit-extensions/tree/main/extensify) |
|
||||
| Fix Findings | Automated analyze-fix-reanalyze loop that resolves spec findings until clean | `code` | Read+Write | [spec-kit-fix-findings](https://github.com/Quratulain-bilal/spec-kit-fix-findings) |
|
||||
| FixIt Extension | Spec-aware bug fixing — maps bugs to spec artifacts, proposes a plan, applies minimal changes | `code` | Read+Write | [spec-kit-fixit](https://github.com/speckit-community/spec-kit-fixit) |
|
||||
| Fleet Orchestrator | Orchestrate a full feature lifecycle with human-in-the-loop gates across all SpecKit phases | `process` | Read+Write | [spec-kit-fleet](https://github.com/sharathsatish/spec-kit-fleet) |
|
||||
| GitHub Issues Integration 1 | Generate spec artifacts from GitHub Issues - import issues, sync updates, and maintain bidirectional traceability | `integration` | Read+Write | [spec-kit-github-issues](https://github.com/Fatima367/spec-kit-github-issues) |
|
||||
| GitHub Issues Integration 2 | Creates and syncs local specs from an existing GitHub issue | `integration` | Read+Write | [spec-kit-issue](https://github.com/aaronrsun/spec-kit-issue) |
|
||||
| Iterate | Iterate on spec documents with a two-phase define-and-apply workflow — refine specs mid-implementation and go straight back to building | `docs` | Read+Write | [spec-kit-iterate](https://github.com/imviancagrace/spec-kit-iterate) |
|
||||
| Jira Integration | Create Jira Epics, Stories, and Issues from spec-kit specifications and task breakdowns with configurable hierarchy and custom field support | `integration` | Read+Write | [spec-kit-jira](https://github.com/mbachorik/spec-kit-jira) |
|
||||
| Learning Extension | Generate educational guides from implementations and enhance clarifications with mentoring context | `docs` | Read+Write | [spec-kit-learn](https://github.com/imviancagrace/spec-kit-learn) |
|
||||
| MAQA — Multi-Agent & Quality Assurance | Coordinator → feature → QA agent workflow with parallel worktree-based implementation. Language-agnostic. Auto-detects installed board plugins. Optional CI gate. | `process` | Read+Write | [spec-kit-maqa-ext](https://github.com/GenieRobot/spec-kit-maqa-ext) |
|
||||
| MAQA Azure DevOps Integration | Azure DevOps Boards integration for MAQA — syncs User Stories and Task children as features progress | `integration` | Read+Write | [spec-kit-maqa-azure-devops](https://github.com/GenieRobot/spec-kit-maqa-azure-devops) |
|
||||
| MAQA CI/CD Gate | Auto-detects GitHub Actions, CircleCI, GitLab CI, and Bitbucket Pipelines. Blocks QA handoff until pipeline is green. | `process` | Read+Write | [spec-kit-maqa-ci](https://github.com/GenieRobot/spec-kit-maqa-ci) |
|
||||
| MAQA GitHub Projects Integration | GitHub Projects v2 integration for MAQA — syncs draft issues and Status columns as features progress | `integration` | Read+Write | [spec-kit-maqa-github-projects](https://github.com/GenieRobot/spec-kit-maqa-github-projects) |
|
||||
| MAQA Jira Integration | Jira integration for MAQA — syncs Stories and Subtasks as features progress through the board | `integration` | Read+Write | [spec-kit-maqa-jira](https://github.com/GenieRobot/spec-kit-maqa-jira) |
|
||||
| MAQA Linear Integration | Linear integration for MAQA — syncs issues and sub-issues across workflow states as features progress | `integration` | Read+Write | [spec-kit-maqa-linear](https://github.com/GenieRobot/spec-kit-maqa-linear) |
|
||||
| MAQA Trello Integration | Trello board integration for MAQA — populates board from specs, moves cards, real-time checklist ticking | `integration` | Read+Write | [spec-kit-maqa-trello](https://github.com/GenieRobot/spec-kit-maqa-trello) |
|
||||
| MarkItDown Document Converter | Convert documents (PDF, Word, PowerPoint, Excel, and more) to Markdown for use as spec reference material | `docs` | Read+Write | [spec-kit-markitdown](https://github.com/BenBtg/spec-kit-markitdown) |
|
||||
| Memory Loader | Loads .specify/memory/ files before lifecycle commands so LLM agents have project governance context | `docs` | Read-only | [spec-kit-memory-loader](https://github.com/KevinBrown5280/spec-kit-memory-loader) |
|
||||
| Memory MD | Repository-native durable memory for Spec Kit projects | `docs` | Read+Write | [spec-kit-memory-hub](https://github.com/DyanGalih/spec-kit-memory-hub) |
|
||||
| MemoryLint | Agent memory governance tool: Automatically audits and fixes boundary conflicts between AGENTS.md and the constitution. | `process` | Read+Write | [memorylint](https://github.com/RbBtSn0w/spec-kit-extensions/tree/main/memorylint) |
|
||||
| Microsoft 365 Integration | Fetch Teams messages, meeting transcripts, and SharePoint/OneDrive files as local Markdown for spec generation | `integration` | Read+Write | [spec-kit-m365](https://github.com/BenBtg/spec-kit-m365) |
|
||||
| Onboard | Contextual onboarding and progressive growth for developers new to spec-kit projects. Explains specs, maps dependencies, validates understanding, and guides the next step | `process` | Read+Write | [spec-kit-onboard](https://github.com/dmux/spec-kit-onboard) |
|
||||
| Optimize | Audit and optimize AI governance for context efficiency — token budgets, rule health, interpretability, compression, coherence, and echo detection | `process` | Read+Write | [spec-kit-optimize](https://github.com/sakitA/spec-kit-optimize) |
|
||||
| Plan Review Gate | Require spec.md and plan.md to be merged via MR/PR before allowing task generation | `process` | Read-only | [spec-kit-plan-review-gate](https://github.com/luno/spec-kit-plan-review-gate) |
|
||||
| PR Bridge | Auto-generate pull request descriptions, checklists, and summaries from spec artifacts | `process` | Read-only | [spec-kit-pr-bridge-](https://github.com/Quratulain-bilal/spec-kit-pr-bridge-) |
|
||||
| Presetify | Create and validate presets and preset catalogs | `process` | Read+Write | [presetify](https://github.com/mnriem/spec-kit-extensions/tree/main/presetify) |
|
||||
| Product Forge | Full product lifecycle from research to release — portfolio, lite mode, monorepo, optional V-Model | `process` | Read+Write | [speckit-product-forge](https://github.com/VaiYav/speckit-product-forge) |
|
||||
| Project Health Check | Diagnose a Spec Kit project and report health issues across structure, agents, features, scripts, extensions, and git | `visibility` | Read-only | [spec-kit-doctor](https://github.com/KhawarHabibKhan/spec-kit-doctor) |
|
||||
| Project Status | Show current SDD workflow progress — active feature, artifact status, task completion, workflow phase, and extensions summary | `visibility` | Read-only | [spec-kit-status](https://github.com/KhawarHabibKhan/spec-kit-status) |
|
||||
| QA Testing Extension | Systematic QA testing with browser-driven or CLI-based validation of acceptance criteria from spec | `code` | Read-only | [spec-kit-qa](https://github.com/arunt14/spec-kit-qa) |
|
||||
| Ralph Loop | Autonomous implementation loop using AI agent CLI | `code` | Read+Write | [spec-kit-ralph](https://github.com/Rubiss/spec-kit-ralph) |
|
||||
| Reconcile Extension | Reconcile implementation drift by surgically updating feature artifacts. | `docs` | Read+Write | [spec-kit-reconcile](https://github.com/stn1slv/spec-kit-reconcile) |
|
||||
| Red Team | Adversarial review of specs before /speckit.plan — parallel lens agents surface risks that clarify/analyze structurally can't (prompt injection, integrity gaps, cross-spec drift, silent failures). Produces a structured findings report; no auto-edits to specs. | `docs` | Read+Write | [spec-kit-red-team](https://github.com/ashbrener/spec-kit-red-team) |
|
||||
| Repository Index | Generate index for existing repo for overview, architecture and module level. | `docs` | Read-only | [spec-kit-repoindex](https://github.com/liuyiyu/spec-kit-repoindex) |
|
||||
| Retro Extension | Sprint retrospective analysis with metrics, spec accuracy assessment, and improvement suggestions | `process` | Read+Write | [spec-kit-retro](https://github.com/arunt14/spec-kit-retro) |
|
||||
| Retrospective Extension | Post-implementation retrospective with spec adherence scoring, drift analysis, and human-gated spec updates | `docs` | Read+Write | [spec-kit-retrospective](https://github.com/emi-dm/spec-kit-retrospective) |
|
||||
| Review Extension | Post-implementation comprehensive code review with specialized agents for code quality, comments, tests, error handling, type design, and simplification | `code` | Read-only | [spec-kit-review](https://github.com/ismaelJimenez/spec-kit-review) |
|
||||
| Ripple | Detect side effects that tests can't catch after implementation — delta-anchored analysis across 9 domain-agnostic categories | `code` | Read+Write | [spec-kit-ripple](https://github.com/chordpli/spec-kit-ripple) |
|
||||
| SDD Utilities | Resume interrupted workflows, validate project health, and verify spec-to-task traceability | `process` | Read+Write | [speckit-utils](https://github.com/mvanhorn/speckit-utils) |
|
||||
| Security Review | Comprehensive security audit of codebases using AI-powered DevSecOps analysis | `code` | Read-only | [spec-kit-security-review](https://github.com/DyanGalih/spec-kit-security-review) |
|
||||
| SFSpeckit | Enterprise Salesforce SDLC with 18 commands for the full SDD lifecycle. | `process` | Read+Write | [spec-kit-sf](https://github.com/ysumanth06/spec-kit-sf) |
|
||||
| Ship Release Extension | Automates release pipeline: pre-flight checks, branch sync, changelog generation, CI verification, and PR creation | `process` | Read+Write | [spec-kit-ship](https://github.com/arunt14/spec-kit-ship) |
|
||||
| Spec Reference Loader | Reads the ## References section from the feature spec and loads only the listed docs into context | `docs` | Read-only | [spec-kit-spec-reference-loader](https://github.com/KevinBrown5280/spec-kit-spec-reference-loader) |
|
||||
| Spec Critique Extension | Dual-lens critical review of spec and plan from product strategy and engineering risk perspectives | `docs` | Read-only | [spec-kit-critique](https://github.com/arunt14/spec-kit-critique) |
|
||||
| Spec Diagram | Auto-generate Mermaid diagrams of SDD workflow state, feature progress, and task dependencies | `visibility` | Read-only | [spec-kit-diagram-](https://github.com/Quratulain-bilal/spec-kit-diagram-) |
|
||||
| Spec Orchestrator | Cross-feature orchestration — track state, select tasks, and detect conflicts across parallel specs | `process` | Read-only | [spec-kit-orchestrator](https://github.com/Quratulain-bilal/spec-kit-orchestrator) |
|
||||
| Spec Refine | Update specs in-place, propagate changes to plan and tasks, and diff impact across artifacts | `process` | Read+Write | [spec-kit-refine](https://github.com/Quratulain-bilal/spec-kit-refine) |
|
||||
| Spec Scope | Effort estimation and scope tracking — estimate work, detect creep, and budget time per phase | `process` | Read-only | [spec-kit-scope-](https://github.com/Quratulain-bilal/spec-kit-scope-) |
|
||||
| Spec Sync | Detect and resolve drift between specs and implementation. AI-assisted resolution with human approval | `docs` | Read+Write | [spec-kit-sync](https://github.com/bgervin/spec-kit-sync) |
|
||||
| Spec Validate | Comprehension validation, review gating, and approval state for spec-kit artifacts — staged quizzes, peer review SLA, and a hard gate before /speckit.implement | `process` | Read+Write | [spec-kit-spec-validate](https://github.com/aeltayeb/spec-kit-spec-validate) |
|
||||
| SpecTest | Auto-generate test scaffolds from spec criteria, map coverage, and find untested requirements | `code` | Read+Write | [spec-kit-spectest](https://github.com/Quratulain-bilal/spec-kit-spectest) |
|
||||
| Staff Review Extension | Staff-engineer-level code review that validates implementation against spec, checks security, performance, and test coverage | `code` | Read-only | [spec-kit-staff-review](https://github.com/arunt14/spec-kit-staff-review) |
|
||||
| Status Report | Project status, feature progress, and next-action recommendations for spec-driven workflows | `visibility` | Read-only | [Open-Agent-Tools/spec-kit-status](https://github.com/Open-Agent-Tools/spec-kit-status) |
|
||||
| Superpowers Bridge | Orchestrates obra/superpowers skills within the spec-kit SDD workflow across the full lifecycle (clarification, TDD, review, verification, critique, debugging, branch completion) | `process` | Read+Write | [superpowers-bridge](https://github.com/RbBtSn0w/spec-kit-extensions/tree/main/superpowers-bridge) |
|
||||
| Superpowers Bridge (WangX0111) | Bridges spec-kit with obra/superpowers (brainstorming, TDD, subagent, code-review) into a unified, resumable workflow with graceful degradation and session progress tracking | `process` | Read+Write | [superspec](https://github.com/WangX0111/superspec) |
|
||||
| TinySpec | Lightweight single-file workflow for small tasks — skip the heavy multi-step SDD process | `process` | Read+Write | [spec-kit-tinyspec](https://github.com/Quratulain-bilal/spec-kit-tinyspec) |
|
||||
| V-Model Extension Pack | Enforces V-Model paired generation of development specs and test specs with full traceability | `docs` | Read+Write | [spec-kit-v-model](https://github.com/leocamello/spec-kit-v-model) |
|
||||
| Verify Extension | Post-implementation quality gate that validates implemented code against specification artifacts | `code` | Read-only | [spec-kit-verify](https://github.com/ismaelJimenez/spec-kit-verify) |
|
||||
| Verify Tasks Extension | Detect phantom completions: tasks marked [X] in tasks.md with no real implementation | `code` | Read-only | [spec-kit-verify-tasks](https://github.com/datastone-inc/spec-kit-verify-tasks) |
|
||||
| Version Guard | Verify tech stack versions against live npm registries before planning and implementation | `process` | Read-only | [spec-kit-version-guard](https://github.com/KevinBrown5280/spec-kit-version-guard) |
|
||||
| What-if Analysis | Preview the downstream impact (complexity, effort, tasks, risks) of requirement changes before committing to them | `visibility` | Read-only | [spec-kit-whatif](https://github.com/DevAbdullah90/spec-kit-whatif) |
|
||||
| Wireframe Visual Feedback Loop | SVG wireframe generation, review, and sign-off for spec-driven development. Approved wireframes become spec constraints honored by /speckit.plan, /speckit.tasks, and /speckit.implement | `visibility` | Read+Write | [spec-kit-extension-wireframe](https://github.com/TortoiseWolfe/spec-kit-extension-wireframe) |
|
||||
| Worktree Isolation | Spawn isolated git worktrees for parallel feature development without checkout switching | `process` | Read+Write | [spec-kit-worktree](https://github.com/Quratulain-bilal/spec-kit-worktree) |
|
||||
| Worktrees | Default-on worktree isolation for parallel agents — sibling or nested layout | `process` | Read+Write | [spec-kit-worktree-parallel](https://github.com/dango85/spec-kit-worktree-parallel) |
|
||||
|
||||
To submit your own extension, see the [Extension Publishing Guide](extensions/EXTENSION-PUBLISHING-GUIDE.md).
|
||||
|
||||
## 🎨 Community Presets
|
||||
|
||||
Community-contributed presets customize how Spec Kit behaves — overriding templates, commands, and terminology without changing any tooling. See the full list on the [Community Presets](https://github.github.io/spec-kit/community/presets.html) page.
|
||||
|
||||
> [!NOTE]
|
||||
> Community presets are third-party contributions and are not maintained by the Spec Kit team. Review them carefully before use, and see the docs page above for the full disclaimer.
|
||||
|
||||
To submit your own preset, see the [Presets Publishing Guide](presets/PUBLISHING.md).
|
||||
|
||||
## 🚶 Community Walkthroughs
|
||||
|
||||
See Spec-Driven Development in action across different scenarios with community-contributed walkthroughs; find the full list on the [Community Walkthroughs](https://github.github.io/spec-kit/community/walkthroughs.html) page.
|
||||
|
||||
## 🛠️ Community Friends
|
||||
|
||||
Community projects that extend, visualize, or build on Spec Kit. See the full list on the [Community Friends](https://github.github.io/spec-kit/community/friends.html) page.
|
||||
|
||||
## 🤖 Supported AI Coding Agent Integrations
|
||||
|
||||
Spec Kit works with 30+ AI coding agents — both CLI tools and IDE-based assistants. See the full list with notes and usage details in the [Supported AI Coding Agent Integrations](https://github.github.io/spec-kit/reference/integrations.html) guide.
|
||||
|
||||
Run `specify integration list` to see all available integrations in your installed version.
|
||||
|
||||
## Available Slash Commands
|
||||
|
||||
After running `specify init`, your AI coding agent will have access to these slash commands for structured development. For integrations that support skills mode, passing `--integration <agent> --integration-options="--skills"` installs agent skills instead of slash-command prompt files.
|
||||
|
||||
#### Core Commands
|
||||
|
||||
Essential commands for the Spec-Driven Development workflow:
|
||||
|
||||
| Command | Agent Skill | Description |
|
||||
| ------------------------ | ---------------------- | -------------------------------------------------------------------------- |
|
||||
| `/speckit.constitution` | `speckit-constitution` | Create or update project governing principles and development guidelines |
|
||||
| `/speckit.specify` | `speckit-specify` | Define what you want to build (requirements and user stories) |
|
||||
| `/speckit.plan` | `speckit-plan` | Create technical implementation plans with your chosen tech stack |
|
||||
| `/speckit.tasks` | `speckit-tasks` | Generate actionable task lists for implementation |
|
||||
| `/speckit.taskstoissues` | `speckit-taskstoissues`| Convert generated task lists into GitHub issues for tracking and execution |
|
||||
| `/speckit.implement` | `speckit-implement` | Execute all tasks to build the feature according to the plan |
|
||||
|
||||
#### Optional Commands
|
||||
|
||||
Additional commands for enhanced quality and validation:
|
||||
|
||||
| Command | Agent Skill | Description |
|
||||
| -------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `/speckit.clarify` | `speckit-clarify` | Clarify underspecified areas (recommended before `/speckit.plan`; formerly `/quizme`) |
|
||||
| `/speckit.analyze` | `speckit-analyze` | Cross-artifact consistency & coverage analysis (run after `/speckit.tasks`, before `/speckit.implement`) |
|
||||
| `/speckit.checklist` | `speckit-checklist` | Generate custom quality checklists that validate requirements completeness, clarity, and consistency (like "unit tests for English") |
|
||||
|
||||
## 🔧 Specify CLI Reference
|
||||
|
||||
The `specify` command supports the following options:
|
||||
For full command details, options, and examples, see the [CLI Reference](https://github.github.io/spec-kit/reference/overview.html).
|
||||
|
||||
### Commands
|
||||
## 🧩 Making Spec Kit Your Own: Extensions & Presets
|
||||
|
||||
| Command | Description |
|
||||
|-------------|----------------------------------------------------------------|
|
||||
| `init` | Initialize a new Specify project from the latest template |
|
||||
| `check` | Check for installed tools (`git`, `claude`, `gemini`, `code`/`code-insiders`, `cursor-agent`, `windsurf`, `qwen`, `opencode`, `codex`) |
|
||||
Spec Kit can be tailored to your needs through two complementary systems — **extensions** and **presets** — plus project-local overrides for one-off adjustments:
|
||||
|
||||
### `specify init` Arguments & Options
|
||||
| Priority | Component Type | Location |
|
||||
| -------: | ------------------------------------------------- | -------------------------------- |
|
||||
| ⬆ 1 | Project-Local Overrides | `.specify/templates/overrides/` |
|
||||
| 2 | Presets — Customize core & extensions | `.specify/presets/templates/` |
|
||||
| 3 | Extensions — Add new capabilities | `.specify/extensions/templates/` |
|
||||
| ⬇ 4 | Spec Kit Core — Built-in SDD commands & templates | `.specify/templates/` |
|
||||
|
||||
| Argument/Option | Type | Description |
|
||||
|------------------------|----------|------------------------------------------------------------------------------|
|
||||
| `<project-name>` | Argument | Name for your new project directory (optional if using `--here`) |
|
||||
| `--ai` | Option | AI assistant to use: `claude`, `gemini`, `copilot`, `cursor`, `qwen`, `opencode`, `codex`, `windsurf`, `kilocode`, or `auggie` |
|
||||
| `--script` | Option | Script variant to use: `sh` (bash/zsh) or `ps` (PowerShell) |
|
||||
| `--ignore-agent-tools` | Flag | Skip checks for AI agent tools like Claude Code |
|
||||
| `--no-git` | Flag | Skip git repository initialization |
|
||||
| `--here` | Flag | Initialize project in the current directory instead of creating a new one |
|
||||
| `--skip-tls` | Flag | Skip SSL/TLS verification (not recommended) |
|
||||
| `--debug` | Flag | Enable detailed debug output for troubleshooting |
|
||||
| `--github-token` | Option | GitHub token for API requests (or set GH_TOKEN/GITHUB_TOKEN env variable) |
|
||||
- **Templates** are resolved at **runtime** — Spec Kit walks the stack top-down and uses the first match.
|
||||
- Project-local overrides (`.specify/templates/overrides/`) let you make one-off adjustments for a single project without creating a full preset.
|
||||
- **Extension/preset commands** are applied at **install time** — when you run `specify extension add` or `specify preset add`, command files are written into agent directories (e.g., `.claude/commands/`).
|
||||
- If multiple presets or extensions provide the same command, the highest-priority version wins. On removal, the next-highest-priority version is restored automatically.
|
||||
- If no overrides or customizations exist, Spec Kit uses its core defaults.
|
||||
|
||||
### Examples
|
||||
### Extensions — Add New Capabilities
|
||||
|
||||
Use **extensions** when you need functionality that goes beyond Spec Kit's core. Extensions introduce new commands and templates — for example, adding domain-specific workflows that are not covered by the built-in SDD commands, integrating with external tools, or adding entirely new development phases. They expand *what Spec Kit can do*.
|
||||
|
||||
```bash
|
||||
# Basic project initialization
|
||||
specify init my-project
|
||||
# Search available extensions
|
||||
specify extension search
|
||||
|
||||
# Initialize with specific AI assistant
|
||||
specify init my-project --ai claude
|
||||
|
||||
# Initialize with Cursor support
|
||||
specify init my-project --ai cursor
|
||||
|
||||
# Initialize with Windsurf support
|
||||
specify init my-project --ai windsurf
|
||||
|
||||
# Initialize with PowerShell scripts (Windows/cross-platform)
|
||||
specify init my-project --ai copilot --script ps
|
||||
|
||||
# Initialize in current directory
|
||||
specify init --here --ai copilot
|
||||
|
||||
# Skip git initialization
|
||||
specify init my-project --ai gemini --no-git
|
||||
|
||||
# Enable debug output for troubleshooting
|
||||
specify init my-project --ai claude --debug
|
||||
|
||||
# Use GitHub token for API requests (helpful for corporate environments)
|
||||
specify init my-project --ai claude --github-token ghp_your_token_here
|
||||
|
||||
# Check system requirements
|
||||
specify check
|
||||
# Install an extension
|
||||
specify extension add <extension-name>
|
||||
```
|
||||
|
||||
### Available Slash Commands
|
||||
For example, extensions could add Jira integration, post-implementation code review, V-Model test traceability, or project health diagnostics.
|
||||
|
||||
After running `specify init`, your AI coding agent will have access to these slash commands for structured development:
|
||||
See the [Extensions reference](https://github.github.io/spec-kit/reference/extensions.html) for the full command guide. Browse the [community extensions](#-community-extensions) above for what's available.
|
||||
|
||||
| Command | Description |
|
||||
|-----------------|-----------------------------------------------------------------------|
|
||||
| `/constitution` | Create or update project governing principles and development guidelines |
|
||||
| `/specify` | Define what you want to build (requirements and user stories) |
|
||||
| `/plan` | Create technical implementation plans with your chosen tech stack |
|
||||
| `/tasks` | Generate actionable task lists for implementation |
|
||||
| `/implement` | Execute all tasks to build the feature according to the plan |
|
||||
### Presets — Customize Existing Workflows
|
||||
|
||||
### Environment Variables
|
||||
Use **presets** when you want to change *how* Spec Kit works without adding new capabilities. Presets override the templates and commands that ship with the core *and* with installed extensions — for example, enforcing a compliance-oriented spec format, using domain-specific terminology, or applying organizational standards to plans and tasks. They customize the artifacts and instructions that Spec Kit and its extensions produce.
|
||||
|
||||
| Variable | Description |
|
||||
|------------------|------------------------------------------------------------------------------------------------|
|
||||
| `SPECIFY_FEATURE` | Override feature detection for non-Git repositories. Set to the feature directory name (e.g., `001-photo-albums`) to work on a specific feature when not using Git branches.<br/>**Must be set in the context of the agent you're working with prior to using `/plan` or follow-up commands. |
|
||||
```bash
|
||||
# Search available presets
|
||||
specify preset search
|
||||
|
||||
## 📚 Core philosophy
|
||||
# Install a preset
|
||||
specify preset add <preset-name>
|
||||
```
|
||||
|
||||
For example, presets could restructure spec templates to require regulatory traceability, adapt the workflow to fit the methodology you use (e.g., Agile, Kanban, Waterfall, jobs-to-be-done, or domain-driven design), add mandatory security review gates to plans, enforce test-first task ordering, or localize the entire workflow to a different language. The [pirate-speak demo](https://github.com/mnriem/spec-kit-pirate-speak-preset-demo) shows just how deep the customization can go. Multiple presets can be stacked with priority ordering.
|
||||
|
||||
See the [Presets reference](https://github.github.io/spec-kit/reference/presets.html) for the full command guide, including resolution order and priority stacking.
|
||||
|
||||
### When to Use Which
|
||||
|
||||
| Goal | Use |
|
||||
| --- | --- |
|
||||
| Add a brand-new command or workflow | Extension |
|
||||
| Customize the format of specs, plans, or tasks | Preset |
|
||||
| Integrate an external tool or service | Extension |
|
||||
| Enforce organizational or regulatory standards | Preset |
|
||||
| Ship reusable domain-specific templates | Either — presets for template overrides, extensions for templates bundled with new commands |
|
||||
|
||||
## 📚 Core Philosophy
|
||||
|
||||
Spec-Driven Development is a structured process that emphasizes:
|
||||
|
||||
- **Intent-driven development** where specifications define the "_what_" before the "_how_"
|
||||
- **Intent-driven development** where specifications define the "*what*" before the "*how*"
|
||||
- **Rich specification creation** using guardrails and organizational principles
|
||||
- **Multi-step refinement** rather than one-shot code generation from prompts
|
||||
- **Heavy reliance** on advanced AI model capabilities for specification interpretation
|
||||
|
||||
## 🌟 Development phases
|
||||
## 🌟 Development Phases
|
||||
|
||||
| Phase | Focus | Key Activities |
|
||||
|-------|-------|----------------|
|
||||
| **0-to-1 Development** ("Greenfield") | Generate from scratch | <ul><li>Start with high-level requirements</li><li>Generate specifications</li><li>Plan implementation steps</li><li>Build production-ready applications</li></ul> |
|
||||
| **Creative Exploration** | Parallel implementations | <ul><li>Explore diverse solutions</li><li>Support multiple technology stacks & architectures</li><li>Experiment with UX patterns</li></ul> |
|
||||
| **Iterative Enhancement** ("Brownfield") | Brownfield modernization | <ul><li>Add features iteratively</li><li>Modernize legacy systems</li><li>Adapt processes</li></ul> |
|
||||
| Phase | Focus | Key Activities |
|
||||
| ---------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **0-to-1 Development** ("Greenfield") | Generate from scratch | <ul><li>Start with high-level requirements</li><li>Generate specifications</li><li>Plan implementation steps</li><li>Build production-ready applications</li></ul> |
|
||||
| **Creative Exploration** | Parallel implementations | <ul><li>Explore diverse solutions</li><li>Support multiple technology stacks & architectures</li><li>Experiment with UX patterns</li></ul> |
|
||||
| **Iterative Enhancement** ("Brownfield") | Brownfield modernization | <ul><li>Add features iteratively</li><li>Modernize legacy systems</li><li>Adapt processes</li></ul> |
|
||||
|
||||
## 🎯 Experimental goals
|
||||
## 🎯 Experimental Goals
|
||||
|
||||
Our research and experimentation focus on:
|
||||
|
||||
@@ -230,22 +437,22 @@ Our research and experimentation focus on:
|
||||
|
||||
## 🔧 Prerequisites
|
||||
|
||||
- **Linux/macOS** (or WSL2 on Windows)
|
||||
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Cursor](https://cursor.sh/), [Qwen CLI](https://github.com/QwenLM/qwen-code), [opencode](https://opencode.ai/), [Codex CLI](https://github.com/openai/codex), or [Windsurf](https://windsurf.com/)
|
||||
- [uv](https://docs.astral.sh/uv/) for package management
|
||||
- **Linux/macOS/Windows**
|
||||
- [Supported](#-supported-ai-coding-agent-integrations) AI coding agent.
|
||||
- [uv](https://docs.astral.sh/uv/) for package management (recommended) or [pipx](https://pypa.github.io/pipx/) for persistent installation
|
||||
- [Python 3.11+](https://www.python.org/downloads/)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
|
||||
If you encounter issues with an agent, please open an issue so we can refine the integration.
|
||||
|
||||
## 📖 Learn more
|
||||
## 📖 Learn More
|
||||
|
||||
- **[Complete Spec-Driven Development Methodology](./spec-driven.md)** - Deep dive into the full process
|
||||
- **[Detailed Walkthrough](#-detailed-process)** - Step-by-step implementation guide
|
||||
|
||||
---
|
||||
|
||||
## 📋 Detailed process
|
||||
## 📋 Detailed Process
|
||||
|
||||
<details>
|
||||
<summary>Click to expand the detailed step-by-step walkthrough</summary>
|
||||
@@ -259,55 +466,67 @@ specify init <project_name>
|
||||
Or initialize in the current directory:
|
||||
|
||||
```bash
|
||||
specify init .
|
||||
# or use the --here flag
|
||||
specify init --here
|
||||
# Skip confirmation when the directory already has files
|
||||
specify init . --force
|
||||
# or
|
||||
specify init --here --force
|
||||
```
|
||||
|
||||

|
||||
|
||||
You will be prompted to select the AI agent you are using. You can also proactively specify it directly in the terminal:
|
||||
You will be prompted to select the coding agent integration you are using. You can also proactively specify it directly in the terminal:
|
||||
|
||||
```bash
|
||||
specify init <project_name> --ai claude
|
||||
specify init <project_name> --ai gemini
|
||||
specify init <project_name> --ai copilot
|
||||
specify init <project_name> --ai cursor
|
||||
specify init <project_name> --ai qwen
|
||||
specify init <project_name> --ai opencode
|
||||
specify init <project_name> --ai codex
|
||||
specify init <project_name> --ai windsurf
|
||||
specify init <project_name> --integration copilot
|
||||
specify init <project_name> --integration gemini
|
||||
specify init <project_name> --integration codex
|
||||
|
||||
# Or in current directory:
|
||||
specify init --here --ai claude
|
||||
specify init --here --ai codex
|
||||
specify init . --integration copilot
|
||||
specify init . --integration codex --integration-options="--skills"
|
||||
|
||||
# or use --here flag
|
||||
specify init --here --integration copilot
|
||||
specify init --here --integration codex --integration-options="--skills"
|
||||
|
||||
# Force merge into a non-empty current directory
|
||||
specify init . --force --integration copilot
|
||||
|
||||
# or
|
||||
specify init --here --force --integration copilot
|
||||
```
|
||||
|
||||
The CLI will check if you have Claude Code, Gemini CLI, Cursor CLI, Qwen CLI, opencode, or Codex CLI installed. If you do not, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command:
|
||||
The CLI will check if you have Claude Code, Gemini CLI, Cursor CLI, Qwen CLI, opencode, Codex CLI, Qoder CLI, Tabnine CLI, Kiro CLI, Pi, Forge, Goose, or Mistral Vibe installed. If you do not, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command:
|
||||
|
||||
```bash
|
||||
specify init <project_name> --ai claude --ignore-agent-tools
|
||||
specify init <project_name> --integration copilot --ignore-agent-tools
|
||||
```
|
||||
|
||||
### **STEP 1:** Establish project principles
|
||||
|
||||
Go to the project folder and run your AI agent. In our example, we're using `claude`.
|
||||
Go to the project folder and run your coding agent. In our example, we're using `claude`.
|
||||
|
||||

|
||||
|
||||
You will know that things are configured correctly if you see the `/constitution`, `/specify`, `/plan`, `/tasks`, and `/implement` commands available.
|
||||
You will know that things are configured correctly if you see the `/speckit.constitution`, `/speckit.specify`, `/speckit.plan`, `/speckit.tasks`, and `/speckit.implement` commands available.
|
||||
|
||||
The first step should be establishing your project's governing principles using the `/constitution` command. This helps ensure consistent decision-making throughout all subsequent development phases:
|
||||
The first step should be establishing your project's governing principles using the `/speckit.constitution` command. This helps ensure consistent decision-making throughout all subsequent development phases:
|
||||
|
||||
```text
|
||||
/constitution Create principles focused on code quality, testing standards, user experience consistency, and performance requirements. Include governance for how these principles should guide technical decisions and implementation choices.
|
||||
/speckit.constitution Create principles focused on code quality, testing standards, user experience consistency, and performance requirements. Include governance for how these principles should guide technical decisions and implementation choices.
|
||||
```
|
||||
|
||||
This step creates or updates the `/memory/constitution.md` file with your project's foundational guidelines that the AI agent will reference during specification, planning, and implementation phases.
|
||||
This step creates or updates the `.specify/memory/constitution.md` file with your project's foundational guidelines that the coding agent will reference during specification, planning, and implementation phases.
|
||||
|
||||
### **STEP 2:** Create project specifications
|
||||
|
||||
With your project principles established, you can now create the functional specifications. Use the `/specify` command and then provide the concrete requirements for the project you want to develop.
|
||||
With your project principles established, you can now create the functional specifications. Use the `/speckit.specify` command and then provide the concrete requirements for the project you want to develop.
|
||||
|
||||
>[!IMPORTANT]
|
||||
>Be as explicit as possible about _what_ you are trying to build and _why_. **Do not focus on the tech stack at this point**.
|
||||
> [!IMPORTANT]
|
||||
> Be as explicit as possible about *what* you are trying to build and *why*. **Do not focus on the tech stack at this point**.
|
||||
|
||||
An example prompt:
|
||||
|
||||
@@ -339,27 +558,38 @@ The produced specification should contain a set of user stories and functional r
|
||||
At this stage, your project folder contents should resemble the following:
|
||||
|
||||
```text
|
||||
├── memory
|
||||
│ ├── constitution.md
|
||||
│ └── constitution_update_checklist.md
|
||||
├── scripts
|
||||
│ ├── check-prerequisites.sh
|
||||
│ ├── common.sh
|
||||
│ ├── create-new-feature.sh
|
||||
│ ├── setup-plan.sh
|
||||
│ └── update-claude-md.sh
|
||||
├── specs
|
||||
│ └── 001-create-taskify
|
||||
│ └── spec.md
|
||||
└── templates
|
||||
├── plan-template.md
|
||||
├── spec-template.md
|
||||
└── tasks-template.md
|
||||
└── .specify
|
||||
├── memory
|
||||
│ └── constitution.md
|
||||
├── scripts
|
||||
│ ├── check-prerequisites.sh
|
||||
│ ├── common.sh
|
||||
│ ├── create-new-feature.sh
|
||||
│ ├── setup-plan.sh
|
||||
│ └── update-claude-md.sh
|
||||
├── specs
|
||||
│ └── 001-create-taskify
|
||||
│ └── spec.md
|
||||
└── templates
|
||||
├── plan-template.md
|
||||
├── spec-template.md
|
||||
└── tasks-template.md
|
||||
```
|
||||
|
||||
### **STEP 3:** Functional specification clarification
|
||||
### **STEP 3:** Functional specification clarification (required before planning)
|
||||
|
||||
With the baseline specification created, you can go ahead and clarify any of the requirements that were not captured properly within the first shot attempt. For example, you could use a prompt like this within the same Claude Code session:
|
||||
With the baseline specification created, you can go ahead and clarify any of the requirements that were not captured properly within the first shot attempt.
|
||||
|
||||
You should run the structured clarification workflow **before** creating a technical plan to reduce rework downstream.
|
||||
|
||||
Preferred order:
|
||||
|
||||
1. Use `/speckit.clarify` (structured) – sequential, coverage-based questioning that records answers in a Clarifications section.
|
||||
2. Optionally follow up with ad-hoc free-form refinement if something still feels vague.
|
||||
|
||||
If you intentionally want to skip clarification (e.g., spike or exploratory prototype), explicitly state that so the agent doesn't block on missing clarifications.
|
||||
|
||||
Example free-form refinement prompt (after `/speckit.clarify` if still needed):
|
||||
|
||||
```text
|
||||
For each sample project or project that you create there should be a variable number of tasks between 5 and 15
|
||||
@@ -377,7 +607,7 @@ It's important to use the interaction with Claude Code as an opportunity to clar
|
||||
|
||||
### **STEP 4:** Generate a plan
|
||||
|
||||
You can now be specific about the tech stack and other technical requirements. You can use the `/plan` command that is built into the project template with a prompt like this:
|
||||
You can now be specific about the tech stack and other technical requirements. You can use the `/speckit.plan` command that is built into the project template with a prompt like this:
|
||||
|
||||
```text
|
||||
We are going to generate this using .NET Aspire, using Postgres as the database. The frontend should use
|
||||
@@ -391,24 +621,23 @@ The output of this step will include a number of implementation detail documents
|
||||
.
|
||||
├── CLAUDE.md
|
||||
├── memory
|
||||
│ ├── constitution.md
|
||||
│ └── constitution_update_checklist.md
|
||||
│ └── constitution.md
|
||||
├── scripts
|
||||
│ ├── check-prerequisites.sh
|
||||
│ ├── common.sh
|
||||
│ ├── create-new-feature.sh
|
||||
│ ├── setup-plan.sh
|
||||
│ └── update-claude-md.sh
|
||||
│ ├── check-prerequisites.sh
|
||||
│ ├── common.sh
|
||||
│ ├── create-new-feature.sh
|
||||
│ ├── setup-plan.sh
|
||||
│ └── update-claude-md.sh
|
||||
├── specs
|
||||
│ └── 001-create-taskify
|
||||
│ ├── contracts
|
||||
│ │ ├── api-spec.json
|
||||
│ │ └── signalr-spec.md
|
||||
│ ├── data-model.md
|
||||
│ ├── plan.md
|
||||
│ ├── quickstart.md
|
||||
│ ├── research.md
|
||||
│ └── spec.md
|
||||
│ └── 001-create-taskify
|
||||
│ ├── contracts
|
||||
│ │ ├── api-spec.json
|
||||
│ │ └── signalr-spec.md
|
||||
│ ├── data-model.md
|
||||
│ ├── plan.md
|
||||
│ ├── quickstart.md
|
||||
│ ├── research.md
|
||||
│ └── spec.md
|
||||
└── templates
|
||||
├── CLAUDE-template.md
|
||||
├── plan-template.md
|
||||
@@ -440,8 +669,8 @@ researching .NET Aspire in general and I don't think that's gonna do much for us
|
||||
That's way too untargeted research. The research needs to help you solve a specific targeted question.
|
||||
```
|
||||
|
||||
>[!NOTE]
|
||||
>Claude Code might be over-eager and add components that you did not ask for. Ask it to clarify the rationale and the source of the change.
|
||||
> [!NOTE]
|
||||
> Claude Code might be over-eager and add components that you did not ask for. Ask it to clarify the rationale and the source of the change.
|
||||
|
||||
### **STEP 5:** Have Claude Code validate the plan
|
||||
|
||||
@@ -459,28 +688,48 @@ This helps refine the implementation plan and helps you avoid potential blind sp
|
||||
|
||||
You can also ask Claude Code (if you have the [GitHub CLI](https://docs.github.com/en/github-cli/github-cli) installed) to go ahead and create a pull request from your current branch to `main` with a detailed description, to make sure that the effort is properly tracked.
|
||||
|
||||
>[!NOTE]
|
||||
>Before you have the agent implement it, it's also worth prompting Claude Code to cross-check the details to see if there are any over-engineered pieces (remember - it can be over-eager). If over-engineered components or decisions exist, you can ask Claude Code to resolve them. Ensure that Claude Code follows the [constitution](base/memory/constitution.md) as the foundational piece that it must adhere to when establishing the plan.
|
||||
> [!NOTE]
|
||||
> Before you have the agent implement it, it's also worth prompting Claude Code to cross-check the details to see if there are any over-engineered pieces (remember - it can be over-eager). If over-engineered components or decisions exist, you can ask Claude Code to resolve them. Ensure that Claude Code follows the [constitution](base/memory/constitution.md) as the foundational piece that it must adhere to when establishing the plan.
|
||||
|
||||
### STEP 6: Implementation
|
||||
### **STEP 6:** Generate task breakdown with /speckit.tasks
|
||||
|
||||
Once ready, use the `/implement` command to execute your implementation plan:
|
||||
With the implementation plan validated, you can now break down the plan into specific, actionable tasks that can be executed in the correct order. Use the `/speckit.tasks` command to automatically generate a detailed task breakdown from your implementation plan:
|
||||
|
||||
```text
|
||||
/implement
|
||||
/speckit.tasks
|
||||
```
|
||||
|
||||
The `/implement` command will:
|
||||
This step creates a `tasks.md` file in your feature specification directory that contains:
|
||||
|
||||
- **Task breakdown organized by user story** - Each user story becomes a separate implementation phase with its own set of tasks
|
||||
- **Dependency management** - Tasks are ordered to respect dependencies between components (e.g., models before services, services before endpoints)
|
||||
- **Parallel execution markers** - Tasks that can run in parallel are marked with `[P]` to optimize development workflow
|
||||
- **File path specifications** - Each task includes the exact file paths where implementation should occur
|
||||
- **Test-driven development structure** - If tests are requested, test tasks are included and ordered to be written before implementation
|
||||
- **Checkpoint validation** - Each user story phase includes checkpoints to validate independent functionality
|
||||
|
||||
The generated tasks.md provides a clear roadmap for the `/speckit.implement` command, ensuring systematic implementation that maintains code quality and allows for incremental delivery of user stories.
|
||||
|
||||
### **STEP 7:** Implementation
|
||||
|
||||
Once ready, use the `/speckit.implement` command to execute your implementation plan:
|
||||
|
||||
```text
|
||||
/speckit.implement
|
||||
```
|
||||
|
||||
The `/speckit.implement` command will:
|
||||
|
||||
- Validate that all prerequisites are in place (constitution, spec, plan, and tasks)
|
||||
- Parse the task breakdown from `tasks.md`
|
||||
- Execute tasks in the correct order, respecting dependencies and parallel execution markers
|
||||
- Follow the TDD approach defined in your task plan
|
||||
- Provide progress updates and handle errors appropriately
|
||||
|
||||
>[!IMPORTANT]
|
||||
>The AI agent will execute local CLI commands (such as `dotnet`, `npm`, etc.) - make sure you have the required tools installed on your machine.
|
||||
> [!IMPORTANT]
|
||||
> The coding agent will execute local CLI commands (such as `dotnet`, `npm`, etc.) - make sure you have the required tools installed on your machine.
|
||||
|
||||
Once the implementation is complete, test the application and resolve any runtime errors that may not be visible in CLI logs (e.g., browser console errors). You can copy and paste such errors back to your AI agent for resolution.
|
||||
Once the implementation is complete, test the application and resolve any runtime errors that may not be visible in CLI logs (e.g., browser console errors). You can copy and paste such errors back to your coding agent for resolution.
|
||||
|
||||
</details>
|
||||
|
||||
@@ -505,11 +754,6 @@ echo "Cleaning up..."
|
||||
rm gcm-linux_amd64.2.6.1.deb
|
||||
```
|
||||
|
||||
## 👥 Maintainers
|
||||
|
||||
- Den Delimarsky ([@localden](https://github.com/localden))
|
||||
- John Lam ([@jflam](https://github.com/jflam))
|
||||
|
||||
## 💬 Support
|
||||
|
||||
For support, please open a [GitHub issue](https://github.com/github/spec-kit/issues/new). We welcome bug reports, feature requests, and questions about using Spec-Driven Development.
|
||||
|
||||
22
SECURITY.md
22
SECURITY.md
@@ -1,10 +1,10 @@
|
||||
Thanks for helping make GitHub safe for everyone.
|
||||
# Security Policy
|
||||
|
||||
# Security
|
||||
Thanks for helping make GitHub safe for everyone.
|
||||
|
||||
GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub).
|
||||
|
||||
Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation.
|
||||
Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
@@ -16,16 +16,16 @@ Instead, please send an email to opensource-security[@]github.com.
|
||||
|
||||
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
|
||||
|
||||
* The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
- The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
|
||||
- Full paths of source file(s) related to the manifestation of the issue
|
||||
- The location of the affected source code (tag/branch/commit or direct URL)
|
||||
- Any special configuration required to reproduce the issue
|
||||
- Step-by-step instructions to reproduce the issue
|
||||
- Proof-of-concept or exploit code (if possible)
|
||||
- Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
## Policy
|
||||
|
||||
See [GitHub's Safe Harbor Policy](https://docs.github.com/en/site-policy/security-policies/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms)
|
||||
See [GitHub's Safe Harbor Policy](https://docs.github.com/en/site-policy/security-policies/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms)
|
||||
|
||||
15
SUPPORT.md
15
SUPPORT.md
@@ -1,18 +1,17 @@
|
||||
# Support
|
||||
# Support
|
||||
|
||||
## How to file issues and get help
|
||||
## How to get help
|
||||
|
||||
This project uses GitHub issues to track bugs and feature requests. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new issue.
|
||||
Please search existing [issues](https://github.com/github/spec-kit/issues) and [discussions](https://github.com/github/spec-kit/discussions) before creating new ones to avoid duplicates.
|
||||
|
||||
For help or questions about using this project, please:
|
||||
|
||||
- Open a [GitHub issue](https://github.com/github/spec-kit/issues/new) for bug reports, feature requests, or questions about the Spec-Driven Development methodology
|
||||
- Check the [comprehensive guide](./spec-driven.md) for detailed documentation on the Spec-Driven Development process
|
||||
- Review the [README](./README.md) for getting started instructions and troubleshooting tips
|
||||
- Check the [comprehensive guide](./spec-driven.md) for detailed documentation on the Spec-Driven Development process
|
||||
- Ask in [GitHub Discussions](https://github.com/github/spec-kit/discussions) for questions about using Spec Kit or the Spec-Driven Development methodology
|
||||
- Open a [GitHub issue](https://github.com/github/spec-kit/issues/new) for bug reports and feature requests
|
||||
|
||||
## Project Status
|
||||
|
||||
**Spec Kit** is under active development and maintained by GitHub staff **AND THE COMMUNITY**. We will do our best to respond to support, feature requests, and community questions in a timely manner.
|
||||
**Spec Kit** is under active development and maintained by GitHub staff and the community. We will do our best to respond to support, feature requests, and community questions as time permits.
|
||||
|
||||
## GitHub Support Policy
|
||||
|
||||
|
||||
1
docs/.gitignore
vendored
1
docs/.gitignore
vendored
@@ -6,3 +6,4 @@ obj/
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.log
|
||||
|
||||
|
||||
@@ -7,11 +7,13 @@ This folder contains the documentation source files for Spec Kit, built using [D
|
||||
To build the documentation locally:
|
||||
|
||||
1. Install DocFX:
|
||||
|
||||
```bash
|
||||
dotnet tool install -g docfx
|
||||
```
|
||||
|
||||
2. Build the documentation:
|
||||
|
||||
```bash
|
||||
cd docs
|
||||
docfx docfx.json --serve
|
||||
|
||||
14
docs/community/friends.md
Normal file
14
docs/community/friends.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Community Friends
|
||||
|
||||
> [!NOTE]
|
||||
> Community projects listed here are independently created and maintained by their respective authors. They are **not reviewed, nor endorsed, nor supported by GitHub**. Review their source code before installation and use at your own discretion.
|
||||
|
||||
Community projects that extend, visualize, or build on Spec Kit:
|
||||
|
||||
- **[cc-spex](https://github.com/rhuss/cc-spex)** — A Claude Code plugin that adds composable traits on top of Spec Kit with [Superpowers](https://github.com/obra/superpowers)-based quality gates, spec/code review, git worktree isolation, and parallel implementation via agent teams.
|
||||
|
||||
- **[Spec Kit Assistant](https://marketplace.visualstudio.com/items?itemName=rfsales.speckit-assistant)** — A VS Code extension that provides a visual orchestrator for the full SDD workflow (constitution → specification → planning → tasks → implementation) with phase status visualization, an interactive task checklist, DAG visualization, and support for Claude, Gemini, GitHub Copilot, and OpenAI backends. Requires the `specify` CLI in your PATH.
|
||||
|
||||
- **[SpecKit Companion](https://marketplace.visualstudio.com/items?itemName=alfredoperez.speckit-companion)** — A VS Code extension that brings a visual GUI to Spec Kit. Browse specs in a rich markdown viewer with clickable file references, create specifications with image attachments, comment and refine each step inline (GitHub-style review), track your progress through the SDD workflow with a visual phase stepper, and manage steering documents like constitutions and templates.
|
||||
|
||||
- **[cc-spec-kit](https://github.com/speckit-community/cc-spec-kit)** — Community-maintained plugin for Claude Code and GitHub Copilot CLI that installs Spec Kit skills via the plugin marketplace.
|
||||
22
docs/community/presets.md
Normal file
22
docs/community/presets.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Community Presets
|
||||
|
||||
> [!NOTE]
|
||||
> Community presets are independently created and maintained by their respective authors. GitHub and the Spec Kit maintainers may review pull requests that add entries to the community catalog for formatting, catalog structure, or policy compliance, but they do **not review, audit, endorse, or support the preset code itself**. Review preset source code before installation and use at your own discretion.
|
||||
|
||||
The following community-contributed presets customize how Spec Kit behaves — overriding templates, commands, and terminology without changing any tooling. Presets are available in [`catalog.community.json`](https://github.com/github/spec-kit/blob/main/presets/catalog.community.json):
|
||||
|
||||
| Preset | Purpose | Provides | Requires | URL |
|
||||
|--------|---------|----------|----------|-----|
|
||||
| AIDE In-Place Migration | Adapts the AIDE extension workflow for in-place technology migrations (X → Y pattern) — adds migration objectives, verification gates, knowledge documents, and behavioral equivalence criteria | 2 templates, 8 commands | AIDE extension | [spec-kit-presets](https://github.com/mnriem/spec-kit-presets) |
|
||||
| Canon Core | Adapts original Spec Kit workflow to work together with Canon extension | 2 templates, 8 commands | — | [spec-kit-canon](https://github.com/maximiliamus/spec-kit-canon) |
|
||||
| Claude AskUserQuestion | Upgrades `/speckit.clarify` and `/speckit.checklist` on Claude Code from Markdown-table prompts to the native AskUserQuestion picker, with a recommended option and reasoning on every question | 2 commands | — | [spec-kit-preset-claude-ask-questions](https://github.com/0xrafasec/spec-kit-preset-claude-ask-questions) |
|
||||
| Explicit Task Dependencies | Adds explicit `(depends on T###)` dependency declarations and an Execution Wave DAG to tasks.md for parallel scheduling | 1 template, 1 command | — | [spec-kit-preset-explicit-task-dependencies](https://github.com/Quratulain-bilal/spec-kit-preset-explicit-task-dependencies) |
|
||||
| Fiction Book Writing | It adapts the Spec-Driven Development workflow for storytelling to create books or audiobooks (with annotations) in 12 languages: features become story elements, specs become story briefs, plans become story structures, and tasks become scene-by-scene writing tasks. Supports single and multi-POV, all major plot structure frameworks, and two style modes: an author voice sample or humanized AI prose. Supports interactive elements like brainstorming, interview, roleplay and extras like statistics, cover builder and bio command. Export with templates for KDP, D2D etc. | 22 templates, 27 commands, 2 scripts | — | [speckit-preset-fiction-book-writing](https://github.com/adaumann/speckit-preset-fiction-book-writing) |
|
||||
| Jira Issue Tracking | Overrides `speckit.taskstoissues` to create Jira epics, stories, and tasks instead of GitHub Issues via Atlassian MCP tools | 1 command | — | [spec-kit-preset-jira](https://github.com/luno/spec-kit-preset-jira) |
|
||||
| Multi-Repo Branching | Coordinates feature branch creation across multiple git repositories (independent repos and submodules) during plan and tasks phases | 2 commands | — | [spec-kit-preset-multi-repo-branching](https://github.com/sakitA/spec-kit-preset-multi-repo-branching) |
|
||||
| Pirate Speak (Full) | Transforms all Spec Kit output into pirate speak — specs become "Voyage Manifests", plans become "Battle Plans", tasks become "Crew Assignments" | 6 templates, 9 commands | — | [spec-kit-presets](https://github.com/mnriem/spec-kit-presets) |
|
||||
| Screenwriting | Spec-Driven Development for screenwriting/scriptwriting/tutorials: feature films, television (pilot, episode, limited series), and stage plays. Adapts the Spec Kit workflow to screenplay craft — slug lines, action lines, act breaks, beat sheets, and industry-standard pitch documents. Supports three-act, Save the Cat, TV pilot, network episode, cable/streaming episode, and stage-play structural frameworks. Export to Fountain, FTX, PDF | 26 templates, 32 commands, 1 script | — | [speckit-preset-screenwriting](https://github.com/adaumann/speckit-preset-screenwriting) |
|
||||
| Table of Contents Navigation | Adds a navigable Table of Contents to generated spec.md, plan.md, and tasks.md documents | 3 templates, 3 commands | — | [spec-kit-preset-toc-navigation](https://github.com/Quratulain-bilal/spec-kit-preset-toc-navigation) |
|
||||
| VS Code Ask Questions | Enhances the clarify command to use `vscode/askQuestions` for batched interactive questioning. | 1 command | — | [spec-kit-presets](https://github.com/fdcastel/spec-kit-presets) |
|
||||
|
||||
To build and publish your own preset, see the [Presets Publishing Guide](https://github.com/github/spec-kit/blob/main/presets/PUBLISHING.md).
|
||||
20
docs/community/walkthroughs.md
Normal file
20
docs/community/walkthroughs.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Community Walkthroughs
|
||||
|
||||
> [!NOTE]
|
||||
> Community walkthroughs are independently created and maintained by their respective authors. They are **not reviewed, nor endorsed, nor supported by GitHub**. Review their content before following along and use at your own discretion.
|
||||
|
||||
See Spec-Driven Development in action across different scenarios with these community-contributed walkthroughs:
|
||||
|
||||
- **[Greenfield .NET CLI tool](https://github.com/mnriem/spec-kit-dotnet-cli-demo)** — Builds a Timezone Utility as a .NET single-binary CLI tool from a blank directory, covering the full spec-kit workflow: constitution, specify, plan, tasks, and multi-pass implement using GitHub Copilot agents.
|
||||
|
||||
- **[Greenfield Spring Boot + React platform](https://github.com/mnriem/spec-kit-spring-react-demo)** — Builds an LLM performance analytics platform (REST API, graphs, iteration tracking) from scratch using Spring Boot, embedded React, PostgreSQL, and Docker Compose, with a clarify step and a cross-artifact consistency analysis pass included.
|
||||
|
||||
- **[Brownfield ASP.NET CMS extension](https://github.com/mnriem/spec-kit-aspnet-brownfield-demo)** — Extends an existing open-source .NET CMS (CarrotCakeCMS-Core, ~307,000 lines of C#, Razor, SQL, JavaScript, and config files) with two new features — cross-platform Docker Compose infrastructure and a token-authenticated headless REST API — demonstrating how spec-kit fits into existing codebases without prior specs or a constitution.
|
||||
|
||||
- **[Brownfield Java runtime extension](https://github.com/mnriem/spec-kit-java-brownfield-demo)** — Extends an existing open-source Jakarta EE runtime (Piranha, ~420,000 lines of Java, XML, JSP, HTML, and config files across 180 Maven modules) with a password-protected Server Admin Console, demonstrating spec-kit on a large multi-module Java project with no prior specs or constitution.
|
||||
|
||||
- **[Brownfield Go / React dashboard demo](https://github.com/mnriem/spec-kit-go-brownfield-demo)** — Demonstrates spec-kit driven entirely from the **terminal using GitHub Copilot CLI**. Extends NASA's open-source Hermes ground support system (Go) with a lightweight React-based web telemetry dashboard, showing that the full constitution → specify → plan → tasks → implement workflow works from the terminal.
|
||||
|
||||
- **[Greenfield Spring Boot MVC with a custom preset](https://github.com/mnriem/spec-kit-pirate-speak-preset-demo)** — Builds a Spring Boot MVC application from scratch using a custom pirate-speak preset, demonstrating how presets can reshape the entire spec-kit experience: specifications become "Voyage Manifests," plans become "Battle Plans," and tasks become "Crew Assignments" — all generated in full pirate vernacular without changing any tooling.
|
||||
|
||||
- **[Greenfield Spring Boot + React with a custom extension](https://github.com/mnriem/spec-kit-aide-extension-demo)** — Walks through the **AIDE extension**, a community extension that adds an alternative spec-driven workflow to spec-kit with high-level specs (vision) and low-level specs (work items) organized in a 7-step iterative lifecycle: vision → roadmap → progress tracking → work queue → work items → execution → feedback loops. Uses a family trading platform (Spring Boot 4, React 19, PostgreSQL, Docker Compose) as the scenario to illustrate how the extension mechanism lets you plug in a different style of spec-driven development without changing any core tooling — truly utilizing the "Kit" in Spec Kit.
|
||||
@@ -4,7 +4,9 @@
|
||||
{
|
||||
"files": [
|
||||
"*.md",
|
||||
"toc.yml"
|
||||
"toc.yml",
|
||||
"community/*.md",
|
||||
"reference/*.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -68,3 +70,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,14 @@ Spec-Driven Development **flips the script** on traditional software development
|
||||
|
||||
- [Installation Guide](installation.md)
|
||||
- [Quick Start Guide](quickstart.md)
|
||||
- [Upgrade Guide](upgrade.md)
|
||||
- [Local Development](local-development.md)
|
||||
|
||||
## Core Philosophy
|
||||
|
||||
Spec-Driven Development is a structured process that emphasizes:
|
||||
|
||||
- **Intent-driven development** where specifications define the "_what_" before the "_how_"
|
||||
- **Intent-driven development** where specifications define the "*what*" before the "*how*"
|
||||
- **Rich specification creation** using guardrails and organizational principles
|
||||
- **Multi-step refinement** rather than one-shot code generation from prompts
|
||||
- **Heavy reliance** on advanced AI model capabilities for specification interpretation
|
||||
@@ -36,27 +37,31 @@ Spec-Driven Development is a structured process that emphasizes:
|
||||
Our research and experimentation focus on:
|
||||
|
||||
### Technology Independence
|
||||
|
||||
- Create applications using diverse technology stacks
|
||||
- Validate the hypothesis that Spec-Driven Development is a process not tied to specific technologies, programming languages, or frameworks
|
||||
|
||||
### Enterprise Constraints
|
||||
|
||||
- Demonstrate mission-critical application development
|
||||
- Incorporate organizational constraints (cloud providers, tech stacks, engineering practices)
|
||||
- Support enterprise design systems and compliance requirements
|
||||
|
||||
### User-Centric Development
|
||||
|
||||
- Build applications for different user cohorts and preferences
|
||||
- Support various development approaches (from vibe-coding to AI-native development)
|
||||
|
||||
### Creative & Iterative Processes
|
||||
|
||||
- Validate the concept of parallel implementation exploration
|
||||
- Provide robust iterative feature development workflows
|
||||
- Extend processes to handle upgrades and modernization tasks
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see our [Contributing Guide](CONTRIBUTING.md) for information on how to contribute to this project.
|
||||
Please see our [Contributing Guide](https://github.com/github/spec-kit/blob/main/CONTRIBUTING.md) for information on how to contribute to this project.
|
||||
|
||||
## Support
|
||||
|
||||
For support, please check our [Support Guide](SUPPORT.md) or open an issue on GitHub.
|
||||
For support, please check our [Support Guide](https://github.com/github/spec-kit/blob/main/SUPPORT.md) or open an issue on GitHub.
|
||||
|
||||
@@ -3,35 +3,52 @@
|
||||
## Prerequisites
|
||||
|
||||
- **Linux/macOS** (or Windows; PowerShell scripts now supported without WSL)
|
||||
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), or [Gemini CLI](https://github.com/google-gemini/gemini-cli)
|
||||
- [uv](https://docs.astral.sh/uv/) for package management
|
||||
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), [Codebuddy CLI](https://www.codebuddy.ai/cli), [Gemini CLI](https://github.com/google-gemini/gemini-cli), or [Pi Coding Agent](https://pi.dev)
|
||||
- [uv](https://docs.astral.sh/uv/) for package management (recommended) or [pipx](https://pypa.github.io/pipx/) for persistent installation
|
||||
- [Python 3.11+](https://www.python.org/downloads/)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
|
||||
## Installation
|
||||
|
||||
> **Important:** The only official, maintained packages for Spec Kit come from the [github/spec-kit](https://github.com/github/spec-kit) GitHub repository. Any packages with the same name available on PyPI (e.g. `specify-cli` on pypi.org) are **not** affiliated with this project and are not maintained by the Spec Kit maintainers. For normal installs, use the GitHub-based commands shown below. For offline or air-gapped environments, locally built wheels created from this repository are also valid.
|
||||
|
||||
### Initialize a New Project
|
||||
|
||||
The easiest way to get started is to initialize a new project:
|
||||
The easiest way to get started is to initialize a new project. Pin a specific release tag for stability (check [Releases](https://github.com/github/spec-kit/releases) for the latest):
|
||||
|
||||
```bash
|
||||
# Install from a specific stable release (recommended — replace vX.Y.Z with the latest tag)
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <PROJECT_NAME>
|
||||
|
||||
# Or install latest from main (may include unreleased changes)
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME>
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> For a persistent installation, `pipx` works equally well:
|
||||
> ```bash
|
||||
> pipx install git+https://github.com/github/spec-kit.git@vX.Y.Z
|
||||
> ```
|
||||
> The project uses a standard `hatchling` build backend and has no uv-specific dependencies.
|
||||
|
||||
Or initialize in the current directory:
|
||||
|
||||
```bash
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init --here
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init .
|
||||
# or use the --here flag
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init --here
|
||||
```
|
||||
|
||||
### Specify AI Agent
|
||||
### Specify Integration
|
||||
|
||||
You can proactively specify your AI agent during initialization:
|
||||
You can proactively specify your coding agent integration during initialization:
|
||||
|
||||
```bash
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai claude
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai gemini
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai copilot
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <project_name> --integration claude
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <project_name> --integration gemini
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <project_name> --integration copilot
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <project_name> --integration codebuddy
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <project_name> --integration pi
|
||||
```
|
||||
|
||||
### Specify Script Type (Shell vs PowerShell)
|
||||
@@ -39,14 +56,16 @@ uvx --from git+https://github.com/github/spec-kit.git specify init <project_name
|
||||
All automation scripts now have both Bash (`.sh`) and PowerShell (`.ps1`) variants.
|
||||
|
||||
Auto behavior:
|
||||
|
||||
- Windows default: `ps`
|
||||
- Other OS default: `sh`
|
||||
- Interactive mode: you'll be prompted unless you pass `--script`
|
||||
|
||||
Force a specific script type:
|
||||
|
||||
```bash
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --script sh
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --script ps
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <project_name> --script sh
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <project_name> --script ps
|
||||
```
|
||||
|
||||
### Ignore Agent Tools Check
|
||||
@@ -54,20 +73,73 @@ uvx --from git+https://github.com/github/spec-kit.git specify init <project_name
|
||||
If you prefer to get the templates without checking for the right tools:
|
||||
|
||||
```bash
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai claude --ignore-agent-tools
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <project_name> --integration claude --ignore-agent-tools
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
After initialization, you should see the following commands available in your AI agent:
|
||||
- `/specify` - Create specifications
|
||||
- `/plan` - Generate implementation plans
|
||||
- `/tasks` - Break down into actionable tasks
|
||||
After installation, run the following command to confirm the correct version is installed:
|
||||
|
||||
```bash
|
||||
specify version
|
||||
```
|
||||
|
||||
This helps verify you are running the official Spec Kit build from GitHub, not an unrelated package with the same name.
|
||||
|
||||
After initialization, you should see the following commands available in your coding agent:
|
||||
|
||||
- `/speckit.specify` - Create specifications
|
||||
- `/speckit.plan` - Generate implementation plans
|
||||
- `/speckit.tasks` - Break down into actionable tasks
|
||||
|
||||
The `.specify/scripts` directory will contain both `.sh` and `.ps1` scripts.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Enterprise / Air-Gapped Installation
|
||||
|
||||
If your environment blocks access to PyPI (you see 403 errors when running `uv tool install` or `pip install`), you can create a portable wheel bundle on a connected machine and transfer it to the air-gapped target.
|
||||
|
||||
**Step 1: Build the wheel on a connected machine (same OS and Python version as the target)**
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/github/spec-kit.git
|
||||
cd spec-kit
|
||||
|
||||
# Build the wheel
|
||||
pip install build
|
||||
python -m build --wheel --outdir dist/
|
||||
|
||||
# Download the wheel and all its runtime dependencies
|
||||
pip download -d dist/ dist/specify_cli-*.whl
|
||||
```
|
||||
|
||||
> **Important:** `pip download` resolves platform-specific wheels (e.g., PyYAML includes native extensions). You must run this step on a machine with the **same OS and Python version** as the air-gapped target. If you need to support multiple platforms, repeat this step on each target OS (Linux, macOS, Windows) and Python version.
|
||||
|
||||
**Step 2: Transfer the `dist/` directory to the air-gapped machine**
|
||||
|
||||
Copy the entire `dist/` directory (which contains the `specify-cli` wheel and all dependency wheels) to the target machine via USB, network share, or other approved transfer method.
|
||||
|
||||
**Step 3: Install on the air-gapped machine**
|
||||
|
||||
```bash
|
||||
pip install --no-index --find-links=./dist specify-cli
|
||||
```
|
||||
|
||||
**Step 4: Initialize a project (no network required)**
|
||||
|
||||
```bash
|
||||
# Initialize a project — no GitHub access needed
|
||||
specify init my-project --integration claude
|
||||
```
|
||||
|
||||
Bundled assets are used by default — no network access is required.
|
||||
|
||||
> **Note:** Python 3.11+ is required.
|
||||
|
||||
> **Windows note:** Offline scaffolding requires PowerShell 7+ (`pwsh`), not Windows PowerShell 5.x (`powershell.exe`). Install from https://aka.ms/powershell.
|
||||
|
||||
### Git Credential Manager on Linux
|
||||
|
||||
If you're having issues with Git authentication on Linux, you can install Git Credential Manager:
|
||||
|
||||
@@ -20,7 +20,7 @@ You can execute the CLI via the module entrypoint without installing anything:
|
||||
```bash
|
||||
# From repo root
|
||||
python -m src.specify_cli --help
|
||||
python -m src.specify_cli init demo-project --ai claude --ignore-agent-tools --script sh
|
||||
python -m src.specify_cli init demo-project --integration claude --ignore-agent-tools --script sh
|
||||
```
|
||||
|
||||
If you prefer invoking the script file style (uses shebang):
|
||||
@@ -52,7 +52,7 @@ Re-running after code edits requires no reinstall because of editable mode.
|
||||
`uvx` can run from a local path (or a Git ref) to simulate user flows:
|
||||
|
||||
```bash
|
||||
uvx --from . specify init demo-uvx --ai copilot --ignore-agent-tools --script sh
|
||||
uvx --from . specify init demo-uvx --integration copilot --ignore-agent-tools --script sh
|
||||
```
|
||||
|
||||
You can also point uvx at a specific branch without merging:
|
||||
@@ -69,16 +69,18 @@ If you're in another directory, use an absolute path instead of `.`:
|
||||
|
||||
```bash
|
||||
uvx --from /mnt/c/GitHub/spec-kit specify --help
|
||||
uvx --from /mnt/c/GitHub/spec-kit specify init demo-anywhere --ai copilot --ignore-agent-tools --script sh
|
||||
uvx --from /mnt/c/GitHub/spec-kit specify init demo-anywhere --integration copilot --ignore-agent-tools --script sh
|
||||
```
|
||||
|
||||
Set an environment variable for convenience:
|
||||
|
||||
```bash
|
||||
export SPEC_KIT_SRC=/mnt/c/GitHub/spec-kit
|
||||
uvx --from "$SPEC_KIT_SRC" specify init demo-env --ai copilot --ignore-agent-tools --script ps
|
||||
uvx --from "$SPEC_KIT_SRC" specify init demo-env --integration copilot --ignore-agent-tools --script ps
|
||||
```
|
||||
|
||||
(Optional) Define a shell function:
|
||||
|
||||
```bash
|
||||
specify-dev() { uvx --from /mnt/c/GitHub/spec-kit specify "$@"; }
|
||||
# Then
|
||||
@@ -93,11 +95,13 @@ After running an `init`, check that shell scripts are executable on POSIX system
|
||||
ls -l scripts | grep .sh
|
||||
# Expect owner execute bit (e.g. -rwxr-xr-x)
|
||||
```
|
||||
|
||||
On Windows you will instead use the `.ps1` scripts (no chmod needed).
|
||||
|
||||
## 6. Run Lint / Basic Checks (Add Your Own)
|
||||
|
||||
Currently no enforced lint config is bundled, but you can quickly sanity check importability:
|
||||
|
||||
```bash
|
||||
python -c "import specify_cli; print('Import OK')"
|
||||
```
|
||||
@@ -110,6 +114,7 @@ Validate packaging before publishing:
|
||||
uv build
|
||||
ls dist/
|
||||
```
|
||||
|
||||
Install the built artifact into a fresh throwaway environment if needed.
|
||||
|
||||
## 8. Using a Temporary Workspace
|
||||
@@ -118,19 +123,19 @@ When testing `init --here` in a dirty directory, create a temp workspace:
|
||||
|
||||
```bash
|
||||
mkdir /tmp/spec-test && cd /tmp/spec-test
|
||||
python -m src.specify_cli init --here --ai claude --ignore-agent-tools --script sh # if repo copied here
|
||||
python -m src.specify_cli init --here --integration claude --ignore-agent-tools --script sh # if repo copied here
|
||||
```
|
||||
|
||||
Or copy only the modified CLI portion if you want a lighter sandbox.
|
||||
|
||||
## 9. Debug Network / TLS Skips
|
||||
## 9. Debug Network / TLS Issues
|
||||
|
||||
If you need to bypass TLS validation while experimenting:
|
||||
|
||||
```bash
|
||||
specify check --skip-tls
|
||||
specify init demo --skip-tls --ai gemini --ignore-agent-tools --script ps
|
||||
```
|
||||
(Use only for local experimentation.)
|
||||
> **Deprecated:** The `--skip-tls` flag is a no-op and has no effect.
|
||||
> It was previously used to bypass TLS validation during local testing.
|
||||
> If you encounter TLS errors (e.g., on a corporate network), configure your
|
||||
> environment's certificate store or proxy instead.
|
||||
>
|
||||
> For example, set `SSL_CERT_FILE` or configure `HTTPS_PROXY` / `HTTP_PROXY`.
|
||||
|
||||
## 10. Rapid Edit Loop Summary
|
||||
|
||||
@@ -146,6 +151,7 @@ specify init demo --skip-tls --ai gemini --ignore-agent-tools --script ps
|
||||
## 11. Cleaning Up
|
||||
|
||||
Remove build artifacts / virtual env quickly:
|
||||
|
||||
```bash
|
||||
rm -rf .venv dist build *.egg-info
|
||||
```
|
||||
@@ -158,11 +164,10 @@ rm -rf .venv dist build *.egg-info
|
||||
| Scripts not executable (Linux) | Re-run init or `chmod +x scripts/*.sh` |
|
||||
| Git step skipped | You passed `--no-git` or Git not installed |
|
||||
| Wrong script type downloaded | Pass `--script sh` or `--script ps` explicitly |
|
||||
| TLS errors on corporate network | Try `--skip-tls` (not for production) |
|
||||
| TLS errors on corporate network | Configure your environment's certificate store or proxy. The `--skip-tls` flag is deprecated and has no effect. |
|
||||
|
||||
## 13. Next Steps
|
||||
|
||||
- Update docs and run through Quick Start using your modified CLI
|
||||
- Open a PR when satisfied
|
||||
- (Optional) Tag a release once changes land in `main`
|
||||
|
||||
|
||||
@@ -2,49 +2,112 @@
|
||||
|
||||
This guide will help you get started with Spec-Driven Development using Spec Kit.
|
||||
|
||||
> NEW: All automation scripts now provide both Bash (`.sh`) and PowerShell (`.ps1`) variants. The `specify` CLI auto-selects based on OS unless you pass `--script sh|ps`.
|
||||
> [!NOTE]
|
||||
> All automation scripts now provide both Bash (`.sh`) and PowerShell (`.ps1`) variants. The `specify` CLI auto-selects based on OS unless you pass `--script sh|ps`.
|
||||
|
||||
## The 4-Step Process
|
||||
## The 6-Step Process
|
||||
|
||||
### 1. Install Specify
|
||||
> [!TIP]
|
||||
> **Context Awareness**: Spec Kit commands automatically detect the active feature based on your current Git branch (e.g., `001-feature-name`). To switch between different specifications, simply switch Git branches.
|
||||
|
||||
Initialize your project depending on the coding agent you're using:
|
||||
### Step 1: Install Specify
|
||||
|
||||
**In your terminal**, run the `specify` CLI command to initialize your project:
|
||||
|
||||
```bash
|
||||
# Create a new project directory
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME>
|
||||
|
||||
# OR initialize in the current directory
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init .
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> You can also install the CLI persistently with `pipx`:
|
||||
> ```bash
|
||||
> pipx install git+https://github.com/github/spec-kit.git
|
||||
> ```
|
||||
> After installing with `pipx`, run `specify` directly instead of `uvx --from ... specify`, for example:
|
||||
> ```bash
|
||||
> specify init <PROJECT_NAME>
|
||||
> specify init .
|
||||
> ```
|
||||
|
||||
Pick script type explicitly (optional):
|
||||
|
||||
```bash
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME> --script ps # Force PowerShell
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME> --script sh # Force POSIX shell
|
||||
```
|
||||
|
||||
### 2. Create the Spec
|
||||
### Step 2: Define Your Constitution
|
||||
|
||||
Use the `/specify` command to describe what you want to build. Focus on the **what** and **why**, not the tech stack.
|
||||
**In your coding agent's chat interface**, use the `/speckit.constitution` slash command to establish the core rules and principles for your project. You should provide your project's specific principles as arguments.
|
||||
|
||||
```bash
|
||||
/specify Build an application that can help me organize my photos in separate photo albums. Albums are grouped by date and can be re-organized by dragging and dropping on the main page. Albums are never in other nested albums. Within each album, photos are previewed in a tile-like interface.
|
||||
```markdown
|
||||
/speckit.constitution This project follows a "Library-First" approach. All features must be implemented as standalone libraries first. We use TDD strictly. We prefer functional programming patterns.
|
||||
```
|
||||
|
||||
### 3. Create a Technical Implementation Plan
|
||||
### Step 3: Create the Spec
|
||||
|
||||
Use the `/plan` command to provide your tech stack and architecture choices.
|
||||
**In the chat**, use the `/speckit.specify` slash command to describe what you want to build. Focus on the **what** and **why**, not the tech stack.
|
||||
|
||||
```bash
|
||||
/plan The application uses Vite with minimal number of libraries. Use vanilla HTML, CSS, and JavaScript as much as possible. Images are not uploaded anywhere and metadata is stored in a local SQLite database.
|
||||
```markdown
|
||||
/speckit.specify Build an application that can help me organize my photos in separate photo albums. Albums are grouped by date and can be re-organized by dragging and dropping on the main page. Albums are never in other nested albums. Within each album, photos are previewed in a tile-like interface.
|
||||
```
|
||||
|
||||
### 4. Break Down and Implement
|
||||
### Step 4: Refine the Spec
|
||||
|
||||
Use `/tasks` to create an actionable task list, then ask your agent to implement the feature.
|
||||
**In the chat**, use the `/speckit.clarify` slash command to identify and resolve ambiguities in your specification. You can provide specific focus areas as arguments.
|
||||
|
||||
```bash
|
||||
/speckit.clarify Focus on security and performance requirements.
|
||||
```
|
||||
|
||||
### Step 5: Create a Technical Implementation Plan
|
||||
|
||||
**In the chat**, use the `/speckit.plan` slash command to provide your tech stack and architecture choices.
|
||||
|
||||
```markdown
|
||||
/speckit.plan The application uses Vite with minimal number of libraries. Use vanilla HTML, CSS, and JavaScript as much as possible. Images are not uploaded anywhere and metadata is stored in a local SQLite database.
|
||||
```
|
||||
|
||||
### Step 6: Break Down and Implement
|
||||
|
||||
**In the chat**, use the `/speckit.tasks` slash command to create an actionable task list.
|
||||
|
||||
```markdown
|
||||
/speckit.tasks
|
||||
```
|
||||
|
||||
Optionally, validate the plan with `/speckit.analyze`:
|
||||
|
||||
```markdown
|
||||
/speckit.analyze
|
||||
```
|
||||
|
||||
Then, use the `/speckit.implement` slash command to execute the plan.
|
||||
|
||||
```markdown
|
||||
/speckit.implement
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> **Phased Implementation**: For complex projects, implement in phases to avoid overwhelming the agent's context. Start with core functionality, validate it works, then add features incrementally.
|
||||
|
||||
## Detailed Example: Building Taskify
|
||||
|
||||
Here's a complete example of building a team productivity platform:
|
||||
|
||||
### Step 1: Define Requirements with `/specify`
|
||||
### Step 1: Define Constitution
|
||||
|
||||
Initialize the project's constitution to set ground rules:
|
||||
|
||||
```markdown
|
||||
/speckit.constitution Taskify is a "Security-First" application. All user inputs must be validated. We use a microservices architecture. Code must be fully documented.
|
||||
```
|
||||
|
||||
### Step 2: Define Requirements with `/speckit.specify`
|
||||
|
||||
```text
|
||||
Develop Taskify, a team productivity platform. It should allow users to create projects, add team members,
|
||||
@@ -53,70 +116,74 @@ let's call it "Create Taskify," let's have multiple users but the users will be
|
||||
I want five users in two different categories, one product manager and four engineers. Let's create three
|
||||
different sample projects. Let's have the standard Kanban columns for the status of each task, such as "To Do,"
|
||||
"In Progress," "In Review," and "Done." There will be no login for this application as this is just the very
|
||||
first testing thing to ensure that our basic features are set up. For each task in the UI for a task card,
|
||||
you should be able to change the current status of the task between the different columns in the Kanban work board.
|
||||
You should be able to leave an unlimited number of comments for a particular card. You should be able to, from that task
|
||||
card, assign one of the valid users. When you first launch Taskify, it's going to give you a list of the five users to pick
|
||||
from. There will be no password required. When you click on a user, you go into the main view, which displays the list of
|
||||
projects. When you click on a project, you open the Kanban board for that project. You're going to see the columns.
|
||||
You'll be able to drag and drop cards back and forth between different columns. You will see any cards that are
|
||||
assigned to you, the currently logged in user, in a different color from all the other ones, so you can quickly
|
||||
see yours. You can edit any comments that you make, but you can't edit comments that other people made. You can
|
||||
delete any comments that you made, but you can't delete comments anybody else made.
|
||||
first testing thing to ensure that our basic features are set up.
|
||||
```
|
||||
|
||||
### Step 2: Refine the Specification
|
||||
### Step 3: Refine the Specification
|
||||
|
||||
After the initial specification is created, clarify any missing requirements:
|
||||
Use the `/speckit.clarify` command to interactively resolve any ambiguities in your specification. You can also provide specific details you want to ensure are included.
|
||||
|
||||
```text
|
||||
For each sample project or project that you create there should be a variable number of tasks between 5 and 15
|
||||
tasks for each one randomly distributed into different states of completion. Make sure that there's at least
|
||||
one task in each stage of completion.
|
||||
```bash
|
||||
/speckit.clarify I want to clarify the task card details. For each task in the UI for a task card, you should be able to change the current status of the task between the different columns in the Kanban work board. You should be able to leave an unlimited number of comments for a particular card. You should be able to, from that task card, assign one of the valid users.
|
||||
```
|
||||
|
||||
Also validate the specification checklist:
|
||||
You can continue to refine the spec with more details using `/speckit.clarify`:
|
||||
|
||||
```text
|
||||
Read the review and acceptance checklist, and check off each item in the checklist if the feature spec meets the criteria. Leave it empty if it does not.
|
||||
```bash
|
||||
/speckit.clarify When you first launch Taskify, it's going to give you a list of the five users to pick from. There will be no password required. When you click on a user, you go into the main view, which displays the list of projects. When you click on a project, you open the Kanban board for that project. You're going to see the columns. You'll be able to drag and drop cards back and forth between different columns. You will see any cards that are assigned to you, the currently logged in user, in a different color from all the other ones, so you can quickly see yours. You can edit any comments that you make, but you can't edit comments that other people made. You can delete any comments that you made, but you can't delete comments anybody else made.
|
||||
```
|
||||
|
||||
### Step 3: Generate Technical Plan with `/plan`
|
||||
### Step 4: Validate the Spec
|
||||
|
||||
Validate the specification checklist using the `/speckit.checklist` command:
|
||||
|
||||
```bash
|
||||
/speckit.checklist
|
||||
```
|
||||
|
||||
### Step 5: Generate Technical Plan with `/speckit.plan`
|
||||
|
||||
Be specific about your tech stack and technical requirements:
|
||||
|
||||
```text
|
||||
We are going to generate this using .NET Aspire, using Postgres as the database. The frontend should use
|
||||
Blazor server with drag-and-drop task boards, real-time updates. There should be a REST API created with a projects API,
|
||||
tasks API, and a notifications API.
|
||||
```bash
|
||||
/speckit.plan We are going to generate this using .NET Aspire, using Postgres as the database. The frontend should use Blazor server with drag-and-drop task boards, real-time updates. There should be a REST API created with a projects API, tasks API, and a notifications API.
|
||||
```
|
||||
|
||||
### Step 4: Validate and Implement
|
||||
### Step 6: Define Tasks
|
||||
|
||||
Have your AI agent audit the implementation plan:
|
||||
Generate an actionable task list using the `/speckit.tasks` command:
|
||||
|
||||
```text
|
||||
Now I want you to go and audit the implementation plan and the implementation detail files.
|
||||
Read through it with an eye on determining whether or not there is a sequence of tasks that you need
|
||||
to be doing that are obvious from reading this. Because I don't know if there's enough here.
|
||||
```bash
|
||||
/speckit.tasks
|
||||
```
|
||||
|
||||
### Step 7: Validate and Implement
|
||||
|
||||
Have your coding agent audit the implementation plan using `/speckit.analyze`:
|
||||
|
||||
```bash
|
||||
/speckit.analyze
|
||||
```
|
||||
|
||||
Finally, implement the solution:
|
||||
|
||||
```text
|
||||
implement specs/002-create-taskify/plan.md
|
||||
```bash
|
||||
/speckit.implement
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> **Phased Implementation**: For large projects like Taskify, consider implementing in phases (e.g., Phase 1: Basic project/task structure, Phase 2: Kanban functionality, Phase 3: Comments and assignments). This prevents context saturation and allows for validation at each stage.
|
||||
|
||||
## Key Principles
|
||||
|
||||
- **Be explicit** about what you're building and why
|
||||
- **Don't focus on tech stack** during specification phase
|
||||
- **Iterate and refine** your specifications before implementation
|
||||
- **Validate** the plan before coding begins
|
||||
- **Let the AI agent handle** the implementation details
|
||||
- **Let the coding agent handle** the implementation details
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Read the complete methodology for in-depth guidance
|
||||
- Check out more examples in the repository
|
||||
- Explore the source code on GitHub
|
||||
- Read the [complete methodology](https://github.com/github/spec-kit/blob/main/spec-driven.md) for in-depth guidance
|
||||
- Check out [more examples](https://github.com/github/spec-kit/tree/main/templates) in the repository
|
||||
- Explore the [source code on GitHub](https://github.com/github/spec-kit)
|
||||
|
||||
79
docs/reference/core.md
Normal file
79
docs/reference/core.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Core Commands
|
||||
|
||||
The core `specify` commands handle project initialization, system checks, and version information.
|
||||
|
||||
## Initialize a Project
|
||||
|
||||
```bash
|
||||
specify init [<project_name>]
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | ------------------------------------------------------------------------ |
|
||||
| `--integration <key>` | AI coding agent integration to use (e.g. `copilot`, `claude`, `gemini`). See the [Integrations reference](integrations.md) for all available keys |
|
||||
| `--integration-options` | Options for the integration (e.g. `--integration-options="--commands-dir .myagent/cmds"`) |
|
||||
| `--script sh\|ps` | Script type: `sh` (bash/zsh) or `ps` (PowerShell) |
|
||||
| `--here` | Initialize in the current directory instead of creating a new one |
|
||||
| `--force` | Force merge/overwrite when initializing in an existing directory |
|
||||
| `--no-git` | Skip git repository initialization |
|
||||
| `--ignore-agent-tools` | Skip checks for AI coding agent CLI tools |
|
||||
| `--preset <id>` | Install a preset during initialization |
|
||||
| `--branch-numbering` | Branch numbering strategy: `sequential` (default) or `timestamp` |
|
||||
|
||||
Creates a new Spec Kit project with the necessary directory structure, templates, scripts, and AI coding agent integration files.
|
||||
|
||||
Use `<project_name>` to create a new directory, or `--here` (or `.`) to initialize in the current directory. If the directory already has files, use `--force` to merge without confirmation.
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Create a new project with an integration
|
||||
specify init my-project --integration copilot
|
||||
|
||||
# Initialize in the current directory
|
||||
specify init --here --integration copilot
|
||||
|
||||
# Force merge into a non-empty directory
|
||||
specify init --here --force --integration copilot
|
||||
|
||||
# Use PowerShell scripts (Windows/cross-platform)
|
||||
specify init my-project --integration copilot --script ps
|
||||
|
||||
# Skip git initialization
|
||||
specify init my-project --integration copilot --no-git
|
||||
|
||||
# Install a preset during initialization
|
||||
specify init my-project --integration copilot --preset compliance
|
||||
|
||||
# Use timestamp-based branch numbering (useful for distributed teams)
|
||||
specify init my-project --integration copilot --branch-numbering timestamp
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description |
|
||||
| ----------------- | ------------------------------------------------------------------------ |
|
||||
| `SPECIFY_FEATURE` | Override feature detection for non-Git repositories. Set to the feature directory name (e.g., `001-photo-albums`) to work on a specific feature when not using Git branches. Must be set in the context of the agent prior to using `/speckit.plan` or follow-up commands. |
|
||||
|
||||
## Check Installed Tools
|
||||
|
||||
```bash
|
||||
specify check
|
||||
```
|
||||
|
||||
Checks that required tools are available on your system: `git` and any CLI-based AI coding agents. IDE-based agents are skipped since they don't require a CLI tool.
|
||||
|
||||
## Version Information
|
||||
|
||||
```bash
|
||||
specify version
|
||||
```
|
||||
|
||||
Displays the Spec Kit CLI version, Python version, platform, and architecture.
|
||||
|
||||
A quick version check is also available via:
|
||||
|
||||
```bash
|
||||
specify --version
|
||||
specify -V
|
||||
```
|
||||
201
docs/reference/extensions.md
Normal file
201
docs/reference/extensions.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Extensions
|
||||
|
||||
Extensions add new capabilities to Spec Kit — domain-specific commands, external tool integrations, quality gates, and more. They introduce new commands and templates that go beyond the built-in Spec-Driven Development workflow.
|
||||
|
||||
## Search Available Extensions
|
||||
|
||||
```bash
|
||||
specify extension search [query]
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ------------ | ------------------------------------ |
|
||||
| `--tag` | Filter by tag |
|
||||
| `--author` | Filter by author |
|
||||
| `--verified` | Show only verified extensions |
|
||||
|
||||
Searches all active catalogs for extensions matching the query. Without a query, lists all available extensions.
|
||||
|
||||
## Install an Extension
|
||||
|
||||
```bash
|
||||
specify extension add <name>
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| --------------- | -------------------------------------------------------- |
|
||||
| `--dev` | Install from a local directory (for development) |
|
||||
| `--from <url>` | Install from a custom URL instead of the catalog |
|
||||
| `--priority <N>`| Resolution priority (default: 10; lower = higher precedence) |
|
||||
|
||||
Installs an extension from the catalog, a URL, or a local directory. Extension commands are automatically registered with the currently installed AI coding agent integration.
|
||||
|
||||
> **Note:** All extension commands require a project already initialized with `specify init`.
|
||||
|
||||
## Remove an Extension
|
||||
|
||||
```bash
|
||||
specify extension remove <name>
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| --------------- | ---------------------------------------------- |
|
||||
| `--keep-config` | Preserve configuration files during removal |
|
||||
| `--force` | Skip confirmation prompt |
|
||||
|
||||
Removes an installed extension. Configuration files are backed up by default; use `--keep-config` to leave them in place or `--force` to skip the confirmation.
|
||||
|
||||
## List Installed Extensions
|
||||
|
||||
```bash
|
||||
specify extension list
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ------------- | -------------------------------------------------- |
|
||||
| `--available` | Show available (uninstalled) extensions |
|
||||
| `--all` | Show both installed and available extensions |
|
||||
|
||||
Lists installed extensions with their status, version, and command counts.
|
||||
|
||||
## Extension Info
|
||||
|
||||
```bash
|
||||
specify extension info <name>
|
||||
```
|
||||
|
||||
Shows detailed information about an installed or available extension, including its description, version, commands, and configuration.
|
||||
|
||||
## Update Extensions
|
||||
|
||||
```bash
|
||||
specify extension update [<name>]
|
||||
```
|
||||
|
||||
Updates a specific extension, or all installed extensions if no name is given.
|
||||
|
||||
## Enable / Disable an Extension
|
||||
|
||||
```bash
|
||||
specify extension enable <name>
|
||||
specify extension disable <name>
|
||||
```
|
||||
|
||||
Disable an extension without removing it. Disabled extensions are not loaded and their commands are not available. Re-enable with `enable`.
|
||||
|
||||
## Set Extension Priority
|
||||
|
||||
```bash
|
||||
specify extension set-priority <name> <priority>
|
||||
```
|
||||
|
||||
Changes the resolution priority of an extension. When multiple extensions provide a command with the same name, the extension with the lowest priority number takes precedence.
|
||||
|
||||
## Catalog Management
|
||||
|
||||
Extension catalogs control where `search` and `add` look for extensions. Catalogs are checked in priority order (lower number = higher precedence).
|
||||
|
||||
### List Catalogs
|
||||
|
||||
```bash
|
||||
specify extension catalog list
|
||||
```
|
||||
|
||||
Shows all active catalogs in the stack with their priorities and install permissions.
|
||||
|
||||
### Add a Catalog
|
||||
|
||||
```bash
|
||||
specify extension catalog add <url>
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------------------ | -------------------------------------------------- |
|
||||
| `--name <name>` | Required. Unique name for the catalog |
|
||||
| `--priority <N>` | Priority (default: 10; lower = higher precedence) |
|
||||
| `--install-allowed / --no-install-allowed` | Whether extensions can be installed from this catalog |
|
||||
| `--description <text>` | Optional description |
|
||||
|
||||
Adds a catalog to the project's `.specify/extension-catalogs.yml`.
|
||||
|
||||
### Remove a Catalog
|
||||
|
||||
```bash
|
||||
specify extension catalog remove <name>
|
||||
```
|
||||
|
||||
Removes a catalog from the project configuration.
|
||||
|
||||
### Catalog Resolution Order
|
||||
|
||||
Catalogs are resolved in this order (first match wins):
|
||||
|
||||
1. **Environment variable** — `SPECKIT_CATALOG_URL` overrides all catalogs
|
||||
2. **Project config** — `.specify/extension-catalogs.yml`
|
||||
3. **User config** — `~/.specify/extension-catalogs.yml`
|
||||
4. **Built-in defaults** — official catalog + community catalog
|
||||
|
||||
Example `.specify/extension-catalogs.yml`:
|
||||
|
||||
```yaml
|
||||
catalogs:
|
||||
- name: "my-org-catalog"
|
||||
url: "https://example.com/catalog.json"
|
||||
priority: 5
|
||||
install_allowed: true
|
||||
description: "Our approved extensions"
|
||||
```
|
||||
|
||||
## Extension Configuration
|
||||
|
||||
Most extensions include configuration files in their install directory:
|
||||
|
||||
```text
|
||||
.specify/extensions/<ext>/
|
||||
├── <ext>-config.yml # Project config (version controlled)
|
||||
├── <ext>-config.local.yml # Local overrides (gitignored)
|
||||
└── <ext>-config.template.yml # Template reference
|
||||
```
|
||||
|
||||
Configuration is merged in this order (highest priority last):
|
||||
|
||||
1. **Extension defaults** (from `extension.yml`)
|
||||
2. **Project config** (`<ext>-config.yml`)
|
||||
3. **Local overrides** (`<ext>-config.local.yml`)
|
||||
4. **Environment variables** (`SPECKIT_<EXT>_*`)
|
||||
|
||||
To set up configuration for a newly installed extension, copy the template:
|
||||
|
||||
```bash
|
||||
cp .specify/extensions/<ext>/<ext>-config.template.yml \
|
||||
.specify/extensions/<ext>/<ext>-config.yml
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why can't I find an extension with `search`?
|
||||
|
||||
Check the spelling of the extension name. The extension may not be published yet, or it may be in a catalog you haven't added. Use `specify extension catalog list` to see which catalogs are active.
|
||||
|
||||
### Why doesn't the extension command appear in my AI coding agent?
|
||||
|
||||
Verify the extension is installed and enabled with `specify extension list`. If it shows as installed, restart your AI coding agent — it may need to reload for it to take effect.
|
||||
|
||||
### How do I set up extension configuration?
|
||||
|
||||
Copy the config template that ships with the extension:
|
||||
|
||||
```bash
|
||||
cp .specify/extensions/<ext>/<ext>-config.template.yml \
|
||||
.specify/extensions/<ext>/<ext>-config.yml
|
||||
```
|
||||
|
||||
See [Extension Configuration](#extension-configuration) for details on config layers and overrides.
|
||||
|
||||
### How do I resolve an incompatible version error?
|
||||
|
||||
Update Spec Kit to the version required by the extension.
|
||||
|
||||
### Who maintains extensions?
|
||||
|
||||
Most extensions are independently created and maintained by their respective authors. The Spec Kit maintainers do not review, audit, endorse, or support extension code. Review an extension's source code before installing and use at your own discretion. For issues with a specific extension, contact its author or file an issue on the extension's repository.
|
||||
140
docs/reference/integrations.md
Normal file
140
docs/reference/integrations.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# Supported AI Coding Agent Integrations
|
||||
|
||||
The Specify CLI supports a wide range of AI coding agents. When you run `specify init`, the CLI sets up the appropriate command files, context rules, and directory structures for your chosen AI coding agent — so you can start using Spec-Driven Development immediately, regardless of which tool you prefer.
|
||||
|
||||
## Supported AI Coding Agents
|
||||
|
||||
| Agent | Key | Notes |
|
||||
| ------------------------------------------------------------------------------------ | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [Amp](https://ampcode.com/) | `amp` | |
|
||||
| [Antigravity (agy)](https://antigravity.google/) | `agy` | Skills-based integration; skills are installed automatically |
|
||||
| [Auggie CLI](https://docs.augmentcode.com/cli/overview) | `auggie` | |
|
||||
| [Claude Code](https://www.anthropic.com/claude-code) | `claude` | Skills-based integration; installs skills in `.claude/skills` |
|
||||
| [CodeBuddy CLI](https://www.codebuddy.ai/cli) | `codebuddy` | |
|
||||
| [Codex CLI](https://github.com/openai/codex) | `codex` | Skills-based integration; installs skills into `.agents/skills` and invokes them as `$speckit-<command>` |
|
||||
| [Cursor](https://cursor.sh/) | `cursor-agent` | |
|
||||
| [Forge](https://forgecode.dev/) | `forge` | |
|
||||
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | `gemini` | |
|
||||
| [GitHub Copilot](https://code.visualstudio.com/) | `copilot` | |
|
||||
| [Goose](https://block.github.io/goose/) | `goose` | Uses YAML recipe format in `.goose/recipes/` |
|
||||
| [IBM Bob](https://www.ibm.com/products/bob) | `bob` | IDE-based agent |
|
||||
| [iFlow CLI](https://docs.iflow.cn/en/cli/quickstart) | `iflow` | |
|
||||
| [Junie](https://junie.jetbrains.com/) | `junie` | |
|
||||
| [Kilo Code](https://github.com/Kilo-Org/kilocode) | `kilocode` | |
|
||||
| [Kimi Code](https://code.kimi.com/) | `kimi` | Skills-based integration; supports `--migrate-legacy` for dotted→hyphenated directory migration |
|
||||
| [Kiro CLI](https://kiro.dev/docs/cli/) | `kiro-cli` | Alias: `--integration kiro` |
|
||||
| [Mistral Vibe](https://github.com/mistralai/mistral-vibe) | `vibe` | |
|
||||
| [opencode](https://opencode.ai/) | `opencode` | |
|
||||
| [Pi Coding Agent](https://pi.dev) | `pi` | Pi doesn't have MCP support out of the box, so `taskstoissues` won't work as intended. MCP support can be added via [extensions](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent#extensions) |
|
||||
| [Qoder CLI](https://qoder.com/cli) | `qodercli` | |
|
||||
| [Qwen Code](https://github.com/QwenLM/qwen-code) | `qwen` | |
|
||||
| [Roo Code](https://roocode.com/) | `roo` | |
|
||||
| [SHAI (OVHcloud)](https://github.com/ovh/shai) | `shai` | |
|
||||
| [Tabnine CLI](https://docs.tabnine.com/main/getting-started/tabnine-cli) | `tabnine` | |
|
||||
| [Trae](https://www.trae.ai/) | `trae` | Skills-based integration; skills are installed automatically |
|
||||
| [Windsurf](https://windsurf.com/) | `windsurf` | |
|
||||
| Generic | `generic` | Bring your own agent — use `--integration generic --integration-options="--commands-dir <path>"` for AI coding agents not listed above |
|
||||
|
||||
## List Available Integrations
|
||||
|
||||
```bash
|
||||
specify integration list
|
||||
```
|
||||
|
||||
Shows all available integrations, which one is currently installed, and whether each requires a CLI tool or is IDE-based.
|
||||
|
||||
## Install an Integration
|
||||
|
||||
```bash
|
||||
specify integration install <key>
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | ------------------------------------------------------------------------ |
|
||||
| `--script sh\|ps` | Script type: `sh` (bash/zsh) or `ps` (PowerShell) |
|
||||
| `--integration-options` | Integration-specific options (e.g. `--integration-options="--commands-dir .myagent/cmds"`) |
|
||||
|
||||
Installs the specified integration into the current project. Fails if another integration is already installed — use `switch` instead. If the installation fails partway through, it automatically rolls back to a clean state.
|
||||
|
||||
> **Note:** All integration management commands require a project already initialized with `specify init`. To start a new project with a specific agent, use `specify init <project> --integration <key>` instead.
|
||||
|
||||
## Uninstall an Integration
|
||||
|
||||
```bash
|
||||
specify integration uninstall [<key>]
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| --------- | --------------------------------------------------- |
|
||||
| `--force` | Remove files even if they have been modified |
|
||||
|
||||
Uninstalls the current integration (or the specified one). Spec Kit tracks every file created during install along with a SHA-256 hash of the original content:
|
||||
|
||||
- **Unmodified files** are removed automatically.
|
||||
- **Modified files** (where you've made manual edits) are preserved so your customizations are not lost.
|
||||
- Use `--force` to remove all integration files regardless of modifications.
|
||||
|
||||
## Switch to a Different Integration
|
||||
|
||||
```bash
|
||||
specify integration switch <key>
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | ------------------------------------------------------------------------ |
|
||||
| `--script sh\|ps` | Script type: `sh` (bash/zsh) or `ps` (PowerShell) |
|
||||
| `--force` | Force removal of modified files during uninstall |
|
||||
| `--integration-options` | Options for the target integration |
|
||||
|
||||
Equivalent to running `uninstall` followed by `install` in a single step.
|
||||
|
||||
## Upgrade an Integration
|
||||
|
||||
```bash
|
||||
specify integration upgrade [<key>]
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | ------------------------------------------------------------------------ |
|
||||
| `--force` | Overwrite files even if they have been modified |
|
||||
| `--script sh\|ps` | Script type: `sh` (bash/zsh) or `ps` (PowerShell) |
|
||||
| `--integration-options` | Options for the integration |
|
||||
|
||||
Reinstalls the current integration with updated templates and commands (e.g., after upgrading Spec Kit). Defaults to the currently installed integration; if a key is provided, it must match the installed one — otherwise the command fails and suggests using `switch` instead. Detects locally modified files and blocks the upgrade unless `--force` is used. Stale files from the previous install that are no longer needed are removed automatically.
|
||||
|
||||
## Integration-Specific Options
|
||||
|
||||
Some integrations accept additional options via `--integration-options`:
|
||||
|
||||
| Integration | Option | Description |
|
||||
| ----------- | ------------------- | -------------------------------------------------------------- |
|
||||
| `generic` | `--commands-dir` | Required. Directory for command files |
|
||||
| `kimi` | `--migrate-legacy` | Migrate legacy dotted skill directories to hyphenated format |
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
specify integration install generic --integration-options="--commands-dir .myagent/cmds"
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
### Can I use multiple integrations at the same time?
|
||||
|
||||
No. Only one AI coding agent integration can be installed per project. Use `specify integration switch <key>` to change to a different AI coding agent.
|
||||
|
||||
### What happens to my changes when I uninstall or switch?
|
||||
|
||||
Files you've modified are preserved automatically. Only unmodified files (matching their original SHA-256 hash) are removed. Use `--force` to override this.
|
||||
|
||||
### How do I know which key to use?
|
||||
|
||||
Run `specify integration list` to see all available integrations with their keys, or check the [Supported AI Coding Agents](#supported-ai-coding-agents) table above.
|
||||
|
||||
### Do I need the AI coding agent installed to use an integration?
|
||||
|
||||
CLI-based integrations (like Claude Code, Gemini CLI) require the tool to be installed. IDE-based integrations (like Windsurf, Cursor) work through the IDE itself. Some agents like GitHub Copilot support both IDE and CLI usage. `specify integration list` shows which type each integration is.
|
||||
|
||||
### When should I use `upgrade` vs `switch`?
|
||||
|
||||
Use `upgrade` when you've upgraded Spec Kit and want to refresh the same integration's templates. Use `switch` when you want to change to a different AI coding agent.
|
||||
33
docs/reference/overview.md
Normal file
33
docs/reference/overview.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# CLI Reference
|
||||
|
||||
The Specify CLI (`specify`) manages the full lifecycle of Spec-Driven Development — from project initialization to workflow automation.
|
||||
|
||||
## Core Commands
|
||||
|
||||
The foundational commands for creating and managing Spec Kit projects. Initialize a new project with the necessary directory structure, templates, and scripts. Verify that your system has the required tools installed. Check version and system information.
|
||||
|
||||
[Core Commands reference →](core.md)
|
||||
|
||||
## Integrations
|
||||
|
||||
Integrations connect Spec Kit to your AI coding agent. Each integration sets up the appropriate command files, context rules, and directory structures for a specific agent. Only one integration is active per project at a time, and you can switch between them at any point.
|
||||
|
||||
[Integrations reference →](integrations.md)
|
||||
|
||||
## Extensions
|
||||
|
||||
Extensions add new capabilities to Spec Kit — domain-specific commands, external tool integrations, quality gates, and more. They are discovered through catalogs and can be installed, updated, enabled, disabled, or removed independently. Multiple extensions can coexist in a single project.
|
||||
|
||||
[Extensions reference →](extensions.md)
|
||||
|
||||
## Presets
|
||||
|
||||
Presets customize how Spec Kit works — overriding command files, template files, and script files without changing any tooling. They let you enforce organizational standards, adapt the workflow to your methodology, or localize the entire experience. Multiple presets can be stacked with priority ordering to layer customizations.
|
||||
|
||||
[Presets reference →](presets.md)
|
||||
|
||||
## Workflows
|
||||
|
||||
Workflows automate multi-step Spec-Driven Development processes into repeatable sequences. They chain commands, prompts, shell steps, and human checkpoints together, with support for conditional logic, loops, fan-out/fan-in, and the ability to pause and resume from the exact point of interruption.
|
||||
|
||||
[Workflows reference →](workflows.md)
|
||||
224
docs/reference/presets.md
Normal file
224
docs/reference/presets.md
Normal file
@@ -0,0 +1,224 @@
|
||||
# Presets
|
||||
|
||||
Presets customize how Spec Kit works — overriding templates, commands, and terminology without changing any tooling. They let you enforce organizational standards, adapt the workflow to your methodology, or localize the entire experience. Multiple presets can be stacked with priority ordering.
|
||||
|
||||
## Search Available Presets
|
||||
|
||||
```bash
|
||||
specify preset search [query]
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ---------- | -------------------- |
|
||||
| `--tag` | Filter by tag |
|
||||
| `--author` | Filter by author |
|
||||
|
||||
Searches all active catalogs for presets matching the query. Without a query, lists all available presets.
|
||||
|
||||
## Install a Preset
|
||||
|
||||
```bash
|
||||
specify preset add [<preset_id>]
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | -------------------------------------------------------- |
|
||||
| `--dev <path>` | Install from a local directory (for development) |
|
||||
| `--from <url>` | Install from a custom URL instead of the catalog |
|
||||
| `--priority <N>` | Resolution priority (default: 10; lower = higher precedence) |
|
||||
|
||||
Installs a preset from the catalog, a URL, or a local directory. Preset commands are automatically registered with the currently installed AI coding agent integration.
|
||||
|
||||
> **Note:** All preset commands require a project already initialized with `specify init`.
|
||||
|
||||
## Remove a Preset
|
||||
|
||||
```bash
|
||||
specify preset remove <preset_id>
|
||||
```
|
||||
|
||||
Removes an installed preset and cleans up its registered commands.
|
||||
|
||||
## List Installed Presets
|
||||
|
||||
```bash
|
||||
specify preset list
|
||||
```
|
||||
|
||||
Lists installed presets with their versions, descriptions, template counts, and current status.
|
||||
|
||||
## Preset Info
|
||||
|
||||
```bash
|
||||
specify preset info <preset_id>
|
||||
```
|
||||
|
||||
Shows detailed information about an installed or available preset, including its templates, metadata, and tags.
|
||||
|
||||
## Resolve a File
|
||||
|
||||
```bash
|
||||
specify preset resolve <name>
|
||||
```
|
||||
|
||||
Shows which file will be used for a given name by tracing the full resolution stack. Useful for debugging when multiple presets provide the same file.
|
||||
|
||||
## Enable / Disable a Preset
|
||||
|
||||
```bash
|
||||
specify preset enable <preset_id>
|
||||
specify preset disable <preset_id>
|
||||
```
|
||||
|
||||
Disable a preset without removing it. Disabled presets are skipped during file resolution but their commands remain registered. Re-enable with `enable`.
|
||||
|
||||
## Set Preset Priority
|
||||
|
||||
```bash
|
||||
specify preset set-priority <preset_id> <priority>
|
||||
```
|
||||
|
||||
Changes the resolution priority of an installed preset. Lower numbers take precedence. When multiple presets provide the same file, the one with the lowest priority number wins.
|
||||
|
||||
## Catalog Management
|
||||
|
||||
Preset catalogs control where `search` and `add` look for presets. Catalogs are checked in priority order (lower number = higher precedence).
|
||||
|
||||
### List Catalogs
|
||||
|
||||
```bash
|
||||
specify preset catalog list
|
||||
```
|
||||
|
||||
Shows all active catalogs with their priorities and install permissions.
|
||||
|
||||
### Add a Catalog
|
||||
|
||||
```bash
|
||||
specify preset catalog add <url>
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| -------------------------------------------- | -------------------------------------------------- |
|
||||
| `--name <name>` | Required. Unique name for the catalog |
|
||||
| `--priority <N>` | Priority (default: 10; lower = higher precedence) |
|
||||
| `--install-allowed / --no-install-allowed` | Whether presets can be installed from this catalog (default: discovery only) |
|
||||
| `--description <text>` | Optional description |
|
||||
|
||||
Adds a catalog to the project's `.specify/preset-catalogs.yml`.
|
||||
|
||||
### Remove a Catalog
|
||||
|
||||
```bash
|
||||
specify preset catalog remove <name>
|
||||
```
|
||||
|
||||
Removes a catalog from the project configuration.
|
||||
|
||||
### Catalog Resolution Order
|
||||
|
||||
Catalogs are resolved in this order (first match wins):
|
||||
|
||||
1. **Environment variable** — `SPECKIT_PRESET_CATALOG_URL` overrides all catalogs
|
||||
2. **Project config** — `.specify/preset-catalogs.yml`
|
||||
3. **User config** — `~/.specify/preset-catalogs.yml`
|
||||
4. **Built-in defaults** — official catalog + community catalog
|
||||
|
||||
Example `.specify/preset-catalogs.yml`:
|
||||
|
||||
```yaml
|
||||
catalogs:
|
||||
- name: "my-org-presets"
|
||||
url: "https://example.com/preset-catalog.json"
|
||||
priority: 5
|
||||
install_allowed: true
|
||||
description: "Our approved presets"
|
||||
```
|
||||
|
||||
## File Resolution
|
||||
|
||||
Presets can provide command files, template files (like `plan-template.md`), and script files. These are resolved at runtime using a **replace** strategy — the first match in the priority stack wins and is used entirely. Each file is looked up independently, so different files can come from different layers.
|
||||
|
||||
> **Note:** Additional composition strategies (`append`, `prepend`, `wrap`) are planned for a future release.
|
||||
|
||||
The resolution stack, from highest to lowest precedence:
|
||||
|
||||
1. **Project-local overrides** — `.specify/templates/overrides/`
|
||||
2. **Installed presets** — sorted by priority (lower = checked first)
|
||||
3. **Installed extensions** — sorted by priority
|
||||
4. **Spec Kit core** — `.specify/templates/`
|
||||
|
||||
Commands are registered at install time (not resolved through the stack at runtime).
|
||||
|
||||
### Resolution Stack
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph stack [" "]
|
||||
direction TB
|
||||
A["⬆ Highest precedence<br/><br/>1. Project-local overrides<br/>.specify/templates/overrides/"]
|
||||
B["2. Presets — by priority<br/>.specify/presets/‹id›/"]
|
||||
C["3. Extensions — by priority<br/>.specify/extensions/‹id›/"]
|
||||
D["4. Spec Kit core<br/>.specify/templates/<br/><br/>⬇ Lowest precedence"]
|
||||
end
|
||||
|
||||
A --> B --> C --> D
|
||||
|
||||
style A fill:#4a9,color:#fff
|
||||
style B fill:#49a,color:#fff
|
||||
style C fill:#a94,color:#fff
|
||||
style D fill:#999,color:#fff
|
||||
```
|
||||
|
||||
Within each layer, files are organized by type:
|
||||
|
||||
| Type | Subdirectory | Override path |
|
||||
| --------- | -------------- | ------------------------------------------ |
|
||||
| Templates | `templates/` | `.specify/templates/overrides/` |
|
||||
| Commands | `commands/` | `.specify/templates/overrides/` |
|
||||
| Scripts | `scripts/` | `.specify/templates/overrides/scripts/` |
|
||||
|
||||
### Resolution in Action
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
A["File requested:<br/>plan-template.md"] --> B{"Project-local override?"}
|
||||
B -- Found --> Z["✓ Use this file"]
|
||||
B -- Not found --> C{"Preset: compliance<br/>(priority 5)"}
|
||||
C -- Found --> Z
|
||||
C -- Not found --> D{"Preset: team-workflow<br/>(priority 10)"}
|
||||
D -- Found --> Z
|
||||
D -- Not found --> E{"Extension files?"}
|
||||
E -- Found --> Z
|
||||
E -- Not found --> F["Spec Kit core"]
|
||||
F --> Z
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```bash
|
||||
specify preset add compliance --priority 5
|
||||
specify preset add team-workflow --priority 10
|
||||
```
|
||||
|
||||
For any file that both provide, `compliance` wins (priority 5 < 10). For files only one provides, that one is used. For files neither provides, the core default is used.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Can I use multiple presets at the same time?
|
||||
|
||||
Yes. Presets stack by priority — each file is resolved independently from the highest-priority source that provides it. Use `specify preset set-priority` to control the order.
|
||||
|
||||
### How do I see which file is actually being used?
|
||||
|
||||
Run `specify preset resolve <name>` to trace the resolution stack and see which file wins.
|
||||
|
||||
### What's the difference between disabling and removing a preset?
|
||||
|
||||
**Disabling** (`specify preset disable`) keeps the preset installed but excludes its files from the resolution stack. Commands the preset registered remain available in your AI coding agent. This is useful for temporarily testing behavior without a preset, or comparing output with and without it. Re-enable anytime with `specify preset enable`.
|
||||
|
||||
**Removing** (`specify preset remove`) fully uninstalls the preset — deletes its files, unregisters its commands from your AI coding agent, and removes it from the registry.
|
||||
|
||||
### Who maintains presets?
|
||||
|
||||
Most presets are independently created and maintained by their respective authors. The Spec Kit maintainers do not review, audit, endorse, or support preset code. Review a preset's source code before installing and use at your own discretion. For issues with a specific preset, contact its author or file an issue on the preset's repository.
|
||||
289
docs/reference/workflows.md
Normal file
289
docs/reference/workflows.md
Normal file
@@ -0,0 +1,289 @@
|
||||
# Workflows
|
||||
|
||||
Workflows automate multi-step Spec-Driven Development processes — chaining commands, prompts, shell steps, and human checkpoints into repeatable sequences. They support conditional logic, loops, fan-out/fan-in, and can be paused and resumed from the exact point of interruption.
|
||||
|
||||
## Run a Workflow
|
||||
|
||||
```bash
|
||||
specify workflow run <source>
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | -------------------------------------------------------- |
|
||||
| `-i` / `--input` | Pass input values as `key=value` (repeatable) |
|
||||
|
||||
Runs a workflow from a catalog ID, URL, or local file path. Inputs declared by the workflow can be provided via `--input` or will be prompted interactively.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
specify workflow run speckit -i spec="Build a kanban board with drag-and-drop task management" -i scope=full
|
||||
```
|
||||
|
||||
> **Note:** All workflow commands require a project already initialized with `specify init`.
|
||||
|
||||
## Resume a Workflow
|
||||
|
||||
```bash
|
||||
specify workflow resume <run_id>
|
||||
```
|
||||
|
||||
Resumes a paused or failed workflow run from the exact step where it stopped. Useful after responding to a gate step or fixing an issue that caused a failure.
|
||||
|
||||
## Workflow Status
|
||||
|
||||
```bash
|
||||
specify workflow status [<run_id>]
|
||||
```
|
||||
|
||||
Shows the status of a specific run, or lists all runs if no ID is given. Run states: `created`, `running`, `completed`, `paused`, `failed`, `aborted`.
|
||||
|
||||
## List Installed Workflows
|
||||
|
||||
```bash
|
||||
specify workflow list
|
||||
```
|
||||
|
||||
Lists workflows installed in the current project.
|
||||
|
||||
## Install a Workflow
|
||||
|
||||
```bash
|
||||
specify workflow add <source>
|
||||
```
|
||||
|
||||
Installs a workflow from the catalog, a URL (HTTPS required), or a local file path.
|
||||
|
||||
## Remove a Workflow
|
||||
|
||||
```bash
|
||||
specify workflow remove <workflow_id>
|
||||
```
|
||||
|
||||
Removes an installed workflow from the project.
|
||||
|
||||
## Search Available Workflows
|
||||
|
||||
```bash
|
||||
specify workflow search [query]
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ------- | --------------- |
|
||||
| `--tag` | Filter by tag |
|
||||
|
||||
Searches all active catalogs for workflows matching the query.
|
||||
|
||||
## Workflow Info
|
||||
|
||||
```bash
|
||||
specify workflow info <workflow_id>
|
||||
```
|
||||
|
||||
Shows detailed information about a workflow, including its steps, inputs, and requirements.
|
||||
|
||||
## Catalog Management
|
||||
|
||||
Workflow catalogs control where `search` and `add` look for workflows. Catalogs are checked in priority order.
|
||||
|
||||
### List Catalogs
|
||||
|
||||
```bash
|
||||
specify workflow catalog list
|
||||
```
|
||||
|
||||
Shows all active catalog sources.
|
||||
|
||||
### Add a Catalog
|
||||
|
||||
```bash
|
||||
specify workflow catalog add <url>
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| --------------- | -------------------------------- |
|
||||
| `--name <name>` | Optional name for the catalog |
|
||||
|
||||
Adds a custom catalog URL to the project's `.specify/workflow-catalogs.yml`.
|
||||
|
||||
### Remove a Catalog
|
||||
|
||||
```bash
|
||||
specify workflow catalog remove <index>
|
||||
```
|
||||
|
||||
Removes a catalog by its index in the catalog list.
|
||||
|
||||
### Catalog Resolution Order
|
||||
|
||||
Catalogs are resolved in this order (first match wins):
|
||||
|
||||
1. **Environment variable** — `SPECKIT_WORKFLOW_CATALOG_URL` overrides all catalogs
|
||||
2. **Project config** — `.specify/workflow-catalogs.yml`
|
||||
3. **User config** — `~/.specify/workflow-catalogs.yml`
|
||||
4. **Built-in defaults** — official catalog + community catalog
|
||||
|
||||
## Workflow Definition
|
||||
|
||||
Workflows are defined in YAML files. Here is the built-in **Full SDD Cycle** workflow that ships with Spec Kit:
|
||||
|
||||
```yaml
|
||||
schema_version: "1.0"
|
||||
workflow:
|
||||
id: "speckit"
|
||||
name: "Full SDD Cycle"
|
||||
version: "1.0.0"
|
||||
author: "GitHub"
|
||||
description: "Runs specify → plan → tasks → implement with review gates"
|
||||
|
||||
requires:
|
||||
speckit_version: ">=0.7.2"
|
||||
integrations:
|
||||
any: ["copilot", "claude", "gemini"]
|
||||
|
||||
inputs:
|
||||
spec:
|
||||
type: string
|
||||
required: true
|
||||
prompt: "Describe what you want to build"
|
||||
integration:
|
||||
type: string
|
||||
default: "copilot"
|
||||
prompt: "Integration to use (e.g. claude, copilot, gemini)"
|
||||
scope:
|
||||
type: string
|
||||
default: "full"
|
||||
enum: ["full", "backend-only", "frontend-only"]
|
||||
|
||||
steps:
|
||||
- id: specify
|
||||
command: speckit.specify
|
||||
integration: "{{ inputs.integration }}"
|
||||
input:
|
||||
args: "{{ inputs.spec }}"
|
||||
|
||||
- id: review-spec
|
||||
type: gate
|
||||
message: "Review the generated spec before planning."
|
||||
options: [approve, reject]
|
||||
on_reject: abort
|
||||
|
||||
- id: plan
|
||||
command: speckit.plan
|
||||
integration: "{{ inputs.integration }}"
|
||||
input:
|
||||
args: "{{ inputs.spec }}"
|
||||
|
||||
- id: review-plan
|
||||
type: gate
|
||||
message: "Review the plan before generating tasks."
|
||||
options: [approve, reject]
|
||||
on_reject: abort
|
||||
|
||||
- id: tasks
|
||||
command: speckit.tasks
|
||||
integration: "{{ inputs.integration }}"
|
||||
input:
|
||||
args: "{{ inputs.spec }}"
|
||||
|
||||
- id: implement
|
||||
command: speckit.implement
|
||||
integration: "{{ inputs.integration }}"
|
||||
input:
|
||||
args: "{{ inputs.spec }}"
|
||||
```
|
||||
|
||||
This produces the following execution flow:
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
A["specify<br/>(command)"] --> B{"review-spec<br/>(gate)"}
|
||||
B -- approve --> C["plan<br/>(command)"]
|
||||
B -- reject --> X1["⏹ Abort"]
|
||||
C --> D{"review-plan<br/>(gate)"}
|
||||
D -- approve --> E["tasks<br/>(command)"]
|
||||
D -- reject --> X2["⏹ Abort"]
|
||||
E --> F["implement<br/>(command)"]
|
||||
|
||||
style A fill:#49a,color:#fff
|
||||
style B fill:#a94,color:#fff
|
||||
style C fill:#49a,color:#fff
|
||||
style D fill:#a94,color:#fff
|
||||
style E fill:#49a,color:#fff
|
||||
style F fill:#49a,color:#fff
|
||||
style X1 fill:#999,color:#fff
|
||||
style X2 fill:#999,color:#fff
|
||||
```
|
||||
|
||||
Run it with:
|
||||
|
||||
```bash
|
||||
specify workflow run speckit -i spec="Build a kanban board with drag-and-drop task management"
|
||||
```
|
||||
|
||||
## Step Types
|
||||
|
||||
| Type | Purpose |
|
||||
| ------------ | ------------------------------------------------ |
|
||||
| `command` | Invoke a Spec Kit command (e.g., `speckit.plan`) |
|
||||
| `prompt` | Send an arbitrary prompt to the AI coding agent |
|
||||
| `shell` | Execute a shell command and capture output |
|
||||
| `gate` | Pause for human approval before continuing |
|
||||
| `if` | Conditional branching (then/else) |
|
||||
| `switch` | Multi-branch dispatch on an expression |
|
||||
| `while` | Loop while a condition is true |
|
||||
| `do-while` | Execute at least once, then loop on condition |
|
||||
| `fan-out` | Dispatch a step for each item in a list |
|
||||
| `fan-in` | Aggregate results from a fan-out step |
|
||||
|
||||
## Expressions
|
||||
|
||||
Steps can reference inputs and previous step outputs using `{{ expression }}` syntax:
|
||||
|
||||
| Namespace | Description |
|
||||
| ------------------------------ | ------------------------------------ |
|
||||
| `inputs.spec` | Workflow input values |
|
||||
| `steps.specify.output.file` | Output from a previous step |
|
||||
| `item` | Current item in a fan-out iteration |
|
||||
|
||||
Available filters: `default`, `join`, `contains`, `map`.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
condition: "{{ steps.test.output.exit_code == 0 }}"
|
||||
args: "{{ inputs.spec }}"
|
||||
message: "{{ status | default('pending') }}"
|
||||
```
|
||||
|
||||
## Input Types
|
||||
|
||||
| Type | Coercion |
|
||||
| --------- | ------------------------------------------------- |
|
||||
| `string` | Pass-through |
|
||||
| `number` | `"42"` → `42`, `"3.14"` → `3.14` |
|
||||
| `boolean` | `"true"` / `"1"` / `"yes"` → `True` |
|
||||
|
||||
## State and Resume
|
||||
|
||||
Each workflow run persists its state at `.specify/workflows/runs/<run_id>/`:
|
||||
|
||||
- `state.json` — current run state and step progress
|
||||
- `inputs.json` — resolved input values
|
||||
- `log.jsonl` — step-by-step execution log
|
||||
|
||||
This enables `specify workflow resume` to continue from the exact step where a run was paused (e.g., at a gate) or failed.
|
||||
|
||||
## FAQ
|
||||
|
||||
### What happens when a workflow hits a gate step?
|
||||
|
||||
The workflow pauses and waits for human input. Run `specify workflow resume <run_id>` after reviewing to continue.
|
||||
|
||||
### Can I run the same workflow multiple times?
|
||||
|
||||
Yes. Each run gets a unique ID and its own state directory. Use `specify workflow status` to see all runs.
|
||||
|
||||
### Who maintains workflows?
|
||||
|
||||
Most workflows are independently created and maintained by their respective authors. The Spec Kit maintainers do not review, audit, endorse, or support workflow code. Review a workflow's source before installing and use at your own discretion.
|
||||
28
docs/toc.yml
28
docs/toc.yml
@@ -9,9 +9,37 @@
|
||||
href: installation.md
|
||||
- name: Quick Start
|
||||
href: quickstart.md
|
||||
- name: Upgrade
|
||||
href: upgrade.md
|
||||
|
||||
# Reference
|
||||
- name: Reference
|
||||
items:
|
||||
- name: Overview
|
||||
href: reference/overview.md
|
||||
- name: Core Commands
|
||||
href: reference/core.md
|
||||
- name: Integrations
|
||||
href: reference/integrations.md
|
||||
- name: Extensions
|
||||
href: reference/extensions.md
|
||||
- name: Presets
|
||||
href: reference/presets.md
|
||||
- name: Workflows
|
||||
href: reference/workflows.md
|
||||
|
||||
# Development workflows
|
||||
- name: Development
|
||||
items:
|
||||
- name: Local Development
|
||||
href: local-development.md
|
||||
|
||||
# Community
|
||||
- name: Community
|
||||
items:
|
||||
- name: Presets
|
||||
href: community/presets.md
|
||||
- name: Walkthroughs
|
||||
href: community/walkthroughs.md
|
||||
- name: Friends
|
||||
href: community/friends.md
|
||||
|
||||
462
docs/upgrade.md
Normal file
462
docs/upgrade.md
Normal file
@@ -0,0 +1,462 @@
|
||||
# Upgrade Guide
|
||||
|
||||
> You have Spec Kit installed and want to upgrade to the latest version to get new features, bug fixes, or updated slash commands. This guide covers both upgrading the CLI tool and updating your project files.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What to Upgrade | Command | When to Use |
|
||||
|----------------|---------|-------------|
|
||||
| **CLI Tool Only** | `uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git@vX.Y.Z` | Get latest CLI features without touching project files |
|
||||
| **CLI Tool Only (pipx)** | `pipx install --force git+https://github.com/github/spec-kit.git@vX.Y.Z` | Reinstall/upgrade a pipx-installed CLI to a specific release |
|
||||
| **Project Files** | `specify init --here --force --integration <your-agent>` | Update slash commands, templates, and scripts in your project |
|
||||
| **Both** | Run CLI upgrade, then project update | Recommended for major version updates |
|
||||
|
||||
---
|
||||
|
||||
## Part 1: Upgrade the CLI Tool
|
||||
|
||||
The CLI tool (`specify`) is separate from your project files. Upgrade it to get the latest features and bug fixes.
|
||||
|
||||
### If you installed with `uv tool install`
|
||||
|
||||
Upgrade to a specific release (check [Releases](https://github.com/github/spec-kit/releases) for the latest tag):
|
||||
|
||||
```bash
|
||||
uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git@vX.Y.Z
|
||||
```
|
||||
|
||||
### If you use one-shot `uvx` commands
|
||||
|
||||
Specify the desired release tag:
|
||||
|
||||
```bash
|
||||
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init --here --integration copilot
|
||||
```
|
||||
|
||||
### If you installed with `pipx`
|
||||
|
||||
Upgrade to a specific release:
|
||||
|
||||
```bash
|
||||
pipx install --force git+https://github.com/github/spec-kit.git@vX.Y.Z
|
||||
```
|
||||
|
||||
### Verify the upgrade
|
||||
|
||||
```bash
|
||||
specify check
|
||||
```
|
||||
|
||||
This shows installed tools and confirms the CLI is working.
|
||||
|
||||
---
|
||||
|
||||
## Part 2: Updating Project Files
|
||||
|
||||
When Spec Kit releases new features (like new slash commands or updated templates), you need to refresh your project's Spec Kit files.
|
||||
|
||||
### What gets updated?
|
||||
|
||||
Running `specify init --here --force` will update:
|
||||
|
||||
- ✅ **Slash command files** (`.claude/commands/`, `.github/prompts/`, etc.)
|
||||
- ✅ **Script files** (`.specify/scripts/`) — **only with `--force`**; without it, only missing files are added
|
||||
- ✅ **Template files** (`.specify/templates/`) — **only with `--force`**; without it, only missing files are added
|
||||
- ✅ **Shared memory files** (`.specify/memory/`) - **⚠️ See warnings below**
|
||||
|
||||
### What stays safe?
|
||||
|
||||
These files are **never touched** by the upgrade—the template packages don't even contain them:
|
||||
|
||||
- ✅ **Your specifications** (`specs/001-my-feature/spec.md`, etc.) - **CONFIRMED SAFE**
|
||||
- ✅ **Your implementation plans** (`specs/001-my-feature/plan.md`, `tasks.md`, etc.) - **CONFIRMED SAFE**
|
||||
- ✅ **Your source code** - **CONFIRMED SAFE**
|
||||
- ✅ **Your git history** - **CONFIRMED SAFE**
|
||||
|
||||
The `specs/` directory is completely excluded from template packages and will never be modified during upgrades.
|
||||
|
||||
### Update command
|
||||
|
||||
Run this inside your project directory:
|
||||
|
||||
```bash
|
||||
specify init --here --force --integration <your-agent>
|
||||
```
|
||||
|
||||
Replace `<your-agent>` with your AI coding agent. Refer to this list of [Supported AI Coding Agent Integrations](reference/integrations.md)
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
specify init --here --force --integration copilot
|
||||
```
|
||||
|
||||
### Understanding the `--force` flag
|
||||
|
||||
Without `--force`, the CLI warns you and asks for confirmation:
|
||||
|
||||
```text
|
||||
Warning: Current directory is not empty (25 items)
|
||||
Template files will be merged with existing content and may overwrite existing files
|
||||
Proceed? [y/N]
|
||||
```
|
||||
|
||||
With `--force`, it skips the confirmation and proceeds immediately. It also **overwrites shared infrastructure files** (`.specify/scripts/` and `.specify/templates/`) with the latest versions from the installed Spec Kit release.
|
||||
|
||||
Without `--force`, shared infrastructure files that already exist are skipped — the CLI will print a warning listing the skipped files so you know which ones were not updated.
|
||||
|
||||
**Important: Your `specs/` directory is always safe.** The `--force` flag only affects template files (commands, scripts, templates, memory). Your feature specifications, plans, and tasks in `specs/` are never included in upgrade packages and cannot be overwritten.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Important Warnings
|
||||
|
||||
### 1. Constitution file will be overwritten
|
||||
|
||||
**Known issue:** `specify init --here --force` currently overwrites `.specify/memory/constitution.md` with the default template, erasing any customizations you made.
|
||||
|
||||
**Workaround:**
|
||||
|
||||
```bash
|
||||
# 1. Back up your constitution before upgrading
|
||||
cp .specify/memory/constitution.md .specify/memory/constitution-backup.md
|
||||
|
||||
# 2. Run the upgrade
|
||||
specify init --here --force --integration copilot
|
||||
|
||||
# 3. Restore your customized constitution
|
||||
mv .specify/memory/constitution-backup.md .specify/memory/constitution.md
|
||||
```
|
||||
|
||||
Or use git to restore it:
|
||||
|
||||
```bash
|
||||
# After upgrade, restore from git history
|
||||
git restore .specify/memory/constitution.md
|
||||
```
|
||||
|
||||
### 2. Custom script or template modifications
|
||||
|
||||
If you customized files in `.specify/scripts/` or `.specify/templates/`, the `--force` flag will overwrite them. Back them up first:
|
||||
|
||||
```bash
|
||||
# Back up custom templates and scripts
|
||||
cp -r .specify/templates .specify/templates-backup
|
||||
cp -r .specify/scripts .specify/scripts-backup
|
||||
|
||||
# After upgrade, merge your changes back manually
|
||||
```
|
||||
|
||||
### 3. Duplicate slash commands (IDE-based agents)
|
||||
|
||||
Some IDE-based agents (like Kilo Code, Windsurf) may show **duplicate slash commands** after upgrading—both old and new versions appear.
|
||||
|
||||
**Solution:** Manually delete the old command files from your agent's folder.
|
||||
|
||||
**Example for Kilo Code:**
|
||||
|
||||
```bash
|
||||
# Navigate to the agent's commands folder
|
||||
cd .kilocode/rules/
|
||||
|
||||
# List files and identify duplicates
|
||||
ls -la
|
||||
|
||||
# Delete old versions (example filenames - yours may differ)
|
||||
rm speckit.specify-old.md
|
||||
rm speckit.plan-v1.md
|
||||
```
|
||||
|
||||
Restart your IDE to refresh the command list.
|
||||
|
||||
---
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Scenario 1: "I just want new slash commands"
|
||||
|
||||
```bash
|
||||
# Upgrade CLI (if using persistent install)
|
||||
uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git
|
||||
|
||||
# Update project files to get new commands
|
||||
specify init --here --force --integration copilot
|
||||
|
||||
# Restore your constitution if customized
|
||||
git restore .specify/memory/constitution.md
|
||||
```
|
||||
|
||||
### Scenario 2: "I customized templates and constitution"
|
||||
|
||||
```bash
|
||||
# 1. Back up customizations
|
||||
cp .specify/memory/constitution.md /tmp/constitution-backup.md
|
||||
cp -r .specify/templates /tmp/templates-backup
|
||||
|
||||
# 2. Upgrade CLI
|
||||
uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git
|
||||
|
||||
# 3. Update project
|
||||
specify init --here --force --integration copilot
|
||||
|
||||
# 4. Restore customizations
|
||||
mv /tmp/constitution-backup.md .specify/memory/constitution.md
|
||||
# Manually merge template changes if needed
|
||||
```
|
||||
|
||||
### Scenario 3: "I see duplicate slash commands in my IDE"
|
||||
|
||||
This happens with IDE-based agents (Kilo Code, Windsurf, Roo Code, etc.).
|
||||
|
||||
```bash
|
||||
# Find the agent folder (example: .kilocode/rules/)
|
||||
cd .kilocode/rules/
|
||||
|
||||
# List all files
|
||||
ls -la
|
||||
|
||||
# Delete old command files
|
||||
rm speckit.old-command-name.md
|
||||
|
||||
# Restart your IDE
|
||||
```
|
||||
|
||||
### Scenario 4: "I'm working on a project without Git"
|
||||
|
||||
If you initialized your project with `--no-git`, you can still upgrade:
|
||||
|
||||
```bash
|
||||
# Manually back up files you customized
|
||||
cp .specify/memory/constitution.md /tmp/constitution-backup.md
|
||||
|
||||
# Run upgrade
|
||||
specify init --here --force --integration copilot --no-git
|
||||
|
||||
# Restore customizations
|
||||
mv /tmp/constitution-backup.md .specify/memory/constitution.md
|
||||
```
|
||||
|
||||
The `--no-git` flag skips git initialization but doesn't affect file updates.
|
||||
|
||||
---
|
||||
|
||||
## Using `--no-git` Flag
|
||||
|
||||
The `--no-git` flag tells Spec Kit to **skip git repository initialization**. This is useful when:
|
||||
|
||||
- You manage version control differently (Mercurial, SVN, etc.)
|
||||
- Your project is part of a larger monorepo with existing git setup
|
||||
- You're experimenting and don't want version control yet
|
||||
|
||||
**During initial setup:**
|
||||
|
||||
```bash
|
||||
specify init my-project --integration copilot --no-git
|
||||
```
|
||||
|
||||
**During upgrade:**
|
||||
|
||||
```bash
|
||||
specify init --here --force --integration copilot --no-git
|
||||
```
|
||||
|
||||
### What `--no-git` does NOT do
|
||||
|
||||
❌ Does NOT prevent file updates
|
||||
❌ Does NOT skip slash command installation
|
||||
❌ Does NOT affect template merging
|
||||
|
||||
It **only** skips running `git init` and creating the initial commit.
|
||||
|
||||
### Working without Git
|
||||
|
||||
If you use `--no-git`, you'll need to manage feature directories manually:
|
||||
|
||||
**Set the `SPECIFY_FEATURE` environment variable** before using planning commands:
|
||||
|
||||
```bash
|
||||
# Bash/Zsh
|
||||
export SPECIFY_FEATURE="001-my-feature"
|
||||
|
||||
# PowerShell
|
||||
$env:SPECIFY_FEATURE = "001-my-feature"
|
||||
```
|
||||
|
||||
This tells Spec Kit which feature directory to use when creating specs, plans, and tasks.
|
||||
|
||||
**Why this matters:** Without git, Spec Kit can't detect your current branch name to determine the active feature. The environment variable provides that context manually.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Slash commands not showing up after upgrade"
|
||||
|
||||
**Cause:** Agent didn't reload the command files.
|
||||
|
||||
**Fix:**
|
||||
|
||||
1. **Restart your IDE/editor** completely (not just reload window)
|
||||
2. **For CLI-based agents**, verify files exist:
|
||||
|
||||
```bash
|
||||
ls -la .claude/commands/ # Claude Code
|
||||
ls -la .gemini/commands/ # Gemini
|
||||
ls -la .cursor/skills/ # Cursor
|
||||
ls -la .pi/prompts/ # Pi Coding Agent
|
||||
```
|
||||
|
||||
3. **Check agent-specific setup:**
|
||||
- Codex requires `CODEX_HOME` environment variable
|
||||
- Some agents need workspace restart or cache clearing
|
||||
|
||||
### "I lost my constitution customizations"
|
||||
|
||||
**Fix:** Restore from git or backup:
|
||||
|
||||
```bash
|
||||
# If you committed before upgrading
|
||||
git restore .specify/memory/constitution.md
|
||||
|
||||
# If you backed up manually
|
||||
cp /tmp/constitution-backup.md .specify/memory/constitution.md
|
||||
```
|
||||
|
||||
**Prevention:** Always commit or back up `constitution.md` before upgrading.
|
||||
|
||||
### "Warning: Current directory is not empty"
|
||||
|
||||
**Full warning message:**
|
||||
|
||||
```text
|
||||
Warning: Current directory is not empty (25 items)
|
||||
Template files will be merged with existing content and may overwrite existing files
|
||||
Do you want to continue? [y/N]
|
||||
```
|
||||
|
||||
**What this means:**
|
||||
|
||||
This warning appears when you run `specify init --here` (or `specify init .`) in a directory that already has files. It's telling you:
|
||||
|
||||
1. **The directory has existing content** - In the example, 25 files/folders
|
||||
2. **Files will be merged** - New template files will be added alongside your existing files
|
||||
3. **Some files may be overwritten** - If you already have Spec Kit files (`.claude/`, `.specify/`, etc.), they'll be replaced with the new versions
|
||||
|
||||
**What gets overwritten:**
|
||||
|
||||
Only Spec Kit infrastructure files:
|
||||
|
||||
- Agent command files (`.claude/commands/`, `.github/prompts/`, etc.)
|
||||
- Scripts in `.specify/scripts/`
|
||||
- Templates in `.specify/templates/`
|
||||
- Memory files in `.specify/memory/` (including constitution)
|
||||
|
||||
**What stays untouched:**
|
||||
|
||||
- Your `specs/` directory (specifications, plans, tasks)
|
||||
- Your source code files
|
||||
- Your `.git/` directory and git history
|
||||
- Any other files not part of Spec Kit templates
|
||||
|
||||
**How to respond:**
|
||||
|
||||
- **Type `y` and press Enter** - Proceed with the merge (recommended if upgrading)
|
||||
- **Type `n` and press Enter** - Cancel the operation
|
||||
- **Use `--force` flag** - Skip this confirmation entirely:
|
||||
|
||||
```bash
|
||||
specify init --here --force --integration copilot
|
||||
```
|
||||
|
||||
**When you see this warning:**
|
||||
|
||||
- ✅ **Expected** when upgrading an existing Spec Kit project
|
||||
- ✅ **Expected** when adding Spec Kit to an existing codebase
|
||||
- ⚠️ **Unexpected** if you thought you were creating a new project in an empty directory
|
||||
|
||||
**Prevention tip:** Before upgrading, commit or back up your `.specify/memory/constitution.md` if you customized it.
|
||||
|
||||
### "CLI upgrade doesn't seem to work"
|
||||
|
||||
Verify the installation:
|
||||
|
||||
```bash
|
||||
# Check installed tools
|
||||
uv tool list
|
||||
|
||||
# Should show specify-cli
|
||||
|
||||
# Verify path
|
||||
which specify
|
||||
|
||||
# Should point to the uv tool installation directory
|
||||
```
|
||||
|
||||
If not found, reinstall:
|
||||
|
||||
```bash
|
||||
uv tool uninstall specify-cli
|
||||
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git
|
||||
```
|
||||
|
||||
### "Do I need to run specify every time I open my project?"
|
||||
|
||||
**Short answer:** No, you only run `specify init` once per project (or when upgrading).
|
||||
|
||||
**Explanation:**
|
||||
|
||||
The `specify` CLI tool is used for:
|
||||
|
||||
- **Initial setup:** `specify init` to bootstrap Spec Kit in your project
|
||||
- **Upgrades:** `specify init --here --force` to update templates and commands
|
||||
- **Diagnostics:** `specify check` to verify tool installation
|
||||
|
||||
Once you've run `specify init`, the slash commands (like `/speckit.specify`, `/speckit.plan`, etc.) are **permanently installed** in your project's agent folder (`.claude/`, `.github/prompts/`, `.pi/prompts/`, etc.). Your AI coding agent reads these command files directly—no need to run `specify` again.
|
||||
|
||||
**If your agent isn't recognizing slash commands:**
|
||||
|
||||
1. **Verify command files exist:**
|
||||
|
||||
```bash
|
||||
# For GitHub Copilot
|
||||
ls -la .github/prompts/
|
||||
|
||||
# For Claude
|
||||
ls -la .claude/commands/
|
||||
|
||||
# For Pi
|
||||
ls -la .pi/prompts/
|
||||
```
|
||||
|
||||
2. **Restart your IDE/editor completely** (not just reload window)
|
||||
|
||||
3. **Check you're in the correct directory** where you ran `specify init`
|
||||
|
||||
4. **For some agents**, you may need to reload the workspace or clear cache
|
||||
|
||||
**Related issue:** If Copilot can't open local files or uses PowerShell commands unexpectedly, this is typically an IDE context issue, not related to `specify`. Try:
|
||||
|
||||
- Restarting VS Code
|
||||
- Checking file permissions
|
||||
- Ensuring the workspace folder is properly opened
|
||||
|
||||
---
|
||||
|
||||
## Version Compatibility
|
||||
|
||||
Spec Kit follows semantic versioning for major releases. The CLI and project files are designed to be compatible within the same major version.
|
||||
|
||||
**Best practice:** Keep both CLI and project files in sync by upgrading both together during major version changes.
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
After upgrading:
|
||||
|
||||
- **Test new slash commands:** Run `/speckit.constitution` or another command to verify everything works
|
||||
- **Review release notes:** Check [GitHub Releases](https://github.com/github/spec-kit/releases) for new features and breaking changes
|
||||
- **Update workflows:** If new commands were added, update your team's development workflows
|
||||
- **Check documentation:** Visit [github.io/spec-kit](https://github.github.io/spec-kit/) for updated guides
|
||||
830
extensions/EXTENSION-API-REFERENCE.md
Normal file
830
extensions/EXTENSION-API-REFERENCE.md
Normal file
@@ -0,0 +1,830 @@
|
||||
# Extension API Reference
|
||||
|
||||
Technical reference for Spec Kit extension system APIs and manifest schema.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Extension Manifest](#extension-manifest)
|
||||
2. [Python API](#python-api)
|
||||
3. [Command File Format](#command-file-format)
|
||||
4. [Configuration Schema](#configuration-schema)
|
||||
5. [Hook System](#hook-system)
|
||||
6. [CLI Commands](#cli-commands)
|
||||
|
||||
---
|
||||
|
||||
## Extension Manifest
|
||||
|
||||
### Schema Version 1.0
|
||||
|
||||
File: `extension.yml`
|
||||
|
||||
```yaml
|
||||
schema_version: "1.0" # Required
|
||||
|
||||
extension:
|
||||
id: string # Required, pattern: ^[a-z0-9-]+$
|
||||
name: string # Required, human-readable name
|
||||
version: string # Required, semantic version (X.Y.Z)
|
||||
description: string # Required, brief description (<200 chars)
|
||||
author: string # Required
|
||||
repository: string # Required, valid URL
|
||||
license: string # Required (e.g., "MIT", "Apache-2.0")
|
||||
homepage: string # Optional, valid URL
|
||||
|
||||
requires:
|
||||
speckit_version: string # Required, version specifier (>=X.Y.Z)
|
||||
tools: # Optional, array of tool requirements
|
||||
- name: string # Tool name
|
||||
version: string # Optional, version specifier
|
||||
required: boolean # Optional, default: false
|
||||
|
||||
provides:
|
||||
commands: # Required, at least one command
|
||||
- name: string # Required, pattern: ^speckit\.[a-z0-9-]+\.[a-z0-9-]+$
|
||||
file: string # Required, relative path to command file
|
||||
description: string # Required
|
||||
aliases: [string] # Optional, same pattern as name; namespace must match extension.id and must not shadow core or installed extension commands
|
||||
|
||||
config: # Optional, array of config files
|
||||
- name: string # Config file name
|
||||
template: string # Template file path
|
||||
description: string
|
||||
required: boolean # Default: false
|
||||
|
||||
hooks: # Optional, event hooks
|
||||
event_name: # e.g., "after_specify", "after_plan", "after_tasks", "after_implement"
|
||||
command: string # Command to execute
|
||||
optional: boolean # Default: true
|
||||
prompt: string # Prompt text for optional hooks
|
||||
description: string # Hook description
|
||||
condition: string # Optional, condition expression
|
||||
|
||||
tags: # Optional, array of tags (2-10 recommended)
|
||||
- string
|
||||
|
||||
defaults: # Optional, default configuration values
|
||||
key: value # Any YAML structure
|
||||
```
|
||||
|
||||
### Field Specifications
|
||||
|
||||
#### `extension.id`
|
||||
|
||||
- **Type**: string
|
||||
- **Pattern**: `^[a-z0-9-]+$`
|
||||
- **Description**: Unique extension identifier
|
||||
- **Examples**: `jira`, `linear`, `azure-devops`
|
||||
- **Invalid**: `Jira`, `my_extension`, `extension.id`
|
||||
|
||||
#### `extension.version`
|
||||
|
||||
- **Type**: string
|
||||
- **Format**: Semantic versioning (X.Y.Z)
|
||||
- **Description**: Extension version
|
||||
- **Examples**: `1.0.0`, `0.9.5`, `2.1.3`
|
||||
- **Invalid**: `v1.0`, `1.0`, `1.0.0-beta`
|
||||
|
||||
#### `requires.speckit_version`
|
||||
|
||||
- **Type**: string
|
||||
- **Format**: Version specifier
|
||||
- **Description**: Required spec-kit version range
|
||||
- **Examples**:
|
||||
- `>=0.1.0` - Any version 0.1.0 or higher
|
||||
- `>=0.1.0,<2.0.0` - Version 0.1.x or 1.x
|
||||
- `==0.1.0` - Exactly 0.1.0
|
||||
- **Invalid**: `0.1.0`, `>= 0.1.0` (space), `latest`
|
||||
|
||||
#### `provides.commands[].name`
|
||||
|
||||
- **Type**: string
|
||||
- **Pattern**: `^speckit\.[a-z0-9-]+\.[a-z0-9-]+$`
|
||||
- **Description**: Namespaced command name
|
||||
- **Format**: `speckit.{extension-id}.{command-name}`
|
||||
- **Examples**: `speckit.jira.specstoissues`, `speckit.linear.sync`
|
||||
- **Invalid**: `jira.specstoissues`, `speckit.command`, `speckit.jira.CreateIssues`
|
||||
|
||||
#### `hooks`
|
||||
|
||||
- **Type**: object
|
||||
- **Keys**: Event names (e.g., `after_specify`, `after_plan`, `after_tasks`, `after_implement`, `before_analyze`)
|
||||
- **Description**: Hooks that execute at lifecycle events
|
||||
- **Events**: Defined by core spec-kit commands
|
||||
|
||||
---
|
||||
|
||||
## Python API
|
||||
|
||||
### ExtensionManifest
|
||||
|
||||
**Module**: `specify_cli.extensions`
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import ExtensionManifest
|
||||
|
||||
manifest = ExtensionManifest(Path("extension.yml"))
|
||||
```
|
||||
|
||||
**Properties**:
|
||||
|
||||
```python
|
||||
manifest.id # str: Extension ID
|
||||
manifest.name # str: Extension name
|
||||
manifest.version # str: Version
|
||||
manifest.description # str: Description
|
||||
manifest.requires_speckit_version # str: Required spec-kit version
|
||||
manifest.commands # List[Dict]: Command definitions
|
||||
manifest.hooks # Dict: Hook definitions
|
||||
```
|
||||
|
||||
**Methods**:
|
||||
|
||||
```python
|
||||
manifest.get_hash() # str: SHA256 hash of manifest file
|
||||
```
|
||||
|
||||
**Exceptions**:
|
||||
|
||||
```python
|
||||
ValidationError # Invalid manifest structure
|
||||
CompatibilityError # Incompatible with current spec-kit version
|
||||
```
|
||||
|
||||
### ExtensionRegistry
|
||||
|
||||
**Module**: `specify_cli.extensions`
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import ExtensionRegistry
|
||||
|
||||
registry = ExtensionRegistry(extensions_dir)
|
||||
```
|
||||
|
||||
**Methods**:
|
||||
|
||||
```python
|
||||
# Add extension to registry
|
||||
registry.add(extension_id: str, metadata: dict)
|
||||
|
||||
# Remove extension from registry
|
||||
registry.remove(extension_id: str)
|
||||
|
||||
# Get extension metadata
|
||||
metadata = registry.get(extension_id: str) # Optional[dict]
|
||||
|
||||
# List all extensions
|
||||
extensions = registry.list() # Dict[str, dict]
|
||||
|
||||
# Check if installed
|
||||
is_installed = registry.is_installed(extension_id: str) # bool
|
||||
```
|
||||
|
||||
**Registry Format**:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"extensions": {
|
||||
"jira": {
|
||||
"version": "1.0.0",
|
||||
"source": "catalog",
|
||||
"manifest_hash": "sha256...",
|
||||
"enabled": true,
|
||||
"registered_commands": ["speckit.jira.specstoissues", ...],
|
||||
"installed_at": "2026-01-28T..."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ExtensionManager
|
||||
|
||||
**Module**: `specify_cli.extensions`
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import ExtensionManager
|
||||
|
||||
manager = ExtensionManager(project_root)
|
||||
```
|
||||
|
||||
**Methods**:
|
||||
|
||||
```python
|
||||
# Install from directory
|
||||
manifest = manager.install_from_directory(
|
||||
source_dir: Path,
|
||||
speckit_version: str,
|
||||
register_commands: bool = True
|
||||
) # Returns: ExtensionManifest
|
||||
|
||||
# Install from ZIP
|
||||
manifest = manager.install_from_zip(
|
||||
zip_path: Path,
|
||||
speckit_version: str
|
||||
) # Returns: ExtensionManifest
|
||||
|
||||
# Remove extension
|
||||
success = manager.remove(
|
||||
extension_id: str,
|
||||
keep_config: bool = False
|
||||
) # Returns: bool
|
||||
|
||||
# List installed extensions
|
||||
extensions = manager.list_installed() # List[Dict]
|
||||
|
||||
# Get extension manifest
|
||||
manifest = manager.get_extension(extension_id: str) # Optional[ExtensionManifest]
|
||||
|
||||
# Check compatibility
|
||||
manager.check_compatibility(
|
||||
manifest: ExtensionManifest,
|
||||
speckit_version: str
|
||||
) # Raises: CompatibilityError if incompatible
|
||||
```
|
||||
|
||||
### CatalogEntry
|
||||
|
||||
**Module**: `specify_cli.extensions`
|
||||
|
||||
Represents a single catalog in the active catalog stack.
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import CatalogEntry
|
||||
|
||||
entry = CatalogEntry(
|
||||
url="https://example.com/catalog.json",
|
||||
name="default",
|
||||
priority=1,
|
||||
install_allowed=True,
|
||||
description="Built-in catalog of installable extensions",
|
||||
)
|
||||
```
|
||||
|
||||
**Fields**:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `url` | `str` | Catalog URL (must use HTTPS, or HTTP for localhost) |
|
||||
| `name` | `str` | Human-readable catalog name |
|
||||
| `priority` | `int` | Sort order (lower = higher priority, wins on conflicts) |
|
||||
| `install_allowed` | `bool` | Whether extensions from this catalog can be installed |
|
||||
| `description` | `str` | Optional human-readable description of the catalog (default: empty) |
|
||||
|
||||
### ExtensionCatalog
|
||||
|
||||
**Module**: `specify_cli.extensions`
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import ExtensionCatalog
|
||||
|
||||
catalog = ExtensionCatalog(project_root)
|
||||
```
|
||||
|
||||
**Class attributes**:
|
||||
|
||||
```python
|
||||
ExtensionCatalog.DEFAULT_CATALOG_URL # default catalog URL
|
||||
ExtensionCatalog.COMMUNITY_CATALOG_URL # community catalog URL
|
||||
```
|
||||
|
||||
**Methods**:
|
||||
|
||||
```python
|
||||
# Get the ordered list of active catalogs
|
||||
entries = catalog.get_active_catalogs() # List[CatalogEntry]
|
||||
|
||||
# Fetch catalog (primary catalog, backward compat)
|
||||
catalog_data = catalog.fetch_catalog(force_refresh: bool = False) # Dict
|
||||
|
||||
# Search extensions across all active catalogs
|
||||
# Each result includes _catalog_name and _install_allowed
|
||||
results = catalog.search(
|
||||
query: Optional[str] = None,
|
||||
tag: Optional[str] = None,
|
||||
author: Optional[str] = None,
|
||||
verified_only: bool = False
|
||||
) # Returns: List[Dict] — each dict includes _catalog_name, _install_allowed
|
||||
|
||||
# Get extension info (searches all active catalogs)
|
||||
# Returns None if not found; includes _catalog_name and _install_allowed
|
||||
ext_info = catalog.get_extension_info(extension_id: str) # Optional[Dict]
|
||||
|
||||
# Check cache validity (primary catalog)
|
||||
is_valid = catalog.is_cache_valid() # bool
|
||||
|
||||
# Clear all catalog caches
|
||||
catalog.clear_cache()
|
||||
```
|
||||
|
||||
**Result annotation fields**:
|
||||
|
||||
Each extension dict returned by `search()` and `get_extension_info()` includes:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `_catalog_name` | `str` | Name of the source catalog |
|
||||
| `_install_allowed` | `bool` | Whether installation is allowed from this catalog |
|
||||
|
||||
**Catalog config file** (`.specify/extension-catalogs.yml`):
|
||||
|
||||
```yaml
|
||||
catalogs:
|
||||
- name: "default"
|
||||
url: "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.json"
|
||||
priority: 1
|
||||
install_allowed: true
|
||||
description: "Built-in catalog of installable extensions"
|
||||
- name: "community"
|
||||
url: "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json"
|
||||
priority: 2
|
||||
install_allowed: false
|
||||
description: "Community-contributed extensions (discovery only)"
|
||||
```
|
||||
|
||||
### HookExecutor
|
||||
|
||||
**Module**: `specify_cli.extensions`
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import HookExecutor
|
||||
|
||||
hook_executor = HookExecutor(project_root)
|
||||
```
|
||||
|
||||
**Methods**:
|
||||
|
||||
```python
|
||||
# Get project config
|
||||
config = hook_executor.get_project_config() # Dict
|
||||
|
||||
# Save project config
|
||||
hook_executor.save_project_config(config: Dict)
|
||||
|
||||
# Register hooks
|
||||
hook_executor.register_hooks(manifest: ExtensionManifest)
|
||||
|
||||
# Unregister hooks
|
||||
hook_executor.unregister_hooks(extension_id: str)
|
||||
|
||||
# Get hooks for event
|
||||
hooks = hook_executor.get_hooks_for_event(event_name: str) # List[Dict]
|
||||
|
||||
# Check if hook should execute
|
||||
should_run = hook_executor.should_execute_hook(hook: Dict) # bool
|
||||
|
||||
# Format hook message
|
||||
message = hook_executor.format_hook_message(
|
||||
event_name: str,
|
||||
hooks: List[Dict]
|
||||
) # str
|
||||
```
|
||||
|
||||
### CommandRegistrar
|
||||
|
||||
**Module**: `specify_cli.extensions`
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import CommandRegistrar
|
||||
|
||||
registrar = CommandRegistrar()
|
||||
```
|
||||
|
||||
**Methods**:
|
||||
|
||||
```python
|
||||
# Register commands for Claude Code
|
||||
registered = registrar.register_commands_for_claude(
|
||||
manifest: ExtensionManifest,
|
||||
extension_dir: Path,
|
||||
project_root: Path
|
||||
) # Returns: List[str] (command names)
|
||||
|
||||
# Parse frontmatter
|
||||
frontmatter, body = registrar.parse_frontmatter(content: str)
|
||||
|
||||
# Render frontmatter
|
||||
yaml_text = registrar.render_frontmatter(frontmatter: Dict) # str
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Command File Format
|
||||
|
||||
### Universal Command Format
|
||||
|
||||
**File**: `commands/{command-name}.md`
|
||||
|
||||
```markdown
|
||||
---
|
||||
description: "Command description"
|
||||
tools:
|
||||
- 'mcp-server/tool_name'
|
||||
- 'other-mcp-server/other_tool'
|
||||
---
|
||||
|
||||
# Command Title
|
||||
|
||||
Command documentation in Markdown.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Requirement 1
|
||||
2. Requirement 2
|
||||
|
||||
## User Input
|
||||
|
||||
$ARGUMENTS
|
||||
|
||||
## Steps
|
||||
|
||||
### Step 1: Description
|
||||
|
||||
Instruction text...
|
||||
|
||||
\`\`\`bash
|
||||
# Shell commands
|
||||
\`\`\`
|
||||
|
||||
### Step 2: Another Step
|
||||
|
||||
More instructions...
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
Information about configuration options.
|
||||
|
||||
## Notes
|
||||
|
||||
Additional notes and tips.
|
||||
```
|
||||
|
||||
### Frontmatter Fields
|
||||
|
||||
```yaml
|
||||
description: string # Required, brief command description
|
||||
tools: [string] # Optional, MCP tools required
|
||||
```
|
||||
|
||||
### Special Variables
|
||||
|
||||
- `$ARGUMENTS` - Placeholder for user-provided arguments
|
||||
- Extension context automatically injected:
|
||||
|
||||
```markdown
|
||||
<!-- Extension: {extension-id} -->
|
||||
<!-- Config: .specify/extensions/{extension-id}/ -->
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Schema
|
||||
|
||||
### Extension Config File
|
||||
|
||||
**File**: `.specify/extensions/{extension-id}/{extension-id}-config.yml`
|
||||
|
||||
Extensions define their own config schema. Common patterns:
|
||||
|
||||
```yaml
|
||||
# Connection settings
|
||||
connection:
|
||||
url: string
|
||||
api_key: string
|
||||
|
||||
# Project settings
|
||||
project:
|
||||
key: string
|
||||
workspace: string
|
||||
|
||||
# Feature flags
|
||||
features:
|
||||
enabled: boolean
|
||||
auto_sync: boolean
|
||||
|
||||
# Defaults
|
||||
defaults:
|
||||
labels: [string]
|
||||
assignee: string
|
||||
|
||||
# Custom fields
|
||||
field_mappings:
|
||||
internal_name: "external_field_id"
|
||||
```
|
||||
|
||||
### Config Layers
|
||||
|
||||
1. **Extension Defaults** (from `extension.yml` `defaults` section)
|
||||
2. **Project Config** (`{extension-id}-config.yml`)
|
||||
3. **Local Override** (`{extension-id}-config.local.yml`, gitignored)
|
||||
4. **Environment Variables** (`SPECKIT_{EXTENSION}_*`)
|
||||
|
||||
### Environment Variable Pattern
|
||||
|
||||
Format: `SPECKIT_{EXTENSION}_{KEY}`
|
||||
|
||||
Examples:
|
||||
|
||||
- `SPECKIT_JIRA_PROJECT_KEY`
|
||||
- `SPECKIT_LINEAR_API_KEY`
|
||||
- `SPECKIT_GITHUB_TOKEN`
|
||||
|
||||
---
|
||||
|
||||
## Hook System
|
||||
|
||||
### Hook Definition
|
||||
|
||||
**In extension.yml**:
|
||||
|
||||
```yaml
|
||||
hooks:
|
||||
after_tasks:
|
||||
command: "speckit.jira.specstoissues"
|
||||
optional: true
|
||||
prompt: "Create Jira issues from tasks?"
|
||||
description: "Automatically create Jira hierarchy"
|
||||
condition: null
|
||||
```
|
||||
|
||||
### Hook Events
|
||||
|
||||
Standard events (defined by core):
|
||||
|
||||
- `before_specify` - Before specification generation
|
||||
- `after_specify` - After specification generation
|
||||
- `before_plan` - Before implementation planning
|
||||
- `after_plan` - After implementation planning
|
||||
- `before_tasks` - Before task generation
|
||||
- `after_tasks` - After task generation
|
||||
- `before_implement` - Before implementation
|
||||
- `after_implement` - After implementation
|
||||
- `before_analyze` - Before cross-artifact analysis
|
||||
- `after_analyze` - After cross-artifact analysis
|
||||
- `before_checklist` - Before checklist generation
|
||||
- `after_checklist` - After checklist generation
|
||||
- `before_clarify` - Before spec clarification
|
||||
- `after_clarify` - After spec clarification
|
||||
- `before_constitution` - Before constitution update
|
||||
- `after_constitution` - After constitution update
|
||||
- `before_taskstoissues` - Before tasks-to-issues conversion
|
||||
- `after_taskstoissues` - After tasks-to-issues conversion
|
||||
|
||||
### Hook Configuration
|
||||
|
||||
**In `.specify/extensions.yml`**:
|
||||
|
||||
```yaml
|
||||
hooks:
|
||||
after_tasks:
|
||||
- extension: jira
|
||||
command: speckit.jira.specstoissues
|
||||
enabled: true
|
||||
optional: true
|
||||
prompt: "Create Jira issues from tasks?"
|
||||
description: "..."
|
||||
condition: null
|
||||
```
|
||||
|
||||
### Hook Message Format
|
||||
|
||||
```markdown
|
||||
## Extension Hooks
|
||||
|
||||
**Optional Hook**: {extension}
|
||||
Command: `/{command}`
|
||||
Description: {description}
|
||||
|
||||
Prompt: {prompt}
|
||||
To execute: `/{command}`
|
||||
```
|
||||
|
||||
Or for mandatory hooks:
|
||||
|
||||
```markdown
|
||||
**Automatic Hook**: {extension}
|
||||
Executing: `/{command}`
|
||||
EXECUTE_COMMAND: {command}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CLI Commands
|
||||
|
||||
### extension list
|
||||
|
||||
**Usage**: `specify extension list [OPTIONS]`
|
||||
|
||||
**Options**:
|
||||
|
||||
- `--available` - Show available extensions from catalog
|
||||
- `--all` - Show both installed and available
|
||||
|
||||
**Output**: List of installed extensions with metadata
|
||||
|
||||
### extension catalog list
|
||||
|
||||
**Usage**: `specify extension catalog list`
|
||||
|
||||
Lists all active catalogs in the current catalog stack, showing name, description, URL, priority, and `install_allowed` status.
|
||||
|
||||
### extension catalog add
|
||||
|
||||
**Usage**: `specify extension catalog add URL [OPTIONS]`
|
||||
|
||||
**Options**:
|
||||
|
||||
- `--name NAME` - Catalog name (required)
|
||||
- `--priority INT` - Priority (lower = higher priority, default: 10)
|
||||
- `--install-allowed / --no-install-allowed` - Allow installs from this catalog (default: false)
|
||||
- `--description TEXT` - Optional description of the catalog
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `URL` - Catalog URL (must use HTTPS)
|
||||
|
||||
Adds a catalog entry to `.specify/extension-catalogs.yml`.
|
||||
|
||||
### extension catalog remove
|
||||
|
||||
**Usage**: `specify extension catalog remove NAME`
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `NAME` - Catalog name to remove
|
||||
|
||||
Removes a catalog entry from `.specify/extension-catalogs.yml`.
|
||||
|
||||
### extension add
|
||||
|
||||
**Usage**: `specify extension add EXTENSION [OPTIONS]`
|
||||
|
||||
**Options**:
|
||||
|
||||
- `--from URL` - Install from custom URL
|
||||
- `--dev PATH` - Install from local directory
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `EXTENSION` - Extension name or URL
|
||||
|
||||
**Note**: Extensions from catalogs with `install_allowed: false` cannot be installed via this command.
|
||||
|
||||
### extension remove
|
||||
|
||||
**Usage**: `specify extension remove EXTENSION [OPTIONS]`
|
||||
|
||||
**Options**:
|
||||
|
||||
- `--keep-config` - Preserve config files
|
||||
- `--force` - Skip confirmation
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `EXTENSION` - Extension ID
|
||||
|
||||
### extension search
|
||||
|
||||
**Usage**: `specify extension search [QUERY] [OPTIONS]`
|
||||
|
||||
Searches all active catalogs simultaneously. Results include source catalog name and install_allowed status.
|
||||
|
||||
**Options**:
|
||||
|
||||
- `--tag TAG` - Filter by tag
|
||||
- `--author AUTHOR` - Filter by author
|
||||
- `--verified` - Show only verified extensions
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `QUERY` - Optional search query
|
||||
|
||||
### extension info
|
||||
|
||||
**Usage**: `specify extension info EXTENSION`
|
||||
|
||||
Shows source catalog and install_allowed status.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `EXTENSION` - Extension ID
|
||||
|
||||
### extension update
|
||||
|
||||
**Usage**: `specify extension update [EXTENSION]`
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `EXTENSION` - Optional, extension ID (default: all)
|
||||
|
||||
### extension enable
|
||||
|
||||
**Usage**: `specify extension enable EXTENSION`
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `EXTENSION` - Extension ID
|
||||
|
||||
### extension disable
|
||||
|
||||
**Usage**: `specify extension disable EXTENSION`
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- `EXTENSION` - Extension ID
|
||||
|
||||
---
|
||||
|
||||
## Exceptions
|
||||
|
||||
### ValidationError
|
||||
|
||||
Raised when extension manifest validation fails.
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import ValidationError
|
||||
|
||||
try:
|
||||
manifest = ExtensionManifest(path)
|
||||
except ValidationError as e:
|
||||
print(f"Invalid manifest: {e}")
|
||||
```
|
||||
|
||||
### CompatibilityError
|
||||
|
||||
Raised when extension is incompatible with current spec-kit version.
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import CompatibilityError
|
||||
|
||||
try:
|
||||
manager.check_compatibility(manifest, "0.1.0")
|
||||
except CompatibilityError as e:
|
||||
print(f"Incompatible: {e}")
|
||||
```
|
||||
|
||||
### ExtensionError
|
||||
|
||||
Base exception for all extension-related errors.
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import ExtensionError
|
||||
|
||||
try:
|
||||
manager.install_from_directory(path, "0.1.0")
|
||||
except ExtensionError as e:
|
||||
print(f"Extension error: {e}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Version Functions
|
||||
|
||||
### version_satisfies
|
||||
|
||||
Check if a version satisfies a specifier.
|
||||
|
||||
```python
|
||||
from specify_cli.extensions import version_satisfies
|
||||
|
||||
# True if 1.2.3 satisfies >=1.0.0,<2.0.0
|
||||
satisfied = version_satisfies("1.2.3", ">=1.0.0,<2.0.0") # bool
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File System Layout
|
||||
|
||||
```text
|
||||
.specify/
|
||||
├── extensions/
|
||||
│ ├── .registry # Extension registry (JSON)
|
||||
│ ├── .cache/ # Catalog cache
|
||||
│ │ ├── catalog.json
|
||||
│ │ └── catalog-metadata.json
|
||||
│ ├── .backup/ # Config backups
|
||||
│ │ └── {ext}-{config}.yml
|
||||
│ ├── {extension-id}/ # Extension directory
|
||||
│ │ ├── extension.yml # Manifest
|
||||
│ │ ├── {ext}-config.yml # User config
|
||||
│ │ ├── {ext}-config.local.yml # Local overrides (gitignored)
|
||||
│ │ ├── {ext}-config.template.yml # Template
|
||||
│ │ ├── commands/ # Command files
|
||||
│ │ │ └── *.md
|
||||
│ │ ├── scripts/ # Helper scripts
|
||||
│ │ │ └── *.sh
|
||||
│ │ ├── docs/ # Documentation
|
||||
│ │ └── README.md
|
||||
│ └── extensions.yml # Project extension config
|
||||
└── scripts/ # (existing spec-kit)
|
||||
|
||||
.claude/
|
||||
└── commands/
|
||||
└── speckit.{ext}.{cmd}.md # Registered commands
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*Last Updated: 2026-01-28*
|
||||
*API Version: 1.0*
|
||||
*Spec Kit Version: 0.1.0*
|
||||
719
extensions/EXTENSION-DEVELOPMENT-GUIDE.md
Normal file
719
extensions/EXTENSION-DEVELOPMENT-GUIDE.md
Normal file
@@ -0,0 +1,719 @@
|
||||
# Extension Development Guide
|
||||
|
||||
A guide for creating Spec Kit extensions.
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Create Extension Directory
|
||||
|
||||
```bash
|
||||
mkdir my-extension
|
||||
cd my-extension
|
||||
```
|
||||
|
||||
### 2. Create `extension.yml` Manifest
|
||||
|
||||
```yaml
|
||||
schema_version: "1.0"
|
||||
|
||||
extension:
|
||||
id: "my-ext" # Lowercase, alphanumeric + hyphens only
|
||||
name: "My Extension"
|
||||
version: "1.0.0" # Semantic versioning
|
||||
description: "My custom extension"
|
||||
author: "Your Name"
|
||||
repository: "https://github.com/you/spec-kit-my-ext"
|
||||
license: "MIT"
|
||||
|
||||
requires:
|
||||
speckit_version: ">=0.1.0" # Minimum spec-kit version
|
||||
tools: # Optional: External tools required
|
||||
- name: "my-tool"
|
||||
required: true
|
||||
version: ">=1.0.0"
|
||||
commands: # Optional: Core commands needed
|
||||
- "speckit.tasks"
|
||||
|
||||
provides:
|
||||
commands:
|
||||
- name: "speckit.my-ext.hello" # Must follow pattern: speckit.{ext-id}.{cmd}
|
||||
file: "commands/hello.md"
|
||||
description: "Say hello"
|
||||
aliases: ["speckit.my-ext.hi"] # Optional aliases, same pattern
|
||||
|
||||
config: # Optional: Config files
|
||||
- name: "my-ext-config.yml"
|
||||
template: "my-ext-config.template.yml"
|
||||
description: "Extension configuration"
|
||||
required: false
|
||||
|
||||
hooks: # Optional: Integration hooks
|
||||
after_tasks:
|
||||
command: "speckit.my-ext.hello"
|
||||
optional: true
|
||||
prompt: "Run hello command?"
|
||||
|
||||
tags: # Optional: For catalog search
|
||||
- "example"
|
||||
- "utility"
|
||||
```
|
||||
|
||||
### 3. Create Commands Directory
|
||||
|
||||
```bash
|
||||
mkdir commands
|
||||
```
|
||||
|
||||
### 4. Create Command File
|
||||
|
||||
**File**: `commands/hello.md`
|
||||
|
||||
```markdown
|
||||
---
|
||||
description: "Say hello command"
|
||||
tools: # Optional: AI tools this command uses
|
||||
- 'some-tool/function'
|
||||
scripts: # Optional: Helper scripts
|
||||
sh: ../../scripts/bash/helper.sh
|
||||
ps: ../../scripts/powershell/helper.ps1
|
||||
---
|
||||
|
||||
# Hello Command
|
||||
|
||||
This command says hello!
|
||||
|
||||
## User Input
|
||||
|
||||
$ARGUMENTS
|
||||
|
||||
## Steps
|
||||
|
||||
1. Greet the user
|
||||
2. Show extension is working
|
||||
|
||||
```bash
|
||||
echo "Hello from my extension!"
|
||||
echo "Arguments: $ARGUMENTS"
|
||||
```
|
||||
|
||||
## Extension Configuration
|
||||
|
||||
Load extension config from `.specify/extensions/my-ext/my-ext-config.yml`.
|
||||
|
||||
### 5. Test Locally
|
||||
|
||||
```bash
|
||||
cd /path/to/spec-kit-project
|
||||
specify extension add --dev /path/to/my-extension
|
||||
```
|
||||
|
||||
### 6. Verify Installation
|
||||
|
||||
```bash
|
||||
specify extension list
|
||||
|
||||
# Should show:
|
||||
# ✓ My Extension (v1.0.0)
|
||||
# My custom extension
|
||||
# Commands: 1 | Hooks: 1 | Status: Enabled
|
||||
```
|
||||
|
||||
### 7. Test Command
|
||||
|
||||
If using Claude:
|
||||
|
||||
```bash
|
||||
claude
|
||||
> /speckit.my-ext.hello world
|
||||
```
|
||||
|
||||
The command will be available in `.claude/commands/speckit.my-ext.hello.md`.
|
||||
|
||||
---
|
||||
|
||||
## Manifest Schema Reference
|
||||
|
||||
### Required Fields
|
||||
|
||||
#### `schema_version`
|
||||
|
||||
Extension manifest schema version. Currently: `"1.0"`
|
||||
|
||||
#### `extension`
|
||||
|
||||
Extension metadata block.
|
||||
|
||||
**Required sub-fields**:
|
||||
|
||||
- `id`: Extension identifier (lowercase, alphanumeric, hyphens)
|
||||
- `name`: Human-readable name
|
||||
- `version`: Semantic version (e.g., "1.0.0")
|
||||
- `description`: Short description
|
||||
|
||||
**Optional sub-fields**:
|
||||
|
||||
- `author`: Extension author
|
||||
- `repository`: Source code URL
|
||||
- `license`: SPDX license identifier
|
||||
- `homepage`: Extension homepage URL
|
||||
|
||||
#### `requires`
|
||||
|
||||
Compatibility requirements.
|
||||
|
||||
**Required sub-fields**:
|
||||
|
||||
- `speckit_version`: Semantic version specifier (e.g., ">=0.1.0,<2.0.0")
|
||||
|
||||
**Optional sub-fields**:
|
||||
|
||||
- `tools`: External tools required (array of tool objects)
|
||||
- `commands`: Core spec-kit commands needed (array of command names)
|
||||
- `scripts`: Core scripts required (array of script names)
|
||||
|
||||
#### `provides`
|
||||
|
||||
What the extension provides.
|
||||
|
||||
**Optional sub-fields**:
|
||||
|
||||
- `commands`: Array of command objects (at least one command or hook is required)
|
||||
|
||||
**Command object**:
|
||||
|
||||
- `name`: Command name (must match `speckit.{ext-id}.{command}`)
|
||||
- `file`: Path to command file (relative to extension root)
|
||||
- `description`: Command description (optional)
|
||||
- `aliases`: Alternative command names (optional, array; each must match `speckit.{ext-id}.{command}`)
|
||||
|
||||
### Optional Fields
|
||||
|
||||
#### `hooks`
|
||||
|
||||
Integration hooks for automatic execution.
|
||||
|
||||
Available hook points:
|
||||
|
||||
- `before_specify` / `after_specify`: Before/after specification generation
|
||||
- `before_plan` / `after_plan`: Before/after implementation planning
|
||||
- `before_tasks` / `after_tasks`: Before/after task generation
|
||||
- `before_implement` / `after_implement`: Before/after implementation
|
||||
- `before_analyze` / `after_analyze`: Before/after cross-artifact analysis
|
||||
- `before_checklist` / `after_checklist`: Before/after checklist generation
|
||||
- `before_clarify` / `after_clarify`: Before/after spec clarification
|
||||
- `before_constitution` / `after_constitution`: Before/after constitution update
|
||||
- `before_taskstoissues` / `after_taskstoissues`: Before/after tasks-to-issues conversion
|
||||
|
||||
Hook object:
|
||||
|
||||
- `command`: Command to execute (typically from `provides.commands`, but can reference any registered command)
|
||||
- `optional`: If true, prompt user before executing
|
||||
- `prompt`: Prompt text for optional hooks
|
||||
- `description`: Hook description
|
||||
- `condition`: Execution condition (future)
|
||||
|
||||
#### `tags`
|
||||
|
||||
Array of tags for catalog discovery.
|
||||
|
||||
#### `defaults`
|
||||
|
||||
Default extension configuration values.
|
||||
|
||||
#### `config_schema`
|
||||
|
||||
JSON Schema for validating extension configuration.
|
||||
|
||||
---
|
||||
|
||||
## Command File Format
|
||||
|
||||
### Frontmatter (YAML)
|
||||
|
||||
```yaml
|
||||
---
|
||||
description: "Command description" # Required
|
||||
tools: # Optional
|
||||
- 'tool-name/function'
|
||||
scripts: # Optional
|
||||
sh: ../../scripts/bash/helper.sh
|
||||
ps: ../../scripts/powershell/helper.ps1
|
||||
---
|
||||
```
|
||||
|
||||
### Body (Markdown)
|
||||
|
||||
Use standard Markdown with special placeholders:
|
||||
|
||||
- `$ARGUMENTS`: User-provided arguments
|
||||
- `{SCRIPT}`: Replaced with script path during registration
|
||||
|
||||
**Example**:
|
||||
|
||||
````markdown
|
||||
## Steps
|
||||
|
||||
1. Parse arguments
|
||||
2. Execute logic
|
||||
|
||||
```bash
|
||||
args="$ARGUMENTS"
|
||||
echo "Running with args: $args"
|
||||
```
|
||||
````
|
||||
|
||||
### Script Path Rewriting
|
||||
|
||||
Extension commands use relative paths that get rewritten during registration:
|
||||
|
||||
**In extension**:
|
||||
|
||||
```yaml
|
||||
scripts:
|
||||
sh: ../../scripts/bash/helper.sh
|
||||
```
|
||||
|
||||
**After registration**:
|
||||
|
||||
```yaml
|
||||
scripts:
|
||||
sh: .specify/scripts/bash/helper.sh
|
||||
```
|
||||
|
||||
This allows scripts to reference core spec-kit scripts.
|
||||
|
||||
---
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### Config Template
|
||||
|
||||
**File**: `my-ext-config.template.yml`
|
||||
|
||||
```yaml
|
||||
# My Extension Configuration
|
||||
# Copy this to my-ext-config.yml and customize
|
||||
|
||||
# Example configuration
|
||||
api:
|
||||
endpoint: "https://api.example.com"
|
||||
timeout: 30
|
||||
|
||||
features:
|
||||
feature_a: true
|
||||
feature_b: false
|
||||
|
||||
credentials:
|
||||
# DO NOT commit credentials!
|
||||
# Use environment variables instead
|
||||
api_key: "${MY_EXT_API_KEY}"
|
||||
```
|
||||
|
||||
### Config Loading
|
||||
|
||||
In your command, load config with layered precedence:
|
||||
|
||||
1. Extension defaults (`extension.yml` → `defaults`)
|
||||
2. Project config (`.specify/extensions/my-ext/my-ext-config.yml`)
|
||||
3. Local overrides (`.specify/extensions/my-ext/my-ext-config.local.yml` - gitignored)
|
||||
4. Environment variables (`SPECKIT_MY_EXT_*`)
|
||||
|
||||
**Example loading script**:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
EXT_DIR=".specify/extensions/my-ext"
|
||||
|
||||
# Load and merge config
|
||||
config=$(yq eval '.' "$EXT_DIR/my-ext-config.yml" -o=json)
|
||||
|
||||
# Apply env overrides
|
||||
if [ -n "${SPECKIT_MY_EXT_API_KEY:-}" ]; then
|
||||
config=$(echo "$config" | jq ".api.api_key = \"$SPECKIT_MY_EXT_API_KEY\"")
|
||||
fi
|
||||
|
||||
echo "$config"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Excluding Files with `.extensionignore`
|
||||
|
||||
Extension authors can create a `.extensionignore` file in the extension root to exclude files and folders from being copied when a user installs the extension with `specify extension add`. This is useful for keeping development-only files (tests, CI configs, docs source, etc.) out of the installed copy.
|
||||
|
||||
### Format
|
||||
|
||||
The file uses `.gitignore`-compatible patterns (one per line), powered by the [`pathspec`](https://pypi.org/project/pathspec/) library:
|
||||
|
||||
- Blank lines are ignored
|
||||
- Lines starting with `#` are comments
|
||||
- `*` matches anything **except** `/` (does not cross directory boundaries)
|
||||
- `**` matches zero or more directories (e.g., `docs/**/*.draft.md`)
|
||||
- `?` matches any single character except `/`
|
||||
- A trailing `/` restricts a pattern to directories only
|
||||
- Patterns containing `/` (other than a trailing slash) are anchored to the extension root
|
||||
- Patterns without `/` match at any depth in the tree
|
||||
- `!` negates a previously excluded pattern (re-includes a file)
|
||||
- Backslashes in patterns are normalised to forward slashes for cross-platform compatibility
|
||||
- The `.extensionignore` file itself is always excluded automatically
|
||||
|
||||
### Example
|
||||
|
||||
```gitignore
|
||||
# .extensionignore
|
||||
|
||||
# Development files
|
||||
tests/
|
||||
.github/
|
||||
.gitignore
|
||||
|
||||
# Build artifacts
|
||||
__pycache__/
|
||||
*.pyc
|
||||
dist/
|
||||
|
||||
# Documentation source (keep only the built README)
|
||||
docs/
|
||||
CONTRIBUTING.md
|
||||
```
|
||||
|
||||
### Pattern Matching
|
||||
|
||||
| Pattern | Matches | Does NOT match |
|
||||
|---------|---------|----------------|
|
||||
| `*.pyc` | Any `.pyc` file in any directory | — |
|
||||
| `tests/` | The `tests` directory (and all its contents) | A file named `tests` |
|
||||
| `docs/*.draft.md` | `docs/api.draft.md` (directly inside `docs/`) | `docs/sub/api.draft.md` (nested) |
|
||||
| `.env` | The `.env` file at any level | — |
|
||||
| `!README.md` | Re-includes `README.md` even if matched by an earlier pattern | — |
|
||||
| `docs/**/*.draft.md` | `docs/api.draft.md`, `docs/sub/api.draft.md` | — |
|
||||
|
||||
### Unsupported Features
|
||||
|
||||
The following `.gitignore` features are **not applicable** in this context:
|
||||
|
||||
- **Multiple `.extensionignore` files**: Only a single file at the extension root is supported (`.gitignore` supports files in subdirectories)
|
||||
- **`$GIT_DIR/info/exclude` and `core.excludesFile`**: These are Git-specific and have no equivalent here
|
||||
- **Negation inside excluded directories**: Because file copying uses `shutil.copytree`, excluding a directory prevents recursion into it entirely. A negation pattern cannot re-include a file inside a directory that was itself excluded. For example, the combination `tests/` followed by `!tests/important.py` will **not** preserve `tests/important.py` — the `tests/` directory is skipped at the root level and its contents are never evaluated. To work around this, exclude the directory's contents individually instead of the directory itself (e.g., `tests/*.pyc` and `tests/.cache/` rather than `tests/`).
|
||||
|
||||
---
|
||||
|
||||
## Validation Rules
|
||||
|
||||
### Extension ID
|
||||
|
||||
- **Pattern**: `^[a-z0-9-]+$`
|
||||
- **Valid**: `my-ext`, `tool-123`, `awesome-plugin`
|
||||
- **Invalid**: `MyExt` (uppercase), `my_ext` (underscore), `my ext` (space)
|
||||
|
||||
### Extension Version
|
||||
|
||||
- **Format**: Semantic versioning (MAJOR.MINOR.PATCH)
|
||||
- **Valid**: `1.0.0`, `0.1.0`, `2.5.3`
|
||||
- **Invalid**: `1.0`, `v1.0.0`, `1.0.0-beta`
|
||||
|
||||
### Command Name
|
||||
|
||||
- **Pattern**: `^speckit\.[a-z0-9-]+\.[a-z0-9-]+$`
|
||||
- **Valid**: `speckit.my-ext.hello`, `speckit.tool.cmd`
|
||||
- **Invalid**: `my-ext.hello` (missing prefix), `speckit.hello` (no extension namespace)
|
||||
|
||||
### Command File Path
|
||||
|
||||
- **Must be** relative to extension root
|
||||
- **Valid**: `commands/hello.md`, `commands/subdir/cmd.md`
|
||||
- **Invalid**: `/absolute/path.md`, `../outside.md`
|
||||
|
||||
---
|
||||
|
||||
## Testing Extensions
|
||||
|
||||
### Manual Testing
|
||||
|
||||
1. **Create test extension**
|
||||
2. **Install locally**:
|
||||
|
||||
```bash
|
||||
specify extension add --dev /path/to/extension
|
||||
```
|
||||
|
||||
3. **Verify installation**:
|
||||
|
||||
```bash
|
||||
specify extension list
|
||||
```
|
||||
|
||||
4. **Test commands** with your AI agent
|
||||
5. **Check command registration**:
|
||||
|
||||
```bash
|
||||
ls .claude/commands/speckit.my-ext.*
|
||||
```
|
||||
|
||||
6. **Remove extension**:
|
||||
|
||||
```bash
|
||||
specify extension remove my-ext
|
||||
```
|
||||
|
||||
### Automated Testing
|
||||
|
||||
Create tests for your extension:
|
||||
|
||||
```python
|
||||
# tests/test_my_extension.py
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from specify_cli.extensions import ExtensionManifest
|
||||
|
||||
def test_manifest_valid():
|
||||
"""Test extension manifest is valid."""
|
||||
manifest = ExtensionManifest(Path("extension.yml"))
|
||||
assert manifest.id == "my-ext"
|
||||
assert len(manifest.commands) >= 1
|
||||
|
||||
def test_command_files_exist():
|
||||
"""Test all command files exist."""
|
||||
manifest = ExtensionManifest(Path("extension.yml"))
|
||||
for cmd in manifest.commands:
|
||||
cmd_file = Path(cmd["file"])
|
||||
assert cmd_file.exists(), f"Command file not found: {cmd_file}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Distribution
|
||||
|
||||
### Option 1: GitHub Repository
|
||||
|
||||
1. **Create repository**: `spec-kit-my-ext`
|
||||
2. **Add files**:
|
||||
|
||||
```text
|
||||
spec-kit-my-ext/
|
||||
├── extension.yml
|
||||
├── commands/
|
||||
├── scripts/
|
||||
├── docs/
|
||||
├── README.md
|
||||
├── LICENSE
|
||||
└── CHANGELOG.md
|
||||
```
|
||||
|
||||
3. **Create release**: Tag with version (e.g., `v1.0.0`)
|
||||
4. **Install from repo**:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/you/spec-kit-my-ext
|
||||
specify extension add --dev spec-kit-my-ext/
|
||||
```
|
||||
|
||||
### Option 2: ZIP Archive (Future)
|
||||
|
||||
Create ZIP archive and host on GitHub Releases:
|
||||
|
||||
```bash
|
||||
zip -r spec-kit-my-ext-1.0.0.zip extension.yml commands/ scripts/ docs/
|
||||
```
|
||||
|
||||
Users install with:
|
||||
|
||||
```bash
|
||||
specify extension add <extension-name> --from https://github.com/.../spec-kit-my-ext-1.0.0.zip
|
||||
```
|
||||
|
||||
### Option 3: Community Reference Catalog
|
||||
|
||||
Submit to the community catalog for public discovery:
|
||||
|
||||
1. **Fork** spec-kit repository
|
||||
2. **Add entry** to `extensions/catalog.community.json`
|
||||
3. **Update** the Community Extensions table in `README.md` with your extension
|
||||
4. **Create PR** following the [Extension Publishing Guide](EXTENSION-PUBLISHING-GUIDE.md)
|
||||
5. **After merge**, your extension becomes available:
|
||||
- Users can browse `catalog.community.json` to discover your extension
|
||||
- Users copy the entry to their own `catalog.json`
|
||||
- Users install with: `specify extension add my-ext` (from their catalog)
|
||||
|
||||
See the [Extension Publishing Guide](EXTENSION-PUBLISHING-GUIDE.md) for detailed submission instructions.
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- **Extension ID**: Use descriptive, hyphenated names (`jira-integration`, not `ji`)
|
||||
- **Commands**: Use verb-noun pattern (`create-issue`, `sync-status`)
|
||||
- **Config files**: Match extension ID (`jira-config.yml`)
|
||||
|
||||
### Documentation
|
||||
|
||||
- **README.md**: Overview, installation, usage
|
||||
- **CHANGELOG.md**: Version history
|
||||
- **docs/**: Detailed guides
|
||||
- **Command descriptions**: Clear, concise
|
||||
|
||||
### Versioning
|
||||
|
||||
- **Follow SemVer**: `MAJOR.MINOR.PATCH`
|
||||
- **MAJOR**: Breaking changes
|
||||
- **MINOR**: New features
|
||||
- **PATCH**: Bug fixes
|
||||
|
||||
### Security
|
||||
|
||||
- **Never commit secrets**: Use environment variables
|
||||
- **Validate input**: Sanitize user arguments
|
||||
- **Document permissions**: What files/APIs are accessed
|
||||
|
||||
### Compatibility
|
||||
|
||||
- **Specify version range**: Don't require exact version
|
||||
- **Test with multiple versions**: Ensure compatibility
|
||||
- **Graceful degradation**: Handle missing features
|
||||
|
||||
---
|
||||
|
||||
## Example Extensions
|
||||
|
||||
### Minimal Extension
|
||||
|
||||
Smallest possible extension:
|
||||
|
||||
```yaml
|
||||
# extension.yml
|
||||
schema_version: "1.0"
|
||||
extension:
|
||||
id: "minimal"
|
||||
name: "Minimal Extension"
|
||||
version: "1.0.0"
|
||||
description: "Minimal example"
|
||||
requires:
|
||||
speckit_version: ">=0.1.0"
|
||||
provides:
|
||||
commands:
|
||||
- name: "speckit.minimal.hello"
|
||||
file: "commands/hello.md"
|
||||
```
|
||||
|
||||
````markdown
|
||||
<!-- commands/hello.md -->
|
||||
---
|
||||
description: "Hello command"
|
||||
---
|
||||
|
||||
# Hello World
|
||||
|
||||
```bash
|
||||
echo "Hello, $ARGUMENTS!"
|
||||
```
|
||||
````
|
||||
|
||||
### Extension with Config
|
||||
|
||||
Extension using configuration:
|
||||
|
||||
```yaml
|
||||
# extension.yml
|
||||
# ... metadata ...
|
||||
provides:
|
||||
config:
|
||||
- name: "tool-config.yml"
|
||||
template: "tool-config.template.yml"
|
||||
required: true
|
||||
```
|
||||
|
||||
```yaml
|
||||
# tool-config.template.yml
|
||||
api_endpoint: "https://api.example.com"
|
||||
timeout: 30
|
||||
```
|
||||
|
||||
````markdown
|
||||
<!-- commands/use-config.md -->
|
||||
# Use Config
|
||||
|
||||
Load config:
|
||||
```bash
|
||||
config_file=".specify/extensions/tool/tool-config.yml"
|
||||
endpoint=$(yq eval '.api_endpoint' "$config_file")
|
||||
echo "Using endpoint: $endpoint"
|
||||
```
|
||||
````
|
||||
|
||||
### Extension with Hooks
|
||||
|
||||
Extension that runs automatically:
|
||||
|
||||
```yaml
|
||||
# extension.yml
|
||||
hooks:
|
||||
after_tasks:
|
||||
command: "speckit.auto.analyze"
|
||||
optional: false # Always run
|
||||
description: "Analyze tasks after generation"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Extension won't install
|
||||
|
||||
**Error**: `Invalid extension ID`
|
||||
|
||||
- **Fix**: Use lowercase, alphanumeric + hyphens only
|
||||
|
||||
**Error**: `Extension requires spec-kit >=0.2.0`
|
||||
|
||||
- **Fix**: Update spec-kit with `uv tool install specify-cli --force`
|
||||
|
||||
**Error**: `Command file not found`
|
||||
|
||||
- **Fix**: Ensure command files exist at paths specified in manifest
|
||||
|
||||
### Commands not registered
|
||||
|
||||
**Symptom**: Commands don't appear in AI agent
|
||||
|
||||
**Check**:
|
||||
|
||||
1. `.claude/commands/` directory exists
|
||||
2. Extension installed successfully
|
||||
3. Commands registered in registry:
|
||||
|
||||
```bash
|
||||
cat .specify/extensions/.registry
|
||||
```
|
||||
|
||||
**Fix**: Reinstall extension to trigger registration
|
||||
|
||||
### Config not loading
|
||||
|
||||
**Check**:
|
||||
|
||||
1. Config file exists: `.specify/extensions/{ext-id}/{ext-id}-config.yml`
|
||||
2. YAML syntax is valid: `yq eval '.' config.yml`
|
||||
3. Environment variables set correctly
|
||||
|
||||
---
|
||||
|
||||
## Getting Help
|
||||
|
||||
- **Issues**: Report bugs at GitHub repository
|
||||
- **Discussions**: Ask questions in GitHub Discussions
|
||||
- **Examples**: See `spec-kit-jira` for full-featured example (Phase B)
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Create your extension** following this guide
|
||||
2. **Test locally** with `--dev` flag
|
||||
3. **Share with community** (GitHub, catalog)
|
||||
4. **Iterate** based on feedback
|
||||
|
||||
Happy extending! 🚀
|
||||
561
extensions/EXTENSION-PUBLISHING-GUIDE.md
Normal file
561
extensions/EXTENSION-PUBLISHING-GUIDE.md
Normal file
@@ -0,0 +1,561 @@
|
||||
# Extension Publishing Guide
|
||||
|
||||
This guide explains how to publish your extension to the Spec Kit extension catalog, making it discoverable by `specify extension search`.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Prerequisites](#prerequisites)
|
||||
2. [Prepare Your Extension](#prepare-your-extension)
|
||||
3. [Submit to Catalog](#submit-to-catalog)
|
||||
4. [Verification Process](#verification-process)
|
||||
5. [Release Workflow](#release-workflow)
|
||||
6. [Best Practices](#best-practices)
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before publishing an extension, ensure you have:
|
||||
|
||||
1. **Valid Extension**: A working extension with a valid `extension.yml` manifest
|
||||
2. **Git Repository**: Extension hosted on GitHub (or other public git hosting)
|
||||
3. **Documentation**: README.md with installation and usage instructions
|
||||
4. **License**: Open source license file (MIT, Apache 2.0, etc.)
|
||||
5. **Versioning**: Semantic versioning (e.g., 1.0.0)
|
||||
6. **Testing**: Extension tested on real projects
|
||||
|
||||
---
|
||||
|
||||
## Prepare Your Extension
|
||||
|
||||
### 1. Extension Structure
|
||||
|
||||
Ensure your extension follows the standard structure:
|
||||
|
||||
```text
|
||||
your-extension/
|
||||
├── extension.yml # Required: Extension manifest
|
||||
├── README.md # Required: Documentation
|
||||
├── LICENSE # Required: License file
|
||||
├── CHANGELOG.md # Recommended: Version history
|
||||
├── .gitignore # Recommended: Git ignore rules
|
||||
│
|
||||
├── commands/ # Extension commands
|
||||
│ ├── command1.md
|
||||
│ └── command2.md
|
||||
│
|
||||
├── config-template.yml # Config template (if needed)
|
||||
│
|
||||
└── docs/ # Additional documentation
|
||||
├── usage.md
|
||||
└── examples/
|
||||
```
|
||||
|
||||
### 2. extension.yml Validation
|
||||
|
||||
Verify your manifest is valid:
|
||||
|
||||
```yaml
|
||||
schema_version: "1.0"
|
||||
|
||||
extension:
|
||||
id: "your-extension" # Unique lowercase-hyphenated ID
|
||||
name: "Your Extension Name" # Human-readable name
|
||||
version: "1.0.0" # Semantic version
|
||||
description: "Brief description (one sentence)"
|
||||
author: "Your Name or Organization"
|
||||
repository: "https://github.com/your-org/spec-kit-your-extension"
|
||||
license: "MIT"
|
||||
homepage: "https://github.com/your-org/spec-kit-your-extension"
|
||||
|
||||
requires:
|
||||
speckit_version: ">=0.1.0" # Required spec-kit version
|
||||
|
||||
provides:
|
||||
commands: # List all commands
|
||||
- name: "speckit.your-extension.command"
|
||||
file: "commands/command.md"
|
||||
description: "Command description"
|
||||
|
||||
tags: # 2-5 relevant tags
|
||||
- "category"
|
||||
- "tool-name"
|
||||
```
|
||||
|
||||
**Validation Checklist**:
|
||||
|
||||
- ✅ `id` is lowercase with hyphens only (no underscores, spaces, or special characters)
|
||||
- ✅ `version` follows semantic versioning (X.Y.Z)
|
||||
- ✅ `description` is concise (under 100 characters)
|
||||
- ✅ `repository` URL is valid and public
|
||||
- ✅ All command files exist in the extension directory
|
||||
- ✅ Tags are lowercase and descriptive
|
||||
|
||||
### 3. Create GitHub Release
|
||||
|
||||
Create a GitHub release for your extension version:
|
||||
|
||||
```bash
|
||||
# Tag the release
|
||||
git tag v1.0.0
|
||||
git push origin v1.0.0
|
||||
|
||||
# Create release on GitHub
|
||||
# Go to: https://github.com/your-org/spec-kit-your-extension/releases/new
|
||||
# - Tag: v1.0.0
|
||||
# - Title: v1.0.0 - Release Name
|
||||
# - Description: Changelog/release notes
|
||||
```
|
||||
|
||||
The release archive URL will be:
|
||||
|
||||
```text
|
||||
https://github.com/your-org/spec-kit-your-extension/archive/refs/tags/v1.0.0.zip
|
||||
```
|
||||
|
||||
### 4. Test Installation
|
||||
|
||||
Test that users can install from your release:
|
||||
|
||||
```bash
|
||||
# Test dev installation
|
||||
specify extension add --dev /path/to/your-extension
|
||||
|
||||
# Test from GitHub archive
|
||||
specify extension add <extension-name> --from https://github.com/your-org/spec-kit-your-extension/archive/refs/tags/v1.0.0.zip
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Submit to Catalog
|
||||
|
||||
### Understanding the Catalogs
|
||||
|
||||
Spec Kit uses a dual-catalog system. For details about how catalogs work, see the main [Extensions README](README.md#extension-catalogs).
|
||||
|
||||
**For extension publishing**: All community extensions should be added to `catalog.community.json`. Users browse this catalog and copy extensions they trust into their own `catalog.json`.
|
||||
|
||||
### 1. Fork the spec-kit Repository
|
||||
|
||||
```bash
|
||||
# Fork on GitHub
|
||||
# https://github.com/github/spec-kit/fork
|
||||
|
||||
# Clone your fork
|
||||
git clone https://github.com/YOUR-USERNAME/spec-kit.git
|
||||
cd spec-kit
|
||||
```
|
||||
|
||||
### 2. Add Extension to Community Catalog
|
||||
|
||||
Edit `extensions/catalog.community.json` and add your extension:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"updated_at": "2026-01-28T15:54:00Z",
|
||||
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json",
|
||||
"extensions": {
|
||||
"your-extension": {
|
||||
"name": "Your Extension Name",
|
||||
"id": "your-extension",
|
||||
"description": "Brief description of your extension",
|
||||
"author": "Your Name",
|
||||
"version": "1.0.0",
|
||||
"download_url": "https://github.com/your-org/spec-kit-your-extension/archive/refs/tags/v1.0.0.zip",
|
||||
"repository": "https://github.com/your-org/spec-kit-your-extension",
|
||||
"homepage": "https://github.com/your-org/spec-kit-your-extension",
|
||||
"documentation": "https://github.com/your-org/spec-kit-your-extension/blob/main/docs/",
|
||||
"changelog": "https://github.com/your-org/spec-kit-your-extension/blob/main/CHANGELOG.md",
|
||||
"license": "MIT",
|
||||
"requires": {
|
||||
"speckit_version": ">=0.1.0",
|
||||
"tools": [
|
||||
{
|
||||
"name": "required-mcp-tool",
|
||||
"version": ">=1.0.0",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"provides": {
|
||||
"commands": 3,
|
||||
"hooks": 1
|
||||
},
|
||||
"tags": [
|
||||
"category",
|
||||
"tool-name",
|
||||
"feature"
|
||||
],
|
||||
"verified": false,
|
||||
"downloads": 0,
|
||||
"stars": 0,
|
||||
"created_at": "2026-01-28T00:00:00Z",
|
||||
"updated_at": "2026-01-28T00:00:00Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Important**:
|
||||
|
||||
- Set `verified: false` (maintainers will verify)
|
||||
- Set `downloads: 0` and `stars: 0` (auto-updated later)
|
||||
- Use current timestamp for `created_at` and `updated_at`
|
||||
- Update the top-level `updated_at` to current time
|
||||
|
||||
### 3. Update Community Extensions Table
|
||||
|
||||
Add your extension to the Community Extensions table in the project root `README.md`:
|
||||
|
||||
```markdown
|
||||
| Your Extension Name | Brief description of what it does | `<category>` | <effect> | [repo-name](https://github.com/your-org/spec-kit-your-extension) |
|
||||
```
|
||||
|
||||
**(Table) Category** — pick the one that best fits your extension:
|
||||
|
||||
- `docs` — reads, validates, or generates spec artifacts
|
||||
- `code` — reviews, validates, or modifies source code
|
||||
- `process` — orchestrates workflow across phases
|
||||
- `integration` — syncs with external platforms
|
||||
- `visibility` — reports on project health or progress
|
||||
|
||||
**Effect** — choose one:
|
||||
|
||||
- Read-only — produces reports without modifying files
|
||||
- Read+Write — modifies files, creates artifacts, or updates specs
|
||||
|
||||
Insert your extension in alphabetical order in the table.
|
||||
|
||||
### 4. Submit Pull Request
|
||||
|
||||
```bash
|
||||
# Create a branch
|
||||
git checkout -b add-your-extension
|
||||
|
||||
# Commit your changes
|
||||
git add extensions/catalog.community.json README.md
|
||||
git commit -m "Add your-extension to community catalog
|
||||
|
||||
- Extension ID: your-extension
|
||||
- Version: 1.0.0
|
||||
- Author: Your Name
|
||||
- Description: Brief description
|
||||
"
|
||||
|
||||
# Push to your fork
|
||||
git push origin add-your-extension
|
||||
|
||||
# Create Pull Request on GitHub
|
||||
# https://github.com/github/spec-kit/compare
|
||||
```
|
||||
|
||||
**Pull Request Template**:
|
||||
|
||||
```markdown
|
||||
## Extension Submission
|
||||
|
||||
**Extension Name**: Your Extension Name
|
||||
**Extension ID**: your-extension
|
||||
**Version**: 1.0.0
|
||||
**Author**: Your Name
|
||||
**Repository**: https://github.com/your-org/spec-kit-your-extension
|
||||
|
||||
### Description
|
||||
Brief description of what your extension does.
|
||||
|
||||
### Checklist
|
||||
- [x] Valid extension.yml manifest
|
||||
- [x] README.md with installation and usage docs
|
||||
- [x] LICENSE file included
|
||||
- [x] GitHub release created (v1.0.0)
|
||||
- [x] Extension tested on real project
|
||||
- [x] All commands working
|
||||
- [x] No security vulnerabilities
|
||||
- [x] Added to extensions/catalog.community.json
|
||||
- [x] Added to Community Extensions table in README.md
|
||||
|
||||
### Testing
|
||||
Tested on:
|
||||
- macOS 13.0+ with spec-kit 0.1.0
|
||||
- Project: [Your test project]
|
||||
|
||||
### Additional Notes
|
||||
Any additional context or notes for reviewers.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verification Process
|
||||
|
||||
### What Happens After Submission
|
||||
|
||||
1. **Automated Checks** (if available):
|
||||
- Manifest validation
|
||||
- Download URL accessibility
|
||||
- Repository existence
|
||||
- License file presence
|
||||
|
||||
2. **Manual Review**:
|
||||
- Code quality review
|
||||
- Security audit
|
||||
- Functionality testing
|
||||
- Documentation review
|
||||
|
||||
3. **Verification**:
|
||||
- If approved, `verified: true` is set
|
||||
- Extension appears in `specify extension search --verified`
|
||||
|
||||
### Verification Criteria
|
||||
|
||||
To be verified, your extension must:
|
||||
|
||||
✅ **Functionality**:
|
||||
|
||||
- Works as described in documentation
|
||||
- All commands execute without errors
|
||||
- No breaking changes to user workflows
|
||||
|
||||
✅ **Security**:
|
||||
|
||||
- No known vulnerabilities
|
||||
- No malicious code
|
||||
- Safe handling of user data
|
||||
- Proper validation of inputs
|
||||
|
||||
✅ **Code Quality**:
|
||||
|
||||
- Clean, readable code
|
||||
- Follows extension best practices
|
||||
- Proper error handling
|
||||
- Helpful error messages
|
||||
|
||||
✅ **Documentation**:
|
||||
|
||||
- Clear installation instructions
|
||||
- Usage examples
|
||||
- Troubleshooting section
|
||||
- Accurate description
|
||||
|
||||
✅ **Maintenance**:
|
||||
|
||||
- Active repository
|
||||
- Responsive to issues
|
||||
- Regular updates
|
||||
- Semantic versioning followed
|
||||
|
||||
### Typical Review Timeline
|
||||
|
||||
- **Automated checks**: Immediate (if implemented)
|
||||
- **Manual review**: 3-7 business days
|
||||
- **Verification**: After successful review
|
||||
|
||||
---
|
||||
|
||||
## Release Workflow
|
||||
|
||||
### Publishing New Versions
|
||||
|
||||
When releasing a new version:
|
||||
|
||||
1. **Update version** in `extension.yml`:
|
||||
|
||||
```yaml
|
||||
extension:
|
||||
version: "1.1.0" # Updated version
|
||||
```
|
||||
|
||||
2. **Update CHANGELOG.md**:
|
||||
|
||||
```markdown
|
||||
## [1.1.0] - 2026-02-15
|
||||
|
||||
### Added
|
||||
- New feature X
|
||||
|
||||
### Fixed
|
||||
- Bug fix Y
|
||||
```
|
||||
|
||||
3. **Create GitHub release**:
|
||||
|
||||
```bash
|
||||
git tag v1.1.0
|
||||
git push origin v1.1.0
|
||||
# Create release on GitHub
|
||||
```
|
||||
|
||||
4. **Update catalog**:
|
||||
|
||||
```bash
|
||||
# Fork spec-kit repo (or update existing fork)
|
||||
cd spec-kit
|
||||
|
||||
# Update extensions/catalog.json
|
||||
jq '.extensions["your-extension"].version = "1.1.0"' extensions/catalog.json > tmp.json && mv tmp.json extensions/catalog.json
|
||||
jq '.extensions["your-extension"].download_url = "https://github.com/your-org/spec-kit-your-extension/archive/refs/tags/v1.1.0.zip"' extensions/catalog.json > tmp.json && mv tmp.json extensions/catalog.json
|
||||
jq '.extensions["your-extension"].updated_at = "2026-02-15T00:00:00Z"' extensions/catalog.json > tmp.json && mv tmp.json extensions/catalog.json
|
||||
jq '.updated_at = "2026-02-15T00:00:00Z"' extensions/catalog.json > tmp.json && mv tmp.json extensions/catalog.json
|
||||
|
||||
# Submit PR
|
||||
git checkout -b update-your-extension-v1.1.0
|
||||
git add extensions/catalog.json
|
||||
git commit -m "Update your-extension to v1.1.0"
|
||||
git push origin update-your-extension-v1.1.0
|
||||
```
|
||||
|
||||
5. **Submit update PR** with changelog in description
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Extension Design
|
||||
|
||||
1. **Single Responsibility**: Each extension should focus on one tool/integration
|
||||
2. **Clear Naming**: Use descriptive, unambiguous names
|
||||
3. **Minimal Dependencies**: Avoid unnecessary dependencies
|
||||
4. **Backward Compatibility**: Follow semantic versioning strictly
|
||||
|
||||
### Documentation
|
||||
|
||||
1. **README.md Structure**:
|
||||
- Overview and features
|
||||
- Installation instructions
|
||||
- Configuration guide
|
||||
- Usage examples
|
||||
- Troubleshooting
|
||||
- Contributing guidelines
|
||||
|
||||
2. **Command Documentation**:
|
||||
- Clear description
|
||||
- Prerequisites listed
|
||||
- Step-by-step instructions
|
||||
- Error handling guidance
|
||||
- Examples
|
||||
|
||||
3. **Configuration**:
|
||||
- Provide template file
|
||||
- Document all options
|
||||
- Include examples
|
||||
- Explain defaults
|
||||
|
||||
### Security
|
||||
|
||||
1. **Input Validation**: Validate all user inputs
|
||||
2. **No Hardcoded Secrets**: Never include credentials
|
||||
3. **Safe Dependencies**: Only use trusted dependencies
|
||||
4. **Audit Regularly**: Check for vulnerabilities
|
||||
|
||||
### Maintenance
|
||||
|
||||
1. **Respond to Issues**: Address issues within 1-2 weeks
|
||||
2. **Regular Updates**: Keep dependencies updated
|
||||
3. **Changelog**: Maintain detailed changelog
|
||||
4. **Deprecation**: Give advance notice for breaking changes
|
||||
|
||||
### Community
|
||||
|
||||
1. **License**: Use permissive open-source license (MIT, Apache 2.0)
|
||||
2. **Contributing**: Welcome contributions
|
||||
3. **Code of Conduct**: Be respectful and inclusive
|
||||
4. **Support**: Provide ways to get help (issues, discussions, email)
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
### Q: Can I publish private/proprietary extensions?
|
||||
|
||||
A: The main catalog is for public extensions only. For private extensions:
|
||||
|
||||
- Host your own catalog.json file
|
||||
- Users add your catalog: `specify extension add-catalog https://your-domain.com/catalog.json`
|
||||
- Not yet implemented - coming in Phase 4
|
||||
|
||||
### Q: How long does verification take?
|
||||
|
||||
A: Typically 3-7 business days for initial review. Updates to verified extensions are usually faster.
|
||||
|
||||
### Q: What if my extension is rejected?
|
||||
|
||||
A: You'll receive feedback on what needs to be fixed. Make the changes and resubmit.
|
||||
|
||||
### Q: Can I update my extension anytime?
|
||||
|
||||
A: Yes, submit a PR to update the catalog with your new version. Verified status may be re-evaluated for major changes.
|
||||
|
||||
### Q: Do I need to be verified to be in the catalog?
|
||||
|
||||
A: No, unverified extensions are still searchable. Verification just adds trust and visibility.
|
||||
|
||||
### Q: Can extensions have paid features?
|
||||
|
||||
A: Extensions should be free and open-source. Commercial support/services are allowed, but core functionality must be free.
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
- **Catalog Issues**: <https://github.com/statsperform/spec-kit/issues>
|
||||
- **Extension Template**: <https://github.com/statsperform/spec-kit-extension-template> (coming soon)
|
||||
- **Development Guide**: See EXTENSION-DEVELOPMENT-GUIDE.md
|
||||
- **Community**: Discussions and Q&A
|
||||
|
||||
---
|
||||
|
||||
## Appendix: Catalog Schema
|
||||
|
||||
### Complete Catalog Entry Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string (required)",
|
||||
"id": "string (required, unique)",
|
||||
"description": "string (required, <200 chars)",
|
||||
"author": "string (required)",
|
||||
"version": "string (required, semver)",
|
||||
"download_url": "string (required, valid URL)",
|
||||
"repository": "string (required, valid URL)",
|
||||
"homepage": "string (optional, valid URL)",
|
||||
"documentation": "string (optional, valid URL)",
|
||||
"changelog": "string (optional, valid URL)",
|
||||
"license": "string (required)",
|
||||
"requires": {
|
||||
"speckit_version": "string (required, version specifier)",
|
||||
"tools": [
|
||||
{
|
||||
"name": "string (required)",
|
||||
"version": "string (optional, version specifier)",
|
||||
"required": "boolean (default: false)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"provides": {
|
||||
"commands": "integer (optional)",
|
||||
"hooks": "integer (optional)"
|
||||
},
|
||||
"tags": ["array of strings (2-10 tags)"],
|
||||
"verified": "boolean (default: false)",
|
||||
"downloads": "integer (auto-updated)",
|
||||
"stars": "integer (auto-updated)",
|
||||
"created_at": "string (ISO 8601 datetime)",
|
||||
"updated_at": "string (ISO 8601 datetime)"
|
||||
}
|
||||
```
|
||||
|
||||
### Valid Tags
|
||||
|
||||
Recommended tag categories:
|
||||
|
||||
- **Integration**: jira, linear, github, gitlab, azure-devops
|
||||
- **Category**: issue-tracking, vcs, ci-cd, documentation, testing
|
||||
- **Platform**: atlassian, microsoft, google
|
||||
- **Feature**: automation, reporting, deployment, monitoring
|
||||
|
||||
Use 2-5 tags that best describe your extension.
|
||||
|
||||
---
|
||||
|
||||
*Last Updated: 2026-01-28*
|
||||
*Catalog Format Version: 1.0*
|
||||
1025
extensions/EXTENSION-USER-GUIDE.md
Normal file
1025
extensions/EXTENSION-USER-GUIDE.md
Normal file
File diff suppressed because it is too large
Load Diff
125
extensions/README.md
Normal file
125
extensions/README.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Spec Kit Extensions
|
||||
|
||||
Extension system for [Spec Kit](https://github.com/github/spec-kit) - add new functionality without bloating the core framework.
|
||||
|
||||
## Extension Catalogs
|
||||
|
||||
Spec Kit provides two catalog files with different purposes:
|
||||
|
||||
### Your Catalog (`catalog.json`)
|
||||
|
||||
- **Purpose**: Default upstream catalog of extensions used by the Spec Kit CLI
|
||||
- **Default State**: Empty by design in the upstream project - you or your organization populate a fork/copy with extensions you trust
|
||||
- **Location (upstream)**: `extensions/catalog.json` in the GitHub-hosted spec-kit repo
|
||||
- **CLI Default**: The `specify extension` commands use the upstream catalog URL by default, unless overridden
|
||||
- **Org Catalog**: Point `SPECKIT_CATALOG_URL` at your organization's fork or hosted catalog JSON to use it instead of the upstream default
|
||||
- **Customization**: Copy entries from the community catalog into your org catalog, or add your own extensions directly
|
||||
|
||||
**Example override:**
|
||||
```bash
|
||||
# Override the default upstream catalog with your organization's catalog
|
||||
export SPECKIT_CATALOG_URL="https://your-org.com/spec-kit/catalog.json"
|
||||
specify extension search # Now uses your organization's catalog instead of the upstream default
|
||||
```
|
||||
|
||||
### Community Reference Catalog (`catalog.community.json`)
|
||||
|
||||
> [!NOTE]
|
||||
> Community extensions are independently created and maintained by their respective authors. GitHub and the Spec Kit maintainers may review pull requests that add entries to the community catalog for formatting, catalog structure, or policy compliance, but they do **not review, audit, endorse, or support the extension code itself**. Review extension source code before installation and use at your own discretion.
|
||||
|
||||
- **Purpose**: Browse available community-contributed extensions
|
||||
- **Status**: Active - contains extensions submitted by the community
|
||||
- **Location**: `extensions/catalog.community.json`
|
||||
- **Usage**: Reference catalog for discovering available extensions
|
||||
- **Submission**: Open to community contributions via Pull Request
|
||||
|
||||
**How It Works:**
|
||||
|
||||
## Making Extensions Available
|
||||
|
||||
You control which extensions your team can discover and install:
|
||||
|
||||
### Option 1: Curated Catalog (Recommended for Organizations)
|
||||
|
||||
Populate your `catalog.json` with approved extensions:
|
||||
|
||||
1. **Discover** extensions from various sources:
|
||||
- Browse `catalog.community.json` for community extensions
|
||||
- Find private/internal extensions in your organization's repos
|
||||
- Discover extensions from trusted third parties
|
||||
2. **Review** extensions and choose which ones you want to make available
|
||||
3. **Add** those extension entries to your own `catalog.json`
|
||||
4. **Team members** can now discover and install them:
|
||||
- `specify extension search` shows your curated catalog
|
||||
- `specify extension add <name>` installs from your catalog
|
||||
|
||||
**Benefits**: Full control over available extensions, team consistency, organizational approval workflow
|
||||
|
||||
**Example**: Copy an entry from `catalog.community.json` to your `catalog.json`, then your team can discover and install it by name.
|
||||
|
||||
### Option 2: Direct URLs (For Ad-hoc Use)
|
||||
|
||||
Skip catalog curation - team members install directly using URLs:
|
||||
|
||||
```bash
|
||||
specify extension add <extension-name> --from https://github.com/org/spec-kit-ext/archive/refs/tags/v1.0.0.zip
|
||||
```
|
||||
|
||||
**Benefits**: Quick for one-off testing or private extensions
|
||||
|
||||
**Tradeoff**: Extensions installed this way won't appear in `specify extension search` for other team members unless you also add them to your `catalog.json`.
|
||||
|
||||
## Available Community Extensions
|
||||
|
||||
> [!NOTE]
|
||||
> Community extensions are independently created and maintained by their respective authors. GitHub and the Spec Kit maintainers may review pull requests that add entries to the community catalog for formatting, catalog structure, or policy compliance, but they do **not review, audit, endorse, or support the extension code itself**. The Community Extensions website is also a third-party resource. Review extension source code before installation and use at your own discretion.
|
||||
|
||||
🔍 **Browse and search community extensions on the [Community Extensions website](https://speckit-community.github.io/extensions/).**
|
||||
|
||||
See the [Community Extensions](../README.md#-community-extensions) section in the main README for the full list of available community-contributed extensions.
|
||||
|
||||
For the raw catalog data, see [`catalog.community.json`](catalog.community.json).
|
||||
|
||||
|
||||
## Adding Your Extension
|
||||
|
||||
### Submission Process
|
||||
|
||||
To add your extension to the community catalog:
|
||||
|
||||
1. **Prepare your extension** following the [Extension Development Guide](EXTENSION-DEVELOPMENT-GUIDE.md)
|
||||
2. **Create a GitHub release** for your extension
|
||||
3. **Submit a Pull Request** that:
|
||||
- Adds your extension to `extensions/catalog.community.json`
|
||||
- Updates this README with your extension in the Available Extensions table
|
||||
4. **Wait for review** - maintainers will review and merge if criteria are met
|
||||
|
||||
See the [Extension Publishing Guide](EXTENSION-PUBLISHING-GUIDE.md) for detailed step-by-step instructions.
|
||||
|
||||
### Submission Checklist
|
||||
|
||||
Before submitting, ensure:
|
||||
|
||||
- ✅ Valid `extension.yml` manifest
|
||||
- ✅ Complete README with installation and usage instructions
|
||||
- ✅ LICENSE file included
|
||||
- ✅ GitHub release created with semantic version (e.g., v1.0.0)
|
||||
- ✅ Extension tested on a real project
|
||||
- ✅ All commands working as documented
|
||||
|
||||
## Installing Extensions
|
||||
Once extensions are available (either in your catalog or via direct URL), install them:
|
||||
|
||||
```bash
|
||||
# From your curated catalog (by name)
|
||||
specify extension search # See what's in your catalog
|
||||
specify extension add <extension-name> # Install by name
|
||||
|
||||
# Direct from URL (bypasses catalog)
|
||||
specify extension add <extension-name> --from https://github.com/<org>/<repo>/archive/refs/tags/<version>.zip
|
||||
|
||||
# List installed extensions
|
||||
specify extension list
|
||||
```
|
||||
|
||||
For more information, see the [Extension User Guide](EXTENSION-USER-GUIDE.md).
|
||||
1962
extensions/RFC-EXTENSION-SYSTEM.md
Normal file
1962
extensions/RFC-EXTENSION-SYSTEM.md
Normal file
File diff suppressed because it is too large
Load Diff
2649
extensions/catalog.community.json
Normal file
2649
extensions/catalog.community.json
Normal file
File diff suppressed because it is too large
Load Diff
22
extensions/catalog.json
Normal file
22
extensions/catalog.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"updated_at": "2026-04-10T00:00:00Z",
|
||||
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.json",
|
||||
"extensions": {
|
||||
"git": {
|
||||
"name": "Git Branching Workflow",
|
||||
"id": "git",
|
||||
"version": "1.0.0",
|
||||
"description": "Feature branch creation, numbering (sequential/timestamp), validation, and Git remote detection",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"bundled": true,
|
||||
"tags": [
|
||||
"git",
|
||||
"branching",
|
||||
"workflow",
|
||||
"core"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
100
extensions/git/README.md
Normal file
100
extensions/git/README.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Git Branching Workflow Extension
|
||||
|
||||
Git repository initialization, feature branch creation, numbering (sequential/timestamp), validation, remote detection, and auto-commit for Spec Kit.
|
||||
|
||||
## Overview
|
||||
|
||||
This extension provides Git operations as an optional, self-contained module. It manages:
|
||||
|
||||
- **Repository initialization** with configurable commit messages
|
||||
- **Feature branch creation** with sequential (`001-feature-name`) or timestamp (`20260319-143022-feature-name`) numbering
|
||||
- **Branch validation** to ensure branches follow naming conventions
|
||||
- **Git remote detection** for GitHub integration (e.g., issue creation)
|
||||
- **Auto-commit** after core commands (configurable per-command with custom messages)
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `speckit.git.initialize` | Initialize a Git repository with a configurable commit message |
|
||||
| `speckit.git.feature` | Create a feature branch with sequential or timestamp numbering |
|
||||
| `speckit.git.validate` | Validate current branch follows feature branch naming conventions |
|
||||
| `speckit.git.remote` | Detect Git remote URL for GitHub integration |
|
||||
| `speckit.git.commit` | Auto-commit changes (configurable per-command enable/disable and messages) |
|
||||
|
||||
## Hooks
|
||||
|
||||
| Event | Command | Optional | Description |
|
||||
|-------|---------|----------|-------------|
|
||||
| `before_constitution` | `speckit.git.initialize` | No | Init git repo before constitution |
|
||||
| `before_specify` | `speckit.git.feature` | No | Create feature branch before specification |
|
||||
| `before_clarify` | `speckit.git.commit` | Yes | Commit outstanding changes before clarification |
|
||||
| `before_plan` | `speckit.git.commit` | Yes | Commit outstanding changes before planning |
|
||||
| `before_tasks` | `speckit.git.commit` | Yes | Commit outstanding changes before task generation |
|
||||
| `before_implement` | `speckit.git.commit` | Yes | Commit outstanding changes before implementation |
|
||||
| `before_checklist` | `speckit.git.commit` | Yes | Commit outstanding changes before checklist |
|
||||
| `before_analyze` | `speckit.git.commit` | Yes | Commit outstanding changes before analysis |
|
||||
| `before_taskstoissues` | `speckit.git.commit` | Yes | Commit outstanding changes before issue sync |
|
||||
| `after_constitution` | `speckit.git.commit` | Yes | Auto-commit after constitution update |
|
||||
| `after_specify` | `speckit.git.commit` | Yes | Auto-commit after specification |
|
||||
| `after_clarify` | `speckit.git.commit` | Yes | Auto-commit after clarification |
|
||||
| `after_plan` | `speckit.git.commit` | Yes | Auto-commit after planning |
|
||||
| `after_tasks` | `speckit.git.commit` | Yes | Auto-commit after task generation |
|
||||
| `after_implement` | `speckit.git.commit` | Yes | Auto-commit after implementation |
|
||||
| `after_checklist` | `speckit.git.commit` | Yes | Auto-commit after checklist |
|
||||
| `after_analyze` | `speckit.git.commit` | Yes | Auto-commit after analysis |
|
||||
| `after_taskstoissues` | `speckit.git.commit` | Yes | Auto-commit after issue sync |
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration is stored in `.specify/extensions/git/git-config.yml`:
|
||||
|
||||
```yaml
|
||||
# Branch numbering strategy: "sequential" or "timestamp"
|
||||
branch_numbering: sequential
|
||||
|
||||
# Custom commit message for git init
|
||||
init_commit_message: "[Spec Kit] Initial commit"
|
||||
|
||||
# Auto-commit per command (all disabled by default)
|
||||
# Example: enable auto-commit after specify
|
||||
auto_commit:
|
||||
default: false
|
||||
after_specify:
|
||||
enabled: true
|
||||
message: "[Spec Kit] Add specification"
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Install the bundled git extension (no network required)
|
||||
specify extension add git
|
||||
```
|
||||
|
||||
## Disabling
|
||||
|
||||
```bash
|
||||
# Disable the git extension (spec creation continues without branching)
|
||||
specify extension disable git
|
||||
|
||||
# Re-enable it
|
||||
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
|
||||
- Remote detection returns empty results
|
||||
|
||||
## Scripts
|
||||
|
||||
The extension bundles cross-platform scripts:
|
||||
|
||||
- `scripts/bash/create-new-feature.sh` — Bash implementation
|
||||
- `scripts/bash/git-common.sh` — Shared Git utilities (Bash)
|
||||
- `scripts/powershell/create-new-feature.ps1` — PowerShell implementation
|
||||
- `scripts/powershell/git-common.ps1` — Shared Git utilities (PowerShell)
|
||||
48
extensions/git/commands/speckit.git.commit.md
Normal file
48
extensions/git/commands/speckit.git.commit.md
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
description: "Auto-commit changes after a Spec Kit command completes"
|
||||
---
|
||||
|
||||
# Auto-Commit Changes
|
||||
|
||||
Automatically stage and commit all changes after a Spec Kit command completes.
|
||||
|
||||
## Behavior
|
||||
|
||||
This command is invoked as a hook after (or before) core commands. It:
|
||||
|
||||
1. Determines the event name from the hook context (e.g., if invoked as an `after_specify` hook, the event is `after_specify`; if `before_plan`, the event is `before_plan`)
|
||||
2. Checks `.specify/extensions/git/git-config.yml` for the `auto_commit` section
|
||||
3. Looks up the specific event key to see if auto-commit is enabled
|
||||
4. Falls back to `auto_commit.default` if no event-specific key exists
|
||||
5. Uses the per-command `message` if configured, otherwise a default message
|
||||
6. If enabled and there are uncommitted changes, runs `git add .` + `git commit`
|
||||
|
||||
## Execution
|
||||
|
||||
Determine the event name from the hook that triggered this command, then run the script:
|
||||
|
||||
- **Bash**: `.specify/extensions/git/scripts/bash/auto-commit.sh <event_name>`
|
||||
- **PowerShell**: `.specify/extensions/git/scripts/powershell/auto-commit.ps1 <event_name>`
|
||||
|
||||
Replace `<event_name>` with the actual hook event (e.g., `after_specify`, `before_plan`, `after_implement`).
|
||||
|
||||
## Configuration
|
||||
|
||||
In `.specify/extensions/git/git-config.yml`:
|
||||
|
||||
```yaml
|
||||
auto_commit:
|
||||
default: false # Global toggle — set true to enable for all commands
|
||||
after_specify:
|
||||
enabled: true # Override per-command
|
||||
message: "[Spec Kit] Add specification"
|
||||
after_plan:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add implementation plan"
|
||||
```
|
||||
|
||||
## Graceful Degradation
|
||||
|
||||
- If Git is not available or the current directory is not a repository: skips with a warning
|
||||
- If no config file exists: skips (disabled by default)
|
||||
- If no changes to commit: skips with a message
|
||||
67
extensions/git/commands/speckit.git.feature.md
Normal file
67
extensions/git/commands/speckit.git.feature.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
description: "Create a feature branch with sequential or timestamp numbering"
|
||||
---
|
||||
|
||||
# Create Feature Branch
|
||||
|
||||
Create and switch to a new git feature branch for the given specification. This command handles **branch creation only** — the spec directory and files are created by the core `/speckit.specify` workflow.
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Verify Git is available by running `git rev-parse --is-inside-work-tree 2>/dev/null`
|
||||
- If Git is not available, warn the user and skip branch creation
|
||||
|
||||
## Branch Numbering Mode
|
||||
|
||||
Determine the branch numbering strategy by checking configuration in this order:
|
||||
|
||||
1. Check `.specify/extensions/git/git-config.yml` for `branch_numbering` value
|
||||
2. Check `.specify/init-options.json` for `branch_numbering` value (backward compatibility)
|
||||
3. Default to `sequential` if neither exists
|
||||
|
||||
## 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.)
|
||||
|
||||
Run the appropriate script based on your platform:
|
||||
|
||||
- **Bash**: `.specify/extensions/git/scripts/bash/create-new-feature.sh --json --short-name "<short-name>" "<feature description>"`
|
||||
- **Bash (timestamp)**: `.specify/extensions/git/scripts/bash/create-new-feature.sh --json --timestamp --short-name "<short-name>" "<feature description>"`
|
||||
- **PowerShell**: `.specify/extensions/git/scripts/powershell/create-new-feature.ps1 -Json -ShortName "<short-name>" "<feature description>"`
|
||||
- **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
|
||||
- The JSON output will contain `BRANCH_NAME` and `FEATURE_NUM`
|
||||
|
||||
## 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
|
||||
49
extensions/git/commands/speckit.git.initialize.md
Normal file
49
extensions/git/commands/speckit.git.initialize.md
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
description: "Initialize a Git repository with an initial commit"
|
||||
---
|
||||
|
||||
# Initialize Git Repository
|
||||
|
||||
Initialize a Git repository in the current project directory if one does not already exist.
|
||||
|
||||
## Execution
|
||||
|
||||
Run the appropriate script from the project root:
|
||||
|
||||
- **Bash**: `.specify/extensions/git/scripts/bash/initialize-repo.sh`
|
||||
- **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
|
||||
- Git hooks installation
|
||||
- Commit signing configuration
|
||||
- Git Flow initialization
|
||||
|
||||
## 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
|
||||
45
extensions/git/commands/speckit.git.remote.md
Normal file
45
extensions/git/commands/speckit.git.remote.md
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
description: "Detect Git remote URL for GitHub integration"
|
||||
---
|
||||
|
||||
# Detect Git Remote URL
|
||||
|
||||
Detect the Git remote URL for integration with GitHub services (e.g., issue creation).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- 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:
|
||||
```
|
||||
[specify] Warning: Git repository not detected; cannot determine remote URL
|
||||
```
|
||||
|
||||
## Execution
|
||||
|
||||
Run the following command to get the remote URL:
|
||||
|
||||
```bash
|
||||
git config --get remote.origin.url
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
Parse the remote URL and determine:
|
||||
|
||||
1. **Repository owner**: Extract from the URL (e.g., `github` from `https://github.com/github/spec-kit.git`)
|
||||
2. **Repository name**: Extract from the URL (e.g., `spec-kit` from `https://github.com/github/spec-kit.git`)
|
||||
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`
|
||||
|
||||
> [!CAUTION]
|
||||
> ONLY report a GitHub repository if the remote URL actually points to github.com.
|
||||
> Do NOT assume the remote is GitHub if the URL format doesn't match.
|
||||
|
||||
## 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
|
||||
49
extensions/git/commands/speckit.git.validate.md
Normal file
49
extensions/git/commands/speckit.git.validate.md
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
description: "Validate current branch follows feature branch naming conventions"
|
||||
---
|
||||
|
||||
# Validate Feature Branch
|
||||
|
||||
Validate that the current Git branch follows the expected feature branch naming conventions.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- 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:
|
||||
```
|
||||
[specify] Warning: Git repository not detected; skipped branch validation
|
||||
```
|
||||
|
||||
## Validation Rules
|
||||
|
||||
Get the current branch name:
|
||||
|
||||
```bash
|
||||
git rev-parse --abbrev-ref HEAD
|
||||
```
|
||||
|
||||
The branch name must match one of these patterns:
|
||||
|
||||
1. **Sequential**: `^[0-9]{3,}-` (e.g., `001-feature-name`, `042-fix-bug`, `1000-big-feature`)
|
||||
2. **Timestamp**: `^[0-9]{8}-[0-9]{6}-` (e.g., `20260319-143022-feature-name`)
|
||||
|
||||
## 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
|
||||
- For timestamp branches, look for `specs/<prefix>-*` where prefix matches the `YYYYMMDD-HHMMSS` portion
|
||||
- If spec directory exists: `✓ Spec directory found: <path>`
|
||||
- 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
|
||||
62
extensions/git/config-template.yml
Normal file
62
extensions/git/config-template.yml
Normal file
@@ -0,0 +1,62 @@
|
||||
# Git Branching Workflow Extension Configuration
|
||||
# Copied to .specify/extensions/git/git-config.yml on install
|
||||
|
||||
# Branch numbering strategy: "sequential" (001, 002, ...) or "timestamp" (YYYYMMDD-HHMMSS)
|
||||
branch_numbering: sequential
|
||||
|
||||
# Commit message used by `git commit` during repository initialization
|
||||
init_commit_message: "[Spec Kit] Initial commit"
|
||||
|
||||
# Auto-commit before/after core commands.
|
||||
# Set "default" to enable for all commands, then override per-command.
|
||||
# Each key can be true/false. Message is customizable per-command.
|
||||
auto_commit:
|
||||
default: false
|
||||
before_clarify:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before clarification"
|
||||
before_plan:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before planning"
|
||||
before_tasks:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before task generation"
|
||||
before_implement:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before implementation"
|
||||
before_checklist:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before checklist"
|
||||
before_analyze:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before analysis"
|
||||
before_taskstoissues:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before issue sync"
|
||||
after_constitution:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add project constitution"
|
||||
after_specify:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add specification"
|
||||
after_clarify:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Clarify specification"
|
||||
after_plan:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add implementation plan"
|
||||
after_tasks:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add tasks"
|
||||
after_implement:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Implementation progress"
|
||||
after_checklist:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add checklist"
|
||||
after_analyze:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add analysis report"
|
||||
after_taskstoissues:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Sync tasks to issues"
|
||||
140
extensions/git/extension.yml
Normal file
140
extensions/git/extension.yml
Normal file
@@ -0,0 +1,140 @@
|
||||
schema_version: "1.0"
|
||||
|
||||
extension:
|
||||
id: git
|
||||
name: "Git Branching Workflow"
|
||||
version: "1.0.0"
|
||||
description: "Feature branch creation, numbering (sequential/timestamp), validation, and Git remote detection"
|
||||
author: spec-kit-core
|
||||
repository: https://github.com/github/spec-kit
|
||||
license: MIT
|
||||
|
||||
requires:
|
||||
speckit_version: ">=0.2.0"
|
||||
tools:
|
||||
- name: git
|
||||
required: false
|
||||
|
||||
provides:
|
||||
commands:
|
||||
- name: speckit.git.feature
|
||||
file: commands/speckit.git.feature.md
|
||||
description: "Create a feature branch with sequential or timestamp numbering"
|
||||
- name: speckit.git.validate
|
||||
file: commands/speckit.git.validate.md
|
||||
description: "Validate current branch follows feature branch naming conventions"
|
||||
- name: speckit.git.remote
|
||||
file: commands/speckit.git.remote.md
|
||||
description: "Detect Git remote URL for GitHub integration"
|
||||
- name: speckit.git.initialize
|
||||
file: commands/speckit.git.initialize.md
|
||||
description: "Initialize a Git repository with an initial commit"
|
||||
- name: speckit.git.commit
|
||||
file: commands/speckit.git.commit.md
|
||||
description: "Auto-commit changes after a Spec Kit command completes"
|
||||
|
||||
config:
|
||||
- name: "git-config.yml"
|
||||
template: "config-template.yml"
|
||||
description: "Git branching configuration"
|
||||
required: false
|
||||
|
||||
hooks:
|
||||
before_constitution:
|
||||
command: speckit.git.initialize
|
||||
optional: false
|
||||
description: "Initialize Git repository before constitution setup"
|
||||
before_specify:
|
||||
command: speckit.git.feature
|
||||
optional: false
|
||||
description: "Create feature branch before specification"
|
||||
before_clarify:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit outstanding changes before clarification?"
|
||||
description: "Auto-commit before spec clarification"
|
||||
before_plan:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit outstanding changes before planning?"
|
||||
description: "Auto-commit before implementation planning"
|
||||
before_tasks:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit outstanding changes before task generation?"
|
||||
description: "Auto-commit before task generation"
|
||||
before_implement:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit outstanding changes before implementation?"
|
||||
description: "Auto-commit before implementation"
|
||||
before_checklist:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit outstanding changes before checklist?"
|
||||
description: "Auto-commit before checklist generation"
|
||||
before_analyze:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit outstanding changes before analysis?"
|
||||
description: "Auto-commit before analysis"
|
||||
before_taskstoissues:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit outstanding changes before issue sync?"
|
||||
description: "Auto-commit before tasks-to-issues conversion"
|
||||
after_constitution:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit constitution changes?"
|
||||
description: "Auto-commit after constitution update"
|
||||
after_specify:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit specification changes?"
|
||||
description: "Auto-commit after specification"
|
||||
after_clarify:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit clarification changes?"
|
||||
description: "Auto-commit after spec clarification"
|
||||
after_plan:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit plan changes?"
|
||||
description: "Auto-commit after implementation planning"
|
||||
after_tasks:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit task changes?"
|
||||
description: "Auto-commit after task generation"
|
||||
after_implement:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit implementation changes?"
|
||||
description: "Auto-commit after implementation"
|
||||
after_checklist:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit checklist changes?"
|
||||
description: "Auto-commit after checklist generation"
|
||||
after_analyze:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit analysis results?"
|
||||
description: "Auto-commit after analysis"
|
||||
after_taskstoissues:
|
||||
command: speckit.git.commit
|
||||
optional: true
|
||||
prompt: "Commit after syncing issues?"
|
||||
description: "Auto-commit after tasks-to-issues conversion"
|
||||
|
||||
tags:
|
||||
- "git"
|
||||
- "branching"
|
||||
- "workflow"
|
||||
|
||||
config:
|
||||
defaults:
|
||||
branch_numbering: sequential
|
||||
init_commit_message: "[Spec Kit] Initial commit"
|
||||
62
extensions/git/git-config.yml
Normal file
62
extensions/git/git-config.yml
Normal file
@@ -0,0 +1,62 @@
|
||||
# Git Branching Workflow Extension Configuration
|
||||
# Copied to .specify/extensions/git/git-config.yml on install
|
||||
|
||||
# Branch numbering strategy: "sequential" (001, 002, ...) or "timestamp" (YYYYMMDD-HHMMSS)
|
||||
branch_numbering: sequential
|
||||
|
||||
# Commit message used by `git commit` during repository initialization
|
||||
init_commit_message: "[Spec Kit] Initial commit"
|
||||
|
||||
# Auto-commit before/after core commands.
|
||||
# Set "default" to enable for all commands, then override per-command.
|
||||
# Each key can be true/false. Message is customizable per-command.
|
||||
auto_commit:
|
||||
default: false
|
||||
before_clarify:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before clarification"
|
||||
before_plan:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before planning"
|
||||
before_tasks:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before task generation"
|
||||
before_implement:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before implementation"
|
||||
before_checklist:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before checklist"
|
||||
before_analyze:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before analysis"
|
||||
before_taskstoissues:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Save progress before issue sync"
|
||||
after_constitution:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add project constitution"
|
||||
after_specify:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add specification"
|
||||
after_clarify:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Clarify specification"
|
||||
after_plan:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add implementation plan"
|
||||
after_tasks:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add tasks"
|
||||
after_implement:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Implementation progress"
|
||||
after_checklist:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add checklist"
|
||||
after_analyze:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Add analysis report"
|
||||
after_taskstoissues:
|
||||
enabled: false
|
||||
message: "[Spec Kit] Sync tasks to issues"
|
||||
140
extensions/git/scripts/bash/auto-commit.sh
Executable file
140
extensions/git/scripts/bash/auto-commit.sh
Executable file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env bash
|
||||
# Git extension: auto-commit.sh
|
||||
# Automatically commit changes after a Spec Kit command completes.
|
||||
# Checks per-command config keys in git-config.yml before committing.
|
||||
#
|
||||
# Usage: auto-commit.sh <event_name>
|
||||
# e.g.: auto-commit.sh after_specify
|
||||
|
||||
set -e
|
||||
|
||||
EVENT_NAME="${1:-}"
|
||||
if [ -z "$EVENT_NAME" ]; then
|
||||
echo "Usage: $0 <event_name>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
_find_project_root() {
|
||||
local dir="$1"
|
||||
while [ "$dir" != "/" ]; do
|
||||
if [ -d "$dir/.specify" ] || [ -d "$dir/.git" ]; then
|
||||
echo "$dir"
|
||||
return 0
|
||||
fi
|
||||
dir="$(dirname "$dir")"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
REPO_ROOT=$(_find_project_root "$SCRIPT_DIR") || REPO_ROOT="$(pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Check if git is available
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
echo "[specify] Warning: Git not found; skipped auto-commit" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo "[specify] Warning: Not a Git repository; skipped auto-commit" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Read per-command config from git-config.yml
|
||||
_config_file="$REPO_ROOT/.specify/extensions/git/git-config.yml"
|
||||
_enabled=false
|
||||
_commit_msg=""
|
||||
|
||||
if [ -f "$_config_file" ]; then
|
||||
# Parse the auto_commit section for this event.
|
||||
# Look for auto_commit.<event_name>.enabled and .message
|
||||
# Also check auto_commit.default as fallback.
|
||||
_in_auto_commit=false
|
||||
_in_event=false
|
||||
_default_enabled=false
|
||||
|
||||
while IFS= read -r _line; do
|
||||
# Detect auto_commit: section
|
||||
if echo "$_line" | grep -q '^auto_commit:'; then
|
||||
_in_auto_commit=true
|
||||
_in_event=false
|
||||
continue
|
||||
fi
|
||||
|
||||
# Exit auto_commit section on next top-level key
|
||||
if $_in_auto_commit && echo "$_line" | grep -Eq '^[a-z]'; then
|
||||
break
|
||||
fi
|
||||
|
||||
if $_in_auto_commit; then
|
||||
# Check default key
|
||||
if echo "$_line" | grep -Eq "^[[:space:]]+default:[[:space:]]"; then
|
||||
_val=$(echo "$_line" | sed 's/^[^:]*:[[:space:]]*//' | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
|
||||
[ "$_val" = "true" ] && _default_enabled=true
|
||||
fi
|
||||
|
||||
# Detect our event subsection
|
||||
if echo "$_line" | grep -Eq "^[[:space:]]+${EVENT_NAME}:"; then
|
||||
_in_event=true
|
||||
continue
|
||||
fi
|
||||
|
||||
# Inside our event subsection
|
||||
if $_in_event; then
|
||||
# Exit on next sibling key (same indent level as event name)
|
||||
if echo "$_line" | grep -Eq '^[[:space:]]{2}[a-z]' && ! echo "$_line" | grep -Eq '^[[:space:]]{4}'; then
|
||||
_in_event=false
|
||||
continue
|
||||
fi
|
||||
if echo "$_line" | grep -Eq '[[:space:]]+enabled:'; then
|
||||
_val=$(echo "$_line" | sed 's/^[^:]*:[[:space:]]*//' | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
|
||||
[ "$_val" = "true" ] && _enabled=true
|
||||
[ "$_val" = "false" ] && _enabled=false
|
||||
fi
|
||||
if echo "$_line" | grep -Eq '[[:space:]]+message:'; then
|
||||
_commit_msg=$(echo "$_line" | sed 's/^[^:]*:[[:space:]]*//' | sed 's/^["'\'']//' | sed 's/["'\'']*$//')
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done < "$_config_file"
|
||||
|
||||
# If event-specific key not found, use default
|
||||
if [ "$_enabled" = "false" ] && [ "$_default_enabled" = "true" ]; then
|
||||
# Only use default if the event wasn't explicitly set to false
|
||||
# Check if event section existed at all
|
||||
if ! grep -q "^[[:space:]]*${EVENT_NAME}:" "$_config_file" 2>/dev/null; then
|
||||
_enabled=true
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# No config file — auto-commit disabled by default
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$_enabled" != "true" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if there are changes to commit
|
||||
if git diff --quiet HEAD 2>/dev/null && git diff --cached --quiet 2>/dev/null && [ -z "$(git ls-files --others --exclude-standard 2>/dev/null)" ]; then
|
||||
echo "[specify] No changes to commit after $EVENT_NAME" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Derive a human-readable command name from the event
|
||||
# e.g., after_specify -> specify, before_plan -> plan
|
||||
_command_name=$(echo "$EVENT_NAME" | sed 's/^after_//' | sed 's/^before_//')
|
||||
_phase=$(echo "$EVENT_NAME" | grep -q '^before_' && echo 'before' || echo 'after')
|
||||
|
||||
# Use custom message if configured, otherwise default
|
||||
if [ -z "$_commit_msg" ]; then
|
||||
_commit_msg="[Spec Kit] Auto-commit ${_phase} ${_command_name}"
|
||||
fi
|
||||
|
||||
# Stage and commit
|
||||
_git_out=$(git add . 2>&1) || { echo "[specify] Error: git add failed: $_git_out" >&2; exit 1; }
|
||||
_git_out=$(git commit -q -m "$_commit_msg" 2>&1) || { echo "[specify] Error: git commit failed: $_git_out" >&2; exit 1; }
|
||||
|
||||
echo "[OK] Changes committed ${_phase} ${_command_name}" >&2
|
||||
453
extensions/git/scripts/bash/create-new-feature.sh
Executable file
453
extensions/git/scripts/bash/create-new-feature.sh
Executable file
@@ -0,0 +1,453 @@
|
||||
#!/usr/bin/env bash
|
||||
# Git extension: create-new-feature.sh
|
||||
# Adapted from core scripts/bash/create-new-feature.sh for extension layout.
|
||||
# Sources common.sh from the project's installed scripts, falling back to
|
||||
# git-common.sh for minimal git helpers.
|
||||
|
||||
set -e
|
||||
|
||||
JSON_MODE=false
|
||||
DRY_RUN=false
|
||||
ALLOW_EXISTING=false
|
||||
SHORT_NAME=""
|
||||
BRANCH_NUMBER=""
|
||||
USE_TIMESTAMP=false
|
||||
ARGS=()
|
||||
i=1
|
||||
while [ $i -le $# ]; do
|
||||
arg="${!i}"
|
||||
case "$arg" in
|
||||
--json)
|
||||
JSON_MODE=true
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
;;
|
||||
--allow-existing-branch)
|
||||
ALLOW_EXISTING=true
|
||||
;;
|
||||
--short-name)
|
||||
if [ $((i + 1)) -gt $# ]; then
|
||||
echo 'Error: --short-name requires a value' >&2
|
||||
exit 1
|
||||
fi
|
||||
i=$((i + 1))
|
||||
next_arg="${!i}"
|
||||
if [[ "$next_arg" == --* ]]; then
|
||||
echo 'Error: --short-name requires a value' >&2
|
||||
exit 1
|
||||
fi
|
||||
SHORT_NAME="$next_arg"
|
||||
;;
|
||||
--number)
|
||||
if [ $((i + 1)) -gt $# ]; then
|
||||
echo 'Error: --number requires a value' >&2
|
||||
exit 1
|
||||
fi
|
||||
i=$((i + 1))
|
||||
next_arg="${!i}"
|
||||
if [[ "$next_arg" == --* ]]; then
|
||||
echo 'Error: --number requires a value' >&2
|
||||
exit 1
|
||||
fi
|
||||
BRANCH_NUMBER="$next_arg"
|
||||
if [[ ! "$BRANCH_NUMBER" =~ ^[0-9]+$ ]]; then
|
||||
echo 'Error: --number must be a non-negative integer' >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--timestamp)
|
||||
USE_TIMESTAMP=true
|
||||
;;
|
||||
--help|-h)
|
||||
echo "Usage: $0 [--json] [--dry-run] [--allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --json Output in JSON format"
|
||||
echo " --dry-run Compute branch name without creating the branch"
|
||||
echo " --allow-existing-branch Switch to branch if it already exists instead of failing"
|
||||
echo " --short-name <name> Provide a custom short name (2-4 words) for the branch"
|
||||
echo " --number N Specify branch number manually (overrides auto-detection)"
|
||||
echo " --timestamp Use timestamp prefix (YYYYMMDD-HHMMSS) instead of sequential numbering"
|
||||
echo " --help, -h Show this help message"
|
||||
echo ""
|
||||
echo "Environment variables:"
|
||||
echo " GIT_BRANCH_NAME Use this exact branch name, bypassing all prefix/suffix generation"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 'Add user authentication system' --short-name 'user-auth'"
|
||||
echo " $0 'Implement OAuth2 integration for API' --number 5"
|
||||
echo " $0 --timestamp --short-name 'user-auth' 'Add user authentication'"
|
||||
echo " GIT_BRANCH_NAME=my-branch $0 'feature description'"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
ARGS+=("$arg")
|
||||
;;
|
||||
esac
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
FEATURE_DESCRIPTION="${ARGS[*]}"
|
||||
if [ -z "$FEATURE_DESCRIPTION" ]; then
|
||||
echo "Usage: $0 [--json] [--dry-run] [--allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Trim whitespace and validate description is not empty
|
||||
FEATURE_DESCRIPTION=$(echo "$FEATURE_DESCRIPTION" | sed -E 's/^[[:space:]]+|[[:space:]]+$//g')
|
||||
if [ -z "$FEATURE_DESCRIPTION" ]; then
|
||||
echo "Error: Feature description cannot be empty or contain only whitespace" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to get highest number from specs directory
|
||||
get_highest_from_specs() {
|
||||
local specs_dir="$1"
|
||||
local highest=0
|
||||
|
||||
if [ -d "$specs_dir" ]; then
|
||||
for dir in "$specs_dir"/*; do
|
||||
[ -d "$dir" ] || continue
|
||||
dirname=$(basename "$dir")
|
||||
# Match sequential prefixes (>=3 digits), but skip timestamp dirs.
|
||||
if echo "$dirname" | grep -Eq '^[0-9]{3,}-' && ! echo "$dirname" | grep -Eq '^[0-9]{8}-[0-9]{6}-'; then
|
||||
number=$(echo "$dirname" | grep -Eo '^[0-9]+')
|
||||
number=$((10#$number))
|
||||
if [ "$number" -gt "$highest" ]; then
|
||||
highest=$number
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$highest"
|
||||
}
|
||||
|
||||
# Function to get highest number from git branches
|
||||
get_highest_from_branches() {
|
||||
git branch -a 2>/dev/null | sed 's/^[* ]*//; s|^remotes/[^/]*/||' | _extract_highest_number
|
||||
}
|
||||
|
||||
# Extract the highest sequential feature number from a list of ref names (one per line).
|
||||
_extract_highest_number() {
|
||||
local highest=0
|
||||
while IFS= read -r name; do
|
||||
[ -z "$name" ] && continue
|
||||
if echo "$name" | grep -Eq '^[0-9]{3,}-' && ! echo "$name" | grep -Eq '^[0-9]{8}-[0-9]{6}-'; then
|
||||
number=$(echo "$name" | grep -Eo '^[0-9]+' || echo "0")
|
||||
number=$((10#$number))
|
||||
if [ "$number" -gt "$highest" ]; then
|
||||
highest=$number
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "$highest"
|
||||
}
|
||||
|
||||
# Function to get highest number from remote branches without fetching (side-effect-free)
|
||||
get_highest_from_remote_refs() {
|
||||
local highest=0
|
||||
|
||||
for remote in $(git remote 2>/dev/null); do
|
||||
local remote_highest
|
||||
remote_highest=$(GIT_TERMINAL_PROMPT=0 git ls-remote --heads "$remote" 2>/dev/null | sed 's|.*refs/heads/||' | _extract_highest_number)
|
||||
if [ "$remote_highest" -gt "$highest" ]; then
|
||||
highest=$remote_highest
|
||||
fi
|
||||
done
|
||||
|
||||
echo "$highest"
|
||||
}
|
||||
|
||||
# Function to check existing branches and return next available number.
|
||||
check_existing_branches() {
|
||||
local specs_dir="$1"
|
||||
local skip_fetch="${2:-false}"
|
||||
|
||||
if [ "$skip_fetch" = true ]; then
|
||||
local highest_remote=$(get_highest_from_remote_refs)
|
||||
local highest_branch=$(get_highest_from_branches)
|
||||
if [ "$highest_remote" -gt "$highest_branch" ]; then
|
||||
highest_branch=$highest_remote
|
||||
fi
|
||||
else
|
||||
git fetch --all --prune >/dev/null 2>&1 || true
|
||||
local highest_branch=$(get_highest_from_branches)
|
||||
fi
|
||||
|
||||
local highest_spec=$(get_highest_from_specs "$specs_dir")
|
||||
|
||||
local max_num=$highest_branch
|
||||
if [ "$highest_spec" -gt "$max_num" ]; then
|
||||
max_num=$highest_spec
|
||||
fi
|
||||
|
||||
echo $((max_num + 1))
|
||||
}
|
||||
|
||||
# Function to clean and format a branch name
|
||||
clean_branch_name() {
|
||||
local name="$1"
|
||||
echo "$name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//'
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Source common.sh for resolve_template, json_escape, get_repo_root, has_git.
|
||||
#
|
||||
# Search locations in priority order:
|
||||
# 1. .specify/scripts/bash/common.sh under the project root (installed project)
|
||||
# 2. scripts/bash/common.sh under the project root (source checkout fallback)
|
||||
# 3. git-common.sh next to this script (minimal fallback — lacks resolve_template)
|
||||
# ---------------------------------------------------------------------------
|
||||
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Find project root by walking up from the script location
|
||||
_find_project_root() {
|
||||
local dir="$1"
|
||||
while [ "$dir" != "/" ]; do
|
||||
if [ -d "$dir/.specify" ] || [ -d "$dir/.git" ]; then
|
||||
echo "$dir"
|
||||
return 0
|
||||
fi
|
||||
dir="$(dirname "$dir")"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_common_loaded=false
|
||||
_PROJECT_ROOT=$(_find_project_root "$SCRIPT_DIR") || true
|
||||
|
||||
if [ -n "$_PROJECT_ROOT" ] && [ -f "$_PROJECT_ROOT/.specify/scripts/bash/common.sh" ]; then
|
||||
source "$_PROJECT_ROOT/.specify/scripts/bash/common.sh"
|
||||
_common_loaded=true
|
||||
elif [ -n "$_PROJECT_ROOT" ] && [ -f "$_PROJECT_ROOT/scripts/bash/common.sh" ]; then
|
||||
source "$_PROJECT_ROOT/scripts/bash/common.sh"
|
||||
_common_loaded=true
|
||||
elif [ -f "$SCRIPT_DIR/git-common.sh" ]; then
|
||||
source "$SCRIPT_DIR/git-common.sh"
|
||||
_common_loaded=true
|
||||
fi
|
||||
|
||||
if [ "$_common_loaded" != "true" ]; then
|
||||
echo "Error: Could not locate common.sh or git-common.sh. Please ensure the Specify core scripts are installed." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Resolve repository root
|
||||
if type get_repo_root >/dev/null 2>&1; then
|
||||
REPO_ROOT=$(get_repo_root)
|
||||
elif git rev-parse --show-toplevel >/dev/null 2>&1; then
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
elif [ -n "$_PROJECT_ROOT" ]; then
|
||||
REPO_ROOT="$_PROJECT_ROOT"
|
||||
else
|
||||
echo "Error: Could not determine repository root." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if git is available at this repo root
|
||||
if type has_git >/dev/null 2>&1; then
|
||||
if has_git "$REPO_ROOT"; then
|
||||
HAS_GIT=true
|
||||
else
|
||||
HAS_GIT=false
|
||||
fi
|
||||
elif git -C "$REPO_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
HAS_GIT=true
|
||||
else
|
||||
HAS_GIT=false
|
||||
fi
|
||||
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
SPECS_DIR="$REPO_ROOT/specs"
|
||||
|
||||
# Function to generate branch name with stop word filtering
|
||||
generate_branch_name() {
|
||||
local description="$1"
|
||||
|
||||
local stop_words="^(i|a|an|the|to|for|of|in|on|at|by|with|from|is|are|was|were|be|been|being|have|has|had|do|does|did|will|would|should|could|can|may|might|must|shall|this|that|these|those|my|your|our|their|want|need|add|get|set)$"
|
||||
|
||||
local clean_name=$(echo "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/ /g')
|
||||
|
||||
local meaningful_words=()
|
||||
for word in $clean_name; do
|
||||
[ -z "$word" ] && continue
|
||||
if ! echo "$word" | grep -qiE "$stop_words"; then
|
||||
if [ ${#word} -ge 3 ]; then
|
||||
meaningful_words+=("$word")
|
||||
elif echo "$description" | grep -qw -- "${word^^}"; then
|
||||
meaningful_words+=("$word")
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#meaningful_words[@]} -gt 0 ]; then
|
||||
local max_words=3
|
||||
if [ ${#meaningful_words[@]} -eq 4 ]; then max_words=4; fi
|
||||
|
||||
local result=""
|
||||
local count=0
|
||||
for word in "${meaningful_words[@]}"; do
|
||||
if [ $count -ge $max_words ]; then break; fi
|
||||
if [ -n "$result" ]; then result="$result-"; fi
|
||||
result="$result$word"
|
||||
count=$((count + 1))
|
||||
done
|
||||
echo "$result"
|
||||
else
|
||||
local cleaned=$(clean_branch_name "$description")
|
||||
echo "$cleaned" | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//'
|
||||
fi
|
||||
}
|
||||
|
||||
# Check for GIT_BRANCH_NAME env var override (exact branch name, no prefix/suffix)
|
||||
if [ -n "${GIT_BRANCH_NAME:-}" ]; then
|
||||
BRANCH_NAME="$GIT_BRANCH_NAME"
|
||||
# Extract FEATURE_NUM from the branch name if it starts with a numeric prefix
|
||||
# Check timestamp pattern first (YYYYMMDD-HHMMSS-) since it also matches the simpler ^[0-9]+ pattern
|
||||
if echo "$BRANCH_NAME" | grep -Eq '^[0-9]{8}-[0-9]{6}-'; then
|
||||
FEATURE_NUM=$(echo "$BRANCH_NAME" | grep -Eo '^[0-9]{8}-[0-9]{6}')
|
||||
BRANCH_SUFFIX="${BRANCH_NAME#${FEATURE_NUM}-}"
|
||||
elif echo "$BRANCH_NAME" | grep -Eq '^[0-9]+-'; then
|
||||
FEATURE_NUM=$(echo "$BRANCH_NAME" | grep -Eo '^[0-9]+')
|
||||
BRANCH_SUFFIX="${BRANCH_NAME#${FEATURE_NUM}-}"
|
||||
else
|
||||
FEATURE_NUM="$BRANCH_NAME"
|
||||
BRANCH_SUFFIX="$BRANCH_NAME"
|
||||
fi
|
||||
else
|
||||
# Generate branch name
|
||||
if [ -n "$SHORT_NAME" ]; then
|
||||
BRANCH_SUFFIX=$(clean_branch_name "$SHORT_NAME")
|
||||
else
|
||||
BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION")
|
||||
fi
|
||||
|
||||
# Warn if --number and --timestamp are both specified
|
||||
if [ "$USE_TIMESTAMP" = true ] && [ -n "$BRANCH_NUMBER" ]; then
|
||||
>&2 echo "[specify] Warning: --number is ignored when --timestamp is used"
|
||||
BRANCH_NUMBER=""
|
||||
fi
|
||||
|
||||
# Determine branch prefix
|
||||
if [ "$USE_TIMESTAMP" = true ]; then
|
||||
FEATURE_NUM=$(date +%Y%m%d-%H%M%S)
|
||||
BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}"
|
||||
else
|
||||
if [ -z "$BRANCH_NUMBER" ]; then
|
||||
if [ "$DRY_RUN" = true ] && [ "$HAS_GIT" = true ]; then
|
||||
BRANCH_NUMBER=$(check_existing_branches "$SPECS_DIR" true)
|
||||
elif [ "$DRY_RUN" = true ]; then
|
||||
HIGHEST=$(get_highest_from_specs "$SPECS_DIR")
|
||||
BRANCH_NUMBER=$((HIGHEST + 1))
|
||||
elif [ "$HAS_GIT" = true ]; then
|
||||
BRANCH_NUMBER=$(check_existing_branches "$SPECS_DIR")
|
||||
else
|
||||
HIGHEST=$(get_highest_from_specs "$SPECS_DIR")
|
||||
BRANCH_NUMBER=$((HIGHEST + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
FEATURE_NUM=$(printf "%03d" "$((10#$BRANCH_NUMBER))")
|
||||
BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# GitHub enforces a 244-byte limit on branch names
|
||||
MAX_BRANCH_LENGTH=244
|
||||
_byte_length() { printf '%s' "$1" | LC_ALL=C wc -c | tr -d ' '; }
|
||||
BRANCH_BYTE_LEN=$(_byte_length "$BRANCH_NAME")
|
||||
if [ -n "${GIT_BRANCH_NAME:-}" ] && [ "$BRANCH_BYTE_LEN" -gt $MAX_BRANCH_LENGTH ]; then
|
||||
>&2 echo "Error: GIT_BRANCH_NAME must be 244 bytes or fewer in UTF-8. Provided value is ${BRANCH_BYTE_LEN} bytes."
|
||||
exit 1
|
||||
elif [ "$BRANCH_BYTE_LEN" -gt $MAX_BRANCH_LENGTH ]; then
|
||||
PREFIX_LENGTH=$(( ${#FEATURE_NUM} + 1 ))
|
||||
MAX_SUFFIX_LENGTH=$((MAX_BRANCH_LENGTH - PREFIX_LENGTH))
|
||||
|
||||
TRUNCATED_SUFFIX=$(echo "$BRANCH_SUFFIX" | cut -c1-$MAX_SUFFIX_LENGTH)
|
||||
TRUNCATED_SUFFIX=$(echo "$TRUNCATED_SUFFIX" | sed 's/-$//')
|
||||
|
||||
ORIGINAL_BRANCH_NAME="$BRANCH_NAME"
|
||||
BRANCH_NAME="${FEATURE_NUM}-${TRUNCATED_SUFFIX}"
|
||||
|
||||
>&2 echo "[specify] Warning: Branch name exceeded GitHub's 244-byte limit"
|
||||
>&2 echo "[specify] Original: $ORIGINAL_BRANCH_NAME (${#ORIGINAL_BRANCH_NAME} bytes)"
|
||||
>&2 echo "[specify] Truncated to: $BRANCH_NAME (${#BRANCH_NAME} bytes)"
|
||||
fi
|
||||
|
||||
if [ "$DRY_RUN" != true ]; then
|
||||
if [ "$HAS_GIT" = true ]; then
|
||||
branch_create_error=""
|
||||
if ! branch_create_error=$(git checkout -q -b "$BRANCH_NAME" 2>&1); then
|
||||
current_branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
|
||||
if git branch --list "$BRANCH_NAME" | grep -q .; then
|
||||
if [ "$ALLOW_EXISTING" = true ]; then
|
||||
if [ "$current_branch" = "$BRANCH_NAME" ]; then
|
||||
:
|
||||
elif ! switch_branch_error=$(git checkout -q "$BRANCH_NAME" 2>&1); then
|
||||
>&2 echo "Error: Failed to switch to existing branch '$BRANCH_NAME'. Please resolve any local changes or conflicts and try again."
|
||||
if [ -n "$switch_branch_error" ]; then
|
||||
>&2 printf '%s\n' "$switch_branch_error"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
elif [ "$USE_TIMESTAMP" = true ]; then
|
||||
>&2 echo "Error: Branch '$BRANCH_NAME' already exists. Rerun to get a new timestamp or use a different --short-name."
|
||||
exit 1
|
||||
else
|
||||
>&2 echo "Error: Branch '$BRANCH_NAME' already exists. Please use a different feature name or specify a different number with --number."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
>&2 echo "Error: Failed to create git branch '$BRANCH_NAME'."
|
||||
if [ -n "$branch_create_error" ]; then
|
||||
>&2 printf '%s\n' "$branch_create_error"
|
||||
else
|
||||
>&2 echo "Please check your git configuration and try again."
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
>&2 echo "[specify] Warning: Git repository not detected; skipped branch creation for $BRANCH_NAME"
|
||||
fi
|
||||
|
||||
printf '# To persist: export SPECIFY_FEATURE=%q\n' "$BRANCH_NAME" >&2
|
||||
fi
|
||||
|
||||
if $JSON_MODE; then
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
jq -cn \
|
||||
--arg branch_name "$BRANCH_NAME" \
|
||||
--arg feature_num "$FEATURE_NUM" \
|
||||
'{BRANCH_NAME:$branch_name,FEATURE_NUM:$feature_num,DRY_RUN:true}'
|
||||
else
|
||||
jq -cn \
|
||||
--arg branch_name "$BRANCH_NAME" \
|
||||
--arg feature_num "$FEATURE_NUM" \
|
||||
'{BRANCH_NAME:$branch_name,FEATURE_NUM:$feature_num}'
|
||||
fi
|
||||
else
|
||||
if type json_escape >/dev/null 2>&1; then
|
||||
_je_branch=$(json_escape "$BRANCH_NAME")
|
||||
_je_num=$(json_escape "$FEATURE_NUM")
|
||||
else
|
||||
_je_branch="$BRANCH_NAME"
|
||||
_je_num="$FEATURE_NUM"
|
||||
fi
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
printf '{"BRANCH_NAME":"%s","FEATURE_NUM":"%s","DRY_RUN":true}\n' "$_je_branch" "$_je_num"
|
||||
else
|
||||
printf '{"BRANCH_NAME":"%s","FEATURE_NUM":"%s"}\n' "$_je_branch" "$_je_num"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "BRANCH_NAME: $BRANCH_NAME"
|
||||
echo "FEATURE_NUM: $FEATURE_NUM"
|
||||
if [ "$DRY_RUN" != true ]; then
|
||||
printf '# To persist in your shell: export SPECIFY_FEATURE=%q\n' "$BRANCH_NAME"
|
||||
fi
|
||||
fi
|
||||
54
extensions/git/scripts/bash/git-common.sh
Executable file
54
extensions/git/scripts/bash/git-common.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
# Git-specific common functions for the git extension.
|
||||
# Extracted from scripts/bash/common.sh — contains only git-specific
|
||||
# branch validation and detection logic.
|
||||
|
||||
# Check if we have git available at the repo root
|
||||
has_git() {
|
||||
local repo_root="${1:-$(pwd)}"
|
||||
{ [ -d "$repo_root/.git" ] || [ -f "$repo_root/.git" ]; } && \
|
||||
command -v git >/dev/null 2>&1 && \
|
||||
git -C "$repo_root" rev-parse --is-inside-work-tree >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Strip a single optional path segment (e.g. gitflow "feat/004-name" -> "004-name").
|
||||
# Only when the full name is exactly two slash-free segments; otherwise returns the raw name.
|
||||
spec_kit_effective_branch_name() {
|
||||
local raw="$1"
|
||||
if [[ "$raw" =~ ^([^/]+)/([^/]+)$ ]]; then
|
||||
printf '%s\n' "${BASH_REMATCH[2]}"
|
||||
else
|
||||
printf '%s\n' "$raw"
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate that a branch name matches the expected feature branch pattern.
|
||||
# Accepts sequential (###-* with >=3 digits) or timestamp (YYYYMMDD-HHMMSS-*) formats.
|
||||
# Logic aligned with scripts/bash/common.sh check_feature_branch after effective-name normalization.
|
||||
check_feature_branch() {
|
||||
local raw="$1"
|
||||
local has_git_repo="$2"
|
||||
|
||||
# For non-git repos, we can't enforce branch naming but still provide output
|
||||
if [[ "$has_git_repo" != "true" ]]; then
|
||||
echo "[specify] Warning: Git repository not detected; skipped branch validation" >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
local branch
|
||||
branch=$(spec_kit_effective_branch_name "$raw")
|
||||
|
||||
# Accept sequential prefix (3+ digits) but exclude malformed timestamps
|
||||
# Malformed: 7-or-8 digit date + 6-digit time with no trailing slug (e.g. "2026031-143022" or "20260319-143022")
|
||||
local is_sequential=false
|
||||
if [[ "$branch" =~ ^[0-9]{3,}- ]] && [[ ! "$branch" =~ ^[0-9]{7}-[0-9]{6}- ]] && [[ ! "$branch" =~ ^[0-9]{7,8}-[0-9]{6}$ ]]; then
|
||||
is_sequential=true
|
||||
fi
|
||||
if [[ "$is_sequential" != "true" ]] && [[ ! "$branch" =~ ^[0-9]{8}-[0-9]{6}- ]]; then
|
||||
echo "ERROR: Not on a feature branch. Current branch: $raw" >&2
|
||||
echo "Feature branches should be named like: 001-feature-name, 1234-feature-name, or 20260319-143022-feature-name" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
54
extensions/git/scripts/bash/initialize-repo.sh
Executable file
54
extensions/git/scripts/bash/initialize-repo.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
# Git extension: initialize-repo.sh
|
||||
# Initialize a Git repository with an initial commit.
|
||||
# Customizable — replace this script to add .gitignore templates,
|
||||
# default branch config, git-flow, LFS, signing, etc.
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Find project root
|
||||
_find_project_root() {
|
||||
local dir="$1"
|
||||
while [ "$dir" != "/" ]; do
|
||||
if [ -d "$dir/.specify" ] || [ -d "$dir/.git" ]; then
|
||||
echo "$dir"
|
||||
return 0
|
||||
fi
|
||||
dir="$(dirname "$dir")"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
REPO_ROOT=$(_find_project_root "$SCRIPT_DIR") || REPO_ROOT="$(pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Read commit message from extension config, fall back to default
|
||||
COMMIT_MSG="[Spec Kit] Initial commit"
|
||||
_config_file="$REPO_ROOT/.specify/extensions/git/git-config.yml"
|
||||
if [ -f "$_config_file" ]; then
|
||||
_msg=$(grep '^init_commit_message:' "$_config_file" 2>/dev/null | sed 's/^init_commit_message:[[:space:]]*//' | sed 's/^["'\'']//' | sed 's/["'\'']*$//')
|
||||
if [ -n "$_msg" ]; then
|
||||
COMMIT_MSG="$_msg"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if git is available
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
echo "[specify] Warning: Git not found; skipped repository initialization" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if already a git repo
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo "[specify] Git repository already initialized; skipping" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Initialize
|
||||
_git_out=$(git init -q 2>&1) || { echo "[specify] Error: git init failed: $_git_out" >&2; exit 1; }
|
||||
_git_out=$(git add . 2>&1) || { echo "[specify] Error: git add failed: $_git_out" >&2; exit 1; }
|
||||
_git_out=$(git commit --allow-empty -q -m "$COMMIT_MSG" 2>&1) || { echo "[specify] Error: git commit failed: $_git_out" >&2; exit 1; }
|
||||
|
||||
echo "✓ Git repository initialized" >&2
|
||||
169
extensions/git/scripts/powershell/auto-commit.ps1
Normal file
169
extensions/git/scripts/powershell/auto-commit.ps1
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# Git extension: auto-commit.ps1
|
||||
# Automatically commit changes after a Spec Kit command completes.
|
||||
# Checks per-command config keys in git-config.yml before committing.
|
||||
#
|
||||
# Usage: auto-commit.ps1 <event_name>
|
||||
# e.g.: auto-commit.ps1 after_specify
|
||||
param(
|
||||
[Parameter(Position = 0, Mandatory = $true)]
|
||||
[string]$EventName
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Find-ProjectRoot {
|
||||
param([string]$StartDir)
|
||||
$current = Resolve-Path $StartDir
|
||||
while ($true) {
|
||||
foreach ($marker in @('.specify', '.git')) {
|
||||
if (Test-Path (Join-Path $current $marker)) {
|
||||
return $current
|
||||
}
|
||||
}
|
||||
$parent = Split-Path $current -Parent
|
||||
if ($parent -eq $current) { return $null }
|
||||
$current = $parent
|
||||
}
|
||||
}
|
||||
|
||||
$repoRoot = Find-ProjectRoot -StartDir $PSScriptRoot
|
||||
if (-not $repoRoot) { $repoRoot = Get-Location }
|
||||
Set-Location $repoRoot
|
||||
|
||||
# Check if git is available
|
||||
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
|
||||
Write-Warning "[specify] Warning: Git not found; skipped auto-commit"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Temporarily relax ErrorActionPreference so git stderr warnings
|
||||
# (e.g. CRLF notices on Windows) do not become terminating errors.
|
||||
$savedEAP = $ErrorActionPreference
|
||||
$ErrorActionPreference = 'Continue'
|
||||
try {
|
||||
git rev-parse --is-inside-work-tree 2>$null | Out-Null
|
||||
$isRepo = $LASTEXITCODE -eq 0
|
||||
} finally {
|
||||
$ErrorActionPreference = $savedEAP
|
||||
}
|
||||
if (-not $isRepo) {
|
||||
Write-Warning "[specify] Warning: Not a Git repository; skipped auto-commit"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Read per-command config from git-config.yml
|
||||
$configFile = Join-Path $repoRoot ".specify/extensions/git/git-config.yml"
|
||||
$enabled = $false
|
||||
$commitMsg = ""
|
||||
|
||||
if (Test-Path $configFile) {
|
||||
# Parse YAML to find auto_commit section
|
||||
$inAutoCommit = $false
|
||||
$inEvent = $false
|
||||
$defaultEnabled = $false
|
||||
|
||||
foreach ($line in Get-Content $configFile) {
|
||||
# Detect auto_commit: section
|
||||
if ($line -match '^auto_commit:') {
|
||||
$inAutoCommit = $true
|
||||
$inEvent = $false
|
||||
continue
|
||||
}
|
||||
|
||||
# Exit auto_commit section on next top-level key
|
||||
if ($inAutoCommit -and $line -match '^[a-z]') {
|
||||
break
|
||||
}
|
||||
|
||||
if ($inAutoCommit) {
|
||||
# Check default key
|
||||
if ($line -match '^\s+default:\s*(.+)$') {
|
||||
$val = $matches[1].Trim().ToLower()
|
||||
if ($val -eq 'true') { $defaultEnabled = $true }
|
||||
}
|
||||
|
||||
# Detect our event subsection
|
||||
if ($line -match "^\s+${EventName}:") {
|
||||
$inEvent = $true
|
||||
continue
|
||||
}
|
||||
|
||||
# Inside our event subsection
|
||||
if ($inEvent) {
|
||||
# Exit on next sibling key (2-space indent, not 4+)
|
||||
if ($line -match '^\s{2}[a-z]' -and $line -notmatch '^\s{4}') {
|
||||
$inEvent = $false
|
||||
continue
|
||||
}
|
||||
if ($line -match '\s+enabled:\s*(.+)$') {
|
||||
$val = $matches[1].Trim().ToLower()
|
||||
if ($val -eq 'true') { $enabled = $true }
|
||||
if ($val -eq 'false') { $enabled = $false }
|
||||
}
|
||||
if ($line -match '\s+message:\s*(.+)$') {
|
||||
$commitMsg = $matches[1].Trim() -replace '^["'']' -replace '["'']$'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# If event-specific key not found, use default
|
||||
if (-not $enabled -and $defaultEnabled) {
|
||||
$hasEventKey = Select-String -Path $configFile -Pattern "^\s*${EventName}:" -Quiet
|
||||
if (-not $hasEventKey) {
|
||||
$enabled = $true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# No config file — auto-commit disabled by default
|
||||
exit 0
|
||||
}
|
||||
|
||||
if (-not $enabled) {
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Check if there are changes to commit
|
||||
# Relax ErrorActionPreference so CRLF warnings on stderr do not terminate.
|
||||
$savedEAP = $ErrorActionPreference
|
||||
$ErrorActionPreference = 'Continue'
|
||||
try {
|
||||
git diff --quiet HEAD 2>$null; $d1 = $LASTEXITCODE
|
||||
git diff --cached --quiet 2>$null; $d2 = $LASTEXITCODE
|
||||
$untracked = git ls-files --others --exclude-standard 2>$null
|
||||
} finally {
|
||||
$ErrorActionPreference = $savedEAP
|
||||
}
|
||||
|
||||
if ($d1 -eq 0 -and $d2 -eq 0 -and -not $untracked) {
|
||||
Write-Host "[specify] No changes to commit after $EventName" -ForegroundColor DarkGray
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Derive a human-readable command name from the event
|
||||
$commandName = $EventName -replace '^after_', '' -replace '^before_', ''
|
||||
$phase = if ($EventName -match '^before_') { 'before' } else { 'after' }
|
||||
|
||||
# Use custom message if configured, otherwise default
|
||||
if (-not $commitMsg) {
|
||||
$commitMsg = "[Spec Kit] Auto-commit $phase $commandName"
|
||||
}
|
||||
|
||||
# Stage and commit
|
||||
# Relax ErrorActionPreference so CRLF warnings on stderr do not terminate,
|
||||
# while still allowing redirected error output to be captured for diagnostics.
|
||||
$savedEAP = $ErrorActionPreference
|
||||
$ErrorActionPreference = 'Continue'
|
||||
try {
|
||||
$out = git add . 2>&1 | Out-String
|
||||
if ($LASTEXITCODE -ne 0) { throw "git add failed: $out" }
|
||||
$out = git commit -q -m $commitMsg 2>&1 | Out-String
|
||||
if ($LASTEXITCODE -ne 0) { throw "git commit failed: $out" }
|
||||
} catch {
|
||||
Write-Warning "[specify] Error: $_"
|
||||
exit 1
|
||||
} finally {
|
||||
$ErrorActionPreference = $savedEAP
|
||||
}
|
||||
|
||||
Write-Host "[OK] Changes committed $phase $commandName"
|
||||
403
extensions/git/scripts/powershell/create-new-feature.ps1
Normal file
403
extensions/git/scripts/powershell/create-new-feature.ps1
Normal file
@@ -0,0 +1,403 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# Git extension: create-new-feature.ps1
|
||||
# Adapted from core scripts/powershell/create-new-feature.ps1 for extension layout.
|
||||
# Sources common.ps1 from the project's installed scripts, falling back to
|
||||
# git-common.ps1 for minimal git helpers.
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$Json,
|
||||
[switch]$AllowExistingBranch,
|
||||
[switch]$DryRun,
|
||||
[string]$ShortName,
|
||||
[Parameter()]
|
||||
[long]$Number = 0,
|
||||
[switch]$Timestamp,
|
||||
[switch]$Help,
|
||||
[Parameter(Position = 0, ValueFromRemainingArguments = $true)]
|
||||
[string[]]$FeatureDescription
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if ($Help) {
|
||||
Write-Host "Usage: ./create-new-feature.ps1 [-Json] [-DryRun] [-AllowExistingBranch] [-ShortName <name>] [-Number N] [-Timestamp] <feature description>"
|
||||
Write-Host ""
|
||||
Write-Host "Options:"
|
||||
Write-Host " -Json Output in JSON format"
|
||||
Write-Host " -DryRun Compute branch name without creating the branch"
|
||||
Write-Host " -AllowExistingBranch Switch to branch if it already exists instead of failing"
|
||||
Write-Host " -ShortName <name> Provide a custom short name (2-4 words) for the branch"
|
||||
Write-Host " -Number N Specify branch number manually (overrides auto-detection)"
|
||||
Write-Host " -Timestamp Use timestamp prefix (YYYYMMDD-HHMMSS) instead of sequential numbering"
|
||||
Write-Host " -Help Show this help message"
|
||||
Write-Host ""
|
||||
Write-Host "Environment variables:"
|
||||
Write-Host " GIT_BRANCH_NAME Use this exact branch name, bypassing all prefix/suffix generation"
|
||||
Write-Host ""
|
||||
exit 0
|
||||
}
|
||||
|
||||
if (-not $FeatureDescription -or $FeatureDescription.Count -eq 0) {
|
||||
Write-Error "Usage: ./create-new-feature.ps1 [-Json] [-DryRun] [-AllowExistingBranch] [-ShortName <name>] [-Number N] [-Timestamp] <feature description>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$featureDesc = ($FeatureDescription -join ' ').Trim()
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($featureDesc)) {
|
||||
Write-Error "Error: Feature description cannot be empty or contain only whitespace"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function Get-HighestNumberFromSpecs {
|
||||
param([string]$SpecsDir)
|
||||
|
||||
[long]$highest = 0
|
||||
if (Test-Path $SpecsDir) {
|
||||
Get-ChildItem -Path $SpecsDir -Directory | ForEach-Object {
|
||||
if ($_.Name -match '^(\d{3,})-' -and $_.Name -notmatch '^\d{8}-\d{6}-') {
|
||||
[long]$num = 0
|
||||
if ([long]::TryParse($matches[1], [ref]$num) -and $num -gt $highest) {
|
||||
$highest = $num
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $highest
|
||||
}
|
||||
|
||||
function Get-HighestNumberFromNames {
|
||||
param([string[]]$Names)
|
||||
|
||||
[long]$highest = 0
|
||||
foreach ($name in $Names) {
|
||||
if ($name -match '^(\d{3,})-' -and $name -notmatch '^\d{8}-\d{6}-') {
|
||||
[long]$num = 0
|
||||
if ([long]::TryParse($matches[1], [ref]$num) -and $num -gt $highest) {
|
||||
$highest = $num
|
||||
}
|
||||
}
|
||||
}
|
||||
return $highest
|
||||
}
|
||||
|
||||
function Get-HighestNumberFromBranches {
|
||||
param()
|
||||
|
||||
try {
|
||||
$branches = git branch -a 2>$null
|
||||
if ($LASTEXITCODE -eq 0 -and $branches) {
|
||||
$cleanNames = $branches | ForEach-Object {
|
||||
$_.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', ''
|
||||
}
|
||||
return Get-HighestNumberFromNames -Names $cleanNames
|
||||
}
|
||||
} catch {
|
||||
Write-Verbose "Could not check Git branches: $_"
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
function Get-HighestNumberFromRemoteRefs {
|
||||
[long]$highest = 0
|
||||
try {
|
||||
$remotes = git remote 2>$null
|
||||
if ($remotes) {
|
||||
foreach ($remote in $remotes) {
|
||||
$env:GIT_TERMINAL_PROMPT = '0'
|
||||
$refs = git ls-remote --heads $remote 2>$null
|
||||
$env:GIT_TERMINAL_PROMPT = $null
|
||||
if ($LASTEXITCODE -eq 0 -and $refs) {
|
||||
$refNames = $refs | ForEach-Object {
|
||||
if ($_ -match 'refs/heads/(.+)$') { $matches[1] }
|
||||
} | Where-Object { $_ }
|
||||
$remoteHighest = Get-HighestNumberFromNames -Names $refNames
|
||||
if ($remoteHighest -gt $highest) { $highest = $remoteHighest }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Write-Verbose "Could not query remote refs: $_"
|
||||
}
|
||||
return $highest
|
||||
}
|
||||
|
||||
function Get-NextBranchNumber {
|
||||
param(
|
||||
[string]$SpecsDir,
|
||||
[switch]$SkipFetch
|
||||
)
|
||||
|
||||
if ($SkipFetch) {
|
||||
$highestBranch = Get-HighestNumberFromBranches
|
||||
$highestRemote = Get-HighestNumberFromRemoteRefs
|
||||
$highestBranch = [Math]::Max($highestBranch, $highestRemote)
|
||||
} else {
|
||||
try {
|
||||
git fetch --all --prune 2>$null | Out-Null
|
||||
} catch { }
|
||||
$highestBranch = Get-HighestNumberFromBranches
|
||||
}
|
||||
|
||||
$highestSpec = Get-HighestNumberFromSpecs -SpecsDir $SpecsDir
|
||||
$maxNum = [Math]::Max($highestBranch, $highestSpec)
|
||||
return $maxNum + 1
|
||||
}
|
||||
|
||||
function ConvertTo-CleanBranchName {
|
||||
param([string]$Name)
|
||||
return $Name.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', ''
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Source common.ps1 from the project's installed scripts.
|
||||
# Search locations in priority order:
|
||||
# 1. .specify/scripts/powershell/common.ps1 under the project root
|
||||
# 2. scripts/powershell/common.ps1 under the project root (source checkout)
|
||||
# 3. git-common.ps1 next to this script (minimal fallback)
|
||||
# ---------------------------------------------------------------------------
|
||||
function Find-ProjectRoot {
|
||||
param([string]$StartDir)
|
||||
$current = Resolve-Path $StartDir
|
||||
while ($true) {
|
||||
foreach ($marker in @('.specify', '.git')) {
|
||||
if (Test-Path (Join-Path $current $marker)) {
|
||||
return $current
|
||||
}
|
||||
}
|
||||
$parent = Split-Path $current -Parent
|
||||
if ($parent -eq $current) { return $null }
|
||||
$current = $parent
|
||||
}
|
||||
}
|
||||
|
||||
$projectRoot = Find-ProjectRoot -StartDir $PSScriptRoot
|
||||
$commonLoaded = $false
|
||||
|
||||
if ($projectRoot) {
|
||||
$candidates = @(
|
||||
(Join-Path $projectRoot ".specify/scripts/powershell/common.ps1"),
|
||||
(Join-Path $projectRoot "scripts/powershell/common.ps1")
|
||||
)
|
||||
foreach ($candidate in $candidates) {
|
||||
if (Test-Path $candidate) {
|
||||
. $candidate
|
||||
$commonLoaded = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $commonLoaded -and (Test-Path "$PSScriptRoot/git-common.ps1")) {
|
||||
. "$PSScriptRoot/git-common.ps1"
|
||||
$commonLoaded = $true
|
||||
}
|
||||
|
||||
if (-not $commonLoaded) {
|
||||
throw "Unable to locate common script file. Please ensure the Specify core scripts are installed."
|
||||
}
|
||||
|
||||
# Resolve repository root
|
||||
if (Get-Command Get-RepoRoot -ErrorAction SilentlyContinue) {
|
||||
$repoRoot = Get-RepoRoot
|
||||
} elseif ($projectRoot) {
|
||||
$repoRoot = $projectRoot
|
||||
} else {
|
||||
throw "Could not determine repository root."
|
||||
}
|
||||
|
||||
# Check if git is available
|
||||
if (Get-Command Test-HasGit -ErrorAction SilentlyContinue) {
|
||||
# Call without parameters for compatibility with core common.ps1 (no -RepoRoot param)
|
||||
# and git-common.ps1 (has -RepoRoot param with default).
|
||||
$hasGit = Test-HasGit
|
||||
} else {
|
||||
try {
|
||||
git -C $repoRoot rev-parse --is-inside-work-tree 2>$null | Out-Null
|
||||
$hasGit = ($LASTEXITCODE -eq 0)
|
||||
} catch {
|
||||
$hasGit = $false
|
||||
}
|
||||
}
|
||||
|
||||
Set-Location $repoRoot
|
||||
|
||||
$specsDir = Join-Path $repoRoot 'specs'
|
||||
|
||||
function Get-BranchName {
|
||||
param([string]$Description)
|
||||
|
||||
$stopWords = @(
|
||||
'i', 'a', 'an', 'the', 'to', 'for', 'of', 'in', 'on', 'at', 'by', 'with', 'from',
|
||||
'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had',
|
||||
'do', 'does', 'did', 'will', 'would', 'should', 'could', 'can', 'may', 'might', 'must', 'shall',
|
||||
'this', 'that', 'these', 'those', 'my', 'your', 'our', 'their',
|
||||
'want', 'need', 'add', 'get', 'set'
|
||||
)
|
||||
|
||||
$cleanName = $Description.ToLower() -replace '[^a-z0-9\s]', ' '
|
||||
$words = $cleanName -split '\s+' | Where-Object { $_ }
|
||||
|
||||
$meaningfulWords = @()
|
||||
foreach ($word in $words) {
|
||||
if ($stopWords -contains $word) { continue }
|
||||
if ($word.Length -ge 3) {
|
||||
$meaningfulWords += $word
|
||||
} elseif ($Description -match "\b$($word.ToUpper())\b") {
|
||||
$meaningfulWords += $word
|
||||
}
|
||||
}
|
||||
|
||||
if ($meaningfulWords.Count -gt 0) {
|
||||
$maxWords = if ($meaningfulWords.Count -eq 4) { 4 } else { 3 }
|
||||
$result = ($meaningfulWords | Select-Object -First $maxWords) -join '-'
|
||||
return $result
|
||||
} else {
|
||||
$result = ConvertTo-CleanBranchName -Name $Description
|
||||
$fallbackWords = ($result -split '-') | Where-Object { $_ } | Select-Object -First 3
|
||||
return [string]::Join('-', $fallbackWords)
|
||||
}
|
||||
}
|
||||
|
||||
# Check for GIT_BRANCH_NAME env var override (exact branch name, no prefix/suffix)
|
||||
if ($env:GIT_BRANCH_NAME) {
|
||||
$branchName = $env:GIT_BRANCH_NAME
|
||||
# Check 244-byte limit (UTF-8) for override names
|
||||
$branchNameUtf8ByteCount = [System.Text.Encoding]::UTF8.GetByteCount($branchName)
|
||||
if ($branchNameUtf8ByteCount -gt 244) {
|
||||
throw "GIT_BRANCH_NAME must be 244 bytes or fewer in UTF-8. Provided value is $branchNameUtf8ByteCount bytes; please supply a shorter override branch name."
|
||||
}
|
||||
# Extract FEATURE_NUM from the branch name if it starts with a numeric prefix
|
||||
# Check timestamp pattern first (YYYYMMDD-HHMMSS-) since it also matches the simpler ^\d+ pattern
|
||||
if ($branchName -match '^(\d{8}-\d{6})-') {
|
||||
$featureNum = $matches[1]
|
||||
} elseif ($branchName -match '^(\d+)-') {
|
||||
$featureNum = $matches[1]
|
||||
} else {
|
||||
$featureNum = $branchName
|
||||
}
|
||||
} else {
|
||||
if ($ShortName) {
|
||||
$branchSuffix = ConvertTo-CleanBranchName -Name $ShortName
|
||||
} else {
|
||||
$branchSuffix = Get-BranchName -Description $featureDesc
|
||||
}
|
||||
|
||||
if ($Timestamp -and $Number -ne 0) {
|
||||
Write-Warning "[specify] Warning: -Number is ignored when -Timestamp is used"
|
||||
$Number = 0
|
||||
}
|
||||
|
||||
if ($Timestamp) {
|
||||
$featureNum = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$branchName = "$featureNum-$branchSuffix"
|
||||
} else {
|
||||
if ($Number -eq 0) {
|
||||
if ($DryRun -and $hasGit) {
|
||||
$Number = Get-NextBranchNumber -SpecsDir $specsDir -SkipFetch
|
||||
} elseif ($DryRun) {
|
||||
$Number = (Get-HighestNumberFromSpecs -SpecsDir $specsDir) + 1
|
||||
} elseif ($hasGit) {
|
||||
$Number = Get-NextBranchNumber -SpecsDir $specsDir
|
||||
} else {
|
||||
$Number = (Get-HighestNumberFromSpecs -SpecsDir $specsDir) + 1
|
||||
}
|
||||
}
|
||||
|
||||
$featureNum = ('{0:000}' -f $Number)
|
||||
$branchName = "$featureNum-$branchSuffix"
|
||||
}
|
||||
}
|
||||
|
||||
$maxBranchLength = 244
|
||||
if ($branchName.Length -gt $maxBranchLength) {
|
||||
$prefixLength = $featureNum.Length + 1
|
||||
$maxSuffixLength = $maxBranchLength - $prefixLength
|
||||
|
||||
$truncatedSuffix = $branchSuffix.Substring(0, [Math]::Min($branchSuffix.Length, $maxSuffixLength))
|
||||
$truncatedSuffix = $truncatedSuffix -replace '-$', ''
|
||||
|
||||
$originalBranchName = $branchName
|
||||
$branchName = "$featureNum-$truncatedSuffix"
|
||||
|
||||
Write-Warning "[specify] Branch name exceeded GitHub's 244-byte limit"
|
||||
Write-Warning "[specify] Original: $originalBranchName ($($originalBranchName.Length) bytes)"
|
||||
Write-Warning "[specify] Truncated to: $branchName ($($branchName.Length) bytes)"
|
||||
}
|
||||
|
||||
if (-not $DryRun) {
|
||||
if ($hasGit) {
|
||||
$branchCreated = $false
|
||||
$branchCreateError = ''
|
||||
try {
|
||||
$branchCreateError = git checkout -q -b $branchName 2>&1 | Out-String
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
$branchCreated = $true
|
||||
}
|
||||
} catch {
|
||||
$branchCreateError = $_.Exception.Message
|
||||
}
|
||||
|
||||
if (-not $branchCreated) {
|
||||
$currentBranch = ''
|
||||
try { $currentBranch = (git rev-parse --abbrev-ref HEAD 2>$null).Trim() } catch {}
|
||||
$existingBranch = git branch --list $branchName 2>$null
|
||||
if ($existingBranch) {
|
||||
if ($AllowExistingBranch) {
|
||||
if ($currentBranch -eq $branchName) {
|
||||
# Already on the target branch
|
||||
} else {
|
||||
$switchBranchError = git checkout -q $branchName 2>&1 | Out-String
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
if ($switchBranchError) {
|
||||
Write-Error "Error: Branch '$branchName' exists but could not be checked out.`n$($switchBranchError.Trim())"
|
||||
} else {
|
||||
Write-Error "Error: Branch '$branchName' exists but could not be checked out. Resolve any uncommitted changes or conflicts and try again."
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
} elseif ($Timestamp) {
|
||||
Write-Error "Error: Branch '$branchName' already exists. Rerun to get a new timestamp or use a different -ShortName."
|
||||
exit 1
|
||||
} else {
|
||||
Write-Error "Error: Branch '$branchName' already exists. Please use a different feature name or specify a different number with -Number."
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
if ($branchCreateError) {
|
||||
Write-Error "Error: Failed to create git branch '$branchName'.`n$($branchCreateError.Trim())"
|
||||
} else {
|
||||
Write-Error "Error: Failed to create git branch '$branchName'. Please check your git configuration and try again."
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($Json) {
|
||||
[Console]::Error.WriteLine("[specify] Warning: Git repository not detected; skipped branch creation for $branchName")
|
||||
} else {
|
||||
Write-Warning "[specify] Warning: Git repository not detected; skipped branch creation for $branchName"
|
||||
}
|
||||
}
|
||||
|
||||
$env:SPECIFY_FEATURE = $branchName
|
||||
}
|
||||
|
||||
if ($Json) {
|
||||
$obj = [PSCustomObject]@{
|
||||
BRANCH_NAME = $branchName
|
||||
FEATURE_NUM = $featureNum
|
||||
HAS_GIT = $hasGit
|
||||
}
|
||||
if ($DryRun) {
|
||||
$obj | Add-Member -NotePropertyName 'DRY_RUN' -NotePropertyValue $true
|
||||
}
|
||||
$obj | ConvertTo-Json -Compress
|
||||
} else {
|
||||
Write-Output "BRANCH_NAME: $branchName"
|
||||
Write-Output "FEATURE_NUM: $featureNum"
|
||||
Write-Output "HAS_GIT: $hasGit"
|
||||
if (-not $DryRun) {
|
||||
Write-Output "SPECIFY_FEATURE environment variable set to: $branchName"
|
||||
}
|
||||
}
|
||||
51
extensions/git/scripts/powershell/git-common.ps1
Normal file
51
extensions/git/scripts/powershell/git-common.ps1
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# Git-specific common functions for the git extension.
|
||||
# Extracted from scripts/powershell/common.ps1 — contains only git-specific
|
||||
# branch validation and detection logic.
|
||||
|
||||
function Test-HasGit {
|
||||
param([string]$RepoRoot = (Get-Location))
|
||||
try {
|
||||
if (-not (Test-Path (Join-Path $RepoRoot '.git'))) { return $false }
|
||||
if (-not (Get-Command git -ErrorAction SilentlyContinue)) { return $false }
|
||||
git -C $RepoRoot rev-parse --is-inside-work-tree 2>$null | Out-Null
|
||||
return ($LASTEXITCODE -eq 0)
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Get-SpecKitEffectiveBranchName {
|
||||
param([string]$Branch)
|
||||
if ($Branch -match '^([^/]+)/([^/]+)$') {
|
||||
return $Matches[2]
|
||||
}
|
||||
return $Branch
|
||||
}
|
||||
|
||||
function Test-FeatureBranch {
|
||||
param(
|
||||
[string]$Branch,
|
||||
[bool]$HasGit = $true
|
||||
)
|
||||
|
||||
# For non-git repos, we can't enforce branch naming but still provide output
|
||||
if (-not $HasGit) {
|
||||
Write-Warning "[specify] Warning: Git repository not detected; skipped branch validation"
|
||||
return $true
|
||||
}
|
||||
|
||||
$raw = $Branch
|
||||
$Branch = Get-SpecKitEffectiveBranchName $raw
|
||||
|
||||
# Accept sequential prefix (3+ digits) but exclude malformed timestamps
|
||||
# Malformed: 7-or-8 digit date + 6-digit time with no trailing slug (e.g. "2026031-143022" or "20260319-143022")
|
||||
$hasMalformedTimestamp = ($Branch -match '^[0-9]{7}-[0-9]{6}-') -or ($Branch -match '^(?:\d{7}|\d{8})-\d{6}$')
|
||||
$isSequential = ($Branch -match '^[0-9]{3,}-') -and (-not $hasMalformedTimestamp)
|
||||
if (-not $isSequential -and $Branch -notmatch '^\d{8}-\d{6}-') {
|
||||
[Console]::Error.WriteLine("ERROR: Not on a feature branch. Current branch: $raw")
|
||||
[Console]::Error.WriteLine("Feature branches should be named like: 001-feature-name, 1234-feature-name, or 20260319-143022-feature-name")
|
||||
return $false
|
||||
}
|
||||
return $true
|
||||
}
|
||||
69
extensions/git/scripts/powershell/initialize-repo.ps1
Normal file
69
extensions/git/scripts/powershell/initialize-repo.ps1
Normal file
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# Git extension: initialize-repo.ps1
|
||||
# Initialize a Git repository with an initial commit.
|
||||
# Customizable — replace this script to add .gitignore templates,
|
||||
# default branch config, git-flow, LFS, signing, etc.
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Find project root
|
||||
function Find-ProjectRoot {
|
||||
param([string]$StartDir)
|
||||
$current = Resolve-Path $StartDir
|
||||
while ($true) {
|
||||
foreach ($marker in @('.specify', '.git')) {
|
||||
if (Test-Path (Join-Path $current $marker)) {
|
||||
return $current
|
||||
}
|
||||
}
|
||||
$parent = Split-Path $current -Parent
|
||||
if ($parent -eq $current) { return $null }
|
||||
$current = $parent
|
||||
}
|
||||
}
|
||||
|
||||
$repoRoot = Find-ProjectRoot -StartDir $PSScriptRoot
|
||||
if (-not $repoRoot) { $repoRoot = Get-Location }
|
||||
Set-Location $repoRoot
|
||||
|
||||
# Read commit message from extension config, fall back to default
|
||||
$commitMsg = "[Spec Kit] Initial commit"
|
||||
$configFile = Join-Path $repoRoot ".specify/extensions/git/git-config.yml"
|
||||
if (Test-Path $configFile) {
|
||||
foreach ($line in Get-Content $configFile) {
|
||||
if ($line -match '^init_commit_message:\s*(.+)$') {
|
||||
$val = $matches[1].Trim() -replace '^["'']' -replace '["'']$'
|
||||
if ($val) { $commitMsg = $val }
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Check if git is available
|
||||
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
|
||||
Write-Warning "[specify] Warning: Git not found; skipped repository initialization"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Check if already a git repo
|
||||
try {
|
||||
git rev-parse --is-inside-work-tree 2>$null | Out-Null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Warning "[specify] Git repository already initialized; skipping"
|
||||
exit 0
|
||||
}
|
||||
} catch { }
|
||||
|
||||
# Initialize
|
||||
try {
|
||||
$out = git init -q 2>&1 | Out-String
|
||||
if ($LASTEXITCODE -ne 0) { throw "git init failed: $out" }
|
||||
$out = git add . 2>&1 | Out-String
|
||||
if ($LASTEXITCODE -ne 0) { throw "git add failed: $out" }
|
||||
$out = git commit --allow-empty -q -m $commitMsg 2>&1 | Out-String
|
||||
if ($LASTEXITCODE -ne 0) { throw "git commit failed: $out" }
|
||||
} catch {
|
||||
Write-Warning "[specify] Error: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "✓ Git repository initialized"
|
||||
69
extensions/selftest/commands/selftest.md
Normal file
69
extensions/selftest/commands/selftest.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
description: "Validate the lifecycle of an extension from the catalog."
|
||||
---
|
||||
|
||||
# Extension Self-Test: `$ARGUMENTS`
|
||||
|
||||
This command drives a self-test simulating the developer experience with the `$ARGUMENTS` extension.
|
||||
|
||||
## Goal
|
||||
|
||||
Validate the end-to-end lifecycle (discovery, installation, registration) for the extension: `$ARGUMENTS`.
|
||||
If `$ARGUMENTS` is empty, you must tell the user to provide an extension name, for example: `/speckit.selftest.extension linear`.
|
||||
|
||||
## Steps
|
||||
|
||||
### Step 1: Catalog Discovery Validation
|
||||
|
||||
Check if the extension exists in the Spec Kit catalog.
|
||||
Execute this command and verify that it completes successfully and that the returned extension ID exactly matches `$ARGUMENTS`. If the command fails or the ID does not match `$ARGUMENTS`, fail the test.
|
||||
|
||||
```bash
|
||||
specify extension info "$ARGUMENTS"
|
||||
```
|
||||
|
||||
### Step 2: Simulate Installation
|
||||
|
||||
First, try to add the extension to the current workspace configuration directly. If the catalog provides the extension as `install_allowed: false` (discovery-only), this step is *expected* to fail.
|
||||
|
||||
```bash
|
||||
specify extension add "$ARGUMENTS"
|
||||
```
|
||||
|
||||
Then, simulate adding the extension by installing it from its catalog download URL, which should bypass the restriction.
|
||||
Obtain the extension's `download_url` from the catalog metadata (for example, via a catalog info command or UI), then run:
|
||||
|
||||
```bash
|
||||
specify extension add "$ARGUMENTS" --from "<download_url>"
|
||||
```
|
||||
|
||||
### Step 3: Registration Verification
|
||||
|
||||
Once the `add` command completes, verify the installation by checking the project configuration.
|
||||
Use terminal tools (like `cat`) to verify that the following file contains a record for `$ARGUMENTS`.
|
||||
|
||||
```bash
|
||||
cat .specify/extensions/.registry/$ARGUMENTS.json
|
||||
```
|
||||
|
||||
### Step 4: Verification Report
|
||||
|
||||
Analyze the standard output of the three steps.
|
||||
Generate a terminal-style test output format detailing the results of discovery, installation, and registration. Return this directly to the user.
|
||||
|
||||
Example output format:
|
||||
```text
|
||||
============================= test session starts ==============================
|
||||
collected 3 items
|
||||
|
||||
test_selftest_discovery.py::test_catalog_search [PASS/FAIL]
|
||||
Details: [Provide execution result of specify extension search]
|
||||
|
||||
test_selftest_installation.py::test_extension_add [PASS/FAIL]
|
||||
Details: [Provide execution result of specify extension add]
|
||||
|
||||
test_selftest_registration.py::test_config_verification [PASS/FAIL]
|
||||
Details: [Provide execution result of registry record verification]
|
||||
|
||||
============================== [X] passed in ... ==============================
|
||||
```
|
||||
16
extensions/selftest/extension.yml
Normal file
16
extensions/selftest/extension.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
schema_version: "1.0"
|
||||
extension:
|
||||
id: selftest
|
||||
name: Spec Kit Self-Test Utility
|
||||
version: 1.0.0
|
||||
description: Verifies catalog extensions by programmatically walking through the discovery, installation, and registration lifecycle.
|
||||
author: spec-kit-core
|
||||
repository: https://github.com/github/spec-kit
|
||||
license: MIT
|
||||
requires:
|
||||
speckit_version: ">=0.2.0"
|
||||
provides:
|
||||
commands:
|
||||
- name: speckit.selftest.extension
|
||||
file: commands/selftest.md
|
||||
description: Validate the lifecycle of an extension from the catalog.
|
||||
39
extensions/template/.gitignore
vendored
Normal file
39
extensions/template/.gitignore
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# Local configuration overrides
|
||||
*-config.local.yml
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
env/
|
||||
venv/
|
||||
|
||||
# Testing
|
||||
.pytest_cache/
|
||||
.coverage
|
||||
htmlcov/
|
||||
|
||||
# IDEs
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# Build artifacts
|
||||
dist/
|
||||
build/
|
||||
*.egg-info/
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
.cache/
|
||||
39
extensions/template/CHANGELOG.md
Normal file
39
extensions/template/CHANGELOG.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this extension will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Planned
|
||||
|
||||
- Feature ideas for future versions
|
||||
- Enhancements
|
||||
- Bug fixes
|
||||
|
||||
## [1.0.0] - YYYY-MM-DD
|
||||
|
||||
### Added
|
||||
|
||||
- Initial release of extension
|
||||
- Command: `/speckit.my-extension.example` - Example command functionality
|
||||
- Configuration system with template
|
||||
- Documentation and examples
|
||||
|
||||
### Features
|
||||
|
||||
- Feature 1 description
|
||||
- Feature 2 description
|
||||
- Feature 3 description
|
||||
|
||||
### Requirements
|
||||
|
||||
- Spec Kit: >=0.1.0
|
||||
- External dependencies (if any)
|
||||
|
||||
---
|
||||
|
||||
[Unreleased]: https://github.com/your-org/spec-kit-my-extension/compare/v1.0.0...HEAD
|
||||
[1.0.0]: https://github.com/your-org/spec-kit-my-extension/releases/tag/v1.0.0
|
||||
158
extensions/template/EXAMPLE-README.md
Normal file
158
extensions/template/EXAMPLE-README.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# EXAMPLE: Extension README
|
||||
|
||||
This is an example of what your extension README should look like after customization.
|
||||
**Delete this file and replace README.md with content similar to this.**
|
||||
|
||||
---
|
||||
|
||||
# My Extension
|
||||
|
||||
<!-- CUSTOMIZE: Replace with your extension description -->
|
||||
|
||||
Brief description of what your extension does and why it's useful.
|
||||
|
||||
## Features
|
||||
|
||||
<!-- CUSTOMIZE: List key features -->
|
||||
|
||||
- Feature 1: Description
|
||||
- Feature 2: Description
|
||||
- Feature 3: Description
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Install from catalog
|
||||
specify extension add my-extension
|
||||
|
||||
# Or install from local development directory
|
||||
specify extension add --dev /path/to/my-extension
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
1. Create configuration file:
|
||||
|
||||
```bash
|
||||
cp .specify/extensions/my-extension/config-template.yml \
|
||||
.specify/extensions/my-extension/my-extension-config.yml
|
||||
```
|
||||
|
||||
2. Edit configuration:
|
||||
|
||||
```bash
|
||||
vim .specify/extensions/my-extension/my-extension-config.yml
|
||||
```
|
||||
|
||||
3. Set required values:
|
||||
<!-- CUSTOMIZE: List required configuration -->
|
||||
```yaml
|
||||
connection:
|
||||
url: "https://api.example.com"
|
||||
api_key: "your-api-key"
|
||||
|
||||
project:
|
||||
id: "your-project-id"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
<!-- CUSTOMIZE: Add usage examples -->
|
||||
|
||||
### Command: example
|
||||
|
||||
Description of what this command does.
|
||||
|
||||
```bash
|
||||
# In Claude Code
|
||||
> /speckit.my-extension.example
|
||||
```
|
||||
|
||||
**Prerequisites**:
|
||||
|
||||
- Prerequisite 1
|
||||
- Prerequisite 2
|
||||
|
||||
**Output**:
|
||||
|
||||
- What this command produces
|
||||
- Where results are saved
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
<!-- CUSTOMIZE: Document all configuration options -->
|
||||
|
||||
### Connection Settings
|
||||
|
||||
| Setting | Type | Required | Description |
|
||||
|---------|------|----------|-------------|
|
||||
| `connection.url` | string | Yes | API endpoint URL |
|
||||
| `connection.api_key` | string | Yes | API authentication key |
|
||||
|
||||
### Project Settings
|
||||
|
||||
| Setting | Type | Required | Description |
|
||||
|---------|------|----------|-------------|
|
||||
| `project.id` | string | Yes | Project identifier |
|
||||
| `project.workspace` | string | No | Workspace or organization |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Override configuration with environment variables:
|
||||
|
||||
```bash
|
||||
# Override connection settings
|
||||
export SPECKIT_MY_EXTENSION_CONNECTION_URL="https://custom-api.com"
|
||||
export SPECKIT_MY_EXTENSION_CONNECTION_API_KEY="custom-key"
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
<!-- CUSTOMIZE: Add real-world examples -->
|
||||
|
||||
### Example 1: Basic Workflow
|
||||
|
||||
```bash
|
||||
# Step 1: Create specification
|
||||
> /speckit.spec
|
||||
|
||||
# Step 2: Generate tasks
|
||||
> /speckit.tasks
|
||||
|
||||
# Step 3: Use extension
|
||||
> /speckit.my-extension.example
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<!-- CUSTOMIZE: Add common issues -->
|
||||
|
||||
### Issue: Configuration not found
|
||||
|
||||
**Solution**: Create config from template (see Configuration section)
|
||||
|
||||
### Issue: Command not available
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check extension is installed: `specify extension list`
|
||||
2. Restart AI agent
|
||||
3. Reinstall extension
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see LICENSE file
|
||||
|
||||
## Support
|
||||
|
||||
- **Issues**: <https://github.com/your-org/spec-kit-my-extension/issues>
|
||||
- **Spec Kit Docs**: <https://github.com/statsperform/spec-kit>
|
||||
|
||||
## Changelog
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md) for version history.
|
||||
|
||||
---
|
||||
|
||||
*Extension Version: 1.0.0*
|
||||
*Spec Kit: >=0.1.0*
|
||||
21
extensions/template/LICENSE
Normal file
21
extensions/template/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 [Your Name or Organization]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
79
extensions/template/README.md
Normal file
79
extensions/template/README.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Extension Template
|
||||
|
||||
Starter template for creating a Spec Kit extension.
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. **Copy this template**:
|
||||
|
||||
```bash
|
||||
cp -r extensions/template my-extension
|
||||
cd my-extension
|
||||
```
|
||||
|
||||
2. **Customize `extension.yml`**:
|
||||
- Change extension ID, name, description
|
||||
- Update author and repository
|
||||
- Define your commands
|
||||
|
||||
3. **Create commands**:
|
||||
- Add command files in `commands/` directory
|
||||
- Use Markdown format with YAML frontmatter
|
||||
|
||||
4. **Create config template**:
|
||||
- Define configuration options
|
||||
- Document all settings
|
||||
|
||||
5. **Write documentation**:
|
||||
- Update README.md with usage instructions
|
||||
- Add examples
|
||||
|
||||
6. **Test locally**:
|
||||
|
||||
```bash
|
||||
cd /path/to/spec-kit-project
|
||||
specify extension add --dev /path/to/my-extension
|
||||
```
|
||||
|
||||
7. **Publish** (optional):
|
||||
- Create GitHub repository
|
||||
- Create release
|
||||
- Submit to catalog (see EXTENSION-PUBLISHING-GUIDE.md)
|
||||
|
||||
## Files in This Template
|
||||
|
||||
- `extension.yml` - Extension manifest (CUSTOMIZE THIS)
|
||||
- `config-template.yml` - Configuration template (CUSTOMIZE THIS)
|
||||
- `commands/example.md` - Example command (REPLACE THIS)
|
||||
- `README.md` - Extension documentation (REPLACE THIS)
|
||||
- `LICENSE` - MIT License (REVIEW THIS)
|
||||
- `CHANGELOG.md` - Version history (UPDATE THIS)
|
||||
- `.gitignore` - Git ignore rules
|
||||
|
||||
## Customization Checklist
|
||||
|
||||
- [ ] Update `extension.yml` with your extension details
|
||||
- [ ] Change extension ID to your extension name
|
||||
- [ ] Update author information
|
||||
- [ ] Define your commands
|
||||
- [ ] Create command files in `commands/`
|
||||
- [ ] Update config template
|
||||
- [ ] Write README with usage instructions
|
||||
- [ ] Add examples
|
||||
- [ ] Update LICENSE if needed
|
||||
- [ ] Test extension locally
|
||||
- [ ] Create git repository
|
||||
- [ ] Create first release
|
||||
|
||||
## Need Help?
|
||||
|
||||
- **Development Guide**: See EXTENSION-DEVELOPMENT-GUIDE.md
|
||||
- **API Reference**: See EXTENSION-API-REFERENCE.md
|
||||
- **Publishing Guide**: See EXTENSION-PUBLISHING-GUIDE.md
|
||||
- **User Guide**: See EXTENSION-USER-GUIDE.md
|
||||
|
||||
## Template Version
|
||||
|
||||
- Version: 1.0.0
|
||||
- Last Updated: 2026-01-28
|
||||
- Compatible with Spec Kit: >=0.1.0
|
||||
210
extensions/template/commands/example.md
Normal file
210
extensions/template/commands/example.md
Normal file
@@ -0,0 +1,210 @@
|
||||
---
|
||||
description: "Example command that demonstrates extension functionality"
|
||||
# CUSTOMIZE: List MCP tools this command uses
|
||||
tools:
|
||||
- 'example-mcp-server/example_tool'
|
||||
---
|
||||
|
||||
# Example Command
|
||||
|
||||
<!-- CUSTOMIZE: Replace this entire file with your command documentation -->
|
||||
|
||||
This is an example command that demonstrates how to create commands for Spec Kit extensions.
|
||||
|
||||
## Purpose
|
||||
|
||||
Describe what this command does and when to use it.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
List requirements before using this command:
|
||||
|
||||
1. Prerequisite 1 (e.g., "MCP server configured")
|
||||
2. Prerequisite 2 (e.g., "Configuration file exists")
|
||||
3. Prerequisite 3 (e.g., "Valid API credentials")
|
||||
|
||||
## User Input
|
||||
|
||||
$ARGUMENTS
|
||||
|
||||
## Steps
|
||||
|
||||
### Step 1: Load Configuration
|
||||
|
||||
<!-- CUSTOMIZE: Replace with your actual steps -->
|
||||
|
||||
Load extension configuration from the project:
|
||||
|
||||
``bash
|
||||
config_file=".specify/extensions/my-extension/my-extension-config.yml"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo "❌ Error: Configuration not found at $config_file"
|
||||
echo "Run 'specify extension add my-extension' to install and configure"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read configuration values
|
||||
|
||||
setting_value=$(yq eval '.settings.key' "$config_file")
|
||||
|
||||
# Apply environment variable overrides
|
||||
|
||||
setting_value="${SPECKIT_MY_EXTENSION_KEY:-$setting_value}"
|
||||
|
||||
# Validate configuration
|
||||
|
||||
if [ -z "$setting_value" ]; then
|
||||
echo "❌ Error: Configuration value not set"
|
||||
echo "Edit $config_file and set 'settings.key'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📋 Configuration loaded: $setting_value"
|
||||
``
|
||||
|
||||
### Step 2: Perform Main Action
|
||||
|
||||
<!-- CUSTOMIZE: Replace with your command logic -->
|
||||
|
||||
Describe what this step does:
|
||||
|
||||
``markdown
|
||||
Use MCP tools to perform the main action:
|
||||
|
||||
- Tool: example-mcp-server example_tool
|
||||
- Parameters: { "key": "$setting_value" }
|
||||
|
||||
This calls the MCP server tool to execute the operation.
|
||||
``
|
||||
|
||||
### Step 3: Process Results
|
||||
|
||||
<!-- CUSTOMIZE: Add more steps as needed -->
|
||||
|
||||
Process the results and provide output:
|
||||
|
||||
`` bash
|
||||
echo ""
|
||||
echo "✅ Command completed successfully!"
|
||||
echo ""
|
||||
echo "Results:"
|
||||
echo " • Item 1: Value"
|
||||
echo " • Item 2: Value"
|
||||
echo ""
|
||||
``
|
||||
|
||||
### Step 4: Save Output (Optional)
|
||||
|
||||
Save results to a file if needed:
|
||||
|
||||
``bash
|
||||
output_file=".specify/my-extension-output.json"
|
||||
|
||||
cat > "$output_file" <<EOF
|
||||
{
|
||||
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
|
||||
"setting": "$setting_value",
|
||||
"results": []
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "💾 Output saved to $output_file"
|
||||
``
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
<!-- CUSTOMIZE: Document configuration options -->
|
||||
|
||||
This command uses the following configuration from `my-extension-config.yml`:
|
||||
|
||||
- **settings.key**: Description of what this setting does
|
||||
- Type: string
|
||||
- Required: Yes
|
||||
- Example: `"example-value"`
|
||||
|
||||
- **settings.another_key**: Description of another setting
|
||||
- Type: boolean
|
||||
- Required: No
|
||||
- Default: `false`
|
||||
- Example: `true`
|
||||
|
||||
## Environment Variables
|
||||
|
||||
<!-- CUSTOMIZE: Document environment variable overrides -->
|
||||
|
||||
Configuration can be overridden with environment variables:
|
||||
|
||||
- `SPECKIT_MY_EXTENSION_KEY` - Overrides `settings.key`
|
||||
- `SPECKIT_MY_EXTENSION_ANOTHER_KEY` - Overrides `settings.another_key`
|
||||
|
||||
Example:
|
||||
``bash
|
||||
export SPECKIT_MY_EXTENSION_KEY="override-value"
|
||||
``
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<!-- CUSTOMIZE: Add common issues and solutions -->
|
||||
|
||||
### "Configuration not found"
|
||||
|
||||
**Solution**: Install the extension and create configuration:
|
||||
``bash
|
||||
specify extension add my-extension
|
||||
cp .specify/extensions/my-extension/config-template.yml \
|
||||
.specify/extensions/my-extension/my-extension-config.yml
|
||||
``
|
||||
|
||||
### "MCP tool not available"
|
||||
|
||||
**Solution**: Ensure MCP server is configured in your AI agent settings.
|
||||
|
||||
### "Permission denied"
|
||||
|
||||
**Solution**: Check credentials and permissions in the external service.
|
||||
|
||||
## Notes
|
||||
|
||||
<!-- CUSTOMIZE: Add helpful notes and tips -->
|
||||
|
||||
- This command requires an active connection to the external service
|
||||
- Results are cached for performance
|
||||
- Re-run the command to refresh data
|
||||
|
||||
## Examples
|
||||
|
||||
<!-- CUSTOMIZE: Add usage examples -->
|
||||
|
||||
### Example 1: Basic Usage
|
||||
|
||||
``bash
|
||||
|
||||
# Run with default configuration
|
||||
>
|
||||
> /speckit.my-extension.example
|
||||
``
|
||||
|
||||
### Example 2: With Environment Override
|
||||
|
||||
``bash
|
||||
|
||||
# Override configuration with environment variable
|
||||
|
||||
export SPECKIT_MY_EXTENSION_KEY="custom-value"
|
||||
> /speckit.my-extension.example
|
||||
``
|
||||
|
||||
### Example 3: After Core Command
|
||||
|
||||
``bash
|
||||
|
||||
# Use as part of a workflow
|
||||
>
|
||||
> /speckit.tasks
|
||||
> /speckit.my-extension.example
|
||||
``
|
||||
|
||||
---
|
||||
|
||||
*For more information, see the extension README or run `specify extension info my-extension`*
|
||||
75
extensions/template/config-template.yml
Normal file
75
extensions/template/config-template.yml
Normal file
@@ -0,0 +1,75 @@
|
||||
# Extension Configuration Template
|
||||
# Copy this to my-extension-config.yml and customize for your project
|
||||
|
||||
# CUSTOMIZE: Add your configuration sections below
|
||||
|
||||
# Example: Connection settings
|
||||
connection:
|
||||
# URL to external service
|
||||
url: "" # REQUIRED: e.g., "https://api.example.com"
|
||||
|
||||
# API key or token
|
||||
api_key: "" # REQUIRED: Your API key
|
||||
|
||||
# Example: Project settings
|
||||
project:
|
||||
# Project identifier
|
||||
id: "" # REQUIRED: e.g., "my-project"
|
||||
|
||||
# Workspace or organization
|
||||
workspace: "" # OPTIONAL: e.g., "my-org"
|
||||
|
||||
# Example: Feature flags
|
||||
features:
|
||||
# Enable/disable main functionality
|
||||
enabled: true
|
||||
|
||||
# Automatic synchronization
|
||||
auto_sync: false
|
||||
|
||||
# Verbose logging
|
||||
verbose: false
|
||||
|
||||
# Example: Default values
|
||||
defaults:
|
||||
# Labels to apply
|
||||
labels: [] # e.g., ["automated", "spec-kit"]
|
||||
|
||||
# Priority level
|
||||
priority: "medium" # Options: "low", "medium", "high"
|
||||
|
||||
# Assignee
|
||||
assignee: "" # OPTIONAL: Default assignee
|
||||
|
||||
# Example: Field mappings
|
||||
# Map internal names to external field IDs
|
||||
field_mappings:
|
||||
# Example mappings
|
||||
# internal_field: "external_field_id"
|
||||
# status: "customfield_10001"
|
||||
|
||||
# Example: Advanced settings
|
||||
advanced:
|
||||
# Timeout in seconds
|
||||
timeout: 30
|
||||
|
||||
# Retry attempts
|
||||
retry_count: 3
|
||||
|
||||
# Cache duration in seconds
|
||||
cache_duration: 3600
|
||||
|
||||
# Environment Variable Overrides:
|
||||
# You can override any setting with environment variables using this pattern:
|
||||
# SPECKIT_MY_EXTENSION_{SECTION}_{KEY}
|
||||
#
|
||||
# Examples:
|
||||
# - SPECKIT_MY_EXTENSION_CONNECTION_API_KEY: Override connection.api_key
|
||||
# - SPECKIT_MY_EXTENSION_PROJECT_ID: Override project.id
|
||||
# - SPECKIT_MY_EXTENSION_FEATURES_ENABLED: Override features.enabled
|
||||
#
|
||||
# Note: Use uppercase and replace dots with underscores
|
||||
|
||||
# Local Overrides:
|
||||
# For local development, create my-extension-config.local.yml (gitignored)
|
||||
# to override settings without affecting the team configuration
|
||||
97
extensions/template/extension.yml
Normal file
97
extensions/template/extension.yml
Normal file
@@ -0,0 +1,97 @@
|
||||
schema_version: "1.0"
|
||||
|
||||
extension:
|
||||
# CUSTOMIZE: Change 'my-extension' to your extension ID (lowercase, hyphen-separated)
|
||||
id: "my-extension"
|
||||
|
||||
# CUSTOMIZE: Human-readable name for your extension
|
||||
name: "My Extension"
|
||||
|
||||
# CUSTOMIZE: Update version when releasing (semantic versioning: X.Y.Z)
|
||||
version: "1.0.0"
|
||||
|
||||
# CUSTOMIZE: Brief description (under 200 characters)
|
||||
description: "Brief description of what your extension does"
|
||||
|
||||
# CUSTOMIZE: Your name or organization name
|
||||
author: "Your Name"
|
||||
|
||||
# CUSTOMIZE: GitHub repository URL (create before publishing)
|
||||
repository: "https://github.com/your-org/spec-kit-my-extension"
|
||||
|
||||
# REVIEW: License (MIT is recommended for open source)
|
||||
license: "MIT"
|
||||
|
||||
# CUSTOMIZE: Extension homepage (can be same as repository)
|
||||
homepage: "https://github.com/your-org/spec-kit-my-extension"
|
||||
|
||||
# Requirements for this extension
|
||||
requires:
|
||||
# CUSTOMIZE: Minimum spec-kit version required
|
||||
# Use >=X.Y.Z for minimum version
|
||||
# Use >=X.Y.Z,<Y.0.0 for version range
|
||||
speckit_version: ">=0.1.0"
|
||||
|
||||
# CUSTOMIZE: Add MCP tools or other dependencies
|
||||
# Remove if no external tools required
|
||||
tools:
|
||||
- name: "example-mcp-server"
|
||||
version: ">=1.0.0"
|
||||
required: true
|
||||
|
||||
# Commands provided by this extension
|
||||
provides:
|
||||
commands:
|
||||
# CUSTOMIZE: Define your commands
|
||||
# Pattern: speckit.{extension-id}.{command-name}
|
||||
- name: "speckit.my-extension.example"
|
||||
file: "commands/example.md"
|
||||
description: "Example command that demonstrates functionality"
|
||||
# Optional: Add aliases in the same namespaced format
|
||||
aliases: ["speckit.my-extension.example-short"]
|
||||
|
||||
# ADD MORE COMMANDS: Copy this block for each command
|
||||
# - name: "speckit.my-extension.another-command"
|
||||
# file: "commands/another-command.md"
|
||||
# description: "Another command"
|
||||
|
||||
# CUSTOMIZE: Define configuration files
|
||||
config:
|
||||
- name: "my-extension-config.yml"
|
||||
template: "config-template.yml"
|
||||
description: "Extension configuration"
|
||||
required: true # Set to false if config is optional
|
||||
|
||||
# CUSTOMIZE: Define hooks (optional)
|
||||
# Remove if no hooks needed
|
||||
hooks:
|
||||
# Hook that runs after /speckit.tasks
|
||||
after_tasks:
|
||||
command: "speckit.my-extension.example"
|
||||
optional: true # User will be prompted
|
||||
prompt: "Run example command?"
|
||||
description: "Demonstrates hook functionality"
|
||||
condition: null # Future: conditional execution
|
||||
|
||||
# ADD MORE HOOKS: Copy this block for other events
|
||||
# after_implement:
|
||||
# command: "speckit.my-extension.another"
|
||||
# optional: false # Auto-execute without prompting
|
||||
# description: "Runs automatically after implementation"
|
||||
|
||||
# CUSTOMIZE: Add relevant tags (2-5 recommended)
|
||||
# Used for discovery in catalog
|
||||
tags:
|
||||
- "example"
|
||||
- "template"
|
||||
# ADD MORE: "category", "tool-name", etc.
|
||||
|
||||
# CUSTOMIZE: Default configuration values (optional)
|
||||
# These are merged with user config
|
||||
defaults:
|
||||
# Example default values
|
||||
feature:
|
||||
enabled: true
|
||||
auto_sync: false
|
||||
|
||||
# ADD MORE: Any default settings for your extension
|
||||
142
integrations/CONTRIBUTING.md
Normal file
142
integrations/CONTRIBUTING.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# Contributing to the Integration Catalog
|
||||
|
||||
This guide covers adding integrations to both the **built-in** and **community** catalogs.
|
||||
|
||||
## Adding a Built-In Integration
|
||||
|
||||
Built-in integrations are maintained by the Spec Kit core team and ship with the CLI.
|
||||
|
||||
### Checklist
|
||||
|
||||
1. **Create the integration subpackage** under `src/specify_cli/integrations/<package_dir>/`
|
||||
— `<package_dir>` matches the integration key when it contains no hyphens (e.g., `gemini`), or replaces hyphens with underscores when it does (e.g., key `cursor-agent` → directory `cursor_agent/`, key `kiro-cli` → directory `kiro_cli/`). Python package names cannot use hyphens.
|
||||
2. **Implement the integration class** extending `MarkdownIntegration`, `TomlIntegration`, or `SkillsIntegration`
|
||||
3. **Register the integration** in `src/specify_cli/integrations/__init__.py`
|
||||
4. **Add tests** under `tests/integrations/test_integration_<package_dir>.py`
|
||||
5. **Add a catalog entry** in `integrations/catalog.json`
|
||||
6. **Update documentation** in `AGENTS.md` and `README.md`
|
||||
|
||||
### Catalog Entry Format
|
||||
|
||||
Add your integration under the top-level `integrations` key in `integrations/catalog.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"integrations": {
|
||||
"my-agent": {
|
||||
"id": "my-agent",
|
||||
"name": "My Agent",
|
||||
"version": "1.0.0",
|
||||
"description": "Integration for My Agent",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Adding a Community Integration
|
||||
|
||||
Community integrations are contributed by external developers and listed in `integrations/catalog.community.json` for discovery.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **Working integration** — tested with `specify integration install`
|
||||
2. **Public repository** — hosted on GitHub or similar
|
||||
3. **`integration.yml` descriptor** — valid descriptor file (see below)
|
||||
4. **Documentation** — README with usage instructions
|
||||
5. **License** — open source license file
|
||||
|
||||
### `integration.yml` Descriptor
|
||||
|
||||
Every community integration must include an `integration.yml`:
|
||||
|
||||
```yaml
|
||||
schema_version: "1.0"
|
||||
integration:
|
||||
id: "my-agent"
|
||||
name: "My Agent"
|
||||
version: "1.0.0"
|
||||
description: "Integration for My Agent"
|
||||
author: "your-name"
|
||||
repository: "https://github.com/your-name/speckit-my-agent"
|
||||
license: "MIT"
|
||||
requires:
|
||||
speckit_version: ">=0.6.0"
|
||||
tools:
|
||||
- name: "my-agent"
|
||||
version: ">=1.0.0"
|
||||
required: true
|
||||
provides:
|
||||
commands:
|
||||
- name: "speckit.specify"
|
||||
file: "templates/speckit.specify.md"
|
||||
scripts:
|
||||
- update-context.sh
|
||||
```
|
||||
|
||||
### Descriptor Validation Rules
|
||||
|
||||
| Field | Rule |
|
||||
|-------|------|
|
||||
| `schema_version` | Must be `"1.0"` |
|
||||
| `integration.id` | Lowercase alphanumeric + hyphens (`^[a-z0-9-]+$`) |
|
||||
| `integration.version` | Valid PEP 440 version (parsed with `packaging.version.Version()`) |
|
||||
| `requires.speckit_version` | Required field; specify a version constraint such as `>=0.6.0` (current validation checks presence only) |
|
||||
| `provides` | Must include at least one command or script |
|
||||
| `provides.commands[].name` | String identifier |
|
||||
| `provides.commands[].file` | Relative path to template file |
|
||||
|
||||
### Submitting to the Community Catalog
|
||||
|
||||
1. **Fork** the [spec-kit repository](https://github.com/github/spec-kit)
|
||||
2. **Add your entry** under the `integrations` key in `integrations/catalog.community.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"integrations": {
|
||||
"my-agent": {
|
||||
"id": "my-agent",
|
||||
"name": "My Agent",
|
||||
"version": "1.0.0",
|
||||
"description": "Integration for My Agent",
|
||||
"author": "your-name",
|
||||
"repository": "https://github.com/your-name/speckit-my-agent",
|
||||
"tags": ["cli"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Open a pull request** with:
|
||||
- Your catalog entry
|
||||
- Link to your integration repository
|
||||
- Confirmation that `integration.yml` is valid
|
||||
|
||||
### Version Updates
|
||||
|
||||
To update your integration version in the catalog:
|
||||
|
||||
1. Release a new version of your integration
|
||||
2. Open a PR updating the `version` field in `catalog.community.json`
|
||||
3. Ensure backward compatibility or document breaking changes
|
||||
|
||||
## Upgrade Workflow
|
||||
|
||||
The `specify integration upgrade` command supports diff-aware upgrades:
|
||||
|
||||
1. **Hash comparison** — the manifest records SHA-256 hashes of all installed files
|
||||
2. **Modified file detection** — files changed since installation are flagged
|
||||
3. **Safe default** — the upgrade blocks if any installed files were modified since installation
|
||||
4. **Forced reinstall** — passing `--force` overwrites modified files with the latest version
|
||||
|
||||
```bash
|
||||
# Upgrade current integration (blocks if files are modified)
|
||||
specify integration upgrade
|
||||
|
||||
# Force upgrade (overwrites modified files)
|
||||
specify integration upgrade --force
|
||||
```
|
||||
129
integrations/README.md
Normal file
129
integrations/README.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Spec Kit Integration Catalog
|
||||
|
||||
The integration catalog enables discovery, versioning, and distribution of AI agent integrations for Spec Kit.
|
||||
|
||||
## Catalog Files
|
||||
|
||||
### Built-In Catalog (`catalog.json`)
|
||||
|
||||
Contains integrations that ship with Spec Kit. These are maintained by the core team and always installable.
|
||||
|
||||
### Community Catalog (`catalog.community.json`)
|
||||
|
||||
Community-contributed integrations. Listed for discovery only — users install from the source repositories.
|
||||
|
||||
## Catalog Configuration
|
||||
|
||||
The catalog stack is resolved in this order (first match wins):
|
||||
|
||||
1. **Environment variable** — `SPECKIT_INTEGRATION_CATALOG_URL` overrides all catalogs with a single URL
|
||||
2. **Project config** — `.specify/integration-catalogs.yml` in the project root
|
||||
3. **User config** — `~/.specify/integration-catalogs.yml` in the user home directory
|
||||
4. **Built-in defaults** — `catalog.json` + `catalog.community.json`
|
||||
|
||||
Example `integration-catalogs.yml`:
|
||||
|
||||
```yaml
|
||||
catalogs:
|
||||
- url: "https://example.com/my-catalog.json"
|
||||
name: "my-catalog"
|
||||
priority: 1
|
||||
install_allowed: true
|
||||
```
|
||||
|
||||
## CLI Commands
|
||||
|
||||
```bash
|
||||
# List built-in integrations (default)
|
||||
specify integration list
|
||||
|
||||
# Browse full catalog (built-in + community)
|
||||
specify integration list --catalog
|
||||
|
||||
# Install an integration
|
||||
specify integration install copilot
|
||||
|
||||
# Upgrade the current integration (diff-aware)
|
||||
specify integration upgrade
|
||||
|
||||
# Upgrade with force (overwrite modified files)
|
||||
specify integration upgrade --force
|
||||
```
|
||||
|
||||
## Integration Descriptor (`integration.yml`)
|
||||
|
||||
Each integration can include an `integration.yml` descriptor that documents its metadata, requirements, and provided commands/scripts:
|
||||
|
||||
```yaml
|
||||
schema_version: "1.0"
|
||||
integration:
|
||||
id: "my-agent"
|
||||
name: "My Agent"
|
||||
version: "1.0.0"
|
||||
description: "Integration for My Agent"
|
||||
author: "my-org"
|
||||
repository: "https://github.com/my-org/speckit-my-agent"
|
||||
license: "MIT"
|
||||
requires:
|
||||
speckit_version: ">=0.6.0"
|
||||
tools:
|
||||
- name: "my-agent"
|
||||
version: ">=1.0.0"
|
||||
required: true
|
||||
provides:
|
||||
commands:
|
||||
- name: "speckit.specify"
|
||||
file: "templates/speckit.specify.md"
|
||||
- name: "speckit.plan"
|
||||
file: "templates/speckit.plan.md"
|
||||
scripts:
|
||||
- update-context.sh
|
||||
- update-context.ps1
|
||||
```
|
||||
|
||||
## Catalog Schema
|
||||
|
||||
Both catalog files follow the same JSON schema:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"updated_at": "2026-04-08T00:00:00Z",
|
||||
"catalog_url": "https://...",
|
||||
"integrations": {
|
||||
"my-agent": {
|
||||
"id": "my-agent",
|
||||
"name": "My Agent",
|
||||
"version": "1.0.0",
|
||||
"description": "Integration for My Agent",
|
||||
"author": "my-org",
|
||||
"repository": "https://github.com/my-org/speckit-my-agent",
|
||||
"tags": ["cli"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Required Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `schema_version` | string | Must be `"1.0"` |
|
||||
| `updated_at` | string | ISO 8601 timestamp |
|
||||
| `integrations` | object | Map of integration ID → metadata |
|
||||
|
||||
### Integration Entry Fields
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `id` | string | Yes | Unique ID (lowercase alphanumeric + hyphens) |
|
||||
| `name` | string | Yes | Human-readable display name |
|
||||
| `version` | string | Yes | PEP 440 version (e.g., `1.0.0`, `1.0.0a1`) |
|
||||
| `description` | string | Yes | One-line description |
|
||||
| `author` | string | No | Author name or organization |
|
||||
| `repository` | string | No | Source repository URL |
|
||||
| `tags` | array | No | Searchable tags (e.g., `["cli", "ide"]`) |
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for how to add integrations to the community catalog.
|
||||
6
integrations/catalog.community.json
Normal file
6
integrations/catalog.community.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"updated_at": "2026-04-08T00:00:00Z",
|
||||
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/integrations/catalog.community.json",
|
||||
"integrations": {}
|
||||
}
|
||||
259
integrations/catalog.json
Normal file
259
integrations/catalog.json
Normal file
@@ -0,0 +1,259 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"updated_at": "2026-04-08T00:00:00Z",
|
||||
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/integrations/catalog.json",
|
||||
"integrations": {
|
||||
"claude": {
|
||||
"id": "claude",
|
||||
"name": "Claude Code",
|
||||
"version": "1.0.0",
|
||||
"description": "Anthropic Claude Code CLI integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli", "anthropic"]
|
||||
},
|
||||
"copilot": {
|
||||
"id": "copilot",
|
||||
"name": "GitHub Copilot",
|
||||
"version": "1.0.0",
|
||||
"description": "GitHub Copilot IDE integration with agent commands and prompt files",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["ide", "github"]
|
||||
},
|
||||
"gemini": {
|
||||
"id": "gemini",
|
||||
"name": "Gemini CLI",
|
||||
"version": "1.0.0",
|
||||
"description": "Google Gemini CLI integration with TOML command format",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli", "google"]
|
||||
},
|
||||
"cursor-agent": {
|
||||
"id": "cursor-agent",
|
||||
"name": "Cursor",
|
||||
"version": "1.0.0",
|
||||
"description": "Cursor IDE integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["ide"]
|
||||
},
|
||||
"windsurf": {
|
||||
"id": "windsurf",
|
||||
"name": "Windsurf",
|
||||
"version": "1.0.0",
|
||||
"description": "Windsurf IDE workflow integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["ide"]
|
||||
},
|
||||
"amp": {
|
||||
"id": "amp",
|
||||
"name": "Amp",
|
||||
"version": "1.0.0",
|
||||
"description": "Amp CLI integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"codex": {
|
||||
"id": "codex",
|
||||
"name": "Codex CLI",
|
||||
"version": "1.0.0",
|
||||
"description": "Codex CLI skills-based integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli", "skills"]
|
||||
},
|
||||
"qwen": {
|
||||
"id": "qwen",
|
||||
"name": "Qwen Code",
|
||||
"version": "1.0.0",
|
||||
"description": "Alibaba Qwen Code CLI integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli", "alibaba"]
|
||||
},
|
||||
"opencode": {
|
||||
"id": "opencode",
|
||||
"name": "opencode",
|
||||
"version": "1.0.0",
|
||||
"description": "opencode CLI integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"forge": {
|
||||
"id": "forge",
|
||||
"name": "Forge",
|
||||
"version": "1.0.0",
|
||||
"description": "Forge CLI integration with parameter-based commands",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"kiro-cli": {
|
||||
"id": "kiro-cli",
|
||||
"name": "Kiro CLI",
|
||||
"version": "1.0.0",
|
||||
"description": "Kiro CLI prompt-based integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"junie": {
|
||||
"id": "junie",
|
||||
"name": "Junie",
|
||||
"version": "1.0.0",
|
||||
"description": "Junie by JetBrains CLI integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli", "jetbrains"]
|
||||
},
|
||||
"auggie": {
|
||||
"id": "auggie",
|
||||
"name": "Auggie CLI",
|
||||
"version": "1.0.0",
|
||||
"description": "Auggie CLI integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"shai": {
|
||||
"id": "shai",
|
||||
"name": "SHAI",
|
||||
"version": "1.0.0",
|
||||
"description": "SHAI CLI integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"tabnine": {
|
||||
"id": "tabnine",
|
||||
"name": "Tabnine CLI",
|
||||
"version": "1.0.0",
|
||||
"description": "Tabnine CLI integration with TOML command format",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"kilocode": {
|
||||
"id": "kilocode",
|
||||
"name": "Kilo Code",
|
||||
"version": "1.0.0",
|
||||
"description": "Kilo Code IDE workflow integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["ide"]
|
||||
},
|
||||
"roo": {
|
||||
"id": "roo",
|
||||
"name": "Roo Code",
|
||||
"version": "1.0.0",
|
||||
"description": "Roo Code IDE integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["ide"]
|
||||
},
|
||||
"bob": {
|
||||
"id": "bob",
|
||||
"name": "IBM Bob",
|
||||
"version": "1.0.0",
|
||||
"description": "IBM Bob IDE integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["ide", "ibm"]
|
||||
},
|
||||
"trae": {
|
||||
"id": "trae",
|
||||
"name": "Trae",
|
||||
"version": "1.0.0",
|
||||
"description": "Trae IDE rules-based integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["ide"]
|
||||
},
|
||||
"codebuddy": {
|
||||
"id": "codebuddy",
|
||||
"name": "CodeBuddy",
|
||||
"version": "1.0.0",
|
||||
"description": "CodeBuddy CLI integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"qodercli": {
|
||||
"id": "qodercli",
|
||||
"name": "Qoder CLI",
|
||||
"version": "1.0.0",
|
||||
"description": "Qoder CLI integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"kimi": {
|
||||
"id": "kimi",
|
||||
"name": "Kimi Code",
|
||||
"version": "1.0.0",
|
||||
"description": "Kimi Code CLI skills-based integration by Moonshot AI",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli", "skills"]
|
||||
},
|
||||
"pi": {
|
||||
"id": "pi",
|
||||
"name": "Pi Coding Agent",
|
||||
"version": "1.0.0",
|
||||
"description": "Pi terminal coding agent prompt-based integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"iflow": {
|
||||
"id": "iflow",
|
||||
"name": "iFlow CLI",
|
||||
"version": "1.0.0",
|
||||
"description": "iFlow CLI integration by iflow-ai",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
},
|
||||
"vibe": {
|
||||
"id": "vibe",
|
||||
"name": "Mistral Vibe",
|
||||
"version": "1.0.0",
|
||||
"description": "Mistral Vibe CLI prompt-based integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli", "mistral"]
|
||||
},
|
||||
"agy": {
|
||||
"id": "agy",
|
||||
"name": "Antigravity",
|
||||
"version": "1.0.0",
|
||||
"description": "Antigravity IDE skills-based integration",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["ide", "skills"]
|
||||
},
|
||||
"generic": {
|
||||
"id": "generic",
|
||||
"name": "Generic (bring your own agent)",
|
||||
"version": "1.0.0",
|
||||
"description": "Generic integration for any agent via --ai-commands-dir",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["generic"]
|
||||
},
|
||||
"goose": {
|
||||
"id": "goose",
|
||||
"name": "Goose",
|
||||
"version": "1.0.0",
|
||||
"description": "Goose CLI integration with YAML recipe format",
|
||||
"author": "spec-kit-core",
|
||||
"repository": "https://github.com/github/spec-kit",
|
||||
"tags": ["cli"]
|
||||
}
|
||||
}
|
||||
}
|
||||
54
newsletters/2026-February.md
Normal file
54
newsletters/2026-February.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Spec Kit - February 2026 Newsletter
|
||||
|
||||
This edition covers Spec Kit activity in February 2026. Versions v0.1.7 through v0.1.13 shipped during the month, addressing bugs and adding features including a dual-catalog extension system and additional agent integrations. Community activity included blog posts, tutorials, and meetup sessions. A category summary is in the table below, followed by details.
|
||||
|
||||
| **Spec Kit Core (Feb 2026)** | **Community & Content** | **Roadmap & Next** |
|
||||
| --- | --- | --- |
|
||||
| Versions **v0.1.7** through **v0.1.13** shipped with bug fixes and features, including a **dual-catalog extension system** and new agent integrations. Over 300 issues were closed (of ~800 filed). The repo reached 71k stars and 6.4k forks. [\[github.com\]](https://github.com/github/spec-kit/releases) [\[github.com\]](https://github.com/github/spec-kit/issues) [\[rywalker.com\]](https://rywalker.com/research/github-spec-kit) | Eduardo Luz published a LinkedIn article on SDD and Spec Kit [\[linkedin.com\]](https://www.linkedin.com/pulse/specification-driven-development-sdd-github-spec-kit-elevating-luz-tojmc?tl=en). Erick Matsen blogged a walkthrough of building a bioinformatics pipeline with Spec Kit [\[matsen.fredhutch.org\]](https://matsen.fredhutch.org/general/2026/02/10/spec-kit-walkthrough.html). Microsoft MVP [Eric Boyd](https://ericboyd.com/) (not the Microsoft AI Platform VP of the same name) presented at the Cleveland .NET User Group [\[ericboyd.com\]](https://ericboyd.com/events/cleveland-csharp-user-group-february-25-2026-spec-driven-development-sdd-github-spec-kit). | **v0.2.0** was released in early March, consolidating February's work. It added extensions for Jira and Azure DevOps, community plugin support, and agents for Tabnine CLI and Kiro CLI [\[github.com\]](https://github.com/github/spec-kit/releases). Future work includes spec lifecycle management and progress toward a stable 1.0 release [\[martinfowler.com\]](https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html). |
|
||||
|
||||
***
|
||||
|
||||
## Spec Kit Project Updates
|
||||
|
||||
Spec Kit released versions **v0.1.7** through **v0.1.13** during February. Version 0.1.7 (early February) updated documentation for the newly introduced **dual-catalog extension system**, which allows both core and community extension catalogs to coexist. Subsequent patches (0.1.8, 0.1.9, etc.) bumped dependencies such as GitHub Actions versions and resolved minor issues. **v0.1.10** fixed YAML front-matter handling in generated files. By late February, **v0.1.12** and **v0.1.13** shipped with additional fixes in preparation for the next version bump. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
|
||||
The main architectural addition was the **modular extension system** with separate "core" and "community" extension catalogs for third-party add-ons. Multiple community-contributed extensions were merged during the month, including a **Jira extension** for issue tracker integration, an **Azure DevOps extension**, and utility extensions for code review, retrospective documentation, and CI/CD sync. The pending 0.2.0 release changelog lists over a dozen changes from February, including the extension additions and support for **multiple agent catalogs concurrently**. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
|
||||
By end of February, **over 330 issues/feature requests had been closed on GitHub** (out of ~870 filed to date). External contributors submitted pull requests including the **Tabnine CLI support**, which was merged in late February. The repository reached ~71k stars and crossed 6,000 forks. [\[github.com\]](https://github.com/github/spec-kit/issues) [\[github.com\]](https://github.com/github/spec-kit/releases) [\[rywalker.com\]](https://rywalker.com/research/github-spec-kit)
|
||||
|
||||
On the stability side, February's work focused on tightening core workflows and fixing edge-case bugs in the specification, planning, and task-generation commands. The team addressed file-handling issues (e.g., clarifying how output files are created/appended) and improved the reliability of the automated release pipeline. The project also added **Kiro CLI** to the supported agent list and updated integration scripts for Cursor and Code Interpreter, bringing the total number of supported AI coding assistants to over 20. [\[github.com\]](https://github.com/github/spec-kit/releases) [\[github.com\]](https://github.com/github/spec-kit)
|
||||
|
||||
## Community & Content
|
||||
|
||||
**Eduardo Luz** published a LinkedIn article on Feb 15 titled *"Specification Driven Development (SDD) and the GitHub Spec Kit: Elevating Software Engineering."* The article draws on his experience as a senior engineer to describe common causes of technical debt and inconsistent designs, and how SDD addresses them. It walks through Spec Kit's **four-layer approach** (Constitution, Design, Tasks, Implementation) and discusses treating specifications as a source of truth. The post generated discussion among software architects on LinkedIn about reducing misunderstandings and rework through spec-driven workflows. [\[linkedin.com\]](https://www.linkedin.com/pulse/specification-driven-development-sdd-github-spec-kit-elevating-luz-tojmc?tl=en)
|
||||
|
||||
**Erick Matsen** (Fred Hutchinson Cancer Center) posted a detailed walkthrough on Feb 10 titled *"Spec-Driven Development with spec-kit."* He describes building a **bioinformatics pipeline** in a single day using Spec Kit's workflow (from `speckit.constitution` to `speckit.implement`). The post includes command outputs and notes on decisions made along the way, such as refining the spec to add domain-specific requirements. He writes: "I really recommend this approach. This feels like the way software development should be." [\[matsen.fredhutch.org\]](https://matsen.fredhutch.org/general/2026/02/10/spec-kit-walkthrough.html) [\[github.com\]](https://github.com/mnriem/spec-kit-dotnet-cli-demo)
|
||||
|
||||
Several other tutorials and guides appeared during the month. An article on *IntuitionLabs* (updated Feb 21) provided a guide to Spec Kit covering the philosophy behind SDD and a walkthrough of the four-phase workflow with examples. A piece by Ry Walker (Feb 22) summarized key aspects of Spec Kit, noting its agent-agnostic design and 71k-star count. Microsoft's Developer Blog post from late 2025 (*"Diving Into Spec-Driven Development with GitHub Spec Kit"* by Den Delimarsky) continued to circulate among new users. [\[intuitionlabs.ai\]](https://intuitionlabs.ai/articles/spec-driven-development-spec-kit) [\[rywalker.com\]](https://rywalker.com/research/github-spec-kit)
|
||||
|
||||
On **Feb 25**, the Cleveland C# .NET User Group hosted a session titled *"Spec Driven Development with GitHub Spec Kit."* The talk was delivered by Microsoft MVP **[Eric Boyd](https://ericboyd.com/)** (Cleveland-based .NET developer; not to be confused with the Microsoft AI Platform VP of the same name). Boyd covered how specs change an AI coding assistant's output, patterns for iterating and refining specs over multiple cycles, and moving from ad-hoc prompting to a repeatable spec-driven workflow. Other groups, including GDG Madison, also listed sessions on spec-driven development in late February and early March. [\[ericboyd.com\]](https://ericboyd.com/events/cleveland-csharp-user-group-february-25-2026-spec-driven-development-sdd-github-spec-kit)
|
||||
|
||||
On GitHub, the **Spec Kit Discussions forum** saw activity around installation troubleshooting, handling multi-feature projects with Spec Kit's branching model, and feature suggestions. One thread discussed how Spec Kit treats each spec as a short-lived artifact tied to a feature branch, which led to discussion about future support for long-running "spec of record" use cases. [\[martinfowler.com\]](https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html)
|
||||
|
||||
## SDD Ecosystem
|
||||
|
||||
Other spec-driven development tools also saw activity in February.
|
||||
|
||||
AWS **Kiro** released version 0.10 on Feb 18 with two new spec workflows: a **Design-First** mode (starting from architecture/pseudocode to derive requirements) and a **Bugfix** mode (structured root-cause analysis producing a `bugfix.md` spec file). Kiro also added hunk-level code review for AI-generated changes and pre/post task hooks for custom automation. AWS expanded Kiro to GovCloud regions on Feb 17 for government compliance use cases. [\[kiro.dev\]](https://kiro.dev/changelog/)
|
||||
|
||||
**OpenSpec** (by Fission AI), a lightweight SDD framework, reached ~29.3k stars and nearly 2k forks. Its community published guides and comparisons during the month, including *"Spec-Driven Development Made Easy: A Practical Guide with OpenSpec."* OpenSpec emphasizes simplicity and flexibility, integrating with multiple AI coding assistants via YAML configs.
|
||||
|
||||
**Tessl** remained in private beta. As described by Thoughtworks writer Birgitta Boeckeler, Tessl pursues a **spec-as-source** model where specifications are maintained long-term and directly generate code files one-to-one, with generated code labeled as "do not edit." This contrasts with Spec Kit's current approach of creating specs per feature/branch. [\[martinfowler.com\]](https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html)
|
||||
|
||||
An **arXiv preprint** (January 2026) categorized SDD implementations into three levels: *spec-first*, *spec-anchored*, and *spec-as-source*. Spec Kit was identified as primarily spec-first with elements of spec-anchored. Tech media published reviews including a *Vibe Coding* "GitHub Spec Kit Review (2026)" and a blog post titled *"Putting Spec Kit Through Its Paces: Radical Idea or Reinvented Waterfall?"* which concluded that SDD with AI assistance is more iterative than traditional Waterfall. [\[intuitionlabs.ai\]](https://intuitionlabs.ai/articles/spec-driven-development-spec-kit) [\[martinfowler.com\]](https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html)
|
||||
|
||||
## Roadmap
|
||||
|
||||
**v0.2.0** was released on March 10, 2026, consolidating the month's work. It includes new extensions (Jira, Azure DevOps, review, sync), support for multiple extension catalogs and community plugins, and additional agent integrations (Tabnine CLI, Kiro CLI). [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
|
||||
Areas under discussion or in progress for future development:
|
||||
|
||||
- **Spec lifecycle management** -- supporting longer-lived specifications that can evolve across multiple iterations, rather than being tied to a single feature branch. Users have raised this in GitHub Discussions, and the concept of "spec-anchored" development is under consideration. [\[martinfowler.com\]](https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html)
|
||||
- **CI/CD integration** -- incorporating Spec Kit verification (e.g., `speckit.checklist` or `speckit.verify`) into pull request workflows and project management tools. February's Jira and Azure DevOps extensions are a step in this direction. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
- **Continued agent support** -- adding integrations as new AI coding assistants emerge. The project currently supports over 20 agents and has been adding new ones (Kiro CLI, Tabnine CLI) as they become available. [\[github.com\]](https://github.com/github/spec-kit)
|
||||
- **Community ecosystem** -- the open extension model allows external contributors to add functionality directly. February's Jira and Azure DevOps plugins were community-contributed. The Spec Kit README now links to community walkthrough demos for .NET, Spring Boot, and other stacks. [\[github.com\]](https://github.com/github/spec-kit)
|
||||
80
newsletters/2026-March.md
Normal file
80
newsletters/2026-March.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Spec Kit - March 2026 Newsletter
|
||||
|
||||
This edition covers Spec Kit activity in March 2026. Nine releases shipped (v0.2.0 through v0.4.3), introducing a pluggable preset system, air-gapped deployment, automatic skill registration, and seven new AI agent integrations. The community extension catalog grew past 20 entries, independent walkthroughs and blog posts proliferated, and industry coverage debated whether "vibe coding" is dead. A summary is in the table below, followed by details.
|
||||
|
||||
| **Spec Kit Core (Mar 2026)** | **Community & Content** | **SDD Ecosystem & Next** |
|
||||
| --- | --- | --- |
|
||||
| Nine releases shipped with major features: multi-catalog extensions, pluggable presets, air-gapped deployment, and auto-registration of extension skills. Seven new agents added. The repo grew from ~71k to **82,616 stars**. [\[github.com\]](https://github.com/github/spec-kit/releases) | Walkthroughs by Tiago Valverde, Alfredo Perez, and Sergey Golubev. Over 20 community extensions. The Spec Kit Assistant VS Code extension was recognized as a Community Friend. A Microsoft Learn training module became available. | ByteIota reported AWS pushing SDD as the new standard. Augment Code published a Spec Kit vs. Intent comparison. Competitors differentiate on orchestration depth and living specs; Spec Kit leads in agent breadth and portability. |
|
||||
|
||||
***
|
||||
|
||||
## Spec Kit Project Updates
|
||||
|
||||
### Releases Overview
|
||||
|
||||
**v0.2.0** (March 10) opened the month with **simultaneous multi-catalog support**, enabling both core and community extension catalogs at the same time. It added **Tabnine CLI** and **Kimi Code CLI** agents, four community extensions (Understanding, Ralph, Review, Fleet Orchestrator), and `.extensionignore` support. Patch **v0.2.1** fixed broken quickstart links and added catalog CLI help. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
|
||||
**v0.3.0** (mid-March) delivered the **pluggable preset system** with catalog, resolver, and skills propagation. Presets let teams override default templates with their own conventions, using priority-based stacking. The release also added a **/selftest.extension** for testing extensions, **Mistral Vibe CLI**, migrated **Qwen Code CLI** from TOML to Markdown, and hardened bash scripts against shell injection. New community extensions included DocGuard CDD, Archive & Reconcile, specify-status, and specify-doctor. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
|
||||
**v0.3.1** added before/after hook events, JSONC deep-merge for `settings.json`, and the **Trae IDE** agent. **v0.3.2** added **Junie**, **iFlow CLI**, and **Pi Coding Agent**, plus a preset submission template and an Extension Comparison Guide. Community extensions continued arriving: verify-tasks, conduct, cognitive-squad, speckit-utils, spec-kit-iterate, and spec-kit-learn. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
|
||||
**v0.4.0** (late March) introduced **auto-registration of extension skills** — installed extensions' commands are now automatically exposed as agent skills. It also delivered **air-gapped/offline deployment** by embedding core templates in the CLI wheel and added timestamp-based branch naming. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
|
||||
Three patches closed the month. **v0.4.1** fixed a missing Assumptions section in the spec template and improved repo root detection. **v0.4.2** added AIDE, Extensify, and Presetify to the community catalog, moved the community extensions table into the main README, and recognized the **Spec Kit Assistant VS Code extension** as a Community Friend. **v0.4.3** unified skill naming conventions and restored **PowerShell 5.1 compatibility**. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
|
||||
### Bug Fixes and Security Hardening
|
||||
|
||||
The most significant fix was **shell injection hardening** of bash scripts, addressing potential vulnerabilities from unsanitized git branch names and environment variables. Other fixes included switching to **global branch numbering** for consistent sequencing, suppressing git checkout exceptions and fetch stdout leaks, properly encoding JSON control characters, and adding explicit PowerShell positional binding. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
|
||||
### The Extension Ecosystem
|
||||
|
||||
By late March, over **20 community extensions** had been built for Spec Kit. Thulasi Rajasekaran's LinkedIn article *"The Feature That Turns Spec Kit Into a Platform"* highlighted standouts: **Conduct** (orchestrates SDD phases via sub-agents to avoid context pollution), **Verify Tasks** (catches "phantom completions" — tasks marked done with no real code), **Understanding** (31 quality metrics against specs based on IEEE/ISO standards), and the **Jira and Azure DevOps integrations**. [\[linkedin.com\]](https://www.linkedin.com/pulse/feature-turns-spec-kit-platform-extensions-presets-rajasekaran-3ejgc)
|
||||
|
||||
Rajasekaran argued the real significance of presets is what they enable: the same machinery that turned "User Stories" into pirate-speak "Crew Tales" could enforce compliance requirements, add mandatory threat-model sections, or require test tasks before implementation tasks. Organizations can curate available extensions by hosting custom catalog URLs. [\[linkedin.com\]](https://www.linkedin.com/pulse/feature-turns-spec-kit-platform-extensions-presets-rajasekaran-3ejgc)
|
||||
|
||||
## Community & Content
|
||||
|
||||
### Developer Walkthroughs and Blog Posts
|
||||
|
||||
March produced a wave of independent content as developers explored SDD in practice.
|
||||
|
||||
**Tiago Valverde** published *"Spec-Driven Development in Practice: A Walkthrough with Spec Kit"* on March 14. He documents building an Instagram-style photo mural feature using the full Spec Kit workflow, contrasting it with previous ad-hoc prompting: while directly prompting Claude worked for small changes, complex work led to scope creep, ambiguous requirements discovered too late, and no artifacts left behind. Valverde recommends being specific in the initial prompt, reviewing `spec.md` immediately, and highlights the clarify step as particularly valuable. A shorter companion piece, *"The Shift from Vibe Coding to Spec-Driven Development,"* appeared on March 8. [\[tiagovalverde.com\]](https://www.tiagovalverde.com/posts/spec-driven-development-in-practice-a-walkthrough-with-spec-kit)
|
||||
|
||||
**Alfredo Perez** published *"Build Your Own SDD Workflow"* on March 21, taking a deliberately contrarian approach. He praises SDD in principle but argues the full seven-step workflow carries too much ceremony for smaller tasks. His solution is a lean **4-step custom workflow** — `specify → plan → tasks → implement` — dropping constitution, clarify, and review, wired into the **SpecKit Companion** VS Code extension. The article highlights an important tradeoff: full rigor vs. lightweight adoption. Perez also presented this workflow at an **Angular Community Meetup** on March 25. [\[alfredo-perez.dev\]](https://www.alfredo-perez.dev/blog/2026-03-21-build-your-own-sdd-workflow)
|
||||
|
||||
**Sergey Golubev** of prodfeat.ai published *"20+ SDD Frameworks: A Catalog for AI Development"* on March 17. The catalog organizes **20+ frameworks in 6 categories**, highlighting **BMAD-METHOD** (~41k stars, simulates an agile team from AI roles), **QuintCode + FPF** (preserves decision rationale via a 5-phase ADI Cycle), and **cc-sdd** (~2.9k stars, enforced SDD workflow for 8 tools). Golubev presents a three-level maturity model: *Spec-First* (spec per task, discarded after), *Spec-Anchored* (living document), and *Spec-as-Source* (spec is the only artifact). His conclusion: "SDD is not a fad… AI agents generate good code when the task is well-defined. Without a spec — you're rolling the dice." [\[prodfeat.ai\]](https://www.prodfeat.ai/en/blog/2026-03-17-sdd-frameworks-catalog)
|
||||
|
||||
### Community Tools and Documentation
|
||||
|
||||
The **Spec Kit Assistant VS Code extension** was formally recognized as a Community Friend and added to the README. The README was reorganized: community extensions table moved into the main page for discoverability, a community presets section was added, and the publishing guide gained Category and Effect columns. New walkthroughs included Java brownfield, Go/React brownfield dashboard, and the Spring Boot pirate-speak preset demo. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
|
||||
A notable community project appeared: **speckit-pipeline** by iandeherdt — a pipeline atop Spec Kit with a **design loop** (designer + critic agents iterating in a browser) and a **build loop** (developer + evaluator agents verifying against acceptance criteria). An open issue (#1966) requests a built-in pipeline command, suggesting this pattern may eventually reach core.
|
||||
|
||||
A public **Microsoft Learn** training module, *"Implement Spec-Driven Development using the GitHub Spec Kit"* (3 hours, 13 units), provided an onboarding path for enterprise developers.
|
||||
|
||||
## SDD Ecosystem & Industry Trends
|
||||
|
||||
### The "Vibe Coding Is Dead" Narrative
|
||||
|
||||
*ByteIota* published *"Spec-Driven Development Kills 'Vibe Coding'"* on March 20, reporting AWS pushing SDD as the new standard. Key claims: over 100,000 developers adopting SDD approaches in early tool previews, AWS demonstrating a two-week feature completed in two days using Kiro IDE, and WEF research indicating 65% of developers expect their role to shift toward spec-first workflows in 2026. [\[byteiota.com\]](https://byteiota.com/spec-driven-development-kills-vibe-coding-march-2026/)
|
||||
|
||||
Critics got equal space. *Marmelab* called SDD "the exact mistakes Agile was designed to solve." An *Isoform* controlled test found SDD took 33 minutes for 689 lines vs. 8 minutes with iterative prompting, with no measured quality improvement. The emerging consensus favored hybrids — a Red Hat developer captured it: "Use the vibes to explore. Use specifications to build." Other independent articles appeared from Shimon Ifrah, Raul Proenza (Cox Automotive), CGI, and Vishal Mysore. ByteIota also raised an underappreciated concern: if specs replace coding, how do juniors build the judgment to write good specs or review AI-generated code? [\[byteiota.com\]](https://byteiota.com/spec-driven-development-kills-vibe-coding-march-2026/)
|
||||
|
||||
### Competitive Landscape
|
||||
|
||||
**Augment Code** published *"Intent vs GitHub Spec Kit (2026): Platform or Framework?"* on March 31. The core tradeoff: Spec Kit's strength is **portability** across 22+ agents; Intent offers **living specs** with automated drift detection. The comparison surfaced spec drift as a key architectural concern — Spec Kit's specs can become stale post-implementation, and while community extensions address this, native real-time drift detection is not yet in core. [\[augmentcode.com\]](https://www.augmentcode.com/tools/intent-vs-github)
|
||||
|
||||
The broader landscape continued evolving. OpenSpec held ~29.3k stars, BMAD-METHOD grew to ~41k, and Tessl continued in private beta. While Spec Kit leads in GitHub popularity and agent breadth, alternatives differentiate on orchestration depth (Intent, BMAD), enforced discipline (cc-sdd), decision trails (QuintCode), and spec-as-source vision (Tessl). [\[prodfeat.ai\]](https://www.prodfeat.ai/en/blog/2026-03-17-sdd-frameworks-catalog)
|
||||
|
||||
## Roadmap
|
||||
|
||||
Areas under discussion or in progress for future development:
|
||||
|
||||
- **Spec lifecycle management** -- supporting longer-lived specifications that evolve across multiple iterations. The Augment Code comparison and community commentary highlighted "spec drift" as a key concern. The Archive & Reconcile extension (#1844) is a community step; a core solution is expected to be a focus area. [\[augmentcode.com\]](https://www.augmentcode.com/tools/intent-vs-github) [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
- **CI/CD integration** -- incorporating Spec Kit verification into pull request workflows and failing builds when specs are out of alignment. The Jira and Azure DevOps extensions (#1764, #1734) are a first step. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
- **End-to-end workflow automation** -- an open issue (#1966) proposes a built-in pipeline command. The community-built **speckit-pipeline** by iandeherdt already demonstrates multi-agent loops with browser verification. [\[github.com\]](https://github.com/iandeherdt/speckit-pipeline)
|
||||
- **Continued agent expansion** -- seven new agents were added in March alone. The agent-agnostic design means support for emerging tools can be added by anyone. [\[byteiota.com\]](https://byteiota.com/spec-driven-development-kills-vibe-coding-march-2026/)
|
||||
- **Experience simplification** -- the preset system, custom workflows, and growing walkthrough library lower the learning curve, but extension discoverability will need a more robust solution as the catalog grows. [\[github.com\]](https://github.com/github/spec-kit/releases)
|
||||
- **Toward a stable release** -- nine releases in one month reflects pre-1.0 momentum. Reaching 1.0 will require stabilizing the extension and preset APIs and ensuring backward compatibility across the agent and extension surface area. [\[github.com\]](https://github.com/github/spec-kit/blob/main/newsletters/2026-February.md)
|
||||
|
||||
|
||||
175
presets/ARCHITECTURE.md
Normal file
175
presets/ARCHITECTURE.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# Preset System Architecture
|
||||
|
||||
This document describes the internal architecture of the preset system — how template resolution, command registration, and catalog management work under the hood.
|
||||
|
||||
For usage instructions, see [README.md](README.md).
|
||||
|
||||
## Template Resolution
|
||||
|
||||
When Spec Kit needs a template (e.g. `spec-template`), the `PresetResolver` walks a priority stack and returns the first match:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["resolve_template('spec-template')"] --> B{Override exists?}
|
||||
B -- Yes --> C[".specify/templates/overrides/spec-template.md"]
|
||||
B -- No --> D{Preset provides it?}
|
||||
D -- Yes --> E[".specify/presets/‹preset-id›/templates/spec-template.md"]
|
||||
D -- No --> F{Extension provides it?}
|
||||
F -- Yes --> G[".specify/extensions/‹ext-id›/templates/spec-template.md"]
|
||||
F -- No --> H[".specify/templates/spec-template.md"]
|
||||
|
||||
E -- "multiple presets?" --> I["lowest priority number wins"]
|
||||
I --> E
|
||||
|
||||
style C fill:#4caf50,color:#fff
|
||||
style E fill:#2196f3,color:#fff
|
||||
style G fill:#ff9800,color:#fff
|
||||
style H fill:#9e9e9e,color:#fff
|
||||
```
|
||||
|
||||
| Priority | Source | Path | Use case |
|
||||
|----------|--------|------|----------|
|
||||
| 1 (highest) | Override | `.specify/templates/overrides/` | One-off project-local tweaks |
|
||||
| 2 | Preset | `.specify/presets/<id>/templates/` | Shareable, stackable customizations |
|
||||
| 3 | Extension | `.specify/extensions/<id>/templates/` | Extension-provided templates |
|
||||
| 4 (lowest) | Core | `.specify/templates/` | Shipped defaults |
|
||||
|
||||
When multiple presets are installed, they're sorted by their `priority` field (lower number = higher precedence). This is set via `--priority` on `specify preset add`.
|
||||
|
||||
The resolution is implemented three times to ensure consistency:
|
||||
- **Python**: `PresetResolver` in `src/specify_cli/presets.py`
|
||||
- **Bash**: `resolve_template()` in `scripts/bash/common.sh`
|
||||
- **PowerShell**: `Resolve-Template` in `scripts/powershell/common.ps1`
|
||||
|
||||
### Composition Strategies
|
||||
|
||||
Templates, commands, and scripts support a `strategy` field that controls how a preset's content is combined with lower-priority content instead of fully replacing it:
|
||||
|
||||
| Strategy | Description | Templates | Commands | Scripts |
|
||||
|----------|-------------|-----------|----------|---------|
|
||||
| `replace` (default) | Fully replaces lower-priority content | ✓ | ✓ | ✓ |
|
||||
| `prepend` | Places content before lower-priority content (separated by a blank line) | ✓ | ✓ | — |
|
||||
| `append` | Places content after lower-priority content (separated by a blank line) | ✓ | ✓ | — |
|
||||
| `wrap` | Content contains `{CORE_TEMPLATE}` (templates/commands) or `$CORE_SCRIPT` (scripts) placeholder replaced with lower-priority content | ✓ | ✓ | ✓ |
|
||||
|
||||
Composition is recursive — multiple composing presets chain. The `PresetResolver.resolve_content()` method walks the full priority stack bottom-up and applies each layer's strategy.
|
||||
|
||||
Content resolution functions for composition:
|
||||
- **Python**: `PresetResolver.resolve_content()` in `src/specify_cli/presets.py` (templates, commands, and scripts)
|
||||
- **Bash**: `resolve_template_content()` in `scripts/bash/common.sh` (templates only; command/script composition is handled by the Python resolver)
|
||||
- **PowerShell**: `Resolve-TemplateContent` in `scripts/powershell/common.ps1` (templates only; command/script composition is handled by the Python resolver)
|
||||
|
||||
## Command Registration
|
||||
|
||||
When a preset is installed with `type: "command"` entries, the `PresetManager` registers them into all detected agent directories using the shared `CommandRegistrar` from `src/specify_cli/agents.py`.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["specify preset add my-preset"] --> B{Preset has type: command?}
|
||||
B -- No --> Z["done (templates only)"]
|
||||
B -- Yes --> C{Extension command?}
|
||||
C -- "speckit.myext.cmd\n(3+ dot segments)" --> D{Extension installed?}
|
||||
D -- No --> E["skip (extension not active)"]
|
||||
D -- Yes --> F["register command"]
|
||||
C -- "speckit.specify\n(core command)" --> F
|
||||
F --> G["detect agent directories"]
|
||||
G --> H[".claude/commands/"]
|
||||
G --> I[".gemini/commands/"]
|
||||
G --> J[".github/agents/"]
|
||||
G --> K["... (17+ agents)"]
|
||||
H --> L["write .md (Markdown format)"]
|
||||
I --> M["write .toml (TOML format)"]
|
||||
J --> N["write .agent.md + .prompt.md"]
|
||||
|
||||
style E fill:#ff5722,color:#fff
|
||||
style L fill:#4caf50,color:#fff
|
||||
style M fill:#4caf50,color:#fff
|
||||
style N fill:#4caf50,color:#fff
|
||||
```
|
||||
|
||||
### Extension safety check
|
||||
|
||||
Command names follow the pattern `speckit.<ext-id>.<cmd-name>`. When a command has 3+ dot segments, the system extracts the extension ID and checks if `.specify/extensions/<ext-id>/` exists. If the extension isn't installed, the command is skipped — preventing orphan files referencing non-existent extensions.
|
||||
|
||||
Core commands (e.g. `speckit.specify`, with only 2 segments) are always registered.
|
||||
|
||||
### Agent format rendering
|
||||
|
||||
The `CommandRegistrar` renders commands differently per agent:
|
||||
|
||||
| Agent | Format | Extension | Arg placeholder |
|
||||
|-------|--------|-----------|-----------------|
|
||||
| Claude, Cursor, opencode, Windsurf, etc. | Markdown | `.md` | `$ARGUMENTS` |
|
||||
| Copilot | Markdown | `.agent.md` + `.prompt.md` | `$ARGUMENTS` |
|
||||
| Gemini, Qwen, Tabnine | TOML | `.toml` | `{{args}}` |
|
||||
|
||||
### Cleanup on removal
|
||||
|
||||
When `specify preset remove` is called, the registered commands are read from the registry metadata and the corresponding files are deleted from each agent directory, including Copilot companion `.prompt.md` files.
|
||||
|
||||
## Catalog System
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["specify preset search"] --> B["PresetCatalog.get_active_catalogs()"]
|
||||
B --> C{SPECKIT_PRESET_CATALOG_URL set?}
|
||||
C -- Yes --> D["single custom catalog"]
|
||||
C -- No --> E{.specify/preset-catalogs.yml exists?}
|
||||
E -- Yes --> F["project-level catalog stack"]
|
||||
E -- No --> G{"~/.specify/preset-catalogs.yml exists?"}
|
||||
G -- Yes --> H["user-level catalog stack"]
|
||||
G -- No --> I["built-in defaults"]
|
||||
I --> J["default (install allowed)"]
|
||||
I --> K["community (discovery only)"]
|
||||
|
||||
style D fill:#ff9800,color:#fff
|
||||
style F fill:#2196f3,color:#fff
|
||||
style H fill:#2196f3,color:#fff
|
||||
style J fill:#4caf50,color:#fff
|
||||
style K fill:#9e9e9e,color:#fff
|
||||
```
|
||||
|
||||
Catalogs are fetched with a 1-hour cache (per-URL, SHA256-hashed cache files). Each catalog entry has a `priority` (for merge ordering) and `install_allowed` flag.
|
||||
|
||||
## Repository Layout
|
||||
|
||||
```
|
||||
presets/
|
||||
├── ARCHITECTURE.md # This file
|
||||
├── PUBLISHING.md # Guide for submitting presets to the catalog
|
||||
├── README.md # User guide
|
||||
├── catalog.json # Official preset catalog
|
||||
├── catalog.community.json # Community preset catalog
|
||||
├── scaffold/ # Scaffold for creating new presets
|
||||
│ ├── preset.yml # Example manifest
|
||||
│ ├── README.md # Guide for customizing the scaffold
|
||||
│ ├── commands/
|
||||
│ │ ├── speckit.specify.md # Core command override example
|
||||
│ │ └── speckit.myext.myextcmd.md # Extension command override example
|
||||
│ └── templates/
|
||||
│ ├── spec-template.md # Core template override example
|
||||
│ └── myext-template.md # Extension template override example
|
||||
└── self-test/ # Self-test preset (overrides all core templates)
|
||||
├── preset.yml
|
||||
├── commands/
|
||||
│ └── speckit.specify.md
|
||||
└── templates/
|
||||
├── spec-template.md
|
||||
├── plan-template.md
|
||||
├── tasks-template.md
|
||||
├── checklist-template.md
|
||||
├── constitution-template.md
|
||||
└── agent-file-template.md
|
||||
```
|
||||
|
||||
## Module Structure
|
||||
|
||||
```
|
||||
src/specify_cli/
|
||||
├── agents.py # CommandRegistrar — shared infrastructure for writing
|
||||
│ # command files to agent directories
|
||||
├── presets.py # PresetManifest, PresetRegistry, PresetManager,
|
||||
│ # PresetCatalog, PresetCatalogEntry, PresetResolver
|
||||
└── __init__.py # CLI commands: specify preset list/add/remove/search/
|
||||
# resolve/info, specify preset catalog list/add/remove
|
||||
```
|
||||
306
presets/PUBLISHING.md
Normal file
306
presets/PUBLISHING.md
Normal file
@@ -0,0 +1,306 @@
|
||||
# Preset Publishing Guide
|
||||
|
||||
This guide explains how to publish your preset to the Spec Kit preset catalog, making it discoverable by `specify preset search`.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Prerequisites](#prerequisites)
|
||||
2. [Prepare Your Preset](#prepare-your-preset)
|
||||
3. [Submit to Catalog](#submit-to-catalog)
|
||||
4. [Verification Process](#verification-process)
|
||||
5. [Release Workflow](#release-workflow)
|
||||
6. [Best Practices](#best-practices)
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before publishing a preset, ensure you have:
|
||||
|
||||
1. **Valid Preset**: A working preset with a valid `preset.yml` manifest
|
||||
2. **Git Repository**: Preset hosted on GitHub (or other public git hosting)
|
||||
3. **Documentation**: README.md with description and usage instructions
|
||||
4. **License**: Open source license file (MIT, Apache 2.0, etc.)
|
||||
5. **Versioning**: Semantic versioning (e.g., 1.0.0)
|
||||
6. **Testing**: Preset tested on real projects with `specify preset add --dev`
|
||||
|
||||
---
|
||||
|
||||
## Prepare Your Preset
|
||||
|
||||
### 1. Preset Structure
|
||||
|
||||
Ensure your preset follows the standard structure:
|
||||
|
||||
```text
|
||||
your-preset/
|
||||
├── preset.yml # Required: Preset manifest
|
||||
├── README.md # Required: Documentation
|
||||
├── LICENSE # Required: License file
|
||||
├── CHANGELOG.md # Recommended: Version history
|
||||
│
|
||||
├── templates/ # Template overrides
|
||||
│ ├── spec-template.md
|
||||
│ ├── plan-template.md
|
||||
│ └── ...
|
||||
│
|
||||
└── commands/ # Command overrides (optional)
|
||||
└── speckit.specify.md
|
||||
```
|
||||
|
||||
Start from the [scaffold](scaffold/) if you're creating a new preset.
|
||||
|
||||
### 2. preset.yml Validation
|
||||
|
||||
Verify your manifest is valid:
|
||||
|
||||
```yaml
|
||||
schema_version: "1.0"
|
||||
|
||||
preset:
|
||||
id: "your-preset" # Unique lowercase-hyphenated ID
|
||||
name: "Your Preset Name" # Human-readable name
|
||||
version: "1.0.0" # Semantic version
|
||||
description: "Brief description (one sentence)"
|
||||
author: "Your Name or Organization"
|
||||
repository: "https://github.com/your-org/spec-kit-preset-your-preset"
|
||||
license: "MIT"
|
||||
|
||||
requires:
|
||||
speckit_version: ">=0.1.0" # Required spec-kit version
|
||||
|
||||
provides:
|
||||
templates:
|
||||
- type: "template"
|
||||
name: "spec-template"
|
||||
file: "templates/spec-template.md"
|
||||
description: "Custom spec template"
|
||||
replaces: "spec-template"
|
||||
|
||||
tags: # 2-5 relevant tags
|
||||
- "category"
|
||||
- "workflow"
|
||||
```
|
||||
|
||||
**Validation Checklist**:
|
||||
|
||||
- ✅ `id` is lowercase with hyphens only (no underscores, spaces, or special characters)
|
||||
- ✅ `version` follows semantic versioning (X.Y.Z)
|
||||
- ✅ `description` is concise (under 200 characters)
|
||||
- ✅ `repository` URL is valid and public
|
||||
- ✅ All template and command files exist in the preset directory
|
||||
- ✅ Template names are lowercase with hyphens only
|
||||
- ✅ Command names use dot notation (e.g. `speckit.specify`)
|
||||
- ✅ Tags are lowercase and descriptive
|
||||
|
||||
### 3. Test Locally
|
||||
|
||||
```bash
|
||||
# Install from local directory
|
||||
specify preset add --dev /path/to/your-preset
|
||||
|
||||
# Verify templates resolve from your preset
|
||||
specify preset resolve spec-template
|
||||
|
||||
# Verify preset info
|
||||
specify preset info your-preset
|
||||
|
||||
# List installed presets
|
||||
specify preset list
|
||||
|
||||
# Remove when done testing
|
||||
specify preset remove your-preset
|
||||
```
|
||||
|
||||
If your preset includes command overrides, verify they appear in the agent directories:
|
||||
|
||||
```bash
|
||||
# Check Claude commands (if using Claude)
|
||||
ls .claude/commands/speckit.*.md
|
||||
|
||||
# Check Copilot commands (if using Copilot)
|
||||
ls .github/agents/speckit.*.agent.md
|
||||
|
||||
# Check Gemini commands (if using Gemini)
|
||||
ls .gemini/commands/speckit.*.toml
|
||||
```
|
||||
|
||||
### 4. Create GitHub Release
|
||||
|
||||
Create a GitHub release for your preset version:
|
||||
|
||||
```bash
|
||||
# Tag the release
|
||||
git tag v1.0.0
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
||||
The release archive URL will be:
|
||||
|
||||
```text
|
||||
https://github.com/your-org/spec-kit-preset-your-preset/archive/refs/tags/v1.0.0.zip
|
||||
```
|
||||
|
||||
### 5. Test Installation from Archive
|
||||
|
||||
```bash
|
||||
specify preset add --from https://github.com/your-org/spec-kit-preset-your-preset/archive/refs/tags/v1.0.0.zip
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Submit to Catalog
|
||||
|
||||
### Understanding the Catalogs
|
||||
|
||||
Spec Kit uses a dual-catalog system:
|
||||
|
||||
- **`catalog.json`** — Official, verified presets (install allowed by default)
|
||||
- **`catalog.community.json`** — Community-contributed presets (discovery only by default)
|
||||
|
||||
All community presets should be submitted to `catalog.community.json`.
|
||||
|
||||
### 1. Fork the spec-kit Repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YOUR-USERNAME/spec-kit.git
|
||||
cd spec-kit
|
||||
```
|
||||
|
||||
### 2. Add Preset to Community Catalog
|
||||
|
||||
Edit `presets/catalog.community.json` and add your preset.
|
||||
|
||||
> **⚠️ Entries must be sorted alphabetically by preset ID.** Insert your preset in the correct position within the `"presets"` object.
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"updated_at": "2026-03-10T00:00:00Z",
|
||||
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.community.json",
|
||||
"presets": {
|
||||
"your-preset": {
|
||||
"name": "Your Preset Name",
|
||||
"description": "Brief description of what your preset provides",
|
||||
"author": "Your Name",
|
||||
"version": "1.0.0",
|
||||
"download_url": "https://github.com/your-org/spec-kit-preset-your-preset/archive/refs/tags/v1.0.0.zip",
|
||||
"repository": "https://github.com/your-org/spec-kit-preset-your-preset",
|
||||
"license": "MIT",
|
||||
"requires": {
|
||||
"speckit_version": ">=0.1.0"
|
||||
},
|
||||
"provides": {
|
||||
"templates": 3,
|
||||
"commands": 1
|
||||
},
|
||||
"tags": [
|
||||
"category",
|
||||
"workflow"
|
||||
],
|
||||
"created_at": "2026-03-10T00:00:00Z",
|
||||
"updated_at": "2026-03-10T00:00:00Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Update Community Presets Table
|
||||
|
||||
Add your preset to the Community Presets table on the docs site at `docs/community/presets.md`:
|
||||
|
||||
```markdown
|
||||
| Your Preset Name | Brief description of what your preset does | N templates, M commands[, P scripts] | — | [repo-name](https://github.com/your-org/spec-kit-preset-your-preset) |
|
||||
```
|
||||
|
||||
Insert your row in alphabetical order by preset **name** (the first column of the table).
|
||||
|
||||
### 4. Submit Pull Request
|
||||
|
||||
```bash
|
||||
git checkout -b add-your-preset
|
||||
git add presets/catalog.community.json docs/community/presets.md
|
||||
git commit -m "Add your-preset to community catalog
|
||||
|
||||
- Preset ID: your-preset
|
||||
- Version: 1.0.0
|
||||
- Author: Your Name
|
||||
- Description: Brief description
|
||||
"
|
||||
git push origin add-your-preset
|
||||
```
|
||||
|
||||
**Pull Request Checklist**:
|
||||
|
||||
```markdown
|
||||
## Preset Submission
|
||||
|
||||
**Preset Name**: Your Preset Name
|
||||
**Preset ID**: your-preset
|
||||
**Version**: 1.0.0
|
||||
**Repository**: https://github.com/your-org/spec-kit-preset-your-preset
|
||||
|
||||
### Checklist
|
||||
- [ ] Valid preset.yml manifest
|
||||
- [ ] README.md with description and usage
|
||||
- [ ] LICENSE file included
|
||||
- [ ] GitHub release created
|
||||
- [ ] Preset tested with `specify preset add --dev`
|
||||
- [ ] Templates resolve correctly (`specify preset resolve`)
|
||||
- [ ] Commands register to agent directories (if applicable)
|
||||
- [ ] Commands match template sections (command + template are coherent)
|
||||
- [ ] Added to presets/catalog.community.json
|
||||
- [ ] Added row to docs/community/presets.md table
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verification Process
|
||||
|
||||
After submission, maintainers will review:
|
||||
|
||||
1. **Manifest validation** — valid `preset.yml`, all files exist
|
||||
2. **Template quality** — templates are useful and well-structured
|
||||
3. **Command coherence** — commands reference sections that exist in templates
|
||||
4. **Security** — no malicious content, safe file operations
|
||||
5. **Documentation** — clear README explaining what the preset does
|
||||
|
||||
Once verified, `verified: true` is set and the preset appears in `specify preset search`.
|
||||
|
||||
---
|
||||
|
||||
## Release Workflow
|
||||
|
||||
When releasing a new version:
|
||||
|
||||
1. Update `version` in `preset.yml`
|
||||
2. Update CHANGELOG.md
|
||||
3. Tag and push: `git tag v1.1.0 && git push origin v1.1.0`
|
||||
4. Submit PR to update `version` and `download_url` in `presets/catalog.community.json`
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Template Design
|
||||
|
||||
- **Keep sections clear** — use headings and placeholder text the LLM can replace
|
||||
- **Match commands to templates** — if your preset overrides a command, make sure it references the sections in your template
|
||||
- **Document customization points** — use HTML comments to guide users on what to change
|
||||
|
||||
### Naming
|
||||
|
||||
- Preset IDs should be descriptive: `healthcare-compliance`, `enterprise-safe`, `startup-lean`
|
||||
- Avoid generic names: `my-preset`, `custom`, `test`
|
||||
|
||||
### Stacking
|
||||
|
||||
- Design presets to work well when stacked with others
|
||||
- Only override templates you need to change
|
||||
- Document which templates and commands your preset modifies
|
||||
|
||||
### Command Overrides
|
||||
|
||||
- Only override commands when the workflow needs to change, not just the output format
|
||||
- If you only need different template sections, a template override is sufficient
|
||||
- Test command overrides with multiple agents (Claude, Gemini, Copilot)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user