{"record":{"id":"917d49802ab333aa","repo":"can1357/oh-my-pi","slug":"rule-rule-name-has-no-usable-ttsr-condition","errorCode":null,"errorMessage":"Rule \"${rule.name}\" has no usable TTSR condition. Add a `condition` (regex) or `astCondition` (ast-grep pattern) to its frontmatter.","messagePattern":"Rule \"(.+?)\" has no usable TTSR condition\\. Add a `condition` \\(regex\\) or `astCondition` \\(ast-grep pattern\\) to its frontmatter\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cli/ttsr-cli.ts","lineNumber":324,"sourceCode":"\tconst name = path.basename(resolved).replace(/\\.(md|mdc)$/, \"\");\n\treturn buildRuleFromMarkdown(name, content, resolved, createSourceMeta(\"ttsr-cli\", resolved, \"project\"), {\n\t\truleName: name,\n\t});\n}\n\nasync function loadIsolatedRule(rulePath: string): Promise<{ rules: Rule[]; manager: TtsrManager }> {\n\tconst rule = await readIsolatedRule(rulePath);\n\tconst manager = await createTtsrManager({\n\t\tenabled: true,\n\t\tcontextMode: \"discard\",\n\t\tinterruptMode: \"always\",\n\t\trepeatMode: \"once\",\n\t\trepeatGap: 10,\n\t\tbuiltinRules: true,\n\t\tdisabledRules: [],\n\t});\n\tif (!manager.addRule(rule)) {\n\t\tthrow new Error(\n\t\t\t`Rule \"${rule.name}\" has no usable TTSR condition. Add a \\`condition\\` (regex) or \\`astCondition\\` (ast-grep pattern) to its frontmatter.`,\n\t\t);\n\t}\n\treturn { rules: manager.getRules(), manager };\n}\n\nasync function loadIsolatedScanRule(rulePath: string): Promise<Rule[]> {\n\tconst rule = await readIsolatedRule(rulePath);\n\treturn filterTtsrRulesForScan([rule]);\n}\n\nasync function runTest(args: TtsrTestArgs, json: boolean, cwd: string): Promise<void> {\n\tif (args.source && !TTSR_SOURCES.includes(args.source)) {\n\t\tthrow new Error(`Invalid --source: ${args.source}. Expected one of: ${TTSR_SOURCES.join(\", \")}`);\n\t}\n\n\tconst snippet = await readSnippet(args);\n","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/ttsr-cli.ts#L306-L342","documentation":"After loading an isolated rule markdown file, loadIsolatedRule registers it with TtsrManager. addRule returns false when the rule has no usable matching condition — i.e. its frontmatter defines neither a `condition` (regex) nor an `astCondition` (ast-grep pattern) — so nothing could ever trigger. The CLI throws this error telling you which frontmatter keys to add.","triggerScenarios":"Running `omp ttsr test --rule <file.md>` or `omp ttsr scan --rule <file.md>` where the markdown frontmatter lacks both `condition:` and `astCondition:` keys, or their values fail to compile into a usable rule.","commonSituations":"Authoring a new rule file that only has description/metadata frontmatter; copying a rule template without filling in the condition; a rule that was fine for documentation purposes but was never meant to match; malformed regex/AST pattern rejected during compile leaving no usable condition.","solutions":["Add a `condition` key with a regex to the rule's frontmatter.","Or add an `astCondition` key with an ast-grep pattern for structural matching.","Verify the condition compiles by re-running the command; also sanity-check regex syntax.","Use `omp ttsr test` with a snippet that should match to confirm the new condition triggers."],"exampleFix":"// before\n---\nname: no-secrets\ndescription: Detect API keys\n---\n// after\n---\nname: no-secrets\ndescription: Detect API keys\ncondition: \"sk-[a-zA-Z0-9]{20,}\"\n---","handlingStrategy":"validation","validationCode":"import * as fs from \"node:fs\";\nconst head = fs.readFileSync(rulePath, \"utf8\").split(\"---\")[1] ?? \"\";\nif (!/^condition:/m.test(head) && !/^astCondition:/m.test(head)) {\n  throw new Error(`${rulePath}: frontmatter needs ` + \"`condition:` or `astCondition:`\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  await runTest(args, json, cwd);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"no usable TTSR condition\")) {\n    console.error(`${err.message}\\nRule file: ${args.rule}`);\n  }\n  throw err;\n}","preventionTips":["Start new rules from a template that includes condition or astCondition.","Lint rule frontmatter in CI (require at least one condition key).","Never commit rules with description-only frontmatter.","Test each new rule with `omp ttsr test` and a matching snippet before committing."],"tags":["cli","rules","configuration","frontmatter"],"backgroundTag":"invalid-rule-configuration","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}