@possumtech/rummy 0.3.1 → 0.4.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.
Files changed (46) hide show
  1. package/.env.example +11 -0
  2. package/README.md +5 -1
  3. package/SPEC.md +31 -17
  4. package/migrations/001_initial_schema.sql +2 -3
  5. package/package.json +1 -1
  6. package/src/agent/AgentLoop.js +50 -151
  7. package/src/agent/KnownStore.js +15 -7
  8. package/src/agent/TurnExecutor.js +75 -318
  9. package/src/agent/XmlParser.js +25 -4
  10. package/src/agent/known_queries.sql +1 -1
  11. package/src/agent/known_store.sql +11 -61
  12. package/src/agent/runs.sql +2 -2
  13. package/src/hooks/Hooks.js +1 -0
  14. package/src/hooks/ToolRegistry.js +6 -5
  15. package/src/plugins/ask_user/ask_userDoc.js +3 -8
  16. package/src/plugins/budget/README.md +26 -18
  17. package/src/plugins/budget/budget.js +60 -3
  18. package/src/plugins/budget/recovery.js +47 -0
  19. package/src/plugins/cp/cpDoc.js +4 -9
  20. package/src/plugins/env/envDoc.js +3 -8
  21. package/src/plugins/get/get.js +2 -4
  22. package/src/plugins/get/getDoc.js +11 -18
  23. package/src/plugins/helpers.js +2 -2
  24. package/src/plugins/instructions/instructions.js +3 -2
  25. package/src/plugins/instructions/preamble.md +27 -16
  26. package/src/plugins/known/known.js +63 -8
  27. package/src/plugins/known/knownDoc.js +10 -14
  28. package/src/plugins/mv/mvDoc.js +6 -21
  29. package/src/plugins/policy/policy.js +47 -0
  30. package/src/plugins/progress/progress.js +9 -45
  31. package/src/plugins/prompt/prompt.js +10 -1
  32. package/src/plugins/rm/rmDoc.js +5 -10
  33. package/src/plugins/rpc/rpc.js +3 -1
  34. package/src/plugins/set/set.js +82 -85
  35. package/src/plugins/set/setDoc.js +28 -41
  36. package/src/plugins/sh/shDoc.js +2 -7
  37. package/src/plugins/summarize/summarize.js +7 -0
  38. package/src/plugins/summarize/summarizeDoc.js +6 -11
  39. package/src/plugins/think/think.js +12 -0
  40. package/src/plugins/think/thinkDoc.js +18 -0
  41. package/src/plugins/unknown/unknown.js +21 -0
  42. package/src/plugins/unknown/unknownDoc.js +9 -14
  43. package/src/plugins/update/update.js +7 -0
  44. package/src/plugins/update/updateDoc.js +6 -11
  45. package/src/server/ClientConnection.js +11 -1
  46. package/src/sql/v_model_context.sql +4 -4
@@ -1,26 +1,37 @@
1
- You are a folksonomic memory agent. YOU MUST organize all information into searchable taxonomies with navigable path hierarchies and searchable summary tags, then YOU MAY answer questions and/or take action.
1
+ You are a folksonomic knowledgebase assistant. YOU MUST discern what you don't know into unknowns, then extract and organize your findings into navigable and searchable knowns, then YOU MAY answer questions and/or perform actions.
2
2
 
3
- # Response Rules
3
+ # Tool Commands
4
4
 
5
- Required: YOU MUST respond with Tool Commands in the XML format. YOU MAY use multiple tools in your response.
5
+ Tools: [%TOOLS%]
6
6
 
7
- Optional: YOU MAY think in an optional <think></think> tag before using any other Tool Commands.
7
+ # Tool Rules
8
8
 
9
+ ## Response Rules
10
+ Required: YOU MUST respond with Tool Commands in the XML format. YOU MAY use up to 12 tools in your response.
9
11
  Required: YOU MUST register all unknowns with <unknown>[specific thing I need to learn]</unknown>.
10
-
11
12
  Required: YOU MUST register all new facts, decisions, and plans with <known path="topic/subtopic" summary="keyword,keyword,keyword">[specific facts, decisions, or plans]</known>.
12
- Required: Every <known> MUST include summary="keyword,keyword" tags.
13
- Info: Paths are addresses for tools. Summary tags tell you what's inside.
14
- Info: Path and summary information is approximate. YOU MUST use <get/> to verify before acting on summarized content.
15
- Info: When information conflicts, later turns are more likely to be relevant and correct than earlier turns.
16
- Info: Your context is limited but your archive is not. Organize and categorize your facts, decisions, plans, and history to optimize your context.
17
-
18
- Required: YOU MUST promote all relevant "summary" entries to "full".
19
- Required: YOU MUST demote all irrelevant "full" entries to "summary".
20
13
 
14
+ ## Folksonomic Memory Management
15
+ * Write paths with navigable hierarchies and summaries with searchable tags.
16
+ * When new facts, decisions, and plans appear, set them as <known/> entries with navigable hierarchies and summaries with searchable tags to improve your folksonomic knowledgebase.
17
+ * When new questions emerge, use pattern matching operations to optimize the fidelity and relevance of your knowledgebase.
18
+ * The turn attribute can be helpful for discerning what's fresh or stale, prefer more recent information if conflicts exist.
19
+ * YOU MUST promote all relevant entries and demote all irrelevant entries before acting or answering. Use body pattern search (Example: <get path="known://*">John Doe</get>) to recall archived entries when needed.
20
+ * Logging entries in <previous/> can also be demoted to optimize context.
21
+
22
+ ## Fidelity Management
23
+ * full: Entire contents are shown (consumes token budget)
24
+ * summary: Only path and summary are shown. (<= 80 chars, saves token budget)
25
+ * archive: Archived in an unlimited archive. Entries can be recalled with path recall or pattern search. (use caution)
26
+
27
+ ## Token Budget Management
28
+ * Entries contain a "fidelity" and a "token" attribute to enable token budget management and context optimization.
29
+ * Set relevant entries to "full" and irrelevant entries to "summary" to optimize context.
30
+ * The less irrelevant information in your context, the better.
31
+
32
+ ## Response Termination
21
33
  Required: YOU MUST conclude every turn with EITHER <update></update> if still working OR <summarize></summarize> if done. Never both.
22
- Required: YOU MUST use one and only one <update></update> or <summarize></summarize> tag, and only at the end.
23
34
 
24
- # Tool Commands
35
+ # Tool Usage
25
36
 
26
- Tools: [%TOOLS%]
37
+ [%TOOLDOCS%]
@@ -1,5 +1,8 @@
1
+ import { countTokens } from "../../agent/tokens.js";
1
2
  import docs from "./knownDoc.js";
2
3
 
4
+ const MAX_ENTRY_TOKENS = Number(process.env.RUMMY_MAX_ENTRY_TOKENS) || 512;
5
+
3
6
  export default class Known {
4
7
  #core;
5
8
 
@@ -8,6 +11,7 @@ export default class Known {
8
11
  core.registerScheme({ category: "data" });
9
12
  core.on("handler", this.handler.bind(this));
10
13
  core.on("full", this.full.bind(this));
14
+ core.on("summary", this.summary.bind(this));
11
15
  core.filter("assembly.system", this.assembleKnown.bind(this), 100);
12
16
  core.filter("instructions.toolDocs", async (docsMap) => {
13
17
  docsMap.known = docs;
@@ -17,19 +21,70 @@ export default class Known {
17
21
 
18
22
  async handler(entry, rummy) {
19
23
  const { entries: store, sequence: turn, runId, loopId } = rummy;
20
- const target = entry.attributes.path || entry.resultPath;
21
- await store.upsert(runId, turn, target, entry.body, 200, { loopId });
24
+ if (!entry.body) return;
25
+
26
+ // Size gate
27
+ const entryTokens = countTokens(entry.body);
28
+ if (entryTokens > MAX_ENTRY_TOKENS) {
29
+ const rejectPath = await store.slugPath(runId, "known", entry.body);
30
+ await store.upsert(
31
+ runId,
32
+ turn,
33
+ rejectPath,
34
+ `Entry too large (${entryTokens} tokens, max ${MAX_ENTRY_TOKENS}). Sort the information, ideas, or plans carefully into multiple entries.`,
35
+ 413,
36
+ { loopId },
37
+ );
38
+ return;
39
+ }
40
+
41
+ // Resolve path: explicit or auto-generated slug
42
+ let knownPath = entry.attributes?.path || null;
43
+ if (knownPath && !knownPath.includes("://")) {
44
+ knownPath = `known://${knownPath}`;
45
+ }
46
+ if (!knownPath) {
47
+ knownPath = await store.slugPath(
48
+ runId,
49
+ "known",
50
+ entry.body,
51
+ entry.attributes?.summary,
52
+ );
53
+ }
54
+
55
+ // Dedup: if path exists, update rather than duplicate
56
+ const existing = await store.getEntriesByPattern(runId, knownPath, null);
57
+ if (existing.length > 0) {
58
+ await store.upsert(
59
+ runId,
60
+ turn,
61
+ existing[0].path,
62
+ entry.body || existing[0].body,
63
+ 200,
64
+ { attributes: entry.attributes, loopId },
65
+ );
66
+ return;
67
+ }
68
+
69
+ await store.upsert(runId, turn, knownPath, entry.body, 200, {
70
+ attributes: entry.attributes,
71
+ loopId,
72
+ });
22
73
  }
23
74
 
24
75
  full(entry) {
25
76
  return `# known ${entry.path}\n${entry.body}`;
26
77
  }
27
78
 
79
+ summary(entry) {
80
+ return this.full(entry);
81
+ }
82
+
28
83
  async assembleKnown(content, ctx) {
29
84
  const entries = ctx.rows.filter((r) => r.category === "data");
30
85
  if (entries.length === 0) return content;
31
86
 
32
- // Rows arrive pre-sorted by SQL: skill → index → summary → full, then by recency
87
+ // Rows arrive pre-sorted by SQL: summary → full, then by recency
33
88
  const demotedSet = new Set(ctx.demoted || []);
34
89
  const lines = entries.map((e) => renderKnownTag(e, demotedSet));
35
90
  return `${content}\n\n<knowns>\n${lines.join("\n")}\n</knowns>`;
@@ -50,12 +105,12 @@ function renderKnownTag(entry, demotedSet) {
50
105
  : entry.attributes;
51
106
  const summary =
52
107
  typeof attrs?.summary === "string"
53
- ? ` summary="${attrs.summary.slice(0, 80)}"`
108
+ ? ` summary="${attrs.summary.replace(/"/g, "'").slice(0, 80)}"`
54
109
  : "";
55
110
 
56
- if (entry.body) {
57
- return `<${tag} path="${entry.path}"${turn}${status}${fidelity}${summary}${tokens}${flag}>${entry.body}</${tag}>`;
111
+ if (entry.fidelity === "archive") return "";
112
+ if (entry.fidelity === "summary") {
113
+ return `<${tag} path="${entry.path}"${turn}${status}${summary}${fidelity}${tokens}${flag}/>`;
58
114
  }
59
-
60
- return `<${tag} path="${entry.path}"${turn}${status}${fidelity}${summary}${tokens}${flag}/>`;
115
+ return `<${tag} path="${entry.path}"${turn}${status}${summary}${fidelity}${tokens}${flag}>${entry.body}</${tag}>`;
61
116
  }
@@ -2,32 +2,28 @@
2
2
  // Text goes to the model. Rationale stays in source.
3
3
  // Changing ANY line requires reading ALL rationales first.
4
4
  const LINES = [
5
- // --- Syntax: path = slash-separated topic hierarchy, body = the information to save
6
5
  [
7
6
  '## <known path="known://topic/subtopic" summary="keyword,keyword,keyword">[specific facts, decisions, or plans]</known> - Sort and save what you learn for later recall',
8
7
  ],
9
- // --- Examples: category-level entries — multiple related facts per entry, not one per item
10
8
  [
11
- 'Example: <known path="known://config/database" summary="database,host,port,pool,replica">Host: db.internal. Port: 5432. Pool: 10 connections. Replica: db-replica.internal:5432.</known>',
12
- "Category entry: all database config facts in one entry. Path is an address (topic/subtopic), body collects every related fact, summary is comma-separated search keywords not a description.",
9
+ 'Example: <known summary="hedberg,comedian,death,2005">Mitch Hedberg died on March 30, 2005</known>',
10
+ "Summary-first pattern: comma-separated keywords, path auto-generated.",
13
11
  ],
14
12
  [
15
- 'Example: <known path="known://project/milestones" summary="milestone,deadline,alpha,launch,2026">Alpha: 2026-03-01. Beta cutoff: 2026-04-15. GA launch: 2026-06-01.</known>',
16
- "Timeline entry: all milestone dates under one path. Multiple facts per entry reduces fragmentation. Recall by glob or keyword.",
13
+ 'Example: <known path="known://people/rumsfeld" summary="defense,secretary,born,1932">Donald Rumsfeld was born in 1932 and served as Secretary of Defense</known>',
14
+ "Explicit path form: slashed path=category/key, summary=keywords.",
17
15
  ],
18
- // --- Constraints: summary and grouping first (model forms generation pattern from header + examples)
19
16
  [
20
- "* `summary` REQUIRED at summary fidelity the body is hidden; these keywords are your only description",
21
- "Self-interest framing: without summary, the model has a path but no idea what's inside.",
17
+ '* Recall with <get path="known://people/*">keyword</get>',
18
+ "Cross-tool lifecycle: glob by category, filter by keyword.",
22
19
  ],
23
20
  [
24
- "* Group related facts by topic one entry per topic category, not one per input chunk",
25
- "Critical behavioral constraint. Topic grouping enables semantic recall; chunk-based filing creates positional, irretrievable entries.",
21
+ "* YOU SHOULD write `summary` keywords, you can search for them later",
22
+ "Motivates summary writing through self-interest.",
26
23
  ],
27
- // --- Lifecycle
28
24
  [
29
- '* Recall with <get path="known://config/*">replica</get>',
30
- "Cross-tool lifecycle: glob by category, filter by keyword. Matches the slashed path convention.",
25
+ "* YOU MUST sort and save all new facts, decisions, and plans in their own <known> entries",
26
+ "Critical behavioral constraint. 'new' prevents re-saving known facts.",
31
27
  ],
32
28
  ];
33
29
 
@@ -2,43 +2,28 @@
2
2
  // Text goes to the model. Rationale stays in source.
3
3
  // Changing ANY line requires reading ALL rationales first.
4
4
  const LINES = [
5
- // --- Syntax: path attr = source, body = destination
6
5
  [
7
6
  '## <mv path="[source]">[destination]</mv> - Move or rename a file or entry',
8
7
  ],
9
-
10
- // --- Examples: entry rename and file move
11
8
  [
12
9
  'Example: <mv path="known://active_task">known://completed_task</mv>',
13
- "Entry rename. Most common mv use case. Shows known:// path convention.",
10
+ "Entry rename. Most common mv use case.",
14
11
  ],
15
12
  [
16
13
  'Example: <mv path="src/old_name.js">src/new_name.js</mv>',
17
- "File rename. Shows that mv works on files too, not just known entries.",
18
- ],
19
-
20
- // --- Archive lifecycle
21
- [
22
- "* You may move entries or pattern-matching batches of entries to and from the archive to manage your context budget.",
23
- "Teaches archival as a reversible budget operation, not permanent deletion.",
14
+ "File rename.",
24
15
  ],
25
16
  [
26
- 'Example: <mv path="known://project/*" fidelity="index"/> ... <mv path="known://project/active_sprint" fidelity="full"/>',
27
- "Index a whole category to free context while keeping paths visible, restore one entry when needed. No destination = fidelity change in place.",
17
+ 'Example: <mv path="known://project/*" fidelity="summary"/>',
18
+ "Batch fidelity change via pattern. No destination = fidelity in place.",
28
19
  ],
29
- [
30
- "* YOU SHOULD demote irrelevant entries to `index` or `archive` — clean context improves reasoning.",
31
- "Core curation principle: clean context is a quality signal, not just a budget concern. Teach the model to curate eagerly.",
32
- ],
33
-
34
- // --- Constraints
35
20
  [
36
21
  "* Source path accepts patterns for batch moves",
37
22
  "Pattern support consistent with get/cp/rm.",
38
23
  ],
39
24
  [
40
- "* In ask mode, destination MUST be a scheme path (not a file)",
41
- "Mode constraint. Prevents file mutations in ask mode via mv.",
25
+ "* Use `preview` to check matches before pattern-based bulk moves",
26
+ "Safety pattern consistent with rm/cp.",
42
27
  ],
43
28
  ];
44
29
 
@@ -0,0 +1,47 @@
1
+ import KnownStore from "../../agent/KnownStore.js";
2
+
3
+ export default class Policy {
4
+ constructor(core) {
5
+ core.filter("entry.recording", this.#enforceAskMode.bind(this), 1);
6
+ }
7
+
8
+ async #enforceAskMode(entry, ctx) {
9
+ if (ctx.mode !== "ask") return entry;
10
+
11
+ if (entry.scheme === "sh") {
12
+ console.warn("[RUMMY] Rejected <sh> in ask mode");
13
+ return { ...entry, status: 403 };
14
+ }
15
+
16
+ if (entry.scheme === "set" && entry.attributes?.path) {
17
+ const scheme = KnownStore.scheme(entry.attributes.path);
18
+ if (scheme === null && entry.body) {
19
+ console.warn(
20
+ `[RUMMY] Rejected file edit to ${entry.attributes.path} in ask mode`,
21
+ );
22
+ return { ...entry, status: 403 };
23
+ }
24
+ }
25
+
26
+ if (entry.scheme === "rm") {
27
+ const pathAttr = entry.attributes?.path || entry.path;
28
+ const scheme = KnownStore.scheme(pathAttr);
29
+ if (scheme === null) {
30
+ console.warn(`[RUMMY] Rejected file rm of ${pathAttr} in ask mode`);
31
+ return { ...entry, status: 403 };
32
+ }
33
+ }
34
+
35
+ if (entry.scheme === "mv" || entry.scheme === "cp") {
36
+ const destScheme = KnownStore.scheme(entry.attributes?.to);
37
+ if (destScheme === null) {
38
+ console.warn(
39
+ `[RUMMY] Rejected ${entry.scheme} to file ${entry.attributes?.to} in ask mode`,
40
+ );
41
+ return { ...entry, status: 403 };
42
+ }
43
+ }
44
+
45
+ return entry;
46
+ }
47
+ }
@@ -10,53 +10,17 @@ export default class Progress {
10
10
  const { lastContextTokens: usedTokens, contextSize } = ctx;
11
11
  const pct = contextSize ? Math.round((usedTokens / contextSize) * 100) : 0;
12
12
 
13
- // Fidelity distribution across all manageable entries (data + logging)
14
- const dataEntries = ctx.rows.filter((r) => r.category === "data");
15
- const loggingEntries = ctx.rows.filter((r) => r.category === "logging");
16
- const entries = [...dataEntries, ...loggingEntries];
17
- const fullEntries = entries.filter((r) => r.fidelity === "full");
18
- const summaryEntries = entries.filter((r) => r.fidelity === "summary");
19
- const indexEntries = entries.filter((r) => r.fidelity === "index");
20
- const fullTokens = fullEntries.reduce((s, r) => s + r.tokens, 0);
21
- const summaryTokens = summaryEntries.reduce((s, r) => s + r.tokens, 0);
22
- const indexTokens = indexEntries.reduce((s, r) => s + r.tokens, 0);
23
-
24
- const unknownCount = ctx.rows.filter(
25
- (r) => r.category === "unknown",
26
- ).length;
27
-
28
- const hasPerformed = loggingEntries.some(
29
- (r) => r.source_turn >= ctx.loopStartTurn,
30
- );
31
-
32
- const parts = [];
33
-
34
- const knownCount = dataEntries.length;
35
- const loggingCount = loggingEntries.length;
36
- const tokenLine = contextSize
37
- ? `${usedTokens} of ${contextSize} tokens (${pct}%) · ${knownCount} known${knownCount !== 1 ? "s" : ""} · ${loggingCount} logging · ${unknownCount} unknown${unknownCount !== 1 ? "s" : ""}`
38
- : "";
39
- if (tokenLine) parts.push(tokenLine);
40
-
41
- // Fidelity distribution
42
- const fidelityParts = [];
43
- if (fullEntries.length > 0)
44
- fidelityParts.push(`${fullEntries.length} full (${fullTokens} tok)`);
45
- if (summaryEntries.length > 0)
46
- fidelityParts.push(
47
- `${summaryEntries.length} summary (${summaryTokens} tok)`,
48
- );
49
- if (indexEntries.length > 0)
50
- fidelityParts.push(`${indexEntries.length} index (${indexTokens} tok)`);
51
- if (fidelityParts.length > 0)
52
- parts.push(`Entries: ${fidelityParts.join(" · ")}`);
53
-
54
- if (hasPerformed) {
55
- parts.push(
56
- "The above actions were performed in response to the following prompt:",
13
+ const lines = [];
14
+ if (contextSize) {
15
+ lines.push(
16
+ `Using ${usedTokens} tokens (${pct}%) of ${contextSize} token budget. Use <get/> or set entry fidelity to "full" to spend tokens. Set entry fidelity to "summary" to save tokens.`,
57
17
  );
58
18
  }
19
+ lines.push(
20
+ 'Conclude with a brief <update></update> to continue or a brief <summarize></summarize> if done.',
21
+ );
22
+ const body = lines.join("\n");
59
23
 
60
- return `${content}<progress turn="${ctx.turn}">${parts.join("\n")}</progress>\n`;
24
+ return `${content}<progress turn="${ctx.turn}">${body}</progress>\n`;
61
25
  }
62
26
  }
@@ -3,7 +3,16 @@ export default class Prompt {
3
3
 
4
4
  constructor(core) {
5
5
  this.#core = core;
6
- core.hooks.tools.onView("prompt", (entry) => entry.body);
6
+ core.hooks.tools.onView("prompt", (entry) => {
7
+ if (entry.fidelity === "summary") {
8
+ const limit = 500;
9
+ const text = entry.body?.slice(0, limit) || "";
10
+ return text.length < (entry.body?.length || 0)
11
+ ? `${text}\n[truncated — promote to full to see the complete prompt]`
12
+ : text;
13
+ }
14
+ return entry.body;
15
+ });
7
16
  core.on("turn.started", this.onTurnStarted.bind(this));
8
17
  core.filter("assembly.user", this.assemblePrompt.bind(this), 300);
9
18
  }
@@ -2,28 +2,23 @@
2
2
  // Text goes to the model. Rationale stays in source.
3
3
  // Changing ANY line requires reading ALL rationales first.
4
4
  const LINES = [
5
- // --- Syntax: path attr, self-closing
6
5
  ['## <rm path="[path]"/> - Remove a file or entry'],
7
-
8
- // --- Examples: file, known (with slug path), preview safety
9
6
  ['Example: <rm path="src/config.js"/>', "File removal. Simplest form."],
10
7
  [
11
8
  'Example: <rm path="known://config/deprecated_service"/>',
12
- "Shows topic-hierarchy path convention. Paths are category/key, not sentence slugs.",
9
+ "Shows topic-hierarchy path convention.",
13
10
  ],
14
11
  [
15
12
  'Example: <rm path="known://temp_*" preview/>',
16
- "Preview before deleting. Glob pattern. Safety pattern for bulk operations.",
13
+ "Preview before deleting. Safety pattern for bulk operations.",
17
14
  ],
18
-
19
- // --- Constraints
20
15
  [
21
16
  '* Permanent. Prefer <set fidelity="archive"/> to preserve for later retrieval',
22
- "Nudges toward archive over rm. Archive keeps the key; rm deletes permanently.",
17
+ "Nudges toward archive over rm.",
23
18
  ],
24
19
  [
25
- "* Paths accept patterns — use `preview` to check matches first",
26
- "Reinforces preview safety pattern. Prevents accidental bulk deletion.",
20
+ "* Use `preview` to check matches before pattern-based bulk deletion",
21
+ "Reinforces preview safety pattern.",
27
22
  ],
28
23
  ];
29
24
 
@@ -178,7 +178,7 @@ export default class Rpc {
178
178
  scheme: e.scheme,
179
179
  status: e.status,
180
180
  fidelity: e.fidelity,
181
- tokens: e.tokens_full,
181
+ tokens: e.tokens,
182
182
  }));
183
183
  },
184
184
  description: "Query entries by pattern.",
@@ -233,6 +233,7 @@ export default class Rpc {
233
233
  contextLimit: params.contextLimit,
234
234
  noRepo: params.noRepo,
235
235
  noInteraction: params.noInteraction,
236
+ noProposals: params.noProposals,
236
237
  noWeb: params.noWeb,
237
238
  fork: params.fork,
238
239
  },
@@ -269,6 +270,7 @@ export default class Rpc {
269
270
  contextLimit: params.contextLimit,
270
271
  noRepo: params.noRepo,
271
272
  noInteraction: params.noInteraction,
273
+ noProposals: params.noProposals,
272
274
  noWeb: params.noWeb,
273
275
  fork: params.fork,
274
276
  },