{"record":{"id":"2cf22bd38d540797","repo":"nanocoai/nanoclaw","slug":"engage-mode-pattern-requires-engage-pattern-u","errorCode":null,"errorMessage":"engage_mode 'pattern' requires --engage-pattern (use \".\" to match every message)","messagePattern":"engage_mode 'pattern' requires --engage-pattern \\(use \"\\.\" to match every message\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/channels/channel-defaults.ts","lineNumber":169,"sourceCode":" * wiring-creation surface (`ncl wirings` create/update, the setup wizard's\n * register step) so a partial update or an explicit flag can't produce a\n * combination create would reject — including session_mode 'per-thread' on a\n * wiring whose thread policy resolves off. May mutate `w.engage_mode`: the\n * mention-sticky→mention coercion when the effective thread policy is off —\n * sticky engagement is keyed on per-thread session existence, so without\n * thread ids it would engage once and never disengage.\n *\n * Declaration-derived checks are gated on hasDeclaredChannelDefaults: stale\n * (undeclared) adapters keep the legacy lenient behavior — the fallback\n * declaration is permissive on mentions but its threads value is false when\n * no adapter is live, which would wrongly coerce offline-created wirings.\n */\nexport function validateEngageAgainstChannel(w: EngageValues, mg: MessagingGroup): void {\n  if (\n    w.engage_mode === 'pattern' &&\n    (w.engage_pattern === undefined || w.engage_pattern === null || w.engage_pattern === '')\n  ) {\n    throw new Error(`engage_mode 'pattern' requires --engage-pattern (use \".\" to match every message)`);\n  }\n\n  // per-thread sessions structurally require honored thread ids — reject the\n  // incoherent combination rather than storing it. Creation paths that resolve\n  // through the declaration derive threads=1 from sessionMode 'per-thread'\n  // (resolveWiringDefaults), so only explicit flags can reach this: an\n  // explicit threads=false, or NULL-inherit on a context whose declared\n  // `threads` is false. Undeclared (stale) adapters stay lenient on the\n  // inherit arm, same as the mention checks below.\n  if (w.session_mode === 'per-thread') {\n    const key = mg.instance ?? mg.channel_type;\n    const explicit = w.threads !== undefined && w.threads !== null;\n    const honored = explicit\n      ? w.threads !== 0 && w.threads !== false\n      : !hasDeclaredChannelDefaults(key, mg.channel_type) ||\n        (mg.is_group === 1\n          ? getChannelDefaults(key, mg.channel_type).group\n          : getChannelDefaults(key, mg.channel_type).dm","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/channels/channel-defaults.ts#L151-L187","documentation":"The directory exists but has no plugin.json and no legacy marker (context/instructions.md), so it is not recognizable as an agent plugin at all. parseTemplate refuses to guess.","triggerScenarios":"Passing an arbitrary directory, an empty folder, or a plugin whose manifest was renamed/misspelled (e.g. plugin-manifest.json).","commonSituations":"Wrong directory passed (parent of the plugin, or a sibling); manifest file deleted or misnamed; unzip produced a nested folder so the actual plugin is one level deeper.","solutions":["Check that <dir>/plugin.json exists exactly with that filename","If unzipping nested the content, point at the inner directory","If building a new plugin, create a plugin.json manifest first"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!fs.existsSync(path.join(dir, 'plugin.json'))) {\n  // wrong dir or not a plugin: fail before parseTemplate\n}","typeGuard":"function looksLikePlugin(dir: string): boolean {\n  return fs.existsSync(path.join(dir, 'plugin.json'));\n}","tryCatchPattern":"try { parseTemplate(dir); } catch (e) { if (e instanceof Error && e.message.startsWith('Not an agent plugin')) { /* locate the manifest or reject the dir */ } else throw e; }","preventionTips":["Validate unpacked plugin directories with a looksLikePlugin check before wiring them in","Watch for nested folders after archive extraction"],"tags":["templates","manifest","not-found"],"backgroundTag":"missing-manifest","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}