can1357/oh-my-pi · error · Error

Rule "${rule.name}" has no usable TTSR condition. Add a `con

Error message

Rule "${rule.name}" has no usable TTSR condition. Add a `condition` (regex) or `astCondition` (ast-grep pattern) to its frontmatter.

What it means

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.

Source

Thrown at packages/coding-agent/src/cli/ttsr-cli.ts:324

	const name = path.basename(resolved).replace(/\.(md|mdc)$/, "");
	return buildRuleFromMarkdown(name, content, resolved, createSourceMeta("ttsr-cli", resolved, "project"), {
		ruleName: name,
	});
}

async function loadIsolatedRule(rulePath: string): Promise<{ rules: Rule[]; manager: TtsrManager }> {
	const rule = await readIsolatedRule(rulePath);
	const manager = await createTtsrManager({
		enabled: true,
		contextMode: "discard",
		interruptMode: "always",
		repeatMode: "once",
		repeatGap: 10,
		builtinRules: true,
		disabledRules: [],
	});
	if (!manager.addRule(rule)) {
		throw new Error(
			`Rule "${rule.name}" has no usable TTSR condition. Add a \`condition\` (regex) or \`astCondition\` (ast-grep pattern) to its frontmatter.`,
		);
	}
	return { rules: manager.getRules(), manager };
}

async function loadIsolatedScanRule(rulePath: string): Promise<Rule[]> {
	const rule = await readIsolatedRule(rulePath);
	return filterTtsrRulesForScan([rule]);
}

async function runTest(args: TtsrTestArgs, json: boolean, cwd: string): Promise<void> {
	if (args.source && !TTSR_SOURCES.includes(args.source)) {
		throw new Error(`Invalid --source: ${args.source}. Expected one of: ${TTSR_SOURCES.join(", ")}`);
	}

	const snippet = await readSnippet(args);

View on GitHub (pinned to 9690622007)

Solutions

  1. Add a `condition` key with a regex to the rule's frontmatter.
  2. Or add an `astCondition` key with an ast-grep pattern for structural matching.
  3. Verify the condition compiles by re-running the command; also sanity-check regex syntax.
  4. Use `omp ttsr test` with a snippet that should match to confirm the new condition triggers.

Example fix

// before
---
name: no-secrets
description: Detect API keys
---
// after
---
name: no-secrets
description: Detect API keys
condition: "sk-[a-zA-Z0-9]{20,}"
---
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from "node:fs";
const head = fs.readFileSync(rulePath, "utf8").split("---")[1] ?? "";
if (!/^condition:/m.test(head) && !/^astCondition:/m.test(head)) {
  throw new Error(`${rulePath}: frontmatter needs ` + "`condition:` or `astCondition:`");
}

Try / catch

try {
  await runTest(args, json, cwd);
} catch (err) {
  if (err instanceof Error && err.message.includes("no usable TTSR condition")) {
    console.error(`${err.message}\nRule file: ${args.rule}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/917d49802ab333aa. Report an issue: GitHub.