feat: TaskBundle — task file + directory of additionals
Pattern: task name maps to file + bundle directory
task/code/review.md ← the task definition
task/code/review/ ← additional context files
conventions.md ← checklist
severity.md ← rating guide
plan.yaml ← structured phases
TaskBundle("code/review") returns (main, bundle, err)
where bundle is map[filename]content of everything in review/.
Agent name maps to lib path:
core:agent-task-code-review → lib/task/code/review + review/
Converted code/ tasks from YAML plans to markdown task prompts
with optional bundles. Simplifier gets patterns.md bundle.
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
aed8226edd
commit
e7b47bf1a0
14 changed files with 186 additions and 153 deletions
10
pkg/prompts/lib/task/code/dead-code.md
Normal file
10
pkg/prompts/lib/task/code/dead-code.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Dead Code Scan
|
||||
|
||||
Find and remove unreachable code, unused functions, and orphaned files.
|
||||
|
||||
## Process
|
||||
|
||||
1. `go vet ./...` for compiler-detected dead code
|
||||
2. Search for unexported functions with zero callers
|
||||
3. Check for unreachable branches (always-true conditions)
|
||||
4. Verify before deleting — some code is used via reflection or build tags
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
name: Dead Code Scan
|
||||
description: Find unreachable functions, unused exports, and orphaned files
|
||||
category: audit
|
||||
|
||||
guidelines:
|
||||
- Only flag code that is genuinely unused, not just potentially unused
|
||||
- Check go.work and cross-repo imports before flagging exports as unused
|
||||
- Orphaned files include leftover migrations, unused configs, stale test fixtures
|
||||
|
||||
phases:
|
||||
- name: Unused Exports
|
||||
description: Find exported functions/types with no callers
|
||||
tasks:
|
||||
- "List all exported functions and types"
|
||||
- "Search for callers within the package and known consumers"
|
||||
- "Flag exports with zero callers (check CONSUMERS.md for cross-repo usage)"
|
||||
|
||||
- name: Dead Functions
|
||||
description: Find unexported functions with no internal callers
|
||||
tasks:
|
||||
- "List unexported (lowercase) functions"
|
||||
- "Check for callers within the same package"
|
||||
- "Flag functions with zero callers"
|
||||
|
||||
- name: Orphaned Files
|
||||
description: Find files that serve no purpose
|
||||
tasks:
|
||||
- "Check for .go files not imported by any other file in the package"
|
||||
- "Check for test fixtures not referenced by any test"
|
||||
- "Check for config files not loaded by any code"
|
||||
- "Check for documentation files referencing deleted code"
|
||||
|
||||
- name: Report
|
||||
description: Document findings
|
||||
tasks:
|
||||
- "List each dead code item with file:line and last git commit that touched it"
|
||||
- "Classify as safe-to-remove or needs-investigation"
|
||||
10
pkg/prompts/lib/task/code/refactor.md
Normal file
10
pkg/prompts/lib/task/code/refactor.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Refactor Task
|
||||
|
||||
Restructure code for clarity without changing behaviour.
|
||||
|
||||
## Process
|
||||
|
||||
1. Identify the refactor target (function, package, pattern)
|
||||
2. Write tests that lock current behaviour FIRST
|
||||
3. Apply refactor in small steps, testing after each
|
||||
4. Verify: same tests pass, same API surface, cleaner internals
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
name: Refactor
|
||||
description: Improve code quality without changing behaviour
|
||||
category: development
|
||||
|
||||
variables:
|
||||
target:
|
||||
description: Code to refactor (file, class, module)
|
||||
required: true
|
||||
goal:
|
||||
description: What improvement to achieve
|
||||
required: false
|
||||
|
||||
guidelines:
|
||||
- Ensure tests exist before refactoring
|
||||
- Make small, incremental changes
|
||||
- Commit frequently
|
||||
- Run tests after each change
|
||||
|
||||
phases:
|
||||
- name: Assessment
|
||||
description: Understand current state
|
||||
tasks:
|
||||
- Review existing code
|
||||
- Identify code smells
|
||||
- Check test coverage
|
||||
- Document current behaviour
|
||||
- List specific improvements
|
||||
|
||||
- name: Preparation
|
||||
description: Set up for safe refactoring
|
||||
tasks:
|
||||
- Ensure tests pass
|
||||
- Add tests for uncovered behaviour
|
||||
- Create feature branch
|
||||
- Set up automated checks
|
||||
- Document expected behaviour
|
||||
|
||||
- name: Extraction
|
||||
description: Extract and simplify
|
||||
tasks:
|
||||
- Extract methods/functions
|
||||
- Extract classes if too large
|
||||
- Remove duplication
|
||||
- Simplify conditionals
|
||||
- Improve naming
|
||||
|
||||
- name: Structure
|
||||
description: Improve organisation
|
||||
tasks:
|
||||
- Reorganise file structure
|
||||
- Update namespaces
|
||||
- Improve class relationships
|
||||
- Apply design patterns
|
||||
- Add interfaces where useful
|
||||
|
||||
- name: Polish
|
||||
description: Final improvements
|
||||
tasks:
|
||||
- Add type hints
|
||||
- Improve documentation
|
||||
- Remove dead code
|
||||
- Optimise performance
|
||||
- Ensure style consistency
|
||||
|
||||
- name: Verification
|
||||
description: Confirm behaviour unchanged
|
||||
tasks:
|
||||
- Run full test suite
|
||||
- Manual testing
|
||||
- Performance comparison
|
||||
- Code review
|
||||
- Merge and monitor
|
||||
21
pkg/prompts/lib/task/code/review.md
Normal file
21
pkg/prompts/lib/task/code/review.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Code Review Task
|
||||
|
||||
Review all changed files for bugs, security issues, and convention violations.
|
||||
|
||||
## Process
|
||||
|
||||
1. Run `git diff --name-only origin/main..HEAD` to find changed files
|
||||
2. Read each changed file
|
||||
3. Check against the conventions in `review/conventions.md`
|
||||
4. Rate each finding by confidence (0-100, report >= 50)
|
||||
5. Output findings by severity
|
||||
|
||||
## Output
|
||||
|
||||
```
|
||||
[SEVERITY] file.go:LINE (confidence: N)
|
||||
Description of the issue.
|
||||
Suggested fix.
|
||||
```
|
||||
|
||||
End with: `X critical, Y high, Z medium, W low findings.`
|
||||
22
pkg/prompts/lib/task/code/review/conventions.md
Normal file
22
pkg/prompts/lib/task/code/review/conventions.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Core Conventions Checklist
|
||||
|
||||
## Error Handling
|
||||
- [ ] `coreerr.E("pkg.Method", "msg", err)` — always 3 args
|
||||
- [ ] Never `fmt.Errorf` or `errors.New`
|
||||
- [ ] Import as `coreerr "forge.lthn.ai/core/go-log"`
|
||||
|
||||
## File I/O
|
||||
- [ ] `coreio.Local.Read/Write/EnsureDir` — never `os.ReadFile/WriteFile`
|
||||
- [ ] `WriteMode(path, content, 0600)` for sensitive files (keys, hashes)
|
||||
- [ ] Import as `coreio "forge.lthn.ai/core/go-io"`
|
||||
|
||||
## Safety
|
||||
- [ ] Check `err != nil` BEFORE `resp.StatusCode`
|
||||
- [ ] Type assertions use comma-ok: `v, ok := x.(Type)`
|
||||
- [ ] No hardcoded paths (`/Users/`, `/home/`, `host-uk`)
|
||||
- [ ] No tokens/secrets in error messages or logs
|
||||
|
||||
## Style
|
||||
- [ ] UK English in comments (colour, organisation, initialise)
|
||||
- [ ] SPDX-License-Identifier: EUPL-1.2 on every file
|
||||
- [ ] Test naming: `_Good`, `_Bad`, `_Ugly`
|
||||
21
pkg/prompts/lib/task/code/review/severity.md
Normal file
21
pkg/prompts/lib/task/code/review/severity.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Severity Guide
|
||||
|
||||
## CRITICAL (90+ confidence)
|
||||
- Security vulnerability (injection, traversal, leaked secrets)
|
||||
- Nil pointer dereference (panic in production)
|
||||
- Data loss risk
|
||||
|
||||
## HIGH (75+ confidence)
|
||||
- Convention violation that causes bugs (wrong error handling)
|
||||
- Missing error check on external call
|
||||
- Race condition
|
||||
|
||||
## MEDIUM (50+ confidence)
|
||||
- Convention violation (style, naming)
|
||||
- Missing test for new code
|
||||
- Unnecessary complexity
|
||||
|
||||
## LOW (25-49 confidence)
|
||||
- Nitpick (could be intentional)
|
||||
- Minor style inconsistency
|
||||
- Suggestion for improvement
|
||||
17
pkg/prompts/lib/task/code/simplifier.md
Normal file
17
pkg/prompts/lib/task/code/simplifier.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Code Simplifier Task
|
||||
|
||||
Simplify recently modified code without changing behaviour.
|
||||
|
||||
## Process
|
||||
|
||||
1. Run `git diff --name-only origin/main..HEAD` to find changed files
|
||||
2. Read each file, identify simplification opportunities
|
||||
3. Apply changes one file at a time
|
||||
4. `go build ./...` after each change to verify
|
||||
5. If build breaks, revert
|
||||
|
||||
## Rules
|
||||
|
||||
- NEVER change public API
|
||||
- NEVER change behaviour
|
||||
- NEVER add features or comments
|
||||
22
pkg/prompts/lib/task/code/simplifier/patterns.md
Normal file
22
pkg/prompts/lib/task/code/simplifier/patterns.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Simplification Patterns
|
||||
|
||||
## Consolidate
|
||||
- Three similar blocks → extract helper function
|
||||
- Duplicate error handling → shared handler
|
||||
- Repeated string → constant
|
||||
|
||||
## Flatten
|
||||
- Nested if/else → early return
|
||||
- Deep indentation → guard clauses
|
||||
- Long switch → map lookup
|
||||
|
||||
## Remove
|
||||
- Unused variables, imports, functions
|
||||
- Wrapper functions that just delegate
|
||||
- Dead branches (always true/false conditions)
|
||||
- Comments that restate the code
|
||||
|
||||
## Tighten
|
||||
- Long function (>50 lines) → split
|
||||
- God struct → focused types
|
||||
- Mixed concerns → separate files
|
||||
10
pkg/prompts/lib/task/code/test-gaps.md
Normal file
10
pkg/prompts/lib/task/code/test-gaps.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Test Coverage Gaps
|
||||
|
||||
Find untested code paths and write tests for them.
|
||||
|
||||
## Process
|
||||
|
||||
1. `go test -cover ./...` to identify coverage
|
||||
2. Focus on exported functions with 0% coverage
|
||||
3. Write tests using Good/Bad/Ugly naming
|
||||
4. Prioritise: error paths > happy paths > edge cases
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
name: Test Coverage Gaps
|
||||
description: Find functions without test coverage and missing edge case tests
|
||||
category: audit
|
||||
|
||||
guidelines:
|
||||
- Focus on exported functions first (public API)
|
||||
- Error paths are more important than happy paths (they're usually untested)
|
||||
- Tests should follow _Good/_Bad/_Ugly naming convention
|
||||
- Use testify assert/require, table-driven preferred
|
||||
|
||||
phases:
|
||||
- name: Coverage Analysis
|
||||
description: Identify untested exported functions
|
||||
tasks:
|
||||
- "List all exported functions and methods"
|
||||
- "Check each has at least one test calling it"
|
||||
- "Flag functions with zero test coverage"
|
||||
- "Note which are critical paths (called by many consumers)"
|
||||
|
||||
- name: Error Path Analysis
|
||||
description: Find untested error conditions
|
||||
tasks:
|
||||
- "For each function that returns error, check if error paths are tested"
|
||||
- "Check for nil/empty input handling tests"
|
||||
- "Check for boundary condition tests (zero, max, negative)"
|
||||
- "Flag error paths with no test coverage"
|
||||
|
||||
- name: Missing Edge Cases
|
||||
description: Find obvious gaps in existing tests
|
||||
tasks:
|
||||
- "Check concurrent access tests for types with mutexes"
|
||||
- "Check for tests with hardcoded paths or environment assumptions"
|
||||
- "Check for tests that only test the happy path"
|
||||
|
||||
- name: Report
|
||||
description: Document findings with priority
|
||||
tasks:
|
||||
- "List untested functions with file:line, consumer count, and priority"
|
||||
- "List untested error paths with the error condition"
|
||||
- "Suggest specific test cases to add"
|
||||
|
|
@ -30,7 +30,7 @@ import (
|
|||
//go:embed lib/prompt/*.md
|
||||
var promptFS embed.FS
|
||||
|
||||
//go:embed lib/task
|
||||
//go:embed all:lib/task
|
||||
var taskFS embed.FS
|
||||
|
||||
//go:embed lib/flow/*.md
|
||||
|
|
@ -57,10 +57,10 @@ func Template(slug string) (string, error) {
|
|||
return Task(slug)
|
||||
}
|
||||
|
||||
// Task returns a structured task plan by slug (written as PLAN.md).
|
||||
// Task returns a task definition by slug.
|
||||
// Slugs: "bug-fix", "new-feature", "code/review", "code/refactor", etc.
|
||||
func Task(slug string) (string, error) {
|
||||
for _, ext := range []string{".yaml", ".yml", ".md"} {
|
||||
for _, ext := range []string{".md", ".yaml", ".yml"} {
|
||||
data, err := taskFS.ReadFile("lib/task/" + slug + ext)
|
||||
if err == nil {
|
||||
return string(data), nil
|
||||
|
|
@ -69,6 +69,38 @@ func Task(slug string) (string, error) {
|
|||
return "", fs.ErrNotExist
|
||||
}
|
||||
|
||||
// TaskBundle returns the task definition plus all additional files in its bundle directory.
|
||||
// For "code/review": returns review.md content + map of {filename: content} from review/.
|
||||
// The bundle directory has the same name as the task file (without extension).
|
||||
func TaskBundle(slug string) (string, map[string]string, error) {
|
||||
// Get the main task definition
|
||||
main, err := Task(slug)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// Look for a bundle directory with the same name
|
||||
bundleDir := "lib/task/" + slug
|
||||
entries, err := fs.ReadDir(taskFS, bundleDir)
|
||||
if err != nil {
|
||||
// No bundle — just the task definition
|
||||
return main, nil, nil
|
||||
}
|
||||
|
||||
bundle := make(map[string]string)
|
||||
for _, e := range entries {
|
||||
if e.IsDir() {
|
||||
continue
|
||||
}
|
||||
data, err := taskFS.ReadFile(bundleDir + "/" + e.Name())
|
||||
if err == nil {
|
||||
bundle[e.Name()] = string(data)
|
||||
}
|
||||
}
|
||||
|
||||
return main, bundle, nil
|
||||
}
|
||||
|
||||
// Flow returns a build/release workflow by slug.
|
||||
// Slugs: "go", "php", "ts", "docker", "release", etc.
|
||||
func Flow(slug string) (string, error) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,24 @@ func TestTask_Good(t *testing.T) {
|
|||
func TestTask_Good_Nested(t *testing.T) {
|
||||
content, err := Task("code/review")
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, content, "name:")
|
||||
assert.Contains(t, content, "Code Review")
|
||||
}
|
||||
|
||||
func TestTaskBundle_Good(t *testing.T) {
|
||||
main, bundle, err := TaskBundle("code/review")
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, main, "Code Review")
|
||||
assert.NotNil(t, bundle)
|
||||
assert.Contains(t, bundle, "conventions.md")
|
||||
assert.Contains(t, bundle, "severity.md")
|
||||
assert.Contains(t, bundle["conventions.md"], "coreerr.E")
|
||||
}
|
||||
|
||||
func TestTaskBundle_Good_NoBundleDir(t *testing.T) {
|
||||
main, bundle, err := TaskBundle("bug-fix")
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, main, "name:")
|
||||
assert.Nil(t, bundle)
|
||||
}
|
||||
|
||||
func TestTask_Bad_NotFound(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue