opencode-swarm 7.53.0 → 7.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,12 +15,12 @@
15
15
  * architect runs 1–3 web_search calls upfront, compiles a RESEARCH CONTEXT
16
16
  * block, and passes it to all three agents in their dispatch message. The
17
17
  * agents themselves have NO tools — they reason from the provided context
18
- * plus their training knowledge.
18
+ * plus stable background knowledge.
19
19
  *
20
20
  * The Round 1 / Round 2 deliberation protocol (independent analysis →
21
21
  * MAINTAIN/CONCEDE/NUANCE for disagreements) is preserved verbatim, as is
22
22
  * the JSON response schema consumed by convene_general_council.
23
23
  */
24
- export declare const GENERALIST_COUNCIL_PROMPT = "You are the GENERALIST voice on a multi-model General Council.\n\nYou are the GENERALIST voice on this council. Your perspective is broad and synthesizing:\n- You reason from first principles and across disciplines.\n- You weigh competing considerations without domain bias.\n- You surface tensions between different valid approaches.\n- You are the integrating voice \u2014 you see what the specialists might miss by being too deep in their domain.\nMember ID: \"council_generalist\" | Role: \"generalist\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and your training knowledge.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n";
25
- export declare const SKEPTIC_COUNCIL_PROMPT = "You are the SKEPTIC voice on a multi-model General Council.\n\nYou are the SKEPTIC voice on this council. Your job is rigorous stress-testing:\n- You challenge assumptions the other members take for granted.\n- You look for weak points, edge cases, and unstated dependencies.\n- You are NOT contrarian for its own sake \u2014 your pushback must be evidence-grounded.\n- You make the council's final answer more robust by finding what could go wrong before the user does.\nMember ID: \"council_skeptic\" | Role: \"skeptic\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and your training knowledge.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n";
26
- export declare const DOMAIN_EXPERT_COUNCIL_PROMPT = "You are the DOMAIN EXPERT voice on a multi-model General Council.\n\nYou are the DOMAIN EXPERT voice on this council. Your perspective is technically precise:\n- You go deep where others stay broad.\n- You cite specific mechanisms, constraints, and implementation-level detail.\n- You surface edge cases and gotchas that only emerge at depth.\n- Your answers are concrete \u2014 no hand-waving, no vague recommendations.\nMember ID: \"council_domain_expert\" | Role: \"domain_expert\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and your training knowledge.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n";
24
+ export declare const GENERALIST_COUNCIL_PROMPT = "You are the GENERALIST voice on a multi-model General Council.\n\nYou are the GENERALIST voice on this council. Your perspective is broad and synthesizing:\n- You reason from first principles and across disciplines.\n- You weigh competing considerations without domain bias.\n- You surface tensions between different valid approaches.\n- You are the integrating voice \u2014 you see what the specialists might miss by being too deep in their domain.\nMember ID: \"council_generalist\" | Role: \"generalist\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.\n- Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.\n- Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or \"state of the art\" claims.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n";
25
+ export declare const SKEPTIC_COUNCIL_PROMPT = "You are the SKEPTIC voice on a multi-model General Council.\n\nYou are the SKEPTIC voice on this council. Your job is rigorous stress-testing:\n- You challenge assumptions the other members take for granted.\n- You look for weak points, edge cases, and unstated dependencies.\n- You are NOT contrarian for its own sake \u2014 your pushback must be evidence-grounded.\n- You make the council's final answer more robust by finding what could go wrong before the user does.\nMember ID: \"council_skeptic\" | Role: \"skeptic\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.\n- Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.\n- Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or \"state of the art\" claims.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n";
26
+ export declare const DOMAIN_EXPERT_COUNCIL_PROMPT = "You are the DOMAIN EXPERT voice on a multi-model General Council.\n\nYou are the DOMAIN EXPERT voice on this council. Your perspective is technically precise:\n- You go deep where others stay broad.\n- You cite specific mechanisms, constraints, and implementation-level detail.\n- You surface edge cases and gotchas that only emerge at depth.\n- Your answers are concrete \u2014 no hand-waving, no vague recommendations.\nMember ID: \"council_domain_expert\" | Role: \"domain_expert\"\n\nYou are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.\n\n================================================================\nROUND PROTOCOL\n================================================================\n\nROUND 1 \u2014 Independent Analysis and Answer\n- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.\n- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).\n- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.\n- For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.\n- Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.\n- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.\n- Do NOT coordinate with other members. You will not see their responses until Round 2.\n- Do NOT pad. Be concise. Substance over volume.\n\nROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)\n- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.\n- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.\n- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:\n MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it\n CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong\n NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them\n- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).\n- Never MAINTAIN without engaging the opposing argument on its merits.\n\n================================================================\nRESPONSE FORMAT (always \u2014 both rounds)\n================================================================\n\nReply with a single fenced JSON block. No prose outside the block.\n\n```json\n{\n \"memberId\": \"<your hardcoded memberId>\",\n \"role\": \"<your hardcoded role>\",\n \"round\": 1,\n \"response\": \"Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.\",\n \"searchQueries\": [],\n \"sources\": [\n { \"title\": \"...\", \"url\": \"...\", \"snippet\": \"...\", \"query\": \"...\" }\n ],\n \"confidence\": 0.85,\n \"areasOfUncertainty\": [\n \"What I'm not sure about, in plain language.\"\n ],\n \"disagreementTopics\": []\n}\n```\n\nNotes:\n- `searchQueries` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.\n- `sources` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.\n- For Round 1: leave `disagreementTopics` as []. For Round 2: list the specific disagreement topics this response addresses.\n\n================================================================\nHARD RULES\n================================================================\n- You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.\n- Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or \"state of the art\" claims.\n- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in `areasOfUncertainty`.\n- Never echo other members' responses verbatim. Paraphrase or quote with attribution.\n- Stay within your role and persona. The architect chose you for a specific perspective.\n";
package/dist/cli/index.js CHANGED
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "opencode-swarm",
55
- version: "7.53.0",
55
+ version: "7.54.0",
56
56
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
57
57
  main: "dist/index.js",
58
58
  types: "dist/index.d.ts",
@@ -16874,11 +16874,11 @@ var init_tool_metadata = __esm(() => {
16874
16874
  agents: ["architect"]
16875
16875
  },
16876
16876
  web_search: {
16877
- description: "External web search (Tavily or Brave) for architect-driven council research. Returns titled results with snippets and URLs. Config-gated on council.general.enabled; requires a search API key. Used by the architect in MODE: COUNCIL to gather a RESEARCH CONTEXT before dispatching council agents.",
16877
+ description: "External web search (Tavily or Brave) for architect-driven council research. Returns titled results with snippets, URLs, normalized query metadata, temporal intent, freshness, and removed stale years. Config-gated on council.general.enabled in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides. Requires a search API key. Used by the architect in MODE: COUNCIL to gather a RESEARCH CONTEXT before dispatching council agents.",
16878
16878
  agents: ["architect", "skill_improver"]
16879
16879
  },
16880
16880
  convene_general_council: {
16881
- description: "Synthesize responses from a multi-model General Council. Accepts parallel member responses (Round 1, optionally Round 2), detects disagreements, and returns consensus points, persisting disagreements, and a structured synthesis. Architect-only. Config-gated on council.general.enabled.",
16881
+ description: "Synthesize responses from a multi-model General Council. Accepts parallel member responses (Round 1, optionally Round 2), detects disagreements, and returns consensus points, persisting disagreements, and a structured synthesis. Architect-only. Config-gated on council.general.enabled in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides.",
16882
16882
  agents: ["architect"]
16883
16883
  },
16884
16884
  write_final_council_evidence: {
@@ -21331,6 +21331,8 @@ ROUND 1 \u2014 Independent Analysis and Answer
21331
21331
  - Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.
21332
21332
  - Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).
21333
21333
  - State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.
21334
+ - For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.
21335
+ - Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.
21334
21336
  - Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.
21335
21337
  - Do NOT coordinate with other members. You will not see their responses until Round 2.
21336
21338
  - Do NOT pad. Be concise. Substance over volume.
@@ -21373,7 +21375,8 @@ Notes:
21373
21375
  - For Round 1: leave \`disagreementTopics\` as []. For Round 2: list the specific disagreement topics this response addresses.`, HARD_RULES = `================================================================
21374
21376
  HARD RULES
21375
21377
  ================================================================
21376
- - You have no tools. Reason from the provided RESEARCH CONTEXT and your training knowledge.
21378
+ - You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.
21379
+ - Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or "state of the art" claims.
21377
21380
  - Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in \`areasOfUncertainty\`.
21378
21381
  - Never echo other members' responses verbatim. Paraphrase or quote with attribution.
21379
21382
  - Stay within your role and persona. The architect chose you for a specific perspective.`, GENERALIST_COUNCIL_PROMPT, SKEPTIC_COUNCIL_PROMPT, DOMAIN_EXPERT_COUNCIL_PROMPT;
@@ -21719,7 +21722,7 @@ var init_guardrails = __esm(() => {
21719
21722
  function clearPendingCoderScope() {
21720
21723
  pendingCoderScopeByTaskId.clear();
21721
21724
  }
21722
- var EvidenceTaskIdPlanSchema, pendingCoderScopeByTaskId, ACTIVE_PARALLEL_TASK_STATES;
21725
+ var EvidenceTaskIdPlanSchema, pendingCoderScopeByTaskId, SWARM_BACKGROUND_TASK_BLOCKED_MESSAGE, ACTIVE_PARALLEL_TASK_STATES;
21723
21726
  var init_delegation_gate = __esm(() => {
21724
21727
  init_zod();
21725
21728
  init_schema();
@@ -21740,6 +21743,7 @@ var init_delegation_gate = __esm(() => {
21740
21743
  }).passthrough()).optional()
21741
21744
  }).passthrough();
21742
21745
  pendingCoderScopeByTaskId = new Map;
21746
+ SWARM_BACKGROUND_TASK_BLOCKED_MESSAGE = "SWARM_BACKGROUND_TASK_BLOCKED: OpenCode background subagents (Task with background=true, " + "requires OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true) are recognized upstream, but swarm " + "cannot yet safely consume their deferred completion events \u2014 the Task returns a running " + "placeholder now and completes later via synthetic injection, which would advance swarm gates " + "before any review/test output exists. Omit `background` (or set background=false) for swarm " + "delegations until the completion-ingestion PR lands.";
21743
21747
  ACTIVE_PARALLEL_TASK_STATES = new Set([
21744
21748
  "coder_delegated",
21745
21749
  "pre_check_passed",
@@ -39867,7 +39871,7 @@ var init_council = __esm(() => {
39867
39871
  " --preset <name> Use a named member preset from council.general.presets",
39868
39872
  " --spec-review Use spec_review mode (single advisory pass on a draft spec)",
39869
39873
  "",
39870
- "Requires council.general.enabled: true and a configured search API key in opencode-swarm.json."
39874
+ "Requires council.general.enabled: true and a configured search API key in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides."
39871
39875
  ].join(`
39872
39876
  `);
39873
39877
  });
@@ -59004,7 +59008,7 @@ Subcommands:
59004
59008
  handler: (ctx) => handleCouncilCommand(ctx.directory, ctx.args),
59005
59009
  description: "Enter architect MODE: COUNCIL \u2014 multi-model deliberation [question] [--preset <name>] [--spec-review]",
59006
59010
  args: "<question> [--preset <name>] [--spec-review]",
59007
- details: "Triggers the architect to convene a three-agent General Council: Generalist (reviewer model), Skeptic (critic model), and Domain Expert (SME model). Use --preset <name> to choose a named member preset from council.general.presets. " + "The architect first runs 1\u20133 targeted web searches and passes a compiled RESEARCH CONTEXT " + "to all three agents before dispatching them in parallel. Agents deliberate using the NSED peer-review protocol (Round 1 independent analysis, Round 2 MAINTAIN/CONCEDE/NUANCE for disagreements). The architect synthesizes the final answer directly from convene_general_council output. --spec-review switches to single-pass advisory mode for spec review. Requires council.general.enabled: true and a search API key in opencode-swarm.json.",
59011
+ details: "Triggers the architect to convene a three-agent General Council: Generalist (reviewer model), Skeptic (critic model), and Domain Expert (SME model). Use --preset <name> to choose a named member preset from council.general.presets. " + "The architect first runs 1\u20133 targeted web searches and passes a compiled RESEARCH CONTEXT " + "to all three agents before dispatching them in parallel. Agents deliberate using the NSED peer-review protocol (Round 1 independent analysis, Round 2 MAINTAIN/CONCEDE/NUANCE for disagreements). The architect synthesizes the final answer directly from convene_general_council output. --spec-review switches to single-pass advisory mode for spec review. Requires council.general.enabled: true and a search API key in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides.",
59008
59012
  category: "agent"
59009
59013
  },
59010
59014
  "pr-review": {
@@ -0,0 +1,11 @@
1
+ export type SearchFreshness = 'day' | 'week' | 'month' | 'year';
2
+ export type SearchTemporalIntent = 'current' | 'historical' | 'unspecified';
3
+ export interface SearchQueryPolicyResult {
4
+ originalQuery: string;
5
+ query: string;
6
+ temporalIntent: SearchTemporalIntent;
7
+ freshness?: SearchFreshness;
8
+ removedStaleYears: string[];
9
+ }
10
+ export declare function applySearchQueryPolicy(rawQuery: string, now?: Date): SearchQueryPolicyResult;
11
+ export declare function collectQueryYears(query: string): string[];
@@ -12,6 +12,7 @@
12
12
  * Malformed but successful responses produce an empty result array, never throw.
13
13
  */
14
14
  import type { GeneralCouncilConfig, WebSearchResult } from './general-council-types.js';
15
+ import type { SearchFreshness } from './search-query-policy.js';
15
16
  export declare class WebSearchError extends Error {
16
17
  readonly cause?: unknown | undefined;
17
18
  constructor(message: string, cause?: unknown | undefined);
@@ -20,16 +21,19 @@ export declare class WebSearchConfigError extends Error {
20
21
  constructor(message: string);
21
22
  }
22
23
  export interface WebSearchProvider {
23
- search(query: string, maxResults: number): Promise<WebSearchResult[]>;
24
+ search(query: string, maxResults: number, options?: WebSearchOptions): Promise<WebSearchResult[]>;
25
+ }
26
+ export interface WebSearchOptions {
27
+ freshness?: SearchFreshness;
24
28
  }
25
29
  export declare class TavilyProvider implements WebSearchProvider {
26
30
  private readonly apiKey;
27
31
  constructor(apiKey: string);
28
- search(query: string, maxResults: number): Promise<WebSearchResult[]>;
32
+ search(query: string, maxResults: number, options?: WebSearchOptions): Promise<WebSearchResult[]>;
29
33
  }
30
34
  export declare class BraveProvider implements WebSearchProvider {
31
35
  private readonly apiKey;
32
36
  constructor(apiKey: string);
33
- search(query: string, maxResults: number): Promise<WebSearchResult[]>;
37
+ search(query: string, maxResults: number, options?: WebSearchOptions): Promise<WebSearchResult[]>;
34
38
  }
35
39
  export declare function createWebSearchProvider(config: GeneralCouncilConfig): WebSearchProvider;
@@ -25,6 +25,30 @@ export declare const pendingCoderScopeByTaskId: Map<string, string[]>;
25
25
  * circular import `state.ts ↔ delegation-gate.ts`. Called by `resetSwarmState`.
26
26
  */
27
27
  export declare function clearPendingCoderScope(): void;
28
+ /**
29
+ * Issue #1151: OpenCode v1.16.2 background subagents.
30
+ *
31
+ * `Task` with `background=true` (gated upstream by
32
+ * `OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true`) returns a "running" placeholder
33
+ * immediately and completes later via synthetic parent injection. The delegation gate
34
+ * treats a `Task` result as completion, so a background swarm delegation would advance
35
+ * Stage B / record gate evidence before any review/test output exists. Until swarm can
36
+ * correlate the deferred completion safely (a separate, spike-gated PR), background
37
+ * swarm delegations are fail-closed-blocked. We do NOT silently coerce `background` to
38
+ * false — the unsupported capability is surfaced explicitly.
39
+ */
40
+ export declare const SWARM_BACKGROUND_TASK_BLOCKED_MESSAGE: string;
41
+ /**
42
+ * Fail-closed background-flag detector. Treats both the boolean `true` and the
43
+ * stringified `'true'` as background so a stringified flag cannot bypass the guard.
44
+ */
45
+ export declare function isBackgroundTrue(value: unknown): boolean;
46
+ /**
47
+ * True when a `Task` tool RESULT looks like an OpenCode background "running"
48
+ * placeholder (`state: "running"` or `metadata.background === true`). Belt-and-
49
+ * suspenders for `toolAfter`; never throws.
50
+ */
51
+ export declare function outputLooksLikeBackgroundRunning(output: unknown): boolean;
28
52
  /**
29
53
  * Parses a string to extract a DelegationEnvelope.
30
54
  * Returns null if no valid envelope is found.
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ var package_default;
69
69
  var init_package = __esm(() => {
70
70
  package_default = {
71
71
  name: "opencode-swarm",
72
- version: "7.53.0",
72
+ version: "7.54.0",
73
73
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
74
74
  main: "dist/index.js",
75
75
  types: "dist/index.d.ts",
@@ -566,11 +566,11 @@ var init_tool_metadata = __esm(() => {
566
566
  agents: ["architect"]
567
567
  },
568
568
  web_search: {
569
- description: "External web search (Tavily or Brave) for architect-driven council research. Returns titled results with snippets and URLs. Config-gated on council.general.enabled; requires a search API key. Used by the architect in MODE: COUNCIL to gather a RESEARCH CONTEXT before dispatching council agents.",
569
+ description: "External web search (Tavily or Brave) for architect-driven council research. Returns titled results with snippets, URLs, normalized query metadata, temporal intent, freshness, and removed stale years. Config-gated on council.general.enabled in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides. Requires a search API key. Used by the architect in MODE: COUNCIL to gather a RESEARCH CONTEXT before dispatching council agents.",
570
570
  agents: ["architect", "skill_improver"]
571
571
  },
572
572
  convene_general_council: {
573
- description: "Synthesize responses from a multi-model General Council. Accepts parallel member responses (Round 1, optionally Round 2), detects disagreements, and returns consensus points, persisting disagreements, and a structured synthesis. Architect-only. Config-gated on council.general.enabled.",
573
+ description: "Synthesize responses from a multi-model General Council. Accepts parallel member responses (Round 1, optionally Round 2), detects disagreements, and returns consensus points, persisting disagreements, and a structured synthesis. Architect-only. Config-gated on council.general.enabled in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides.",
574
574
  agents: ["architect"]
575
575
  },
576
576
  write_final_council_evidence: {
@@ -40596,6 +40596,18 @@ import * as path19 from "node:path";
40596
40596
  function clearPendingCoderScope() {
40597
40597
  pendingCoderScopeByTaskId.clear();
40598
40598
  }
40599
+ function isBackgroundTrue(value) {
40600
+ return value === true || value === "true";
40601
+ }
40602
+ function outputLooksLikeBackgroundRunning(output) {
40603
+ if (typeof output !== "object" || output === null)
40604
+ return false;
40605
+ const o = output;
40606
+ if (o.state === "running")
40607
+ return true;
40608
+ const metadata2 = o.metadata;
40609
+ return typeof metadata2 === "object" && metadata2 !== null && metadata2.background === true;
40610
+ }
40599
40611
  function extractTaskLine(text) {
40600
40612
  const match = text.match(/TASK:\s*(.+?)(?:\n|$)/i);
40601
40613
  return match ? match[1].trim() : null;
@@ -40874,6 +40886,9 @@ function createDelegationGateHook(config2, directory) {
40874
40886
  if (typeof subagentType !== "string")
40875
40887
  return;
40876
40888
  const targetAgent = stripKnownSwarmPrefix(subagentType);
40889
+ if (isBackgroundTrue(args2.background) && isKnownCanonicalRole(targetAgent)) {
40890
+ throw new Error(SWARM_BACKGROUND_TASK_BLOCKED_MESSAGE);
40891
+ }
40877
40892
  if (targetAgent === "reviewer") {
40878
40893
  try {
40879
40894
  const reviewSession = swarmState.agentSessions.get(input.sessionID);
@@ -40974,6 +40989,11 @@ function createDelegationGateHook(config2, directory) {
40974
40989
  const directArgs = input.args;
40975
40990
  const storedArgs = getStoredInputArgs(input.callID);
40976
40991
  const subagentType = directArgs?.subagent_type ?? storedArgs?.subagent_type;
40992
+ if (typeof subagentType === "string" && isKnownCanonicalRole(stripKnownSwarmPrefix(subagentType)) && (isBackgroundTrue(directArgs?.background) || isBackgroundTrue(storedArgs?.background) || outputLooksLikeBackgroundRunning(_output))) {
40993
+ if (storedArgs !== undefined)
40994
+ deleteStoredInputArgs(input.callID);
40995
+ return;
40996
+ }
40977
40997
  let hasReviewer = false;
40978
40998
  let hasTestEngineer = false;
40979
40999
  if (typeof subagentType === "string") {
@@ -41451,7 +41471,7 @@ ${warningLines.join(`
41451
41471
  toolAfter
41452
41472
  };
41453
41473
  }
41454
- var EvidenceTaskIdPlanSchema, pendingCoderScopeByTaskId, ACTIVE_PARALLEL_TASK_STATES;
41474
+ var EvidenceTaskIdPlanSchema, pendingCoderScopeByTaskId, SWARM_BACKGROUND_TASK_BLOCKED_MESSAGE, ACTIVE_PARALLEL_TASK_STATES;
41455
41475
  var init_delegation_gate = __esm(() => {
41456
41476
  init_zod();
41457
41477
  init_schema();
@@ -41472,6 +41492,7 @@ var init_delegation_gate = __esm(() => {
41472
41492
  }).passthrough()).optional()
41473
41493
  }).passthrough();
41474
41494
  pendingCoderScopeByTaskId = new Map;
41495
+ SWARM_BACKGROUND_TASK_BLOCKED_MESSAGE = "SWARM_BACKGROUND_TASK_BLOCKED: OpenCode background subagents (Task with background=true, " + "requires OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true) are recognized upstream, but swarm " + "cannot yet safely consume their deferred completion events — the Task returns a running " + "placeholder now and completes later via synthetic injection, which would advance swarm gates " + "before any review/test output exists. Omit `background` (or set background=false) for swarm " + "delegations until the completion-ingestion PR lands.";
41475
41496
  ACTIVE_PARALLEL_TASK_STATES = new Set([
41476
41497
  "coder_delegated",
41477
41498
  "pre_check_passed",
@@ -62057,7 +62078,7 @@ var init_council = __esm(() => {
62057
62078
  " --preset <name> Use a named member preset from council.general.presets",
62058
62079
  " --spec-review Use spec_review mode (single advisory pass on a draft spec)",
62059
62080
  "",
62060
- "Requires council.general.enabled: true and a configured search API key in opencode-swarm.json."
62081
+ "Requires council.general.enabled: true and a configured search API key in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides."
62061
62082
  ].join(`
62062
62083
  `);
62063
62084
  });
@@ -82637,7 +82658,7 @@ Subcommands:
82637
82658
  handler: (ctx) => handleCouncilCommand(ctx.directory, ctx.args),
82638
82659
  description: "Enter architect MODE: COUNCIL — multi-model deliberation [question] [--preset <name>] [--spec-review]",
82639
82660
  args: "<question> [--preset <name>] [--spec-review]",
82640
- details: "Triggers the architect to convene a three-agent General Council: Generalist (reviewer model), Skeptic (critic model), and Domain Expert (SME model). Use --preset <name> to choose a named member preset from council.general.presets. " + "The architect first runs 1–3 targeted web searches and passes a compiled RESEARCH CONTEXT " + "to all three agents before dispatching them in parallel. Agents deliberate using the NSED peer-review protocol (Round 1 independent analysis, Round 2 MAINTAIN/CONCEDE/NUANCE for disagreements). The architect synthesizes the final answer directly from convene_general_council output. --spec-review switches to single-pass advisory mode for spec review. Requires council.general.enabled: true and a search API key in opencode-swarm.json.",
82661
+ details: "Triggers the architect to convene a three-agent General Council: Generalist (reviewer model), Skeptic (critic model), and Domain Expert (SME model). Use --preset <name> to choose a named member preset from council.general.presets. " + "The architect first runs 1–3 targeted web searches and passes a compiled RESEARCH CONTEXT " + "to all three agents before dispatching them in parallel. Agents deliberate using the NSED peer-review protocol (Round 1 independent analysis, Round 2 MAINTAIN/CONCEDE/NUANCE for disagreements). The architect synthesizes the final answer directly from convene_general_council output. --spec-review switches to single-pass advisory mode for spec review. Requires council.general.enabled: true and a search API key in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides.",
82641
82662
  category: "agent"
82642
82663
  },
82643
82664
  "pr-review": {
@@ -83065,7 +83086,7 @@ Present the eleven gates with their defaults (DEFAULT_QA_GATES) as a single user
83065
83086
  - council_mode (default: OFF) — multi-member council gate (recommended for high-impact architecture, public APIs, schema/data mutation, security-sensitive code)
83066
83087
  - hallucination_guard (default: OFF) — when enabled, mandatory per-phase API/signature/claim/citation verification via critic_hallucination_verifier at PHASE-WRAP; phase_complete will REJECT phase completion unless .swarm/evidence/{phase}/hallucination-guard.json exists with an APPROVED verdict (recommended for claim-heavy or research-heavy work)
83067
83088
  - mutation_test (default: OFF) — when enabled, runs mutation testing on source files touched this phase via generate_mutants + mutation_test + write_mutation_evidence at PHASE-WRAP; FAIL verdict blocks phase_complete; WARN is non-blocking (recommended for projects with coverage gaps or safety-critical code)
83068
- - council_general_review (default: OFF) — when enabled, MODE: SPECIFY runs convene_general_council on the draft spec before the critic-gate; the architect runs a curated web_search pass, dispatches council_generalist / council_skeptic / council_domain_expert in parallel with a shared RESEARCH CONTEXT block, deliberates on disagreements, and synthesizes the result directly into the spec (recommended for novel architecture, unclear best practices, or high-risk design decisions). Requires council.general.enabled: true and a configured search API key.
83089
+ - council_general_review (default: OFF) — when enabled, MODE: SPECIFY runs convene_general_council on the draft spec before the critic-gate; the architect runs a curated web_search pass, dispatches council_generalist / council_skeptic / council_domain_expert in parallel with a shared RESEARCH CONTEXT block, deliberates on disagreements, and synthesizes the result directly into the spec (recommended for novel architecture, unclear best practices, or high-risk design decisions). Requires council.general.enabled: true and a configured search API key in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides.
83069
83090
  - drift_check (default: ON) — when enabled, mandatory per-phase drift verification via critic_drift_verifier at PHASE-WRAP; compares implemented changes against spec.md intent; hard-blocks phase_complete when spec.md exists and drift evidence is missing or REJECTED; advisory-only when no spec.md exists (recommended for all projects with a specification)
83070
83091
  - final_council (default: OFF) - when enabled, after all phases complete the architect dispatches the same five phase-council members (\`critic\`, \`reviewer\`, \`sme\`, \`test_engineer\`, \`explorer\`) at project scope, collects \`CouncilMemberVerdict\` objects, and calls \`write_final_council_evidence\`. This is not General Council mode and does not require \`council.general.enabled\`.
83071
83092
 
@@ -84492,6 +84513,8 @@ ROUND 1 — Independent Analysis and Answer
84492
84513
  - Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.
84493
84514
  - Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).
84494
84515
  - State your confidence (0.0–1.0) explicitly. Be honest — overconfident answers hurt the council.
84516
+ - For current, latest, today, now, or otherwise time-sensitive claims, training knowledge is NOT evidence. If the RESEARCH CONTEXT is missing, stale, or ambiguous, say the claim is not established instead of filling the gap from memory.
84517
+ - Treat the dispatch message's CURRENT DATE as authoritative for relative time. Do not append your own training cutoff year to search-oriented reasoning or recommendations.
84495
84518
  - Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.
84496
84519
  - Do NOT coordinate with other members. You will not see their responses until Round 2.
84497
84520
  - Do NOT pad. Be concise. Substance over volume.
@@ -84534,7 +84557,8 @@ Notes:
84534
84557
  - For Round 1: leave \`disagreementTopics\` as []. For Round 2: list the specific disagreement topics this response addresses.`, HARD_RULES = `================================================================
84535
84558
  HARD RULES
84536
84559
  ================================================================
84537
- - You have no tools. Reason from the provided RESEARCH CONTEXT and your training knowledge.
84560
+ - You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.
84561
+ - Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or "state of the art" claims.
84538
84562
  - Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in \`areasOfUncertainty\`.
84539
84563
  - Never echo other members' responses verbatim. Paraphrase or quote with attribution.
84540
84564
  - Stay within your role and persona. The architect chose you for a specific perspective.`, GENERALIST_COUNCIL_PROMPT, SKEPTIC_COUNCIL_PROMPT, DOMAIN_EXPERT_COUNCIL_PROMPT;
@@ -111014,7 +111038,7 @@ var ArgsSchema2 = exports_external.object({
111014
111038
  working_directory: exports_external.string().optional()
111015
111039
  });
111016
111040
  var convene_general_council = createSwarmTool({
111017
- description: "Synthesize responses from a multi-model General Council. Accepts parallel member " + "responses (Round 1, optionally Round 2), detects disagreements, and returns " + "consensus points, persisting disagreements, and a structured synthesis. " + "Architect-only. Config-gated on council.general.enabled.",
111041
+ description: "Synthesize responses from a multi-model General Council. Accepts parallel member " + "responses (Round 1, optionally Round 2), detects disagreements, and returns " + "consensus points, persisting disagreements, and a structured synthesis. " + "Architect-only. Config-gated on council.general.enabled in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides.",
111018
111042
  args: {
111019
111043
  question: exports_external.string().min(1).max(8000).describe("The question put to the council, or the spec text to review."),
111020
111044
  mode: exports_external.enum(["general", "spec_review"]).optional().describe('"general" for /swarm council; "spec_review" for SPECIFY-COUNCIL-REVIEW gate.'),
@@ -111093,7 +111117,7 @@ var convene_general_council = createSwarmTool({
111093
111117
  const fail = {
111094
111118
  success: false,
111095
111119
  reason: "council_general_disabled",
111096
- message: "convene_general_council requires council.general.enabled: true in opencode-swarm.json."
111120
+ message: "convene_general_council requires council.general.enabled: true in the resolved config: global ~/.config/opencode/opencode-swarm.json or project .opencode/opencode-swarm.json."
111097
111121
  };
111098
111122
  return JSON.stringify(fail, null, 2);
111099
111123
  }
@@ -126130,7 +126154,7 @@ var set_qa_gates = createSwarmTool({
126130
126154
  hallucination_guard: exports_external.boolean().optional().describe("Enable hallucination_guard checks on plan and implementation claims."),
126131
126155
  sast_enabled: exports_external.boolean().optional().describe("Enable SAST scanning as a required QA gate."),
126132
126156
  mutation_test: exports_external.boolean().optional().describe("Enable the mutation-testing gate (default: off). Requires mutation " + "tests to achieve a passing kill rate before phase completion; " + "WARN verdict allows advancement, FAIL blocks."),
126133
- council_general_review: exports_external.boolean().optional().describe("Enable the council_general_review gate (default: off). When on, " + "MODE: SPECIFY runs convene_general_council on the draft spec " + "before the critic-gate, folding multi-model deliberation into " + "the spec. Requires council.general.enabled and a search API key."),
126157
+ council_general_review: exports_external.boolean().optional().describe("Enable the council_general_review gate (default: off). When on, " + "MODE: SPECIFY runs convene_general_council on the draft spec " + "before the critic-gate, folding multi-model deliberation into " + "the spec. Requires council.general.enabled and a search API key " + "in the resolved config: global ~/.config/opencode/opencode-swarm.json, " + "then project .opencode/opencode-swarm.json overrides."),
126134
126158
  drift_check: exports_external.boolean().optional().describe("Enable drift verification gate (default: on). Blocks phase_complete " + "until drift-verifier.json has an approved verdict. When disabled, " + "drift verification is skipped entirely."),
126135
126159
  final_council: exports_external.boolean().optional().describe("Enable the final_council gate (default: off). When on, " + "after all phases complete the architect dispatches critic, reviewer, " + "sme, test_engineer, and explorer with project-scoped context, " + "collects their CouncilMemberVerdict objects, and calls " + "write_final_council_evidence. This is not General Council mode " + "and does not require council.general.enabled."),
126136
126160
  project_type: exports_external.string().optional().describe('Project type label (e.g. "ts", "python"). Only applied when the profile is being created for the first time.')
@@ -128928,6 +128952,52 @@ var update_task_status = createSwarmTool({
128928
128952
  init_zod();
128929
128953
  init_loader();
128930
128954
 
128955
+ // src/council/search-query-policy.ts
128956
+ var CURRENT_INTENT_RE = /\b(?:latest|current|currently|today|now|newest|recent|recently|up\s*-?\s*to\s*-?\s*date|this\s+(?:week|month|year)|as\s+of\s+(?:today|now))\b/i;
128957
+ var HISTORICAL_INTENT_RE = /\b(?:history|historical|archive|archived|in\s+20\d{2}|during\s+20\d{2}|from\s+20\d{2}|for\s+20\d{2}|as\s+of\s+20\d{2})\b/i;
128958
+ function applySearchQueryPolicy(rawQuery, now = new Date) {
128959
+ const originalQuery = rawQuery;
128960
+ let query = rawQuery.trim().replace(/\s+/g, " ");
128961
+ const currentYear = now.getUTCFullYear();
128962
+ const temporalIntent = detectTemporalIntent(query);
128963
+ const removedStaleYears = [];
128964
+ if (temporalIntent === "current") {
128965
+ query = removeTrailingStaleCutoffYears(query, currentYear, removedStaleYears);
128966
+ }
128967
+ return {
128968
+ originalQuery,
128969
+ query,
128970
+ temporalIntent,
128971
+ freshness: temporalIntent === "current" ? chooseFreshness(query) : undefined,
128972
+ removedStaleYears
128973
+ };
128974
+ }
128975
+ function detectTemporalIntent(query) {
128976
+ if (CURRENT_INTENT_RE.test(query))
128977
+ return "current";
128978
+ if (HISTORICAL_INTENT_RE.test(query))
128979
+ return "historical";
128980
+ return "unspecified";
128981
+ }
128982
+ function chooseFreshness(query) {
128983
+ if (/\b(?:today|now|as\s+of\s+(?:today|now))\b/i.test(query))
128984
+ return "day";
128985
+ if (/\bthis\s+week\b/i.test(query))
128986
+ return "week";
128987
+ if (/\b(?:recent|recently|this\s+month)\b/i.test(query))
128988
+ return "month";
128989
+ return "year";
128990
+ }
128991
+ function removeTrailingStaleCutoffYears(query, currentYear, removed) {
128992
+ return query.replace(/\s+(?:as\s+of\s+)?(20\d{2})\s*$/i, (match, year) => {
128993
+ const numericYear = Number(year);
128994
+ if (numericYear >= currentYear)
128995
+ return match;
128996
+ removed.push(year);
128997
+ return "";
128998
+ }).replace(/\s+/g, " ").trim();
128999
+ }
129000
+
128931
129001
  // src/council/web-search-provider.ts
128932
129002
  class WebSearchError extends Error {
128933
129003
  cause;
@@ -128950,18 +129020,22 @@ class TavilyProvider {
128950
129020
  constructor(apiKey) {
128951
129021
  this.apiKey = apiKey;
128952
129022
  }
128953
- async search(query, maxResults) {
129023
+ async search(query, maxResults, options = {}) {
129024
+ const requestBody = {
129025
+ api_key: this.apiKey,
129026
+ query,
129027
+ max_results: maxResults,
129028
+ search_depth: "advanced"
129029
+ };
129030
+ if (options.freshness) {
129031
+ requestBody.time_range = options.freshness;
129032
+ }
128954
129033
  let response;
128955
129034
  try {
128956
129035
  response = await fetch("https://api.tavily.com/search", {
128957
129036
  method: "POST",
128958
129037
  headers: { "Content-Type": "application/json" },
128959
- body: JSON.stringify({
128960
- api_key: this.apiKey,
128961
- query,
128962
- max_results: maxResults,
128963
- search_depth: "advanced"
128964
- })
129038
+ body: JSON.stringify(requestBody)
128965
129039
  });
128966
129040
  } catch (err3) {
128967
129041
  throw new WebSearchError(`Tavily network error for query "${query}"`, err3);
@@ -128993,10 +129067,14 @@ class BraveProvider {
128993
129067
  constructor(apiKey) {
128994
129068
  this.apiKey = apiKey;
128995
129069
  }
128996
- async search(query, maxResults) {
129070
+ async search(query, maxResults, options = {}) {
128997
129071
  const url3 = new URL("https://api.search.brave.com/res/v1/web/search");
128998
129072
  url3.searchParams.set("q", query);
128999
129073
  url3.searchParams.set("count", String(maxResults));
129074
+ const freshness = toBraveFreshness(options.freshness);
129075
+ if (freshness) {
129076
+ url3.searchParams.set("freshness", freshness);
129077
+ }
129000
129078
  let response;
129001
129079
  try {
129002
129080
  response = await fetch(url3.toString(), {
@@ -129030,6 +129108,20 @@ class BraveProvider {
129030
129108
  }));
129031
129109
  }
129032
129110
  }
129111
+ function toBraveFreshness(freshness) {
129112
+ switch (freshness) {
129113
+ case "day":
129114
+ return "pd";
129115
+ case "week":
129116
+ return "pw";
129117
+ case "month":
129118
+ return "pm";
129119
+ case "year":
129120
+ return "py";
129121
+ default:
129122
+ return;
129123
+ }
129124
+ }
129033
129125
  function resolveApiKey(provider, configKey) {
129034
129126
  if (configKey && configKey.length > 0) {
129035
129127
  return configKey;
@@ -129042,7 +129134,7 @@ function createWebSearchProvider(config3) {
129042
129134
  const apiKey = resolveApiKey(config3.searchProvider, config3.searchApiKey);
129043
129135
  if (!apiKey) {
129044
129136
  const envName = config3.searchProvider === "tavily" ? "TAVILY_API_KEY" : "BRAVE_SEARCH_API_KEY";
129045
- throw new WebSearchConfigError(`No API key for search provider "${config3.searchProvider}". Set ` + `council.general.searchApiKey in opencode-swarm.json or export ${envName}.`);
129137
+ throw new WebSearchConfigError(`No API key for search provider "${config3.searchProvider}". Set ` + `council.general.searchApiKey in the resolved config (global ~/.config/opencode/opencode-swarm.json, project .opencode/opencode-swarm.json override) or export ${envName}.`);
129046
129138
  }
129047
129139
  switch (config3.searchProvider) {
129048
129140
  case "tavily":
@@ -129136,12 +129228,14 @@ var MAX_RESULTS_HARD_CAP = 10;
129136
129228
  var ArgsSchema6 = exports_external.object({
129137
129229
  query: exports_external.string().min(1).max(500),
129138
129230
  max_results: exports_external.number().int().min(1).max(20).optional(),
129231
+ freshness: exports_external.enum(["auto", "none", "day", "week", "month", "year"]).default("auto"),
129139
129232
  working_directory: exports_external.string().optional()
129140
129233
  });
129141
129234
  var web_search = createSwarmTool({
129142
- description: "External web search for architect-driven council research. Returns titled results with snippets and URLs. " + "Used by the architect in MODE: COUNCIL to gather a RESEARCH CONTEXT before dispatching council agents. " + "Requires council.general.enabled and a configured search API key (Tavily or Brave). max_results is capped at 10 with default from council.general.maxSourcesPerMember.",
129235
+ description: "External web search for architect-driven council research. Returns titled results with snippets and URLs. " + "Used by the architect in MODE: COUNCIL to gather a RESEARCH CONTEXT before dispatching council agents. " + "Normalizes current-intent queries, strips trailing stale cutoff years, and applies provider freshness filters by default. " + "Requires council.general.enabled and a configured search API key (Tavily or Brave) in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides. max_results is capped at 10 with default from council.general.maxSourcesPerMember.",
129143
129236
  args: {
129144
129237
  query: exports_external.string().min(1).max(500).describe("Search query string (1–500 characters)."),
129238
+ freshness: exports_external.enum(["auto", "none", "day", "week", "month", "year"]).optional().describe('Optional freshness filter. Query normalization always runs; "auto" infers provider freshness from current/recency terms, while "none" disables provider freshness filtering.'),
129145
129239
  max_results: exports_external.number().int().min(1).max(20).optional().describe(`Number of results to request (1–20). Hard-capped at ${MAX_RESULTS_HARD_CAP}. Defaults to council.general.maxSourcesPerMember.`),
129146
129240
  working_directory: exports_external.string().optional().describe("Project root for config resolution. Optional.")
129147
129241
  },
@@ -129170,12 +129264,15 @@ var web_search = createSwarmTool({
129170
129264
  const fail = {
129171
129265
  success: false,
129172
129266
  reason: "council_general_disabled",
129173
- message: "web_search is disabled set council.general.enabled: true in opencode-swarm.json."
129267
+ message: "web_search is disabled - set council.general.enabled: true in the resolved config: global ~/.config/opencode/opencode-swarm.json or project .opencode/opencode-swarm.json."
129174
129268
  };
129175
129269
  return JSON.stringify(fail, null, 2);
129176
129270
  }
129177
129271
  const requested = parsed.data.max_results ?? generalConfig.maxSourcesPerMember;
129178
129272
  const maxResults = Math.min(requested, MAX_RESULTS_HARD_CAP);
129273
+ const policy = applySearchQueryPolicy(parsed.data.query);
129274
+ const requestedFreshness = parsed.data.freshness ?? "auto";
129275
+ const freshness = requestedFreshness === "auto" ? policy.freshness : requestedFreshness === "none" ? undefined : requestedFreshness;
129179
129276
  let provider;
129180
129277
  try {
129181
129278
  provider = createWebSearchProvider(generalConfig);
@@ -129188,11 +129285,17 @@ var web_search = createSwarmTool({
129188
129285
  return JSON.stringify(fail, null, 2);
129189
129286
  }
129190
129287
  try {
129191
- const results = await provider.search(parsed.data.query, maxResults);
129192
- const evidence = await captureSearchEvidence(dirResult.directory, parsed.data.query, results);
129288
+ const results = await provider.search(policy.query, maxResults, {
129289
+ freshness
129290
+ });
129291
+ const evidence = await captureSearchEvidence(dirResult.directory, policy.query, results);
129193
129292
  const ok2 = {
129194
129293
  success: true,
129195
- query: parsed.data.query,
129294
+ query: policy.query,
129295
+ originalQuery: policy.originalQuery,
129296
+ temporalIntent: policy.temporalIntent,
129297
+ freshness,
129298
+ removedStaleYears: policy.removedStaleYears,
129196
129299
  totalResults: results.length,
129197
129300
  results: results.map(({ title, url: url3, snippet }) => ({
129198
129301
  title,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.53.0",
3
+ "version": "7.54.0",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",