Documentation
¶
Overview ¶
CANARY: REQ=CP-252; FEATURE="NextPriorityCommand"; ASPECT=CLI; STATUS=BENCHED; TEST=TestCANARY_CBIN_132_CLI_NextPrioritySelection,TestCANARY_CBIN_132_CLI_DBAndScanAgreeOnOrder,TestCANARY_CBIN_132_CLI_Candidate51IsFound,TestCANARY_CBIN_132_CLI_PromptResolvesUnderRoot; BENCH=BenchmarkCANARY_CBIN_132_CLI_PriorityQuery; OWNER=canary; UPDATED=2026-08-31
Index ¶
Constants ¶
const ( FormatJSON = "json" FormatText = "text" )
Output formats accepted by --format.
const ( SourceDatabase = "database" SourceFilesystem = "filesystem" )
Sources a selection can come from, reported verbatim in --format json's "source" field so a caller always knows what the answer was computed from.
Variables ¶
var NextCmd = &cobra.Command{ Use: "next [flags]", Short: "Identify and implement next highest priority requirement", Long: `Identify the next highest priority unimplemented requirement and generate comprehensive implementation guidance. This command automatically: - Uses the token index when it still describes this tree, and scans the tree itself when it does not - Identifies highest priority STUB or IMPL requirement - Excludes hidden requirements (test files, templates, examples) - Requires every dependency to be proven complete -- passing evidence at the current commit for a local one, a satisfied external/peer state otherwise - Generates comprehensive implementation prompt with: - Specification details - Constitutional principles - Test-first guidance - Token placement examples Priority determination factors: 1. PRIORITY field (1=highest, 10=lowest); a token that declares none is ranked -- and reported -- at the neutral default 5 2. STATUS (STUB before IMPL) 3. DEPENDS_ON (every dependency must be proven complete by evidence, or satisfied as an external/peer requirement) The answer names its own source: "database" when the index is present and still describes this tree, "filesystem" when the tree had to be scanned directly. Completion is only ever claimed from a current index.`, RunE: func(cmd *cobra.Command, args []string) error { format, err := resolveFormat(cmd) if err != nil { return err } dbPath, _ := cmd.Flags().GetString("db") promptFlag, _ := cmd.Flags().GetBool("prompt") dryRun, _ := cmd.Flags().GetBool("dry-run") filterStatus, _ := cmd.Flags().GetString("status") filterAspect, _ := cmd.Flags().GetString("aspect") allowUnknownExternal, _ := cmd.Flags().GetBool("allow-unknown-external") root, _ := cmd.Flags().GetString("root") if root == "" { root = "." } dbPath = resolveDBPath(root, dbPath) filters := make(map[string]string) if filterStatus != "" { filters["status"] = filterStatus } if filterAspect != "" { filters["aspect"] = filterAspect } projectID := utils.ReadProjectID(cmd) sel, err := selectNext(selection{ DBPath: dbPath, Root: root, ProjectID: projectID, Filters: filters, AllowUnknownExternal: allowUnknownExternal, Stderr: cmd.ErrOrStderr(), }) if err != nil { if guarded := utils.GuardContract(cmd, err); errors.Is(guarded, utils.ErrContractFailed) { return guarded } return fmt.Errorf("select next priority: %w", err) } out := cmd.OutOrStdout() if format == FormatJSON { return emitJSON(out, sel) } if sel.Token == nil { printNoWork(out, sel.Source, sel.Blocked) return nil } if dryRun { fmt.Fprintf(out, "Next priority (dry run): %s - %s\n", sel.Token.ReqID, sel.Token.Feature) fmt.Fprintf(out, "Priority: %d | Status: %s | Aspect: %s\n", sel.Token.Priority, sel.Token.Status, sel.Token.Aspect) fmt.Fprintf(out, "Location: %s\n", sel.Token.FilePath) fmt.Fprintf(out, "Source: %s\n", sel.Source) return nil } promptArg, _ := cmd.Flags().GetString("prompt-arg") output, err := renderPrompt(root, sel.Token, projectID, dbPath, promptFlag, promptArg) if err != nil { return fmt.Errorf("render prompt: %w", err) } fmt.Fprintln(out, output) return nil }, }
CANARY: REQ=CP-252; FEATURE="NextCmd"; ASPECT=CLI; STATUS=BENCHED; TEST=TestCANARY_CBIN_132_CLI_NextPrioritySelection,TestCANARY_CBIN_132_CLI_DBAndScanAgreeOnOrder,TestCANARY_CBIN_132_CLI_Candidate51IsFound,TestCANARY_CBIN_132_CLI_PromptResolvesUnderRoot; BENCH=BenchmarkCANARY_CBIN_132_CLI_PriorityQuery; OWNER=canary; DOC=user:docs/user/next-priority-guide.md; DOC_HASH=6a276e6735100236; UPDATED=2026-08-31
Functions ¶
func SelectNext ¶ added in v0.3.3
func SelectNext(dbPath, root, projectID string, filters map[string]string, allowUnknownExternal bool, stderr io.Writer) (token *storage.Token, source string, blocked int, err error)
SelectNext is the exported entry point to `canary next`'s selection: the same source decision (fresh index, else canonical filesystem scan) and the same dependency gate the CLI applies, returning the chosen token, the source that answered, and how many candidates were passed over as blocked.
It exists so the MCP `next` tool can delegate rather than reimplement. The MCP tool used to carry a hand-maintained replica of the dependency rule, and the replica drifted: it still accepted a declared STATUS=TESTED as proof and still let an unresolvable external dependency pass, months after the CLI stopped doing either. Two answers to "may this work start?" is one answer too many, so there is now exactly one implementation and the MCP surface calls it.
root is the tree the answer is about; projectID scopes index queries ("" means every project, refused only when ambiguous); stderr receives the one-line notes about unresolvable dependencies (io.Discard is fine).
Types ¶
type PromptData ¶
type PromptData struct {
ReqID string
Feature string
Aspect string
Status string
Priority int
SpecFile string
SpecContent string
Constitution string
RelatedSpecs []RelatedSpec
Dependencies []*storage.Token
SuggestedFiles []string
TestGuidance string
TokenExample string
SuccessCriteria []string
Today string
SuggestedTestFile string
PackageName string
// PromptArg is the --prompt-arg value as given, and PromptContent the
// prompt it resolved to. Both are empty when no extra prompt was asked
// for.
PromptArg string
PromptContent string
}
PromptData holds template variables for prompt generation
type RelatedSpec ¶
RelatedSpec represents a related specification reference