Compare commits
202 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb2b9f435a | |||
| cd02fc1bd4 | |||
| 359cbc3c91 | |||
| 00fa7bf50a | |||
| ba8de6847e | |||
| 98e9f06564 | |||
| 2f5a7a271f | |||
| 2d8ccb3eb6 | |||
| a7035b6ba7 | |||
| 8ead452b73 | |||
| 4036acbe59 | |||
| c5dc938bdf | |||
| a091bec6d4 | |||
| e9954d244b | |||
| e1cea8f958 | |||
| adee92c5e9 | |||
| daeac81e84 | |||
| 8059df8330 | |||
| f199bf3979 | |||
| d32bef5020 | |||
| 9f523b448d | |||
| fade022b55 | |||
| 289092d88f | |||
| 45f97167fd | |||
| dae6486ada | |||
| 1bf32c6537 | |||
| 199c8eb448 | |||
| 641384e794 | |||
| 48a193484e | |||
| 9b05f94c4c | |||
| 759c00556e | |||
| 4808279873 | |||
| c7d6d568d3 | |||
| 0995c55a82 | |||
| 41197c667a | |||
| 7da73aa435 | |||
| 3d83cc61b6 | |||
| 334d52bd2b | |||
| 8ff1de73d4 | |||
| d37fdf8e10 | |||
| 7ff88641c0 | |||
| b8ac5622d6 | |||
| 4df3f8594c | |||
| 56e71293d6 | |||
| 2df214cad1 | |||
| f43b84a7ef | |||
| ce4a0cb7f9 | |||
| 52e9fe2a87 | |||
| a22d67c36c | |||
| 0cb98c2a3e | |||
| e6439238d2 | |||
| 967a306ea8 | |||
| 46d09d4d45 | |||
| 13e3bd00f1 | |||
| cd6d98b99f | |||
| 358f177584 | |||
| b60bb57aa4 | |||
| 7003fca873 | |||
| b5d825356e | |||
| 896eb4fc52 | |||
| f8d7438eec | |||
| f7f4e8f95b | |||
| af76910f36 | |||
| f06111f045 | |||
| c6020b7f43 | |||
| 488b798275 | |||
| 0df19967ca | |||
| 6e04015676 | |||
| acaf9477a1 | |||
| 46a89d481a | |||
| c51428414e | |||
| 50405800c6 | |||
| 4aca056bc9 | |||
| 5e725340b4 | |||
| 3fa2064e3e | |||
| 16f9722851 | |||
| 5f0680c6c1 | |||
| 57e0197d75 | |||
| dc4bac3a85 | |||
| f16545ec36 | |||
| d132ed8e64 | |||
| 2a633d604a | |||
| 6a44c0b8ee | |||
| 3f97e34f21 | |||
| 49a8a23d75 | |||
| 1358a32476 | |||
| 9b79160c95 | |||
| 0cbe99677f | |||
| 46b1609528 | |||
| 2b0b08ceda | |||
| 19cc684433 | |||
| fecb157291 | |||
| ac84e7240e | |||
| d5d82bdb00 | |||
| f10edd6718 | |||
| 3f6cd55833 | |||
| a9e8bc4d87 | |||
| 063e0fa76e | |||
| 9e7bd33822 | |||
| 7427865e46 | |||
| ff5f9c76fd | |||
| 641bbfbe2e | |||
| 5516ec4595 | |||
| 762467efd4 | |||
| 3f54bda360 | |||
| 4d1e388a48 | |||
| 10be86587a | |||
| 6a10591413 | |||
| 321c88e05e | |||
| 23562dfa61 | |||
| cb6ebf1d69 | |||
| a006985faf | |||
| 3fce9ec082 | |||
| 03026c70cc | |||
| b75679175b | |||
| 440081016d | |||
| e8f3629c76 | |||
| c5cdc0f594 | |||
| fec417cb16 | |||
| a70a06a5fb | |||
| 0a617e1c18 | |||
| 4527f71857 | |||
| 6e0d12d145 | |||
| d471d29c72 | |||
| 0b652eec21 | |||
| b32fdf7d65 | |||
| 2da0e1eb55 | |||
| 269124a1fd | |||
| 5992f9bd19 | |||
| a53967453e | |||
| ab4b218ac7 | |||
| d5b936c88d | |||
| 07cc0e3f29 | |||
| db4a84c70f | |||
| 3048d26e66 | |||
| 8e45b2a08d | |||
| ddc4a57cd2 | |||
| d216f3c267 | |||
| 8cd881c8f1 | |||
| 2867e1d15f | |||
| c2c9d3f9cb | |||
| f734b4a3c6 | |||
| 890693efda | |||
| 5403b29261 | |||
| 8ee59f5dc1 | |||
| 5dcc35a1b3 | |||
| af70b68cd1 | |||
| e356f9b2dd | |||
| 96793de11b | |||
| bfe70f5599 | |||
| 98aedaddf0 | |||
| 496ce864d7 | |||
| 243738551c | |||
| 20f2d97f06 | |||
| b6edc1bff7 | |||
| c45613a3ad | |||
| 7efed33851 | |||
| b00a477070 | |||
| 52f2e89659 | |||
| 08db28d9d6 | |||
| 77ff0ce093 | |||
| 0ab1b1232b | |||
| 209e01bc06 | |||
| 2650b1a42e | |||
| 3595df4d9d | |||
| 5d84100c41 | |||
| dd436ad186 | |||
| b811b9188f | |||
| 9935311c35 | |||
| be0036922a | |||
| 361f9dff0d | |||
| fc160b5c5f | |||
| 9092b8a2c9 | |||
| dfe3d96313 | |||
| bcefa6a25d | |||
| 50bfeddcb5 | |||
| 8e6b8ef338 | |||
| d363eb63e2 | |||
| 422cec370d | |||
| 973b7d6f72 | |||
| 49b78f3642 | |||
| 93576e3f83 | |||
| dd7f71dd87 | |||
| 9a8492c72f | |||
| ac9bdde164 | |||
| 0b2ec64c74 | |||
| fe0a032e8e | |||
| eff8f6a6a6 | |||
| e45eab82f2 | |||
| 310ad365e6 | |||
| 0b50c66caa | |||
| 9feed0f882 | |||
| bb3301c5af | |||
| a2123274a5 | |||
| 3cbbc5387a | |||
| 4e828fbdd1 | |||
| 6d88595e0d | |||
| aa90646edf | |||
| 7235ab7c7c | |||
| a0326dae78 | |||
| 953fce2ca6 | |||
| 5035b84de5 |
+10
-7
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"enabledMcpjsonServers": ["storkit"],
|
||||
"enabledMcpjsonServers": [
|
||||
"huskies"
|
||||
],
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(./server/target/debug/storkit:*)",
|
||||
"Bash(./target/debug/storkit:*)",
|
||||
"Bash(STORKIT_PORT=*)",
|
||||
"Bash(./server/target/debug/huskies:*)",
|
||||
"Bash(./target/debug/huskies:*)",
|
||||
"Bash(HUSKIES_PORT=*)",
|
||||
"Bash(cargo build:*)",
|
||||
"Bash(cargo check:*)",
|
||||
"Bash(cargo clippy:*)",
|
||||
@@ -54,7 +56,7 @@
|
||||
"WebFetch(domain:portkey.ai)",
|
||||
"WebFetch(domain:www.shuttle.dev)",
|
||||
"WebSearch",
|
||||
"mcp__storkit__*",
|
||||
"mcp__huskies__*",
|
||||
"Edit",
|
||||
"Write",
|
||||
"Bash(find *)",
|
||||
@@ -67,7 +69,8 @@
|
||||
"Bash(tail *)",
|
||||
"Bash(wc *)",
|
||||
"Bash(npx vite:*)",
|
||||
"Bash(npm run dev:*)"
|
||||
"Bash(npm run dev:*)",
|
||||
"Bash(stat *)"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -2,9 +2,9 @@
|
||||
**/target/
|
||||
**/node_modules/
|
||||
frontend/dist/
|
||||
.storkit/worktrees/
|
||||
.storkit/logs/
|
||||
.storkit/work/6_archived/
|
||||
.huskies/worktrees/
|
||||
.huskies/logs/
|
||||
.huskies/work/6_archived/
|
||||
.git/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
+7
-3
@@ -5,10 +5,10 @@
|
||||
# Local environment (secrets)
|
||||
.env
|
||||
|
||||
# App specific (root-level; storkit subdirectory patterns live in .storkit/.gitignore)
|
||||
# App specific (root-level; huskies subdirectory patterns live in .huskies/.gitignore)
|
||||
store.json
|
||||
.storkit_port
|
||||
.storkit/bot.toml.bak
|
||||
.huskies_port
|
||||
.huskies/bot.toml.bak
|
||||
|
||||
# Rust stuff
|
||||
target
|
||||
@@ -45,3 +45,7 @@ server/target
|
||||
*.sln
|
||||
*.sw?
|
||||
/test-results/.last-run.json
|
||||
|
||||
# Ignore old story files until we feel like deleting them
|
||||
.storkit
|
||||
.storkit_port
|
||||
|
||||
@@ -23,3 +23,6 @@ token_usage.jsonl
|
||||
|
||||
# Chat service logs
|
||||
whatsapp_history.json
|
||||
|
||||
# Timers
|
||||
timers.json
|
||||
@@ -9,16 +9,22 @@
|
||||
|
||||
When you start a new session with this project:
|
||||
|
||||
1. **Check for MCP Tools:** Read `.mcp.json` to discover the MCP server endpoint. Then list available tools by calling:
|
||||
1. **Check Setup Wizard:** Call `wizard_status` to check if project setup is complete. If the wizard is not complete, guide the user through the remaining steps. Important rules for the wizard flow:
|
||||
- **Be conversational.** Don't show tool names, step numbers, or raw wizard output to the user.
|
||||
- **On projects with existing code:** Read the codebase and generate each file, then show the user what you wrote and ask if it looks right.
|
||||
- **On bare projects with no code:** Ask the user what they want to build, what language/framework they plan to use, and generate files from their answers.
|
||||
- **You must actually generate the files.** The workflow for each step is: (1) call `wizard_generate` with no args to get a hint, (2) write the file content yourself based on the conversation, (3) call `wizard_generate` again with the `content` argument containing the full file body, (4) show the user what you wrote, (5) call `wizard_confirm` (they approve), `wizard_retry` (they want changes), or `wizard_skip` (they want to skip). Do not stop after discussing — follow through and write the files.
|
||||
- **Keep moving.** After each step is confirmed, immediately proceed to the next wizard step without waiting for the user to ask.
|
||||
2. **Check for MCP Tools:** Read `.mcp.json` to discover the MCP server endpoint. Then list available tools by calling:
|
||||
```bash
|
||||
curl -s "$(jq -r '.mcpServers["storkit"].url' .mcp.json)" \
|
||||
curl -s "$(jq -r '.mcpServers["huskies"].url' .mcp.json)" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
|
||||
```
|
||||
This returns the full tool catalog (create stories, spawn agents, record tests, manage worktrees, etc.). Familiarize yourself with the available tools before proceeding. These tools allow you to directly manipulate the workflow and spawn subsidiary agents without manual file manipulation.
|
||||
2. **Read Context:** Check `.story_kit/specs/00_CONTEXT.md` for high-level project goals.
|
||||
3. **Read Stack:** Check `.story_kit/specs/tech/STACK.md` for technical constraints and patterns.
|
||||
4. **Check Work Items:** Look at `.story_kit/work/1_backlog/` and `.story_kit/work/2_current/` to see what work is pending.
|
||||
3. **Read Context:** Check `.huskies/specs/00_CONTEXT.md` for high-level project goals.
|
||||
4. **Read Stack:** Check `.huskies/specs/tech/STACK.md` for technical constraints and patterns.
|
||||
5. **Check Work Items:** Look at `.huskies/work/1_backlog/` and `.huskies/work/2_current/` to see what work is pending.
|
||||
|
||||
|
||||
---
|
||||
@@ -232,7 +238,7 @@ If a user hands you this document and says "Apply this process to my project":
|
||||
|
||||
Story Kit includes a chat bot that can be connected to one messaging platform at a time. The bot handles commands, LLM conversations, and pipeline notifications.
|
||||
|
||||
**Only one transport can be active at a time.** To configure the bot, copy the appropriate example file to `.storkit/bot.toml`:
|
||||
**Only one transport can be active at a time.** To configure the bot, copy the appropriate example file to `.huskies/bot.toml`:
|
||||
|
||||
| Transport | Example file | Webhook endpoint |
|
||||
|-----------|-------------|-----------------|
|
||||
@@ -242,7 +248,7 @@ Story Kit includes a chat bot that can be connected to one messaging platform at
|
||||
| Slack | `bot.toml.slack.example` | `/webhook/slack` |
|
||||
|
||||
```bash
|
||||
cp .storkit/bot.toml.matrix.example .storkit/bot.toml
|
||||
cp .huskies/bot.toml.matrix.example .huskies/bot.toml
|
||||
# Edit bot.toml with your credentials
|
||||
```
|
||||
|
||||
@@ -63,40 +63,62 @@ system_prompt = "You are a full-stack engineer working autonomously in a git wor
|
||||
[[agent]]
|
||||
name = "qa-2"
|
||||
stage = "qa"
|
||||
role = "Reviews coder work in worktrees: runs quality gates, generates testing plans, and reports findings."
|
||||
role = "Reviews coder work in worktrees: runs quality gates, verifies acceptance criteria, and reports findings."
|
||||
model = "sonnet"
|
||||
max_turns = 40
|
||||
max_budget_usd = 4.00
|
||||
prompt = """You are the QA agent for story {{story_id}}. Your job is to review the coder's work in the worktree and produce a structured QA report.
|
||||
prompt = """You are the QA agent for story {{story_id}}. Your job is to verify the coder's work satisfies the story's acceptance criteria and produce a structured QA report.
|
||||
|
||||
Read CLAUDE.md first, then .story_kit/README.md to understand the dev process.
|
||||
|
||||
## Your Workflow
|
||||
|
||||
### 1. Code Quality Scan
|
||||
- Run `git diff master...HEAD --stat` to see what files changed
|
||||
- Run `git diff master...HEAD` to review the actual changes for obvious coding mistakes (unused imports, dead code, unhandled errors, hardcoded values)
|
||||
- Run `cargo clippy --all-targets --all-features` and note any warnings
|
||||
### 0. Read the Story
|
||||
- Read the story file at `.huskies/work/3_qa/{{story_id}}.md`
|
||||
- Extract every acceptance criterion (the `- [ ]` checkbox lines)
|
||||
- Keep this list in mind for Step 3
|
||||
|
||||
### 1. Deterministic Gates (Prerequisites)
|
||||
Run these first — if any fail, reject immediately without proceeding to AC review:
|
||||
- Run `cargo clippy --all-targets --all-features` — must show 0 errors, 0 warnings
|
||||
- Run `cargo test` and verify all tests pass
|
||||
- If a `frontend/` directory exists:
|
||||
- Run `npm run build` and note any TypeScript errors
|
||||
- Run `npx @biomejs/biome check src/` and note any linting issues
|
||||
- Run `npm test` and verify all frontend tests pass
|
||||
|
||||
### 2. Test Verification
|
||||
- Run `cargo test` and verify all tests pass
|
||||
- If `frontend/` exists: run `npm test` and verify all frontend tests pass
|
||||
- Review test quality: look for tests that are trivial or don't assert meaningful behavior
|
||||
### 2. Code Change Review
|
||||
- Run `git diff master...HEAD --stat` to see what files changed
|
||||
- Run `git diff master...HEAD` to review the actual changes
|
||||
- Flag any incomplete implementations:
|
||||
- `todo!()`, `unimplemented!()`, `panic!()` used as stubs
|
||||
- Placeholder strings like "TODO", "FIXME", "not implemented"
|
||||
- Empty match arms or arms that just return `Default::default()`
|
||||
- Hardcoded values where real logic is expected
|
||||
- Note any obvious coding mistakes (unused imports, dead code, unhandled errors)
|
||||
|
||||
### 3. Manual Testing Support
|
||||
### 3. Acceptance Criteria Review
|
||||
For each AC extracted in Step 0:
|
||||
- Review the diff and test files to determine if the code addresses this AC
|
||||
- PASS: describe specifically how the code addresses it (which file/function/test)
|
||||
- FAIL: explain exactly what is missing or incorrect
|
||||
|
||||
An AC fails if:
|
||||
- No code change or test relates to it
|
||||
- The implementation is stubbed out (todo!/unimplemented!)
|
||||
- A test exists but doesn't actually assert the behaviour described
|
||||
|
||||
### 4. Manual Testing Support (only if all gates PASS and all ACs PASS)
|
||||
- Build the server: run `cargo build` and note success/failure
|
||||
- If build succeeds: find a free port (try 3010-3020) and attempt to start the server
|
||||
- Generate a testing plan including:
|
||||
- URL to visit in the browser
|
||||
- Things to check in the UI
|
||||
- curl commands to exercise relevant API endpoints
|
||||
- Kill the test server when done: `pkill -f 'target.*storkit' || true` (NEVER use `pkill -f storkit` — it kills the vite dev server)
|
||||
- Kill the test server when done: `pkill -f 'target.*huskies' || true` (NEVER use `pkill -f huskies` — it kills the vite dev server)
|
||||
|
||||
### 4. Produce Structured Report
|
||||
Print your QA report to stdout before your process exits. The server will automatically run acceptance gates. Use this format:
|
||||
### 5. Produce Structured Report and Verdict
|
||||
Print your QA report to stdout. Then call `approve_qa` or `reject_qa` via the MCP tool based on the overall result. Use this format:
|
||||
|
||||
```
|
||||
## QA Report for {{story_id}}
|
||||
@@ -105,27 +127,38 @@ Print your QA report to stdout before your process exits. The server will automa
|
||||
- clippy: PASS/FAIL (details)
|
||||
- TypeScript build: PASS/FAIL/SKIP (details)
|
||||
- Biome lint: PASS/FAIL/SKIP (details)
|
||||
- Code review findings: (list any issues found, or "None")
|
||||
|
||||
### Test Verification
|
||||
- cargo test: PASS/FAIL (N tests)
|
||||
- npm test: PASS/FAIL/SKIP (N tests)
|
||||
- Test quality issues: (list any trivial/weak tests, or "None")
|
||||
- Incomplete implementations: (list any todo!/unimplemented!/stubs found, or "None")
|
||||
- Other code review findings: (list any issues found, or "None")
|
||||
|
||||
### Acceptance Criteria Review
|
||||
- AC: <criterion text>
|
||||
Result: PASS/FAIL
|
||||
Evidence: <how the code addresses it, or what is missing>
|
||||
|
||||
(repeat for each AC)
|
||||
|
||||
### Manual Testing Plan
|
||||
- Server URL: http://localhost:PORT (or "Build failed")
|
||||
- Pages to visit: (list)
|
||||
- Things to check: (list)
|
||||
- curl commands: (list)
|
||||
- Server URL: http://localhost:PORT (or "Skipped — gate/AC failure" or "Build failed")
|
||||
- Pages to visit: (list, or "N/A")
|
||||
- Things to check: (list, or "N/A")
|
||||
- curl commands: (list, or "N/A")
|
||||
|
||||
### Overall: PASS/FAIL
|
||||
Reason: (summary of why it passed or the primary reason it failed)
|
||||
```
|
||||
|
||||
After printing the report:
|
||||
- If Overall is PASS: call `approve_qa(story_id='{{story_id}}')` via MCP
|
||||
- If Overall is FAIL: call `reject_qa(story_id='{{story_id}}', notes='<concise reason>')` via MCP so the coder knows exactly what to fix
|
||||
|
||||
## Rules
|
||||
- Do NOT modify any code — read-only review only
|
||||
- If the server fails to start, still provide the testing plan with curl commands
|
||||
- The server automatically runs acceptance gates when your process exits"""
|
||||
system_prompt = "You are a QA agent. Your job is read-only: review code quality, run tests, try to start the server, and produce a structured QA report. Do not modify code. The server automatically runs acceptance gates when your process exits."
|
||||
- Gates must pass before AC review — a gate failure is an automatic reject
|
||||
- If any AC is not met, the overall result is FAIL
|
||||
- Always call approve_qa or reject_qa — never leave the story without a verdict"""
|
||||
system_prompt = "You are a QA agent. Your job is read-only: run quality gates, verify each acceptance criterion against the diff, and produce a structured QA report. Always call approve_qa or reject_qa via MCP to record your verdict. Do not modify code."
|
||||
|
||||
[[agent]]
|
||||
name = "coder-opus"
|
||||
@@ -140,40 +173,62 @@ system_prompt = "You are a senior full-stack engineer working autonomously in a
|
||||
[[agent]]
|
||||
name = "qa"
|
||||
stage = "qa"
|
||||
role = "Reviews coder work in worktrees: runs quality gates, generates testing plans, and reports findings."
|
||||
role = "Reviews coder work in worktrees: runs quality gates, verifies acceptance criteria, and reports findings."
|
||||
model = "sonnet"
|
||||
max_turns = 40
|
||||
max_budget_usd = 4.00
|
||||
prompt = """You are the QA agent for story {{story_id}}. Your job is to review the coder's work in the worktree and produce a structured QA report.
|
||||
prompt = """You are the QA agent for story {{story_id}}. Your job is to verify the coder's work satisfies the story's acceptance criteria and produce a structured QA report.
|
||||
|
||||
Read CLAUDE.md first, then .story_kit/README.md to understand the dev process.
|
||||
|
||||
## Your Workflow
|
||||
|
||||
### 1. Code Quality Scan
|
||||
- Run `git diff master...HEAD --stat` to see what files changed
|
||||
- Run `git diff master...HEAD` to review the actual changes for obvious coding mistakes (unused imports, dead code, unhandled errors, hardcoded values)
|
||||
- Run `cargo clippy --all-targets --all-features` and note any warnings
|
||||
### 0. Read the Story
|
||||
- Read the story file at `.huskies/work/3_qa/{{story_id}}.md`
|
||||
- Extract every acceptance criterion (the `- [ ]` checkbox lines)
|
||||
- Keep this list in mind for Step 3
|
||||
|
||||
### 1. Deterministic Gates (Prerequisites)
|
||||
Run these first — if any fail, reject immediately without proceeding to AC review:
|
||||
- Run `cargo clippy --all-targets --all-features` — must show 0 errors, 0 warnings
|
||||
- Run `cargo test` and verify all tests pass
|
||||
- If a `frontend/` directory exists:
|
||||
- Run `npm run build` and note any TypeScript errors
|
||||
- Run `npx @biomejs/biome check src/` and note any linting issues
|
||||
- Run `npm test` and verify all frontend tests pass
|
||||
|
||||
### 2. Test Verification
|
||||
- Run `cargo test` and verify all tests pass
|
||||
- If `frontend/` exists: run `npm test` and verify all frontend tests pass
|
||||
- Review test quality: look for tests that are trivial or don't assert meaningful behavior
|
||||
### 2. Code Change Review
|
||||
- Run `git diff master...HEAD --stat` to see what files changed
|
||||
- Run `git diff master...HEAD` to review the actual changes
|
||||
- Flag any incomplete implementations:
|
||||
- `todo!()`, `unimplemented!()`, `panic!()` used as stubs
|
||||
- Placeholder strings like "TODO", "FIXME", "not implemented"
|
||||
- Empty match arms or arms that just return `Default::default()`
|
||||
- Hardcoded values where real logic is expected
|
||||
- Note any obvious coding mistakes (unused imports, dead code, unhandled errors)
|
||||
|
||||
### 3. Manual Testing Support
|
||||
### 3. Acceptance Criteria Review
|
||||
For each AC extracted in Step 0:
|
||||
- Review the diff and test files to determine if the code addresses this AC
|
||||
- PASS: describe specifically how the code addresses it (which file/function/test)
|
||||
- FAIL: explain exactly what is missing or incorrect
|
||||
|
||||
An AC fails if:
|
||||
- No code change or test relates to it
|
||||
- The implementation is stubbed out (todo!/unimplemented!)
|
||||
- A test exists but doesn't actually assert the behaviour described
|
||||
|
||||
### 4. Manual Testing Support (only if all gates PASS and all ACs PASS)
|
||||
- Build the server: run `cargo build` and note success/failure
|
||||
- If build succeeds: find a free port (try 3010-3020) and attempt to start the server
|
||||
- Generate a testing plan including:
|
||||
- URL to visit in the browser
|
||||
- Things to check in the UI
|
||||
- curl commands to exercise relevant API endpoints
|
||||
- Kill the test server when done: `pkill -f 'target.*storkit' || true` (NEVER use `pkill -f storkit` — it kills the vite dev server)
|
||||
- Kill the test server when done: `pkill -f 'target.*huskies' || true` (NEVER use `pkill -f huskies` — it kills the vite dev server)
|
||||
|
||||
### 4. Produce Structured Report
|
||||
Print your QA report to stdout before your process exits. The server will automatically run acceptance gates. Use this format:
|
||||
### 5. Produce Structured Report and Verdict
|
||||
Print your QA report to stdout. Then call `approve_qa` or `reject_qa` via the MCP tool based on the overall result. Use this format:
|
||||
|
||||
```
|
||||
## QA Report for {{story_id}}
|
||||
@@ -182,27 +237,38 @@ Print your QA report to stdout before your process exits. The server will automa
|
||||
- clippy: PASS/FAIL (details)
|
||||
- TypeScript build: PASS/FAIL/SKIP (details)
|
||||
- Biome lint: PASS/FAIL/SKIP (details)
|
||||
- Code review findings: (list any issues found, or "None")
|
||||
|
||||
### Test Verification
|
||||
- cargo test: PASS/FAIL (N tests)
|
||||
- npm test: PASS/FAIL/SKIP (N tests)
|
||||
- Test quality issues: (list any trivial/weak tests, or "None")
|
||||
- Incomplete implementations: (list any todo!/unimplemented!/stubs found, or "None")
|
||||
- Other code review findings: (list any issues found, or "None")
|
||||
|
||||
### Acceptance Criteria Review
|
||||
- AC: <criterion text>
|
||||
Result: PASS/FAIL
|
||||
Evidence: <how the code addresses it, or what is missing>
|
||||
|
||||
(repeat for each AC)
|
||||
|
||||
### Manual Testing Plan
|
||||
- Server URL: http://localhost:PORT (or "Build failed")
|
||||
- Pages to visit: (list)
|
||||
- Things to check: (list)
|
||||
- curl commands: (list)
|
||||
- Server URL: http://localhost:PORT (or "Skipped — gate/AC failure" or "Build failed")
|
||||
- Pages to visit: (list, or "N/A")
|
||||
- Things to check: (list, or "N/A")
|
||||
- curl commands: (list, or "N/A")
|
||||
|
||||
### Overall: PASS/FAIL
|
||||
Reason: (summary of why it passed or the primary reason it failed)
|
||||
```
|
||||
|
||||
After printing the report:
|
||||
- If Overall is PASS: call `approve_qa(story_id='{{story_id}}')` via MCP
|
||||
- If Overall is FAIL: call `reject_qa(story_id='{{story_id}}', notes='<concise reason>')` via MCP so the coder knows exactly what to fix
|
||||
|
||||
## Rules
|
||||
- Do NOT modify any code — read-only review only
|
||||
- If the server fails to start, still provide the testing plan with curl commands
|
||||
- The server automatically runs acceptance gates when your process exits"""
|
||||
system_prompt = "You are a QA agent. Your job is read-only: review code quality, run tests, try to start the server, and produce a structured QA report. Do not modify code. The server automatically runs acceptance gates when your process exits."
|
||||
- Gates must pass before AC review — a gate failure is an automatic reject
|
||||
- If any AC is not met, the overall result is FAIL
|
||||
- Always call approve_qa or reject_qa — never leave the story without a verdict"""
|
||||
system_prompt = "You are a QA agent. Your job is read-only: run quality gates, verify each acceptance criterion against the diff, and produce a structured QA report. Always call approve_qa or reject_qa via MCP to record your verdict. Do not modify code."
|
||||
|
||||
[[agent]]
|
||||
name = "mergemaster"
|
||||
@@ -1,4 +1,4 @@
|
||||
# Example project.toml — copy to .storkit/project.toml and customise.
|
||||
# Example project.toml — copy to .huskies/project.toml and customise.
|
||||
# This file is checked in; project.toml itself is gitignored (it may contain
|
||||
# instance-specific settings).
|
||||
|
||||
@@ -37,7 +37,7 @@ max_turns = 50
|
||||
max_budget_usd = 5.00
|
||||
prompt = """
|
||||
You are working in a git worktree on story {{story_id}}.
|
||||
Read CLAUDE.md first, then .storkit/README.md to understand the dev process.
|
||||
Read CLAUDE.md first, then .huskies/README.md to understand the dev process.
|
||||
Run: cd "{{worktree_path}}" && git difftool {{base_branch}}...HEAD
|
||||
Commit all your work before your process exits.
|
||||
"""
|
||||
@@ -6,7 +6,7 @@ Slack integration is configured via `bot.toml` in the project's `.story_kit/` di
|
||||
|
||||
```toml
|
||||
transport = "slack"
|
||||
display_name = "Storkit"
|
||||
display_name = "Huskies"
|
||||
slack_bot_token = "xoxb-..."
|
||||
slack_signing_secret = "..."
|
||||
slack_channel_ids = ["C01ABCDEF"]
|
||||
@@ -29,11 +29,11 @@ Slash commands provide quick access to pipeline commands without mentioning the
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/storkit-status` | Show pipeline status and agent availability |
|
||||
| `/storkit-cost` | Show token spend: 24h total, top stories, and breakdown |
|
||||
| `/storkit-show` | Display the full text of a work item (e.g. `/storkit-show 42`) |
|
||||
| `/storkit-git` | Show git status: branch, changes, ahead/behind |
|
||||
| `/storkit-htop` | Show system and agent process dashboard |
|
||||
| `/huskies-status` | Show pipeline status and agent availability |
|
||||
| `/huskies-cost` | Show token spend: 24h total, top stories, and breakdown |
|
||||
| `/huskies-show` | Display the full text of a work item (e.g. `/huskies-show 42`) |
|
||||
| `/huskies-git` | Show git status: branch, changes, ahead/behind |
|
||||
| `/huskies-htop` | Show system and agent process dashboard |
|
||||
|
||||
All slash command responses are **ephemeral** — only the user who invoked the command sees the response.
|
||||
|
||||
@@ -118,8 +118,8 @@ To support both Remote and Local models, the system implements a `ModelProvider`
|
||||
|
||||
Multiple instances can run simultaneously in different worktrees. To avoid port conflicts:
|
||||
|
||||
- **Backend:** Set `STORKIT_PORT` to a unique port (default is 3001). Example: `STORKIT_PORT=3002 cargo run`
|
||||
- **Frontend:** Run `npm run dev` from `frontend/`. It auto-selects the next unused port. It reads `STORKIT_PORT` to know which backend to talk to, so export it before running: `export STORKIT_PORT=3002 && cd frontend && npm run dev`
|
||||
- **Backend:** Set `HUSKIES_PORT` to a unique port (default is 3001). Example: `HUSKIES_PORT=3002 cargo run`
|
||||
- **Frontend:** Run `npm run dev` from `frontend/`. It auto-selects the next unused port. It reads `HUSKIES_PORT` to know which backend to talk to, so export it before running: `export HUSKIES_PORT=3002 && cd frontend && npm run dev`
|
||||
|
||||
When running in a worktree, use a port that won't conflict with the main instance (3001). Ports 3002+ are good choices.
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
---
|
||||
name: "Fly.io Machines API integration for multi-tenant storkit SaaS"
|
||||
name: "Fly.io Machines API integration for multi-tenant huskies SaaS"
|
||||
---
|
||||
|
||||
# Spike 408: Fly.io Machines API integration for multi-tenant storkit SaaS
|
||||
# Spike 408: Fly.io Machines API integration for multi-tenant huskies SaaS
|
||||
|
||||
## Question
|
||||
|
||||
@@ -28,7 +28,7 @@ A thin Rust service using `reqwest` for the Machines API and `axum` for the reve
|
||||
- [ ] Test attaching a persistent volume to a machine and verify it persists across stop/start
|
||||
- [ ] Test secret injection — pass a dummy `credentials.json` as a Fly secret and verify it's readable inside the machine
|
||||
- [ ] Sketch the auth proxy: JWT validation → machine lookup → reverse proxy to machine's private IP; verify WebSocket proxying works
|
||||
- [ ] Measure actual cold start time for a minimal storkit container image
|
||||
- [ ] Measure actual cold start time for a minimal huskies container image
|
||||
- [ ] Document any API quirks, rate limits, or sharp edges discovered during testing
|
||||
|
||||
## Findings
|
||||
+2
-2
@@ -6,13 +6,13 @@ name: "Multi-account OAuth token rotation on rate limit"
|
||||
|
||||
## User Story
|
||||
|
||||
As a storkit user with multiple Claude Max subscriptions, I want the system to automatically rotate to a different account when one gets rate limited, so that agents and chat don't stall out waiting for limits to reset.
|
||||
As a huskies user with multiple Claude Max subscriptions, I want the system to automatically rotate to a different account when one gets rate limited, so that agents and chat don't stall out waiting for limits to reset.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] OAuth login flow stores credentials per-account (keyed by email), not overwriting previous accounts
|
||||
- [ ] GET /oauth/status returns all stored accounts and their status (active, rate-limited, expired)
|
||||
- [ ] When the active account hits a rate limit, storkit automatically swaps to the next available account's refresh token, refreshes, and retries
|
||||
- [ ] When the active account hits a rate limit, huskies automatically swaps to the next available account's refresh token, refreshes, and retries
|
||||
- [ ] The bot sends a notification in Matrix/WhatsApp when it swaps accounts
|
||||
- [ ] If all accounts are rate limited, the bot surfaces a clear message with the time until the earliest reset
|
||||
- [ ] A new /oauth/authorize login adds to the account pool rather than replacing the current credentials
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: "Unblock command handles all stuck states not just blocked flag"
|
||||
---
|
||||
|
||||
# Story 435: Unblock command handles all stuck states not just blocked flag
|
||||
|
||||
## User Story
|
||||
|
||||
As a project owner, I want the unblock command to clear any stuck state on a story — not just the blocked flag — so that I have a single command to unstick stories regardless of why they're stuck.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Unblock clears merge_failure field in addition to blocked flag
|
||||
- [ ] Unblock clears review_hold field
|
||||
- [ ] Unblock reports which fields were cleared in the confirmation message
|
||||
- [ ] Unblock works on stories in any pipeline stage (backlog, current, qa, merge, done)
|
||||
- [ ] If no stuck state is found (no blocked, merge_failure, or review_hold), returns a clear message saying so
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- TBD
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: "Unify story stuck states into a single status field"
|
||||
---
|
||||
|
||||
# Refactor 436: Unify story stuck states into a single status field
|
||||
|
||||
## Current State
|
||||
|
||||
- TBD
|
||||
|
||||
## Desired State
|
||||
|
||||
Replace the separate blocked, merge_failure, and review_hold front matter fields with a single status field (e.g. status: blocked, status: merge_failure, status: review_hold). Simplifies the unblock command, auto-assign checks, and pipeline advance logic.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Replace blocked: true, merge_failure: string, and review_hold: true with a single status: field in story front matter
|
||||
- [ ] Auto-assign checks a single field instead of three separate ones
|
||||
- [ ] Pipeline advance and lifecycle code reads/writes the unified status field
|
||||
- [ ] Unblock command clears the status field regardless of which stuck state it was
|
||||
- [ ] retry_count remains a separate field (it's a counter, not a state)
|
||||
- [ ] Migration: existing stories with old fields are handled gracefully on read
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- TBD
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: "Rename project from \"huskies\" to \"huskies\""
|
||||
---
|
||||
|
||||
# Story 455: Rename project from "huskies" to "huskies"
|
||||
|
||||
## User Story
|
||||
|
||||
As a project maintainer, I want to rename the project from \"huskies\" to \"huskies\" so that the product has its new identity throughout the codebase, tooling, and documentation. The new domain is huskies.dev — update all references to huskies.dev accordingly (website, contact email hello@huskies.dev, etc).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Rust crate name in server/Cargo.toml changed from 'huskies' to 'huskies'
|
||||
- [ ] Binary name changed to 'huskies' (Dockerfile CMD, release script binary names)
|
||||
- [ ] Environment variables renamed: STORKIT_PORT → HUSKIES_PORT, STORKIT_HOST → HUSKIES_HOST
|
||||
- [ ] Docker service name, container_name, image name, and volume names updated in docker-compose.yml
|
||||
- [ ] Docker user/group renamed from 'huskies' to 'huskies' in Dockerfile (groupadd, useradd, home dir /home/huskies/.claude)
|
||||
- [ ] MCP server registration renamed from 'huskies' to 'huskies' in scaffold-generated .mcp.json and in server/src/http/mcp/mod.rs serverInfo name
|
||||
- [ ] All 35+ MCP tool permission patterns updated from mcp__huskies__* to mcp__huskies__* across code and permission configs
|
||||
- [ ] The .huskies/ project directory marker renamed to .huskies/ throughout all Rust source (paths.rs, config.rs, scaffold.rs, watcher.rs, prompts.rs, and all agent/pipeline code)
|
||||
- [ ] Release script updated: Gitea repo path dave/huskies → dave/huskies, changelog regex updated to match ^(huskies|huskies|story-kit): for backwards-compatible history parsing, binary artifact names updated
|
||||
- [ ] Git commit prefix convention updated from 'huskies:' to 'huskies:' in huskies README and agent prompts
|
||||
- [ ] Website updated: page title, headings, and contact email (hello@huskies.dev) if domain changes
|
||||
- [ ] README.md updated: all CLI examples use 'huskies' binary name, all .huskies/ references become .huskies/
|
||||
- [ ] A migration path exists for existing installs: either huskies auto-detects and migrates .huskies/ → .huskies/, or a migration script (script/migrate) is provided
|
||||
- [ ] All Claude Code .mcp.json files in existing worktrees are regenerated via scaffold or migration
|
||||
- [ ] Gitea repository renamed from dave/huskies to dave/huskies (external action required, noted in story)
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- TBD
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
---
|
||||
name: "Stage transition notifications can arrive out of order and show wrong story name"
|
||||
agent: coder-opus
|
||||
---
|
||||
|
||||
# Bug 462: Stage transition notifications can arrive out of order and show wrong story name
|
||||
|
||||
## Description
|
||||
|
||||
When a story moves through stages quickly (e.g. QA → Merge → Done), the stage transition notifications can arrive out of order in Matrix chat. The Done notification appears before the Merge notification.
|
||||
|
||||
Two issues:
|
||||
|
||||
1. **Out-of-order delivery**: When two notifications are sent close together, the Matrix homeserver can deliver them in the wrong order. The notification handler processes events sequentially and awaits each send, but the homeserver does not guarantee ordering for near-simultaneous messages.
|
||||
|
||||
2. **Missing story name on stale notifications**: The second notification shows the raw item_id instead of the story name because `read_story_name` looks in the stage directory from the event (e.g. `4_merge/`), but the file has already moved to the next stage (e.g. `5_done/`).
|
||||
|
||||
3. **`inferred_from_stage` guesses the source stage** instead of tracking the actual from-stage. This means skipped stages would show incorrect transitions.
|
||||
|
||||
## How to Reproduce
|
||||
|
||||
1. Have a story in QA that passes quickly
|
||||
2. Story moves QA → Merge → Done in rapid succession
|
||||
3. Observe notifications in Matrix
|
||||
|
||||
## Actual Result
|
||||
|
||||
Notifications arrive in wrong order (Done before Merge). The later notification shows the raw item_id instead of the story name:
|
||||
|
||||
🎉 #32 upgrade TypeScript... — Merge → Done
|
||||
#32 32_story_upgrade_typescript_and_tsconfig... — QA → Merge
|
||||
|
||||
## Expected Result
|
||||
|
||||
Notifications arrive in chronological order. All notifications show the story name. Ideally, rapid transitions are coalesced into a single notification for the final stage.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] read_story_name falls back to searching all stages when the expected stage directory has no match
|
||||
- [ ] Consider deduplicating rapid transitions within a short window (e.g. only notify for the final stage)
|
||||
- [ ] Track actual from-stage in WatcherEvent instead of guessing via inferred_from_stage
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: "Configurable rate limit notification suppression"
|
||||
---
|
||||
|
||||
# Story 463: Configurable rate limit notification suppression
|
||||
|
||||
## User Story
|
||||
|
||||
As a ..., I want ..., so that ...
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] New boolean config field in project.toml (e.g. rate_limit_notifications) defaults to true
|
||||
- [ ] When false, RateLimitWarning chat notifications are suppressed
|
||||
- [ ] RateLimitHardBlock and StoryBlocked notifications are always sent regardless of the setting
|
||||
- [ ] Stage transition notifications are unaffected
|
||||
- [ ] Config is hot-reloaded when project.toml changes
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- TBD
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: "Timer rejects backlog stories — should move to current on fire"
|
||||
---
|
||||
|
||||
# Bug 464: Timer rejects backlog stories — should move to current on fire
|
||||
|
||||
## Description
|
||||
|
||||
The `timer` bot command requires stories to be in `work/2_current/` before scheduling. When a user tries to schedule a backlog story (e.g. `timer 463 12:45`), it returns:
|
||||
|
||||
"Story **463_story_...** is not in `work/2_current/`. Move it to current before scheduling a timer."
|
||||
|
||||
The timer should accept backlog stories. When the timer fires, it should move the story from backlog to current and let auto-assign start an agent.
|
||||
|
||||
## How to Reproduce
|
||||
|
||||
1. Have a story in backlog (e.g. 463)
|
||||
2. Run `timer 463 12:45`
|
||||
3. Observe rejection message
|
||||
|
||||
## Actual Result
|
||||
|
||||
Timer command rejects stories not in `work/2_current/`.
|
||||
|
||||
## Expected Result
|
||||
|
||||
Timer command accepts backlog stories. When the timer fires, it moves the story to current and auto-assign picks it up.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Timer bot command accepts stories in backlog or current
|
||||
- [ ] Timer tick loop calls move_story_to_current before start_agent for backlog stories
|
||||
- [ ] Unit tests cover scheduling and firing for backlog stories
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: "Timer tick loop never fires due entries"
|
||||
agent: coder-opus
|
||||
---
|
||||
|
||||
# Bug 465: Timer tick loop never fires due entries
|
||||
|
||||
## Description
|
||||
|
||||
The timer tick loop (`spawn_timer_tick_loop`) is spawned by the Matrix bot runner, the Matrix bot is confirmed running (processing messages), but timers never fire. Past-due entries remain in `.huskies/timers.json` indefinitely — `take_due` never consumes them.
|
||||
|
||||
The tick loop uses `tokio::spawn` which swallows panics silently. If `move_story_to_current` or `start_agent` panics on the first tick (when all past-due entries fire at once), the entire task dies with no log output. The PTY debug spam may also push any `[timer]` log entries out of the ring buffer.
|
||||
|
||||
The bot command successfully adds entries to the in-memory store and persists them to disk, but the tick loop never processes them.
|
||||
|
||||
## How to Reproduce
|
||||
|
||||
1. Set a timer via bot command: `timer 463 HH:MM` (a time in the near future)
|
||||
2. Wait past the scheduled time
|
||||
3. Check `.huskies/timers.json` — entries are still present
|
||||
4. Check server logs for `[timer]` — no entries found
|
||||
|
||||
## Actual Result
|
||||
|
||||
Timer entries remain in timers.json indefinitely. No `[timer] Timer fired` log entries appear. The story is never moved to current and no agent is started.
|
||||
|
||||
## Expected Result
|
||||
|
||||
Within 30 seconds of the scheduled time, the tick loop should call `take_due`, remove the entry from disk, move the story to current (if in backlog), and start an agent.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Add panic-catching (catch_unwind or tokio CancellationToken) to the tick loop so failures are logged
|
||||
- [ ] Add a startup log line confirming the tick loop is running and how many pending timers were loaded
|
||||
- [ ] Verify take_due runs on each 30-second tick by adding periodic debug logging
|
||||
- [ ] Integration test: create a past-due timer entry, run the tick loop, assert the entry is consumed
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: "Configurable timezone in project.toml for timer scheduling"
|
||||
---
|
||||
|
||||
# Story 466: Configurable timezone in project.toml for timer scheduling
|
||||
|
||||
## User Story
|
||||
|
||||
As a user running huskies in a container where TZ defaults to UTC, I want to configure my project's timezone in project.toml so that timer HH:MM inputs are interpreted in my actual timezone.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Add a `timezone` field to project.toml (e.g. `timezone = "Europe/London"`)
|
||||
- [ ] next_occurrence_of_hhmm uses the configured timezone instead of chrono::Local
|
||||
- [ ] Falls back to chrono::Local if no timezone is configured
|
||||
- [ ] Timer confirmation message displays the time in the configured timezone
|
||||
- [ ] timer list command shows times in the configured timezone
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- TBD
|
||||
+1
-1
@@ -10,7 +10,7 @@ The `prompt_permission` MCP tool returns plain text ("Permission granted for '..
|
||||
|
||||
## How to Reproduce
|
||||
|
||||
1. Start the storkit server and open the web UI
|
||||
1. Start the huskies server and open the web UI
|
||||
2. Chat with the claude-code-pty model
|
||||
3. Ask it to do something that requires a tool NOT in `.claude/settings.json` allow list (e.g. `wc -l /etc/hosts`, or WebFetch to a non-allowed domain)
|
||||
4. The permission dialog appears — click Approve
|
||||
+1
-1
@@ -6,7 +6,7 @@ name: "Retry limit for mergemaster and pipeline restarts"
|
||||
|
||||
## User Story
|
||||
|
||||
As a developer using storkit, I want pipeline auto-restarts to have a configurable retry limit so that failing agents don't loop infinitely consuming CPU and API credits.
|
||||
As a developer using huskies, I want pipeline auto-restarts to have a configurable retry limit so that failing agents don't loop infinitely consuming CPU and API credits.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ The watcher should periodically check `5_done/` and move items older than 4 hour
|
||||
- All MCP tools and pipeline logic that reference `5_archived` need updating to use `5_done`
|
||||
- Frontend pipeline display if it shows archived/done items
|
||||
- `.story_kit/README.md`: update pipeline stage documentation
|
||||
- Story 116's init scaffolding: `storkit init` must create `5_done/` and `6_archived/` directories
|
||||
- Story 116's init scaffolding: `huskies init` must create `5_done/` and `6_archived/` directories
|
||||
- Any templates or scaffold code that creates the `.story_kit/work/` directory structure
|
||||
|
||||
## Acceptance Criteria
|
||||
@@ -35,7 +35,7 @@ The watcher should periodically check `5_done/` and move items older than 4 hour
|
||||
- [ ] Existing items in old `5_archived/` are migrated to `6_archived/`
|
||||
- [ ] Frontend pipeline display updated if applicable
|
||||
- [ ] `.story_kit/README.md` updated to reflect the new pipeline stages
|
||||
- [ ] `storkit init` scaffolding creates `5_done/` and `6_archived/` (coordinate with story 116)
|
||||
- [ ] `huskies init` scaffolding creates `5_done/` and `6_archived/` (coordinate with story 116)
|
||||
|
||||
## Out of Scope
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user