@balpal4495/quorum 0.1.8 → 0.1.9

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 (3) hide show
  1. package/README.md +235 -110
  2. package/bin/init.js +5 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,48 +1,45 @@
1
1
  # Quorum
2
2
 
3
- Quorum is a portable reasoning layer for agentic codebases.
3
+ **Quorum gives AI agents memory and judgment.**
4
4
 
5
- Drop the `quorum/` folder into any Node.js project, tell your AI to follow `quorum/SETUP.md`, and it wires itself in installing dependencies, merging instruction files, and initialising a persistent knowledge store called Chronicle.
5
+ Drop it into any Node.js project, wire up your LLM, and your agents can query what's been tried before, validate decisions against prior evidence, and write new knowledge back — with a human approving every write.
6
6
 
7
- From that point, every AI agent working in the codebase queries Chronicle before proposing solutions, and every significant decision gets written back to it (with human approval). Over time it becomes the institutional memory of the project: what was tried, what worked, what failed, and why.
7
+ ```bash
8
+ npx @balpal4495/quorum@latest init
9
+ ```
10
+
11
+ That's it. Quorum copies itself into your project, merges instruction files for your AI, and creates the knowledge store directory. Run `npm install` and you're ready.
8
12
 
9
13
  ---
10
14
 
11
- ## What's inside
15
+ ## Why this exists
16
+
17
+ When AI agents work in a codebase over weeks or months, they lose context between sessions. They retry approaches that already failed. They contradict previous decisions. They have no memory of what the team has already learned.
12
18
 
13
- Four portable TypeScript modules:
19
+ Quorum solves this with four modules:
14
20
 
15
21
  | Module | What it does |
16
22
  |---|---|
17
- | **Oracle** | Query and write interface to Chronicle. No LLM required. |
18
- | **Jury** | Evaluates a proposed design against Oracle evidence. Returns a confidence score. |
19
- | **Council** | Adversarial validation via a parallel panel of advisors and reviewers. Returns a verdict. |
20
- | **Sentinel** | Chronicle coverage and drift detection. Surfaces gaps and stale knowledge as Vitest assertions. |
21
-
22
- ```
23
- oracle.query() → jury.evaluate() → council.deliberate() → human gate → Executor
24
- sentinel.coverage() + sentinel.detectDrift() → advisory test output
25
- ```
23
+ | **Oracle** | Stores and retrieves project knowledge decisions, investigations, outcomes |
24
+ | **Jury** | Scores a proposed design against that knowledge gives you confidence before acting |
25
+ | **Council** | A panel of advisors challenges the design and a Chairman gives a final verdict |
26
+ | **Sentinel** | Shows you which parts of the codebase the AI knows nothing about — and flags stale knowledge |
26
27
 
27
28
  ---
28
29
 
29
30
  ## How it works
30
31
 
31
- **Flow system components and connections:**
32
+ Every significant decision goes through a pipeline before execution:
32
33
 
33
- ```mermaid
34
- flowchart LR
35
- Agent[AI Agent] -->|query| Oracle
36
- Oracle -->|evidence| Jury
37
- Jury -->|scores| Council
38
- Council -->|verdict| Gate[Human Gate]
39
- Oracle -. reads .-> Chronicle[(Chronicle)]
40
- Gate -. approved commit .-> Chronicle
41
- Chronicle -. coverage + drift .-> Sentinel
42
- Sentinel -. advisory report .-> CI([CI / Developer])
34
+ ```
35
+ oracle.query() → jury.evaluate() → council.deliberate() → human gate → Executor
43
36
  ```
44
37
 
45
- **Sequenceone full decision cycle:**
38
+ 1. **Query**retrieve everything Chronicle knows about the problem
39
+ 2. **Evaluate** — Jury scores the proposed design against that evidence (0–1 confidence)
40
+ 3. **Deliberate** — Council advisors challenge it independently, reviewers anonymously critique, Chairman gives a verdict
41
+ 4. **Human gate** — if satisfied, a human approves the Chronicle entry; nothing is written automatically
42
+ 5. **Execute** — agent proceeds with a validated, documented decision
46
43
 
47
44
  ```mermaid
48
45
  sequenceDiagram
@@ -54,149 +51,277 @@ sequenceDiagram
54
51
  participant Chronicle
55
52
 
56
53
  Agent->>Oracle: query(text)
57
- Oracle->>Chronicle: vector search
58
- Chronicle-->>Oracle: ranked entries
59
- Oracle-->>Agent: OracleResult[]
54
+ Oracle->>Chronicle: vector + BM25 search
55
+ Chronicle-->>Agent: ranked evidence
60
56
 
61
57
  Agent->>Jury: evaluate(design, evidence)
62
- Jury-->>Agent: score, flags, passed
58
+ Jury-->>Agent: confidence score + gaps
63
59
 
64
- Agent->>Council: deliberate(design, evaluations)
65
- Council-->>Agent: satisfied, verdict, proposal
60
+ Agent->>Council: deliberate(design, evidence, jury_output)
61
+ Council-->>Agent: verdict + proposal
66
62
 
67
- alt Council not satisfied
68
- Note over Agent: revise design and retry
69
- else Council satisfied
70
- Agent->>Human: surface verdict and proposal
63
+ alt Council satisfied
64
+ Agent->>Human: surface verdict for approval
71
65
  Human->>Oracle: commit(proposalId)
72
- Oracle->>Chronicle: upsert entry
73
- Oracle-->>Human: ChronicleEntry
66
+ Oracle->>Chronicle: index entry
67
+ else not satisfied
68
+ Note over Agent: revise and retry
74
69
  end
75
70
  ```
76
71
 
77
72
  ---
78
73
 
79
- ## How to use it
74
+ ## Real examples
80
75
 
81
- Run this from any Node.js project root:
76
+ ### Example 1 An agent remembers a past failure
82
77
 
83
- ```bash
84
- npx @balpal4495/quorum@latest init
78
+ Your agent is about to propose JWT with symmetric signing. Oracle returns an entry:
79
+
80
+ ```
81
+ [abc-123] Tried symmetric JWT (HS256) in March. Rejected — no way to rotate keys
82
+ without invalidating all active sessions. Use RS256 with short-lived tokens.
83
+ confidence: 0.91 · status: committed
85
84
  ```
86
85
 
87
- Quorum scaffolds itself copying modules into `quorum/`, merging AI instruction files (CLAUDE.md, AGENTS.md), and initialising Chronicle. Then run `npm install`.
86
+ Jury flags this as a conflict. The agent revises to RS256 before Council even sees it.
88
87
 
89
- For manual control or AI-assisted setup, tell your AI: *"follow quorum/SETUP.md"*.
88
+ ---
90
89
 
91
- See [SETUP.md](SETUP.md) for the full bootstrap sequence.
90
+ ### Example 2 Validating a database migration plan
92
91
 
93
- ---
92
+ An agent proposes adding a `NOT NULL` column to a 50M-row table.
94
93
 
95
- ## Chronicle
94
+ ```typescript
95
+ const evidence = await oracle.query("schema migrations large tables")
96
96
 
97
- Chronicle lives at `.chronicle/` and is the persistent knowledge store that underpins everything. Every Oracle entry goes through a human-gated write path — `oracle.propose()` stages it, a human calls `oracle.commit()` to index it. There are no auto-commits.
97
+ const jury = await evaluate({
98
+ outcome: "Add NOT NULL column users.verified",
99
+ design: "ALTER TABLE, backfill with default false, then add constraint",
100
+ evidence,
101
+ })
102
+ // jury.confidence: 0.41 — gaps: ["no lock strategy", "no rollback plan"]
98
103
 
99
- ```
100
- .chronicle/
101
- committed/ ← approved entries as JSON (committed to git, source of truth)
102
- proposals/ ← staged entries awaiting human approval (JSON, not indexed yet)
103
- SUMMARY.md ← auto-generated agent context, rebuilt on every commit
104
+ const verdict = await deliberate({
105
+ outcome: "Add NOT NULL column users.verified",
106
+ design: "ALTER TABLE, backfill with default false, then add constraint",
107
+ evidence,
108
+ jury_output: jury,
109
+ })
110
+ // verdict.satisfied: false
111
+ // verdict.verdict: "No lock strategy specified. On a table this size, a naive ALTER TABLE
112
+ // will take an exclusive lock for minutes. Use a shadow column pattern
113
+ // or pg_repack."
104
114
  ```
105
115
 
106
- `SUMMARY.md` groups the last 12 weeks of entries by week and work context. It gives agents temporal sequence — what happened and in what order — which vector search alone cannot provide.
116
+ The agent revises the plan. Chronicle records the reasoning once approved.
107
117
 
108
118
  ---
109
119
 
110
- ## Dependencies
120
+ ### Example 3 — Onboarding a new AI to an established project
111
121
 
112
- | Package | Purpose |
113
- |---|---|
114
- | `zod` | Structured LLM output validation |
115
- | `vectordb` | LanceDB embedded vector store (swappable) |
116
- | `@xenova/transformers` | Local ONNX embedder all-MiniLM-L6-v2 (swappable) |
122
+ On day one, a fresh AI session queries Chronicle before touching anything:
123
+
124
+ ```typescript
125
+ const evidence = await oracle.query("authentication, session handling, token strategy")
126
+ // Returns 6 entries covering prior decisions, a failed experiment with Redis sessions,
127
+ // the current RS256 approach, and a note about the upcoming OAuth migration.
128
+ ```
117
129
 
118
- The LLM provider is injectable Quorum defines a simple function interface and never hardcodes a provider. Wire OpenAI, Anthropic, or anything else at the application level.
130
+ The AI works with full context from the first message no archaeology through git history.
119
131
 
120
132
  ---
121
133
 
122
- ## Designed to be dropped in — not installed
134
+ ## Quick start
123
135
 
124
- Quorum is intentionally a folder, not an npm package. The source lives in your repo, the modules are readable by any AI agent working in the codebase, and the instruction files (`AGENTS.md`, `CLAUDE.md`) travel with the code. Nothing is hidden inside `node_modules`.
136
+ ```typescript
137
+ import { setup } from "./quorum/modules/setup"
125
138
 
126
- ---
139
+ const { oracle, evaluate, deliberate } = await setup({
140
+ llm: myLLMProvider, // any function that calls your LLM — see wiring below
141
+ })
127
142
 
128
- ## Sentinel
143
+ // Query what Chronicle knows
144
+ const evidence = await oracle.query("authentication patterns in this codebase")
129
145
 
130
- Sentinel answers three questions Chronicle cannot answer about itself.
146
+ // Evaluate a proposed design
147
+ const jury = await evaluate({
148
+ outcome: "Add OAuth2 login via GitHub",
149
+ design: "Use passport-github2, store sessions in Redis, 1-hour TTL",
150
+ evidence,
151
+ })
131
152
 
132
- **Coverage** which files have no Chronicle entries? These are the blind spots where agents have no prior knowledge to draw on.
153
+ // Get a Council verdict
154
+ const verdict = await deliberate({
155
+ outcome: "Add OAuth2 login via GitHub",
156
+ design: "Use passport-github2, store sessions in Redis, 1-hour TTL",
157
+ evidence,
158
+ jury_output: jury,
159
+ })
133
160
 
134
- **Drift** do existing Chronicle entries still accurately describe the code? Insights become stale without anyone noticing.
161
+ if (verdict.satisfied) {
162
+ // → surface verdict.proposal to a human for approval
163
+ // → human calls oracle.commit(proposalId) to index it
164
+ // → Executor proceeds
165
+ } else {
166
+ // verdict.verdict contains the specific objection
167
+ // verdict.recommendation is "redesign" or "investigate-more"
168
+ }
169
+ ```
135
170
 
136
- **PR coverage map** — when a PR is opened, every module in the codebase is shown with its Chronicle coverage percentage, risk colour, and how many files the PR touches. Reviewers see exactly where the knowledge is solid and where it goes dark — as a table and a colour-coded heatmap, not a prose summary.
171
+ ---
137
172
 
138
- Sentinel is designed for both new and established projects. On a brand-new project with no Chronicle entries it surfaces a bootstrap prompt rather than a wall of red. As the project matures, coverage thresholds can be raised to enforce standards in CI.
173
+ ## Wiring your LLM
139
174
 
140
- ### In CI coverage and drift as Vitest assertions
175
+ Quorum accepts any function with this signature you're never locked in:
141
176
 
142
177
  ```typescript
143
- import { describe } from "vitest"
144
- import { sentinelAssertions } from "./modules/sentinel/assert"
178
+ import type { LLMProvider } from "./quorum/modules/shared/types"
179
+ ```
145
180
 
146
- const assertions = sentinelAssertions({
147
- chronicleDir: ".chronicle",
148
- codebasePath: "src", // path to your source tree defaults to "."
149
- llm: myLLMProvider, // optional drift tests skip gracefully when absent
150
- minCoveragePercent: 50, // optional — 0 (default) = advisory only, never fails CI
181
+ ```typescript
182
+ // Anthropic
183
+ const llm: LLMProvider = async (messages, model = "claude-3-5-sonnet-20241022") => {
184
+ const system = messages.find(m => m.role === "system")?.content ?? ""
185
+ const user = messages.filter(m => m.role !== "system")
186
+ const res = await anthropic.messages.create({ model, system, messages: user, max_tokens: 2048 })
187
+ return res.content[0].type === "text" ? res.content[0].text : ""
188
+ }
189
+
190
+ // OpenAI
191
+ const llm: LLMProvider = async (messages, model = "gpt-4o") => {
192
+ const res = await openai.chat.completions.create({ model, messages })
193
+ return res.choices[0].message.content ?? ""
194
+ }
195
+
196
+ // Per-step model overrides (optional)
197
+ const { oracle, evaluate, deliberate } = await setup({
198
+ llm,
199
+ models: {
200
+ jury: "gpt-4o-mini",
201
+ council: {
202
+ frame: "gpt-4o-mini",
203
+ advisors: "gpt-4o-mini",
204
+ reviewers: "gpt-4o",
205
+ chairman: "gpt-4o",
206
+ },
207
+ },
151
208
  })
209
+ ```
210
+
211
+ Oracle requires no LLM — only Jury, Council, and Sentinel drift checks need one.
212
+
213
+ ---
214
+
215
+ ## Chronicle — the knowledge store
216
+
217
+ Chronicle lives at `.chronicle/` in your project root. It persists across sessions, machines, and contributors.
152
218
 
153
- describe("sentinel", () => { assertions.forEach(a => a()) })
219
+ ```
220
+ .chronicle/
221
+ committed/ ← approved entries as JSON (commit these to git)
222
+ proposals/ ← staged entries awaiting approval (commit these too — they're human-readable)
223
+ SUMMARY.md ← auto-generated weekly context, rebuilt on every commit
154
224
  ```
155
225
 
156
- Coverage tests are deterministic — no LLM required, always run. By default (`minCoveragePercent: 0`) gaps are logged but CI never fails, which is right for a new project. Raise the threshold as Chronicle matures. Drift tests are always advisory — they skip when no LLM is configured and never hard-block the build.
226
+ **The write path is always human-gated:**
157
227
 
158
- Test files (`__tests__/`, `*.test.ts`, `*.spec.ts`) are excluded from tracking by default — only source files count toward coverage.
228
+ ```
229
+ oracle.propose() ← AI stages a candidate entry (no indexing yet)
230
+ oracle.commit() ← human approves — entry is indexed and searchable
231
+ ```
232
+
233
+ `deliberate()` automatically calls `oracle.propose()` at the end of every Council run. You only need to call `oracle.commit(proposalId)` when you're ready to approve it.
234
+
235
+ There are no auto-commits. Ever.
236
+
237
+ ---
159
238
 
160
- ### In PRs the coverage map
239
+ ## Sentinelcodebase coverage and drift
161
240
 
162
- The `sentinel-pr.yml` workflow runs on every PR and posts a comment with a full-project coverage table and a colour-coded Mermaid heatmap. Changed modules are bolded. The comment updates in place on each push — one comment per PR, never a thread of duplicates.
241
+ Sentinel answers three questions Chronicle can't answer about itself.
163
242
 
243
+ ### Which files does the AI know nothing about?
244
+
245
+ ```typescript
246
+ import { coverage } from "./quorum/modules/sentinel"
247
+
248
+ const report = await coverage(".chronicle", "src")
249
+ // report.percentage — 34%
250
+ // report.uncoveredFiles — ["src/auth/session.ts", "src/payments/stripe.ts", ...]
164
251
  ```
165
- ## Sentinel — Chronicle Coverage Map — 2026-W20
166
252
 
167
- | Module | Coverage | Entries | Files | PR Changes | Risk |
168
- |----------|----------|---------|-------|-------------|--------|
169
- | council/ | 0% | 0 | 8 | — | high |
170
- | jury/ | 0% | 0 | 4 | — | high |
171
- | oracle/ | 22% | 4 | 9 | — | medium |
172
- | scripts/ | 0% | 0 | 1 | **1 files** | high |
173
- | sentinel/| 0% | 0 | 5 | **2 files** | high |
174
- | shared/ | 100% | 2 | 1 | — | low |
253
+ ### Is the AI's knowledge stale?
175
254
 
176
- [mermaid heatmap — Chronicle root → all modules, nodes coloured red/yellow/green by risk,
177
- changed modules labelled with file count]
255
+ ```typescript
256
+ import { detectDrift } from "./quorum/modules/sentinel"
178
257
 
179
- ### Chronicle context for changed modules
180
- **oracle/**
181
- - `[30bdc1c1]` schema constraints not LLM self-evaluation — validated (0.88)
258
+ const report = await detectDrift(".chronicle", "src", llm)
259
+ // report.flags — entries where the key_insight may no longer match the code
182
260
  ```
183
261
 
184
- On a new project with no Chronicle entries, the comment instead shows a bootstrap prompt guiding the team toward their first `oracle.propose()` call.
262
+ ### Coverage as CI assertions
185
263
 
186
- ```mermaid
187
- flowchart LR
188
- Chronicle[(Chronicle)] -->|committed entries| Sentinel
189
- Codebase[Codebase] -->|source files, excl. tests| Sentinel
190
- LLM[LLM Provider] -. drift eval .-> Sentinel
191
- Sentinel --> Vitest([Vitest assertions])
192
- Sentinel --> PRComment([PR coverage map])
264
+ ```typescript
265
+ import { describe } from "vitest"
266
+ import { sentinelAssertions } from "./quorum/modules/sentinel"
267
+
268
+ describe("sentinel", () => {
269
+ sentinelAssertions({
270
+ chronicleDir: ".chronicle",
271
+ codebasePath: "src",
272
+ llm: myLLMProvider, // omit to skip drift tests
273
+ minCoveragePercent: 50, // 0 = advisory only (default — safe for new projects)
274
+ }).forEach(a => a())
275
+ })
193
276
  ```
194
277
 
278
+ ### PR coverage map
279
+
280
+ Add `.github/workflows/sentinel-pr.yml` (included in `quorum/`) to get a comment on every PR showing which modules are covered, which are blind spots, and which files the PR touches — as a table and a colour-coded Mermaid heatmap.
281
+
282
+ ---
283
+
284
+ ## Modules at a glance
285
+
286
+ | Module | Needs LLM | Entry point |
287
+ |---|---|---|
288
+ | Oracle | No | `oracle.query()` / `oracle.propose()` / `oracle.commit()` |
289
+ | Jury | Yes | `evaluate(input, deps)` |
290
+ | Council | Yes | `deliberate(input, deps)` |
291
+ | Sentinel | Optional | `coverage()` / `detectDrift()` / `sentinelAssertions()` |
292
+
293
+ Full API reference: [modules/README.md](modules/README.md)
294
+ Design decisions (what not to change): [modules/CLAUDE.md](modules/CLAUDE.md)
295
+
296
+ ---
297
+
298
+ ## Dependencies
299
+
300
+ | Package | Why |
301
+ |---|---|
302
+ | `zod` | Validates all structured LLM output — required |
303
+ | `vectordb` | LanceDB embedded vector store — default adapter, swappable |
304
+ | `@xenova/transformers` | Local ONNX embedder (all-MiniLM-L6-v2) — default adapter, swappable |
305
+
306
+ `vectordb` and `@xenova/transformers` are optional if you bring your own vector store and embedder. Implement the `VectorStore` interface in `oracle/types.ts` and pass your own `embedder` function to `setup()`.
307
+
308
+ ---
309
+
310
+ ## Releases
311
+
312
+ Quorum is published to npm as `@balpal4495/quorum`. New versions are released by pushing a semver tag:
313
+
314
+ ```bash
315
+ git tag v0.2.0 && git push origin v0.2.0
316
+ ```
317
+
318
+ GitHub Actions publishes to npm automatically via OIDC Trusted Publishing — no stored tokens.
319
+
195
320
  ---
196
321
 
197
- ## Module docs
322
+ ## Docs
198
323
 
199
- - [modules/README.md](modules/README.md) — full API reference and quick-start
200
- - [modules/AGENTS.md](modules/AGENTS.md) — file ownership and invariants
201
- - [modules/CLAUDE.md](modules/CLAUDE.md) — design decisions and what not to change
202
- - [SETUP.md](SETUP.md) — bootstrap sequence for new projects
324
+ - [modules/README.md](modules/README.md) — full API reference
325
+ - [modules/AGENTS.md](modules/AGENTS.md) — file ownership and what each file owns
326
+ - [modules/CLAUDE.md](modules/CLAUDE.md) — design decisions and invariants
327
+ - [SETUP.md](SETUP.md) — manual bootstrap sequence (for AI-assisted setup)
package/bin/init.js CHANGED
@@ -15,6 +15,10 @@ import { promises as fs } from "fs"
15
15
  import path from "path"
16
16
  import { fileURLToPath } from "url"
17
17
  import { execSync } from "child_process"
18
+ import { createRequire } from "module"
19
+
20
+ const _require = createRequire(import.meta.url)
21
+ const PKG_VERSION = _require("../package.json").version
18
22
 
19
23
  const __dirname = path.dirname(fileURLToPath(import.meta.url))
20
24
  const QUORUM_ROOT = path.resolve(__dirname, "..")
@@ -346,7 +350,7 @@ async function cli() {
346
350
  }
347
351
 
348
352
  if (command === "--version" || command === "-v" || command === "version") {
349
- console.log("0.1.0")
353
+ console.log(PKG_VERSION)
350
354
  return
351
355
  }
352
356
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@balpal4495/quorum",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Portable reasoning layer for agentic codebases — Oracle, Jury, Council, Sentinel",
5
5
  "type": "module",
6
6
  "license": "MIT",